CroX Уже сделано давно. Mikl__ Хорошая ветка получается, занимательная, плавно перетекла к общей оптимизации. гуд.
Для чистоты эксперимента создал диалог с единственной кнопкой через редактор ресурсов (688 байт), через заполнение структур (816), программное создание кнопки в диалоге и в окне (696 и 696), создание диалога через DialogTemplate (528). О результатах судите сами...
.IF это не условное ассемблирование (не путать с IF) а т.н. "высокоуровневый синтаксис" ассемблера. Да кстати нюанс который нигде не встречал в доках (пришлось у Hutcha выспрашивать): .IF eax < 5 генерирует беззнаковый код: cmp eax, 5 jae ... Поэтому когда eax может быть как положительным так и отрицательным нужно писать .IF sdword ptr eax < 5 компилируемое в: cmp eax, 5 jge ... При любом способе пробегания по списку возможных сообщений рационально сначала проверять часто посылаемые WM_TIMER, WM_MOUSEMOVE, WM_PAINT и т.п. а одноразовые WM_CREATE, WM_DESTROY выкинуть на последнее место. И ещё насколько я понимаю (если что Leo поправит) механизм предсказания переходов один на все задачи, поэтому к приходу очередного сообщения (достаточно редкое событие) другие задачи повытесняют из ВТВ все "предидущие наработки" и оптимизированный вариант типа "дерево" может проигрывать варианту типа "поиск в таблице" за счёт большего количества неверно предсказанных переходов.
asmfan Сижу, пересматриваю Кип Р.Ирвинг "Язык ассемблера для процессоров Intel" стр 295-296 Код (Text): .data val2 SDWORD -1 result SDWORD ? .code mov eax,6 .IF eax>val2 mov result,1 .ENDIF будет сгенерировано mov eax,6 cmp eax,val2 jle @A mov result,1 @A запустил, сгенерировал, действительно так, но если "val2 dd 1" будет jbe
Y_Mur Все что связано с WM_CREATE можно расположить сразу после CreateWindow до цикла обработки сообщений, а вот насчет дерева я не понял
Я вообще-то про то, что ты пишешь про оптимизацию обработчика сообщений, но везде рассматриваешь их в последовательности: WM_DESTROY,WM_CREATE,WM_PAINT,WM_TIMER, т.е. сначала делаешь сравнение с одноразовыми (WM_DESTROY,WM_CREATE), а затем с теми что идут сплошным потоком (WM_PAINT,WM_TIMER), соответственно если сделать наоборот, то количество лишних проверок существенно сократится (конечно визуально по скорости работы программы ты этого не заметишь, но раз уж оптимизировать, то оптимизировать Очень хорошо, что ты приводишь пример организации бинарного дерева: Но в обработчике оконных сообщений имхо этот метод будет постоянно спотыкаться об неверно предсказанные переходы и из-за этого может оказаться менее эффективным чем поиск в таблице сообщений отсортированной по частоте прихода сообщений см. выше
Mikl__ 1) Мелочное замечание об имени класса главного окна: на самом деле можно и Edit-ом обозвать, если приложение не использует настоящие Edit-ы. 2) Наверное, следовало бы порадовать начинающих оптимизаторов благой вестью о L2EXTIA, перегоняющей masm-овские либы в inc-файлы с _imp__. А в аттаче - утилитка by Vortex (http://www.masm32.com/board/index.php?topic=416.0), которая конвертирует не либы, а исходники, причем не только для masm, но и для fasm и др. (Кстати, как насчет конвертера исходников Iszelion-а в исходники Mikl__-а ? )
kero Спасибо огромное. Я примерно это и хотел сказать, но... обзываю AppClass и AppName "BUTTON", случайно "забываю" вызвать RegisterClass и получаю окно в виде одной большой кнопки Я за), что для этого нужно? А давайте сделаем Вижуал Асм
Пусть наше приложение завершается invoke ExitProcess,0. Тогда можно упростить цикл обработки сообщений, без проверки возвращает ли GetMessageA в eax 0 Код (Text): message_loop: push ebx ;цикл обработки сообщений push ebx push ebx push edi call _imp__GetMessageA@16 push edi call _imp__DispatchMessageA@4 ;вернуть управление Windows jmp short message_loop А в обработчик WM_DESTROY вместо PostQuitMessage ставится ExitProcess Код (Text): @@WM_DESTROY: push 0 ;завершение программы call _imp__ExitProcess@4
Оптимизация в ущерб надёжности. Советую всегда проверять возвращаемые значения, а для ф-ии GetMessage проверять не только на ноль, а на -1, т.е. Код (Text): call _imp__GetMessageA@16 test eax,eax jle .fail
Реализуем мультиветвление при помощи косвенного перехода по таблице. Для увеличения скорости просмотра очереди сообщений строим таблицу MsgTable, где номер элемента таблицы соответствует номеру сообщения. Сами табличные элементы представляют собой адреса (процедур), где эти сообщения обрабатываются. Чтобы не перечислять все 400h (1024) сообщений, можно определить номер максимального сообщения Max_Msg и если номер сообщения больше максимального, сразу отправлять на обработку сообщения по умолчанию (метка @@default). Сообщения, не обрабатываемые в процедуре WinProc, также имеют адрес обработки соответствующий адресу метки @@default. При этом время выполнения перехода всегда одинаково для всех вариантов мультиветвления. Код (Text): mov eax,Msg cmp eax,Max_Msg ja @@default;MsgTable - таблица с адресами обработки jmp MsgTable[eax*4];каждый адрес обработки расположен через 4 байта Но у этого способа есть и оборотная сторона. К сожалению, большая скорость обработки сообщений будет компенсирована раздувшейся таблицей MsgTable. Программы с обработкой сообщения WM_NULL =0h мне пока еще не попадались. Обработку сообщения WM_CREATE=1h можно расположить сразу после вызова функции CreateWindow до цикла обработки сообщений. Сообщение WM_DESTROY=2 должно обрабатываться в любой программе. То есть можно сократить нашу таблицу еще на 2 элемента (WM_NULL, WM_CREATE) Код (Text): mov eax,Msg sub eax,Min_Msg cmp eax,Max_Msg-Min_Msg ja @@default jmp MsgTable[eax*4] Наиболее часто используемые сообщения: WM_PAINT=0Fh, WM_CHAR=102h, WM_COMMAND=111h, WM_TIMER=113h, WM_LBUTTONDOWN=201h, WM_RBUTTONDOWN=204h и т.д. Пусть адреса необрабатываемых сообщений в нашей таблице (матрице) равны 0. Мы получили разреженную матрицу, у которой лишь незначительная часть элементов отличны от нуля, причем все ненулевые элементы распределены внутри таблицы произвольным образом. Для того чтобы не расходовать лишнюю память на запись нулей, ненулевые элементы можно занести в хэш-таблицу, причем в этом случае номер сообщения WM_XX, указывающая позицию элемента в матрице, выступает в качестве его «ключевого слова». Хэш-функция F должна возвращать адрес элемента в хэш-таблице т.е. F(WM_COMMAND)=адрес(@@WM_COMMAND) Но это теория, а вот как должна выглядеть эта самая хэш-функция на практике?
Mikl__ Раз таблица разреженная, то зачем её хранить в виде матрицы? Сделать список (массив) из отсортированных элементов (которые ненулевые, естественно), и каждый раз в нём находить нужный элемент бинарным поиском. При данных ограничениях затраты на бин. поиск будут сравнимы с затратами на вычисление хэш-функции.