Autor Beitrag
Gausi
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 8548
Erhaltene Danke: 477

Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
BeitragVerfasst: Sa 12.04.08 15:23 
Ich habe gerade ein kleines Delphi-Projekt nach Lazarus konvertiert. Die automatische Konvertierung hat nicht so ganz geklappt, daher hat das etwas länger gedauert. Aber jetzt läuft es so halbwegs.

Aber: Es läuft deutlich langsamer. Da steckt ein Faktor zwischen 2 und 3 drin. Hat jemand Erfahrung damit, kann das bestätigen oder weiß, ob man da was drehen kann? Gibt es da Compiler-Optionen, die das verursachen können, oder ist der Freepascal-Compiler einfach nur deutlich schlechter als der von Delphi?

_________________
We are, we were and will not be.
Jakob_Ullmann
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1747
Erhaltene Danke: 15

Win 7, *Ubuntu GNU/Linux*
*Anjuta* (C, C++, Python), Geany (Vala), Lazarus (Pascal), Eclipse (Java)
BeitragVerfasst: Sa 12.04.08 16:20 
1. Warum konvertierst du das Projekt denn nach Lazarus?
2. Ich denke, es wird schon seine Gründe haben, weshalb Delphi einen (hohen) Preis hat und Lazarus / FreePascal kostenlos ist.
Dunkel
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 682

Mac OS X Snow Leopard
Xcode 3.1
BeitragVerfasst: Sa 12.04.08 17:01 
user profile iconJakob_Ullmann hat folgendes geschrieben:
1. Warum konvertierst du das Projekt denn nach Lazarus?

Hast Du schon mal probiert eine Delphi-Echse unter Linux auszuführen? Oder unter Mac OS, oder auf einem PPC, oder, oder oder...

user profile iconJakob_Ullmann hat folgendes geschrieben:

2. Ich denke, es wird schon seine Gründe haben, weshalb Delphi einen (hohen) Preis hat und Lazarus / FreePascal kostenlos ist.

Nicht alles, was Open-Source oder Freeware ist, ist zwangsläufig schlechter als das kommerzielle Pendent. :roll:

BTT:
Keine Ahnung. Ich habe vor Urzeiten auch mal versucht, ein Projekt nach Lazarus/Free Pascal zu portieren. Hat ebenfalls nicht wirklich geklappt. Außerdem hat mir die IDE nicht wirklich gefallen; also habe ich es gelassen. :?

_________________
Ich streite einsam mich mit dieser Oberflächenwelt
Gutes sei ein löblich Brot von dem ich zehre - bis zum Tod [Das Ich - Im Ich]
Allesquarks
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 510

Win XP Prof
Delphi 7 E
BeitragVerfasst: Sa 12.04.08 19:31 
In den Projektoptionen gab es meiner Meinung nach einen Schalter für Optimierungen. Also ich hab auch schon andere Meinungen gehört, dass freepascal wesentlich schneller ist, was ich mir durchaus eher vorstellen kann, da ich jedesmal nen Krampf bekomme, wenn ich das Delphi CPU Window öffne.
Vielleicht liegt das an deren LCL oder wie sie es nennen. Die programmieren ja immer noch die VCL nach. Könnte mir vorstellen, dass das noch nicht so läuft bzw die erstmal Masse statt Klasse schaffen wollen.
Vlt hilft es ja auch Teile davon mit dem gcc zu compilieren. Da soll ja auch ein pascal-part drin sein. Das ist aber nur eine Anregung ich jedenfalls weiß über das speziell gar nichts.
Horst_H
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1654
Erhaltene Danke: 244

WIN10,PuppyLinux
FreePascal,Lazarus
BeitragVerfasst: Sa 12.04.08 20:31 
Hallo,

Eine Konsolenanwendung hat aber kein geändertes Verhalen ( ausser der gigantischen Grösse 1,6 Mb..6,3 Mb (Zeileneinformationen des debuggers an ))
www.delphi-forum.de/viewtopic.php?p=452360

