Научная статья на тему 'Иерархическая модель глобальной оптимизации у параллельных объектных программ'

Иерархическая модель глобальной оптимизации у параллельных объектных программ Текст научной статьи по специальности «Компьютерные и информационные науки»

CC BY
107
41
i Надоели баннеры? Вы всегда можете отключить рекламу.

Аннотация научной статьи по компьютерным и информационным наукам, автор научной работы — Корячко B. П., Скворцов C. В.

Предлагается модель и метод глобальной оптимизации объектного кода для RISC-процессоров с управлением по технологии VLIW, основанные на использовании дизъюнктивных графов информационно-структурных зависимостей.

i Надоели баннеры? Вы всегда можете отключить рекламу.

Похожие темы научных работ по компьютерным и информационным наукам , автор научной работы — Корячко B. П., Скворцов C. В.

iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.
i Надоели баннеры? Вы всегда можете отключить рекламу.

Текст научной работы на тему «Иерархическая модель глобальной оптимизации у параллельных объектных программ»



электронный журнал ц

ИНЖСНЕРН0Е1

ОБРАЗОВАНИЕ

#8 август 2006 Ред. совет Специальности Рецензентам Авторам English Koi-8 Win

Иерархическая модель глобальной оптимизации у параллельных объектных программ #8 август 2006

B. П. Корячко, д-р техн. наук проф.,

C. В. Скворцов, канд. техн. наук доц., Рязанская государственная радиотехническая академия

Иерархическая модель глобальной оптимизации у параллельных объектных

программ

Предлагается модель и метод глобальной оптимизации объектного кода для ШЭС-процессоров с управлением по технологии VLIW, основанные на использовании дизъюнктивных графов информационно-структурных зависимостей.

Введение

Наиболее распространенным подходом к решению задачи синтеза параллельного объектного кода для программ с циклами и ветвлениями является последовательное выделение линейных участков (ЛУ) и синтез командных слов (КС) для каждого Лу в отдельности с последующим объединением полученных фрагментов кода [1—4].

Однако результаты исследований [1, 4—7] показывают,

