Здравствуй, уважаемый Хабр! Я являюсь участником разработки автоматизированных систем управления высокой надежности, которые применяются на электростанциях, космодромах, сложных производствах и т.п. Однажды передо мной встала задача придумать метод проверки работоспособности программ в условиях загруженности
- Загруженность процессора
- Загруженность сети отправкой/приемом
- Нехватка оперативной памяти
- Загруженность жесткого диска запросами чтения/записи
Под катом описываются две утилитки, которые у меня получились и принцип их работы, а так же парочка скриншотов и видео.
Итак у нас есть набор тестируемых программ.
Необходимо разработать программу, которая проверяла бы их устойчивость при большой загруженности процессора.
Казалось бы, что может быть проще:
while true do
x:=x+1-1;
вот и загрузили машину.
Но нужно ли объяснять, что сто процентов загрузки процессора (из диспетчера задач) ста процентам рознь. Во первых, на компьютере, возможно, имеется несколько ядер, и при загрузке одного ядра другое будет спокойно работать. Во вторых, даже если все ядра процессора заняты на 100%, и вентилятор охлаждения, изрыгая раскаленный воздух, вот-вот отправит компьютер в свободный полет по кабинету, нет никаких гарантий, что это окажет хоть какое-то влияние на работу тестируемых программ, что уж говорить о каких-то видимых
А хочется, чтобы MouseClick был через три секунды после MouseDown, чтобы таймер с периодом секунда срабатывал через 5 секунд, чтобы потокам программы было действительно «трудно» синхронизироваться, и чтобы творился управляемый хаос.
Тут становится ясно, что необходимо создавать для каждого ядра/процессора отдельный поток (class TThread).
Выясняем количество ядер:
var info: TSystemInfo;
...
GetSystemInfo(info);
n:=info.dwNumberOfProcessors;
Далее создаем n потоков, в которых крутятся какие-нибудь бессмысленные вычисления. Операционная система сама распределяет их по разным ядрам. При этом необходимо, чтобы приоритет созданных потоков случайным образом переключался как минимум между двумя значениями. Если этого не сделать, то при их низком приоритете тестируемые программы могут ничего не «почувствовать», а при слишком высоком — могут почти не получать процессорного времени. Так как приоритеты созданных нами нескольких потоков могут оказаться критичными, для гарантированного переключения из tpTimeCritical во что-нибудь другое необходимо, чтобы этим занялся сам критичный поток.
В своей программке, при создании потоков я делаю один из них «бригадиром», который переключает свой приоритет и приоритеты всех остальных синхронно себе (хорошим бригадиром: и руководит и сам работает).
Для того чтобы помочь управляющему потоку решить, когда и на какой приоритет переключать, при создании я задаю ему необходимые параметры:
- pr1 — значение приоритета 1
- pr2 — значение приоритета 2
- P1 — вероятность переключения в приоритет 1
- P2 — вероятность переключения в приоритет 2
- Tmax — максимальный интервал времени, через который необходимо разыграть переключение приоритетов
Ясно, что P1+p2=100%;
Если определить, что pr1 – критичный приоритет, а pr2 – нормальный, то получим своего рода «управляемый хаос»: череда почти полных остановок в работе компьютера с заданным распределением.
Остается это все как-то проверить и зафиксировать.
Итак…
Вершим хаос и наблюдаем
Я использовал нечто вроде временной шкалы:
По обычному таймеру с интервалом 100мсек содержимое этой шкалы смещается влево на M пикселей, где M – количество сотен миллисекунд, прошедших с предыдущего такта. Освободившееся справа место заполняется красным цветом, а самый правый столбик пикселей заполняется оттенком зеленого. Таким образом, если никаких задержек нет, т.е. M = 1, содержимое шкалы каждые 100 мсек сползает влево на 1 пиксель, справа дорисовывается зеленый столбик. При появлении существенных задержек M оказывается больше 1 и мы начинаем наблюдать красные полосы, ширина которых пропорциональна случившейся задержке. Цифры справа от шкалы показывают соотношение времени задержек ко времени нормальной работы за последние несколько секунд. Видеозапись иллюстрирует весь процесс:
В «красных зонах» на видео видно, как еле-еле работает мышка.
От себя добавлю, что в видео не показано: не проигрывается музыка, видео, не запускаются программы и т.п.
Ну вот, теперь осталось лишь сделать такую шкалу для каждого ядра процессора отдельно, и можно наблюдать, делать скриншоты, оценивать насколько та или иная программа устраивает задержки в работе того или иного ядра или даже всего процессора.
Для этого создаем столько потоков, сколько ядер в процессоре. Принуждаем систему исполнять их на разных ядрах с помощью API:
SetThreadAffinityMask(handle,mask);
Каждый такой процесс в памяти держит свою шкалу и дорисовывает её в памяти по вышеуказанному алгоритму. При этом, можно увеличить чувствительность к задержкам, уменьшив время между тактами. Ну а в основной программе, по отдельному таймеру все эти шкалы выводятся подряд одна над другой. Результат можно лицезреть на видео:
Для того чтобы оценить, на сколько тестируемая программа делает задержки в работе других программ, в моем конкретном случае хватило нескольких субъективных оценок изображений этих шкал в стиле:
«шкалы в основном зеленые по всем ядрам, поэтому программа А не сильно мешает другим программам, а для программы Б наоборот — шкалы наполовину красные, что не может не насторожить».
Однако стоит отметить, что для проведения численной оценки задержек, которые делает в системе программа, необходимо выявление таких показателей как: функция распределения времени задержек, мат. ожидание задержек, дисперсия задержек.
Именно эти показатели позволят избежать субъективных оценок, а так же позволят формулировать четкие требования к программам и алгоритмам.
Если уважаемое Хабрасообщество сочтет такую информацию полезной — с удовольствием сделаю это темой следующего топика.
Надеюсь, сей текст окажется кому-то интересным, а если окажется кому-то нужным, то это сделает меня совсем счастливым! ;-)
PS. Я здесь новичок. Честно пересмотрел все разделы сайта, не нашел более подходящего места для размещения. Буду признателен за подсказки.
UPD
Спасибо хабралюдям за ссылки на похожие решения и инструменты.
Вот их список:
- Load Test Analyzer — инструмент от Microsoft, входящий в состав VS Ultimate. Благодарим EndUser
- Windows Hardware Quality Labs testing — тоже от Microsoft. Благодарим int80h
- Iperf — генератор TCP и UDP трафика. Благодарим amarao