Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Потрепаться";
Текущий архив: 2004.09.05;
Скачать: [xml.tar.bz2];

Вниз

критика кода DMClient   Найти похожие ветки 

 
nikkie ©   (2004-08-12 11:45) [0]

тема, родившаяся в недрах (со 114-го по 128-й примерно пост)
http://delphimaster.net/view/14-1091941670/

если у кого есть желание выступить с конструктивными предложениями или просто поругать код, милости просим сюда.


 
Sandman25 ©   (2004-08-12 11:48) [1]

AssignFile и Rewrite рулят.
CreateFile может стать deprecated в новых версиях виндоус :)


 
Думкин ©   (2004-08-12 11:49) [2]

Можно чтобы "Написать ответ" было внизу окна всегда или по желанию?
А то иногда прыгать приходится по ветке и набирать корзину для ответа, а потом уже отвечать скопом.
Или никак?


 
nikkie ©   (2004-08-12 11:50) [3]

по поводу AssignFile и т.д. мы вроде разобрались - это личная неприязнь к этим функциям у Fay. теперь хотелось бы разъяснить такой момент.

>Fay
>А вычисление количества строк через ReadLn в цикле - просто шедевр.

какие есть альтернативы?


 
Sandman25 ©   (2004-08-12 11:50) [4]

[2] Думкин ©   (12.08.04 11:49)

Запускай 2 клиента :)


 
Anatoly Podgoretsky ©   (2004-08-12 11:52) [5]

nikkie ©   (12.08.04 11:45)  
Обычно этот процесс называют - порка <наименование>, эта терминология уже прижилась.


 
Danilka ©   (2004-08-12 11:53) [6]

[3] nikkie ©   (12.08.04 11:50)
> какие есть альтернативы?

Например, читать файл посимвольно и подсчитывать #13#10.

[4] Sandman25 ©   (12.08.04 11:50)
Попробуй, не запускается. :))


 
Sandman25 ©   (2004-08-12 11:55) [7]

[6] Danilka ©   (12.08.04 11:53)

Упс. Предыдущая версия запускалась. Зря я экзешник не переименовал при апгрейде, пригодился бы.


 
Anatoly Podgoretsky ©   (2004-08-12 11:59) [8]

nikkie ©   (12.08.04 11:50) [3]
Нет альтернативы

Danilka ©   (12.08.04 11:53) [6]
Работать с текстовыми файлами как с двоичными конечно можно, но не кошерно.


 
nikkie ©   (2004-08-12 12:02) [9]

>Думкин
>Можно чтобы "Написать ответ" было внизу окна всегда или по желанию?
идея понятна, можно подумать на эту тему.

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

о программе
http://schachspieler.narod.ru/dmclient.html
скачать исходники можно здесь:
http://prdownloads.sourceforge.net/dmclient/dmclient_2.1.2_src.zip?download


 
nikkie ©   (2004-08-12 12:07) [10]

>Anatoly Podgoretsky
хорошо, назовем это:
"публичная порка меня родимого"
с хитрым прицелом...

>Sandman25
>Запускай 2 клиента :)
есть проще и удобнее вариант - notepad или какой там твой любимый текстовый редактор в качестве второго окна.


 
Piter ©   (2004-08-12 12:27) [11]

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

P.S. Не забывайте, Nikkie - мастер, хоть и не засвеченный, поэтому туфты в коде не напишет :)


 
Piter ©   (2004-08-12 12:27) [12]

nikkie ©   (12.08.04 12:07) [10]
есть проще и удобнее вариант


а еще проще и удобнее - сделать как я сделал в клиенте


 
Fay ©   (2004-08-12 12:42) [13]

2 nikkie ©   (12.08.04 11:50) [3]


function GetLineCount(const cFileName : string) : Integer;
var
 h, m, sz : DWORD;
 v, p, pe : PChar;
begin
 Result := 0;
 h := CreateFile(PChar(cFileName), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);
 if h = INVALID_HANDLE_VALUE then Exit;
 m := 0;
 v := nil;
 try
   sz := GetFileSize(h, nil);
   if (sz = INVALID_FILE_SIZE) or (sz = 0) then Exit;
   m := CreateFileMapping(h, nil, PAGE_READONLY, 0, 0, nil);
   if m = 0 then Exit;
   v := MapViewOfFile(m, FILE_MAP_READ, 0, 0, 0);
   if v = nil then Exit;
   p := v - 1;
   pe := p + sz;
   if pe^ <> #10 then Result := 1;
   repeat
     Inc(p);
     if p^ = #13 then
       begin
         Inc(Result);
         if p[1] = #10 then Inc(p);
       end;
   until p >= pe;
 finally
   if v <> nil then UnmapViewOfFile(v);
   if m <> 0 then CloseHandle(m);
   CloseHandle(h);
 end;
end;


 
Fay ©   (2004-08-12 12:50) [14]

2 Anatoly Podgoretsky ©   (12.08.04 11:59) [8]
Не кошерно работать с многозадачной, имеющей продвинутую систему прав, ОС так же, как под "ДОСкой". А вещи типа "если файл есть, то открыть, иначе - создать" пишутся одной функцией CreateFile. Но говорить об это не принято. Идиотизм.


 
Fay ©   (2004-08-12 12:59) [15]

2 Piter ©   (12.08.04 12:27) [11]
Глянь на GetLastQuestionTimeStamp.

З.Ы.
В целом - программа ничего. Просто не нравится. Особенно работа с текстом и файлами.


 
Anatoly Podgoretsky ©   (2004-08-12 13:03) [16]

