@@ -35,50 +35,49 @@ jobs:
3535 cmake .. -DCMAKE_BUILD_TYPE=RelWithDebInfo
3636 make -j$(nproc)
3737
38- - name : Build toy benchmark
38+ - name : Build benchmarks
3939 run : |
4040 cd build
4141 cmake .. -DBUILD_BENCHMARKS=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo
42- make -j$(nproc) toy
42+ make -j$(nproc) toy lock_test
4343
4444 - name : Verify build artifacts
4545 run : |
4646 test -f build/libcoz/libcoz.so
4747 test -x build/benchmarks/toy/toy
48+ test -x build/benchmarks/lock_test/lock_test
4849 echo "Build artifacts verified"
4950
5051 - name : Run toy benchmark with coz
5152 run : |
5253 cd build
5354 # Run coz with the toy benchmark for a short duration
54- timeout 30 ../coz run -o profile.coz --- ./benchmarks/toy/toy || true
55+ timeout 30 ../coz run -o profile.jsonl --- ./benchmarks/toy/toy || true
5556
56- # Check that profile was created
57- if [ ! -f profile.coz ]; then
58- echo "ERROR: profile.coz was not created"
57+ if [ ! -f profile.jsonl ]; then
58+ echo "ERROR: profile.jsonl was not created"
5959 exit 1
6060 fi
6161
6262 echo "Profile created successfully"
6363
64- - name : Validate profile output
64+ - name : Validate toy profile output
6565 run : |
6666 cd build
6767
68- # Check profile has content
69- if [ ! -s profile.coz ]; then
70- echo "ERROR: profile.coz is empty"
68+ if [ ! -s profile.jsonl ]; then
69+ echo "ERROR: profile.jsonl is empty"
7170 exit 1
7271 fi
7372
7473 echo "=== Profile Contents ==="
75- cat profile.coz
74+ cat profile.jsonl
7675 echo ""
7776
7877 # Check for expected profile format (should contain experiment lines)
79- EXPERIMENT_COUNT=$(grep -c 'experiment' profile.coz || echo 0)
78+ EXPERIMENT_COUNT=$(grep -c 'experiment' profile.jsonl || echo 0)
8079 echo "=== Profile Summary ==="
81- echo " Total lines: $(wc -l < profile.coz )"
80+ echo " Total lines: $(wc -l < profile.jsonl )"
8281 echo " Experiments: $EXPERIMENT_COUNT"
8382
8483 if [ "$EXPERIMENT_COUNT" -eq 0 ]; then
8786 fi
8887
8988 # Validate profile references toy.cpp line 18 (the loop in function a())
90- # This is the critical line that should show optimization potential
91- if grep -q "toy.cpp:18" profile.coz; then
89+ if grep -q "toy.cpp:18" profile.jsonl; then
9290 echo " Found experiments for toy.cpp:18 (loop in function a())"
9391 else
9492 echo "ERROR: toy.cpp:18 not found in profile - expected loop in a() to be profiled"
@@ -98,44 +96,27 @@ jobs:
9896 echo ""
9997 echo "Profile validation PASSED"
10098
101- - name : Validate optimization potential
99+ - name : Validate toy optimization potential
102100 run : |
103101 cd build
104102
105- # Validate that toy.cpp:18 shows expected optimization behavior:
106- # - Linear speedup potential up to ~50% (because a() takes 2x as long as b())
107- # - Diminishing returns beyond 50% (speeding up a() more doesn't help since b() becomes bottleneck)
108-
109103 python3 << 'VALIDATION_SCRIPT'
110104 import sys
111- import re
105+ import json
112106
113- # Parse profile.coz
114- # Format: experiment\tselected=path:line\tspeedup=X.XX\tduration=N\tselected-samples=N
115- # Followed by: throughput-point\tname=path:line\tdelta=N
116107 experiments = []
117108 current_exp = None
118109
119- with open('profile.coz ', 'r') as f:
110+ with open('profile.jsonl ', 'r') as f:
120111 for line in f:
121112 line = line.strip()
122- if line.startswith('experiment'):
123- # Parse key=value pairs
124- parts = line.split('\t')
125- exp = {}
126- for part in parts[1:]:
127- if '=' in part:
128- key, val = part.split('=', 1)
129- exp[key] = val
130- current_exp = exp
131- elif line.startswith('throughput-point') and current_exp:
132- # Parse throughput point and attach to current experiment
133- parts = line.split('\t')
134- for part in parts[1:]:
135- if '=' in part:
136- key, val = part.split('=', 1)
137- if key == 'delta':
138- current_exp['delta'] = float(val)
113+ if not line:
114+ continue
115+ obj = json.loads(line)
116+ if obj.get('type') == 'experiment':
117+ current_exp = obj
118+ elif obj.get('type') == 'throughput_point' and current_exp:
119+ current_exp['delta'] = float(obj['delta'])
139120 experiments.append(current_exp)
140121 current_exp = None
141122
@@ -151,7 +132,7 @@ jobs:
151132 # Group by speedup percentage and calculate average delta
152133 speedup_deltas = {}
153134 for e in line18_exps:
154- s = int(float(e['speedup']) * 100) # Convert decimal (0.40) to percentage (40)
135+ s = int(float(e['speedup']) * 100)
155136 if s not in speedup_deltas:
156137 speedup_deltas[s] = []
157138 speedup_deltas[s].append(e['delta'])
@@ -162,7 +143,6 @@ jobs:
162143 avg_delta = sum(deltas) / len(deltas)
163144 print(f" {speedup}%: avg_delta={avg_delta:.2f} (n={len(deltas)})")
164145
165- # Validation: Check that we have data for multiple speedup levels
166146 if len(speedup_deltas) < 3:
167147 print(f"WARNING: Only {len(speedup_deltas)} speedup levels - need more data for accurate validation")
168148 else:
@@ -172,9 +152,80 @@ jobs:
172152 print("\nProfile validation COMPLETE")
173153 VALIDATION_SCRIPT
174154
175- - name : Upload profile artifact
155+ - name : Run lock_test benchmark with coz
156+ run : |
157+ cd build
158+ timeout 60 ../coz run -o lock_test_profile.jsonl --- ./benchmarks/lock_test/lock_test || true
159+
160+ if [ ! -f lock_test_profile.jsonl ]; then
161+ echo "ERROR: lock_test_profile.jsonl was not created"
162+ exit 1
163+ fi
164+
165+ echo "Lock test profile created successfully"
166+
167+ - name : Validate lock_test profile
168+ run : |
169+ cd build
170+
171+ if [ ! -s lock_test_profile.jsonl ]; then
172+ echo "ERROR: lock_test_profile.jsonl is empty"
173+ exit 1
174+ fi
175+
176+ echo "=== Lock Test Profile Contents ==="
177+ cat lock_test_profile.jsonl
178+ echo ""
179+
180+ python3 << 'VALIDATION_SCRIPT'
181+ import sys
182+ import json
183+
184+ experiments = []
185+ current_exp = None
186+
187+ with open('lock_test_profile.jsonl', 'r') as f:
188+ for line in f:
189+ line = line.strip()
190+ if not line:
191+ continue
192+ obj = json.loads(line)
193+ if obj.get('type') == 'experiment':
194+ current_exp = obj
195+ elif obj.get('type') == 'throughput_point' and current_exp:
196+ current_exp['delta'] = float(obj['delta'])
197+ experiments.append(current_exp)
198+ current_exp = None
199+
200+ # Check for experiments on critical_work (line 12) and local_work (line 20)
201+ line12_exps = [e for e in experiments if 'lock_test.cpp:12' in e['selected']]
202+ line20_exps = [e for e in experiments if 'lock_test.cpp:20' in e['selected']]
203+
204+ print(f"Experiments for line 12 (critical_work): {len(line12_exps)}")
205+ print(f"Experiments for line 20 (local_work): {len(line20_exps)}")
206+
207+ if not line12_exps:
208+ print("ERROR: No experiments found for lock_test.cpp:12 (critical section)")
209+ sys.exit(1)
210+
211+ # Check samples to verify critical_work dominates
212+ with open('lock_test_profile.jsonl', 'r') as f:
213+ for line in f:
214+ obj = json.loads(line.strip())
215+ if obj.get('type') == 'samples':
216+ loc = obj['location']
217+ count = obj['count']
218+ print(f" Samples: {loc} = {count}")
219+
220+ print("\nLock contention benchmark validation: PASSED")
221+ print(" - lock_test.cpp:12 (critical section) identified as profiling target")
222+ VALIDATION_SCRIPT
223+
224+ - name : Upload profile artifacts
176225 uses : actions/upload-artifact@v4
177226 with :
178- name : coz-profile
179- path : build/profile.coz
227+ name : coz-profiles
228+ path : |
229+ build/profile.jsonl
230+ build/lock_test_profile.jsonl
180231 retention-days : 7
0 commit comments