Skip to content

Commit a2ddd52

Browse files
author
Ram Rachum
committed
Going crazy
1 parent 38bdf56 commit a2ddd52

File tree

8 files changed

+206
-8
lines changed

8 files changed

+206
-8
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
from cruncherthread import *
2+
from cruncherprocess import *
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
"""
2+
3+
todo: What if EdgeRenderer has a run-time error?
4+
5+
6+
todo: In the future, we may want the EdgeCruncher to receive a
7+
copy of the SimulationCore object. We will have to implement
8+
a copy() method on SimulationCore and pass it on to the new process.
9+
10+
11+
todo maybe: put something on edgecruncher that will shut it off
12+
if the main program is killed
13+
14+
todo maybe: process creation is sometimes slow on windows.
15+
maybe have a spare EdgeCruncher at all times?
16+
17+
todo maybe: instead of passing the starter state as a parameter,
18+
it should be sent in a queue.
19+
20+
todo: make sure the cursor does not get an hourglass when it shouldn't
21+
22+
todo: Smarter priority setting. Besides, obviously, supporting Linux,
23+
Mac OS, etc., we need to monitor how much de-facto priority the
24+
process is actually getting from the OS, and to tweak its "official"
25+
priority accordingly.
26+
27+
todo: it seems that on one-core systems the crunching is very slow.
28+
Maybe due to very low process priority of edgecruncher.
29+
30+
31+
"""
32+
33+
34+
import multiprocessing
35+
36+
try:
37+
import queue
38+
except ImportError:
39+
import Queue as queue
40+
41+
try:
42+
from garlicsim.misc.processpriority import set_process_priority
43+
except:
44+
pass
45+
46+
class CruncherProcess(multiprocessing.Process):
47+
"""
48+
EdgeCruncher is a subclass of multiprocessing.Process. An EdgeCruncher
49+
is responsible for crunching the simulation in the background.
50+
An EdgeCruncher gets its instruction from the method `Project.sync_workers`.
51+
52+
How does the EdgeCruncher work? Essentially, it gets sent a state from
53+
sync_workers. It then starts repeatedly stepping from this state, and puts
54+
all the resulting states in a queue. An EdgeCruncher is quite dumb actually,
55+
most of the smart work is being done by sync_workers.
56+
"""
57+
def __init__(self,starter,step_function,*args,**kwargs):
58+
multiprocessing.Process.__init__(self,*args,**kwargs)
59+
60+
self.step=step_function
61+
self.starter=starter
62+
self.daemon=True
63+
64+
self.work_queue=multiprocessing.Queue()
65+
"""
66+
The EdgeCruncher puts the work that it has completed
67+
into this queue, to be picked up by sync_workers.
68+
"""
69+
70+
self.message_queue=multiprocessing.Queue()
71+
"""
72+
This queue is used by sync_workers to send instructions
73+
to the EdgeRenderer.
74+
"""
75+
76+
77+
def set_priority(self,priority):
78+
"""
79+
Sets the priority of this process: Currently Windows only.
80+
"""
81+
assert priority in [0,1,2,3,4,5]
82+
set_process_priority(self.pid,priority)
83+
84+
def run(self):
85+
"""
86+
The function ran by EdgeCruncher. Does the actual work.
87+
"""
88+
89+
try:
90+
self.set_priority(0)
91+
except:
92+
pass
93+
94+
#import psyco #These two belong here?
95+
#psyco.full()
96+
97+
current = self.starter
98+
order = None
99+
while True:
100+
next = self.step(current)
101+
self.work_queue.put(next)
102+
current = next
103+
104+
try:
105+
order=self.message_queue.get(block=False)
106+
#do something with order
107+
if order=="Terminate":
108+
return
109+
order = None
110+
except queue.Empty:
111+
pass
112+
113+
def terminate(self):
114+
self.message_queue.put("Terminate")
115+
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
"""
3232

3333

34-
#from core import *
3534
import threading
3635

3736
try:
@@ -44,7 +43,7 @@
4443
except:
4544
pass
4645

47-
class EdgeCruncher(threading.Thread):
46+
class CruncherThread(threading.Thread):
4847
"""
4948
EdgeCruncher is a subclass of multiprocessing.Process. An EdgeCruncher
5049
is responsible for crunching the simulation in the background.