Fay ©   (12.08.04 12:50) [14]
Можно, но придется дублировать работу, которая уже проделана разработчиками Паскаля. Если есть желание то почему бы и нет.


 
nikkie ©   (2004-08-12 13:05) [17]

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

>Идиотизм.
ну зачем так... кому-то может вопрос кросс-платформенности важнее.


 
Fay ©   (2004-08-12 13:08) [18]

2 Anatoly Podgoretsky ©   (12.08.04 13:03) [16]
Это не дублирование. Почти ничего общего. А вот сделать раз в 20 быстрее - почему бы и нет? С тому же, использовать CreateFile под Windows - нормально и правильно.


 
Fay ©   (2004-08-12 13:09) [19]

2 nikkie ©   (12.08.04 13:05) [17]
Не скинешь ссылочку на кроссплатформенный MSHTMP_tbl.pas ? Очень надо 8)


 
Danilka ©   (2004-08-12 13:19) [20]

[18] Fay ©   (12.08.04 13:08)
> А вот сделать раз в 20 быстрее - почему бы и нет?

Чем тестировал? Откуда такие результаты, что через CreateFile в 20 раз быстрее чем через по-обычному, для паскаля, способу?


 
nikkie ©   (2004-08-12 13:24) [21]

>раз в 20 быстрее
ой ли? сейчас будем проверять...

>GetLastQuestionTimeStamp
что там не понравилось?

>Не скинешь ссылочку на кроссплатформенный MSHTMP_tbl.pas ? Очень надо 8)
я иронию уловил... тебя не удивляет, что работа с сервером вынесена DMCServer.pas, работа с файлами собрана в DMCStorageFile.pas, за каким-то лешим еще сделан DMCStorage.pas, а не навалено все в Main.pas? в той ветке мы обсуждаем возможность создания клиента в виде web-сервера или news-gate. ты думаешь, что этот код не мог бы быть повторно использован для такого приложения, будучи откомпилированным FPC или Kylix?

так что MSHTML_TLB.pas не абсолютно необходим... и потом, ты ведь не только меня ругаешь, а всех, использующих AssignFile и co.


 
Fay ©   (2004-08-12 13:26) [22]

2 Danilka ©   (12.08.04 13:19) [20]
Присылай пример. Сравним. А то так можно кому хочешь сказать "У мене типа с пол-метра, не меньше".

2 nikkie ©   (12.08.04 13:05) [17]
MSHTMP_tbl.pas следует читать как MSHTML_tbl.pas


 
Danilka ©   (2004-08-12 13:31) [23]

[22] Fay ©   (12.08.04 13:26)
У меня нет примера. Но видимо у тебя есть, раз ты так смело говоришь, что в 20 раз быстрее. Поэтому я и хотел узнать, откуда ты взял эту цифру, как тестировал.


 
Danilka ©   (2004-08-12 13:32) [24]

[21] nikkie ©   (12.08.04 13:24)
В качестве оффтопика, у тебя под какую версию дельфи клиент писан?


 
Fay ©   (2004-08-12 13:35) [25]

Это цифра из сравнения способов вычисления количества строк в файле. А TDMCStorageFile.GetLastQuestionTimeStamp думаю раз в 100 можно ускорить. Если не больше.


 
Fay ©   (2004-08-12 13:37) [26]

2 Sandman25 ©   (12.08.04 11:48) [1]
Надо иметь неслабое здоровье, чтобы дожить до этого.


 
nikkie ©   (2004-08-12 13:56) [27]

>GetLastQuestionTimeStamp думаю раз в 100 можно ускорить
каким образом? пиши свою версию, сравним.


 
Fay ©   (2004-08-12 13:57) [28]

ОК


 
Sandman25 ©   (2004-08-12 13:58) [29]

[26] Fay ©   (12.08.04 13:37)

Ну, если Вы подрабатываете в MS главным идеологом, спорить не буду :)


 
nikkie ©   (2004-08-12 13:58) [30]

>Danilka
>под какую версию дельфи клиент писан?
исходники компилируются под D5-D7 при условии, что установлены Indy и EmbeddedWB.


 
Anatoly Podgoretsky ©   (2004-08-12 14:07) [31]

Danilka ©   (12.08.04 13:19) [20]
Проверка скорости загрузки списка строк операциями ReadLn и потоковыми, показывала неодназначные результаты, раз на раз не приходился. И никакими 20 разами и близко не пахнет. Красота работы со строками у ReadLn большая, а когда оказывается нужным сделать например такое ReadLn(F, IntVar, FloatVar, BooleanVar, DateVar, SteVar) то особо проявляется, сложность создания такого же но не средствами ReadLn ни как не может окупить даже возможное некоторое замедление.
Ну и самое простое если кому то не нравится поддержка текстовых и типизированых файлов в Паскале, а есть желание разработать свое, то это его право, было бы желание, а запрета нет.


 
cyborg ©   (2004-08-12 14:08) [32]

На Фрипаскале написал:

Program test2;

Uses SysUtils;

function GetCPUTick: int64; assembler;
asm
 db 0fh,31h;
end;

Function GetNumStrings(Var P : Pointer; Size : Longint) : Longint;
Var
 Num : Longint;
 i : Longint;
begin
 Num:=0;

 for i:=0 to Size-1 do
 begin
   if Byte(Pointer( Longint(P)+i )^)=10 then inc(Num);
 end;
 
 GetNumStrings:=Num;
end;

Var
 Time : Int64;
 F : File;
 P : Pointer;
 Size : Longint;
 NumStrings : Longint;
