Подтвердить что ты не робот

Как я могу unit test оптимизировать производительность на С#?

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

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

Любые идеи о том, как я буду обращаться к этому в С#/.NET 4?

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

РЕДАКТИРОВАТЬ 2: Подумайте об этом так: как вы примените red- > green- > refactor, когда производительность является критическим требованием?

4b9b3361

Ответ 1

Я отвечу на третью часть вашего вопроса, так как я сделал это с некоторым успехом несколько раз.

как вы примените red- > green- > refactor, когда производительность будет критическое требование?

  • Записывайте тесты для фиксации регрессий, для того, что вы планируете изменить, и других методов, которые могут замедляться в результате ваших изменений.
  • Запишите тест производительности, который не работает.
  • Сделайте улучшения производительности, часто выполняйте все тесты.
  • Обновите тесты на пиннинг, чтобы более точно настроить производительность.

Записывать тесты пиннинга

Создайте вспомогательный метод, подобный этому, к тому, что вы хотите вывести.

private TimeSpan Time(Action toTime)
{
    var timer = Stopwatch.StartNew();
    toTime();
    timer.Stop();
    return timer.Elapsed;
}

Затем напишите тест, который утверждает, что ваш метод не требует времени:

[Test]
public void FooPerformance_Pin()
{
    Assert.That(Time(()=>fooer.Foo()), Is.LessThanOrEqualTo(TimeSpan.FromSeconds(0));
}

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

[Test]
public void FooPerformance_Pin()
{
    Assert.That(Time(()=>fooer.Foo()), Is.LessThanOrEqualTo(TimeSpan.FromSeconds(0.8));
}
[Test]
public void BarPerformance_Pin()
{
    Assert.That(Time(()=>fooer.Foo()), Is.LessThanOrEqualTo(TimeSpan.FromSeconds(6));
}

Записать неудачный тест производительности

Мне нравится называть этот тест "испытанием на избиение". Это только первый шаг теста пиннинга.

[Test]
public void FooPerformance_Bait()
{
    Assert.That(Time(()=>fooer.Foo()), Is.LessThanOrEqualTo(TimeSpan.FromSeconds(0));
}

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

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

Что вы будете делать с этими тестами сейчас?

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

На противоположной стороне спектра работы создание разумно хорошо контролируемой подсистемы в CI для запуска таких тестов - действительно хороший способ контролировать регрессии производительности. По моему опыту есть много беспокойства о том, что они "случайно не работают из-за загрузки процессора из чего-то другого", чем есть фактические сбои. Успех такого рода усилий зависит в большей степени от командной культуры, чем от вашей способности осуществлять контроль над окружающей средой.