что потенциальная возможность параллелизма существует и для операций, принадлежащих разным ЛУ исходной программы. Выявление таких операций проводится методами глобального анализа программ [4, 6, 7], разработка и развитие которых приобретают особую актуальность в связи с распространением ШБС-процессоров с управлением параллельным выполнением операций по технологии длинного командного слова (УЫ^ [4].

Наиболее известными методами глобального анализа являются планирование трасс [4, 6] и проникающее планирование [4, 7]. Суть этих методов сводится к определению комбинаций ЛУ, операции из которых целесообразно исследовать на возможность параллельного исполнения.

Планирование трасс предполагает предварительное независимое формирование списка КС для каждого ЛУ с последующим определением наиболее вероятных трасс из нескольких последовательных ЛУ и улучшением полученного кода за счет перемещения отдельных операций между этими участками. Наличие условных переходов в пределах одной трассы приводит к необходимости дублирования некоторых перемещенных операций при оптимизации последующих трасс программы.

Проникающее планирование исключает дублирование операций в процессе глобального переупорядочения кода за границами ЛУ и выполняется над моделью программы, которая является обобщением управляющего графа (вершины соответствуют ЛУ, а дуги определяют возможные пути исполнения). Параллелизм в программе выявляется перемещением между вершинами графовой модели условных и безусловных операций. Результатом является преобразованный управляющий граф, обеспечивающий максимальный параллелизм для идеального компьютера, причем для синтеза реального кода требуется выполнить генерацию КС, в которых учитываются ограничения доступа к общим ресурсам процессора.

В работах [8—10] описана новая формальная модель

организации параллельных вычислений на уровне

операций — дизъюнктивный граф информационно-

структурных зависимостей Н* = (А, V, Е). Дуги графа

показывают зависимости по данным, а ребра

е определяют все пары конфликтных операций,

которые не могут быть выполнены параллельно из-за необходимости доступа к общим ресурсам процессора. Каждый бесконтурный орграф С^ = (Л, V), получаемый в

результате замены ребер графа Н* дугами, определяет корректный вариант параллельной объектной программы 1№/ = (LW1, . ., LWN), в которой каждое командное слово

т? еьш составляют операции расположенные на

одном ярусе графа С. Орграф С* = (А, V*) с минимальной

длиной критического пути соответствует объектной программе, исполняемой за минимальное время [8, 10].

Анализ свойств дизъюнктивных графов информационно-структурных зависимостей [8, 9] позволяет предложить на их основе оригинальный подход к глобальной оптимизации объектного кода, не требующий предварительного синтеза КС для всех ЛУ в отдельности (ограничиваясь выделением циклических участков и альтернативных ветвей) и сочетающий преимущества обоих указанных выше методов, а именно:

• глобальное преобразование кода достигается перемещением операций программы между различными ЛУ;

• отсутствует дублирование операций исходной программы;

• учитываются ограничения архитектуры процессора.

Иерархическая графовая модель программы

Предположим, что в процессе трансляции исходная программа преобразована в последовательность А = (а^

а2,..., ап) операций, представленных в стандартной

машинно-независимой тетрадной форме [11] вида

которая определяет тип С,- операнды и

результат О/ производимой операции, причем для организации

ветвлений и циклов могут использоваться следующие операции: безусловного перехода (/#?!„, ак) на операцию акел,

где к > / или к < /; условных переходов к выполнению операции аК&л (к > /' или к < /) по нулевому (¡тг, X, , ак), положительному

(¡тр, X, , ак), отрицательному (¡тп, X, , а^ и другим значениям

операнда X.

Информационная зависимость операций порождает

биологический граф программы [12, 13], адекватно описывающий структуру исходной программы А на микроуровне параллелизма и представляющий собой орграф С б = (А, Уб), вершины которого соответствуют операциям

^ел, а дуги задают связи по данным и управлению.

Для вершин Сб с помощью логических функций И и

ИСКЛЮЧАЮЩЕЕ ИЛИ (ИСКЛ. ИЛИ) определены условия входа и выхода, которые описывают логику программы, т. е. каждой вершине сопоставлена одна из пар вида (&, &), (&, ©), (

©, &) или (©,©), что определяет разбиение

л = лш и а&ф и аш и ^фф, где первый индекс показывает тип

входной, а второй — выходной логики для вершин каждого подмножества.

В корректной билогической модели [13] вершина а<=Аф&Афф может иметь выходную функцию ИСКЛ. ИЛИ

только при |Г(а/)| = 2 (условный переход для выбора одной из

альтернативных ветвей или выход из цикла с постусловием) и вершина а,. е — входную функцию ИСКЛ. ИЛИ

только для |Г-1(а/)| = 2, что определяет точку схождения двух ветвей или входа в цикл. При необходимости это достигается

введением дополнительных вершин ai е л&& с логикой

И, которые определяют фиктивные операции входа и выхода для соответствующих альтернативных и циклических фрагментов программы.

Граф G6 = (А, VQ) позволяет выполнить глобальный

анализ структуры (логики) программы, но не учитывает ограничений на параллелизм операций из-за конфликтов по ресурсам. Поэтому предлагается использовать билогическую модель Gq в качестве источника свойств глобального

параллелизма операций, необходимых для построения иерархической графовой модели И** = (А*, V*, Е*) синтеза параллельного объектного кода с циклами и ветвлениями на

основе Р>\множеств мр =0^} вложенных дизъюнктивных графов R¡p) =(A¡p\v¿p) ,E¡p)) информационно-структурных

зависимостей, отражающих возможные варианты конфликтов операций на каждом р-м уровне иерархии P=iJ*.

Для каждого значения p < p* число элементов множества Mp определяется числом циклических и альтернативных

ветвей равного уровня вложенности, а множество MF* = {н{р*) = (a}p*),v1(p*),eíp*))} всегда содержит только один

элемент, который описывает иерархическую модель И** = (Л*,

V*, Е*), где A*=AÍ?t\F*=Fl?t\B*=Sli?t).

Построение модели Н** осуществляется посредством эквивалентных, с точки зрения семантики программы, преобразований билогического графа, начиная с низшего (p =

0) уровня иерархии, для которого G6=GlJ)=G(^\ где

Осо) = Cj4(0)>^0)) и = лт u лт yj лт ^ лт . Переход на более

высокий (p + 1)-й уровень иерархии означает частичное

исключение циклов и ветвлений [12], а следовательно,

сокращение общего числа вершин

й,е4ф+1) ^ ^ логикой I/ICKJ1. ИЛИ в графовой модели