BEGIN
 Time:=0;

 if ParamCount>0 then
 if FileExists(ParamStr(1)) then
 begin
   Time:=GetCPUTick;

   AssignFile(F,ParamStr(1));
   Reset(F,1);
   Size:=FileSize(F);
   GetMem(P,Size);
   
   BlockRead(F,P^,Size);
   NumStrings:=GetNumStrings(P, Size);
   
   FreeMem(P,Size);
   CloseFile(F);
   
   Time:=GetCPUTick-Time;
 end;

 WriteLn("File: ",ParamStr(1));
 WriteLn("Number of strings - ",NumStrings);
 WriteLn("Speed CPU ticks - ",Time);
 WriteLn;
 WriteLn("Press ENTER:");
 ReadLn;
 
END.


Результат по файлу этого же исхождника:


File: test2.pas
Number of strings - 60
Speed CPU ticks - 544590

Press ENTER:


Напиши чтобы в 20 раз быстрее было?


 
Sandman25 ©   (2004-08-12 14:10) [33]

[32] cyborg ©   (12.08.04 14:08)

А если файл имеет размер 10Гб. Так и будем GetMem(FileSize) юзать?


 
Anatoly Podgoretsky ©   (2004-08-12 14:14) [34]

cyborg ©   (12.08.04 14:08) [32]
Писать по требованию надо, что бы в 20 раз медленнее было!!! Такого было утверждение. Где у тебя проверка с ReadLn? Я к тому же не заостряю внимание на том, что код неправильный, разделитель строк не #10, а #13#10.


 
cyborg ©   (2004-08-12 14:16) [35]


> [34] Anatoly Podgoretsky ©   (12.08.04 14:14)

проверка разделителей как раз правильна, это в ДОСе было только #13#10, сейчас достаточно искать только #10, оно и в таком и в таком формате разделителя присутствует.


 
cyborg ©   (2004-08-12 14:19) [36]


> [33] Sandman25 ©   (12.08.04 14:10)

10 гигов не каждая файловая система держит. Я знал, что акой пример приведут, достаточно переделать на чтение по частям, функция таже, только несколько раз вызывать с новыми читаемыми данными и складывая реультат, к примеру по 4 килобайта достаточно для экономии памяти?


 
nikkie ©   (2004-08-12 14:23) [37]

тестовая программа:
program LineCount;

{$APPTYPE CONSOLE}

uses
 SysUtils, Windows;

function GetLineCountStd(const FileName : string) : Integer;
var
 F: TextFile;
 s: String;
begin
 Result := 0;
 if not FileExists(FileName) then begin
   Exit;
 end;

 AssignFile(F, FileName);
 Reset(F);
 try
   while not EOF(F) do begin
     Readln(F, s);
     Inc(Result);
   end;
 finally
   CloseFile(F);
 end;
end;

function GetLineCountFay(const cFileName : string) : Integer;
var
h, m, sz : DWORD;
v, p, pe : PChar;
begin
Result := 0;
h := CreateFile(PChar(cFileName), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);
if h = INVALID_HANDLE_VALUE then Exit;
m := 0;
v := nil;
try
  sz := GetFileSize(h, nil);
  if (sz = INVALID_FILE_SIZE) or (sz = 0) then Exit;
  m := CreateFileMapping(h, nil, PAGE_READONLY, 0, 0, nil);
  if m = 0 then Exit;
  v := MapViewOfFile(m, FILE_MAP_READ, 0, 0, 0);
  if v = nil then Exit;
  p := v - 1;
  pe := p + sz;
  if pe^ <> #10 then Result := 1;
  repeat
    Inc(p);
    if p^ = #13 then
      begin
        Inc(Result);
        if p[1] = #10 then Inc(p);
      end;
  until p >= pe;
finally
  if v <> nil then UnmapViewOfFile(v);
  if m <> 0 then CloseHandle(m);
  CloseHandle(h);
end;
end;

type
 TGetLineCountFunc = function (const cFileName : string) : Integer;
const
 TEST_NUM   = 100;
 TEST_FILE = "C:\temp\list.txt";

procedure Test(f: TGetLineCountFunc; const FileName: string; Desc: string);
var
 dwStart, dwEnd: DWORD;
 i: integer;
begin
 dwStart := GetTickCount;
 for i := 0 to TEST_NUM do begin
   f(FileName);
 end;
 dwEnd := GetTickCount;
 Writeln(Desc, dwEnd - dwStart, " ticks spent");
end;

begin
 Test(GetLineCountStd, TEST_FILE, "Std:");
 Test(GetLineCountFay, TEST_FILE, "Fay:");
end.


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

"Потрепаться" (размер 5181701 байт, 16256 строк).
Std:11687 ticks spent
Fay:1266 ticks spent

"Основная" (размер 6342060 байт, 20328 строк).
Std:14328 ticks spent
Fay:1532 ticks spent

резюме: работает почти в 10 раз быстрее, 0.01 секунды вместо 0.1 секунды.

btw, если в файле последний символ 0x12, в твоей функции все пучком будет?


 
Sandman25 ©   (2004-08-12 14:25) [38]

[36] cyborg ©   (12.08.04 14:19)

Вполне.


 
Anatoly Podgoretsky ©   (2004-08-12 14:26) [39]

nikkie ©   (12.08.04 14:23) [37]
Упрости Readln(F);
и поменяй местами

Test(GetLineCountStd, TEST_FILE, "Std:");
Test(GetLineCountFay, TEST_FILE, "Fay:");


 
nikkie ©   (2004-08-12 14:28) [40]

