Информатика, вычислительная техника и управление
УДК 004.272
DOI: 10.14529/cmsel60404
ОПТИМИЗАЦИЯ ОБНАРУЖЕНИЯ КОНФЛИКТОВ В ПАРАЛЛЕЛЬНЫХ ПРОГРАММАХ С ТРАНЗАКЦИОННОЙ
ПАМЯТЬЮ*
© 2016 г. И.И. Кулагин1, М.Г. Курносов2
1 Сибирский государственный университет телекоммуникаций и информатики (630102 Новосибирск, ул. Кирова. д. 86), 2 Санкт-Петербургский государственный электротехнический университет «ЛЭТИ» имени В. И. Ульянова (Ленина) (197376 Санкт-Петербург, ул. Профессора Попова, д. 5) E-mail: ivan.i.kulagin@gmail.com, mkurnosov@gmail.com, Поступила в редакцию: 10.03.2016
В настоящее время активно развивается альтернативный подход к созданию масштабируемых и по-токобезопасных параллельных программ для многопроцессорных систем с общей памятью — технология транзакционной памяти (transactional memory). Ожидается, что она войдет в стандарт языка С++17. В данной работе предложен метод оптимизации обнаружения конфликтов (конкурентного доступа потоков к общим областям памяти), возникающих при выполнении параллельных программ на базе транзакционной памяти. Реализован модуль компилятора GCC для профилирования параллельных программ и адаптивной настройки параметров реализации транзакционной памяти под программу. Эффективность метода исследована на тестовых программах из пакета STAMP.
Ключевые слова: программная транзакционная память, параллельное программирование, профилирование, компиляторы.
Кулагин И.И., Курносов М.Г. Оптимизация обнаружения конфликтов в параллельных программах с транзакционной памятью // Вестник ЮУрГУ. Серия: Вычислительная математика и информатика. 2016. Т. 5, № 4. С. 46-60. DOI: 10.14529/cmsel60404.
Введение
Синхронизация доступа к разделяемым ресурсам является одной из важных и сложных задач при разработке параллельных алгоритмов для многопоточных программ. Используя примитивы синхронизации (семафоры, мыотексы и др.), программист должен обеспечить не только корректность программы — отсутствие взаимных блокировок (deadlock, livelock) и состояний гонок за данными (data race), но и минимизировать время ожидания доступа к критическим секциям (разделяемым ресурсам). Классические методы синхронизации, основанные на механизме блокировок, позволяют создавать в коде программы критические секции, выполнение которых возможно только одним потоком в каждый момент времени [1]. Такие примитивы синхронизации позволяют защитить участок кода программы, одновременно выполняющийся множеством потоков.
""Статья рекомендована к публикации программным комитетом Международной научной конференции «Параллельные вычислительные технологии — 2016».
ОБРАЗЕЦ ЦИТИРОВАНИЯ
Анализ многопоточиых программ показывает, что при одновременном выполнении потоками одной критической секций в ней может происходить обращения по разным адресам памяти и, следовательно, возникновение состояния гонки данных маловероятно. Например, такая ситуация наблюдается, если в критическую секцию помещен код добавления элемента в хеш-таблицу (рис. 1). Если все потоки в один момент времени обратятся к функции для добавления нового элемента с хеш-кодом г, то с большой долей вероятности ключи key будут иметь разные хеш-коды и, как следствие, каждый поток будет выполнять добавление нового узла в отдельный связный список /г[г]. Здесь блокировка мыотексом всей функции является избыточной и неэффективной.
function hashtable_add(h, key, value) lock_acquire() i = hash(key)
list_add_front(h[i], key, value) lock_release() end function
Рис. 1. Добавление пары (key, value) в хеш-таблиц}' h
Активно развиваются два альтернативных подхода к созданию потокобезопасных и масштабируемых многопоточных программ — это неблокирующие алгоритмы и структуры данных (lock-free data structures) [2] и транзакционная память (ТП, transactional memory) [3, 4]. Использование неблокирующих структур данных, как правило, требует глубокой переработки многопоточных программ и совместно используемых потоками объектов в памяти [2].
Менее трудоемким и прозрачным для программиста видится использование технологии транзакциопной памяти, основная идея которой заключается в защите от конкурентного доступа области памяти программы, а не участка кода, как в случае использования блокировок на базе мыотексов. Известны как программные реализации транзакциопной памяти (software transactional memory - STM): LazySTM, TinySTM, GCC TM, DTMC, RSTM, STMX, STM Monad, так и аппаратные реализации в процессорах (hardware transactional memory): Intel TSX, AMD ASF, Oracle Rock, IBM POWER8, IBM PowerPC A2.
В рамках программной транзакциопной памяти программисту предоставляются языковые конструкции или API для формирования в программе т,ранзакционных секций (transactional section) — участков кода, в которых осуществляется защита совместно используемых областей памяти. Выполнение потоками таких секций осуществляется без их блокирования. На среду выполнения (runtime) ложатся задачи по контролю за корректностью выполнения транзакций. Если во время выполнения транзакции другие потоки одновременно с ней не модифицировали защищенную область памяти, то транзакция считается корректной, и она фиксируется. Если же два или более потока при выполнении транзакций обращаются к одной и той же области памяти и как минимум один из них выполняет операцию записи, то возникает конфликт (аналог состояния гонки данных). Для его разрешения выполнение одной или нескольких транзакций может быть либо приостановлено (до завершения конфликтующей транзакции), либо прервано, а все модифицированные ими (их потоками) области памяти приведены в исходное состояние (на момент старта транзакции) - от,мена т,ранзакции и восстановление (cancel and rollback).
Для того чтобы обнаруживать конфликты, runtime-система должна отслеживать попытки одновременного доступа к одной и той же области памяти. Это реализуется путем поддержки информации о состоянии защищаемых регионов памяти. Возможны два уровня гранулярности контролируемых областей: уровень программных объектов (object-based STM) и уровень слов памяти (word-based STM).
Уровень программных объектов подразумевает поддержку runtime-системой метаданных о состоянии каждого объекта программы. Например, объектов в С++-программе.
Для реализации уровня слов памяти в простейшем случае требуется каждый байт линейного адресного пространства процесса сопровождать метаданными, что является практически невозможным. Вместо этого линейное адресное пространство процесса разбивается на фиксированные блоки, каждый из которых сопровождается метаданными о состоянии (подход, подобный прямому отображению физических адресов на кеш-память процессора) [5, 6]. Это приводит к тому, что множеству областей памяти соответствуют одни метаданные, что является источником возникновения ложных конфликтов. Ложный конфликт, (false conflict)— это ситуация, при которой два или более потока во время выполнения транзакции обращаются к разным участкам линейного адресного пространства, но отображаемым на одни и те же метаданные. Поэтому runtime-система воспринимает такую ситуацию как конфликт (data race), хотя на самом деле таковой отсутствует.
Ложные конфликты существенно снижают эффективность параллельных STM-программ. Поэтому остро стоит задача разработки алгоритмов обнаружения и сокращения числа ложных конфликтов в реализациях STM.
В данной работе предлагается метод оптимизации ложных конфликтов по результатам предварительного профилирования C/C++ STM-программы. Для чего разработан программный инструментарий, который позволяет выполнять профилирование STM-программ и варьировать параметры реализации runtime-библиотеки STM в компиляторе
GCC (libitm).
Работа организована следующим образом. Раздел 1 вводит основные понятия связанные с программной транзакционной памятью, содержит примеры использования данного примитива синхронизации, описывает основные аспекты реализации STM в runtime-системах, а также содержит описание предложенного метода сокращения числа ложных конфликтов. Раздел 2 раскрывает детали реализации программного инструментария для оптимизации ложных конфликтов, возникающих при выполнении параллельных программ с транзакционной памятью. В разделе 3 показаны основные результаты экспериментального исследования предложенного метода оптимизации ложных конфликтов.
1. Метод оптимизации обнаружения конфликтов
Международным комитетом ISO по стандартизации языка С++, в рамках рабочей группы WG21, ведутся работы по внедрению транзакционной памяти в стандарт языка. Окончательное внедрение планируется в стандарт С++17. На сегодняшний день предложен черновой вариант спецификации поддержки транзакционной памяти в С++ [7]. Она реализована в компиляторе GCC, начиная с версии 4.8 и предоставляет ключевые слова __transaction_atomic,__transaction_relaxed для создания транзакционных секций, а
также__transaction_cancel для принудительной отмены транзакции.
Для выполнения транзакционных секций runtime-системой создаются транзакции. Транзакция (transaction) — это конечная последовательность операций транзакционного
чтения/записи памяти. Операция транзакционного чтения выполняет копирование содержимого указанного участка общей памяти в соответствующий участок локальной памяти потока. Транзакционная запись копирует содержимое указанного участка локальной памяти в соответствующий участок общей памяти, доступной всем потокам.
Инструкции транзакций выполняются потоками параллельно (конкурентно). После завершения выполнения транзакция может быть либо зафиксирована (commit), либо отменена (cancel). Фиксация транзакции подразумевает, что все сделанные в рамках нее изменения памяти становятся необратимыми. При отмене транзакции ее выполнение прерывается, а состояние всех модифицированных областей памяти восстанавливается в исходное с последующим перезапуском транзакции (откат, транзакции, rollback).
Отмена транзакции происходит в случае обнаружения конфликта — ситуации, при которой два или более потока обращаются к одному и тому же участку памяти и как минимум один из них выполняет операцию записи.
Для разрешения конфликта разработаны различные походы, например, можно приостановить на некоторое время или отменить одну из конфликтующих транзакций.
На рис. 2 представлен пример создания транзакциопной секции, в теле которой выполняется добавление элемента в хэш-таблицу множеством потоков. После выполнения тела транзакциопной секции каждый поток приступит к выполнению кода, следующего за ней, в случае отсутствия конфликтов. В противном случае поток повторно будет выполнять транзакцию до тех пор, пока его транзакция не будет успешно зафиксирована.
/* Совместно используемая хеш-таблица */ hashtable_t *h; /* Код потоков */ void *thread_start(void *arg) {
struct data *d = (struct data *)arg; prepareData(d); /* Транзакционная секция */
__transaction_atomic {
/* Добавление элемента в хеш-таблицу */ struct data *d = (struct data *)arg; hashtable_insert(h, d);
}
saveData(d); return NULL;
}
Рис. 2. Добавление пары (key.value) в хеш-таблицу h
Основными аспектами реализации транзакциопной памяти в runtime-системах являют-
• политика обновления объектов в памяти;
• стратегия обнаружения конфликтов;
• метод разрешения конфликтов.
Политика обновления объектов в памяти определяет, когда изменения объектов в рамках транзакции будут записаны в память. Распространение получили две основные политики — ленивая и ранняя. Ленивая политика обновления объектов в памяти (lazy version management) откладывает все операции с объектами до момента фиксации транзакции.
Все операции записываются в специальном журнале (redo log), который при фиксации используется для отложенного выполнения операций. Очевидно, что это замедляет операцию фиксации, но существенно упрощает процедуры ее отмены и восстановления. Примером реализаций ТП, использующих данную политику, являются RSTM-LLT [8] и RSTM-RingSW [9, 11].
Ранняя политика обновления (eager version management) предполагает, что все изменения объектов сразу записываются в память. В журнале отката (undo log) фиксируются все выполненные операции с памятью. Он используется для восстановления оригинального состояния модифицируемых участков памяти в случае возникновения конфликта. Эта политика характеризуется быстрым выполнением операции фиксации транзакции, но медленным выполнением процедуры ее отмены. Примерами реализаций, использующих раннюю политику обновления данных, являются GCC (libitm), TinySTM [5], LSA-STM [6], Log-TM [10], RSTM [8] и др.
Момент времени, когда инициируется алгоритм обнаружения конфликта, определяется стратегией обнаружения конфликтов. При отложенной стратегии (lazy conflict detection) алгоритм обнаружения конфликтов запускается на этапе фиксации транзакции [11]. Недостатком этой стратегии является то, что временной интервал между возникновением конфликта и его обнаружением может быть достаточно большим. Эта стратегия используется в RSTM-LLT [8] и RSTM-RingSW [8, 9, 11].
Пессимистичная стратегия обнаружения конфликтов (eager conflict detection) запускает алгоритм их обнаружения при каждой операции обращения к памяти. Такой подход позволяет избежать недостатков отложенной стратегии, но может привести к значительным накладным расходам, а также, в некоторых случаях, может привести к увеличению числа откатов транзакций. Стратегия реализована в TinySTM [5], LSA-STM [6] и TL2 [12]. В компиляторе GCC (libitm) реализован комбинированный подход к обнаружению конфликтов
— отложенная стратегия используется совместно с пессимистической.
Для обнаружения конфликтных операций требуется отслеживать изменения состояния используемых областей памяти. Информация о состоянии может соответствовать областям памяти различной степени гранулярности. Выбор гранулярности обнаружения конфликтов
- один из ключевых моментов при реализации программной транзакционной памяти.
На сегодняшний день используются два уровня гранулярности: уровень программных объектов (object-based STM) и уровень слов памяти (word-based STM). Уровень программных объектов подразумевает отображение объектов модели памяти языка (объекты С++, Java, Scala) на метаданные runtime-библиотеки. При использовании уровня слов памяти осуществляется отображение блоков линейного адресного пространства процесса на метаданные. Метаданные хранятся в таблице, каждая строка которой соответствует объекту программы или области линейного адресного пространства процесса. В строке содержатся номер транзакции, выполняющей операцию чтения/записи памяти; номер версии отображаемых данных; их состояние и др. Модификация метаданных выполняется runtime-системой с помощью атомарных операций процессора.
В данной работе рассматривается реализация программной транзакционной памяти в компиляторе GCC, использующая уровень слов памяти (в версиях GCC 4.8+ размер блока -16 байт).
На рис. 3 представлен пример организации метаданных транзакционной памяти с использованием уровня слов памяти (GCC 4.8+). Линейное адресное пространство процес-
са фиксированными блоками циклически отображается на строки таблицы, подобно кешу прямого отображения. Выполнение операции записи приведет к изменению поля «состояние» соответствующей строки таблицы на «заблокировано». Доступ к области линейного адресного пространства, у которой соответствующая строка таблицы помечена как «заблокировано», приводит к конфликту.
Линейное адресное проетранетво процесса
0X0. .0 I Метаданные о состоянии oo.iacieii мамяш процесса
0x1. .0 1
0x2. .0 Состояние Владелец
0x3. .0 Состояние Владелец
0Х. . 1 Состояние Владелец
0Х. . 1 Состояние Владелец
1
0xF. . F 1
Рис. 3. Таблица с метаданными GCC 4.8+ (word-based STM): В = 16, S = 219
Основными параметрами транзакционпой памяти с использованием уровня слов памяти являются число S строк таблицы и количество В адресов линейного адресного пространства, отображаемых на одну строку таблицы. От выбора этих параметров зависит число ложных конфликтов — ситуаций аналогичных ситуации ложного разделения данных при работе кеша процессора. В текущей реализации GCC (4.8-5.1) эти параметры фиксированы [13].
При отображении блоков линейного адресного пространства процесса на метаданные runtime-библиотеки возникают коллизии. Это неизбежно, так как размер таблицы метаданных гораздо меньше размера линейного адресного пространства процесса. Коллизии приводят к возникновению ложных конфликтов. Ложный конфликт — ситуация, при которой два или более потока во время выполнения транзакции обращаются к разным участкам линейного адресного пространства, но сопровождаемым одними и теми же метаданными о состоянии, и как минимум один поток выполняет операцию записи. Таким образом, ложный конфликт — это конфликт, который происходит не на уровне данных программы, а на уровне метаданных runtime-библиотеки.
Возникновение ложных конфликтов приводит к откату транзакций так же, как и возникновение обычных конфликтов, несмотря на то что состояние гонки за данными не возникает, что влечет за собой увеличение времени выполнения STM-программ. Сократив число ложных конфликтов, можно существенно уменьшить время выполнения программы.
На рис. 4 показан пример возникновения ложного конфликта в результате коллизии отображения линейного адресного пространства на строку таблицы. Поток 1 при выполнении операции записи над областью памяти с адресом А1 захватывает соответствующую строку таблицы. Выполнение операции чтения над областью памяти с адресом А2 потоком 2 приводит к возникновению конфликта, несмотря на то что операции чтения и записи выполняются над различными адресами. Последнее обусловлено тем, что 1 и 2 отображены на одну строку таблицы метаданных.
Поток 1
/* Транзакция 1 */
_transaction_atomic {
globalB++;
}
Поток 2
/* Транзакция 2 */
_transaction_atomic {
tmp = globalA;
}
Линейное адресное пространство процесса
А1
0X1. . 0x2.. 0x3.. 0х... Эх...
А2 0xF...F
globalB
globalA
Метаданные о состоянии областей памяти процесса
Сое юн и не Владелец
'Заблокировано Транзакция 1
Рис. 4. Пример возникновения ложного конфликта при выполнении двух транзакций (GCC 4.8+)
В работе [14] для минимизации числа ложных конфликтов предлагается использовать вместо таблицы с прямой адресацией (как в GCC 4.8+), в которой индексом является часть линейного адреса, хеш-таблицу, коллизии в которой разрешаются методом цепочек. В случае отображения нескольких адресов на одну запись таблицы каждый адрес добавляется в список и помечается тэгом для идентификации (рис. 5). Такой подход позволяет избежать ложных конфликтов, однако накладные расходы на синхронизацию доступа к метаданным существенно возрастают, так как значительно увеличивается количество атомарных операций «сравнение с обменом» (compare and swap — CAS).
0X0. 0X1. 0X2. 0x3. 0X. . 0x5. 0x, . 0xF.
Линейное адресное пространство процесса
0
Метаданные о состоянии областей памяти процесса
Хеш Состояние Владелец Тег Указатель
0 NULL-
1 0x2 Укн-мтшм.
\U1.L
S- 1 0x1 NULL
Состояние Владелец 0x5 NULL
Рис. 5. Хеш-таблица для хранения метаданных
Авторами предложен метод, позволяющий сократить число ложных конфликтов в STM-программах. Предполагается, что метаданные организованы в виде таблицы с прямой адресацией. Суть метода заключается в автоматической настройке параметров S и В таблицы под динамические характеристики конкретной STM-программы. Метод включает три этапа.
Этап 1. Внедрение функций библиотеки профилирования в транзакционные секции. На первом этапе выполняется компиляция C/C++ STM-программы с использованием разработанного модуля анализа транзакционных секций и внедрения вызова функций библиотеки профилирования (модуль расширения GCC). В ходе статического анализа транзакционных секций STM-программ выполняется внедрение кода для регистрации обращений
к функциям Intel ТМ ABI (_ITM_beginTransaction, _ITM_comitTransaction, _ITM_LU4, _ITM_WU4 и др.). Детали реализации модуля описаны ниже.
Этап 2. Профилирование программы. На данном этапе выполняется запуск STM-программы в режиме профилирования. Профилировщик регистрирует все операции чтения/записи памяти в транзакциях. В результате формируется протокол (trace), содержащий информацию о ходе выполнения транзакционных секций:
• адрес и размер области памяти, над которой выполняется операция;
• временная метка (timestamp) начала выполнения операции.
Этап 3. Настройка параметров таблицы. По протоколу определяются средний размер W читаемой/записываемой области памяти во время выполнения транзакций. По значению W подбираются субоптимальиые параметры В и S таблицы, с которыми STM-программа компилируется. Эксперименты с тестовыми STM-программами из пакета STAMP (6 типов STM-программ) позволили сформулировать эвристические правила для подбора параметров В и S по значению W. Значение параметра S целесообразно выбирать из множества {218,219,220.221}. Значение параметра В выбирается следующим образом:
• если W = 1 байт, то В = 24 байт;
• если W = 4 байт, то В = 26 байт;
• если W = 8 байт, то В = Т байт;
• если W >= 64 байт, то В = 28 байт.
2. Программный инструментарий для сокращения ложных конфликтов
Авторами разработан программный инструментарий (STM false conflict optimizer) для оптимизации ложных конфликтов, возникающих при выполнении параллельных программ с транзакциопной памятью. Инструментарий позволяет выполнять профилирование STM-программ. Информация, полученная в результате профилирования, предоставляет достаточно сведений о динамических характеристиках транзакционных секций для того, чтобы ответить на вопрос: «Фиксации каких транзакций или операции над какими данными приводят к отмене других транзакций?». Кроме этого, разработанное программное средство позволяет определить значения субоптимальных значений параметров реализации runtime-системы ТП, а именно число строк таблицы метаданных о состоянии областей памяти и количество адресов линейного адресного пространства, отображаемых на одну строку таблицы.
2.1. Функциональная структура пакета
Программный инструментарий состоит из трех основных компонентов (рис. б):
• модуль внедрения функций библиотеки профилирования в код транзакционных секций (tm_prof _analyzer)\
• библиотека профилирования параллельной программы с транзакциопной памятью
(ilibiim_proJ)\
• модуль анализа протокола выполнения транзакционных секций, установки значений параметров реализации (tm_proto_analyzer).
Рис. 6. Функциональная структура разработанного пакета; 1 — компиляция STM-программы; 2 — запуск STM-программы под управление профилировщика; 3 — обращение к функциям профилировщика
2.2. Внедрение функций профилировщика
STM-компилятор осуществляет трансляцию транзакционных секций в последовательность вызовов функций runtime-системы поддержки ТМ [15]. Компания Intel предложила спецификацию ABI для runtime-систем поддержки транзакционной памяти Intel ТМ ABI [16]. Компилятор GCC, библиотека libitm, реализует этот интерфейс начиная с версии 4.8. На рис. 7 представлен пример трансляции компилятором GCC транзакционной секции в обращения к функциям Intel ТМ ABI.
В общем случае последовательность выполнения транзакции следующая:
1. Создание транзакции (вызов _ITM_beginTransaction) и анализ ее состояния. Если состояние транзакции содержит флаг принудительной отмены, то выполнение продолжается с метки <L3>, т.е. осуществляется выход из транзакции, иначе выполнение тела транзакции начинается с метки <L2>.
2. Выполнение транзакции. Если выполняется принудительная отмена транзакции, то в состоянии устанавливается флаг принудительной отмены (a_abortTransaction) и управление передается метке <L1>.
3. Попытка фиксации транзакции (вызов _ITM_commitTransaction). В случае возникновения конфликта транзакция отменяется, в состояние транзакции записывается причина отмены и выполнение транзакции повторяется начиная с метки <L1>. Разработанный модуль tm_prof _analyzer внедрения функций библиотеки профилирования выполнен в виде встраиваемого модуля компилятора GCC. Программист компилирует STM-программу с ключом —fplugin = tm_prof_analyzer.so. Модуль внедрения выполняет анализ промежуточного представления GIMPLE транзакционных секций и добавляет функции регистрации обращений к функциям Intel ТМ ABI: регистрация начала транзакции и ее фиксации, транзакционное чтения/запись областей памяти.
int а, Ь; .. .
state = _ITM_beginTransaction()
__transaction_atomic { <L1>
if (а == 0) if (state & a.abortTransaction)
Ъ = 1; goto <L3>;
else else
а = 0; goto <L2>;
} <L2>
. .. if (_ITM_LU4(&a) == 0)
_ITM_WU4(&b, 1);
else
_ITM_WU4(&a, 0);
_ITM_commitTransaction();
<L3>
/♦Исходная Транзакционная секция*/ /♦Трансформированная транзакционная секция*/
Рис. 7. Трансляция транзакционной секции компилятором GCC; код слева — исходная транзакционная секция; код справа — промежуточное представление трансформированной транзакционной секции
На рис. 8 представлен пример внедрения вызовов функций библиотеки профилирования в транзакционпую секцию. Функции с префиксом tm_prof _ выполняют регистрацию событий.
Во время выполнения STM-программы под управлением профилировщика (libitm_prof), функции регистрации обращений к интерфейсам Intel ТМ ABI заносят в протокол адреса и размер областей памяти, над которыми выполняются операции, а также время начала выполнения операций. После завершения выполнения STM-программы формируется протокол выполнения программы, на основе которого модуль анализа (tm_proto_analyzer) осуществляет выбор субоптимальных параметров таблицы метаданных транзакционной памяти.
3. Эксперименты
Экспериментальное исследование проводилось на вычислительной системе, оснащенной двумя четырехъядерными процессорами Intel Xeon Е5420. В данных процессорах отсутствует поддержка аппаратной транзакционной памяти (Intel TSX). В качестве тестовых программ использовались многопоточные STM-программы из пакета STAMP [9, 11, 12]. Число потоков варьировалось от 1 до 8. Тесты собирались компилятором GCC 5.1.1. Операционная система GNU/Linux Fedora 21 х86_64.
В рамках экспериментов измерялись значения двух показателей:
• время I выполнения STM-программы;
• количество С ложных конфликтов в программе.
На рис. 9а, 9b, 10а, 10Ь показана зависимость количества С ложных конфликтов и времени I выполнения теста от числа потоков при различных значениях параметров В и S. Результаты приведены для программы genome из пакета STAMP. В ней порядка 10 транзак-ционных секций, реализующих операции над хеш-таблицей и связными списками. Видно, что увеличение значений параметров S и В приводит к уменьшению числа возможных кол-
int a, b; ...
state = _ITM_beginTransaction()
__transaction_atomic { tm_prof_begin(state);
if (a == 0) <L1>:
b = 1; if (state & a.abortTransaction)
else goto <L3>;
a = 0; else
} goto <L2>;
<L2>:
tm.prof_operation(sizeof(a)); if (_ITM_LU4(&a) == 0) {
tm_prof.operation(sizeof(b)); _ITM_WU4(&b, 1); } else {
tm_prof.operation(sizeof(a)); _ITM_WU4(&a, 0);
}
_ITM_commitTransaction(); tm_prof_commit();
<L3>:
/*Исходная Транзакционная секция*/ /*Трансформированная транзакционная секция*/
Рис. 8. Встраивание в транзакционную секцию функций библиотеки профилирования; код слева — исходная транзакционная секция; код справа — промежуточное представление трансформированной транзакциопной секции
лизий (ложных конфликтов), возникающих при отображении адресов линейного адресного пространства процесса на записи таблицы. При размере таблицы 221 записей, на каждую из которых отображается 26 адресов линейного адресного пространства, достигается минимум времени выполнения теста genome, а также минимум числа ложных конфликтов.
С
500000 450000 400000 350000 300000 250000 200000 150000 100000 50000 0
1 2 3 4 5 N
700000 600000 500000 400000 300000 200000 100000 0
1 2345678 N
(a) S- 2И)
Рис. 9. Зависимость числа С ложных конфликтов от числа N потоков
Время выполнения теста genome удалось сократить в среднем на 20% за счет минимизации числа ложных конфликтов.
(a) S — 219
(Ь) В ■
оО
Рис. 10. Зависимость времени I выполнения теста от числа N потоков
Заключение
Основным вкладом данной работы является метод оптимизации параметров внутренних структур данных runtime-библиотеки транзакционной памяти компилятора GCC (libitm) под конкретное приложение. Создан программный инструментарий сокращения числа ложных конфликтов в STM-программах. Программный инструментарий позволяет осуществлять инструментацию и профилирование параллельных STM-программ. Результаты профилирования показывают хронологию выполнения транзакций. В данной работе результаты профилирования используются только для выбора значений параметров реализации runtime-библиотеки транзакционной памяти, однако, они могут быть использованы и для других целей, например, для выбора политика обновления объектов в памяти и стратегии обнаружения конфликтов.
Предложенный метод был экспериментально исследован на тестовых программах из пакета STAMP. Эксперименты показали, что применяя разработанный метод, время выполнения теста genome удалось сократить на 20% за счет минимизации числа ложных конфликтов.
В дальнейшем планируется разработать алгоритм реализаций программной транзакционной памяти без централизованного хранения метаданных о состоянии областей памяти процесса.
Работа выполнена в СПбГЭТУ при финансовой поддержке Министерства образования и науки Российской Федерации в рамках договора № 02.G25.31.0149 от, 01.12.2015 г.
Литература
1. Herlihy М., Shavit N. The Art of Multiprocessor Programming. Morgan Kaufmann Publishers Inc., San Francisco, CA, USA, 2008. 508 p.
2. Hendler D., Shavit N., Yerushalmi L. A scalable lock-free stack algorithm // Proceedings of the sixteenth annual ACM symposium on Parallelism in algorithms and architectures. 2004. P. 206-215.
3. Кузнецов С.Д. Транзакциоиная память. URL: www.citforum.ru/programming/digest/ transactional_memory/ (дата обращения: 21.06.2016).
4. Shavit N., Touitou D. Software Transactional Memory // Proceedings of the fourteenth annual
ACM symposium on Principles of distributed computing. Aug. 1995. New York, NY, USA, P. 204-213.
5. Felber P., Fetzer C.,Marlier P., Riegel T. Time-based Software Transactional Memory // IEEE Transactions on Parallel and Distributed Systems. December 2010. Vol. 21, Issue 12. P. 1793-1807.
6. Riegel Т., Felber P., Fetzer C. A Lazy Snapshot Algorithm with Eager Validation // 20th International Symposium on Distributed Computing. 2006.
7. Luchango V., Maurer J., Moir M. Transactional memory for С-Ы-. URL: http://www.open-std.org/jtcl/sc22/wg21/docs/papers/2013/n3718.pdf (дата обращения: 21.06.2016).
8. Scott M.L. Rochester Software Transactional Memory Runtime. URL: wTww.cs.rochester.edu/research/synchronization/rstm/ (дата обращения: 21.06.2016).
9. Spear M.F., Dalessandro L., Marathe V.J., Scott M.L. A comprehensive strategy for contention management in software transactional memory // Proc. 14th ACM SIGPLAN Symposium on Principles and Practice of Parallel Programming. February 2009. P. 141-150.
10. Moore K.E., Bobba J., Moravan M.J., Hill M.D., Wood D.A. LogTM: Log-based transactional memory // Proceedings of the 12th International Symposium on High-Performance Computer Architecture. February 2006. P. 254-265.
11. Spear M.F., Michael M.M., Praun C. RingSTM: scalable transactions with a single atomic instruction // Proceedings of the 20th Annual Symposium on Parallelism in Algorithms and Architectures. June 2008. P. 275-284.
12. Dice D., Shalev O., Shavit N. Transactional locking II // Proceedings of the 20th International Symposium on Distributed Computing. September 2006. Vol. 4167. P. 194-208.
13. Felber P., Fetzer C., Riegel T. Dynamic performance tuning of word-based software transactional memory // Proceedings of the 17th ACM SIGPLAN Symposium on Principles and Practice of Parallel Programming. 2008. P. 237-246.
14. Zilles C., Rajwar R. Implications of false conflict rate trends for robust software transactional memory. URL: http://zilles.cs.illinois.edu/papers/tm_false_conflicts.iiswTc2007.pdf (дата обращения: 21.06.2016).
15. Olszewski M., Cutler J., Steffan J.G. JudoSTM: A Dynamic Binary-Rewriting Approach to Software Transactional Memory // Proceedings of the 16th International Conference on Parallel Architecture and Compilation Techniques. 2007. P. 365-375.
16. Intel Corporation. Intel Transactional Memory Compiler and Runtime Application Binary Interface. URL: ht tps: / / software.intel.com/sites / default/files/m/5/a/2/a/f/809 7-Intel_TM_ABI_l_0_l.pdf (дата обращения: 21.06.2016)
DOI: 10.14529/cmsel60404
OPTIMIZATION OF CONFLICT DETECTION IN PARALLEL PROGRAMS WITH TRANSACTIONAL MEMORY
© 2016 I.I. Kulagin1, M.G. Kurnosov2
1 Siberian State University of Telecommunications and Information Science (Kirova 86,
Novosibirsk, 630102 Russia), 2Saint-Petersburg Electrotechnical University "LETI"(Professora Popova 5,
St. Petersburg, 197376 Russia) E-mail: wan.i.kulagin@gmail.com, mkurnosov@gmail.com Received: 10.03.2016
Transactional memory is a perspective abstraction for the creating a scalable parallel programs for multi-core systems. It will be included in C-f-1-17. In this work, are proposed optimization method of conflicts detection, that accur in parallel programs with the software transactional memory during execution. The autors have implemented a module for GCC compiler for profiling parallel programs with software transactional memory and a tool for adaptive tuning runtime-library. The efficiency of method is investigated on the STAMP benchmarks.
Keywords: software transactional memory, parallel programming, profiling, compilers.
FOR CITATION
Kulagin I.I., Kurnosov M.G. Optimization of Conflict Detection in Parallel Programs with Transactional Memory. Bulletin of the South Ural State University. Series: Computational Mathematics and Software Engineering. 2016. vol. 5, no. 4. pp. 46-60. (in Russian) DOI: 10.14529/cmsel60404.
References
1. Herlihy M., Shavit N. The Art of Multiprocessor Programming. Morgan Kaufmann Publishers Inc., San Francisco, CA, USA, 2008. 508 p.
2. Hendler D., Shavit N., Yerushalmi L. A Scalable Lock-free Stack Algorithm. Proceedings of the Sixteenth Annual ACM Symposium on Parallelism in Algorithms and Architectures. 2004. pp. 206-215. DOI: 10.1145/1007912.1007944.
3. Kuznetsov S.D. Transaktsionnaya pam,at [Transactional Memory]. Available at: http://citforum.ru/programming/digest/transactional_memory/ (accessed: 21.06.2016).
4. Shavit N., Touitou D. Software Transactional Memory. Proceedings of the Fourteenth Annual ACM Symposium on Principles of Distributed Computing. Aug. 1995. New York, NY, USA. pp. 204-213. DOI: 10.1145/224964.224987.
5. Felber P., Fetzer C.,Marlier P., Riegel T. Time-based Software Transactional Memory. IEEE Transactions on Parallel and Distributed Systems. December 2010. vol. 21, issue 12. pp. 1793-1807. DOI: 10.1109/TPDS.2010.49.
6. Riegel Т., Felber P., Fetzer C. A Lazy Snapshot Algorithm with Eager Validation. 20th International Symposium on Distributed Computing. 2006. DOI: 10.1007/11864219_20.
7. Luchango V., Maurer J., Moir М. Transactional Memory for С++. Available at: http://www.open-std.org/jtcl/sc22/wg21/docs/papers/2013/n3718.pdf (accessed: 21.06.2016).
8. Scott M.L. Rochester Software Transactional Memory Runtime. Available at: www.cs.rochester.edu/research/synchronization/rstm/ (accessed: 21.06.2016).
0. Spear M.F., Dalessandro L ., Marat he V.J., Scott M.L. A Comprehensive Strategy for Contention Management in Software Transactional Memory. Proc. Utth ACM SIGPLAN Symposium on Principles and Practice of Parallel Programming- February 2000. pp. 141-150. DOI: 10.1145/1594835.1504199.
10. Moore K.E., Bobba J., Moravan M.J.. Hill M.D., Wood D.A. Log I'M: Log-based Transactional Memory. Proceedings of the 12th International Symposium on High-Performance Computer Architecture. February 2006. pp. 254 -265. DOI: 10.1109/НРСА.2006.Ш8134.
11. Spear M.F.j Michael M.M., Praun C. RingSTM: Scalable Transactions with a Single Atomic Instruction. Proceedings of the 20th Annual Symposium on Parallelism in Algorithms and Architectures. June 2008. pp. 275-284. DOI: 10.1145/1378533.1378583.
12. Dice D., Shalev O., Shavit N. Transactional Locking II. Proceedings of the 20th International Symposium on Distributed Computing. September 2006. vol. 4167. pp. 104-208. DOI: 10.1007/11864210 _ 14.
13. Felber P., Fetzer C., Riegel T. Dynamic Performance Timing of Word-based Software Transactional Memory. Proceedings of the 17th ACM SIGPLAN Symposium on Principles and Practice of Parallel Programming. 2008. pp. 237-246. DOI: 10.1145/1345206.1345241.
14. Zilles C., Rajwar R.. Implications of False Conflict Rate Trends for Robust Software Transactional Memory. Available at: http://zilles.cs.illinois.edu/papers/ tm_fabe_conflicts.iiswc2007.pdf (accessed: 21.06.2016).
15. Olszewski M., Cutler J., Steffan J.G. JudoSTM: A Dynamic Binary-Rewriting Approach to Software Transactional Memory. Proceedings of the 16th International Conference on Parallel Architecture and Compilation Techniques. 2007. pp. 365-375. DOI: 10.-Ш9/РАСТ.2007.4336226.
16. Intel Corporation. Intel Transactional Memory Compiler and Runtime Application Binary Interface. Available at: https://software.intel.com/sites/default/files / m/5/a/2 / a/f/8007-Intel_TM_ABI_l_0_l.pdf (accessed: 21.06.2016)