- PVSM.RU - https://www.pvsm.ru -

Не так давно я писал [1] о C++ библиотеках для микробенчмаркинга. Я рассказал о трех библиотеках: Nonius, Hayai и Celero. Но в действительности я хотел поговорить о четвертой. Мой Windows тогда не поддерживал Google Benchmark library, так что я не мог ее протестировать. К счастью, из комментариев к прошлому посту я узнал, что теперь библиотека доступна в Visual Studio!
Давайте посмотрим, как можно ее использовать.
→ Основной github репозиторий [2]
→ Обсуждение [3]
Благодаря коммиту KindDragon: Support MSVC on appveyor [4], мы можем собрать библиотеку в Visual Studio. Я без затруднений скачал последний код из репозитория, сгенерировал solution-файлы с помощью CMake и собрал нужную версию. Чтобы использовать библиотеку в вашем проекте, остается только подключить саму библиотеку и один заголовочный файл.
В исходной статье я проводил два эксперимента:
IntToStringConversionTest(count) — конвертирует целые числа из диапазона 0…count-1 в строки и возвращает вектор этих строк.DoubleToStringConversionTest(count) — конвертирует 0.12345… count-1+0.12345 в строки и возвращает вектор строк.Пример бенчмарков целиком:
#include "benchmark/benchmark_api.h"
#include "../commonTest.h"
void IntToString(benchmark::State& state) {
while (state.KeepRunning()) {
benchmark::DoNotOptimize(
IntToStringConversionTest(state.range_x())
);
}
}
BENCHMARK(IntToString)->Arg(TEST_NUM_COUNT1000);
void DoubleToString(benchmark::State& state) {
while (state.KeepRunning()) {
benchmark::DoNotOptimize(
DoubleToStringConversionTest(state.range_x())
);
}
}
BENCHMARK(DoubleToString)->Arg(TEST_NUM_COUNT1000);
BENCHMARK_MAIN()
Красиво и просто! Макрос BENCHMARK используется для определения бенчмарка, затем можно добавить параметры вызова. В примере выше я использовал метод Arg. Параметр в этом методе передается в объект state, доступный функции бенчмарка. В нашем примере мы получаем это значение с помощью state.range_x(). Затем оно используется как размер выходного вектора строк.
Внутри функции бенчмарка в while-цикле выполняется основной код. Количество итераций библиотека выберет автоматически.
Обычно приложение выполняется в консоли и выводит следующий результат:

Вывод очень прост: название бенчмарка, время в наносекундах (можно изменить с помощью метода Unit()), время CPU, количество выполненных итераций.
Чем же так хороша эта библиотека?
state.get_x(), state.get_y()state.SetLabel()state.SetItemsProcessed() и state.SetBytesProcessed()Вот так выглядит вывод бенчмарка с байтами в секунду, объектами в секунду, метками и измененными единицами времени.

В другом посте о библиотеках для микробенчмаркинга [5] я тестировал библиотеки на немного более сложном примере. Это мой обычный бенчмарк — вектор указателей против вектора объектов. Посмотрим, сможем ли реализовать этот пример с помощью Google Benchmark.
Вот, что мы собираемся протестировать:
vector<Particle>vector<shared_ptr<Particle>> — с рандомизацией размещения в памятиvector<shared_ptr<Particle>> — без рандомизации размещения в памятиvector<unique_ptr<Particle>> — с рандомизацией размещения в памятиvector<unique_ptr<Particle>> — без рандомизации размещения в памяти
Пример кода для vector<Particle>:
template <class Part>
class ParticlesObjVectorFixture : public ::benchmark::Fixture {
public:
void SetUp(const ::benchmark::State& st) {
particles = std::vector<Part>(st.range_x());
for (auto &p : particles)
p.generate();
}
void TearDown(const ::benchmark::State&) {
particles.clear();
}
std::vector<Part> particles;
};
А вот бенчмарк:
using P76Fix = ParticlesObjVectorFixture<Particle>;
BENCHMARK_DEFINE_F(P76Fix, Obj)(benchmark::State& state) {
while (state.KeepRunning()) {
UpdateParticlesObj(particles);
}
}
BENCHMARK_REGISTER_F(P76Fix, Obj)->Apply(CustomArguments);
using P160Fix = ParticlesObjVectorFixture<Particle160>;
BENCHMARK_DEFINE_F(P160Fix, Obj)(benchmark::State& state) {
while (state.KeepRunning()) {
UpdateParticlesObj(particles);
}
}
BENCHMARK_REGISTER_F(P160Fix, Obj)->Apply(CustomArguments);
С помощью этого кода мы протестируем два вида частиц: маленькие — 76 байт и побольше — 160 байт. Метод CustomArguments генерирует количество частиц для каждой итерации бенчмарка: 1k, 3k, 5k, 7k, 9k, 11k.
В этом посте мы уделили основное внимание самой библиотеке, но я хотел бы ответить на вопрос, который мне задавали раньше — вопрос о различных размерах частиц. Пока я использовал только два типа: 76-байтные и 160-байтные.
Результаты для 76 байт:

