Seite 2 von 3

Verfasst: 30.01.2008 00:19
von NicTheQuick
al90 hat geschrieben:
AND51 hat geschrieben:Müssen zurückgegebene Strings nicht in globalen Variablen gespeichert werden?
AFAIK nicht. Bei mir funzt es 100%ig. Die oben beschriebenen probleme
bezogen sich ja auch nur auf Linux. PureCrunch ist aber PB4.10 Windows lib.

BTW:
Ich denke mal das TailBite die von dir oben beschriebenen Globals
automatisch generiert (?) Sonst dürfte das ganze erst garnit laufen IMHO.
Deine Versions-Procedure gibt nur einen Pointer zu dem in der Procedure
lokal allokierten String zurück, der aber nach dem 'ProcedureReturn'
wieder freigegeben wird.
Es ist klar, dass es funktioniert, weil mal normalerweise den
zurückgegebenen String sofort einer String-Variablen zuweist. Aber
saubere Programmierung ist das nicht. Sonst müsste man ja auch nicht bei
allen Win-API-Befehlen einen Buffer und seine Länge übergeben, der dann
mit dem String gefüllt wird.
Entweder solltest du das auch so machen wie in der Win-API, oder darauf
hoffen, dass es immer funktioniert, oder es wie folgt machen.

Code: Alles auswählen

Procedure.l getVersion()
  Protected a.l = 2 << 16 + 4
  ProcedureReturn a
EndProcedure

Version.l = getVersion()

Debug "High Version:" + Str(Version >> 16)
Debug "Low Version:" + Str(Version & $FFFF)

Verfasst: 30.01.2008 01:12
von edel
Warum so umstaendlich?

Folgender Code reicht doch vollkommen.

Code: Alles auswählen


#version = "0.1"

Procedure.s getVersion()
  ProcedureReturn #version
EndProcedure 


Verfasst: 30.01.2008 01:16
von NicTheQuick
Das ist nichts anderes als al90s Code, weil die Konstante während des
Kompilierens durch den String ersetzt wird.

Mir ist übrigens eben nochmal eingefallen, dass das ganze ja mit Tailbite
kompiliert wird. Da sollte es natürlich nicht zu solchen String-Fehlern
kommen, weil die entstehende Userlib ja weiterhin die PB-internen
Stringfunktionen nutzt. Ohne Gewähr.

Verfasst: 30.01.2008 13:51
von HeX0R
NicTheQuick hat geschrieben:Das ist nichts anderes als al90s Code, weil die Konstante während des
Kompilierens durch den String ersetzt wird.
Aber das in al90s Code ist kein lokal allokierter String, sondern eine in die Exe gemeiselte Zeichenfolge.
Die Adresse dieser Zeichenfolge ist nach dem Verlassen der Prozedur immernoch dieselbe, also würde es ebenso in einer DLL funktionieren.

Verfasst: 30.01.2008 13:56
von edel
Hab ich auch gedacht, aber beide Schnipsel kopieren den String, der in Exe,
in einen neuen String.

Verfasst: 30.01.2008 14:22
von Rings
ne linux lib geht ja nur wenn die unter linux kompiliert ist.
Entweder brauch man dafür den source oder der author machts.
apropo, wie schnell iss den dein algo und wie packt (effizienz) er ?
als vergleich kann man ja die quelloffenen Algos von
Purebasic (JCalG1 oder BriefLZ von PBOSL ) verwenden:

Verfasst: 30.01.2008 21:16
von al90
Rings hat geschrieben:ne linux lib geht ja nur wenn die unter linux kompiliert ist.
Entweder brauch man dafür den source oder der author machts.
Hatte ich mir irgendwie auch schon gedacht. War mir jetzt nur bei Libs nicht so sicher.
Vllt. mache ich das später mal, wenn Linux nochmal auf ne HeftCD oder so ist.
Hab nur ISDN. Bei aller liebe zur Community, aber den Download werde ich mir
bestimmt nicht antun. :shock:
apropo, wie schnell iss den dein algo und wie packt (effizienz) er ?
als vergleich kann man ja die quelloffenen Algos von
Purebasic (JCalG1 oder BriefLZ von PBOSL ) verwenden:
Wie gesagt, es ist in erster linie eine Fast Compression. Der schwerpunkt
liegt also auf speed. Meinen Tests zufolge ist er i.d.r. schneller als Zip.
(Zumindest bei einer grossen masse an Daten. Sollte also schon 100MB+ haben)
Und wenn mal nicht, dann in etwa genauso schnell. Manchmal ist er auch
30%+ schneller. (Abhängig von der masse an Daten und natürlich die Daten selbst)
Das beste speed-ergebniss war mal 50% schneller als Zip.

