Текущий архив: 2004.08.22;
Скачать: CL | DM;
Вниз
Баг в StrScan Найти похожие ветки
← →
VoX (2004-03-12 01:46) [0]С StrScan определенно что-то не так. Писал парсер и удивлялся почему он так медленно работает, хотя везде использую PChar и вообще все должно было работать на ура. Тогда уже стал замерять определенные участки кода вот такими вещами:
Time := GetTickCount;
код
Inc(TimeSum, GetTickCount-Time);
и выяснил что бутылочным горлышком является как раз функция StrScan(). Причем замедление от нее было такое что парсинг с ней выполнялся у меня ~10 секунд, а после замены ее на паскальную версию из SysUtils время выполнения стало исчисляться десятками миллисекунд!
← →
VoX (2004-03-12 03:30) [1]Хм, и еще заметил вещь непонятную.
Есть две процедуры: одна {1} - парсер работает много с PChar и глубокая рекурсия, вторая {2} - работа с MemStream, много записи в поток.
И вот замечена такая вещь: если отключена замена системных dcu, то {1} выполняется ~40мс, а {2} ~11 секунд! Если же включить замену, то {1} выполняется ~200мс, а {2} ~460 миллисекунд!!! Вот я не пойму откуда такая разница?! И ладно бы с заменой было бы медленней, ну там менеджер памяти может другой стоит, дак нет ведь {1} медленней, а {2} намного быстрей! Проект каждый раз я пересобираю (build), проверил уже несколько раз - история повторяется. Из-за чего такое может происходить?! Как такое объяснить?!
P.S. У меня Д7. Кстати, похоже что в замененных модулях для Д7 нету UseDelphiMemoryManager. А какой менеджер там стоит по умолчанию: дельфийский или свой какой-то и как его тогда поменять потому что на UseDelphiMemoryManager компилятор ругается.
← →
VoX (2004-03-12 03:50) [2]Ай, пардон, насчет UseDelphiMemoryManager соврал, есть такой. Попробовал его и результат получился как уже выше описано с отключенными dcu! Как это можно объяснить? Все всегда кричат что наоборот в замененных библиотеках тормозной менеджер памяти, ан нет, получается что не всегда
← →
Владимир Кладов (2004-03-13 10:32) [3]в замененных библиотеках по умолчанию работа начинается с упрощенного менеджера памяти, который весь состоит из 3 строк кода. Ясно, что он будет тормозить, т.к. не содержит никакой оптимизации. Для простых случаев этого достаточно. Вызов UseDelphiMemoryManager устанавливает тот менеджер памяти, который изначально сделан фирмой Borland - Inprise и оптимизирован для многократного выделения и освобождения мелких кусочков памяти, что и происходит при интенсивной работе с AnsiString. Но если НЕ ИСПОЛЬЗОВАТЬ AnsiString и переделать алгоритм так, чтобы работа шла исключительно с PChar, без постоянного выделения и освобождения памяти, то можно получить ускорение по сравнению с прежним алгоритмом в сотни раз, даже если использовался стандартный менеджер памяти.
← →
Владимир Кладов (2004-03-14 13:22) [4]По оптимизации работы с потоками в памяти могу добавить: они тоже вообще не оптимизируются автоматически. Потому что для минимальных целей и так работает. Если надо оптимизировать, это очень просто: заранее укажите требуемый Size для потока. И тогда при записи по одному байту не будет происходить перевыделение памяти для всего потока. Другой вариант: перед записью проверять, что Position+AddedBytes<=Size, если это не так, перевыделить память: Size:=Size+N, где N - достаточно большое (например, 65536). Делается во многих местах и не хочется устраивать у себя такую проверку в каждом месте? Сделайте себе процедуру, и обращайтесь к ней. Например Write2Stream( Stream: PStream; var Buf; Size: Integer );
Вы программисты в общем, чего вас учить.
← →
VoX (2004-03-15 15:56) [5]Ну а что насчет StrScan? Тут вне зависимости от менеджера памяти asm-версия из KOL работает намноого медленней чем pascal версия выдернутая из SysUtils
← →
Владимир Кладов (2004-03-15 18:59) [6]а в исходники заглянуть - лень?
function StrScan(Str: PChar; Chr: Char): PChar; assembler;
asm
{$IFDEF F_P}
MOV EAX, [Str]
MOVZX EDX, [Chr]
{$ENDIF}
PUSH EDI
PUSH EAX
MOV EDI,Str
OR ECX, -1
XOR AL,AL
REPNE SCASB
NOT ECX
POP EDI
XCHG EAX, EDX
REPNE SCASB
XCHG EAX, EDI
POP EDI
JE @@1
XOR EAX, EAX
RET
@@1: DEC EAX
end {$IFDEF F_P} [ "EAX", "EDX", "ECX" ] {$ENDIF};
function StrScan(const Str: PChar; Chr: Char): PChar; assembler;
asm
PUSH EDI
PUSH EAX
MOV EDI,Str
MOV ECX,0FFFFFFFFH
XOR AL,AL
REPNE SCASB
NOT ECX
POP EDI
MOV AL,Chr
REPNE SCASB
MOV EAX,0
JNE @@1
MOV EAX,EDI
DEC EAX
@@1: POP EDI
end;
найдите 10 отличий
← →
VoX (2004-03-16 19:33) [7]А я что не смотрел в исходники? Естественно смотрел. Сейчас попробовал обе эти функции и результат тот же самый. При использовании функций что дали вы, время выполнения ~12-13 секунд вне зависимости от исполльзования замены системных библиотек или нет. При использовании вот такой функции:
function StrScan(const Str: PChar; Chr: Char): PChar;
begin
Result := Str;
while Result^ <> Chr do
begin
if Result^ = #0 then
begin
Result := nil;
Exit;
end;
Inc(Result);
end;
end;
Без замены системных библиотек я получил 20мс!!!
И с заменой 231мс!
Почему получается что асм-версия работает настооолько медленней?
← →
Yury Sidorov (2004-03-17 00:29) [8]Потому, что в ASM функции сначала ищется конец строки, а потом ищется нужный символ. Т. е. сканирование производится дважды, но быстро (REPNE SCASB). На коротких строках это дает выигрыш. У тебя, наверное, строки очень длинные, поэтому предпочтительнее твой вариант. А еще лучше его аналог на асме.
Страницы: 1 вся ветка
Текущий архив: 2004.08.22;
Скачать: CL | DM;
Память: 0.49 MB
Время: 0.036 c