Г* 1 / \ ГЛ .1 \ гЯ Ж-Г \ Т Т /— \ • \ \ /-ъ Г\ У S- 1 . 1

^ хн^женерное образование. модель глобальной оптимизации у пир... ха^е о ол 2

Для этого в текущей билогической модели о(6р) = (А(р),¥&) выделяются ориентированные подграфы

которые описывают циклические и альтернативные фрагменты, содержащие только вершины хел1р\ где а£р) На их основе строятся дизъюнктивные

подграфы Н1*=№ЛЮЛ») и далее И<* где

а1р) с а[р) и с которые затем заменяются

макровершинами типа <*{/! или в соответствии

со схемами, показанными на рис. 1 и 2.

и инженер ное обр аз

• иерар

у пар ... хм^е ' ол 21

Рис. 1. Преобразование циклических фрагментов:

а — цикл с постусловием в билогической модели; б — дизъюнктивный подграф р-го уровня иерархии для цикла

с постусловием; в — результат стягивания цикла с постусловием; г — цикл с предусловием в исходной билогической модели; д — дизъюнктивный подграф р-го уровня для цикла с предусловием; е — результат стягивания цикла с предусловием

Схемы стягивания циклических фрагментов билогической модели в вершины показаны на рис. 1. Структура

исходного цикла с постусловием выхода представлена на рис. 1, а, где символом © явно указана логика вершин ИСКЛ. ИЛИ (

<¿1 е — точка входа, а. е дЦ1 — точка выхода из цикла), а

подграф описывающий тело цикла, условно изображен

прямоугольником. Рис. 1, б иллюстрирует преобразование графовой модели в целях исключения логики ИСКЛ. ИЛИ и получения дизъюнктивного графа н(кр), ограниченного

штриховой линией. Конечный результат преобразования циклического фрагмента билогического графа с постусловием выхода показан на рис. 1, в. Преобразование циклической структуры с предусловием выхода показано на рис. 1, г— 1, е, где а,ае аЩ — точка входа и выхода одновременно, причем

вершина может соответствовать фиктивной

операции, которая введена, чтобы обеспечить выполнение условий корректности билогической модели программы [11].

и инженер ное обр аз

• иерар

у пар... хм^е 9 оа 21

Рис. 2. Преобразование условных и альтернативных

ветвей:

а — условная ветвь программы в билогической модели; б — дизъюнктивный подграф р-го уровня иерархии для условной ветви; в — результат стягивания условной ветви; г — альтернативные ветви в билогической модели; д — результат стягивания альтернативных ветвей; е — составная макровершина иерархического

iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.

дизъюнктивного графа

Условная ветвь программы (рис. 2, а—2, в), которой соответствует дизъюнктивный граф н(/}, стягивается в одну

вершину типа '. Пара вершин ак1 и ак2 , описывающая

альтернативные ветви программы, заменяется составной макровершиной р{/}, как это показано на рис. 2, г—2, е, где

„(Р) ч fy(p)

ветвь ак2 выполняется при истинном (true), а акх — при ложном (false) результате проверки условия перехода.

Затем каждая вершина а[р) или р[р} включается в с

соответствующей корректировкой л^^^^л^ и далее

рассматривается как макрооперация, блокирующая доступ к любым ресурсам процессора на период Т(в^) или

TifiiF)) = T(cif)+T(^)), длительность которого определяется

временем однократного исполнения (в тактах) сформированной последовательности КС, которую будем называть макрокомандой, для циклического или альтернативного фрагмента объектной программы.

Если полученный билогический граф

g^ = (а(р*\удовлетворяет условию

Л&©+1) иЛв&+1) = то достигнут максимальный уровень

иерархии р* = р + 1, для которого л^ = А^.

В противном случае процедура стягивания подграфов повторяется для следующего уровня иерархии, причем каждый раз, когда множество а[р) графа H(hp) содержит

макровершины alq) или filq), где q < р, множество ребер распадается на два подмножества E(f> = Щр) и ё™ , такие, что

ребра из Е^ указывают пары конфликтных операций

Г* 1 / \ ГЛ .1 \ гя ж-Г \ Т Т \ • \ \ Л V ,»4 V 1 , 1

исходной программы [8, 9], а е£р) включает ребра и Е(кр),де {од,...,р}, описывающие для

