Для измерения скорости работы будем использовать счетчик производительности — это высокопроизводительный счетчик, поддерживаемый системой для измерения производительности. Текущее значение счетчика можно узнать с помощью функции
QueryPerformanceCounter
, число тактов счетчика в секунду — с помощью функции
QueryPerformanceFrequency
. Этот счетчик позволяет получить более точные результаты, чем традиционно применяющаяся для таких целей функция
GetTickCount
. Теоретически, счетчик производительности может не поддерживаться аппаратной частью (в этом случае функция
QueryPerformanceFrequency
вернет нулевую частоту), однако все современные компьютеры такой счетчик поддерживают, поэтому его можно применять без опасений.
В зависимости от параметра
PixelFormat
метод
DoTest
создает DDB- или DIB-изображение и тестирует скорость исполнения операций с ним. В первом тесте
Cnt
раз рисуется линия случайного цвета со случайными координатами — так проверяется скорость рисования на картинке. Разумеется, это весьма односторонний тест, т.к. при рисовании других примитивов будет, скорее всего, иное соотношение скоростей для DIB и DDB. Но общее представление о соотношении скоростей он все же дает.
Во втором тесте полученное изображение
Cnt
раз выводится на экран. Если бы оно выводилось всегда в одном и том же месте, пользователь не видел бы процесс вывода на экран, т.к. каждый следующий раз картинка рисовалась бы точно в том же месте, что и в предыдущий, и общее изображение не менялось бы. Чтобы этого не происходило, изображение выводится со случайным смещением относительно базовых координат, и пользователь может наблюдать за процессом. Кроме того, координаты определяются также параметром XOfs — это сделано для того, чтобы при тестировании DDB- и DIB-изображений рисунки выводились в разных частях окна и не накладывались
друг на друга.
На некоторых компьютерах в этом тесте с DDB-изображением наблюдается интересный эффект: время, измеренное программой, заметно меньше, чем время, когда картинка меняется на экране (например, пользователь ясно видит, что тест выполняется в течение примерно трех секунд, в то время как программа дает значение около одной секунды). Это связано со способностью некоторых видеокарт буферизовать переданные им команды и выполнять их асинхронно, т.е. вызов функции завершается очень быстро, программа продолжает работать дальше, а видеокарта параллельно ей выполняет команду. Если вы столкнетесь с такой ситуацией, можете провести небольшой эксперимент: вставить вызов функции Beep сразу после окончания второго теста. Вы услышите звуковой сигнал раньше, чем изображение закончит меняться.
Третий тест самый простой:
Cnt
раз значение свойства ScanLine присваивается переменной
P
. Так как значение
P
потом нигде не используется, компилятор выдает соответствующую подсказку, но в данном случае ее можно игнорировать.
Таким образом, метод
DoTest
нужно вызвать два раза: для DDB-изображения и для DIB это делает обработчик нажатия кнопки
BtnStart
(листинг 1.41).
Листинг 1.41. Обработчик нажатия кнопки
BtnStart
procedure TForm1.BtnStartClick(Sender: TObject);
var
IterCnt, RandomStart: Integer;
begin
IterCnt := StrToInt(EditIter.Text);
GridResults.Cells[1, 1] := '';
GridResults.Cells[1, 2] := '';
GridResults.Cells[1, 3] := '';
GridResults.Cells[2, 1] := '';
GridResults.Cells[2, 2] := '';
GridResults.Cells[2, 3] := '';
// Чтобы новый текст ячеек отобразился в GridResults,
// нужно, чтобы было извлечено их очереди и обработано
// сообщение WM_PAINT. Чтобы сделать это немедленно,
// вызываем Application.ProcessMessages.
Application.ProcessMessages;
Random.Start := Random(MaxInt);
Screen.Cursor := crHourGlass;
// Точное измерение времени выполнения кода в Windows
// невозможно, потому что это многозадачная система, и
// часть измеренного времени может быть потрачена на
// выполнение кода других процессов. Чтобы максимально
// уменьшить погрешность измерения, нужно установить
// наивысший приоритет процессу и его главной нити -
// тогда вероятность переключения процессора на
// выполнение другой задачи будет минимальным. Столь