Рандомизированные указатели почти на 76% медленнее, чем векторы объектов.
Результаты для 160 байт:

Почти прямые линии в случае больших частиц! Рандомизированные указатели медленнее только на 17%…. Ну хорошо, пускай не совсем прямые :)
Кроме того, мы протестировали и unique_ptr. Как видите, с точки зрения update (доступа к данным), скорость почти такая же, как и у shared_ptr. Таким образом, косвенное обращение — это проблема умного указателя, а не неизбежные накладные расходы.
Репозиторий с примерами кода [6]
У меня не было трудностей с использованием Google Benchmark library. Вы сможете освоить основные принципы написания бенчмарков за несколько минут. Многопоточные бенчмарки, fixture, автоматический подбор количества итераций, вывод в формате CSV или Json — вот и все базовые функции. Лично мне больше всего нравится гибкость передачи параметров в код бенчмарка. У остальных проверенных мной библиотек имелись проблемы с тем, чтобы передать бенчмарку параметры проблемной области. Самой простой с этой точки зрения была Celero.
Не хватает, пожалуй, только расширенного отображения результатов. Библиотека показывает нам только среднее время выполнения итераций. Хотя в большинстве случаев этого достаточно.
С точки зрения эксперимента, я получил интересные результаты для частиц разного размера. Это может стать основой для будущего финального теста. Я попробую переписать мои примеры с большим разнообразием размеров объектов. Ожидаю увидеть огромную разницу в результатах для маленьких объектов и незначительную — для больших.
О, а приходите к нам работать? :)wunderfund.io [7] — молодой фонд, который занимается высокочастотной алготорговлей [8]. Высокочастотная торговля — это непрерывное соревнование лучших программистов и математиков всего мира. Присоединившись к нам, вы станете частью этой увлекательной схватки.Мы предлагаем интересные и сложные задачи по анализу данных и low latency разработке для увлеченных исследователей и программистов. Гибкий график и никакой бюрократии, решения быстро принимаются и воплощаются в жизнь.
Присоединяйтесь к нашей команде: wunderfund.io [7]
Автор: Wunder Fund
Источник [9]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/programmirovanie/251840
Ссылки в тексте:
[1] я писал: http://www.bfilipek.com/2016/01/micro-benchmarking-libraries-for-c.html
[2] Основной github репозиторий: https://github.com/google/benchmark
[3] Обсуждение: https://groups.google.com/forum/#!forum/benchmark-discuss
[4] Support MSVC on appveyor: https://github.com/google/benchmark/commit/9e37d69b23743db226a284ca709a3a89bda30c2d
[5] другом посте о библиотеках для микробенчмаркинга: http://www.bfilipek.com/2016/02/revisiting-old-benchmark-vector-of.html
[6] Репозиторий с примерами кода: https://github.com/fenbf/benchmarkLibsTest
[7] wunderfund.io: http://wunderfund.io
[8] высокочастотной алготорговлей: https://en.wikipedia.org/wiki/High-frequency_trading
[9] Источник: https://habrahabr.ru/post/325634/
Нажмите здесь для печати.