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...
Performance...
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.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?
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.
- 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.
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.
- jens
- Python-Forum Veteran
- Beiträge: 8502
- Registriert: Dienstag 10. August 2004, 09:40
- Wohnort: duisburg
- Kontaktdaten:
Das erklärt die Messwerte... D.h. in Python 3 erbt man i.d.R. noch mehr von 'object' ?EyDu hat geschrieben:Python 3 hat keine old-style-Klassen mehr, die sind alle automatisch new-style
Hab mich bisher wenig mit Python 3 beschäftigt.
- 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.:
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 ?!?
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()
Benchmark:
CPython 2.7: vorher: 895.000 cycles/sec - nachher: 918.000 cycles/sec
Bei PyPy schient es nichts, bzw. etwas bremsend zu wirken ?!?
@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.
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.
- jens
- Python-Forum Veteran
- Beiträge: 8502
- Registriert: Dienstag 10. August 2004, 09:40
- Wohnort: duisburg
- Kontaktdaten:
Ich hab das jetzt an zwei Stellen gemacht: https://github.com/jedie/DragonPy/commi ... a6e2b87952BlackJack 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.
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
- 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
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
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
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
- jens
- Python-Forum Veteran
- Beiträge: 8502
- Registriert: Dienstag 10. August 2004, 09:40
- Wohnort: duisburg
- Kontaktdaten:
Hab nun doch https://github.com/jedie/DragonPy/issues/1 angefangen: https://github.com/jedie/DragonPy/commi ... lit#diff-7jens 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
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?!?
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.