Was die effizienz angeht, liegt das ergebnis i.d.r. über Zip & JCalG1.
(Brief_LZ konnte ich leider nicht testen, da ich es nicht am laufen bekommen hatte)

Hier mal ein TestPack mit 17 verschiedenen Dateien in allen möglichen grössen und inhalt:

PureCrunch: 15 Sek. - (von 37.2 MB auf 24.6 MB)
PBs_JCalG1: 23 Sek. - (von 37.2 MB auf 17.1 MB)
PureZip: 14 Sek. - (von 37.2 MB auf 14.6 MB)

Zip+PC ist bei diesem test also in etwa gleich. JCalG1 brauchte erwartungsgemäß am längsten.
Wer es gerne mal umfangreicher testen möchte, ohne die lib zu installieren, der kann auch FastBackup benutzen.
Es beinhaltet den selben algo.

BTW:
Das problem mit dem ProcedureReturn frage ich am besten mal direkt bei ABBKlaus nach.
Er wird mir bestimmt sagen können, ob es von Tailbite unterstützt wird oder nicht. :wink:

Verfasst: 31.01.2008 12:28
von Rings
Brieflz liegt doch als fertige Userlib bei PBOSL dabei
(Und im Source).
Kleiner Test ergab (mit ner 8mb bitmap(Einfach nen Screenshot gemacht)):
len of File=7864374
jCalg time for packing 7864374 bytes to 695082 bytes (8.84%) =5672 msec.s
jCalg time for Depacking to 7864374 bytes =15 msec.s
BriefLZ time for packing 7864374 bytes to 903025 bytes (11.48%) =172 msec.s
BriefLZ time for Depacking to 7864374 bytes =63 msec.s
AL90 time for packing 7864374 bytes to 1801506 bytes (22.91%) =1437 msec.s
PureZip time for packing 7864374 bytes to 1255300 bytes (15.96)% =266 msec.s
PureZip time for unpacking 7864374 bytes from 1255300 bytes =15 msec.s
Leider habe ich das mit dem buffer (der nur bis 65000) geht beim entpacken net so hinbekommen bei deiner Lib.
und mit folgendem source wurde getestet:

Code: Alles auswählen

Filename.s="C:\bibeltext.txt" ; a 4,3 mb textfile
Filename.s="C:\test.bmp"; a 2,3mb screenshot
;Filename.s="C:\pbor\Datenbank Ohne Mod.pbor"
Filename2.s="C:\test.pck"
Filename3.s="C:\bibeltext2.txt"



BlockSize=6000 : Level=9

If ReadFile(1,Filename.s)
 l=Lof(1)
 Source=AllocateMemory(l)
 ReadData(1,Source,L)
 CloseFile(1)

 ;L=Blocksize
 ;Debug PeekS(Source,40)
 Debug "len of File="+Str(l)
 DestLen=L+1024
 Dest=AllocateMemory(DestLen) ;genausoviel Destinationram allokieren
 
 t1=GetTickCount_()
 Result=PackMemory(Source,Dest,L,9);@TestMe())
 t2=GetTickCount_()
 Debug "jCalg time for packing "+Str(L) +" bytes to "+Str(result)+" bytes ("+StrF(Result/L*100,2)+"%) =" + Str(t2-t1)+" msec.s"
 t1=GetTickCount_()
 result= UnpackMemory(Dest, Source)
 t2=GetTickCount_()
 Debug "jCalg time for Depacking to "+Str(result)+" bytes =" + Str(t2-t1)+" msec.s"

 
 t1=GetTickCount_()
 Result=BriefLZPack(Source,Dest,L,0);@TestMe())
 t2=GetTickCount_()
 Debug "BriefLZ time for packing "+Str(L) +" bytes to "+Str(result)+" bytes ("+StrF(Result/L*100,2)+"%) =" + Str(t2-t1)+" msec.s"
 t1=GetTickCount_()
 result= BriefLZDePack(Dest, Source,L,0)
 t2=GetTickCount_()
 Debug "BriefLZ time for Depacking to "+Str(result)+" bytes =" + Str(t2-t1)+" msec.s"
 
 ;BlockSize=L
 t1=GetTickCount_()
 Rest=L
 Source2=Source
 bytes2=0
 While Rest>0
  Bytes=PC_CrunchMemory(Source2,Dest,BlockSize,Level)
  Rest=Rest-Blocksize
  Source2=Source2+Blocksize
  bytes2=bytes2+Bytes
 Wend
 t2=GetTickCount_()
 Debug "AL90 time for packing "+Str(L) +" bytes to "+Str(bytes2)+" bytes ("+StrF(bytes2/L*100,2)+"%) =" + Str(t2-t1)+" msec.s"
 
 ;PC_DeCrunchMemory(SourceBuffer.l, DestinationBuffer.l, PackedSize.l) 
 
 
 
 t1=GetTickCount_()
 Result=PureZIP_PackMemory(Source, l, Dest, @DestLen) 
 t2=GetTickCount_()
 Debug "PureZip time for packing "+Str(L) +" bytes to "+Str(DestLen)+" bytes ("+StrF(DestLen/L*100,2)+")% =" + Str(t2-t1)+" msec.s"

 t1=GetTickCount_()
 Result=PureZIP_UnpackMemory(Dest,Destlen,Source, @l) 
 t2=GetTickCount_()
 Debug "PureZip time for unpacking "+Str(L) +" bytes from "+Str(DestLen)+" bytes =" + Str(t2-t1)+" msec.s"



 FreeMemory(Dest)
 FreeMemory(Source)
 