выделенных макроопераций псевдоконфликты доступа к общим ресурсам процессора.

Псевдоконфликт доступа к ресурсам определен для каждой пары информационно независимых элементов из

включающей хотя бы одну макровершину а[р) или р{/}, где q

< р. Его суть заключается в невозможности параллельного исполнения любой операции <¿1 е л[р) с операциями каждой

макрокоманды, а также двух или более макроопераций одновременно. Длины дуг, порождаемых в таких случаях, определяются как 1{с$\х) = ,х)= т{р[я)) или для

противоположного направления 1{х,с^)=1{х,0^)=т{х) = тя, где

Окончательно иерархическая модель Н** = (А*, V*, Е*) синтеза параллельного объектного кода с циклами и ветвлениями имеет вид дизъюнктивного графа я^ц^/м,^), построенного на основе преобразованной

билогической модели о^ = в которой содержатся

только вершины с конъюнктивной логикой, где

А* = А¡^ = А(р*\¥* = У^ = V™, а множество ребер

е*=е[г*) определяет пары конфликтных операций и

макроопераций программы. Характерной особенностью модели Н** является неопределенность временных

характеристик и макроопераций и где

р = о,р*-1, до завершения процедуры синтеза КС каждой макрокоманды.

Алгоритм синтеза КС объектной программы

Для решения задачи глобальной оптимизации

и инженер ное обр аз

• иерар

параллельного кода при синтезе объектных программ с циклами и ветвлениями предлагается следующий итерационный алгоритм, который базируется на рассмотренной дизъюнктивной иерархической модели, а для определения временных характеристик макрокоманд использует процедуру синтеза последовательности командных слов для линейного фрагмента программы по заданному критерию качества [8].

Данные: иерархическая модель синтеза Н** = (А*, V*, Е*); множества мр ={н<*> = (вложенных

дизъюнктивных графов информационно-структурных зависимостей операций ЛУ программы, где р = о,р*-\т,

максимальный уровень иерархии р*

Результаты: последовательность Ш/ = (LW1, LW2, ...,

¡-¡Л/щ) КС для программы в целом; списки КС для

линейных участков, представленных дизъюнктивными графами я;

■О) й;

Мр,р = 0, р*- \.

Шаг 1. Присвоить р = 0.

Шаг 2. Если р = р*, то выполнить переход к шагу 6.

Шаг 3. Для каждой вершины

а

О)

графа

Н{кр) выполнить синтез последовательности ¿Ща^ ) и КС по заданному критерию качества. Определить время 7x4") = исполнения макрооперации а{кр), где —число тактов выполнения макрокоманды 1Ж(а[р}).

Шаг 4. Для каждой вершины е л(/} графа

н1р) выполнить по заданному критерию качества синтез списков ЬЩа^) и КС для альтернативных ветвей.

Определить время исполнения и

сформировать

= (ш(а^)лш(а^)) список

Л?)

командных слов для составной макрокоманды где

¿Щя^') — ветвь, исполняемая при ложном, а — при

истинном результате проверки условия ветвления.

Шаг 5. Присвоить р = р + 1 и выполнить переход к шагу 2.

Шаг 6. На основе дизъюнктивного графа Н** выполнить синтез последовательности Ш/ = LWN) с

циклами и ветвлениями.

Шаг 7. В полученном списке 1№/ найти макрокоманду

с временем исполнения = Л/(х), где х = а

А

ы

или

командных слов LW(x).

заменить Ц на

фрагмент последовательность

Шаг 8. Если список ИМ/ изменился, повторить выполнение шага 7. В противном случае конец алгоритма.

Следует отметить, что представленный алгоритм позволяет выполнять синтез объектного кода как после, так и во время формирования иерархической модели глобальной оптимизации. Во втором случае синтез соответствующих

списков £,ТГ(а1р)) или (р/ ) может быть проведен сразу же после стягивания фрагментов билогического графа в

вершины а[р) или Д

г (?)

Покажем преимущества предлагаемого подхода на примере решения задачи синтеза параллельной объектной программы LW с циклами и ветвлениями по критерию минимального времени исполнения.

Пусть фрагмент исходной программы, представленной в тетрадной форме, а также матрица с = [с..]пхп конфликтов

операций, где с^ = 1, если операции, а-! и а^ не могут быть

