Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   brauche kleine Hilfe in ASM, Flaschenhals (https://www.delphipraxis.net/71888-brauche-kleine-hilfe-asm-flaschenhals.html)

stoxx 22. Jun 2006 05:10


brauche kleine Hilfe in ASM, Flaschenhals
 
ich habe hier eine Funktion, die mein programm irgendwie bremst.
Wenn ich sie testweise abschalte, dann bin ich 20-30 prozent schneller, und das in einem komplexen Verarbeiten von noch viel mehr Funktionen und proceduren.

kann man das in ASM vielleicht schneller gestalten oder lässt sich da nicht mehr soviel rausholen ?
Habe leider keine Ahnung von Assembler. Deshalb wollte ich Euch mal um Rat fragen.

Vielen Dank !

Delphi-Quellcode:
function SmallToDouble(CodZahl : Integer): Double;
var Scale : Integer;
begin
  // Entschlüsseln !!
  //    Maske := 3; // 0000 0000 0000 0000 0000 0000 0000 0011

   case ( (CodZahl shr 29) and 3) of
   0 : Scale := 100;
   1 : Scale := 10000;
   2 : Scale := 1000000;
   else
     Scale := 1;
   end;

   // löschen der Bits
   //  MaskePositiv := $9FFFFFFF; // 1001 1111 1111 1111 1111 1111 1111 1111
   //  MaskeNegativ := $60000000; // 0110 0000 0000 0000 0000 0000 0000 0000


   if CodZahl >= 0
     then CodZahl := CodZahl and $9FFFFFFF // Bits müssen Null sein
       else CodZahl := CodZahl or $60000000; // Bits müssen Eins sein
   Result := CodZahl / Scale;
end;

Union 22. Jun 2006 07:42

Re: brauche kleine Hilfe in ASM, Flaschenhals
 
Hi,

Deine Funktion wird schon recht kompakt in Assembler umgesetzt - und zwar automatisch von Delphi. Der aufwändigste Teil ist die Division in der letzten Zeile. Aber auch das lässt sich von Hand wahrscheinlich nicht mehr gut optimieren.

Stellt sich die Frage, ob es nicht einen besseren Algo für die gesamte Umwandlung gibt. Wie hast Du eigentlich den hohen Laufzeit-Anteil ermittelt? Hast Du dafür den Source instrumentiert oder ist das nur eine Schätzung?

Christian Seehase 22. Jun 2006 08:27

Re: brauche kleine Hilfe in ASM, Flaschenhals
 
Moin Stoxx,

mal abgesehen von der Division:
Das SHR im Case kannst Du Dir doch auch einsparen.
Kostet Zeit und ist ja eigentlich reine Bequemlichkeit ;-)

stoxx 22. Jun 2006 13:02

Re: brauche kleine Hilfe in ASM, Flaschenhals
 
Zitat:

Wie hast Du eigentlich den hohen Laufzeit-Anteil ermittelt?
naja .. ich habe die Funktion einfach ausgeschaltet und dem Wert, der mit dieser Funktion was zugewiesen bekommen sollte, einen beliebigen Wert zugewiesen. Mit dieser Funktion liest mein programm große Mengen an Daten von der Festplatte in denen diese 4 Byte "Zahl" enthalten ist. Bisher waren das Double Werte (8 Byte groß)
Die Datenmenge ist nun kleiner, aber müssen nun "encodiert" werden. Und eigentlich dachte ich durch das lesen von Festplatte einen Geschwindigkeitsvorteil zu bekommen. Dem war aber nicht so, leider.
Irgendwann cached Windows die Daten aber sowieso im RAM ( bei 2 GB ) . Erster Test mit einem "kleine" 50 MB File.

Zitat:

Das SHR im Case kannst Du Dir doch auch einsparen.
Kostet Zeit und ist ja eigentlich reine Bequemlichkeit
Wie meinst Du das mit dem einsparen ? Was könnte ich denn an Stelle des SHR sonst tun um die Funktionalität zu bewahren ?

Union 22. Jun 2006 13:07

Re: brauche kleine Hilfe in ASM, Flaschenhals
 
Hi,

was sind denn das für Werte - Meßdaten? Und das Format dieser 32-Bit Werte, hat das einen Namen? Vielleicht gibts da ja eine Library oder einen Algorythmus zur Umwandlung wenn es sich um einen Standard handelt.

Und was machst Du mit den Werten nachdem Du sie eingelesen und umgewandelt hast? Kommen die in eine Datenbank oder berechnest Du daraus einen statistischen Wert?

Das Einlesen in den Speicher ist aufgrund des Delphi Memory Managers nicht immer die performanteste Variante. Liest Du das Ganze in einen MemoryStream ein oder wie hast Du das gelöst?

alzaimar 22. Jun 2006 13:08

