Научная статья на тему 'Статическое обнаружение гонок в коде, содержащем ветвления и циклы'

Статическое обнаружение гонок в коде, содержащем ветвления и циклы Текст научной статьи по специальности «Математика»

CC BY
110
20
i Надоели баннеры? Вы всегда можете отключить рекламу.
Журнал
Прикладная информатика
ВАК
RSCI
Область наук
Ключевые слова
МНОГОПОТОЧНОЕ ИСПОЛНЕНИЕ / СОСТОЯНИЕ ГОНКИ / СТАТИЧЕСКИЙ АНАЛИЗ / STATIC ANALYSIS / MULTIPROCESSING / CONCURRENT EXECUTION / DATA-RACE

Аннотация научной статьи по математике, автор научной работы — Заборовский Н.В., Тормасов А.Г.

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

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

Static detection of races in code that contains loops and branching

Today analyzing data-races is a relevant problem because of complex architecture of the modern programs. The article introduces the model of concurrent threads execution that alows analyzing data-races statically. Target algorithms for the model are ones containing custom synchronization machinery and atomic operations. As opposed to known models of a concurrent execution the suggested model analyze the code at a lower level of instructions.

Текст научной работы на тему «Статическое обнаружение гонок в коде, содержащем ветвления и циклы»

№ 6 (36) 2011

Н. В. Заборовский, аспирант Московского физико-технического института

(государственного университета)

А. Г. Тормасов, докт. физ.-мат. наук, профессор Московского физико-технического института

(государственного университета)

Статическое обнаружение гонок в коде, содержащем ветвления и циклы

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

Введение

Состояние гонки — ситуация, когда состояние общей для нескольких потоков ячейки памяти зависит от распределения процессорного времени между потоками (фактически нельзя предугадать это состояние на уровне алгоритма — скорее всего, в реализации алгоритма ошибка). Используется статический подход к анализу: анализируется сам исходный код на 0/0++. Далее будет изложена методика, которая позволяет проанализировать код в статическом режиме и его обоснование. Модель, построенная на основе предлагаемого подхода, позволяет отслеживать ситуации гонки для одной из разделяемых переменных и может быть расширена, в частности, до анализа корректности организованных средствами языка критических секций.

Обзор методов

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

В работе [2] была предложена идея построения модели взаимного исполнения ато-

марных инструкций двумя потоками на разделяемой памяти и принцип ее анализа с целью определения состояния гонки. Общая процедура работы с исходным кодом для выявления состояний гонки выглядит следующим образом:

1. Для каждого потока выделяются операции с интересующими нас разделяемыми переменными.

2. Строится граф на основании операций с разделяемыми переменными.

3. На графе выделяются определенные пути, представляющие интерес для анализа.

4. Выделенные пути анализируются, например, с помощью метода неопределенных коэффициентов.

5. По состоянию в финальной вершине делается вывод о наличии гонок.

В основе модели лежит граф G = (V, А) совместного исполнения потоков, в котором путям соответствуют всевозможные варианты исполнения многопоточного алгоритма. Вершинам графа А соответствует множество состояний общей памяти после выполнения очередной инструкции, дугам V — атомарные операции над разделяемыми переменными. Каждому ребру приведена в соответствие операция (чтение/запись) и ячейка памяти, над которой производится операция.

Также для модели определена функция корректности, отражающая субъективное

№ 6 (36) 2011

понятие о корректном или некорректном исполнении программы. Одна и та же многопоточная программа корректна с точки зрения одной функции корректности и некорректна — с другой. Функцию корректности можно переформулировать в терминах частей графа G. К примеру, задача о нахождении неразрешенного состояния гонки может быть сведена к поиску двух различных путей на графе, приводящих к различным значениям одной из разделяемых переменных.

Граф G имеет вид ромба, в котором начальная вершина находится вверху, а конечная внизу, и все ребра имеют направление сверху вниз. Сильное место подхода — небольшая сложность анализа. Количество вершин на каждом из ребер ромба линейно по количеству операций, и каждая вершина проходится при анализе только один раз. Сложность подхода для двух потоков оценивается как О (к • л), где к и п — количество атомарных операций каждого из потоков. Важно заметить, что рассматриваются только операции с разделяемыми переменными.

Далее с построенным графом поступают следующим образом. Рассматривают произвольный путь на графе из начальной вершины в конечную. Такой путь описывает взаимную последовательность исполнения атомарных операций потоками. На графе есть вершины, из которых исходят ребра с операциями над разными ячейками памяти или только операциями чтения одной и той же разделяемой переменной. В этом случае считается, что из вершины можно двигаться по любому из исходящих ребер, т. к. на состояние памяти в финальном состоянии это не повлияет. В остальных случаях результат алгоритма будет зависеть от порядка исполнения инструкций — от того, какой путь из вершины избрать. При этом операции на ребрах называют не коммутирующими, а соответствующую ячейку графа отмечают крестом.

