RoadRunner with Multiprocessing
For these simulations we use a simple model that we can access easily from one of RoadRunners
test suites. Its called BatchImmigrationDeath03
and is model number 00039
from the
stochastic sbml test suite.
In each of the following sections we use RoadRunner to generate 1e6 stochastic simulations.
Serial code
Performing the simulations in serial gives us a way to measure the performance enhancements of using parallel code.
1import sys
2sys.path += [
3 r'D:\roadrunner\roadrunner\roadrunner-install-rel-llvm6\site-packages',
4 # r'D:\roadrunner\roadrunner\roadrunner-install-rel-llvm12\site-packages'
5]
6
7import roadrunner
8assert "llvm6" in roadrunner.__file__, roadrunner.__file__
9
10from roadrunner import RoadRunner
11from roadrunner.tests import TestModelFactory as tmf
12import time
13import numpy as np
14from platform import platform
15import cpuinfo # pip install py-cpuinfo
16
17
18
19NSIMS = 1000000
20
21if __name__ == '__main__':
22 # setup timing
23 start = time.time()
24
25 # get sbml to work with from one of our test modules
26 sbml = tmf.BatchImmigrationDeath03().str()
27
28 # create our roadrunner instance
29 rr = RoadRunner(sbml)
30
31 # set up a stochastic simulation
32 rr.setIntegrator('gillespie')
33
34 # set the seed for reproducible example
35 gillespie_integrator = rr.getIntegrator()
36 gillespie_integrator.seed = 1234
37
38 start_time = 0
39 end_time = 10
40 num_points = 11
41
42 # preallocate for efficiency
43 data = np.ndarray((NSIMS, num_points, 2))
44 for simulation_number in range(NSIMS):
45 rr.resetAll()
46 data[simulation_number] = rr.simulate(start_time, end_time, num_points)
47
48 print(data)
49 print(data.shape)
50
51 print('Took', time.time() - start, 'seconds to run', NSIMS, 'stochastic simulations on 1 core')
52 cpu_info = cpuinfo.get_cpu_info()
53 print(f'Platform: {platform()}')
54 print('python_version:', cpu_info['python_version'])
55 print('Processor:', cpu_info['brand_raw'])
56
57 '''
58 Output:
59 Took 64.92753291130066 seconds to run 1000000 stochastic simulations on 1 core
60
61 Platform: Windows-10-10.0.22000-SP0
62 python_version: 3.9.5.final.0 (64 bit)
63 Processor: 11th Gen Intel(R) Core(TM) i9-11980HK @ 2.60GHz
64 '''
Multiprocessing library
The simplest way in Python to use multiple cores simultaneously for running RoadRunner simulations is to use the multiprocessing library. Further, the simplest multiprocessing tool that one can use is a multiprocessing.Pool. This leads to about a x3 speed up for this example.
1from roadrunner import RoadRunner
2from roadrunner.tests import TestModelFactory as tmf
3from multiprocessing import Pool, cpu_count
4import time
5from platform import platform
6import cpuinfo # pip install py-cpuinfo
7
8NCORES = cpu_count()
9NSIMS = 1000000
10
11def simulate_worker(rr: RoadRunner):
12 rr.resetAll()
13 return rr.simulate(0, 10, 11)
14
15
16if __name__ == '__main__':
17 # setup timing
18 start = time.time()
19
20 # get sbml to work with from one of our test modules
21 sbml = tmf.BatchImmigrationDeath03().str()
22
23 # create our roadrunner instance
24 rr = RoadRunner(sbml)
25
26 # set up a stochastic simulation
27 rr.setIntegrator('gillespie')
28
29 # set the seed for reproducuble example
30 gillespie_integrator = rr.getIntegrator()
31 gillespie_integrator.seed = 1234
32
33 # create a processing pool
34 p = Pool(processes=NCORES)
35
36 # perform the simulations
37 arrays = p.map(simulate_worker, [rr for i in range(NSIMS)])
38
39 duration = time.time() - start
40
41 # the time it took in serial
42 serial_time = 64.92753291130066
43
44 # compute speedup
45 speedup = serial_time / duration
46
47 print(f'Took {duration} seconds to run', NSIMS, 'stochastic simulations on', NCORES, 'cores')
48 print(f'Speed up is {speedup}')
49 cpu_info = cpuinfo.get_cpu_info()
50 print(f'Platform: {platform()}')
51 print('python_version:', cpu_info['python_version'])
52 print('Processor:', cpu_info['brand_raw'])
53
54 '''
55 Output:
56 Took 19.231333017349243 seconds to run 1000000 stochastic simulations on 16 cores
57 Speed up is 3.3761327336346008
58 Platform: Windows-10-10.0.22000-SP0
59 python_version: 3.9.5.final.0 (64 bit)
60 Processor: 11th Gen Intel(R) Core(TM) i9-11980HK @ 2.60GHz
61 '''
Ray library
1import numpy as np
2
3from roadrunner import RoadRunner
4from roadrunner.tests import TestModelFactory as tmf
5from multiprocessing import cpu_count
6import ray
7import time
8from platform import platform
9import cpuinfo # pip install py-cpuinfo
10
11NCORES = cpu_count()
12NSIMS = 1000000
13
14ray.init(ignore_reinit_error=True)
15
16
17@ray.remote
18class SimulatorActorPath(object):
19 """Ray actor to execute simulations."""
20
21 def __init__(self, rr: RoadRunner):
22 self.rr: RoadRunner = rr
23
24 def simulate(self, size=1):
25 num_points = 101
26 results = np.ndarray((size, num_points, 2)) # 2 for 1 model species and time
27 for k in range(size):
28 self.rr.resetAll()
29 results[k] = self.rr.simulate(0, 100, num_points)
30 return results
31
32
33if __name__ == '__main__':
34 # setup timing
35 start = time.time()
36
37 # get sbml to work with from one of our test modules
38 sbml = tmf.BatchImmigrationDeath03().str()
39
40 # create our roadrunner instance
41 rr = RoadRunner(sbml)
42
43 # set up a stochastic simulation
44 rr.setIntegrator('gillespie')
45
46 # set the seed for reproducuble example
47 gillespie_integrator = rr.getIntegrator()
48 gillespie_integrator.seed = 1234
49
50 simulators = [SimulatorActorPath.remote(rr) for _ in range(NCORES)]
51
52 # run simulations
53 tc_ids = []
54 for k, simulator in enumerate(simulators):
55 tcs_id = simulator.simulate.remote(size=int(np.floor(NSIMS / NCORES)))
56 tc_ids.append(tcs_id)
57 results = ray.get(tc_ids)
58 print(results)
59
60 duration = time.time() - start
61
62 # the time it took in serial
63 serial_time = 64.92753291130066
64
65 # compute speedup
66 speedup = serial_time / duration
67
68 print(f'Took {duration} seconds to run', NSIMS, 'stochastic simulations on', NCORES, 'cores')
69 print(f'Speed up is {speedup}')
70 cpu_info = cpuinfo.get_cpu_info()
71 print(f'Platform: {platform()}')
72 print('python_version:', cpu_info['python_version'])
73 print('Processor:', cpu_info['brand_raw'])
74
75 '''
76 Output:
77 Took 99.32935857772827 seconds to run 1000000 stochastic simulations on 16 cores
78 Speed up is 0.6536590373780867
79 Platform: Windows-10-10.0.22000-SP0
80 python_version: 3.9.5.final.0 (64 bit)
81 Processor: 11th Gen Intel(R) Core(TM) i9-11980HK @ 2.60GHz
82 '''