Re: brauche kleine Hilfe in ASM, Flaschenhals
 
Anstaat Code um 29 stellen nach rechts zu shiften und die dann untersten 2 bits zu prüfen, prüfe doch einfach die obersten 2 bits....

negaH 22. Jun 2006 13:11

Re: brauche kleine Hilfe in ASM, Flaschenhals
 
Delphi-Quellcode:
function SmallToDouble(CodZahl: Integer): Double;
var
  Scale: Double;
begin
  case CodZahl and (3 shl 29) of
    (0 shl 29) : Scale := 1/100;
    (1 shl 29) : Scale := 1/10000;
    (2 shl 29) : Scale := 1/1000000;
  else
    Scale := 1;
  end;

  if CodZahl >= 0 then CodZahl := CodZahl and $9FFFFFFF // Bits müssen Null sein
    else CodZahl := CodZahl or $60000000; // Bits müssen Eins sein

  Result := CodZahl * Scale;
end;

stoxx 22. Jun 2006 13:16

Re: brauche kleine Hilfe in ASM, Flaschenhals
 
Zitat:

Zitat von alzaimar
Anstaat Code um 29 stellen nach rechts zu shiften und die dann untersten 2 bits zu prüfen, prüfe doch einfach die obersten 2 bits....

ähm, gute Idee .. aber ich wußte nicht, wie das geht ? Wie bekomme ich denn diese 2 Bits aus den 32 Bit heraus ?

Zitat:

was sind denn das für Werte - Meßdaten? Und das Format dieser 32-Bit Werte, hat das einen Namen? Vielleicht gibts da ja eine Library oder einen Algorythmus zur Umwandlung wenn es sich um einen Standard handelt.
Sowas ähnliches. Das sind Tickdaten von Futures (Aktien). Das ist kein Standartformat, sondern meine eigene Erfindung. Ähnlich dem Currency Format, aber mit einer variablen Nachkommestelle. (werden in 2 Bits kodiert). Single war dazu mit 7-8 stelliger Genauigkeit etwas zu klein.

Zitat:

Das Einlesen in den Speicher ist aufgrund des Delphi Memory Managers nicht immer die performanteste Variante
das weiß ich nicht, ich kann es ja nur mit dem Zustand davor (Double Wert) vergleichen.

alzaimar 22. Jun 2006 13:49

Re: brauche kleine Hilfe in ASM, Flaschenhals
 
Na ja, wenn das Deine Erfindung ist, dann weißt Du ja nun auch, wo die 'Schwachstelle' ist. Alternativ hätte man auch einfach unsigned 32-bit fixed point mit festen 4 Decimals nehmen können: Damit hätte man immerhin Kurse bis 429496,7296 Darstellen können. Mit anderen Worten: Der Kurs wird als 10000stel cent als Cardinal dargestellt, da braucht man dann gar keine Umwandlung mehr. Und Rundungsfehler gibt es, zumindest bei der Addition auch nicht mehr. Nur beim Rechnen müsste man auf 64 bit erweitern...

Na egal, hinterher ist man immer schlauer. :zwinker:

stoxx 22. Jun 2006 14:03

Re: brauche kleine Hilfe in ASM, Flaschenhals
 
Zitat:

Alternativ hätte man auch einfach unsigned 32-bit fixed point mit festen 4 Decimals nehmen können: Damit hätte man immerhin Kurse bis 429496,7296 Darstellen können.
ja, das sind so die ersten Gedanken, die man hat, wenn man auf das Problem stößt.
Dummerweise haben einige Futures und Forex Kurse 6 Nachkommastellen.
(z.B. USD/JPY Future hat 6 Nachkommastellen)

Mit 4294,967296 bei einem Festkomma von 6 wird es arg knapp ;-)

ich kann jetzt:

FMinValue2 = -5368709.12;
FMaxValue2 = 5368709.11;

FMinValue4 = -53687.0912;
FMaxValue4 = 53687.0911;

FMinValue6 = -536.870912;
FMaxValue6 = 536.870911;

// FMinValue8 = -5.36870912; //frei
// FMaxValue8 = 5.36870911;


@Hagen .. 3 shl 29 ist eine super Idee ! Das war das, wo ich im Gefühl hatte, man kann noch etwas ändern ;-)
ich glaube ich bin zufrieden, werde es jetzt mal ausgiebig testen.

Vielen Dank !!
Gruß stoxx

Amateurprofi 22. Jun 2006 14:59

Re: brauche kleine Hilfe in ASM, Flaschenhals
 
Und so geht es noch simpler und schneller.

Delphi-Quellcode:
function xSmallToDouble(CodZahl: Integer): Double;
const scale:array[0..7] of double=
     (1/100,1/10000,1/1000000,1.0,1/100,1/10000,1/1000000,1.0);