Turbo Delphi 2007
8 bit lookup table (Reference): 1034435
16 bit lookup table: 530772
Horst_H: 541955 <--
Horst_H2: 220742
Reinhard Kern: 1692761

Freepascal 2.2.0
optimiert Register variable Optimierugen O2 und für AMD eingestellt, aller debugger Kram raus.
8 bit lookup table (Reference): 1381376
16 bit lookup table: 653001
Horst_H: 248621 <--
Horst_H2: 235787
Reinhard Kern: 1354820

Lazarus
optimiert für AMD nicht eingestellt
8 bit lookup table (Reference): 1094116
16 bit lookup table: 596681
Horst_H: 399932 <--
Horst_H2: 226541
Reinhard Kern: 1281640

Ohne die Registeroptimierung ist es aber viel langsamer

Gruß Horst
Gausi Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 8548
Erhaltene Danke: 477

Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
BeitragVerfasst: Sa 12.04.08 20:40 
Hm. In der Tat. Jetzt ist es schneller. Aber ich glaube das liegt daran, dass einfach ganze Funktionen wegoptimiert wurden, als ich {$mode delphi} auf {$mode objfpc} gesetzt habe. Also alle Funktionen bis auf die, die ca. 600mal so lange wie unter Delphi braucht. Der Aufbau einer bestimmten Datenstruktur braucht auf einmal ein paar Zehnerpotenzen mehr Zeit. :gruebel:

Ich fürchte, da geht irgendwas komplett daneben. :(

_________________
We are, we were and will not be.
Gausi Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 8548
Erhaltene Danke: 477

Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
BeitragVerfasst: So 13.04.08 13:28 
Ok, das Problem mit dem mode ist geklärt - da wurden Strings als Pascal-Strings und nicht mehr als Ansi-Strings interpretiert.

Trotz aller Optimierungen in den Compiler-Einstellungen des Projekts bleibt das ganze langsamer. Besonders extrem ist das bei dieser Funktion (ist mal egal, was die macht. Die macht halt was ;-))

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:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
  // Datenstruktur
  TDawgRecord = record
      Init: Integer;  // Der Startknoten
      Len: Array of Integer;        // Speichert die "Länge" der Knoten
      Terminal: Array of Boolean;   // ... die Eigenschaft Terminal  der Knoten
      SuffixLink: Array of Integer; // ... die Suffixlinks der Knoten
      Target:  Array of Array[Char] of Integer;  // Kanten, Größe: |Nodes| * 256
  end;   

function BuildDawg(p: AnsiString): TDawgRecord;
var m,i,NodeCount: Integer;
  last, u, v, w, r: Integer;
  c:Char;
  CopyC: Char;
