В силу специфики научной деятельности мне нужно замерять время работы алгоритмов и строить по получившимся данным графики. Раньше процесс выглядел так:
- Алгоритм подготовлен.
- Запуск эксперимента, выходные данные идут в лог.
- Перенос данных в эксель.
- Постобработка: разбить, группировать, отсортировать.
- Строим график, а он кривой — ошибка в эксперименте, переход на шаг 1.
Первая проблема — просто посмотреть как прошел эксперимент занимало очень много времени.
Ладно, пережили, графики построили, время идет, готовим публикацию и выясняется, что в результатах экспериментов не сохранены некоторые параметры запуска алгоритма. Не доглядел. Это уже вторая проблема — хранение метаданных об эксперименте.
Меня как программиста всегда раздражала необходимость «ручной работы». Да график готов, но мы еще что-то вручную подвинем, там перекрасим, тут подрисуем. Каждый раз когда приходят новые данные этот процесс приходится повторять. Третья проблема — перестроение графиков должно быть полностью автоматизированным.
Для решения озвученных проблем я придумал формат хранения данных в JSON и назвал его Measurelook. В этой статье я расскажу о Measurelook и о его применении в подготовке научной публикации.
Первоосновы — формат и просмотровщик
Формат и просмотровщик это два ключевых компонента Measurelook. Формат описывает схему хранения данных эксперимента. Просмотровщик это автономная веб-страница, визуализирующая данные эксперимента. Вы загружаете в нее файл с данными эксперимента и просмотровщик рисует по нему графики.
В просмотровщик входят также валидатор и мигратор. Валидатор проверяет с помощью JSON Schema корректность загружаемого файла. Мигратор автоматически обновляет версию файла с экспериментом. С одной стороны это обеспечивает обратную совместимость с актуальной версией просмотровщика. С другой стороны вам не обязательно обновлять свои исходники до новой версии формата, если старая вас устраивает.
Формат и просмотровщик работают вместе, но при их создании преследуются разные цели. Формат сделан так, чтобы исследователь мог сохранить нужные ему данные. Просмотровщик сделан для визуализации простых данных. Двухмерные графики он строит, но трёх- и более мерные нет. В описании формата я буду указывать, что может хранить формат и не может показать просмотровщик.
Формат Measurelook
Measurelook описывает структуру JSON файла для хранения информации о вычислительном эксперименте.
Meta — произвольный JSON объект для хранения данных об эксперименте. Примеры данных: название реализации алгоритма, параметры компиляции, параметры аппаратного и программного окружения, название датасета. Сюда же можно вывести некоторые параметры запуска алгоритма, но об этом позже.
Прим.: просмотровщик в текущий момент не умеет обращаться с произвольными метаданными. Он предполагает, что все метаданные являются строками.
Пример:
{
"meta": {
"Algorithm implementation name": "md_cluster4_4",
"dataset": "../datasets/power.csv",
"COMPILE_COMPILER_VERSION": "Intel(R) C++ gcc 4.4 mode",
"env_core_number": "24",
"env_proc_model": "model name: Intel(R) Xeon(R) CPU X5680 @ 3.33GHz",
"max": 35840,
"min": 5120,
"step": 5120,
"dataLoadingTime": 0.062945,
"Openmp thread number": 24
}
}
Параметры алгоритма. Раньше моё представление об экспериментах было несколько наивным — один параметр меняем, другой измеряем, строим график. Ну хорошо, один меняем, несколько измеряем, строим несколько графиков. Но когда я ознакомился с диссертацией Теплова А.М. «Анализ масштабируемости параллельных приложений на основе технологий суперкомпьютерного кодизайна» концепция изменилась. В его исследовании строятся графики по двум изменяемым параметрам и одному измеряемому. Например, мы меняем размер входных данных и количество процессов, а измеряем производительность. Соответственно визуализироваться это должно поверхностью в трёхмерном пространстве.
Я решил, что это важное обобщение и выделил три группы параметров алгоритма: константы, изменяемые параметры и измеряемые параметры.
Константа это параметр алгоритма, который не изменяется в ходе эксперимента. Константа описывается тройкой: название, единицы измерения, значение. Хранить константы предпочтительнее в этом блоке, но может вам будет удобнее хранить их в метаданных. Пример: размерность датасета.
Изменяемый параметр это параметр алгоритма, который меняется в ходе эксперимента. Он описывается парой: название, единицы измерения. Пример: объем входных данных, количество потоков.
Измеряемый параметр это параметр алгоритма, который измеряется в ходе эксперимента. Ранее он так же описывался парой: название, единицы измерения. Позже было добавлено разделение на фиксированные и косвенные параметры. Фиксированный параметр это непосредственно измеренное в ходе эксперимента значение. Пример: время загрузки данных, время работы алгоритма. Косвенный параметр это параметр, вычисляемый как сумма значений фиксированных параметров. Для них указывается список фиксированных параметров. Пример: полное время работы алгоритма является суммой времени загрузки данных и времени работы алгоритма.
Прим.: в текущий момент просмотровщик умеет строить графики только по одному изменяемому параметру и нескольким измеряемым. Случай с двумя изменяемыми параметрами нужно рисовать в виде поверхности в трёхмерном пространстве либо трансформировать в серию графиков в двухмерном пространстве через перевод одного изменяемого параметра в измеряемый. Это реализуемо, но у меня не было такой потребности.
Примеры:
{
"constantParams": [{
"name": "dimensionality",
"units": "natural number",
"value": 3
}],
"changedParams": [{
"name": "arraySize",
"units": "natural number"
}],
"measuredParams": [{
"name": "calcDistMatrix_duration",
"units": "seconds",
"type": "direct"
},
{
"name": "pamTotal_duration",
"units": "seconds",
"type": "indirect",
"sumOf": ["pamBuild_duration", "pamSwap_duration"]
}],
}
После описания параметров эксперимента переходим к замерам. Структура записи о замере:
- measureKey, строка — уникальный ключ каждого измерения. Рекомендуется собирать его как набор значений всех изменяемых параметров и номера прогона.
- passId, число — номер прогона.
- changedParams.name, число — значения всех изменяемых параметров, зафиксированных на время прогона.
- measuredParams.name, число — значения всех измеренных параметров, полученных во время прогона.
- raw, объект — произвольные данные о прогоне, которые вы хотите сохранить. Например, чтобы в будущем перепроверить значения измеренных параметров.
Пример:
{
"measures": {
"5120_0": {
"measureKey": "5120_0",
"raw": {
},
"passId": 0,
"arraySize": 5120,
"calcDistMatrix_duration": 0.033690,
"pamBuild_duration": 0.054846,
"pamSwap_duration": 0.199832,
"iterationCount": 5,
"avgIterationTime_duration": 0.039966
}
}
}
Прочие значения:
- version, строка — версия формата. В систему встроен мигратор, автоматически обновляющий файлы в старом формате до нового для обеспечения обратной совместимости.
- name, строка — название эксперимента. Добавлено в формат, но в текущий момент просмотровщиком не используется.
- timestamp, строка — время проведения эксперимента. Указывается в свободной форме. Добавлено в формат, но в текущий момент просмотровщиком не используется.
Пример:
{
"version": "0.3.0",
"name": "PAM performance 1",
"timestamp": "27.11.2017 22:33:44",
}
Просмотровщик
Просмотровщик это веб-страница, на которой выводится основная информация об эксперименте и можно посмотреть первичные графики.
Реализованные функции:
- Отображение графика для каждого прогона
- Отображение графиков по среднему значению и/или медиане
- Выбор любого подмножества изменяемых параметров для отрисовки
- Замена значений изменяемых параметров на их логарифмы
- Отображение текущих отрисованных данных в виде таблицы с возможностью скачать CSV
- И самая главная фича — вставка результатов эксперимента из буфера обмена. Очень удобно в процессе отладки.
От данных к конечным графикам
JSON штука распространённая, формат простой. Полагаю организовать вывод данных в таком виде можно на многих языках программирования. Для себя я сделал вспомогательный принтер на языке Си с помощью bstring. Он опубликован вместе с примером использования на гитхабе (см. ссылки).
Засим я считаю, что завершил часть «Как это сделать?» и перехожу к части «Что с этим делать?»
Как это было у меня — есть много файлов, результатов замеров. Нужно их переработать в красивые графики.
Я это делал следующим образом:
- Программа на nodejs считывает данные и выполняет постобработку. Например, пересчитывает время работы алгоритма в ускорение.
- Вызывается шаблонизатор Mustache. Ему передаётся шаблон программы на языке R для построения графика, в который внедряются наши данные. На выходе мы получаем программу для R рисующую нужный график.
- R программа исполняется, и ее результат сохраняется в векторный формат svg.
- svg конвертируется с помощью Inkscape в конечное представление: pdf изображение для статьи или png для презентации.
Предвосхищая вопросы:
В: Почему R, а не d3.js?
О: Потому что у меня был до этого небольшой опыт на R, и потому что программирование d3 мне субъективно показалось слишком низкоуровневым.
В: Почему R сохраняет svg, а не сразу pdf и png?
О: R это безусловно может, но когда я это пробовал, pdf он пытался печатать по-умному со шрифтами. По-видимому он не находил кириллицу и графики получались без надписей. Так что да, еще одна лишняя программа, зато гарантированно работает и я больше доверяю качеству преобразования Inkscape.
Из своего большого репозитория для рисования 8 видов графиков, я сделал маленький, рисующий один вид и опубликовал на гитхабе (см. ссылки).
Заключение
Проект Measurelook решил поставленные перед ним задачи — организация хранения данных вычислительных экспериментов и простое средство предварительного просмотра. Также он послужил основой для решения третьей задачи — полностью автоматизированного перестроения графиков.
Ссылки
- Просмотровщик онлайн
- Репозиторий со сборками просмотровщика Measurelook
- Репозиторий с принтером Measurelook на Си + пример использования
- Репозиторий с примером отрисовки конечных графиков с помощью Measurelook, R и Inkscape
- Исходный код просмотровщика Measurelook (проект не основной, см. contributing.md)
Автор: Тимофей Речкалов