Skip to content

Commit 6caf288

Browse files
committed
multithread optimizations
1 parent 303487d commit 6caf288

6 files changed

Lines changed: 35 additions & 23 deletions

File tree

figures/ap_plot.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@
1313
traces = {
1414
"matexp": {},
1515
"sparse": {},
16-
"approx32": {},
17-
"approx64": {},
16+
"approx": {},
1817
"accuracy": {},
1918
}
2019

@@ -42,7 +41,7 @@
4241
"Backwards Euler Method",
4342
"Approximate Matrix Exponential Method vs Time Step",
4443
"Approximate Matrix Exponential Method vs Accuracy",]
45-
methods = ["matexp", "sparse", "approx32", "accuracy"]
44+
methods = ["matexp", "sparse", "approx", "accuracy"]
4645

4746
t_min, t_max = (3, 3.6)
4847

@@ -67,7 +66,7 @@
6766
title = titles[index]
6867
method = methods[index]
6968
#
70-
axes.text(t_min+.1, 15, chr(ord("A") + index), ha='left', va='top',
69+
axes.text(t_min+.05, 25, chr(ord("A") + index), ha='left', va='top',
7170
fontsize="large", weight="bold")
7271
num_traces = len(traces[method])
7372
for trace_index, (value, (t, v)) in enumerate(traces[method].items()):
@@ -83,7 +82,10 @@
8382
# axes.grid(which="major", axis='both', linestyle='solid', linewidth=1)
8483
axes.set_xlabel("time (ms)")
8584
axes.set_xlim(xmin=t_min, xmax=t_max)
86-
axes.legend()
85+
if index == 3:
86+
axes.legend(loc='center right')
87+
else:
88+
axes.legend(loc='best')
8789

8890
fig.savefig("ap_demo.png", dpi=600, bbox_inches='tight')
8991
if not os.environ.get('NOSHOW', ''): plt.show()

figures/ap_run.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ max_errors=(
3232
)
3333

3434
for err in "${max_errors[@]}"; do
35-
python ap_sim.py approx .025 $err
35+
python ap_sim.py approx .001 $err
3636
done
3737

3838
python ap_plot.py

figures/err_run.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ exec 2>&1
77

88
CELLS=10000
99

10-
SEED=$RANDOM
10+
# SEED=$RANDOM
11+
SEED=12345
1112

1213
# python -c "import numpy; print('\n'.join(str(x) for x in numpy.geomspace(.001, 1, 10)))"
1314

matexp/__init__.py

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,6 @@
1111

1212
# Written by David McDougall, 2022-2026
1313

14-
# Disable automatic multithreading
15-
import os
16-
os.environ['OPENBLAS_NUM_THREADS'] = '1'
17-
os.environ['MKL_NUM_THREADS'] = '1'
18-
os.environ['OMP_NUM_THREADS'] = '1'
19-
2014
from .approx import Approx1D, Approx2D, MatrixSamples
2115
from .codegen import Codegen
2216
from .inputs import LinearInput, LogarithmicInput
@@ -25,14 +19,17 @@
2519
from pathlib import Path
2620
import multiprocessing
2721
import numpy as np
22+
import dill
2823
import time
24+
import os
2925
import sys
3026

3127
__all__ = ('main', 'LinearInput', 'LogarithmicInput')
3228

3329
_num_threads = len(os.sched_getaffinity(0))
3430
_thread_pool = None
35-
def _initialize_thread_pool(verbose):
31+
_derivative = None
32+
def _initialize_thread_pool(model, verbose):
3633
global _thread_pool
3734
if verbose: print("Worker pool:", _num_threads, 'processes')
3835
# Manually delete any leftover shared memory files from a previous run.
@@ -42,15 +39,27 @@ def _initialize_thread_pool(verbose):
4239
else:
4340
pass # todo
4441
multiprocessing.set_start_method('spawn')
45-
_thread_pool = multiprocessing.Pool(_num_threads)
42+
_thread_pool = multiprocessing.Pool(
43+
_num_threads,
44+
_initialize_worker_process,
45+
(dill.dumps(model.derivative),)) # Send the derivative function to every worker.
4646
return _thread_pool
4747

48+
def _initialize_worker_process(derivative_pickle):
49+
# Recv the derivative function.
50+
global _derivative
51+
_derivative = dill.loads(derivative_pickle)
52+
# Disable automatic multithreading
53+
os.environ['OPENBLAS_NUM_THREADS'] = '1'
54+
os.environ['MKL_NUM_THREADS'] = '1'
55+
os.environ['OMP_NUM_THREADS'] = '1'
56+
4857
def main(nmodl_filename, inputs, time_step, temperature,
4958
error, target,
5059
outfile=None, verbose=False):
51-
_initialize_thread_pool(verbose >= 2)
5260
# Read and process the NMODL file.
5361
model = LTI_Model(nmodl_filename, inputs, time_step, temperature)
62+
_initialize_thread_pool(model, verbose >= 2)
5463
if model.num_inputs == 1: OptimizerClass = Optimize1D
5564
elif model.num_inputs == 2: OptimizerClass = Optimize2D
5665
else: raise NotImplementedError('too many inputs.')

matexp/approx.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
from itertools import pairwise, repeat
55
import math
66
import numpy as np
7-
import scipy.stats
87

98
class MatrixSamples:
109
def __init__(self, model, verbose=False):

matexp/lti_model.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
from .nmodl_compiler import NMODL_Compiler
22
from multiprocessing.shared_memory import SharedMemory
33
from itertools import pairwise, repeat
4-
import dill
54
import numpy as np
65
import scipy.linalg
76

@@ -48,8 +47,10 @@ def make_deriv_matrix(self, inputs):
4847
boundaries = [num_samples * i // num_chunks for i in range(num_chunks + 1)]
4948
input_slices = [slice(*pair) for pair in pairwise(boundaries)]
5049
#
51-
derivative = dill.dumps(self.derivative)
52-
args = (repeat(derivative), repeat(self.num_inputs), repeat(self.num_states), repeat(num_samples), input_slices)
50+
args = (repeat(self.num_inputs),
51+
repeat(self.num_states),
52+
repeat(num_samples),
53+
input_slices)
5354
for _ in _thread_pool.map(self._compute_deriv, zip(*args), chunksize=1): pass
5455
# for _ in map(self._compute_deriv, zip(*args)): pass
5556
return np.ndarray(deriv_shape, dtype=np.float64, buffer=deriv_sm.buf).copy(), deriv_sm
@@ -60,8 +61,8 @@ def make_deriv_matrix(self, inputs):
6061

6162
@staticmethod
6263
def _compute_deriv(args):
63-
derivative, num_inputs, num_states, num_samples, input_slice = args
64-
derivative = dill.loads(derivative)
64+
num_inputs, num_states, num_samples, input_slice = args
65+
from . import _derivative
6566
inputs_shape = (num_inputs, num_samples)
6667
deriv_shape = (num_samples, num_states, num_states)
6768
inputs_sm = SharedMemory('matexp_deriv_inputs', False)
@@ -74,7 +75,7 @@ def _compute_deriv(args):
7475
for col in range(num_states):
7576
state.fill(0.)
7677
state[col, :] = 1.
77-
deriv[input_slice, :, col] = np.transpose(derivative(*chunk_inputs, *state))
78+
deriv[input_slice, :, col] = np.transpose(_derivative(*chunk_inputs, *state))
7879
inputs_sm.close()
7980
deriv_sm.close()
8081

0 commit comments

Comments
 (0)