src/garlicsim/project.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@
1717
1818
"""
1919

20+
import random
2021
import state
21-
from edgecruncher import EdgeCruncher
22+
from crunchers import CruncherThread, CruncherProcess
2223
from misc.dumpqueue import dump_queue
2324
from misc.infinity import Infinity # Same as Infinity=float("inf")
2425

@@ -45,7 +46,7 @@ class Project(object):
4546

4647
def __init__(self,simulation_package):
4748

48-
self.simulation_package=simulation_package
49+
self.init_simulation_package(simulation_package)
4950
self.tree=state.Tree()
5051

5152
self.workers={}
@@ -59,6 +60,19 @@ def __init__(self,simulation_package):
5960
how many nodes should be created after them.
6061
"""
6162

63+
def init_simulation_package(self, simulation_package):
64+
65+
self.simulation_package = simulation_package
66+
67+
step_defined = hasattr(simulation_package, "step")
68+
history_step_defined = hasattr(simulation_package, "history_step")
69+
70+
if step_defined and history_step_defined:
71+
raise StandardError("The simulation package is defining both a\
72+
step and a history_step - That's forbidden!")
73+
74+
self.history_looker = history_step_defined
75+
6276

6377
def make_plain_root(self,*args,**kwargs):
6478
"""
@@ -138,6 +152,8 @@ def sync_workers(self,temp_infinity_node=None):
138152
Returns the total amount of nodes that were added to the tree.
139153
"""
140154

155+
Cruncher = random.choice([CruncherThread, CruncherProcess])
156+
141157
my_edges_to_crunch=self.edges_to_crunch.copy()
142158

143159
if temp_infinity_node!=None:
@@ -208,7 +224,7 @@ def sync_workers(self,temp_infinity_node=None):
208224
else:
209225
# Create worker
210226
if edge.still_in_editing==False:
211-
worker=self.workers[edge]=EdgeCruncher(edge.state,step_function=self.simulation_package.step)
227+
worker=self.workers[edge]=Cruncher(edge.state,step_function=self.simulation_package.step)
212228
worker.start()
213229
if edge==temp_infinity_node:
214230
continuation_of_temp_infinity_node=edge

src/garlicsimwx/misc/threadtimer.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,16 @@ def stop(self):
2121
self.alive = False
2222

2323
class Thread(threading.Thread):
24+
2425
def run(self):
25-
while self.parent.alive:
26-
time.sleep(self.parent.interval / 1000.0)
26+
27+
interval_in_seconds = self.parent.interval / 1000.0
28+
def sleep():
29+
time.sleep(interval_in_seconds)
30+
31+
sleep()
32+
while self.parent.alive:
2733
event = wx.PyEvent()
2834
event.SetEventType(wxEVT_THREAD_TIMER)
29-
wx.PostEvent(self.parent.parent, event)
35+
wx.PostEvent(self.parent.parent, event)
36+
sleep()
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from historytest import *
2+
3+
wx_installed=False
4+
try:
5+
import wx
6+
wx_installed=True
7+
except ImportError:
8+
pass
9+
10+
if wx_installed:
11+
from historytestgui import *
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import garlicsim.state
2+
import copy
3+
#from garlicsim.misc.myprint import my_print
4+
5+
import random
6+
random.seed()
7+
8+
def make_plain_state(*args,**kwargs):
9+
state=garlicsim.state.State()
10+
state._State__touched=True
11+
state.number=0
12+
return state
13+
14+
15+
def make_random_state(*args,**kwargs):
16+
state=garlicsim.state.State()
17+
state._State__touched=True
18+
state.number=random.randint(0,10)
19+
return state
20+
21+
22+
def step(history_browser,*args,**kwargs):
23+
24+
new_state=garlicsim.state.State()
25+
26+
with history_browser:
27+
root=history_browser.request_state_by_number(0)
28+
29+
if random.choice([True,False]):
30+
new_state.number=root.number
31+
else:
32+
new_state.number=888
33+
return new_state
34+
35+
step.history_looker=True
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import wx
2+
3+
def initialize(gui_project):
4+
gui_project.text_ctrl=wx.TextCtrl(gui_project.state_showing_window,-1,style=wx.TE_MULTILINE)
5+
sizer=wx.BoxSizer(wx.VERTICAL)
6+
sizer.Add(gui_project.text_ctrl,1,wx.EXPAND)
7+
gui_project.state_showing_window.SetSizer(sizer)
8+
9+
10+
11+
def show_state(gui_project,state):
12+
gui_project.text_ctrl.SetValue(str(state.number))
13+

0 commit comments

Comments
 (0)