тьфу, не 0x12, а 0x13, конечно.
по-моему строку
if p[1] = #10 then Inc(p);
выкинуть надо, а 0x13 заменить на 0x10.


 
nikkie ©   (2004-08-12 14:34) [41]

>[39] Anatoly Podgoretsky ©   (12.08.04 14:26)
>Упрости Readln(F);
>и поменяй местами


Fay:1500 ticks spent
Std:13312 ticks spent

пробовал несколько раз, результат воспроизводим.

проверял также на  2х идентичных копиях файла, чтобы исключить вопросы перекоса из-за кеширования. проверял на FAT и NTFS, результат примерно тот же.


 
Anatoly Podgoretsky ©   (2004-08-12 14:39) [42]

Вот теперь после этого можно говорить о некоторой достверности теста, всегда надо учитывать кеширование.


 
Danilka ©   (2004-08-12 14:42) [43]

Хм, у меня такие результаты:
Fay:1734 ticks spent
Std:9016 ticks spent

когда примерно такие:
Fay:9078 ticks spent
Std:1797 ticks spent


 
Danilka ©   (2004-08-12 14:43) [44]

второй вариант, это когда сначала Std, затем Fay


 
nikkie ©   (2004-08-12 14:47) [45]

>Danilka
размер файла какой?


 
Danilka ©   (2004-08-12 14:49) [46]

3633087
:))


 
Anatoly Podgoretsky ©   (2004-08-12 14:50) [47]

Danilka ©   (12.08.04 14:43) [44]
У меня были такие же результаты в более давних испытаниях, вечером дома тест проведу на этих процедурах.

nikkie ©   (12.08.04 14:47) [45]
А вот размер файла ни причем, не надо привязываться к этому, будем лучше говорить о размерах от 0 до 2 гб, так честнее будет.


 
nikkie ©   (2004-08-12 14:52) [48]

3633087
:))

надо же, какой у меня диск тормознутый...


 
Anatoly Podgoretsky ©   (2004-08-12 14:56) [49]

nikkie ©   (12.08.04 14:52) [48]
Вечером возможно вообще будешь плакать :-)


 
cyborg ©   (2004-08-12 14:58) [50]

Вот переписал, получается весьма быстро:

Program test2;

Uses SysUtils,Windows;

function GetCPUTick: int64; assembler;
asm
 db 0fh,31h;
end;

Function GetNumStrings(Const P : Pointer; Size : Longint) : Longint;
Var
 Num : Longint;
 i : Longint;
begin
 Num:=0;

 for i:=0 to Size-1 do
 begin
   if Byte(Pointer( Longint(P)+i )^)=10 then inc(Num);
 end;
 
 GetNumStrings:=Num;
end;

Const
 BlockSize = 4096;
Var
 Time : Int64;
 Time2 : Int64;
 F : File;
 P : Pointer;
 Size : Longint;
 NumStrings : Longint;
 
 iRead : Longint;
 ReadSize : Longint;
BEGIN
 Time:=0;
 NumStrings:=0;

 if ParamCount>0 then
 if FileExists(ParamStr(1)) then
 begin
   Time2:=GetTickCount;
   Time:=GetCPUTick;

   AssignFile(F,ParamStr(1));
   Reset(F,1);
   Size:=FileSize(F);
   GetMem(P,BlockSize);

   for iRead:=0 to (Size div BlockSize) do
   begin

     ReadSize:=Size - (BlockSize*iRead);
     if ReadSize>BlockSize then ReadSize:=BlockSize;
     
     BlockRead(F,P^,ReadSize);
     Inc(NumStrings,GetNumStrings(P, ReadSize));
   end;
   
   FreeMem(P,BlockSize);
   CloseFile(F);
   
   Time:=GetCPUTick-Time;
   Time2:=GetTickCount-Time2;
 end;

 WriteLn("File: ",ParamStr(1));
 WriteLn("FileSize: ",Size);
 WriteLn("Number of strings - ",NumStrings);
 WriteLn("Speed CPU ticks - ",Time);
 WriteLn("Speed time      - ",Time2);
 WriteLn;
 WriteLn("Press ENTER:");
 ReadLn;
 
END.


Вроде не глючит. :)
Константа BlockSize указывает размер блока по сколько байт читать.

Результат такой:

File: G:\DOCUMENTS\DOC\80486.TXT
FileSize: 2076287
Number of strings - 40719
Speed CPU ticks - 40108688
Speed time      - 50

Press ENTER:


nikkie пользуйся моей функцией ;)


 
Anatoly Podgoretsky ©   (2004-08-12 15:01) [51]

Я уже подчеркивал, что такой поиск строк не корректен, надо проверять на #13#10
ReadLn это делает честно.


 
Anatoly Podgoretsky ©   (2004-08-12 15:03) [52]

Да у меня нет тестовой базы, поэтому буду проверять на сгенерированой, со строками размером от 10 до 100 символов, как типичное для текстовых файлов. Размером где ни будь в 4-6 мегабайт.


 
cyborg ©   (2004-08-12 15:05) [53]


> [51] Anatoly Podgoretsky ©   (12.08.04 15:01)

не согласен я :), в юниксовом формате текста переход строки только #10.
Поэтому корректно только его проверять! Попадётся такой текст, у вас покажет что там всего одна строка.


 
Anatoly Podgoretsky ©   (2004-08-12 15:11) [54]

cyborg ©   (12.08.04 15:05) [53]
Про Юникс и Мак давай пока не будем, поскольку речь идет о клиенте под платформу Win32
Нам обязан повтоемый резултат вне зависимости кто писал функцию, можно конечно сделать скидку, мол гарантируем, что исходные данные будут обязательно правильные для нашей функцией, но это не чисто. Это как с обсуждаемыми калькуляторами.


 
Anatoly Podgoretsky ©   (2004-08-12 15:13) [55]

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


 
Vss   (2004-08-12 15:22) [56]

Подскажите начинающему, как ON Line понаблюдать за Вашей  беседой?


 
cyborg ©   (2004-08-12 15:27) [57]

Есть ошибка, исправить надо:

   GetMem(P,BlockSize);

   if Size>0 then NumStrings:=1;
   
   for iRead:=0 to (Size div BlockSize) do


 
cyborg ©   (2004-08-12 15:31) [58]


> [54] Anatoly Podgoretsky ©   (12.08.04 15:11)

Почему же не будем, не обязательно же сидеть под юниксом, чтобы читать текстовые файлы. Я например скачаю у себя с сервера скрипт для правки, он уже с таким переходом строки идёт, и что же, теперь, если я в виндвс, то мне нельзя ничего с ним делать, и я так не играю? Обычными редакторами крайне трудно такие файлы редактировать, так как они (строки) идут в них одной строкой, в TotalCommander-е только нормально могу просмотреть смодержимое такого файла.
Давайте уж лучше будем!


 
KSergey ©   (2004-08-12 15:34) [59]

> [56] Vss   (12.08.04 15:22)

F5


 
Anatoly Podgoretsky ©   (2004-08-12 20:00) [60]

Ну вот проверил все три метода, данные такие
файл размером 5б5 мб, ровно 100000 строк
самопальные утилиты с задачей не справились, насчитали только 99999 строк. Временные результаты, измерение проводилось с помощью системных и процессорных тактов. Каждое измерение проводилось минимум три раза, что бы уменьшить погрешности от кеширования.

ReadLn             387 261 396 тактов,  156 мс
Mapping   (Fay)     33 353 196 тактов,   15 мс
BlockRead (cyborg)  46 791 724 тактов,   32 мс

Измерение в мс естественно не точные, не отражающие сути


 
Anatoly Podgoretsky ©   (2004-08-12 20:06) [61]

Дополнение к третьему измерению, показание в тиках сильно прыгают, но в основном около 32 мс

Расзер файла не 5б5 :-) а 5,5 мб


 
Fay ©   (2004-08-12 20:12) [62]

2 nikkie ©   (12.08.04 13:56) [27]
Только в 2 раза. Больше года так не ошибался - очень подозрительно смотрелся исходный вариант. 8)


 
cyborg ©   (2004-08-12 21:39) [63]

При буффере 4 кило медленно читает :)

Вот размер буффера подбирал:


File: I:\VIDEO\Куда уж хуже.AVI
FileSize: 717850624
Number of strings - 3695343

Buffer=4 kb
Speed CPU ticks - 15760752043
Speed time      - 19128

Buffer=8 kb
Speed CPU ticks - 15541846027
Speed time      - 18867

Buffer=16 kb
Speed CPU ticks - 15537888368
Speed time      - 18857

Buffer=32 kb
Speed CPU ticks - 15542828862
Speed time      - 18867

Buffer=64 kb
Speed CPU ticks - 15569491958
Speed time      - 18897

Buffer=96 kb
Speed CPU ticks - 17620727761
Speed time      - 21391

Buffer=128 kb
Speed CPU ticks - 22125965570
Speed time      - 26858

Buffer=1024 kb
Speed CPU ticks - 34017783595
Speed time      - 41289


Для рассчётов размер буффера поставил 32 кило.

Файл тектсовый ~2 мегабайта скопипастил 20 раз, получилось 41 525 740 байт, сначала (в тестовой программе) прогонял все три теста не учитывая время, затем опять три теста засекая время, результаты такие:


Cbrg - 814381
Number of strings - 814381
Speed CPU ticks - 432005600
Speed time      - 521

Std  - 814381
Number of strings - 814381
Speed CPU ticks - 1141449599
Speed time      - 1382

Fay  - 814381
Number of strings - 814381
Speed CPU ticks - 537899487
Speed time      - 661


Прогнал по тесту лог-файл моего сервера (cyborghome.ru.txt - 1 155 495 байт):


Cbrg - 4142
Number of strings - 4142
Speed CPU ticks - 17302976
Speed time      - 20

Std  - 4141
Number of strings - 4141
Speed CPU ticks - 29207198
Speed time      - 40

Fay  - 0
Number of strings - 0
Speed CPU ticks - 16504663
Speed time      - 20


Переход строки там #10, Тест FAY провалился, ReadLn во Фрипаскале такой переход строки понимает.


 
Fay ©   (2004-08-12 21:43) [64]

2 cyborg ©   (12.08.04 21:39) [63]
Правила на ходу меняем? Очень странно. Можно подумать, что мой пример нельзя доработать. Какая глупость.


 
cyborg ©   (2004-08-12 21:43) [65]

Вот код программы:


Program test2;

Uses SysUtils,Windows;

function GetCPUTick: int64; assembler;
asm
 db 0fh,31h;
end;

//===========================================================================//

function GetLineCountCbrg(const FileName : string) : Integer;
Const
 BlockSize = 1024*32; //размер читаемого блока
