1+ import hashlib
12import threading
23
34import numpy as np
45
6+ from igor2 .binarywave import load as loadibw
57from igor2 .packed import load as loadpxp
68
79from helper import data_dir
@@ -13,6 +15,67 @@ def tostr(data):
1315 return data
1416
1517
18+ def _array_fingerprint (data ):
19+ # Array signature for equality checks
20+ array = np .ascontiguousarray (data )
21+ return (
22+ str (array .dtype ),
23+ tuple (int (i ) for i in array .shape ),
24+ hashlib .sha256 (array .tobytes ()).hexdigest (),
25+ )
26+
27+
28+ def _ibw_fingerprint (path ):
29+ data = loadibw (path )
30+ wave = data ["wave" ]["wData" ]
31+ header = data ["wave" ]["wave_header" ]
32+ # Include metadata plus payload signature for equality checks.
33+ return (
34+ int (data ["version" ]),
35+ tostr (header ["bname" ]),
36+ _array_fingerprint (wave ),
37+ )
38+
39+
40+ def _pxp_fingerprint (path , initial_byte_order ):
41+ records , filesystem = loadpxp (path , initial_byte_order = initial_byte_order )
42+ # Check both tree shape and wave payloads for equality checks.
43+ root_keys = tuple (sorted (tostr (key ) for key in filesystem ["root" ].keys ()))
44+ waves = []
45+ for record in records :
46+ if hasattr (record , "wave" ):
47+ wave = record .wave ["wave" ]["wData" ]
48+ name = tostr (record .wave ["wave" ]["wave_header" ]["bname" ])
49+ waves .append ((name ,) + _array_fingerprint (wave ))
50+ return (len (records ), root_keys , tuple (waves ))
51+
52+
53+ def _run_concurrent_workload (worker_count , iterations_per_worker , task ):
54+ barrier = threading .Barrier (worker_count )
55+ errors = []
56+ lock = threading .Lock ()
57+
58+ def worker (thread_id ):
59+ try :
60+ barrier .wait ()
61+ for iteration in range (iterations_per_worker ):
62+ task (thread_id , iteration )
63+ except Exception as exc :
64+ with lock :
65+ errors .append (f"thread { thread_id } : { exc !r} " )
66+
67+ threads = []
68+ for thread_id in range (worker_count ):
69+ thread = threading .Thread (target = worker , args = (thread_id ,))
70+ threads .append (thread )
71+ thread .start ()
72+
73+ for thread in threads :
74+ thread .join ()
75+
76+ assert not errors , "\n " .join (errors [:10 ])
77+
78+
1679def test_pxp ():
1780 data = loadpxp (data_dir / 'polar-graphs-demo.pxp' )
1881 records = data [0 ]
@@ -157,22 +220,50 @@ def test_pxt():
157220
158221
159222def test_thread_safe ():
223+ jobs = [
224+ (data_dir / "polar-graphs-demo.pxp" , None ),
225+ (data_dir / "packed-byteorder.pxt" , ">" ),
226+ ]
227+ expected = {job : _pxp_fingerprint (* job ) for job in jobs }
160228
161- def worker ( fileobj , thread_id ):
162- expt = None
163- for bo in ( '<' , '>' ):
164- try :
165- _ , expt = loadpxp ( fileobj , initial_byte_order = bo )
166- except ValueError :
167- pass
168- if expt is None :
169- raise ValueError ( f"No experiment loaded for thread { thread_id } " )
229+ def task ( thread_id , iteration ):
230+ job = jobs [( thread_id + iteration ) % len ( jobs )]
231+ assert _pxp_fingerprint ( * job ) == expected [ job ]
232+
233+ _run_concurrent_workload (
234+ worker_count = 32 ,
235+ iterations_per_worker = 12 ,
236+ task = task ,
237+ )
170238
171- threads = []
172- for i , fname in enumerate ([data_dir / 'packed-byteorder.pxt' ] * 100 ):
173- t = threading .Thread (target = worker , args = (fname , i ))
174- threads .append (t )
175- t .start ()
176239
177- for t in threads :
178- t .join ()
240+ def test_thread_safe_mixed ():
241+ ibw_jobs = [
242+ data_dir / "mac-double.ibw" ,
243+ data_dir / "win-double.ibw" ,
244+ data_dir / "mac-version5.ibw" ,
245+ data_dir / "win-version5.ibw" ,
246+ ]
247+ pxp_jobs = [
248+ (data_dir / "polar-graphs-demo.pxp" , None ),
249+ (data_dir / "packed-byteorder.pxt" , ">" ),
250+ ]
251+
252+ expected_ibw = {job : _ibw_fingerprint (job ) for job in ibw_jobs }
253+ expected_pxp = {job : _pxp_fingerprint (* job ) for job in pxp_jobs }
254+ all_jobs = (
255+ [("ibw" , job ) for job in ibw_jobs ] + [("pxp" , job ) for job in pxp_jobs ]
256+ )
257+
258+ def task (thread_id , iteration ):
259+ kind , payload = all_jobs [(thread_id * 3 + iteration ) % len (all_jobs )]
260+ if kind == "ibw" :
261+ assert _ibw_fingerprint (payload ) == expected_ibw [payload ]
262+ else :
263+ assert _pxp_fingerprint (* payload ) == expected_pxp [payload ]
264+
265+ _run_concurrent_workload (
266+ worker_count = 32 ,
267+ iterations_per_worker = 10 ,
268+ task = task ,
269+ )
0 commit comments