Seite 1 von 6

SetBits / GetBits gut genug?

Verfasst: 25.10.2018 16:55
von Mijikai
Hallo ich verwende nachfolgenden Code um 3 Bits in Folge zu schreiben oder zu lesen.
Es funktioniert aber ich vermute das es schneller geht bzw. bessere Methoden gibt.
Ist mein Code so ok oder geht es besser?

Das ganze soll nämlich bei der Bildbearbeitung eingesetzt werden daher sollte es so flott wie möglich sein :)

Code:

Code: Alles auswählen

;PB v.5.62 x64 (Win 7 / 10)

Procedure.i SetBit(*Target,Bit.i)
  !mov rax,[rsp + 30h]
  !mov rcx,[rsp + 38h]
  !bts [rax],rcx
EndProcedure

Procedure.i GetBit(*Target,Bit.i)
  !xor rax,rax
  !mov rcx,[rsp + 30h]
  !mov rdx,[rsp + 38h]
  !bt [rcx],rdx
  !setc al
  ProcedureReturn
EndProcedure

Procedure.i SetBits(*Target,Offset.i,Value.i)
  Select Value
    Case 1;001
      SetBit(*Target,Offset + 2)
    Case 2;010
      SetBit(*Target,Offset + 1)
    Case 3;011
      SetBit(*Target,Offset + 1)
      SetBit(*Target,Offset + 2)
    Case 4;100
      SetBit(*Target,Offset)
    Case 5;101
      SetBit(*Target,Offset)
      SetBit(*Target,Offset + 2)
    Case 6;110
      SetBit(*Target,Offset)
      SetBit(*Target,Offset + 1)
    Case 7;111
      SetBit(*Target,Offset + 0)
      SetBit(*Target,Offset + 1)
      SetBit(*Target,Offset + 2)
  EndSelect
EndProcedure

Procedure.i GetBits(*Target.Long,Offset.i)
  Protected Dim Bit.a(3)
  Bit(0) = GetBit(*Target,Offset)
  Bit(1) = GetBit(*Target,Offset + 1)
  Bit(2) = GetBit(*Target,Offset + 2)
  *Target = @Bit()
  Select *Target\l
    Case 65536
      ProcedureReturn 1
    Case 256
      ProcedureReturn 2
    Case 65792
      ProcedureReturn 3
    Case 1
      ProcedureReturn 4
    Case 65537
      ProcedureReturn 5
    Case 257
      ProcedureReturn 6
    Case 65793
      ProcedureReturn 7
  EndSelect
EndProcedure

Global Buffer.i

SetBits(@Buffer,0,4);<- setze den Wert 4 (in 3 Bits) an die Position @Buffer + Offset (in Bits)
Debug GetBits(@Buffer,0);<- hier wird der Wert wieder ausgelesen

Re: SetBits / GetBits gut genug?

Verfasst: 25.10.2018 17:42
von ccode_new
Gut genug ?

Da kann ich nicht /möchte ich mich nicht festlegen.

Aber es ist schnell.

Procedure.i SetBit(*Target,Bit.i)
!mov rax,[rsp + 30h]
!mov rcx,[rsp + 38h]
!bts [rax],rcx
EndProcedure

Das ist aber bei mir nicht schneller als:

Procedure SetBit(*T, B.i)
*T + (B >> 3)
PokeB(*T, PeekB(*T) | (1 << (B & 7)))
EndProcedure

Beide Funktionen sind aber eigentlich gleich schnell, oder nur extrem minimal unterschiedlich schnell.
Ich habe nur etwas Komisches festgestellt. Umso kürzer die Variablennamen sind, umso schneller wird der Code.
(Ist aber sehr minimal)

Re: SetBits / GetBits gut genug?

Verfasst: 25.10.2018 17:51
von Sicro
Verwende Macros anstelle der Procedures, um noch ein paar Millisekunden zu sparen.

Re: SetBits / GetBits gut genug?

Verfasst: 25.10.2018 18:30
von NicTheQuick
Genau, wenn es schnell gehen soll, dann verabschiede dich von Procedures. Purebasic erkennt leider nicht von selbst, wann es eine Procedure inline kompilieren kann.
Ansonsten ist dein Select-Case auch sehr kontraproduktiv.

Abgesehen davon bekomme ich einen ungültigen Speicherzugriff beim Starten deines Codes. Das könnte entweder daran liegen, dass Linux hier was anders macht oder dass ich den Purifier immer aktiviert habe.

Ich hätte es wahrscheinlich einfach so gemacht:

Code: Alles auswählen

;PB v.5.62 x64 (Win 7 / 10)

Procedure.i SetBits(*Target.Long, Offset.i, Value.i)
	*Target\l | (Value << Offset)
EndProcedure
EndProcedure

Procedure.i GetBits(*Target.Long, Offset.i)
	ProcedureReturn (*Target\l >> Offset) & %111
EndProcedure

Global Buffer.l

SetBits(@Buffer,0,3);<- setze den Wert 4 (in 3 Bits) an die Position @Buffer + Offset (in Bits)
Debug GetBits(@Buffer,0);<- hier wird der Wert wieder ausgelesen
Die Procedures waren hier aber praktisch, da ich dann besser eine Struktur anhängen konnte, weil ich Peek und Poke nicht so mag. :-D

Übrigens setze ich hier wirklich nur Bits. Vorhandene 1en werden keine 0, wenn man SetBits benutzt. Aber es war auch nicht ersichtlich wie viele Bits bei dir berücksichtigt werden sollten. Mit einer genaueren Spezifikation kann ich dir vielleicht noch besser helfen.

Re: SetBits / GetBits gut genug?

Verfasst: 25.10.2018 18:52
von Mijikai
ccode_new hat geschrieben:...Beide Funktionen sind aber eigentlich gleich schnell, oder nur extrem minimal unterschiedlich schnell.
Ich habe nur etwas Komisches festgestellt. Umso kürzer die Variablennamen sind, umso schneller wird der Code.
(Ist aber sehr minimal)
Danke für den Geschwindigkeitsvergleich mit anderem Code. 8)
Wie ist das mit den Variablennamen zu Verstehen? :|
Sicro hat geschrieben:Verwende Macros anstelle der Procedures, um noch ein paar Millisekunden zu sparen.
Danke, werd ich versuchen Leider hab ich noch nie wirklich mit Macros gearbeitet. :freak:
NicTheQuick hat geschrieben:...
Übrigens setze ich hier wirklich nur Bits. Vorhandene 1en werden keine 0, wenn man SetBits benutzt. Aber es war auch nicht ersichtlich wie viele Bits bei dir berücksichtigt werden sollten. Mit einer genaueren Spezifikation kann ich dir vielleicht noch besser helfen.
Danke für das alternative Codebeispiel.

Es sollen immer 3 Bits kontinuierlich gelesen bzw. geschrieben werden bis das Ende der Datei erreicht ist.
Mit 3 Bits kann ich dann maximal 8 Zustände bzw. Grauwerte abbilden.

Ich hab mal was von Bit-Masken gelesen (es nicht Verstanden) und vermutet, dass es eventuell möglich ist
3 Bits auf einen Schlag zu lesen oder zu schreiben.

Re: SetBits / GetBits gut genug?

Verfasst: 25.10.2018 18:53
von ccode_new
Abgesehen davon bekomme ich einen ungültigen Speicherzugriff beim Starten deines Codes. Das könnte entweder daran liegen, dass Linux hier was anders macht oder dass ich den Purifier immer aktiviert habe.
So ist es auch unter einem anderen Betriebssystem lauffähig. (getestet unter Linux ;) )

Code: Alles auswählen

Procedure.i SetBit(*Target,Bit.i)
  !mov rax,[p.p_Target]
  !mov rcx,[p.v_Bit] 
  !bts [rax],rcx
EndProcedure

Procedure.i GetBit(*Target,Bit.i)
  !xor rax,rax
  !mov rcx,[p.p_Target]
  !mov rdx,[p.v_Bit]
  !bt [rcx],rdx
  !setc al
  ProcedureReturn
EndProcedure

Re: SetBits / GetBits gut genug?

Verfasst: 25.10.2018 18:55
von NicTheQuick
Musst du sequentiell lesen und schreiben oder eher durcheinander? Falls es nur sequentiell laufen soll, dann kann man da viel optimieren. Zum Beispiel 8 mal 3 Bits in einen 3-Byte-Speicherbereich shiften und dann diese 3 Bytes auf einmal schreiben.

Re: SetBits / GetBits gut genug?

Verfasst: 25.10.2018 18:58
von Mijikai
NicTheQuick hat geschrieben:Musst du sequentiell lesen und schreiben oder eher durcheinander? Falls es nur sequentiell laufen soll, dann kann man da viel optimieren. Zum Beispiel 8 mal 3 Bits in einen 3-Byte-Speicherbereich shiften und dann diese 3 Bytes auf einmal schreiben.
Nur sequentiell beim en- und decodiren des Bildes.
Das Problem -> ich muss immer erst einen RGB/A Wert auslesen/einlesen und umwandeln.
Also steppe ich entweder nur 3 oder 4 Bytes durch den Speicher.

Re: SetBits / GetBits gut genug?

Verfasst: 25.10.2018 21:54
von juergenkulow
Hallo Mijikai,

1.DisableDebugger
2.CPU-Takte messen

Code: Alles auswählen

Define T0,T1,T2
EnableASM
RDTSC
mov T0,rax
SetBits(@Buffer,0,4);<- setze den Wert 4 (in 3 Bits) an die Position @Buffer + Offset (in Bits)
RDTSC
mov T1,rax
GetBits(@Buffer,0)  ;<- hier wird der Wert wieder ausgelesen
RDTSC
mov T2,rax
EnableDebugger
Debug T2-T1
Debug T1-T0 
3. Stimmt die Hex/Bit-Matrix:
$10000 --1
$00100 -1-
$00001 1--

4. LODSD, STOSD brauchbar
5. Schleifen und Call möglichst vermeiden.
6. Tabellen nutzen.
7. Aufteilung auf mehrere CPUs(Threads)
8. GPU-Aufgabe?
9. Verwendung von 6 Byte 48 Bit 16x3 Bit (Octel) prüfen

Gruß

Re: SetBits / GetBits gut genug?

Verfasst: 25.10.2018 22:03
von ccode_new
@juergenkulow

:allright:

Für Punkt 7 und 8 hätte ich ja gerne mal Beispiele. :wink: