Re: Emulator in Python...
Verfasst: Freitag 8. August 2014, 07:43
Wobei Lifo hab ich nun auch im Einsatz: der CPU status, dabei interessiert ja eigentlich nur der neuste Eintrag... 

Seit 2002 Diskussionen rund um die Programmiersprache Python
https://www.python-forum.de/
Doch dann bremst wieder die Interprocess-Kommunikation aus?!?jens hat geschrieben:[/size]Code: Alles auswählen
Main Thread Sub Thread +------------------+ +---------------------+ | | | | | +-------------+ | CPU cycles/sec queue | | | | <------------------------------------+6809 CPU | | | | | | + ^ | | | GUI | | | | | | | | | | Display RAM write queue | +--v-----+--+ | | | .--------------------------------------------+ Memory | | | | | | | | +--+-----^--+ | | | | | | | | | | | | | | | | +-----v-----+-----+ | | | | | | | | Periphery | | | | | | | Keyboard queue | | MC6883 SAM | | | | | +--------------------------------->MC6821 PIA | | | | | | | | | | | | +--+-----^----+ | | | | | | | | | | +-----------------+ | | | | | | | | +--v-----+----+ | | | | | | | | | | | Display | | | | | | | | | | | +-------------+ | | | +------------------+ +---------------------+
Code: Alles auswählen
Main Process Sub Process
+------------------+ +-------------------+
| | | |
| Queue.Queue <-----> multiprocessing.Queue <-------> Queue.Queue |
| | | |
+------------------+ +-------------------+
Das legt die Vermutung nahe, dass du aus dem Thread auf die GUI zugreifst.jens hat geschrieben:Habe immer wieder einen Crash, ob nun CPython oder PyPy. Das Grundproblem sind wohl threads und TKinter (Wobei das wohl auch mit anderen Toolkits so wäre, vermute ich mal...)
Jein. Wenn die parallelisierten Threads nur Berechnungen durchführen, dann macht dir der GIL einen Strich durch die Rechnung. Threads lohnen sich aber dann, wenn ein Thread Berechnungen durchführt und ein anderer irgendwo IO-Aufgaben durchführt. Daten von der Festplatte lesen, Daten über das Netzwer verschicken, etc. In deinem Fall kommen die letzten Aufgaben wohl eher selten vor. Wenn du allerdings pseude-parallele Berechnungen brauchst, dann wirst du um irgendeinen Threadingmechanismus nicht herumkommen. Egal ob nun Threads, Prozesse oder Pseude-Threads mit Generatoren.jens hat geschrieben:Dann ist generell die Frage, ob Threads überhaupt Sinn machen. Denn durch den Global Interpreter Lock ("GIL") kann ja eh nur wirklich ein Thread laufen.
Nein, das kann nicht passieren. In CPython werden 100 Instruktionen durchgeführt, das ist zumindest der letzte Wert an den ich mich erinnern kann, und dann ein Thread-Wechsel durchgeführt. Blockiert ein Aufruf, eine Queue oder ein Lock, so wird immer gewechselt.jens hat geschrieben:Von daher kann ein Thread dennoch die GUI lähmen...
Das hatte ich in einem der vorherigen Beiträge ja schon geschrieben. Das macht nur Sinn, wenn die Berechnungen auch wirklich parallel sind. Wenn du ständig Synchronisieren musst, dann macht dir der Overhead den ganzen Gewinn kaputt.jens hat geschrieben:Vielleicht macht wegen des GIL multiprocessing doch Sinn?!?
Das ist nach wie vor die Frage.EyDu hat geschrieben:Das hatte ich in einem der vorherigen Beiträge ja schon geschrieben. Das macht nur Sinn, wenn die Berechnungen auch wirklich parallel sind. Wenn du ständig Synchronisieren musst, dann macht dir der Overhead den ganzen Gewinn kaputt.jens hat geschrieben:Vielleicht macht wegen des GIL multiprocessing doch Sinn?!?
Code: Alles auswählen
import sys
if sys.version_info[0] == 2:
# python 2.7
print(type(1)) # <type 'int'>
print(type(int(sys.maxint))) # <type 'int'>
print(type(int(sys.maxint+1))) # <type 'long'>
else:
# Python 3
print(type(1)) # <class 'int'>
print(type(int(sys.maxsize))) # <class 'int'>
print(type(int(sys.maxsize+1))) # <class 'int'>
Ja, ich habe deine Erklärung nicht vergessen. Auf weniger Speichernutztung muß ich IMHO nicht achten. Da ist alles im grünen Bereich...BlackJack hat geschrieben:@jens: Den Unterschied hatte ich doch schon mal erklärt: `bytearray` wird kompakter gespeichert, ist aber geringfügig langsamer (in CPython) weil dort immer der Zwischenschritt interne ”native” Zahl in Python `int` umsetzen, und umgekehrt, bei jedem Indexzugriff besteht. Ob das also das richtige für Deinen Emulator ist, hängt davon ab was Dir wichtiger ist, Speicherplatz oder Geschwindigkeit, beziehungsweise welche Python-Implementierung Du verwendest, weil PyPy bei `bytearray` natürlich mehr ”statische” Typinformationen hat als bei einer Liste in der zwar immer nur ganze Zahlen im Bereich 0 bis 255 gespeichert werden, aber jederzeit auch etwas völlig anderes kommen könnte und PyPy das zur Laufzeit natürlich zusätzlich prüfen muss.
Die Überlegung war, das meine Speicher intern nur ints sind und die schneller sind als long...BlackJack hat geschrieben:Edit: Ich sehe nicht warum Python 3 mit dem Zusammenlegen von `int` und `long` zwingend langsamer sein muss. Grundsätzlich kann man doch intern genau das gleiche machen wie bei Python 2, also zwei Varianten von `int` implementieren beziegungsweise die bereits vorhandenen nutzen, nur diesmal ohne das nach aussen durch den Typ zu zeigen.
-> https://github.com/jedie/DragonPy/#readme# clone the repro:
~$ git clone https://github.com/jedie/DragonPy.git
# Alternative download as .zip: https://github.com/jedie/DragonPy/archive/master.zip
~$ cd DragonPy
# Download all ROM files:
~/DragonPy$ ./download_ROMs.sh
# Start Dragon 32
~/DragonPy$ python2 DragonPy_CLI.py --machine=Dragon32 run
Change Display Queue to a simple Callback
Reimplement Multicomp 6809 and SBC09
Many code refactoring and cleanup
Ja, da hast du sicherlich recht. Es gibt noch einiges an Optimierungspotential.jerch hat geschrieben:@jens:
Alles innerhalb Deiner self.get_and_call_next_op Methode ist "busy loop", d.h. jeder kleine Zusatzaufwand summiert sich auf. Und von da absteigend hast Du immernoch self.-Zugriffe drin, diese sind halt teurer als lokale. Was spricht dagegen, den äusseren Zustand per Parameter an den lokalen Namensraum mitzugeben (siehe memory-Übergabe im Bsp. oben)?
Bei Deiner Registerimplementation nutzt Du u.a. getter und setter-Methoden. Die sind deutlich teurer in CPython als der direkte lesende/schreibende Attributzugriff. Da die Registermanipulation die Hauptarbeit der CPU ist, wirkt sich das massiv aus.
Ich vermute, dass Du mit Umstellung auf lokale Namen und direkten Attributzugriff die Cyclerate der CPython-Version etwa verdoppelt könntest.
Code: Alles auswählen
ncalls tottime percall cumtime percall filename:lineno(function)
12541/11961 0.052 0.000 487.153 0.041 /usr/lib/python3.4/tkinter/__init__.py:1485(__call__)
8240 0.122 0.000 485.559 0.059 /home/jens/DragonPy_env/src/dragonpy/dragonpy/core/gui.py:241(cpu_interval)
8240 0.073 0.000 485.027 0.059 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:404(run)
8240 8.553 0.001 484.876 0.059 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:333(burst_run)
12512 0.063 0.000 483.947 0.039 /usr/lib/python3.4/tkinter/__init__.py:533(callit)
8255100 25.451 0.000 476.791 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:272(get_and_call_next_op)
8403598/8255100 20.331 0.000 371.806 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:288(call_instruction_func)
15549487 66.446 0.000 149.411 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:535(read_pc_byte)
2254891 7.468 0.000 54.801 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/instruction_call.py:537(relative_ea)
16584767 33.130 0.000 50.417 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:37(increment)
646331 2.206 0.000 42.781 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/instruction_call.py:136(direct_word_X_read16)
668298 2.237 0.000 38.780 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/instruction_call.py:365(indexed_A_read8)
1792270 11.384 0.000 36.726 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:592(get_ea_indexed)
2254891 9.770 0.000 35.719 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:756(get_ea_relative)
709969 3.198 0.000 29.866 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:1709(instruction_CMP16)
20645223/20638957 27.729 0.000 28.087 0.000 /home/jens/DragonPy_env/src/dragonpy/dragonpy/components/memory.py:191(read_byte)
27069837 27.168 0.000 27.168 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:98(set_flag)
1931097 6.406 0.000 26.688 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:561(get_ea_direct)
1010482 4.428 0.000 26.634 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:1517(instruction_LD8)
1897318 5.883 0.000 25.682 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:293(update_NZ_8)
26651989 25.038 0.000 25.038 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:31(get)
355525 1.643 0.000 22.798 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/instruction_call.py:50(direct_ea_read8_write8)
843845 4.508 0.000 22.251 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:329(update_NZVC_8)
21038722 22.019 0.000 22.019 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:81(set)
614495 2.060 0.000 20.639 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/instruction_call.py:455(indexed_ea_X)
357440 1.230 0.000 20.088 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/instruction_call.py:289(immediate_A_read8)
41281/40419 1.656 0.000 19.682 0.000 {method 'call' of 'tkapp' objects}
734403 4.039 0.000 19.604 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:335(update_NZVC_16)
1 0.000 0.000 19.125 19.125 /home/jens/DragonPy_env/src/dragonpy/basic_editor/editor.py:189(command_load_file)
698567 2.273 0.000 19.040 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:712(get_m_indexed)
...
Code: Alles auswählen
ncalls tottime percall cumtime percall filename:lineno(function)
15549487 66.446 0.000 149.411 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:535(read_pc_byte)
16584767 33.130 0.000 50.417 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:37(increment)
20645223/20638957 27.729 0.000 28.087 0.000 /home/jens/DragonPy_env/src/dragonpy/dragonpy/components/memory.py:191(read_byte)
27069837 27.168 0.000 27.168 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:98(set_flag)
8255100 25.451 0.000 476.791 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:272(get_and_call_next_op)
26651989 25.038 0.000 25.038 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:31(get)
21038722 22.019 0.000 22.019 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:81(set)
8403598/8255100 20.331 0.000 371.806 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:288(call_instruction_func)
14943248 14.632 0.000 14.632 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:101(get_flag)
1792270 11.384 0.000 36.726 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:592(get_ea_indexed)
2254891 9.770 0.000 35.719 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:756(get_ea_relative)
2885523 9.441 0.000 15.200 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:197(set_N8)
2893451 9.213 0.000 14.940 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:177(set_Z8)
2068990 8.881 0.000 15.147 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:270(clear_NZV)
8240 8.553 0.001 484.876 0.059 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:333(burst_run)
1578248 8.419 0.000 14.731 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:276(clear_NZVC)
2254891 7.468 0.000 54.801 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/instruction_call.py:537(relative_ea)
1931097 6.406 0.000 26.688 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:561(get_ea_direct)
1897318 5.883 0.000 25.682 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:293(update_NZ_8)
1684193 5.427 0.000 8.761 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:187(set_Z16)
1661084 5.426 0.000 9.744 0.000 /home/jens/DragonPy_env/src/dragonpy/dragonpy/components/memory.py:227(read_word)
843845 4.508 0.000 22.251 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:329(update_NZVC_8)
1010482 4.428 0.000 26.634 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:1517(instruction_LD8)
2428999 4.375 0.000 5.602 0.000 /home/jens/DragonPy_env/src/dragonpy/dragonpy/components/memory.py:242(write_byte)
734403 4.039 0.000 19.604 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:335(update_NZVC_16)
1233863 3.955 0.000 6.414 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:2116(instruction_BNE)
1069682 3.515 0.000 5.663 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:207(set_N16)
919873 3.242 0.000 5.041 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:237(set_V8)
709969 3.198 0.000 29.866 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:1709(instruction_CMP16)
2517144 3.182 0.000 3.182 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/utils/bits.py:20(is_bit_set)
...
Code: Alles auswählen
ncalls tottime percall cumtime percall filename:lineno(function)
12541/11961 0.052 0.000 487.153 0.041 /usr/lib/python3.4/tkinter/__init__.py:1485(__call__)
8240 0.122 0.000 485.559 0.059 /home/jens/DragonPy_env/src/dragonpy/dragonpy/core/gui.py:241(cpu_interval)
8240 0.073 0.000 485.027 0.059 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:404(run)
8240 8.553 0.001 484.876 0.059 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:333(burst_run)
12512 0.063 0.000 483.947 0.039 /usr/lib/python3.4/tkinter/__init__.py:533(callit)
8255100 25.451 0.000 476.791 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:272(get_and_call_next_op)
8403598/8255100 20.331 0.000 371.806 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:288(call_instruction_func)
15549487 66.446 0.000 149.411 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:535(read_pc_byte)
2254891 7.468 0.000 54.801 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/instruction_call.py:537(relative_ea)
16584767 33.130 0.000 50.417 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:37(increment)
646331 2.206 0.000 42.781 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/instruction_call.py:136(direct_word_X_read16)
668298 2.237 0.000 38.780 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/instruction_call.py:365(indexed_A_read8)
1792270 11.384 0.000 36.726 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:592(get_ea_indexed)
2254891 9.770 0.000 35.719 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:756(get_ea_relative)
709969 3.198 0.000 29.866 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:1709(instruction_CMP16)
20645223/20638957 27.729 0.000 28.087 0.000 /home/jens/DragonPy_env/src/dragonpy/dragonpy/components/memory.py:191(read_byte)
27069837 27.168 0.000 27.168 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:98(set_flag)
1931097 6.406 0.000 26.688 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:561(get_ea_direct)
1010482 4.428 0.000 26.634 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:1517(instruction_LD8)
1897318 5.883 0.000 25.682 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:293(update_NZ_8)
26651989 25.038 0.000 25.038 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:31(get)
355525 1.643 0.000 22.798 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/instruction_call.py:50(direct_ea_read8_write8)
843845 4.508 0.000 22.251 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:329(update_NZVC_8)
21038722 22.019 0.000 22.019 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:81(set)
614495 2.060 0.000 20.639 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/instruction_call.py:455(indexed_ea_X)
357440 1.230 0.000 20.088 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/instruction_call.py:289(immediate_A_read8)
41281/40419 1.656 0.000 19.682 0.000 {method 'call' of 'tkapp' objects}
734403 4.039 0.000 19.604 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:335(update_NZVC_16)
1 0.000 0.000 19.125 19.125 /home/jens/DragonPy_env/src/dragonpy/basic_editor/editor.py:189(command_load_file)
698567 2.273 0.000 19.040 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:712(get_m_indexed)
...