Var
 F : File;
 P : Pointer;
 Size : Longint;
 NumStrings : Longint;

 iRead : Longint;
 ReadSize : Longint;
 //+++
 Function GetNumStrings(Const P : Pointer; Size : Longint) : Longint;
 Var
   Num : Longint;
   i : Longint;
 begin
   Num:=0;

   for i:=0 to Size-1 do
   begin
     if Byte(Pointer( Longint(P)+i )^)=10 then inc(Num);
   end;

   GetNumStrings:=Num;
 end;
 //+++
begin
 Result:=0;

 NumStrings:=0;

 if not FileExists(FileName) then Exit;

 AssignFile(F,FileName);
 Reset(F,1);
 Size:=FileSize(F);
 GetMem(P,BlockSize);

 if Size>0 then NumStrings:=1;

 for iRead:=0 to (Size div BlockSize) do
 begin

   ReadSize:=Size - (BlockSize*iRead);
   if ReadSize>BlockSize then ReadSize:=BlockSize;

   BlockRead(F,P^,ReadSize);
   Inc(NumStrings,GetNumStrings(P, ReadSize));
 end;

 FreeMem(P,BlockSize);
 CloseFile(F);
 
 Result:=NumStrings;
end;

//===========================================================================//

function GetLineCountStd(const FileName : string) : Integer;
var
F: TextFile;
s: String;
begin
Result := 0;
if not FileExists(FileName) then begin
  Exit;
end;

AssignFile(F, FileName);
Reset(F);
try
  while not EOF(F) do begin
    Readln(F, s);
    Inc(Result);
  end;
finally
  CloseFile(F);
end;
end;

//===========================================================================//

function GetLineCountFay(const cFileName : string) : Integer;
var
h, m, sz : DWORD;
v, p, pe : PChar;
begin
Result := 0;
h := CreateFile(PChar(cFileName), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);
if h = INVALID_HANDLE_VALUE then Exit;
m := 0;
v := nil;
try
 sz := GetFileSize(h, nil);
//  if (sz = INVALID_FILE_SIZE) or (sz = 0) then Exit;
 m := CreateFileMapping(h, nil, PAGE_READONLY, 0, 0, nil);
 if m = 0 then Exit;
 v := MapViewOfFile(m, FILE_MAP_READ, 0, 0, 0);
 if v = nil then Exit;
 p := v - 1;
 pe := p + sz;
 if pe^ <> #10 then Result := 1;
 repeat
   Inc(p);
   if p^ = #13 then
     begin
       Inc(Result);
       if p[1] = #10 then Inc(p);
     end;
 until p >= pe;
finally
 if v <> nil then UnmapViewOfFile(v);
 if m <> 0 then CloseHandle(m);
 CloseHandle(h);
end;
end;

//===========================================================================//

VAR
 Time : Int64;
 Time2 : Int64;
 StringCount : Longint;

BEGIN
 Time:=0;
 Time2:=0;

 WriteLn("File: ",ParamStr(1));

 if ParamCount>0 then
 if FileExists(ParamStr(1)) then
 begin
   GetLineCountCbrg(ParamStr(1));
   GetLineCountStd(ParamStr(1));
   GetLineCountFay(ParamStr(1));

   Time2:=GetTickCount;
   Time:=GetCPUTick;
   StringCount:=GetLineCountCbrg(ParamStr(1));
   Time:=GetCPUTick-Time;
   Time2:=GetTickCount-Time2;
   WriteLn("Cbrg - ",StringCount);
   WriteLn("Number of strings - ",StringCount);
   WriteLn("Speed CPU ticks - ",Time);
   WriteLn("Speed time      - ",Time2);

   WriteLn;

   Time2:=GetTickCount;
   Time:=GetCPUTick;
   StringCount:=GetLineCountStd(ParamStr(1));
   Time:=GetCPUTick-Time;
   Time2:=GetTickCount-Time2;
   WriteLn("Std  - ",StringCount);
   WriteLn("Number of strings - ",StringCount);
   WriteLn("Speed CPU ticks - ",Time);
   WriteLn("Speed time      - ",Time2);

   WriteLn;

   Time2:=GetTickCount;
   Time:=GetCPUTick;
   StringCount:=GetLineCountFay(ParamStr(1));
   Time:=GetCPUTick-Time;
   Time2:=GetTickCount-Time2;
   WriteLn("Fay  - ",StringCount);
   WriteLn("Number of strings - ",StringCount);
   WriteLn("Speed CPU ticks - ",Time);
   WriteLn("Speed time      - ",Time2);

 end;

 WriteLn;
 WriteLn("Press ENTER:");
 ReadLn;
 
END.


//  if (sz = INVALID_FILE_SIZE) or (sz = 0) then Exit; закомментировал так, как фрипаскаль не знает константы INVALID_FILE_SIZE (или я не нашол модуль требуемый), но этот участок не важен для данного теста.


 
cyborg ©   (2004-08-12 21:46) [66]


> [64] Fay ©   (12.08.04 21:43)

Какие правила я меняю? Про доработку ествественно можно, я сказал провалился не имея ввиду "ха ха ха, ха ха, слабак!", а имея ввиду спор с Анатолием ;).


 
Danilka ©   (2004-08-12 21:50) [67]

Вот, дома померил, 7 измерений, файл 7.6МБ, средние результаты:

Std:14672 ticks spent
Fay:3781 ticks spent

Fay:3890 ticks spent
Std:14906 ticks spent

Странно, почему все-таки так сильно отличаются от: [41] и [61]..

Anatoly Podgoretsky ©, nikkie © а у вас какие операционки? У меня и дома и на работе ВинХР. Просто, не пойму, от чего могут быть расхождения более чем в два раза.


 
Anatoly Podgoretsky ©   (2004-08-12 21:56) [68]

