Сообщение [CodeJam] PerformaceTests, pre-alpha от 11.04.2016 21:11
Изменено 13.04.2016 13:13 Sinix
Отпишусь пожалуй, чтобы не забыть по горячим следам и потом проще было документацию писать.
Поехали
Набор хелперов для competition performance tests, работающий поверх единственного более-менее правильного .net-фреймворка для бенчмарков — BenchmarkDotNet. В CodeJam лежит в проекте CodeJam.Main-Tests.Performance.
Говоря русским языком, эта штука позволяет написать набор реализаций-кандидатов, дополнить их образцом (baseline test), оформить в виде юнит-теста, и дальше CI-сервер за вас сам проверяет, что все реализации укладываются в заданные лимиты по производительности. Лимиты записываются в виде коэффициентов — производительность относительно baseline.
Абсолютные значения тут неприменимы по очевидным причинам: тесты будут выполняться на разном железе/в разном окружении и абсолютное время может легко различаться в разы.
Главная и уникальная киллфича проекта: нет необходимости самому размечать лимиты по перфомансу для каждого из тестов, это делается автоматически.
Чтоб было понятно о чём речь: простейший тест, который гарантирует, что sum += i выполняется примерно в полтора раза быстрее, чем sum += i + 1 выглядит
Минимальный/максимальный коэффициенты в [CompetitionBenchmark(1.55, 1.65)] заполнены автоматически. После того, как режим автозаполнения отключен, тест упадёт, если Test01PlusOne будет выполняться быстрее/медленнее заданных значений.
Пример — см папку Arithmetic с перфтестами для Operators<T>.
Во-вторых, для регрессионных юнит-тестов и для документирования perf-контракта.
К сожалению, не всё можно обойти самостоятельно и часть изменений надо продавить в виде pull requests в сам BenchmarkDotNet.
Сюрпрайз №2: похоже, очень мало кто занимается перфтестами, поэтому помимо "что надо поменять" нужно ещё обосновать "зачем это надо" даже в очевидных (мне ) моментах.
Это ещё больше замедляет дело, так что точных сроков когда я назвать пока не могу.
Проблемные моменты:
1. В текущей реализации каждый метод-кандидат собирается как отдельный бинарник и запускается в собственном процессе. В лучшем случае каждый тест занимает 5-10 секунд, бонусом идёт 2..20 мб мусора в папке bin. Это ключевой затык, тикет с проверенно рабочим решением заведён, жду ответа от команды Bench.NET.
2. Нет возможности задать лимиты по аллокациям/сборкам мусора. Точнее, она есть, но ждёт реализации п.1.
Если есть желание добавить свой перфест, на примере кода выше:
1. Написать метод-образец, пометить как [CompetitionBaseline]
2. Написать методы-кандидаты, пометить их как [CompetitionBenchmark]. В параметрах конструктора атрибута можно указать лимиты по времени в виде мин/макс коэффициентов относительно Baseline-метода.
3. Добавить запуск бенчмарка:
4. Если лень расставлять коэффициенты самому:
4.1. в App.config ставим value="true" в строчке
Чтобы случайно не закоммитить изменённый конфиг, рекомендую пометить его как skip-worktree (в tortoisegit: check for modifications — Skip worktree в контекстном меню).
4.2. Запустить тест вручную через VS test explorer. Раннер решарпера (по крайней мере в EAP) пока не поддерживается.
* В режиме автоаннотации тест выполняется в несколько проходов (до 10), пока не начнёт укладываться в свежесобранные лимиты. Т.е. если обычных десяти секунд тест выполняется полторы минуты — это нормально.
После завершения работы теста значения min/max в [CompetitionBenchmark] будут заполнены актуальными лимитами.
5. После того, как лимиты расставлены, запустить тест. Если он зелёный — вы угадали с лимитами. Если он красный — или лимиты слишком жёсткие, или реализация одного из методов поменялась и вы нашли баг
Подробнее — см сообщения теста и таблицу с результатами в output.
6. Для динамически генерируемых бенчмарков лимиты можно задавать в виде xml-файла. Пример см в NumOperatorsPerfTest.generated.cs. Для этого надо:
6.1. Добавить xml-файл рядом с файлом с кодом бенчмарка, build action — embedded resource. Имя файла должно различаться только расширением (.xml вместо .cs). Содержимое файла:
6.2. Пометить класс с бенчмарками атрибутом
Параметр атрибута — имя ресурса с xml-файлом.
6.3. В коде не указывать лимиты в виде параметров [CompetitionBenchmark] — они будут игнорироваться.
6.4. Запустить перфтест в режиме авто-аннотирования.
Вопросы / предложения? Велкам
P.S. Будет обновляться по мере появления вопросов/прогресса/наличия свободного времени.
Поехали
Что это такое
Набор хелперов для competition performance tests, работающий поверх единственного более-менее правильного .net-фреймворка для бенчмарков — BenchmarkDotNet. В CodeJam лежит в проекте CodeJam.Main-Tests.Performance.
Говоря русским языком, эта штука позволяет написать набор реализаций-кандидатов, дополнить их образцом (baseline test), оформить в виде юнит-теста, и дальше CI-сервер за вас сам проверяет, что все реализации укладываются в заданные лимиты по производительности. Лимиты записываются в виде коэффициентов — производительность относительно baseline.
Абсолютные значения тут неприменимы по очевидным причинам: тесты будут выполняться на разном железе/в разном окружении и абсолютное время может легко различаться в разы.
Главная и уникальная киллфича проекта: нет необходимости самому размечать лимиты по перфомансу для каждого из тестов, это делается автоматически.
Чтоб было понятно о чём речь: простейший тест, который гарантирует, что sum += i выполняется примерно в полтора раза быстрее, чем sum += i + 1 выглядит
вот так: | |
| |
Минимальный/максимальный коэффициенты в [CompetitionBenchmark(1.55, 1.65)] заполнены автоматически. После того, как режим автозаполнения отключен, тест упадёт, если Test01PlusOne будет выполняться быстрее/медленнее заданных значений.
Зачем это нужно
Во-первых, чтобы принимать обоснованные решения о выборе конкретной реализации и чтобы узнать, что текущая реализация перестала быть оптимальной при смене компилятора/фреймворка.Пример — см папку Arithmetic с перфтестами для Operators<T>.
Во-вторых, для регрессионных юнит-тестов и для документирования perf-контракта.
В каком оно состоянии
Pre-alpha. Проблема в следующем: BenchmarkDotNet не затачивался под запуск в виде юнит-тестов, всю доработку напильником приходится делать самому.К сожалению, не всё можно обойти самостоятельно и часть изменений надо продавить в виде pull requests в сам BenchmarkDotNet.
Сюрпрайз №2: похоже, очень мало кто занимается перфтестами, поэтому помимо "что надо поменять" нужно ещё обосновать "зачем это надо" даже в очевидных (мне ) моментах.
Это ещё больше замедляет дело, так что точных сроков когда я назвать пока не могу.
Проблемные моменты:
1. В текущей реализации каждый метод-кандидат собирается как отдельный бинарник и запускается в собственном процессе. В лучшем случае каждый тест занимает 5-10 секунд, бонусом идёт 2..20 мб мусора в папке bin. Это ключевой затык, тикет с проверенно рабочим решением заведён, жду ответа от команды Bench.NET.
2. Нет возможности задать лимиты по аллокациям/сборкам мусора. Точнее, она есть, но ждёт реализации п.1.
Как использовать:
На сегодня — только внутри самого CodeJam. Я намеренно не выпускаю отдельный пакет, т.к. в процессе догфудинга время от времени удаётся заметно облегчить написание/использование юнит-тестов. В частности, с вероятностью в 100% будут поправлены имена классов/методов в самих перфтестах, текущий вариант неудачный.Если есть желание добавить свой перфест, на примере кода выше:
1. Написать метод-образец, пометить как [CompetitionBaseline]
2. Написать методы-кандидаты, пометить их как [CompetitionBenchmark]. В параметрах конструктора атрибута можно указать лимиты по времени в виде мин/макс коэффициентов относительно Baseline-метода.
3. Добавить запуск бенчмарка:
[Test]
public void TestName() => CompetitionBenchmarkRunner.Run(this, AssemblyWideConfig.RunConfig);
поддерживается любой из юнит-тест-фреймворков. Главное, чтоб он распознавал исключения как ошибки теста и перенаправлял вывод на консоль в output теста.4. Если лень расставлять коэффициенты самому:
4.1. в App.config ставим value="true" в строчке
<add key="AssemblyWideConfig.AnnotateOnRun" value="false" />
Чтобы случайно не закоммитить изменённый конфиг, рекомендую пометить его как skip-worktree (в tortoisegit: check for modifications — Skip worktree в контекстном меню).
4.2. Запустить тест вручную через VS test explorer. Раннер решарпера (по крайней мере в EAP) пока не поддерживается.
* В режиме автоаннотации тест выполняется в несколько проходов (до 10), пока не начнёт укладываться в свежесобранные лимиты. Т.е. если обычных десяти секунд тест выполняется полторы минуты — это нормально.
После завершения работы теста значения min/max в [CompetitionBenchmark] будут заполнены актуальными лимитами.
5. После того, как лимиты расставлены, запустить тест. Если он зелёный — вы угадали с лимитами. Если он красный — или лимиты слишком жёсткие, или реализация одного из методов поменялась и вы нашли баг
Подробнее — см сообщения теста и таблицу с результатами в output.
6. Для динамически генерируемых бенчмарков лимиты можно задавать в виде xml-файла. Пример см в NumOperatorsPerfTest.generated.cs. Для этого надо:
6.1. Добавить xml-файл рядом с файлом с кодом бенчмарка, build action — embedded resource. Имя файла должно различаться только расширением (.xml вместо .cs). Содержимое файла:
<?xml version="1.0" encoding="utf-8"?>
<CompetitionBenchmarks>
</CompetitionBenchmarks>
6.2. Пометить класс с бенчмарками атрибутом
[CompetitionMetadata("CodeJam.Arithmetic.NumOperatorsPerfTest.generated.xml")] // имя ресурса
public class NumOperatorsPerfTest
Параметр атрибута — имя ресурса с xml-файлом.
6.3. В коде не указывать лимиты в виде параметров [CompetitionBenchmark] — они будут игнорироваться.
6.4. Запустить перфтест в режиме авто-аннотирования.
Вопросы / предложения? Велкам
P.S. Будет обновляться по мере появления вопросов/прогресса/наличия свободного времени.
[CodeJam] PerformaceTests, pre-alpha
Отпишусь пожалуй, чтобы не забыть по горячим следам и потом проще было документацию писать.
Поехали
Набор хелперов для competition performance tests, работающий поверх единственного более-менее правильного .net-фреймворка для бенчмарков — BenchmarkDotNet. В CodeJam лежит в проекте CodeJam.Main-Tests.Performance.
Говоря русским языком, эта штука позволяет написать набор реализаций-кандидатов, дополнить их образцом (baseline test), оформить в виде юнит-теста, и дальше CI-сервер за вас сам проверяет, что все реализации укладываются в заданные лимиты по производительности. Лимиты записываются в виде коэффициентов — производительность относительно baseline.
Абсолютные значения тут неприменимы по очевидным причинам: тесты будут выполняться на разном железе/в разном окружении и абсолютное время может легко различаться в разы.
Главная и уникальная киллфича проекта: нет необходимости самому размечать лимиты по перфомансу для каждого из тестов, это делается автоматически.
Чтоб было понятно о чём речь: простейший тест, который гарантирует, что sum += i выполняется примерно в полтора раза быстрее, чем sum += i + 1 выглядит
Минимальный/максимальный коэффициенты в [CompetitionBenchmark(1.55, 1.65)] заполнены автоматически. После того, как режим автозаполнения отключен, тест упадёт, если Test01PlusOne будет выполняться быстрее/медленнее заданных значений.
Пример — см папку Arithmetic с перфтестами для Operators<T>.
Во-вторых, для регрессионных юнит-тестов и для документирования perf-контракта.
К сожалению, не всё можно обойти самостоятельно и часть изменений надо продавить в виде pull requests в сам BenchmarkDotNet.
Сюрпрайз №2: похоже, очень мало кто занимается перфтестами, поэтому помимо "что надо поменять" нужно ещё обосновать "зачем это надо" даже в очевидных (мне ) моментах.
Это ещё больше замедляет дело, так что точных сроков когда я назвать пока не могу.
Проблемные моменты:
1. В текущей реализации каждый метод-кандидат собирается как отдельный бинарник и запускается в собственном процессе. В лучшем случае каждый тест занимает 5-10 секунд, бонусом идёт 2..20 мб мусора в папке bin. Это ключевой затык, тикет с проверенно рабочим решением заведён, жду ответа от команды Bench.NET.
2. Нет возможности задать лимиты по аллокациям/сборкам мусора. Точнее, она есть, но ждёт реализации п.1.
Если есть желание добавить свой перфест, на примере кода выше:
1. Написать метод-образец, пометить как [CompetitionBaseline]
2. Написать методы-кандидаты, пометить их как [CompetitionBenchmark]. В параметрах конструктора атрибута можно указать лимиты по времени в виде мин/макс коэффициентов относительно Baseline-метода. Значения коэффициентов <0 обрабатываются как "не учитывать". Итого:
3. Добавить запуск бенчмарка:
4. Если лень расставлять коэффициенты самому:
4.1. в App.config ставим value="true" в строчке
Чтобы случайно не закоммитить изменённый конфиг, рекомендую пометить его как skip-worktree (в tortoisegit: check for modifications — Skip worktree в контекстном меню).
4.2. Запустить тест вручную через VS test explorer. Раннер решарпера (по крайней мере в EAP) пока не поддерживается.
* В режиме автоаннотации тест выполняется в несколько проходов (до 10), пока не начнёт укладываться в свежесобранные лимиты. Т.е. если обычных десяти секунд тест выполняется полторы минуты — это нормально.
После завершения работы теста значения min/max в [CompetitionBenchmark] будут заполнены актуальными лимитами.
5. После того, как лимиты расставлены, запустить тест. Если он зелёный — вы угадали с лимитами. Если он красный — или лимиты слишком жёсткие, или реализация одного из методов поменялась и вы нашли баг
Подробнее — см сообщения теста и таблицу с результатами в output.
6. Для динамически генерируемых бенчмарков лимиты можно задавать в виде xml-файла. Пример см в NumOperatorsPerfTest.generated.cs. Для этого надо:
6.1. Добавить xml-файл рядом с файлом с кодом бенчмарка, build action — embedded resource. Имя файла должно различаться только расширением (.xml вместо .cs). Содержимое файла:
6.2. Пометить класс с бенчмарками атрибутом
Параметр атрибута — имя ресурса с xml-файлом.
6.3. В коде не указывать лимиты в виде параметров [CompetitionBenchmark] — они будут игнорироваться.
6.4. Запустить перфтест в режиме авто-аннотирования.
Вопросы / предложения? Велкам
P.S. Будет обновляться по мере появления вопросов/прогресса/наличия свободного времени.
Поехали
Что это такое
Набор хелперов для competition performance tests, работающий поверх единственного более-менее правильного .net-фреймворка для бенчмарков — BenchmarkDotNet. В CodeJam лежит в проекте CodeJam.Main-Tests.Performance.
Говоря русским языком, эта штука позволяет написать набор реализаций-кандидатов, дополнить их образцом (baseline test), оформить в виде юнит-теста, и дальше CI-сервер за вас сам проверяет, что все реализации укладываются в заданные лимиты по производительности. Лимиты записываются в виде коэффициентов — производительность относительно baseline.
Абсолютные значения тут неприменимы по очевидным причинам: тесты будут выполняться на разном железе/в разном окружении и абсолютное время может легко различаться в разы.
Главная и уникальная киллфича проекта: нет необходимости самому размечать лимиты по перфомансу для каждого из тестов, это делается автоматически.
Чтоб было понятно о чём речь: простейший тест, который гарантирует, что sum += i выполняется примерно в полтора раза быстрее, чем sum += i + 1 выглядит
вот так: | |
| |
Минимальный/максимальный коэффициенты в [CompetitionBenchmark(1.55, 1.65)] заполнены автоматически. После того, как режим автозаполнения отключен, тест упадёт, если Test01PlusOne будет выполняться быстрее/медленнее заданных значений.
Зачем это нужно
Во-первых, чтобы принимать обоснованные решения о выборе конкретной реализации и чтобы узнать, что текущая реализация перестала быть оптимальной при смене компилятора/фреймворка.Пример — см папку Arithmetic с перфтестами для Operators<T>.
Во-вторых, для регрессионных юнит-тестов и для документирования perf-контракта.
В каком оно состоянии
Pre-alpha. Проблема в следующем: BenchmarkDotNet не затачивался под запуск в виде юнит-тестов, всю доработку напильником приходится делать самому.К сожалению, не всё можно обойти самостоятельно и часть изменений надо продавить в виде pull requests в сам BenchmarkDotNet.
Сюрпрайз №2: похоже, очень мало кто занимается перфтестами, поэтому помимо "что надо поменять" нужно ещё обосновать "зачем это надо" даже в очевидных (мне ) моментах.
Это ещё больше замедляет дело, так что точных сроков когда я назвать пока не могу.
Проблемные моменты:
1. В текущей реализации каждый метод-кандидат собирается как отдельный бинарник и запускается в собственном процессе. В лучшем случае каждый тест занимает 5-10 секунд, бонусом идёт 2..20 мб мусора в папке bin. Это ключевой затык, тикет с проверенно рабочим решением заведён, жду ответа от команды Bench.NET.
2. Нет возможности задать лимиты по аллокациям/сборкам мусора. Точнее, она есть, но ждёт реализации п.1.
Как использовать:
На сегодня — только внутри самого CodeJam. Я намеренно не выпускаю отдельный пакет, т.к. в процессе догфудинга время от времени удаётся заметно облегчить написание/использование юнит-тестов. В частности, с вероятностью в 100% будут поправлены имена классов/методов в самих перфтестах, текущий вариант неудачный.Если есть желание добавить свой перфест, на примере кода выше:
1. Написать метод-образец, пометить как [CompetitionBaseline]
2. Написать методы-кандидаты, пометить их как [CompetitionBenchmark]. В параметрах конструктора атрибута можно указать лимиты по времени в виде мин/макс коэффициентов относительно Baseline-метода. Значения коэффициентов <0 обрабатываются как "не учитывать". Итого:
[CompetitionBenchmark] // падает всегда, т.к. не заданы границы.
[CompetitionBenchmark(1.5, 3)] // падает, если быстрее, чем 1.5x и медленнее, чем 3x.
[CompetitionBenchmark(1.5, -1)] // падает, если быстрее, чем 1.5x.
[CompetitionBenchmark(-1, 3)] // падает, если медленнее, чем 3x.
[CompetitionBenchmark(3)] // падает, если медленнее, чем 3x.
[CompetitionBenchmark(-2, -3)] // не падает вообще.
[Benchmark] // не падает вообще.
3. Добавить запуск бенчмарка:
[Test]
public void TestName() => CompetitionBenchmarkRunner.Run(this, AssemblyWideConfig.RunConfig);
поддерживается любой из юнит-тест-фреймворков. Главное, чтоб он распознавал исключения как ошибки теста и перенаправлял вывод на консоль в output теста.4. Если лень расставлять коэффициенты самому:
4.1. в App.config ставим value="true" в строчке
<add key="AssemblyWideConfig.AnnotateOnRun" value="false" />
Чтобы случайно не закоммитить изменённый конфиг, рекомендую пометить его как skip-worktree (в tortoisegit: check for modifications — Skip worktree в контекстном меню).
4.2. Запустить тест вручную через VS test explorer. Раннер решарпера (по крайней мере в EAP) пока не поддерживается.
* В режиме автоаннотации тест выполняется в несколько проходов (до 10), пока не начнёт укладываться в свежесобранные лимиты. Т.е. если обычных десяти секунд тест выполняется полторы минуты — это нормально.
После завершения работы теста значения min/max в [CompetitionBenchmark] будут заполнены актуальными лимитами.
5. После того, как лимиты расставлены, запустить тест. Если он зелёный — вы угадали с лимитами. Если он красный — или лимиты слишком жёсткие, или реализация одного из методов поменялась и вы нашли баг
Подробнее — см сообщения теста и таблицу с результатами в output.
6. Для динамически генерируемых бенчмарков лимиты можно задавать в виде xml-файла. Пример см в NumOperatorsPerfTest.generated.cs. Для этого надо:
6.1. Добавить xml-файл рядом с файлом с кодом бенчмарка, build action — embedded resource. Имя файла должно различаться только расширением (.xml вместо .cs). Содержимое файла:
<?xml version="1.0" encoding="utf-8"?>
<CompetitionBenchmarks>
</CompetitionBenchmarks>
6.2. Пометить класс с бенчмарками атрибутом
[CompetitionMetadata("CodeJam.Arithmetic.NumOperatorsPerfTest.generated.xml")] // имя ресурса
public class NumOperatorsPerfTest
Параметр атрибута — имя ресурса с xml-файлом.
6.3. В коде не указывать лимиты в виде параметров [CompetitionBenchmark] — они будут игнорироваться.
6.4. Запустить перфтест в режиме авто-аннотирования.
Вопросы / предложения? Велкам
P.S. Будет обновляться по мере появления вопросов/прогресса/наличия свободного времени.