Консолидация серверов Linux® на платформе IBM System z™
дает ряд преимуществ, однако перенос существующих приложений требует
особых знаний. В данной статье освещаются основные аспекты портирования
на System z, включая виртуализацию на мэйнфреймах, порядок следования
байтов и особенности вычисления адреса в System z. Статья
рассматривает, каким образом инструменты разработки (компилятор,
компоновщик, отладчик) работают в System z, а также знакомит с
бесплатным пакетом миграции Migration Kit с ОС Solaris на Linux.
Консолидация
серверов в среде Linux на платформе System z сулит множество
преимуществ, однако даже бесплатный пингвин не позволит вам получить их
даром. Перенос существующих Linux-приложений и серверов на платформу
System z потребует особых знаний и некоторых усилий.
Данная
статья дает скорее общий обзор, нежели детальное руководство по
портированию приложений. Для тех, кто хочет глубоко освоить тему,
приведены ссылки на подробную информацию.
Пакет миграции
Migration Kit из ОС Solaris на Linux включает в себя различные
интерактивные утилиты, помогающие при портировании, а также некоторый
объем документации (например, Руководство по переносу приложений из ОС Solaris в Linux и книгу серии IBM Redbook® Миграция из Solaris в Linux: руководство для системных администраторов). Организация процесса портирования
Прежде
чем менять что-либо в своем проекте, рекомендуется ознакомиться с
отличиями системы System z с Linux от вашей существующей программной и
аппаратной платформы. Также полезно изучить темы, описанные в данной
статье (порядок байтов, опции компилятора и т.д.). Помимо ссылок,
приведенных в этой статье, существует еще много замечательных
источников информации об отличиях других ОС и Linux. Книга Перенос Unix®-программ в Linux
рассматривает основные идеи портирования приложений из коммерческих
систем Unix, таких как AIX®, Solaris и HP-UX, в Linux. Также в ней
детально описаны инструменты разработки Linux.
Начав
модифицировать приложение, постарайтесь не менять слишком много на
каждом этапе. Сначала меняйте среду разработки, а потом -- сам исходный
код. Убедитесь, что на вашей текущей платформе доступны инструменты
разработки для Linux (самые главные -- компиляторы GCC и GNU make).
Информацию о них можно отыскать через любую поисковую систему, однако
проще всего -- обратиться к Web-страницам GNU и GCC.
Далее попробуйте собрать приложение на существующей платформе с
использованием инструментов Linux и проведите полный цикл тестов.
Только после этого переносите исходный код в Linux и модифицируйте его
по необходимости. Дальнейшие шаги стандартны, как и для любого другого
процесса портирования:
- Провести исчерпывающее тестирование.
- Найти и исправить дефекты.
Для выполнения этих этапов в Linux доступны различные инструменты. Также имеются средства оптимизации производительности.
Linux на платформе IBM System z
К счастью, подготовка Linux-приложения для исполнения на мэйнфрейме IBM
System z затрагивает всего несколько ключевых моментов. Вспомним, что
интерфейсы ядра Linux не зависят от конкретной платформы.
Первое основное отличие заключается в виртуализации. В персональном
компьютере вся система находится под контролем единственной ОС,
запущенной в данное время. В отличие от ПК, машины IBM System z
поддерживают механизм виртуализации, который предполагает
запуск нескольких ОС в отдельных виртуальных средах, причем в одно и то
же время могут работать несколько экземпляров одной и той же ОС (как
правило так и происходит). Наличие виртуальных сред добавляет забот в
части системного администрирования.
Общая структура мэйнфрейма System z
На мэйнфрейме IBM System z ОС Linux всегда запускается внутри
виртуальной среды. Мэйнфрейм состоит из нескольких логических разделов.
Каждый логический раздел (или LPAR, от англ. logical partitions)
способен исполнять либо готовую ОС, например ядро Linux, либо несколько
образов виртуальных машин (Virtual Machines, VM). Эта схема показана на
рисунке 1. Любой образ VM также может содержать Linux, что добавляет
еще один способ запуска этой ОС.
Рисунок 1. Общая структура компьютера System z с несколькими логическими разделами и виртуальными машинами
Такая
структура имеет заметные преимущества -- начиная от возможности
динамической балансировки нагрузки и планирования мощностей и
заканчивая повышенной безопасностью и наличием высокоскоростной
виртуальной сети между виртуальными машинами. Виртуальная сеть
позволяет узлам отправлять и получать данные как будто по физической
сети, причем в реальности данные передаются через память мэйнфрейма,
что обеспечивает намного большую скорость.
Но сам факт запуска Linux в виртуальной
машине System z не является причиной портирования пользовательских
приложений, поэтому мы не будем подробно на этом останавливаться. Для
ознакомления с этой темой рекомендую обратиться к замечательной книге Linux на мэйнфрейме.
Также много полезной и актуальной информации можно найти в серии книг
IBM Redbooks, доступных в электронном виде .
Соглашения об именовании
Платформа
IBM System z имела в прошлом несколько названий. Она называлась
System/390®, когда Linux был впервые портирован на нее, поэтому ее
часто называют S/390® при упоминании вместе с Linux.
Если некий исходный код должен зависеть от платформы, то используют следующие встроенные символы препроцессора:
-
__s390__ означает сборку для 31- или 64-разрядного режима System z, либо для S/390. -
__s390x__ означает сборку для 64-разрядного режима System z.
Пожалуй,
самое заметное различие заключается в адресном диапазоне. Современные
системы System z имеют 64-разрядную адресацию, в то время как ранние
модели -- 31-разрядную. Всякий раз, когда нужно подчеркнуть различие в
адресации, 31-разрядную платформу принято называть s390, а 64-разрядную -- s390x. Каждый режим адресации имеет свои особенности, рассматриваемые в данной статье. Заметим, что 31-разрядный режим основывается на 32-разрядной архитектуре, в которой старший бит служит для обозначения самого режима.
31-разрядная адресация
Повторюсь, что в 31-разрядном режиме 32-й бит не используется для адресации, поэтому любой адрес вида:
0x80000000 +n
соответствует адресу:
0x00000000 +n
Таким
образом, код, который интерпретирует целые числа как указатели, требует
особого внимания. Однако не забудьте, что приведение целых типов к
указателям противоречит стандарту языка C. Также отметим, что
абсолютные адреса почти всегда платформенно-зависимы. Это означает, что
такой код также требует пересмотра.
В то же время
указатели, созданные "легальными" средствами С, не вызовут ошибок
компиляции. Учитывая, что компилятор не обязан игнорировать старший
бит, результат выражения ниже будет "ложь":
(void*)0x80000000 == (void*)0x00000000
Схожая проблема возникает, если приложение пытается загрузить исполняемый код по абсолютному адресу путем вызова mmap с флагом MAP_FIXED . Такой вызов непереносим и требует изменения.
Соглашение о нумерации битов
В
Linux принято обозначать отдельные биты байта или слова степенью, в
которую возводится двоичное основание. Например, биты 32-разрядного
слова выглядят так:
| 31 | 30 | 29 | ... 2 | 1 | 0 |
Однако в руководствах по IBM System z применяется нумерация слева направо:
| 0 | 1 | 2 | ... 29 | 30 | 31 |
В этом примере самый младший бит, имеющий двоичный вес 2^0, называется 31-м битом. На 64-разрядной системе этот бит называется 63-м битом.
Разрядности стандартных типов данных
В таблице 1 показаны размеры стандартных типов данных C.
Таблица 1. Размеры стандартных типов C в байтах
Тип | 31-разрядный режим | 64-разрядный режим |
---|
char | 1 | 1 |
---|
short | 2 | 2 |
---|
int | 4 | 4 |
---|
float | 4 | 4 |
---|
long | 4 | 8 |
---|
pointer | 4 | 8 |
---|
long long | 8 | 8 |
---|
double | 8 | 8 |
---|
long double | 8 | 8 |
---|
size_t | 4 | 8 |
---|
ptrdiff_t | 4 | 8 |
---|
wchar_t | 4 | 4 |
---|
Выравнивание всегда равно размеру типа: переменная типа int занимает 4 байта и будет выровнена по 4-байтовой границе. В таблице 2 приведены стандартные типы данных ядра Linux.
Таблица 2. Стандартные типы данных ядра Linux
Режим | gid_t | mode_t | pid_t | uid_t |
---|
31-разрядный режим | unsigned int | unsigned int | int | unsigned int |
---|
64-разрядный режим | unsigned int | unsigned int | int | unsigned int |
---|
Размещение данных подробно рассмотрено в приложении к интерфейсу двоичных ELF-программ (ELF Application Binary Interface Supplement).
Порядок байтов
Порядок байтов
определяет, в каком именно порядке располагаются в памяти отдельные
байты много-байтового слова. Существует несколько вариантов хранения
32-разрядного числа, имеющего значение 4A3B2C1D :
- Порядок
от старшего к младшему (big-endian) предполагает хранение старшего
байта (most significant byte, MSB) в старшем адресе, что выглядит как
0x4A 0x3B 0x2C 0x1D . - Порядок
от младшего к старшему (little-endian) предполагает хранение в старшем
адресе младшего байта (least significant byte, LSB), что выглядит как
0x1D 0x2C 0x3B 0x4A .
В
системах Sun SPARC и IBM System z применяется порядок от старшего к
младшему, а в процессорах семейства x86 -- от младшего к старшему.
К
несчастью, многие программы полагаются на физическое расположение
данных в памяти, что вызывает несовместимость между платформами и
крайне опасно, так как приводит к возникновению ошибок во время
выполнения, а не на стадии компиляции. Это серьезная проблема.
Перечислим потенциально опасные задачи, чувствительные к порядку
байтов:
- Байт-ориентированная обработка данных.
- Доступ
к структурам данным из ассемблерного кода. В этом случае требуется
детальное знание представления данных при портировании таких участков
кода.
- Чтение данных из сети.
- Приведение типов путем "ухищрений" над указателями. Например, такой с виду простой код зависит от порядка следования байтов:
int x= 1; if (* (char *)&x == 1) printf ("little endian \n"); else printf ("big endian \n");
|
- Передача в функцию фактических параметров слишком малого размера. Эта ситуация схожа с предыдущей.
- Приведение типов с возможно неправильным использованием наложений (union).
Пакет
миграции Migration Kit из Solaris на Linux содержит утилиту проверки
порядка байтов (Endianess Checking Tool), помогающую найти участки
исходного кода, которые полагаются на порядок следования байтов. На
вход утилите передается исходный код и соответствующий двоичный файл,
собранный с определенными опциями компилятора. В руководстве по работе
с утилитой приведена более подробная информация. Обычно нахождение
проблемного участка выглядит так:
/test/src/init.c - Line 199: E30001 Variable/parameter size mismatch arg 2 size 4 in call to mystrncpy. (Defined in /test/src/init.c at line 190 size 1) /test/src/init.c - Строка 199: E30001 Несоответствие размера для переменной/параметра 2-го аргумента размера 4 при вызове mystrncpy. (Объявлен в файле /test/src/init.c в строке 190 с размером 1)
|
Утилита проверки порядка байтов не привязана к ОС Solaris. Она работает с любым C-кодом.
Если
вам все же требуется явная поддержка разных порядков байтов, включите
заголовочный файл asm/byteorder.h ядра Linux, который даст один из двух
соответствующих макросов: __BIG_ENDIAN или __LITTLE_ENDIAN .
Заголовочные файлы, находящиеся в каталоге
/usr/src/linux/include/linux/byteorder/, определяют различные макросы
для преобразования данных между двумя рассматриваемыми представлениями.
Некоторые из этих макросов могут ничего не делать, если преобразование
не меняет порядка байтов.
Похожие функции существуют для управления порядком байтов для
данных, передаваемых по сети. Эти функции определены в файле
/usr/include/netinet/in.h и преобразовывают значения между порядком
байтов сети и компьютера. Обычно в сетях применяется порядок от
старшего к младшему, поэтому приложениям для System z такое
преобразование не требуется. В любом случае, хорошим тоном
программирования является использование нужных функций преобразования.
Кодировки ASCII и EBCDIC
По
историческим причинам операционные системы мэйнфреймов, такие как z/OS®
и z/VM®, применяют набор символов EBCDIC. Однако Linux для System z
полностью основана на наборе ASCII, поэтому перенос Linux-приложений
или данных на другие платформы не вызовет проблем. С другой стороны,
взаимодействие Linux на System z с данными или программами под
управлением ОС, основанной на EBCDIC, требует преобразования.
Для
преобразования файла из одного набора символов в другой в Linux
существует утилита recode. Текущая версия утилиты распознает около 280
кодировок, включая 19 разновидностей EBCDIC с поддержкой национальных
символов. Для того чтобы сделать подобное преобразование, включите в
программу файл /usr/include/iconv.h и используйте функцию iconv .
Списки переменного числа параметров
Обычно
для C-программы не важно, как именно реализованы списки переменного
числа параметров. Однако может встретиться код, содержащий присвоение,
которое непереносимо и не будет работать в Linux на System z.
В Linux для System z тип va_list определен как struct . Следовательно, такое общепринятое присвоение одной переменной другой не даст ожидаемого результата:
va_list va1, va2; va_start (va1); va2 = va1; /* Это присвоение не сработает. */
|
Вместо этого используйте макрос __va_copy() для копирования: __va_copy (va2, va1); .
Библиотеки и системные вызовы, зависимые от платформы
Все
операционные системы предоставляют прикладным программам некоторый
интерфейс, который реализуется посредством большого количества
библиотек. Некоторых библиотек может не оказаться в Linux, либо они
могут по-другому называться. Сведения о таких различиях можно найти,
например, в руководстве Портирование из Unix в Linux.
При
переносе приложений из Solaris на Linux может пригодится интерактивная
утилита проверки исходного кода (Source Checking Tool), имеющаяся в
пакете миграции Migration Kit из ОС Solaris на Linux. Она распознает
около 3800 различных системных вызовов Solaris, а также файлы,
специфичные для Solaris, и директивы компилятора Sun.
На рисунке 2 показано, как можно интерактивно выбрать C- и C++-файлы Solaris, подлежащие проверке.
Рисунок 2. Интерактивный выбор файлов или целых каталогов
Затем утилита находит вызовы, требующие замены, и подсвечивает их (рисунок 3).
Рисунок 3. Утилита Source Checking Tool подсвечивает библиотечные вызовы, требующие вмешательства
Linux-варианты
вызовов и сопутствующая техническая информация доступны интерактивно,
либо могут быть вставлены как комментарии, чтобы разработчики могли ими
воспользоваться уже без запуска утилиты (рисунок 4).
Рис 4. Утилита предлагает заменить специфичные для Solaris вызовы на Linux-аналоги и предоставляет техническую справку
К
счастью, все же существуют некоторые стандарты и соглашения. Так, в
процессе разработки утилиты Source Checking Tool было подсчитано, что
46% всех вызовов идентичны. Один из примеров -- математические функции
из math.h, которые не имеют различий. Компиляция, компоновка и отладка
Портирование
приложения подразумевает использование стандартного для Linux
компилятора GCC и связанных с ним утилит. Все эти инструменты так или
иначе имеют поддержку System z. Чтобы задействовать все улучшения в
области производительности платформы, введенные с 1999 по 2005 год,
рекомендуется включить опции оптимизации, характерные для System z и
для конкретной модели процессора (рисунок 5).
Рисунок 5. Выигрыш в производительности при включении специальных опций оптимизации
На
рисунке 5 все результаты нормализованы и соответствуют новейшим моделям
System z, выпущенным в каждом году. При снятии показателей для каждой
модели System z измерения проводились несколько раз. В статье Вклад в развитие компиляторов GCC, опубликованной в IBM Systems Journal, рассказано подробно о проведении упомянутых измерений.
Опции компилятора
GCC
и утилиты binutils имеют ряд опций для платформы System z с Linux.
Подробное описание всех опций GCC вы найдете в руководстве Использование компиляторов GNU (GCC). Там же есть раздел, посвященный специфичным для System z опциям, поэтому мы дадим только краткий обзор.
Очень
может быть, что с выпуском новых моделей System z появятся
дополнительные опции GCC, а также может быть доработана поддержка
существующих моделей. Опции платформы System z показаны ниже:
-
-march=cpu-type : Задействовать инструкции только указанной модели процессора cpu-type ,
включая те, которые не поддерживаются старыми моделями -- получаемый
код скорее всего не будет на них работать. На web-сайте GCC приведен
список всех поддерживаемых типов процессоров.
-
-mtune=cpu-type : Стараться задействовать инструкции, наиболее эффективно использующие особенности процессора cpu-type . Получаемый код будет работать и на более старых моделях, но медленнее.
-
-mzarch и -mesa :
Задействовать инструкции процессоров архитектуры ESA/390 и
z/Architecture® соответственно. Значения этих опций по умолчанию, а
также сведения о согласовании с другими опциями приведены на web-сайте
GCC.
-
-m64 и -m31 : Указывает, какому двоичному стандарту должен соответствовать код -- S/390 (-m31 ) или System z (-m64 ). Стандарт zSeries описан в Принципах работы платформы z/Architecture и в Приложении к двоичному интерфейсу ELF-программ для zSeries; стандарт S/390 -- в Принципах работы платформы ESA/390 и в Приложении к двоичному интерфейсу ELF-программ Linux для S/390 .
-
-msmall-exec и
-mno-small-exec : Использовать или нет оптимизируемую инструкцию безусловного перехода, если исполняемый файл укладывается в 64 КБ.
Некоторые опции для управления и оптимизации работы стека:
-
-mwarn-framesize=framesize и
-mwarn-dynamicstack : Опции выводят предупреждения на этапе компиляции, если какая-либо функция захватит больший, чем framesize ,
стековый фрейм или задействует динамически выделяемые стековые фреймы
соответственно. Эти опции полезны в случаях, когда размер стека
ограничен (как в ядре Linux), а также для программ, страдающих
переполнением стека.
-
-mstack-guard=stack-guard и
-mstack-size=stack-size :
Еще пара опций, помогающих выявлять проблемы с размером стека путем
включения в исполняемый файл специального проверяющего кода.
-
-mpacked-stack и -mno-packed-stack :
Опции контролируют, будет ли задействован механизм, при котором
содержимое регистров хранится в стековом фрейме в упакованном виде для
экономии места. Уточните в справочнике GCC совместимость с другими
опциями, а также совместимость (при вызове функций) с кодом, полученным
компилятором GCC версии до 3.0.
-
-mbackchain и -mno-backchain :
Опции контролируют, нужно ли хранить в стековом фрейме вызываемой
функции указатель на стековый фрейм вызывающей функции. Этот указатель
называется указателем обратного списка (backchain pointer). За
подробной информацией о совместимости с другими опциями и особенностях
отладки обратитесь к справочнику GCC.
В
отличие от других ОС, совместно используемые библиотеки System z могут
существенно различаться в зависимости от того, какая опция была
применена: -fpic или -fPIC . Обе опции
приводят к генерации позиционно-независимого кода, что необходимо для
создания совместно используемых реентерабельных библиотек. Если указать
опцию -fpic , компоновщик создаст глобальную таблицу смещений маленького размера, поэтому для библиотек большого размера применяют -fPIC .
Если
компоновщик выдает сообщение об ошибке "relocation overflow"
("переполнение при модификации адресов"), проверьте, не была ли сборка
сделана с опцией -fpic . Если это так, замените ее на -fPIC ,
и проблема должна исчезнуть. Обратите внимание, что нельзя смешивать
использование обеих опций при компиляции одного и того же приложения.
Реализация операций с плавающей запятой контролируется опциями -mfused-madd , -mno-fused-madd , -mhard-float и -msoft-float . Полное описание архитектуры и набора команд System z можно найти в руководствах Архитектура z и Принципы работы платформы ESA/390. Также имеется техническая документация , где детально описаны внутренние механизмы GCC, лежащие в основе генерации кода для System z:
- "Компилятор 64-разрядного языка PL8 от GNU: на пути к разработке микропрограмм в открытой среде".
- "Портирование GCC на платформу IBM S/390".
- "Вклад в развитие компиляторов GNU".
Отладка
В
Linux доступно множество средств отладки. Одно из наиболее
функциональных -- отладчик GDB (GNU debugger, отладчик GNU). Существует
также графическая оболочка для GDB под названием Data Display Debugger,
которая может, например, представлять в наглядном виде связные списки.
Полезны
программы для анализа ошибок при работе с памятью. Так, для многих
платформ имеется утилита Electric Fence, способная выявлять нарушения
при работе с динамической памятью.
Еще один мощный
инструмент -- VALGRIND. Способность отлаживать программу даже при
отсутствии отладочной информации и исходных кодов делает его поистине
незаменимым. Это достигается специальным методом динамической инспекции
кода.
Можно также использовать опцию MUDFLAP ,
которая заставляет GCC вставлять в исполняемую программу проверочный
код, отслеживающий все важные операции с памятью. Диагностика MUDFLAP весьма информативна, так как проверочный код снабжается информацией об исходном коде.
При запуске Linux внутри виртуальной машины мэйнфрейма имеется мощная команда TRACE , предоставляющая удобные средства для отладки Linux-системы целиком.
Основы отладки изложены в книге Linux на мэйнфрейме, где можно найти подробные сведения об отладке в Linux, взятые из файла /usr/src/linux/Documentation/s390/debugging390.txt.
При
отладке таких серьезных вещей как использование регистров или
организация стекового фрейма вам помогут материалы и стандарты,
изложенные в Приложении к двоичному интерфейсу ELF-программ. Кроме того, в руководстве Портирование GCC на платформу IBM S/390 приведены стандарты, характерные для компиляции под System z.
Желаю вам успеха в портировании ваших Linux-проектов.
|