Опубликован: 28.10.2009 | Доступ: свободный | Студентов: 516 / 40 | Оценка: 4.67 / 4.39 | Длительность: 20:33:00
Лекция 7:

Оптимизация параллельной программы

10.5. Основные концепции и понятия профилирования

10.5.1. Понятие критического пути

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

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

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

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

Пример критического пути многопоточного приложения

Рис. 10.2. Пример критического пути многопоточного приложения

Рассмотрим диаграмму подробнее. В начальный момент времени существовал только один поток, выполняющийся последовательно. Затем в момент времени t1 происходит создание дочернего потока, который начинает функционировать в момент времени t2, но сразу попадает в состояние ожидания, поскольку данные для визуализации еще не подготовлены. Затем в точке t3 завершаются вычисления, и дочерний поток начинает визуализацию подготовленных данных, которая продолжается с момента t4 до момента t7. Заметим, что второй поток может освободить массивы с результатами вычислений сразу после того, как переведет их в формат, необходимый для графического представления (момент времени t5 ). За счет этого и достигается распараллеливание в рассматриваемом приложении. Можно видеть, что потоки работают параллельно на промежутке времени между моментами t6 и t7 . Далее осуществляется еще одна итерация, после чего в момент времени t12 второй поток завершает свое исполнение, а в момент времени t14 завершается весь процесс.

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

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

Таким образом, профилирование и оптимизация приложения неразрывно связаны с процессом анализа критического пути. Критический путь - это первое, на что нужно обращать внимание, поскольку не входящие в него участки приложения вносят меньший вклад в суммарное время работы приложения. Далее мы увидим, что ITP позволяет строить критический путь приложения и предоставляет различные средства для его анализа.

10.5.2. Состояния потоков

При анализе критического пути пользуются таким понятием как состояние потока (thread state). А именно, поток может находиться в трех состояниях:

  • Активное состояние (active) - поток исполняется в настоящее время;
  • Состояние активного ожидания (spin) - постоянно повторяемая проверка состояния блокировки(например, при использовании pthread_spin_lock() );
  • Состояние ожидания (wait) - ожидание завершения какой-либо блокирующей операции (например, операции ввода-вывода).

10.5.3. Понятие категорий времени

Рассмотрим теперь характеристики эффективности использования аппаратных ресурсов активными потоками приложения. Для этого в ITP используются два параметра: уровень параллелизма (concurrency) и поведение (behavior).

Уровни параллелизма используются для обозначения того, насколько полно потоки нагружают процессоры вычислительного узла. Так, одновременная работа двух потоков на двухъядерном процессоре означает эффективное использование его ресурсов ( full utilization ), на одноядерном - сверхиспользование ( over utilization ), а на четырехъядерном - недостаточно эффективное использование ( under utilization ).

Существует несколько типов поведения потока в активном состоянии:

  • Сдерживание (impact) - ситуация, когда поток сдерживает выполнение другого потока (например, поток занял мьютекс, освобождения которого ожидают другие потоки);
  • Блокировка (blocking) - приостановка потока в результате вызова блокирующих функций (например, операций ввода/вывода);
  • Критический путь (critical path) - ситуация, когда поток выполняет участок кода, входящий в критический путь, при отсутствии других ожидающих потоков.

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

В ITP используется несколько видов представления критического пути, каждое из которых мы впоследствии подробно изучим. Для удобства анализа каждый участок критического пути окрашивается в определенный цвет в зависимости от уровня параллелизма и поведения потока на этом участке. На рис. 10.3 представлена сводная таблица используемых цветов. n обозначает число активных потоков приложения, а p - число процессоров (ядер).

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

Рис. 10.3. Цвета, используемые для обозначения категорий времени

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

Рассмотрим теперь второй параметр - тип поведения потоков. Для обозначения типа поведения потока цветом используется изменение яркости. При этом используется простое правило: чем ярче цвет участка, тем большего внимания от разработчика он требует. Самый яркий цвет используется для указания impact -состояния потока, поскольку прежде всего необходимо сокращать время ожидания потоков друг другом. Далее по важности следует blocking -состояние, которое тоже требует пристального контроля, так как нужно минимизировать время ожидания потоков. Последним идет состояние critical path.

Имеется особая категория времени, обозначаемая желтым цветом и указывающая на непроизводительные издержки ( overhead ) в многопоточном приложении. Под непроизводительными издержками понимаются накладные расходы на создание потоков, управление и синхронизацию между потоками. Другими словами, эта величина показывает количество процессорного времени, израсходованного на поддержку работы потоков. Чаще всего большая доля желтого цвета в критическом пути свидетельствует о чрезмерно частом вызове функций синхронизации и необходимости перепроектирования приложения.

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

Пример раскраски критического пути многопоточного приложения в соответствии с категориями времени

Рис. 10.4. Пример раскраски критического пути многопоточного приложения в соответствии с категориями времени

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