EndIf
Die packgröße kann natürlich variieren je nach ausgangsmaterial.
Allerding kann man sagen das jcalg am besten packt, jedoch auch am längsten braucht.
Zip befindet sich im mittelmaß, ist sehr schnell und packt gut.
BriefLZ packt mittelmässig, das aber sehr schnell. dafür iss es nich so schnell beim entpacken wie JCalg.
Fazit: Man entscheidet im Bedarfsfall was man verwendet, ob speed oder size.
Bau deinen Algo mal um das er ohne diese Buffergeschichte auskommt,
evtl. mit asm bissl speed veibringen.

Verfasst: 31.01.2008 23:52
von al90
Hallo Rings,

Wie ich sehe, hast du den crunch teil in einer (While) schleife gesteckt.
Das kostet aber extra zeit. Um einen fairen test durchzuführen, sollte
der code aber stets gleich bleiben und nur die Syntax der packer
ausgetauscht werden. Dazu habe ich mal ein example gemacht.
Es ist GUI gesteuert und man kann den packer per Combobox
auswählen. Allerdings hatte ich probleme BriefLZ stabil zu bekommen.
Es gab immer ein Invalid Memory Access aus. Dann habe ich
die Memorys +1000 alloziert und dann gings kurrioserweise. Na egal,
so ist der test jetzt für alle packer gleich und fair. Nur auf Zip habe ich
verzichtet, weil es nicht die packsize zurückgibt und somit schwierig ist
mit einzubringen.

Die Ergebnisse waren doch recht überraschend:
testfile = hexen.wad / 20083672 bytes.

PackTest:
JCalG1 = 10688740 bytes in 13875 millisec.
PureCrunch = 14063545 bytes in 6813 millisec.
BriefLZ = 13336249 bytes in 10281 millisec.

UnpackTest:
JCalG1 = 547 millisec.
PureCrunch = 4074 millisec.
BriefLZ = 516 millisec.
Während PureCrunch beim packen noch am schnellsten war, hinkt es
beim entpacken noch hinterher. Auffällig ist auch das die ergebnisse
zwichen BriefLZ + PureCrunch nur sehr gering sind. Geringer als
wenn man bei BriefLZ einen grösseren Buffer benutzt. Während dessen
ist es bei PureCrunch adersherum. (kleinere buffer = effizienter und grosse = schlechter)

Fazit:
Der speed beim packen ist mehr als ok bei PureCrunch. Was ich noch
verbessern müsste, das wäre dann wohl den DeCruncher zu optimieren.
Ausserdem werde ich mal versuchen, (Wie du ja schon selbst vorgeschlagen hattest)
die BufferSize des Crunchers nicht mehr zu beschränken.

Und zum schluss noch der (Benchmark) TestCode. :wink:

Code: Alles auswählen

; PureCrunch, BriefLZ & JCalG1 Benchmark (Beispiel) Code für PureBasic v4.10

; Init variables & Memory

#JCalG1=0
#PureCrunch=1
#BriefLZ=2

BlockSize=6000 : Level=9
Buffer1=AllocateMemory(BlockSize+1000)
Buffer2=AllocateMemory(BlockSize+1000)

; Init GUI

OpenWindow(0, 450, 200, 403, 193, "Packer Benchmark", #PB_Window_SystemMenu|#PB_Window_MinimizeGadget|#PB_Window_TitleBar|#PB_Window_ScreenCentered) And CreateGadgetList(WindowID(0))
StringGadget(0, 113, 24, 244, 20, "")
StringGadget(1, 113, 48, 245, 20, "")
ProgressBarGadget(2, 20, 115, 365, 20, 0, 100, #PB_ProgressBar_Smooth)
TextGadget(3, 20, 90, 365, 20, "De/Compress Process", #PB_Text_Center|#PB_Text_Border)
TextGadget(4, 8, 26, 90, 20, "Source File", #PB_Text_Right)
TextGadget(5, 8, 50, 90, 20, "Destination File", #PB_Text_Right)
ButtonGadget(6, 362, 24, 25, 20, "...")
ButtonGadget(7, 362, 48, 25, 20, "...")
ButtonGadget(8, 228, 153, 79, 25, "Packen")
ButtonGadget(9, 310, 153, 79, 25, "Entpacken")
ComboBoxGadget(10,60,155,120,200)
TextGadget(11,5,158,45,23,"Packer",#PB_Text_Right)
AddGadgetItem(10,-1,"JCalG1")
AddGadgetItem(10,-1,"PureCrunch")
AddGadgetItem(10,-1,"BriefLZ")
SetGadgetState(10,0)

; Wait for Events

Repeat

  Gadget.l=0
  Event=WaitWindowEvent()
  If Event=#PB_Event_Gadget
    Gadget.l=EventGadget()
  EndIf

  ; File(s) selection

  If Gadget=6
    File$=OpenFileRequester("Please choose a file","","",0)
    If File$<>""
      SetGadgetText(0,File$)
    EndIf
  EndIf
  If Gadget=7
    File$=SaveFileRequester("Please choose a file","","",0)
    If File$<>""
      SetGadgetText(1,File$)
    EndIf
  EndIf

  ; Start Crunch

  If Gadget=8
    PackerType = GetGadgetState(10)
    Source$=GetGadgetText(0)
    Dest$=GetGadgetText(1)
    Size.l=FileSize(Source$)
    Blocks.l=Size/BlockSize : Rest.l=Size-(Blocks*BlockSize)
    SetGadgetAttribute(2,#PB_ProgressBar_Maximum,Blocks)
    If ReadFile(0,Source$)
      If CreateFile(1,Dest$)
        WriteLong(1,Blocks)
        WriteLong(1,Rest)
        If Blocks>0
          StartTime=ElapsedMilliseconds()
          For i=1 To Blocks
            SetGadgetState(2,i)
            While WindowEvent():Wend
            ReadData(0,Buffer1,BlockSize)
            If PackerType=#JCalG1
              Bytes=PackMemory(Buffer1,Buffer2,BlockSize,Level)
            ElseIf PackerType=#PureCrunch
              Bytes=PC_CrunchMemory(Buffer1,Buffer2,BlockSize,Level)
            ElseIf PackerType=#BriefLZ
              Bytes=BriefLZPack(Buffer1,Buffer2,BlockSize,0)
            EndIf
            WriteLong(1,Bytes)
            If Bytes>0
              WriteData(1,Buffer2,Bytes)
            Else
              WriteData(1,Buffer1,BlockSize)
            EndIf
          Next
          ElapsedTime=ElapsedMilliseconds()-StartTime
        EndIf
        If Rest>0
          ReadData(0,Buffer1,Rest)
          If PackerType=#JCalG1
            Bytes=PackMemory(Buffer1,Buffer2,Rest,Level)
          ElseIf PackerType=#PureCrunch
            Bytes=PC_CrunchMemory(Buffer1,Buffer2,Rest,Level)
          ElseIf PackerType=#BriefLZ
            Bytes=BriefLZPack(Buffer1,Buffer2,Rest,0)
          EndIf
          WriteLong(1,Bytes)
          If Bytes>0
            WriteData(1,Buffer2,Bytes)
          Else
            WriteData(1,Buffer1,Rest)
          EndIf
        EndIf
        CloseFile(1)
        len=FileSize(Dest$)
        MessageRequester("Info", "Gepackte Grösse = "+Str(len)+" Bytes"+Chr(10)+"Benötigte Zeit = "+Str(ElapsedTime)+" millisec.", #MB_OK|#MB_ICONINFORMATION)
        SetGadgetState(2,0)
      EndIf
      CloseFile(0)
    EndIf
  EndIf

  ; Start DeCrunch

  If Gadget=9
    PackerType = GetGadgetState(10)
    Source$=GetGadgetText(0)
    Dest$=GetGadgetText(1)
    If ReadFile(0,Source$)
      If CreateFile(1,Dest$)
        Blocks=ReadLong(0)
        Rest=ReadLong(0)
        SetGadgetAttribute(2,#PB_ProgressBar_Maximum,Blocks)
        If Blocks>0
          StartTime=ElapsedMilliseconds()
          For i=1 To Blocks
            SetGadgetState(2,i)
            While WindowEvent():Wend
            Bytes=ReadLong(0)
            If Bytes>0
              ReadData(0,Buffer1,Bytes)
              If PackerType=#JCalG1
                UnPackLen.l=UnpackMemory(Buffer1,Buffer2)
              ElseIf PackerType=#PureCrunch
                UnPackLen.l=PC_DeCrunchMemory(Buffer1,Buffer2,Bytes)
              ElseIf PackerType=#BriefLZ
                UnPackLen.l=BriefLZDePack(Buffer1,Buffer2,BlockSize,0)
              EndIf
            Else
              ReadData(0,Buffer2,BlockSize)
              UnPackLen.l=BlockSize
            EndIf
            WriteData(1,Buffer2,UnPackLen)
          Next
          ElapsedTime=ElapsedMilliseconds()-StartTime
        EndIf
        If Rest>0
          Bytes=ReadLong(0)
          If Bytes>0
            ReadData(0,Buffer1,Bytes)
            If PackerType=#JCalG1
              UnPackLen.l=UnpackMemory(Buffer1,Buffer2)
            ElseIf PackerType=#PureCrunch
              UnPackLen.l=PC_DeCrunchMemory(Buffer1,Buffer2,Bytes)
            ElseIf PackerType=#BriefLZ
              UnPackLen.l=BriefLZDePack(Buffer1,Buffer2,Rest,0)
            EndIf
          Else
            ReadData(0,Buffer2,Rest)
            UnPackLen.l=Rest
          EndIf
          WriteData(1,Buffer2,UnPackLen)
        EndIf
        CloseFile(1)
        len=FileSize(Dest$)
        MessageRequester("Info", "Ungepackte Grösse = "+Str(len)+" Bytes"+Chr(10)+"Benötigte Zeit = "+Str(ElapsedTime)+" millisec.", #MB_OK|#MB_ICONINFORMATION)
        SetGadgetState(2,0)
      EndIf
      CloseFile(0)
    EndIf
  EndIf

Until Event=#PB_Event_CloseWindow

FreeMemory(Buffer1)
FreeMemory(Buffer2)
CloseWindow(0)

Verfasst: 01.02.2008 18:52
von Rings
al90 hat geschrieben:Wie ich sehe, hast du den crunch teil in einer (While) schleife gesteckt.
Das kostet aber extra zeit. Um einen fairen test durchzuführen, sollte
der code aber stets gleich bleiben und nur die Syntax der packer
ausgetauscht werden.
Ja klar, mach deinen Buffer Größer, es gibt keinen Sinn (IMHO) nur 6kb pakete zu packen, wenn dann hab ich immer 100kb aufwärts zupacken.
al90 hat geschrieben: Allerdings hatte ich probleme BriefLZ stabil zu bekommen.
Noch nie ein Problem damit. Benutzt du BriefLZ aus der PBOSL ?
evtl. den Callback auf Nullsetzen
al90 hat geschrieben: Nur auf Zip habe ich
verzichtet, weil es nicht die packsize zurückgibt und somit schwierig ist
mit einzubringen.
Gibts im letzen Parameter zurück,siehe mein Beispiel

Wenn du das mit dem Buffer geändert hast werd ich nochmals testen.
Mit dieser Buffer-Beschränkung iss so net so richtig zu gebrauchen
sowie nat. noch net lauffähig unter Linux/mac (Was BriefLZ aber ist)
Ich nutze BriefLZ um Teile von Screenshots zu packen und übers netz zu verschicken, dabei iss er bisher noch unschlagbar was Speed&Size als gemeinsamer Faktor betrifft.
Kommt halt auch immer auf den Einsatz an.
Wenn man Sachen zeitunkritisch packen kann wird jcalg oder
ZIP meist die beste wahl sein.
Ich lass mich nat. gerne eines besseren belehren ;)