begin
  m := length(p);
  Setlength(result.Len, 2*m+2);
  Setlength(result.Terminal, 2*m+2);
  Setlength(result.SuffixLink, 2*m+2);
  Setlength(result.Target, 2*m+2);
  result.Init := 0;
  result.SuffixLink[0] := -1;
  for c := Low(Char) to High(Char) do result.Target[0,c] := -1;
  NodeCount := 0;
  last := 0;

  for i := 1 to m do
  begin
      u := last;
      inc(NodeCount); // neuen Knoten einfügen
      v := NodeCount;
      result.Len[v] := result.Len[u] + 1;
      // Knoten initialisieren
      result.Terminal[v] := False;
      for c := Low(Char) to High(Char) do result.Target[v,c] := -1;

      While (u > 0and (result.Target[u,p[i]] = -1do
      begin
          // Kante einfügen
          result.Target[u,p[i]] := v;
          u := result.SuffixLink[u];
      end;

      if result.Target[u,p[i]] = -1  then
      begin
          // Wir sind am Startknoten
          result.Target[0,p[i]] := v;
          result.SuffixLink[v] := 0;
      end else
      begin
          // Kante existiert
          w := result.Target[u,p[i]];
          if result.Len[u] + 1 = result.Len[w] then
          begin
              // (u,w) ist feste Kante
              result.SuffixLink[v] := w;
          end else
          begin
              inc(NodeCount);
              r := NodeCount;
              result.Terminal[r] := False;

              //  Knoten w kopieren
              for CopyC := Low(Char) to High(Char) do
                result.Target[r,CopyC] := result.Target[w,CopyC];
              result.SuffixLink[r] := result.SuffixLink[w];

              result.Len[r] := result.Len[u] + 1;
              result.SuffixLink[w] := r;
              result.SuffixLink[v] := r;

              while (u >= 0and (result.Target[u,p[i]] = w) do
              begin
                  result.Target[u,p[i]] := r;
                  u := result.SuffixLink[u];
              end;
          end;
      end// u <> Startknoten, d.h. Kante existiert
      last := v;
  end// for i = 1 to m
  result.Terminal[last] := True;
  while last >= 0 do
  begin
      last := result.SuffixLink[last];
      result.Terminal[last] := True;
  end;
end;


Folgendermaßen messe ich die Zeiten:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
//unter Delphi:
  QueryPerformanceFrequency(freq);
  QueryPerformanceCounter(s);
  BuildDawg('das ist ein test');
  //sleep(1000);
  QueryPerformanceCounter(e);
  Showmessage(Format('%.8f', [(e-s)/freq]));


ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
// unter Lazarus
  EpikTimer1.Clear;
  EpikTimer1.Start;
  s := EpikTimer1.Elapsed;
  BuildDawg('das ist ein test');
  //sleep(1000);
  e := EpikTimer1.Elapsed;
  Showmessage(Format('%.8f', [e-s]));

Zeit unter Delphi: ca. 0.00009 Sekunden. Unter Lazarus: ca. 0.25 Sekunden. Die Einheiten stimmen - wenn das sleep(1000) drin ist, gibts beides mal ca. eine Sekunde mehr. ;-)

Jetzt die Aufgabe an die Optimierungs-Freak: Woran kann das liegen? Ein Faktor 2-3 mag ich ja noch verschmerzen können, aber das hier ist dann doch etwas zu extrem...

_________________
We are, we were and will not be.
Horst_H
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1654
Erhaltene Danke: 244

WIN10,PuppyLinux
FreePascal,Lazarus
BeitragVerfasst: Mo 14.04.08 13:28 
Hallo,


Test mit freepascal
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:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
program testDawG;

uses
  windows,sysutils;
type
  tCharInt = Array[Char] of Integer;
  // Datenstruktur
  TDawgRecord = record
      Init: Integer;  // Der Startknoten
      Len: Array of Integer;        // Speichert die "Länge" der Knoten
      Terminal: Array of Boolean;   // ... die Eigenschaft Terminal  der Knoten
      SuffixLink: Array of Integer; // ... die Suffixlinks der Knoten
      Target:  Array of tCharInt;  // Kanten, Größe: |Nodes| * 256
  end;
var
  e,s,freq: Int64;

function BuildDawg(const p: AnsiString): TDawgRecord;
var
  e,s: Int64;
  m,i,NodeCount: Integer;
  last, u, v, w, r: Integer;
  c:Char;
  CopyC: Char;
  pCharInt : ^tCharInt;
begin
  QueryPerformanceCounter(s);
  m := length(p);
  with result do
    begin
    Setlength(Len, 2*m+2);
    Setlength(Terminal, 2*m+2);
    Setlength(SuffixLink, 2*m+2);
    Setlength(Target, 2*m+2);
    Init := 0;
    SuffixLink[0] := -1;
    end;
with result do // Ob mit oder ohne with, es tut sich nichts..
  begin
//Mit Zeiger brachte auch nichts
  pCharINt := @Target[0];
  for c := Low(Char) to High(Char) do
     pCharInt^[c]:= -1;

  NodeCount := 0;
  last := 0;
  for i := 1 to m do
    begin
      u := last;
      inc(NodeCount); // neuen Knoten einfügen
      v := NodeCount;
      Len[v] := Len[u] + 1;
      // Knoten initialisieren
      Terminal[v] := False;
      for c := Low(Char) to High(Char) do
        Target[v][c] := -1;

      While (u > 0and (Target[u,p[i]] = -1do
        begin
        // Kante einfügen
        Target[u,p[i]] := v;
        u := SuffixLink[u];
        end;


      if Target[u,p[i]] = -1  then
        begin
        // Wir sind am Startknoten
        Target[0,p[i]] := v;
        SuffixLink[v] := 0;
        end
      else
        begin
        // Kante existiert
        w := Target[u,p[i]];
        if Len[u] + 1 = Len[w] then
          begin
          // (u,w) ist feste Kante
          SuffixLink[v] := w;
          end
        else
          begin

          inc(NodeCount);
          r := NodeCount;
          Terminal[r] := False;
          //  Knoten w kopieren
          for CopyC := Low(Char) to High(Char) do
            Target[r,CopyC] := Target[w,CopyC];
          SuffixLink[r] := SuffixLink[w];
          Len[r] := len[u] + 1;
          SuffixLink[w] := r;
          SuffixLink[v] := r;
          while (u >= 0and (Target[u,p[i]] = w) do
            begin
            Target[u,p[i]] := r;
            u := SuffixLink[u];
            end;

          end;
      end// u <> Startknoten, d.h. Kante existiert

      last := v;
  end// for i = 1 to m

  Terminal[last] := True;
  while last >= 0 do
    begin
    last := SuffixLink[last];
    Terminal[last] := True;
    end;
  writeln(nodecount);
  QueryPerformanceCounter(e);
  writeln(Format('Zeit innerhalb Funktion  %.8f', [(e-s)/freq]));
end;

end;

Begin
  QueryPerformanceFrequency(freq);
  QueryPerformanceCounter(s);
  BuildDawg('das ist ein test');
  //sleep(1000);
  QueryPerformanceCounter(e);
  writeln(Format('%.8f', [(e-s)/freq]));
end.


Ergibt
22
Zeit innerhalb Funktion 0,00019109
0,22291409



Na da kann man nur EXTREM staunen...
Da hilft es, wenn man statt function eine procedure mit out Parameter nimmt funktioniert es in 0.0003 Sekunden
ausblenden Delphi-Quelltext
1:
procedure BuildDawg(const p: AnsiString,result:TDawgRecord);//result als Gag damit ich nichts umschreiben muss					


Gruß Horst
Gausi Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 8548
Erhaltene Danke: 477

Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
BeitragVerfasst: Mo 14.04.08 13:52 
Hey, danke! :D

Hab die Funktion grade mal zu einer Prozedur umgebaut - das geht ja wirklich. Komischerweise dauert der Aufbau weiterhin solange, wenn ich die Funktion außerhalb eines Button-Clicks in einer anderen Unit benutze. :gruebel:

Hat jemand ne Idee, warum das als Funktion solange dauert, und als Prozedur mit var/out-Parameter so schnell ist?

_________________
We are, we were and will not be.
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Mi 16.04.08 15:27 
Bei VAR-\OUT-Parametern stellt die Aufrufende Funktion den Ergebnis-Puffer bereit, bei Funktionen wird dieser i.d.R. von der aufgerufenen Funktion alloziiert.

Wo liegt da der Unterschied: Wenn man Rekursive Funktionen hat, wird u.U. der globale Aufruf-Puffer einfach durchgeschleift und es wird nicht jedes Mal eine Kopie angelegt. Das spart Zeit UND der Compiler kann Optimierungen vornehmen, die so tun, als ob das Funktionsergebnis durch Manipulation innerhalb der Routine entstehen; brauch also nicht vorher irgendwas sichern, was er so einfach nur umverteilen kann, weil er weiß, wie die Verarbeitung abläuft ...

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.