выполнены параллельно из-за необходимости использования общих ресурсов процессора, и Су = 0 — в

противном случае, имеют следующий вид:

а1 = (ааа, В, 10, О); а2 = (ааа, С, 2, 71); а3 = (эиЬ, О, Т1, Т2); а4 = ^тр, Т2, , а7); а5 = (ааа, Т2, 1, У); а6 = От, , , а8); а7 = (э1оге, Т2, , У); а8 = (эиЬ, У, г, Т3); а9 = (ааа, Т1, X, Т4); а10 = (ааа, Т4, 3, Т5); а11 = ^оге, Т5, , О).

I /-1 .1

У л . л

V V/ у V

у

&

X 0 0 I 0 I I I I 0 0

0 X I I 0 0 0 0 0 0 I

0 I X I 0 0 0 0 0 0 I

I I I X 0 I I I I 0 I

0 0 0 0 X I 0 0 I I I

I 0 0 I I X 0 I I I I

I 0 0 I 0 0 X I I 0 0

I 0 0 I 0 I I X I 0 0

I 0 0 I I I I I X I I

0 0 0 0 I I 0 0 I X I

iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.

0 I I I I I 0 0 I I X

Таблица

Синтез командных слов для линейных участков

ЛУ Дизъюнктивный граф Ориентированный граф решения Список КОМ ^ НЛП их СЛОЕ

(й?) (¡ь) ¿^.-{аь в*}

\ /

Шъ - {и,}

(й) м

Шг 0*0 © © (5) = { <г,} 1Щ - {о*}

© © - * ау)

1В, - { а9)

(от / О ! ¿}Уц= а») IV* - {«и}

© (5)

Фрагмент программы содержит четыре ЛУ:

Г* 1 / /уч \ .1 \ т-т ж-г \ т т /— \ • \ \ /-Ъ г\ у у 1 . 1

- (а1> а2> а3' а4);

1_В2 - (а5, а6); LB3 - (а7);

- (а8> ад> аю> ац)>

где LB2_ и LBз являются альтернативными, так как при

конкретной реализации программы выполняется только один из них. Время выполнения любой операции составляет один такт, а операнды тк(к =!д) представляют собой промежуточные

результаты, сформированные компилятором.

Формирование последовательностей длинных КС для каждого ЛУ в отдельности показаны в таблице. Время исполнения фрагмента программы в целом составляет восемь и семь тактов по трассам LB1, LB2, LB4 и LB1, LBз, LB4

соответственно.

Модель синтеза КС, учитывающая глобальную структуру исходного фрагмента программы, формируется на основе билогического графа (рис. 3, а), где символом & обозначена конъюнктивная логика вершин. Иерархическая модель И** -(А*, V*, Е*), приведенная на рис. 3, б, определяется как дизъюнктивный граф я^с^11,^11,^15), множество вершин

которого содержит одну составную макровершину д(0>,

полученную стягиванием альтернативных ветвей LB2 и LBз,.

Время реализации соответствующей макрооперации = з определяется по результатам синтеза КС для

линейных участков LB2 и LBз, показанным в таблице.

и инженер ное обр аз

• иерар

у

Рис. 3. Модели глобальной оптимизации кода:

а — билогический граф программы; б — иерархический дизъюнктивный граф; в — ориентированный граф, определяющий решение; г — список командных слов

объектной программы

Множество Е* определяется как ^^и^1, где ребра [д!.,а/]е11(1)| показанные штриховой линией, задают

Г"» 1 I 1Г-Л \ гл , 1 \ т-т Я-Т \ т т /—' \ • \ Л. Л л гл г\ л г\ г\

конфликтные пары операций исходной программы (с^ =

1). Длина дуги (а, а) или (а, а), полученной из такого ребра,

определяется видом конфликта по ресурсам [8—10] и для данного примера во всех случаях /(а, а) = /(а^, а) = 1.

Ребра [^.д^е!/4, показанные пунктирной линией,

описывают псевдоконфликты макровершины отношением предшествования, что гарантирует сохранение логики программы в процессе синтеза КС. Длины порождаемых дуг определяются как 1($ц>,ак)= т($0)),1(ак,$а}) = тк, где - время

реализации макрокоманды операции

ак еА соответственно. Для данного примера получаем:

Искомый орграф С* = (Л, V*) с минимальной длиной

критического пути, порождаемый дизъюнктивным графом я{ц,

приведен на рис. 3, е. Эквивалентная параллельная объектная программа ИМ содержит семь командных слов (рис. 3, г), причем время выполнения составляет шесть и семь тактов по трассам ^в1, ^В2, ^В4 и ^в1, ^В3, ^В4

соответственно.

* * *

В статье показана возможность и предложен метод решения задачи глобальной оптимизации параллельных объектных программ для RISC-процессоров с управлением по технологии VLIW, основанный на применении иерархической графовой модели, которая представляется множеством вложенных дизъюнктивных графов информационно-структурных зависимостей [9]. Это позволяет использовать единые алгоритмы [8] синтеза длинных КС объектной программы как для отдельных ЛУ, так и для программ с

циклами и ветвлениями в целом, причем во втором случае достигается существенное сокращение общего числа КС и времени реализации за счет параллельного исполнения операций, принадлежащих разным линейным участкам исходной программы.

Список литературы

1. Трахтенгерц Э. А. Программное обеспечение параллельных процессов. М.: Наука, 1987. 272 с.

2. Французов Ю. А. Обзор методов распараллеливания кода и программной конвейеризации // Программирование. 1992. № 3. С. 16-37.

3. Local microcode compaction techniques / D. Landscov, S. Davidson, B. Shriver, P. W. Mallett // ACM Comput. Surveys. 1980. V. 12. № 3. P. 261-294.

4. Евстигнеев В. А. Некоторые особенности программного обеспечения ЭВМ с длинным командным словом // Программирование. 1991. № 2. С. 69—80.

5. Riscman E. M., Foster С. С. The inhibition of potential parallelism by conditional jumps // IEEE Trans. Comput. 1972. V. C-21. № 12. P. 1405-1411.

6. Fisher J. A. Trace scheduling: A technique for global microcode compaction // IEEE Trans. Comput. 1981. V. C-30. №

7. P. 478-490.

7. Nicolau A. Uniform parallelism exploitation in ordinary programs // Proc. of the 1985 Intern. Conf. on Parallel Processing, Aug. 1985. P. 614-618.

8. Скворцов С. В. Оптимизация кода для суперскалярных процессоров с использованием дизъюнктивных графов // Программирование. 1996. № 2. С. 41—52.

9. Корячко В. П., Скворцов С. В., Телков И. А. Модель

планирования параллельных процессов в суперскалярных процессорах// Информационные технологии. 1997. № 1. С. 8— 12.

10. Скворцов С. В. Целочисленные модели оптимизации кода по критерию времени // Информационные технологии. 1997. № 10. С. 2-7.

11. Грис Д. Конструирование компиляторов для цифровых вычислительных машин. М.: Мир, 1975. 544 с.

12. Головкин Б. А. Расчет характеристик и планирование параллельных вычислительных процессов. М.: Радио и связь, 1983. 272 с.

13. Рыжков А. П. Правильная билогическая граф-модель параллельного вычислительного процесса и ее свойства // Изв. АН СССР. Техническая кибернетика. 1976. № 2. С. 96— 104.

ИНФОРМАЦИОННЫЕ ТЕХНОЛОГИИ, № 9, 1998 ВЫЧИСЛИТЕЛЬНЫЕ СИСТЕМЫ И СЕТИ

Публикации с ключевыми словами: ООП - RISC - Параллельное программирование - VLIW - глобальная оптимизация - иерархия - модели программ - графовые модели - преобразование циклов - преобразование альтернатив

Публикации со словами: ООП - RISC - Параллельное программирование - VLIW - глобальная оптимизация - иерархия - модели программ - графовые модели - преобразование циклов - преобразование альтернатив См. также:

■ Математическая модель мобильных вычислений

■ Осваиваем С

C++BUILDER: ПЕРВЫЕ ОПЫТЫ

Объектно-ориентированные технологии проектирования прикладных программных систем

Как программировать на С++: Третье издание C/C++. Программирование на языке высокого уровня Visual C++ и MFC

Все публикации на ту же тему>> Написать комментарий >>

Журнал | Портал | Раздел Copyright © 2003 «Инженерное образование» E-mail: [email protected] | тел.: +7 (495) 263-68-63

Вход для редакторов

i Надоели баннеры? Вы всегда можете отключить рекламу.