На данном наблюдении основывается построение классов эквивалентности — набо-

ры полных путей на графе G, для которых содержимое ячеек памяти в финальном состоянии одинаково.

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

В работе [2] понятие гонки вводится как существование двух разных полных путей, для которых в финальной вершине состояния хотя бы одной из ячеек памяти различны. Формулировка согласуется с функцией корректности, которая может быть выражена как количество различных векторов значений переменных в конечной вершине. Для анализа используется метод неопределенных коэффициентов: на каждом ветвлении добавляется коэффициент к изменению в левой ветви и (1 - а) — в правой. Значение каждой переменной финальной вершины описывается формулой:

X = ^ (х0,{а}),

(1)

где х0 — состояние всех ячеек памяти в начальной вершине; {а} — значения неопределенных коэффициентов. Исходя из определения понятия гонки и введенных принципов построения и анализа графа, условие гонки формулируется как

3/,{а}1,{а}2 : ^(Хо,{а^) ф ^(Хо,{а}2

(2)

где {а}1 и {а}2 — наборы бинарных коэффициентов, в которых хотя бы одна из компонент отличается.

Кроме того, приводятся рассуждения о том, какую сложность привносят в анализ такие конструкции кода, как ветвления и циклы.

Предлагается дополнить определение графа G, чтобы он работал также для ветвлений и циклов, но при этом использовал старые принципы анализа.

о

л

1 £

о

.Э со

со

Эй

39

№ 6 (36) 2011

Проблемы современных систем статического анализа

I. Ложные срабатывания

Для существующих в настоящее время программных средств статического анализа программ проблемой является ошибочное определение состояния гонки (false-positive) и не нахождение гонки при ее наличии (false-negative). Эта проблема неминуемо возникает при анализе программного кода из-за наличия циклов, ветвлений, псевдонимов и других конструкций, усложняющих его. Обычная практика для синтаксических анализаторов — использование набора эвристик для определения состояния гонки. Эвристики хорошо работают на элементарных тестах и модельных задачах, но показывают очень плохие результаты на реальных задачах.

В модели исполнения алгоритма в нескольких потоках сделана попытка учесть все возможные варианты исполнения путем введения не коммутирующих операций и классификации вариантов совместного з исполнения на их основе. Для определен-s£ ных задач анализ модели исполнения по-ss зволяет свести к нулю возможность ошиб-| ки false-negative (что очень важно). Однако | класс задач, для которых метод хорошо ра-

£ ботает, довольно узок. §

I II. Учет значений переменных

&

Ц Возьмем алгоритм взаимного исключе-

¡^ ния Петерсона. Критическая секция явля-

§ ется таковой за счет проверки значений

g переменных, ограничивающих исполнения

g для всех потоков, кроме того, что находит-

§ ся в критической секции. Если статический

^ анализ не включает контроль значений,

Ц критическая секция с точки зрения такого

анализа не является критической. В общем

§ случае задача контроля переменных рав-

g носильна полноценному исполнению про-

£ граммы и вычислению значений всех пере-s

¿3 менных.

Предлагаемый подход

I. Представление ветвлений

Простейшее ветвление, которое можно представить — одиночный оператор if следующего вида: if (condition) { operation;}. Отметим, что одна из идей построения графа совместного исполнения потоков — однозначное отображение один в один инструкций исходного кода на вершины, расположенные по периметру графа. Именно такое построение обеспечивает линейную по набору инструкций сложность в рамках каждого потока. В случае простейшего ветвления имеется набор операций, которые могут исполняться в зависимости от выполнения условия condition. Используем принцип неопределенных коэффициентов. Введем бинарный коэффициент в е {0,1}, чтобы обозначить «попадание» в одну из ветвей — все модификации значений внутри ветви будут иметь множитель р.

Например, пусть в двух потоках исполняется следующий код при начальном значении х = 0:

if (x == 0) { x += 2;}.

С точки зрения графа он будет иметь вид ребра, на котором значение x меняется на величину 2 • р.

Итак, в финальной вершине графа G значение i-й переменной равно f(х0,{а},{р}). Анализ на предмет наличия гонки проводится относительно неопределенных коэффициентов {р} аналогично анализу относительно коэффициентов {а}. Согласно обозначениям, принятым в [1] и [2], в вершине графа ставятся значения разделяемых переменных, а ребра подписываются соответствующей операцией. Для рассмотренного примера получили значение разделяемой переменной 2р1 + 2р2 (рис. 1). Коэффициенты в выражении определяют ветвь, для которой моделируется исполнение. Существуют такие значения неопределенных коэффициентов, при которых разделяемая

№ 6 (36) 2011

{0}

{О + 2Р, + 2Рг}

Рис.1.Граф совместного исполнения двух потоков на разделяемой памяти

переменная принимает различные значения, т. е. присутствует неразрешенное условие гонки.

Обращаем внимание, что коэффициенты {а} отвечают за очередность исполнения операций, а {в} — за путь по ветвлениям.

В общем случае любое ветвление является композицией элементарных ветвлений. Также необходимо заметить, что в случае одиночного if в финальное выражение коэффициент в может войти как множитель, что говорит о вариативности исполнения кода. В случае конструкции if - else в финальное выражение войдут члены с коэффициентами в и (1 - в), отражающие тот факт, что выполняться будет блок кода либо под if, либо под else.

Корректность описанного представления докажем в следующей теореме.

Теорема. Наличие гонки в предлагаемой модели с ветвлениями эквивалентно наличию гонки в исходной задаче.

Доказательство. Фактически формулировка теоремы означает, что предложенное выше представление корректно описывает ветвление в терминах и смысле анализа графа совместного исполнения потоков. Зафиксируем значения коэффициентов {в} в формуле f (1). При этом анализируем линейный участок кода (пути по ветвлениям описаны коэффициентами {в}) способом, изложенным в [1]. Далее, если,

3{р},/,{а}1,{а}2 :f (*0,{аМР}) * f(*о,М2,т | это означает, что есть два пути по ветвлени- ^ ям, которые дают разные значения разде- ¡^ ляемой переменной номер /. Обратно: пусть ^ есть два пути, приводящих к гонке. В соот- Ц*

ветствии с формулой (2) §

О

&

3/,{а}1,{а}2 : f (^МО * f(*о,{аЬ) Ц

со

оба пути описываются с помощью общего оо подхода к ветвлениям коэффициентами {в}. * Таким образом, наличие гонки в модели эквивалентно наличию гонки в задаче.

II. Представление циклов

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

Теорема. Для описания цикла в анализируемом графе достаточно одного повторения тела цикла.

Доказательство. Применим метод доказательства от противного. Допустим, что необходимо повторение тела цикла два раза, чтобы обнаружить наличие гонки.

На рисунке 2 жирной линией обозначен произвольный путь на графе. По предположению два подобных этому пути приводят к гонке, тогда как никакие два пути в графе с одним повторением тела цикла к гонке не приводят. Рассматриваем отдельно каждый подграф, соответствующий одному повторению тела цикла и учитываем, что гонка в нем отсутствует. Поскольку в анализе используются только попарные сравнения, а не последовательность использования операций, то из отсутствия гонки в каждой из подзадач следует отсутствие гонки в общей задаче, что противоречит исходному предположению. Таким образом, предположение о том, что надо повторять граф совместного исполнения с повторением более одного раза тела цикла, неверно. Теорема доказана.

№ 6 (36) 2011

Тело цикла Тело цикла

Остальной код

Остальной код

Рис. 2. Представление графа с несколькими повторениями тела цикла в виде подграфов

с одним повторением в каждом

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

I

I I

5 <и

t ¡5

u

if

an *

0

1

I £

0 <u

1 is is is

и

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

Разберем простейший пример применения подхода. Пусть в двух потоках исполняется следующий код:

while (true) { if (i == 0) {i = 1; x++}; else break;}.

Исходное состояние: x = 0; i = 0. Функция корректности имеет следующий вид:

c( x, i) =

true,x = 1 false, x ф 1

(3)

Используем для анализа подходы, изложенные в настоящей работе: оставляем тело цикла и приписываем каждому из ветвлений коэффициент. Строим граф совместного исполнения потоков и отмечаем на нем операции чтения и записи. Берем путь, не идущий по внешним ребрам графа, и выписываем значения переменных с помощью метода неопределенных коэффициентов: i = а1, x=а1 + а2, откуда при а1 = а2 = 1 получим значение x, при котором функция корректности имеет значение false. Значит, состояние гонки присутствует относительно переменной x.

42

Заключение

Итак, реальные практические программы, содержащие циклы и ветвления, могут быть проанализированы в рамках освещаемого подхода. Если раньше в [3] процедура анализа реального кода, содержащего циклы и ветвления, не была полностью описана в рамках существующих подходов, то теперь такое описание появилось. Кроме того, доказана его корректность в рамках применяемого подхода. Расширенный подход создает хорошую базу для дальнейших разработок средств детектирования гонок.

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

1. Заборовский Н. В., Тормасов А. Г. Моделирование многопоточного исполнения программы и метод статического анализа кода на предмет состояний гонки // Прикладная информатика. 2011. № 4 (34). С. 105 - 110.

2. Кудрин М. Ю., Прокопенко А. С., Тормасов А. Г. Метод нахождения состояний гонки в потоках, работающих на разделяемой памяти // Труды МФТИ. 2009. Т. 1. № 4. С. 182 - 201.

3. Gao H, Groote J. and Hesselink W. Almost Wait-Free Resizable Hashtables // In Proceedings of the 18th International Parallel and Distributed Processing Symposium, April. 2004. Р. 50.

4. Herlihy M, Shavit N. The Art of Multiprocessor Programming. Burlington: Elsevier, 2008.

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