Fay ©   (12.08.04 21:43) [64]
Не стоит обращать на это внимание, мы именно рассматривает платформу Win32 другие платформы не заказывалист. А вот то что количество строк читается не верно это очень плохо. Я не анализировал код для поиска ошибки. В принчипе для примера это не важно, нас интересовала производительность по подсчету количества строк.

cyborg ©   (12.08.04 21:46) [66]
Сообственно я особо и не спорил, тем более что подсчет только малая часть задач и в ней можно достигнуть повышеного быстродействия. Ну в принципе данных тестов нам достаточнои не столько их ха результатов, сколько из за демонстрации трех кардинально различных методов работы.


 
Anatoly Podgoretsky ©   (2004-08-12 22:05) [69]

Danilka ©   (12.08.04 21:50) [67]
открою большой секрет, дело в не в операционках (я проверял на XP PRO, NTFS) а в объеме оперативной памяти, у меня 1,5 гб, даже кинофильмы второй раз считываеются из диского кеша :-)
Плюc PIV 2.4C c гипер тредингом и двухканальной памятью, я паралельно запуска показ их ТИ тюнера, время меняется незначительно.

На 512 мб я наблюдал именно такую картину, смена порядка тестов, показывало разные результаты для них. Для проверки надо делать несколько измерений подряд, например запуска отдельный тест в обработчике отдельной клавиши, для тестов у меня было сделано три кнопки и сразу проводилось три попытки, все три результата выводились в отдельные метки, при желании можно запускать любой тест несколько раз подряд и в любом порядке.

То есть у меня получается чистое измерение без влияния параметров винчестера. Хотел похвалиться скорость винчестера, а из за этого не получилось. :-)


 
Anatoly Podgoretsky ©   (2004-08-12 22:07) [70]

Цикл генерации тестового набора выглядел так
For I := 1 nj 100000 do WriteLn(F, случайная строка от 10 до 100 символов). Очень удобно увидеть ошибки тестов :-)


 
Fay ©   (2004-08-12 22:31) [71]

1) Днём было ~20. Сейчас меньше. Хрень какая-то.
2) Порядок имеет значение.
3) Длина строк имеет значение.

Сейчас (вечером 8)) минимальный выигрыш ~4 раза. Максимальный, действительно 20, но только на строках длины < 10.


 
Danilka ©   (2004-08-13 08:56) [72]

[69] Anatoly Podgoretsky ©   (12.08.04 22:05)
Да я про другое. Про то, что в [41] и [61] разница на глаз в 8-10 раз по-скорости между Fay и Std, а у меня в 4-5 раз.

[71] Fay ©   (12.08.04 22:31)
Порядок имеет значение, но при большом количестве проведенных тестов он влияет уже не так сильно.
На счет длинны строк. В [41] и [43] тестировалось на практически одинаковых файлах, список тем от "Потрепаться", только у nikkie он больше, что вполне естественно, т.к. он своим клиентом раньше меня начал пользоваться, но мое содержимое один в один есть у него + то, что он раньше насобирал.

То-есть, странно то, что на одинаковых файлах одинаковый тест на разных машинах дает отношение скоростей в 2 раза.
Возможно, это тоже, как-то связано с объемом памяти? У меня и дома и на работе 256МБ. У Анатолия 1.5ГБ (блин, я тоже так хочу).


 
Danilka ©   (2004-08-13 09:03) [73]

Или, может скорость памяти влияет? У меня старая и медленная, у Анатолия двухканальная.


 
Anatoly Podgoretsky ©   (2004-08-13 09:28) [74]

Danilka ©   (13.08.04 09:03) [73]
Двухканальная DDR400, FSB 800, поэтому эта скорость обеспечивается и кеш загружается не за два такта а за один, ширина кэша у P4c - 128 бит, ширина памяти 64 бита

Снижение на разных машинах можно объяснить разными процессорами и разным объемом памяти. На P4e например будет другое количество тактов процессора и другое соотношение между тестами.


 
nikkie ©   (2004-08-13 14:18) [75]

>[54] Anatoly Podgoretsky
>Про Юникс и Мак давай пока не будем, поскольку речь идет о клиенте под платформу Win32
cyborg прав - и на Windows могут быть файл с переводом строки 0A вместо 0D 0A. достаточно может оказаться просто файл через ftp пронести. в конце концов мы добиваемся совпадения с тем, как работает Readln - я проверил, он считает оба варианта за перевод строки, 0D за перевод не считается. поэтому для подсчета числа строк достаточно считать количество 0A.


 
nikkie ©   (2004-08-13 14:20) [76]

>[62] Fay
>Только в 2 раза. Больше года так не ошибался - очень подозрительно смотрелся исходный вариант. 8)
ну а у меня 100% попадание :)
[17]
>думаю, что пользователь не заметит разницы.
[37]
>0.01 секунды вместо 0.1 секунды.

за код спасибо, надо только исправить
 p := v - 1;
 pe := p + sz;
 if pe^ <> #10 then Result := 1;
 repeat
   Inc(p);
   if p^ = #13 then
     begin
       Inc(Result);
       if p[1] = #10 then Inc(p);
     end;
 until p >= pe;

на
 p := v;
 pe := p + sz - 1;
 if pe^ <> #10 then Result := 1;
 while p <= pe do begin
   if p^ = #10 then
     Inc(Result);
   Inc(p);
 end;

получается проще и корректнее. а если заменить еще
 if pe^ <> #10 then Result := 1;
на
 Result := 1;
получится еще корректнее, по крайней мере, FAR так считает строки, хоть это и несовпадает с Readln-версией.


 
nikkie ©   (2004-08-13 14:20) [77]

про FileMapping у меня мысль была, не было времени и необходимости ей заниматься. если бы возникли серьезные тормоза, то задумался бы. но скорее стал бы хранить количество строк в первой строке файла или в рядом лежащем.

кстати, по поводу FileMapping. твоя функция заведомо не будет работать на файлах размера 2Gb и немногим меньше (Readln надеюсь будет работать, хотя не проверял...). получается, что CreateFileMapping надо делать по кусочкам, не знаю только какого размера...

а еще озадачивает комментарий
Windows 95: MapViewOfFile may require the swapfile to grow. If the swapfile cannot grow, the function fails.
Windows NT/2000: If the file-mapping object is backed by the paging file (hFile is INVALID_HANDLE_VALUE), the paging file must be large enough to hold the entire mapping. If it is not, MapViewOfFile fails.
Note  To guard against an access violation, use structured exception handling to protect any code that writes to or reads from a memory mapped view. For more information, see Reading and Writing.


а в разделе Reading and Writing:
Note  Reading from or writing to a file view can cause an exception. For example, accessing a mapped file that resides on a remote server can generate an exception if the connection to the server is lost. Exceptions can also occur because of a full disk, because the file is shared and a different process has locked a byte range, or because of an underlying device failure or memory allocation failure. To guard against exceptions due to input and output (I/O) errors, all attempts to access memory mapped files should be wrapped in structured exception handlers.

If you are mapping a compressed or sparse file on an NTFS partition, there is additional potential for an I/O error when paging in a portion of the file. In this case, the address space mapped by MapViewOfFile may not be backed by allocated disk space. This is because a sparse file can have regions of zeroes for which NTFS does not allocate disk space, and a compressed file can take up less disk space than the actual data that it represents. If you read from or write to a portion of a sparse or compressed file that is not backed by disk space, the operating system may try to allocate disk space. If the disk is full, this can result in an exception indicating an I/O error. For more information, see File Compression, Sparse Files, and Structured Exception Handling.


так что думается мне, что BlockRead aka ReadFile надежнее будет.


 
Fay ©   (2004-08-13 22:32) [78]

С большими файлами работать не так приятно, но можно. Коран не запрещает использовать MapViewOfFile/UnmapViewOfFile несколько раз.
Но на таких файлах и разница в скорости будет заметнее.


 
Fay ©   (2004-08-13 22:38) [79]

По поводу "озадачивающих" комментиариев - всё не так ужасно 8)


 
nikkie ©   (2004-08-13 23:04) [80]

>Коран не запрещает использовать MapViewOfFile/UnmapViewOfFile несколько раз.
значит надо использовать... пока что получается, ты привел нерабочий код. так ведь? ну хорошо, работающий, но при некоторых ограничениях... :)

кстати, какими кусками MapView будешь делать? 32K? будет после выигрыш по сравнению с BlockRead?

>По поводу "озадачивающих" комментиариев - всё не так ужасно 8)
честно - я не знаю, в деталях, что такое SEH. означает ли это, что мы рискуем получить AV при работе со сжатым NTFS-томом, файлом на share или любым файлом на Win98?

ты продолжаешь настаивать, что MapViewOfFile - это наиболее правильный способ?

ЗЫ ты, кстати, обещал в 100 раз ускорить GetLastQuestionTimeStamp. опиши хотя бы, что ты собираешь оптимизировать там - работу с файлом или заменить TStringList на парсинг строки? у меня такое ощущение, что первое, и ты просто не заметил, что читается только первая строка...


 
Fay ©   (2004-08-13 23:17) [81]

>> ЗЫ ты, кстати, обещал в 100 раз ускорить GetLastQuestionTimeStamp
Хватит издеваться 8). У меня была библиотека, которую я переписывал. Стало быстрее в ~3 - ~1200 (тысяча двести) раз (в зависимости от  функции). Там был код похожий - вот я и ляпнул. Но в 2 раза - свободно 8).

А про правильные способы - это кто так любит. Я начинаю бороться от ~30% скорости. Юзера живут как раз в рельном режиме времени - это надо уважать.

З.Ы.
Никогда не имел проблем с маппингом. Попробую создать ему невыносимые условия - проверить серьёзность MS-предупреждений.


 
nikkie ©   (2004-08-13 23:21) [82]

>опиши хотя бы, что ты собираешь оптимизировать там
или придется тебе писать код... а ты пока еще подсчет строк в файле не написал...


 
Fay ©   (2004-08-13 23:27) [83]

Где там (оптимизировать)? Я собираюсь идти домой пить перцовку 8)
Дома посмотрю исходники. Будут предложения - напишу



Страницы: 1 2 3 вся ветка

Форум: "Потрепаться";
Текущий архив: 2004.09.05;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.72 MB
Время: 0.048 c
1-1092933826
alexts
2004-08-19 20:43
2004.09.05
Парсинг текстовых файлов


1-1093023657
dracula
2004-08-20 21:40
2004.09.05
Как отделить имя файла?


8-1087466421
ПсихЪ
2004-06-17 14:00
2004.09.05
Wave.pas, Wave.dcu - где взять?


10-1035224514
Прохожий
2002-10-21 22:21
2004.09.05
OMNIORB и C++ Builder


8-1087240660
external
2004-06-14 23:17
2004.09.05
Bicubic resampling, etc...





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский