Максимально точное измерение кода
В моей статье полугодичной давности о длинной арифметике есть замеры скорости (throughput в тактах) очень коротких фрагментов кода — всего по несколько инструкций. Методика измерения была кривовата, но давала правдоподобные результаты. Потом выяснилось, что результаты таки неверные — поверхностный подход всегда сказывается.
В этом посте я опишу надежный метод «нанобенчмаркинга» с минимальной погрешностью и без подключения специальных библиотек и драйверов, к которому в итоге пришел. Применимость: сравнение однопоточного потенциала процессоров, просто интерес.
Я использую только GCC — соответственно способ заточен под него. Но буду делать обобщения, чтобы владельцы других компиляторов могли разобраться.
Непосредственно мерилом служит команда RDTSC. На Википедии справедливо отмечается, что она ненадежна и рекомендуется использовать специальные сервисы ОС. Однако для микроизмерений они работают слишком долго (сотни тактов) и неодинаково от запуска к запуску, что вносит неустранимые погрешности. Сама по себе RDTSC работает не более нескольких десятков тактов — постоянное количество или одно из небольшого набора.
Измерительная обвязка состоит из трех вложенных циклов.
Средний цикл содержит 2 замера тактов и неизменный внутренний цикл посередине. Его роль — определить минимальное время, за которое может выполниться внутренний цикл. 20-30 итераций вполне хватает, чтобы все данные попали в кеш, начальная и конечная RDTSC заняли одинаковое время, а также сошлись все прочие звезды, если они существуют 🙂
Внешний цикл управляет длиной внутреннего. Расположите в нем инициализацию входных данных перед средним циклом.
Внешний цикл необходим, потому что время, достигнутое в среднем цикле, всегда включает константу — время инициализации внутреннего цикла + затраты на 1 ошибку в предсказании перехода (самые умные интеловские ядра ошибаются реже). Поэтому время из среднего цикла нельзя просто разделить на кол-во итераций.
В итоге на конвейере устанавливается «паттерн» работы длиной от 1 до 10-15(?) итераций:
Точный througput в тактах имеет смысл считать как минимум для 1 такого паттерна, а не 1 итерации.
Как легко убедиться из цифр в примерах ниже, даже при измерении паттернов разброс результатов остается. Предположительно, на самом деле RDTSC не так хороша, как расписано выше 🙂
Итак, получив разницы времени выполнения внутренних циклов с длинами кратными шагу паттерна, остается посчитать статистики.
Примеры
Сравните результаты замеров (здесь и далее все значения в тактах) из статьи про длинную арифметику:
Поверхностный метод | 7.5 | 5.5 | 5.5 | 7 | 5 | 2 | 2.5 | 3.25(?)–3.5 |
Умный метод | 7 | 6 | 6 | 7 | 5 | 2 | 2 | 3 |
Все дальнейшие тесты проводились на 2 ядрах: AMD K10 и Intel Core 2 Wolfdale.
Важно оценить сами инструменты.
Пустой цикл
Внутренний цикл выглядит так:
Далее (10, 1.0) — (длина паттерна, итого в среднем на 1 итерацию)
RDTSC
Без среднего и внутреннего цикла:
Приближенное вычисление синуса
Интересно посмотреть, сколько можно сэкономить, вычисляя синус рядом Тейлора 3-го порядка. При углах от −π/2 до π/2 получается точность в 2 знака после запятой. Можно представить приложения, где ее будет достаточно.
Инструкция FSIN — точный синус
угол | 0.0 | 0.0001 | π/2 | случайный |
K10 | 30.2 ± 10.3 | 89.8 ± 2.9 | 143.1 ± 8.5 (2, 71.6) | 75.6 |
Core 2 | 40.0 ± 11.0 | 68.0 ± 5.6 | 88.0 ± 13.0 | 89.4 |
Ряд Тейлора 3-го порядка
Векторизованный ряд Тейлора
Получается, что вычисление синуса с точностью до 2 знаков можно организовать как минимум в 10 раз быстрее, чем обычно.
Измерение производительности функций в JavaScript
Производительность всегда играла ключевую роль в программном обеспечении. А в веб-приложениях её значение ещё выше, поскольку пользователи легко могут пойти к конкурентам, если сделанный вами сайт работает медленно. Любой профессиональный веб-разработчик должен об этом помнить. Сегодня по-прежнему можно успешно применять массу старых приёмов оптимизации производительности, вроде минимизации количества запросов, использования CDN и не использования для рендеринга блокирующего кода. Но чем больше разработчики применяют JavaScript, тем важнее становится задача оптимизации его кода.
Вероятно, у вас есть определённые подозрения относительно производительности часто используемых вами функций. Возможно, вы даже прикинули, как можно улучшить ситуацию. Но как вы измерите прирост производительности? Как можно точно и быстро протестировать производительность функций в JavaScript? Идеальный вариант — использовать встроенную функцию performance.now() и измерять время до и после выполнения ваших функций. Здесь мы рассмотрим, как это делается, а также разберём ряд подводных камней.
Performance.now()
С точки зрения математики монотонная функция либо только возрастает, либо только убывает. Другой пример, для лучшего понимания: переход на летнее или зимнее время, когда все часы в стране переводятся на час назад или час вперёд. Если мы сравним значения двух копий Date — до и после перевода часов, то получим, например, разницу «1 час 3 секунды и 123 миллисекунды». А при использовании двух копий performance.now() — «3 секунды 123 миллисекунды 456 789 тысячных миллисекунды». Не будем здесь подробно разбирать этот API, желающие могут обратиться к статье Discovering the High Resolution Time API.
Выполнение подобных функций можно измерить следующим способом:
Если выполнить данный код в браузере, то результат будет выглядеть так:
Ошибка № 1: случайное измерение ненужных вещей
Ошибка № 2: однократное измерение
Многие проводят лишь одно измерение, складывают общее время и делают далеко идущие выводы. Но ситуация каждый раз может меняться, ведь скорость выполнения сильно зависит от таких факторов, как:
Риск данного подхода заключается в том, что браузерный JavaScript-движок может выполнять субоптимизацию, т. е. во второй раз функция будет вызвана с теми же входными данными, которые будут запомнены и использованы в дальнейшем. Чтобы это обойти, можно использовать много разных входных строк вместо того, чтобы раз за разом брать одно и то же значение. Однако при разных входных данных и скорость выполнения функции раз от раза может отличаться.
Ошибка № 3: излишнее доверие к средним значениям
Итак, целесообразно делать серию измерений, чтобы точнее оценить производительность той или иной функции. Но как определить производительность функции, если при разных входных данных она выполняется с разной скоростью? Давайте сначала поэкспериментируем и измерим время выполнения десять раз с одними и теми же входными данными. Результаты будут выглядеть примерно так:
Обратите внимание, насколько самое первое значение отличается от остальных. Скорее всего, причина как раз в проведении субоптимизации и в необходимости «прогрева» компилятора. Мало что можно сделать, чтобы этого избежать, но зато можно обезопасить себе от неверных заключений.
Например, можно исключить первое значение и вычислить среднеарифметическое из остальных девяти. Но лучше взять все результаты и вычислить медиану. Результаты сортируются по порядку, и выбирается средний. Вот где performance.now() очень полезен, потому что вы получаете значение, с которым можно делать что угодно.
Итак, давайте измерим снова, но в этот раз используем срединное значение выборки:
Ошибка № 4: сравнение функций в предсказуемом порядке
Теперь мы знаем, что всегда лучше делать несколько измерений и брать среднее. Более того, последний пример говорит о том, что в идеале нужно вместо среднего брать медиану.
Этот код можно улучшить, поскольку цикл haystack.forEach будет перебирать все элементы, даже если мы быстро нашли совпадение. Воспользуемся старым добрым for:
Теперь посмотрим, какой вариант быстрее. Выполним каждую функцию по десять раз и вычислим «правильные» результаты:
Получим такой результат:
Выводы
Ещё одна причина, почему мы не можем знать заранее, какой вариант будет быстрее, заключается в том, что всё зависит от ситуации. В последнем примере мы искали совпадение среди 26 значений вне зависимости от регистра. Но если мы будем искать среди 100 000 значений, то выбор функции может оказаться иным.
Инструмент анализа скорости PHP-функций
В последнее время обращал внимание на материалы о производительности и замерах скорости функций PHP. После анализа ряда материалов был сделан следующий вывод. Сравнений довольно много, но все замеры проводятся с разными входными условиями, вывод результатов тестирования у каждого решения свой, не говоря уже о том, если появится желание проверить тесты в своей среде, то придется копипастить куски кода.
Поэтому возникла идея написать собственный механизм простого тестирования скорости различных операций. Задумка показалась интересной, поэтому начало было положено!
Начать следовало с постановки целей будущего инструмента. Проект хотелось видеть как универсальный инструмент для тестирования скорости чего угодно. Но поразмыслив над деталями и ошибками прошлого, решено было начать с малого.
Итак, требовалось получить инструмент, который:
Механизм замеров
Для замера времени выполнения функции было решено воспользоваться подобным, методом
Принцип действия прост, если происходит вызов без параметров, то возвращаем текущее состоянии времени, если же вызов происходит с параметром времени, тогда возвращается разница между текущим и переданным временем.
Но там где расчет времени, там же и потребляемый объем памяти, поэтому в последствии был добавлен аналогичный метод измерения потребляемой памяти.
Механизм аналогичен механике замера времени, только в данном случае происходит передача значения выделенной памяти скрипту.
Как известно, некоторые функции ведут себя по разному в зависимости от входного набора данных, поэтому в каждом тесте определен массив входных данных для функций тестирования. Для получения наиболее точных результатов, тестирование функций проводится на каждом наборе несколько раз. Помимо прочего, тестирование проводится в разной последовательности.
В ходе экспериментов, было замечено, что объем свободной памяти перед началом каждого теста разный, хоть для большинства проводимый испытаний это было незначительным, но для порядка хотелось бы иметь условия одинаковые для всех испытаний либо близкие к таковым. Поэтому хранение результатов было решено реализовать в локальном хранилище SQLite, а перед началом испытаний делать один проверочный тест для заполнения переменных данными.
Для того, чтобы иметь возможность создания собственных вариантов представления результатов и собственных вариантов теста, создано 2 модели абстракции. Модель тестов (Test), содержит всю информацию о тесте, включая функции тестирования. Модель представления данных (DataViwer) содержит методы преобразования результатов тестирования в читаемый вид. Для удобного вывода представлений был задействован шаблонизатор Twig и подключена библиотека стилей bootstrap, также создан вьювер с графиком HighCharts.
В итоге общий механизм работы такой. Берутся необходимые для сравнения функции и запускаются на выполнение с разными наборами данных и в разной последовательности. При этом происходит замер времени каждого выполнения и запись результата в хранилище. За данный этап отвечает модель теста (Test). После всех замеров происходит передача результатов в представление данных (DataViwer), где происходит обработка и вывод информации.
Реализация тестирования
Класс теста
Простой пример реализации класса теста, на примере тестирования скорости выполнения операции пред инкрементирования и пост инкрементирования.
Класс должен наследовать абстрактный класс TestAbstract, в котором заложена основная механика работы с потоками данных.
$name — задает название теста, которое может быть использовано при выводе в DataViewer.
$valueTest — объем выборки тестирования, массив значений, с каждым из которых будет выполнена функция для тестирования. Таким образом каждая тестируемая функция должна обязательно принимать один параметр. Будет он являться числом, строкой или массивом не важно, все зависит от конкретного случая. В нашем примере, достаточно чисел, которые будут обозначать объем проводимых операций с инкрементом.
$qntTest — говорит о том, какое количество раз будет протестирован каждый объем выборки.
$viewers — массив представлений данных, который будет сформирован при рендере отчета. На самом деле это набор полных имен классов наследующих абстрактный класс ViewrAbstract. Заранее подготовленные вьюверы вынесены в константы класса TestCore.
$functions — массив названий функций которые будут использоваться в тестировании. Ключами массива являются названия, которые будут отображены в результатах.
$strategy — массив стратегий тестирования, каждая стратегия должна быть представлена массивом с последовательностью имен функций. В примере указано 2 стратегии — прямой последовательности и в обратной.
Непосредственно сами функции, которые как говорилось выше, должны принимать одно значение. В нашем примере, мы считаем это за количество выполняемых операций серии инкрементирования.
В итоге получим, серию тестов где каждая стратегия тестирования будет протестирована по 5 раз с каждым объемом выборки ([100, 1000, 2000, 3000]).
Класс представления данных
Сейчас давайте подробнее рассмотрим простой класс представления данных.
Класс реализует абстрактный класс ViewerAbstract.
$view — содержит имя представления, которое поумолчанию должно лежать в папке /views/viewers
function generateData($data) — метод обработки массива результатов тестирования. Результат будет передан поумолчанию в параметр data в указанное представление.
function run($data) — необязательный для реализации метод, но если необходимо изменить путь к представлению данных, то именно он должен быть переопределен.
public static function model($class = __CLASS__) — метод поддержки статического обращения к методам
Варианты использования
Чтобы воспользоваться функционалом тестирования, создано 2 основных метода.
Метод запуска теста
$test — полное имя запускаемого теста. Могут быть задействованы как свои варианты тестов либо заранее подготовленные.
$params — массив параметров для запуска теста. Данным параметром можно точечно изменить параметры тестирования.
$onlyData — параметр отвечающий за вывод набора результатов либо отрендеренное представление.
Метод сравнения функций
Метод сравнения пользовательских функций без создания дополнительных классов
$func — массив анонимных функций, где ключи массива являются названиями функций в результатах тестирования.
$params — массив параметров тестирования, аналогичен параметрам метода test.
$onlyData — также аналогичен параметру метода test, и отвечает за вариант вывода результатов.
Примеры работы
Самый простой и быстрый вариант использования — это воспользоваться заранее подготовленным тестом. Все подготовленные тесты вынесены в константы класса Speedy.
Для сравнения пользовательских функций, необходимо создать анонимные функции и вызвать метод Speedy::compare
Результаты тестирования
Результаты тестирования на данный момент могут быть выведены 4мя представлениями.
VIEWER_TLIST
Представление в табличной форме списка всех произведенных замеров времени. По сути это вывод всех записей из хранилища, без каких-либо преобразований. В наборе данных содержится информация о имени тестируемой функции, затраченном времени, объему выборки, используемому объему памяти, номер партии в которой выполнялся тест и комментарий. В комментарии указывается в рамках какой стратегии был выполнен тест данной функции.
Результат тестирования операторов инкрементирования.
name | time | size | memory | part | comment |
postInc | 0.000650882720947 | 100 | 48 | 2 | postInc-prefInc |
prefInc | 0.000411987304688 | 100 | 48 | 2 | postInc-prefInc |
prefInc | 0.000406980514526 | 100 | 48 | 3 | prefInc-postInc |
postInc | 0.000549077987671 | 100 | 48 | 3 | prefInc-postInc |
postInc | 0.000330924987793 | 100 | 48 | 5 | postInc-prefInc |
prefInc | 0.000287055969238 | 100 | 48 | 5 | postInc-prefInc |
prefInc | 0.00043797492981 | 100 | 48 | 6 | prefInc-postInc |
postInc | 0.000365018844604 | 100 | 48 | 6 | prefInc-postInc |
postInc | 0.000295162200928 | 100 | 48 | 8 | postInc-prefInc |
prefInc | 0.000373125076294 | 100 | 48 | 8 | postInc-prefInc |
prefInc | 0.000263929367065 | 100 | 48 | 9 | prefInc-postInc |
postInc | 0.000449895858765 | 100 | 48 | 9 | prefInc-postInc |
postInc | 0.00030517578125 | 100 | 48 | 11 | postInc-prefInc |
prefInc | 0.000247955322266 | 100 | 48 | 11 | postInc-prefInc |
prefInc | 0.000244140625 | 100 | 48 | 12 | prefInc-postInc |
postInc | 0.000265121459961 | 100 | 48 | 12 | prefInc-postInc |
postInc | 0.000267028808594 | 100 | 48 | 14 | postInc-prefInc |
prefInc | 0.000245094299316 | 100 | 48 | 14 | postInc-prefInc |
prefInc | 0.000285148620605 | 100 | 48 | 15 | prefInc-postInc |
postInc | 0.000273942947388 | 100 | 48 | 15 | prefInc-postInc |
postInc | 0.00273203849792 | 1000 | 48 | 17 | postInc-prefInc |
prefInc | 0.00240206718445 | 1000 | 48 | 17 | postInc-prefInc |
prefInc | 0.00274896621704 | 1000 | 48 | 18 | prefInc-postInc |
postInc | 0.00259804725647 | 1000 | 48 | 18 | prefInc-postInc |
postInc | 0.00391817092896 | 1000 | 48 | 20 | postInc-prefInc |
prefInc | 0.00303602218628 | 1000 | 48 | 20 | postInc-prefInc |
prefInc | 0.00229096412659 | 1000 | 48 | 21 | prefInc-postInc |
postInc | 0.00281691551208 | 1000 | 48 | 21 | prefInc-postInc |
postInc | 0.00273108482361 | 1000 | 48 | 23 | postInc-prefInc |
prefInc | 0.00221014022827 | 1000 | 48 | 23 | postInc-prefInc |
prefInc | 0.00266814231873 | 1000 | 48 | 24 | prefInc-postInc |
postInc | 0.00307106971741 | 1000 | 48 | 24 | prefInc-postInc |
postInc | 0.00283098220825 | 1000 | 48 | 26 | postInc-prefInc |
prefInc | 0.00239992141724 | 1000 | 48 | 26 | postInc-prefInc |
prefInc | 0.00246214866638 | 1000 | 48 | 27 | prefInc-postInc |
postInc | 0.00273704528809 | 1000 | 48 | 27 | prefInc-postInc |
postInc | 0.00283288955688 | 1000 | 48 | 29 | postInc-prefInc |
prefInc | 0.00229215621948 | 1000 | 48 | 29 | postInc-prefInc |
prefInc | 0.00220608711243 | 1000 | 48 | 30 | prefInc-postInc |
postInc | 0.0028657913208 | 1000 | 48 | 30 | prefInc-postInc |
postInc | 0.00557017326355 | 2000 | 48 | 32 | postInc-prefInc |
prefInc | 0.0048840045929 | 2000 | 48 | 32 | postInc-prefInc |
prefInc | 0.00449013710022 | 2000 | 48 | 33 | prefInc-postInc |
postInc | 0.0064799785614 | 2000 | 48 | 33 | prefInc-postInc |
postInc | 0.00543594360352 | 2000 | 48 | 35 | postInc-prefInc |
prefInc | 0.00509881973267 | 2000 | 48 | 35 | postInc-prefInc |
prefInc | 0.00483298301697 | 2000 | 48 | 36 | prefInc-postInc |
postInc | 0.00555992126465 | 2000 | 48 | 36 | prefInc-postInc |
postInc | 0.00516104698181 | 2000 | 48 | 38 | postInc-prefInc |
prefInc | 0.00512599945068 | 2000 | 48 | 38 | postInc-prefInc |
prefInc | 0.00484395027161 | 2000 | 48 | 39 | prefInc-postInc |
postInc | 0.00530505180359 | 2000 | 48 | 39 | prefInc-postInc |
postInc | 0.00509691238403 | 2000 | 48 | 41 | postInc-prefInc |
prefInc | 0.00525093078613 | 2000 | 48 | 41 | postInc-prefInc |
prefInc | 0.00447416305542 | 2000 | 48 | 42 | prefInc-postInc |
postInc | 0.00536584854126 | 2000 | 48 | 42 | prefInc-postInc |
postInc | 0.0054669380188 | 2000 | 48 | 44 | postInc-prefInc |
prefInc | 0.00468182563782 | 2000 | 48 | 44 | postInc-prefInc |
prefInc | 0.00512504577637 | 2000 | 48 | 45 | prefInc-postInc |
postInc | 0.00545692443848 | 2000 | 48 | 45 | prefInc-postInc |
postInc | 0.00782418251038 | 3000 | 48 | 47 | postInc-prefInc |
prefInc | 0.00726389884949 | 3000 | 48 | 47 | postInc-prefInc |
prefInc | 0.00674796104431 | 3000 | 48 | 48 | prefInc-postInc |
postInc | 0.007483959198 | 3000 | 48 | 48 | prefInc-postInc |
postInc | 0.00781297683716 | 3000 | 48 | 50 | postInc-prefInc |
prefInc | 0.0069580078125 | 3000 | 48 | 50 | postInc-prefInc |
prefInc | 0.00711393356323 | 3000 | 48 | 51 | prefInc-postInc |
postInc | 0.0072808265686 | 3000 | 48 | 51 | prefInc-postInc |
postInc | 0.00790119171143 | 3000 | 48 | 53 | postInc-prefInc |
prefInc | 0.00662994384766 | 3000 | 48 | 53 | postInc-prefInc |
prefInc | 0.00825595855713 | 3000 | 48 | 54 | prefInc-postInc |
postInc | 0.00739097595215 | 3000 | 48 | 54 | prefInc-postInc |
postInc | 0.00811100006104 | 3000 | 48 | 56 | postInc-prefInc |
prefInc | 0.00712990760803 | 3000 | 48 | 56 | postInc-prefInc |
prefInc | 0.00698399543762 | 3000 | 48 | 57 | prefInc-postInc |
postInc | 0.00758218765259 | 3000 | 48 | 57 | prefInc-postInc |
postInc | 0.00795316696167 | 3000 | 48 | 59 | postInc-prefInc |
prefInc | 0.00725698471069 | 3000 | 48 | 59 | postInc-prefInc |
prefInc | 0.00684094429016 | 3000 | 48 | 60 | prefInc-postInc |
postInc | 0.00778198242188 | 3000 | 48 | 60 | prefInc-postInc |
VIEWER_TGROUP
Представление в табличной форме в виде сгруппированных данных по партии тестирования (по номеру прохода по стратегии), т.е. в одной строке окажутся результаты тестирования функций которые проводились в рамках одной стратегии и в рамках одного прохода теста.
В столбцах таблицы будут отображены данные о размере выборки, времени выполнения, проценту скорости от худшего результата, затраченной памяти, комментария и названия функции, которая стала победителем по времени среди текущего прохода. Отдельно хотелось бы пояснить столбец процента. Данное значение высчитывается как процент, на сколько по времени функция опередила выполнение самой медленной функции. Если значение не установлено, значит эта функция по времени выполнения является аутсайдером в проходе.
Результат тестирования операторов инкрементирования.
size | postInc | prefInc | comment | time win | ||||
time | % | memory | time | % | memory | |||
100 | 0.000650882720947 | 48 | 0.000411987304688 | 36.7 | 48 | postInc-prefInc | prefInc | |
100 | 0.000549077987671 | 48 | 0.000406980514526 | 25.88 | 48 | prefInc-postInc | prefInc | |
100 | 0.000330924987793 | 48 | 0.000287055969238 | 13.26 | 48 | postInc-prefInc | prefInc | |
100 | 0.000365018844604 | 16.66 | 48 | 0.00043797492981 | 48 | prefInc-postInc | postInc | |
100 | 0.000295162200928 | 20.89 | 48 | 0.000373125076294 | 48 | postInc-prefInc | postInc | |
100 | 0.000449895858765 | 48 | 0.000263929367065 | 41.34 | 48 | prefInc-postInc | prefInc | |
100 | 0.00030517578125 | 48 | 0.000247955322266 | 18.75 | 48 | postInc-prefInc | prefInc | |
100 | 0.000265121459961 | 48 | 0.000244140625 | 7.91 | 48 | prefInc-postInc | prefInc | |
100 | 0.000267028808594 | 48 | 0.000245094299316 | 8.21 | 48 | postInc-prefInc | prefInc | |
100 | 0.000273942947388 | 3.93 | 48 | 0.000285148620605 | 48 | prefInc-postInc | postInc | |
1000 | 0.00273203849792 | 48 | 0.00240206718445 | 12.08 | 48 | postInc-prefInc | prefInc | |
1000 | 0.00259804725647 | 5.49 | 48 | 0.00274896621704 | 48 | prefInc-postInc | postInc | |
1000 | 0.00391817092896 | 48 | 0.00303602218628 | 22.51 | 48 | postInc-prefInc | prefInc | |
1000 | 0.00281691551208 | 48 | 0.00229096412659 | 18.67 | 48 | prefInc-postInc | prefInc | |
1000 | 0.00273108482361 | 48 | 0.00221014022827 | 19.07 | 48 | postInc-prefInc | prefInc | |
1000 | 0.00307106971741 | 48 | 0.00266814231873 | 13.12 | 48 | prefInc-postInc | prefInc | |
1000 | 0.00283098220825 | 48 | 0.00239992141724 | 15.23 | 48 | postInc-prefInc | prefInc | |
1000 | 0.00273704528809 | 48 | 0.00246214866638 | 10.04 | 48 | prefInc-postInc | prefInc | |
1000 | 0.00283288955688 | 48 | 0.00229215621948 | 19.09 | 48 | postInc-prefInc | prefInc | |
1000 | 0.0028657913208 | 48 | 0.00220608711243 | 23.02 | 48 | prefInc-postInc | prefInc | |
2000 | 0.00557017326355 | 48 | 0.0048840045929 | 12.32 | 48 | postInc-prefInc | prefInc | |
2000 | 0.0064799785614 | 48 | 0.00449013710022 | 30.71 | 48 | prefInc-postInc | prefInc | |
2000 | 0.00543594360352 | 48 | 0.00509881973267 | 6.2 | 48 | postInc-prefInc | prefInc | |
2000 | 0.00555992126465 | 48 | 0.00483298301697 | 13.07 | 48 | prefInc-postInc | prefInc | |
2000 | 0.00516104698181 | 48 | 0.00512599945068 | 0.68 | 48 | postInc-prefInc | prefInc | |
2000 | 0.00530505180359 | 48 | 0.00484395027161 | 8.69 | 48 | prefInc-postInc | prefInc | |
2000 | 0.00509691238403 | 2.93 | 48 | 0.00525093078613 | 48 | postInc-prefInc | postInc | |
2000 | 0.00536584854126 | 48 | 0.00447416305542 | 16.62 | 48 | prefInc-postInc | prefInc | |
2000 | 0.0054669380188 | 48 | 0.00468182563782 | 14.36 | 48 | postInc-prefInc | prefInc | |
2000 | 0.00545692443848 | 48 | 0.00512504577637 | 6.08 | 48 | prefInc-postInc | prefInc | |
3000 | 0.00782418251038 | 48 | 0.00726389884949 | 7.16 | 48 | postInc-prefInc | prefInc | |
3000 | 0.007483959198 | 48 | 0.00674796104431 | 9.83 | 48 | prefInc-postInc | prefInc | |
3000 | 0.00781297683716 | 48 | 0.0069580078125 | 10.94 | 48 | postInc-prefInc | prefInc | |
3000 | 0.0072808265686 | 48 | 0.00711393356323 | 2.29 | 48 | prefInc-postInc | prefInc | |
3000 | 0.00790119171143 | 48 | 0.00662994384766 | 16.09 | 48 | postInc-prefInc | prefInc | |
3000 | 0.00739097595215 | 10.48 | 48 | 0.00825595855713 | 48 | prefInc-postInc | postInc | |
3000 | 0.00811100006104 | 48 | 0.00712990760803 | 12.1 | 48 | postInc-prefInc | prefInc | |
3000 | 0.00758218765259 | 48 | 0.00698399543762 | 7.89 | 48 | prefInc-postInc | prefInc | |
3000 | 0.00795316696167 | 48 | 0.00725698471069 | 8.75 | 48 | postInc-prefInc | prefInc | |
3000 | 0.00778198242188 | 48 | 0.00684094429016 | 12.09 | 48 | prefInc-postInc | prefInc |
VIEWER_TAVG
Представление в табличной форме в виде усредненных показателей по размеру выборки, т.е. в одной строке окажутся средние показатели тестирования функций по одной выборке.
В столбцах представлена информация по количеству побед функции в выборке, средний процент времени побед, имя функции-победителя. Функции-победитель — определяется количеством побед в выборке.
Результат тестирования операторов инкрементирования.
size | postInc | prefInc | winner | ||
winns | % | winns | % | ||
100 | 3 | 13.83 | 7 | 21.72 | prefInc |
1000 | 1 | 5.49 | 9 | 16.98 | prefInc |
2000 | 1 | 2.93 | 9 | 12.08 | prefInc |
3000 | 1 | 10.48 | 9 | 9.68 | prefInc |
VIEWER_GBUBLE
Итоги
Подытожить хотелось бы тем, что поставленные цели были достигнуты. Но конечно же еще есть над чем поработать. В планах работа над обработкой исключений, добавление возможности смены в настройках набора столбцов а также возможность задавать собственные имена столбцам, увеличение количества тестов. Также хотелось бы добавить возможность удобного тестирования скорости работы с базами данных.