Performance...

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Bin bei http://lucumr.pocoo.org/2014/8/16/the-p ... ke-to-see/ beim Thema "Slots" darauf gestoßen, das old style classes von der performance schneller sein sollen, als new style classes...

War mir neu. Dachte ich, teste ich mal in DragonPy... Und in der Tat, mit old style classes bin ich so bei ~1.070.000 cycles/sec und bei new style classes bei ~990.000 cycles/sec
Nicht so furchtbar viel, aber da ich bei class quasi nur das (object) löschen mußte und sonst nicht großartig was ändern muß, warum nicht?

Dann hab ich mich mal gefragt, was macht eigentlich CPython 2 vs. 3 so aus. Soll nicht 3 schneller sein?
Bei meinem Test nicht: Py2.7.8: ~1.080.000 cycles/sec und Py3.4.1: ~860.000 cycles/sec
Allerdings schießt da vielleicht Tkinter quer. Denn beim Fenster verschieben, mit Py3 schnellen die Zahlen kurzzeitig hoch, bei Py2 bleibt es relativ Konstanz...

Ich denke ich werde mal ein Benchmark implementieren, der ohne GUI und ohne Threads auskommt... Dann mal sehen...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

jens hat geschrieben:Nicht so furchtbar viel, aber da ich bei class quasi nur das (object) löschen mußte und sonst nicht großartig was ändern muß, warum nicht?
Weil unter anderem Deskriptoren nicht mehr funktionieren, niemand erwartet dass du ernsthaft old-style Klassen nutzt und du dementsprechend einiges an Verwirrung produzieren wirst, möglicherweise auch bei dir selbst. Außerdem ist die Performance nicht so viel höher als dass es sich ernsthaft lohnt. Du cachest ja hoffentlich auch nicht Zugriffe auf Attribute und globale Variablen in lokalen Variablen.

Wenn du willst das DragonPy schnell wird, implementier den Emulator in RPython und lass dir einen JIT und brauchbaren GC generieren. Eine solche Implementation wäre um mehrere Größenordnungen schneller als alles was du in Python implementieren kannst.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Ich hab nun nicht überall auf Old-Style-Klasse gewechselt, sondern nur bei den paar wichtigen: https://github.com/jedie/DragonPy/compa ... yleClasses

Da nutzte ich auch nichts relevantes, somit ist es IMHO egal ob old oder new style...

Habe mit https://github.com/jedie/DragonPy/commi ... 2f6a333905 einen einfachen 6809 CPU benchmark implementiert und mal alle Tests gemacht:

mit new style Klassen:
CPython 2.7.1: ~870.000 CPU cycles/sec
CPython 3.4.1: ~800.000 CPU cycles/sec
PyPy2 v2.3.1: ~8.500.000 CPU cycles/sec
PyPy3 v2.3.1: ~8.380.000 CPU cycles/sec

mit old style Klassen:
CPython 2.7.1: ~1.000.000 CPU cycles/sec
CPython 3.4.1: ~800.000 CPU cycles/sec
PyPy2 v2.3.1: ~10.500.000 CPU cycles/sec
PyPy3 v2.3.1: ~8.700.000 CPU cycles/sec

Auffällig ist allerdings das CPython 3, egal ob old oder new style Klassen, scheint deutlich mehr Schwankt in den Ergebnissen als alle anderen Varianten.

Der Unterschied bei CPython 2 ist doch schon recht viel. Aber natürlich im Vergleich zu PyPy nix.

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Python 3 hat keine old-style-Klassen mehr, die sind alle automatisch new-style ;-)
Das Leben ist wie ein Tennisball.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

EyDu hat geschrieben:Python 3 hat keine old-style-Klassen mehr, die sind alle automatisch new-style ;-)
Das erklärt die Messwerte... D.h. in Python 3 erbt man i.d.R. noch mehr von 'object' ?

Hab mich bisher wenig mit Python 3 beschäftigt.

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Hab nun mal geschaut ob bytearray() statt einer Liste für das in DragonPy Emulierte RAM/ROM besser wäre.

Hab einfach nur die Initialisierung von RAM/ROM durch bytearray ersetzt. Sonst keine Anpassungen.
Jeweils drei Benchmark Durchgänge (mit --loops 10, PyPy mit 100) gemacht und die besten zwei Werte gemittelt.

list:
CPython 2.7: 895.000 cycles/sec
CPython 3.4: 840.000 cycles/sec
PyPy2: 32,8Mio cycles/sec

bytearray:
CPython 2.7: 893.000 cycles/sec
CPython 3.4: 825.000 cycles/sec
PyPy2: 33,8Mio cycles/sec

Hm. PyPy profitiert ein wenig und CPython ist es ein Tick langsamer?!?

Ich lass da mal die Finger davon... ;)



Hab was anderes gemacht, nach: https://wiki.python.org/moin/PythonSpee ... iding_dots...
z.B.:

Code: Alles auswählen

+        get_and_call_next_op = self.cpu.get_and_call_next_op
         for __ in range(burst_count):
-            self.cpu.get_and_call_next_op()
+            get_and_call_next_op()
Das bringt was (CPython): in der GUI: Vorher: ~840.000 Nachher: ~860.000
Benchmark:
CPython 2.7: vorher: 895.000 cycles/sec - nachher: 918.000 cycles/sec
Bei PyPy schient es nichts, bzw. etwas bremsend zu wirken ?!?

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
BlackJack