begin
  if CodZahl>=0 then result:=(CodZahl and $9FFFFFFF)*scale[CodZahl shr 29]
   else result:=(CodZahl or $60000000)*scale[CodZahl shr 29];
end;


Diese Funktion braucht durchschnittlich 53 CPU-Ticks.
Die von negaH schon sehr schön konstruierte Lösung braucht durchschnittlich 88 CPU-Ticks.
Die Resultate sind bei beiden Funktionen identisch (getestet für alle 2^32-1 möglichen Integer-Werte)

Die Ticks wurden so ermittelt.

Delphi-Quellcode:
PROCEDURE TMain.Test;
var v:double; i:integer; q1,q2,qs,qe,tsdelay:int64;
FUNCTION TimeStamp:int64;
asm
   rdtsc
end;
FUNCTION TimeStampDelay:int64;
var i:integer; ts0,ts1:int64;
begin
   result:=maxint;
   for i:=1 to 3 do begin
      ts0:=TimeStamp;
      ts1:=TimeStamp;
      dec(ts1,ts0);
      if ts1<result then result:=ts1;
   end;
end;
begin
   tsdelay:=TimeStampDelay;
    q1:=High(int64);
   for i:=1 to 10 do begin
      qs:=TimeStamp;
      v:=SmallToDouble($FFFFFFFF);
      v:=SmallToDouble($EFFFFFFF);
      v:=SmallToDouble($DFFFFFFF);
      v:=SmallToDouble($CFFFFFFF);
      v:=SmallToDouble($BFFFFFFF);
      v:=SmallToDouble($AFFFFFFF);
      v:=SmallToDouble($9FFFFFFF);
      v:=SmallToDouble($8FFFFFFF);
      v:=SmallToDouble($7FFFFFFF);
      v:=SmallToDouble($6FFFFFFF);
      v:=SmallToDouble($5FFFFFFF);
      v:=SmallToDouble($4FFFFFFF);
      v:=SmallToDouble($3FFFFFFF);
      v:=SmallToDouble($2FFFFFFF);
      v:=SmallToDouble($1FFFFFFF);
      v:=SmallToDouble($0FFFFFFF);
      qe:=TimeStamp;
      dec(qe,qs);
      if qe<q1 then q1:=qe;
   end;
   dec(q1,tsdelay);
   q2:=High(int64);
   for i:=1 to 10 do begin
      qs:=TimeStamp;
      v:=xSmallToDouble($FFFFFFFF);
      v:=xSmallToDouble($EFFFFFFF);
      v:=xSmallToDouble($DFFFFFFF);
      v:=xSmallToDouble($CFFFFFFF);
      v:=xSmallToDouble($BFFFFFFF);
      v:=xSmallToDouble($AFFFFFFF);
      v:=xSmallToDouble($9FFFFFFF);
      v:=xSmallToDouble($8FFFFFFF);
      v:=xSmallToDouble($7FFFFFFF);
      v:=xSmallToDouble($6FFFFFFF);
      v:=xSmallToDouble($5FFFFFFF);
      v:=xSmallToDouble($4FFFFFFF);
      v:=xSmallToDouble($3FFFFFFF);
      v:=xSmallToDouble($2FFFFFFF);
      v:=xSmallToDouble($1FFFFFFF);
      v:=xSmallToDouble($0FFFFFFF);
      qe:=TimeStamp;
      dec(qe,qs);
      if qe<q2 then q2:=qe;
   end;
   dec(q2,tsdelay);
   showmessage(inttostr(q1 div 16)+#13+inttostr(q2 div 16));
end;

stoxx 22. Jun 2006 15:34

Re: brauche kleine Hilfe in ASM, Flaschenhals
 
Zitat:

Zitat von Amateurprofi
Und so geht es noch simpler und schneller.

Delphi-Quellcode:
function xSmallToDouble(CodZahl: Integer): Double;
const scale:array[0..7] of double=
     (1/100,1/10000,1/1000000,1.0,1/100,1/10000,1/1000000,1.0);
begin
  if CodZahl>=0 then result:=(CodZahl and $9FFFFFFF)*scale[CodZahl shr 29]
   else result:=(CodZahl or $60000000)*scale[CodZahl shr 29];
end;


das ist ja cool ! also das ist wirklich praktisch nicht mehr zu unterscheiden, als wenn man die Double Werte einliest.
Auch wenn ich noch nicht wirklich verstehe, was Du da machst und warum das schneller ist !
Bringt ungefähr 10 Prozent beim Einlesen von Daten.

Bei Deiner Messfunktion kommt bei mir 32 zu 20 raus und nicht 88 zu 53 wie bei Dir. Hat das was mit der CPU Geschwindigkeit zu tun ?
Sollte doch eigentlich nicht ? (Prozessor Typ AMD-Intel)
Ist Dein rdtsc gleichbedeutend mit : queryperformancecounter ? Damit messe ich immer.
Vielen Dank !

Amateurprofi 22. Jun 2006 16:25

Re: brauche kleine Hilfe in ASM, Flaschenhals
 
Zitat:

Auch wenn ich noch nicht wirklich verstehe, was Du da machst
Die unterschiedlichen Scales werden durch die Bits 29-30 bestimmt.
Um 29 Bits nach rechts verschoben ergeben sich (wenn Bit 31=0 ist) also 4 mögliche Werte, nämlich 0..3.
Da Bit 31 aber auch 1 sein könnte, ergibt die Verschiebung um 29 Bits 8 mögliche Werte, wobei die Werte 4..7 den Werten 0..3 entsprechen.
Das Array scale[0..7] enthält diese 2*4 möglichen Scales und mit
Delphi-Quellcode:
scale[CodZahl shr 29]
hole ich den passenden Scale aus dem Array.

Zitat:

und warum das schneller ist
Weil der Zugriff auf ein Array, zudem eines, dessen Felder 8 Bytes lang (double=64 Bit) sind, deutlich schneller ist, als den Scale in einer Case-Struktur zu ermitteln.

Zitat:

Bei Deiner Messfunktion kommt bei mir 32 zu 20 raus und nicht 88 zu 53 wie bei Dir
Bei mir werkelt eine Intel P4 CPU.
AMD-CPUs schaffen wohl mehr in einem CPU-Takt, arbeiten aber (glaube ich, weiß ich aber nicht) mit niedrigeren Taktraten, als Intel-CPUs.
Zitat:

Hat das was mit der CPU Geschwindigkeit zu tun
Nein, sondern mit der unterschiedlichen Prozessor-Architektur.
Vorausgesetzt du benutzt gleiche Prozessor-Architekturen, sollten die benötigten CPU-Ticks auch bei unterschiedlichen CPU-Taktfrequenzen übereinstimmen. (meine Meinung....).

Zitat:

Ist Dein rdtsc gleichbedeutend mit : queryperformancecounter ? Damit messe ich immer.
Nein!
QueryPerformanceCounter tickt mit (bei mir) knapp 3.6 MHz.
RDTSC tickt mit dem CPU-Takt (bei mir) knapp 2.7 GHz, also um den Faktor 750 schneller. Bei AMD liegt dieser Faktor vermutlich niedriger.
Um sehr kleine Performance-Unterschiede zu messen, ist (meine Meinung) RDTSC besser geeignet.

stoxx 22. Jun 2006 18:30

Re: brauche kleine Hilfe in ASM, Flaschenhals
 
Hi Amateurprofi !
auf den ersten Blick hatte ich befürchtet, Du würdest das Vorzeichen Bit verwurschteln.
Aber ist ja nicht der Fall !
Ziemlich elegante Lösung, vielen Dank nochmal !!

Zitat:

AMD-CPUs schaffen wohl mehr in einem CPU-Takt, arbeiten aber (glaube ich, weiß ich aber nicht) mit niedrigeren Taktraten, als Intel-CPUs.
ja, ich habe einen AMD, war schon meine Vermutung, interessant !
Die Sache mit dem Array Zugriff werde ich mal als Anlass nehmen, meinen Quelltext mal nach Optimierungen zu durchsuchen !

Um nach einem Hin und Herwandeln wieder wirklich auf (Bit)-Gleichheit prüfen zu können, verwende ich meine xRound Funktion.
Dann ist 0,47 wieder wirklich gleich 0,47. Und man kann sich "abs(a-b) < Toleranz" sparen.

http://www.delphipraxis.net/internal...037&highlight=

Die sieht schon vom Quelltext sehr optimierungsfähig aus. Darf ich Dich da nochmal bemühen ?
Hast Du da auch noch eine wunderschöne Idee ?
Vielen Dank nochmal !!

Amateurprofi 24. Jun 2006 15:03

Re: brauche kleine Hilfe in ASM, Flaschenhals
 
Zitat:

Zitat von stoxx
Um nach einem Hin und Herwandeln wieder wirklich auf (Bit)-Gleichheit prüfen zu können, verwende ich meine xRound Funktion.
Dann ist 0,47 wieder wirklich gleich 0,47. Und man kann sich "abs(a-b) < Toleranz" sparen.
http://www.delphipraxis.net/internal...037&highlight=

Die sieht schon vom Quelltext sehr optimierungsfähig aus. Darf ich Dich da nochmal bemühen ?
Hast Du da auch noch eine wunderschöne Idee ?
Vielen Dank nochmal !!

Hallo Stoxx,
ja, habe ich, gehört aber wohl in den anderen Thread und da stelle ich das rein.


Alle Zeitangaben in WEZ +1. Es ist jetzt 21:32 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz