Autor Beitrag
Flamefire Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1207
Erhaltene Danke: 31

Win 10
Delphi 2009 Pro, C++ (Visual Studio)
BeitragVerfasst: So 12.07.09 12:57 
das mit dem inhaltsverzeichnis wäre noch eine idee
könnte ich machen
aber:
hab grade mal id o.g. idee implementiert:
die funktion, aus der der ausschnitt stammt, soll ein paar voranalysen machen. funktioniert aber genauso
aus zeilen mit:
"x ID1 zz
x ID2 zz
x ID2 zz"
soll jeweils die ID gespeichert werden.
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
function FasterCharPos(c: Char; s: PChar; l:Integer): Integer;
Begin
  for Result := 1 to l do
    if s^ = c then Exit
    else Inc(s);
  Result := -1;
end;

//...
var buffer,buffer2:TDynByteArray;
    p,l,p2,l2,maxID,curID:Integer;
    curPos,curPos2:PChar;
//...
      curPos2:=PChar(@buffer2[0]);
      Inc(curPos2,1);
      l2:=length(buffer2) div 2 -1;
      //get IDs
      while(l2>0) do begin
        p2:=FasterCharPos(#9,curPos2,l2);
        if(p2<=0) then break;
        Inc(curPos2,p2);
        Dec(l2,p2);
        p2:=FasterCharPos(#9,curPos2,l2);
        if(p2<=0) then break;
        curID:=StrToIntDef(Copy(curPos2,1,p2),-1);
        if(curID>=0) then begin
          FIDTable[curID].typ:=typeMob;
          if(curID>maxID) then maxID:=curID;
        end;
        Inc(curPos2,p2+1);
        Dec(l2,p2+1);
        p2:=FasterCharPos(#$A,curPos2,l2);
        if(p2<=0) then break;
        Inc(curPos2,p2);
        Dec(l2,p2);
      end;

Hab Delphi 2009 (-->Pchar=PWideChar) und die datei liegt im unicode format vor
Dummerweise: bei den knapp 10MB Daten (ca 20000 Zeilen) braucht die funktion fast eine MINUTE!
Ich brauch also dringend etwas zum optimieren. Find aber nichts mehr...
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19346
Erhaltene Danke: 1754

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 12.07.09 13:10 
Was mir auffällt:
TDynByteArray und StrToIntDef, beides liest sich komisch in dem Zusammenhang. Ein Speicherbereich, der schnell gefüllt wird, wäre vielleicht besser, und die Umwandlung in eine Zahl ist eben nicht besonders schnell.

Könntest du vielleicht ein kleines Beispielprojekt draus machen, da sollte man im Quelltext und im Profiler schnell sehen was da so lange dauert.
Flamefire Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1207
Erhaltene Danke: 31

Win 10
Delphi 2009 Pro, C++ (Visual Studio)
BeitragVerfasst: So 12.07.09 13:26 
ok habs grad mal mit gettickcount getract...
TDynByteArray ist ein Array of Byte (wie der name schon sagt)
darein wird die datei gelesen. geht auch kaum anders, da die datei komprimiert in einer anderen liegt

die string suchen usw sind alle verdammt schnell...
was so lange dauert ist tatsächlich StrToIntDef

Was meinst du mit "Ein Speicherbereich, der schnell gefüllt wird"

ok also muss das StrToIntDef weg oder optimiert werden.
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
  TIDEntry=record
    typ:Byte;
//kommt vl noch was dazu.
  end;
//...
    FIDTable:Array of TIDEntry;

sinn des ganzen ist folgendes:
ich bekomme wärend des programmes häufiger IDs
die IDs sind im bereich 0-30000 (vermutlich lückenhaft, aber fast vollständig)
diese IDs stehen für verschiedene Bereiche (6 verschiedene). und ich will schnell einer ID einem bereich zuorden
also hab ich gedacht: Array[0..30000] of byte
und Bereich:=FIDTable[ID];

und fertig

Das einzige was mit einfällt ist, jetzt den string der ID zu speichern und dann jeweils nen stringvergleich zu machen.
wird aber dann um einiges langsamer als ein direkter zugriff...
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19346
Erhaltene Danke: 1754

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 12.07.09 13:29 
user profile iconFlamefire hat folgendes geschrieben Zum zitierten Posting springen:
ok habs grad mal mit gettickcount getract...
Damit kannst du ja keine sinnvollen Ergebnisse bekommen was die einzelnen Funktionen angeht, das ist bei einzelnen Funktionen fast reiner Zufall was da raus kommt.
Geeignet sind nur Profiling-Tools oder Messungen mit QueryPerformanceCounter usw.

user profile iconFlamefire hat folgendes geschrieben Zum zitierten Posting springen:
Das einzige was mit einfällt ist, jetzt den string der ID zu speichern und dann jeweils nen stringvergleich zu machen.
wird aber dann um einiges langsamer als ein direkter zugriff...
Kommt auf die Umsetzung an. Wenn man da die Bytes vergleicht, geht das relativ schnell. Je nach Länge der IDs kann man das entsprechend optimieren.
Flamefire Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1207
Erhaltene Danke: 31

Win 10
Delphi 2009 Pro, C++ (Visual Studio)
BeitragVerfasst: So 12.07.09 13:45 
Zitat:
Damit kannst du ja keine sinnvollen Ergebnisse bekommen was die einzelnen Funktionen angeht, das ist bei einzelnen Funktionen fast reiner Zufall was da raus kommt.

nur bedingt richtig:
wenn meine funktion 50000 ticks braucht und ich zwischenmessungen mache von verschiedenen befehlen und herausfinde, dass der strtointdef befehl fast die kompletten 50k ticks braucht, dann ist das schon sehr aussagekräftig, wie ich finde.
brauch einfach nur ne sehr einfach methode, herauszufinden, was relativ am längsten braucht, und da hat es sehr geholfen

ausblenden Delphi-Quelltext
1:
Kommt auf die Umsetzung an. Wenn man da die Bytes vergleicht, geht das relativ schnell. Je nach Länge der IDs kann man das entsprechend optimieren.					

Wie würdest du das machen?
Ich würde ein dynamisches array of record(ID:AnsiString;typ:Byte) machen und in der lesen-methode dann erst die id in nen string umwandeln dann alle einträge durchgehen und mittels comparemem vergleichen

wie kann man das noch optimieren?

Meine Variante:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
function getIDType(ID: Cardinal):Byte;
var i,l:Integer;
    sID:AnsiString;
begin
  if(ID<Cardinal(Length(FIDTable))) then begin
    sID:=AnsiString(IntToStr(ID));
    l:=Length(sID);
    for i := 0 to Length(FIDTable) - 1 do begin
      with FIDTable[i] do begin
        if(Length(ID)<>l) then continue;
        if(CompareMem(@ID[1],@sID[1],l)) then begin
          Result:=typ;
          exit;
        end;
      end;
    end;
  end;
  Result:=typeUK;//Typ unbekannt
end;


EDIT: Hab grade mal weiter getestet, da das mit dem string nicht schneller war
Die langsame methode ist Copy()!!!
Mit
ausblenden Delphi-Quelltext
1:
2:
        SetLength(curID,p2);
        Move(curPos2^,curID[1],p2*sizeOf(curID[1]));

ist das ganze praktisch sofort durchgelaufen.

Woran liegt das denn schon wieder?
ffgorcky
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 573

WIN XP/2000 & 7Prof (Familie:Win95,Win98)

BeitragVerfasst: So 12.07.09 15:19 
user profile iconFlamefire hat folgendes geschrieben Zum zitierten Posting springen:
EDIT: Hab grade mal weiter getestet, da das mit dem string nicht schneller war
Die langsame methode ist Copy()!!!
Mit
ausblenden Delphi-Quelltext
1:
2:
        SetLength(curID,p2);
        Move(curPos2^,curID[1],p2*sizeOf(curID[1]));

ist das ganze praktisch sofort durchgelaufen.

Woran liegt das denn schon wieder?


Das müsste doch eigentlich und für solch einen (lt. der Beitrags-Anzahl) erfahrenen, wie Dich ganz klar sein:
Durch Copy muss doch erst mal wieder neuer Arbeitsspeicher zur Verfügung gestellt werden, wärend durch Move doch nur "der Index" gewechselt wird.

Entschuldigung für diese Antwort - auch ich habe öfter einfach mal "ein Brett vor dem Kopf"...
Flamefire Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1207
Erhaltene Danke: 31

Win 10
Delphi 2009 Pro, C++ (Visual Studio)
BeitragVerfasst: So 12.07.09 15:45 
hmm...bin trotzdem der meinung dass copy() zu meiner lösung äquivalent ist, außer dass es noch die länge prüft und ab einer bestimmten position kopieren kann

ich lege doch auch per SetLength neuen speicher an, und kopiere dann die werte

oder hab ich move falsch verstanden?
ffgorcky
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 573

WIN XP/2000 & 7Prof (Familie:Win95,Win98)

BeitragVerfasst: So 12.07.09 17:32 
Soweit ich denke, ändert Move doch nur den Zeiger auf den Speicherplatz, lässt aber den Speicherplatzinhalt dort, wo er vorher auch war (sprich: er verschiebt nicht so viele Bits) - oder?
Da müsstest Du wahrscheinlich von anderen verlässlichere Antworten bekommen.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19346
Erhaltene Danke: 1754

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 12.07.09 18:17 
user profile iconffgorcky hat folgendes geschrieben Zum zitierten Posting springen:
Soweit ich denke, ändert Move doch nur den Zeiger auf den Speicherplatz, lässt aber den Speicherplatzinhalt dort, wo er vorher auch war (sprich: er verschiebt nicht so viele Bits) - oder?
Nein, Move kopiert ebenso den Inhalt. Allerdings wird dabei keine Bereichsprüfung durchgeführt. Diese Prüfung sollte allerdings eigentlich nicht so lange dauern.

Was bei Copy passiert sind zusätzlich Stringoperationen, evtl. ist es deshalb langsamer, ich selbst arbeite da öfter auch mit SetString + CopyMemory oder so, je nach Anwendungszweck.