@jens: Bei einem Bytearray muss bei jedem Zugriff in CPython ein `int`-Objekt in einen Bytewert bzw. umgekehrt gewandelt werden. Bei PyPy ist das dagegen eher ein kleiner Typhinweis für den JIT-Compiler der an der Stelle vorher wahrscheinlich sowieso schon zumindest C-``int``\s verwendet nach dem er herausgefunden hat das in der Liste nur ganze Zahlen gespeichert werden. So würde ich die Ergebnisse jedenfalls erklären ohne konkret geschaut zu haben was passiert.

Mit anderen Worten: Der Typ `bytearray` ist nicht dazu da um Geschwindigkeit zu erzielen, sondern um Speicherplatz zu sparen und weil er die Buffer-API implementiert zum Austausch mit ”externem” Code, also zum Beispiel schreiben in eine Datei oder Datenaustausch von Binärdaten mit C oder anderem ”nativen” Code.

Und jetzt machst Du genau das was DasIch ja schon in seinem letzten Beitrag befürchtet hat — Attributzugriffe mit explizitem Code cachen. Wenn man bei solchen Mikrooptimierungen angekommen ist, die relativ wenig bringen, aber konsequent angewendet nerviger Boilerplate-Code sind, ist die Zeit gekommen das (Teil)Problem in einer anderen Programmiersprache umzusetzen.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

BlackJack hat geschrieben:Und jetzt machst Du genau das was DasIch ja schon in seinem letzten Beitrag befürchtet hat — Attributzugriffe mit explizitem Code cachen. Wenn man bei solchen Mikrooptimierungen angekommen ist, die relativ wenig bringen, aber konsequent angewendet nerviger Boilerplate-Code sind, ist die Zeit gekommen das (Teil)Problem in einer anderen Programmiersprache umzusetzen.
Ich hab das jetzt an zwei Stellen gemacht: https://github.com/jedie/DragonPy/commi ... a6e2b87952
Das finde ich noch ok.

Auf andere Programmiersprachen will ich aber nicht setzten ;)

Zumindest auf meinem Rechner bin ich ja schon bei "Echtzeit" auch mit CPython angekommen. Das reicht mir vollkommen. Zumal man halt dann einfach PyPy nehmen kann, wenn man es schneller will ;)

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Statt bytearray käme noch array.array() in Frage.

Hab mal Tests gemacht:

mit einfacher Liste (Dir bisherige Lösung):
CPython 2.7: 910.000 CPU cycles/sec
CPython 3.4: 843.000 CPU cycles/sec
PyPy2 2.3.1: 31.800.000 CPU cycles/sec

mit array.array("B", ...): # unsigned char
CPython 2.7: 903.000 CPU cycles/sec
CPython 3.4: 851.000 CPU cycles/sec
PyPy2 2.3.1: 32.700.000 CPU cycles/sec

mit array.array("H", ...): # unsigned short
CPython 2.7: 902.000 CPU cycles/sec
CPython 3.4: 838.000 CPU cycles/sec
PyPy2 2.3.1: 32.400.000 CPU cycles/sec

mit array.array("I", ...) # unsigned int
CPython 2.7: 778.000 CPU cycles/sec
CPython 3.4: 839.000 CPU cycles/sec
PyPy2 2.3.1: 9.600.000 CPU cycles/sec


(Jeweils der Best-Wert aus mehreren Durchgängen)

Letztlich bringt array auch nur ein wenig Einsparungen im Speicherverbrauch.


EDIT: Hab nun mal auf array.array umgestellt: https://github.com/jedie/DragonPy/commi ... 48d409c26a :D
Wobei es gibt noch wesentlich mehr Potential als das. Denn ich sollte generell nochmal den RAM/ROM Lösung überarbeiten: https://github.com/jedie/DragonPy/issues/1

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

jens hat geschrieben:mit array.array("B", ...): # unsigned char
CPython 2.7: 903.000 CPU cycles/sec
CPython 3.4: 851.000 CPU cycles/sec
PyPy2 2.3.1: 32.700.000 CPU cycles/sec
Hab nun doch https://github.com/jedie/DragonPy/issues/1 angefangen: https://github.com/jedie/DragonPy/commi ... lit#diff-7

erste Messungen:
CPython 2.7: 962.000 CPU cycles/sec
CPython 3.4: 877.000 CPU cycles/sec
PyPy2 2.3.1: 25.200.000 CPU cycles/sec

Mir ist schleierhaft, warum die PyPy Werte schlechter werden :K Zumal die GUI Werte was anderes sagen... Wer misst misst Mist?!? :twisted:

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Mach einfach mal Bugs in PyPys Bugtracker auf. Möglicherweise hat PyPy einen Bug oder da ist noch Optimierungspotential. Sollte keines davon der Fall sein wirst du dann wahrscheinlich zumindest eine Antwort darauf bekommen, wieso PyPy da langsamer ist.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Wenn, dann sollte ich vorher einen kleinen timeit test basteln. Ansonsten kann es ja an irgendwas liegen...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Antworten