Debug Counters Implementation - Clean History
Major Features: - Debug counter infrastructure for Refill Stage tracking - Free Pipeline counters (ss_local, ss_remote, tls_sll) - Diagnostic counters for early return analysis - Unified larson.sh benchmark runner with profiles - Phase 6-3 regression analysis documentation Bug Fixes: - Fix SuperSlab disabled by default (HAKMEM_TINY_USE_SUPERSLAB) - Fix profile variable naming consistency - Add .gitignore patterns for large files Performance: - Phase 6-3: 4.79 M ops/s (has OOM risk) - With SuperSlab: 3.13 M ops/s (+19% improvement) This is a clean repository without large log files. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
128
benchmarks/scripts/utils/parse_usdt_stat.py
Normal file
128
benchmarks/scripts/utils/parse_usdt_stat.py
Normal file
@ -0,0 +1,128 @@
|
||||
#!/usr/bin/env python3
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
import csv
|
||||
|
||||
# Accept PMU events with or without user-only suffix (":u")
|
||||
PMU_EVENTS = {
|
||||
'cycles': 'cycles',
|
||||
'cycles:u': 'cycles',
|
||||
'instructions': 'instructions',
|
||||
'instructions:u': 'instructions',
|
||||
'L1-dcache-load-misses': 'l1_miss',
|
||||
'L1-dcache-load-misses:u': 'l1_miss',
|
||||
'branch-misses': 'br_miss',
|
||||
'branch-misses:u': 'br_miss',
|
||||
}
|
||||
|
||||
USDT_EVENTS = {
|
||||
'sdt:hakmem:sll_pop': 'sll_pop',
|
||||
'sdt:hakmem:mag_pop': 'mag_pop',
|
||||
'sdt:hakmem:front_pop': 'front_pop',
|
||||
'sdt:hakmem:bump_hit': 'bump_hit',
|
||||
'sdt:hakmem:slow_alloc': 'slow_alloc',
|
||||
'sdt:hakmem:sll_push': 'sll_push',
|
||||
'sdt:hakmem:mag_push': 'mag_push',
|
||||
'sdt:hakmem:spill_super': 'spill_super',
|
||||
'sdt:hakmem:spill_tiny': 'spill_tiny',
|
||||
'sdt:hakmem:remote_drain': 'remote_drain',
|
||||
'sdt:hakmem:superslab_alloc': 'super_alloc',
|
||||
'sdt:hakmem:superslab_fail': 'super_fail',
|
||||
'sdt:hakmem:quick_pop': 'quick_pop',
|
||||
'sdt:hakmem:quick_refill_sll': 'quick_refill_sll',
|
||||
'sdt:hakmem:quick_refill_mag': 'quick_refill_mag',
|
||||
'sdt:hakmem:bitmap_burst': 'bitmap_burst',
|
||||
'sdt:hakmem:mag_refill': 'mag_refill',
|
||||
'sdt:hakmem:bitmap_scan': 'bitmap_scan',
|
||||
}
|
||||
|
||||
def parse_value(s):
|
||||
s = s.strip()
|
||||
# perf may print numbers with no separators in -x , mode; best-effort
|
||||
try:
|
||||
return int(s)
|
||||
except ValueError:
|
||||
# try float to int
|
||||
try:
|
||||
return int(float(s))
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
def parse_stat_file(path):
|
||||
data = {}
|
||||
with open(path, 'r', errors='ignore') as f:
|
||||
for line in f:
|
||||
parts = [p.strip() for p in line.strip().split(',')]
|
||||
if len(parts) < 3:
|
||||
continue
|
||||
val = parse_value(parts[0])
|
||||
event = parts[2]
|
||||
if val is None:
|
||||
continue
|
||||
# Normalize PMU event key (strip optional ":u")
|
||||
if not event.startswith('sdt:'):
|
||||
base = event.split(':')[0]
|
||||
if event not in PMU_EVENTS and base in PMU_EVENTS:
|
||||
event = base
|
||||
if event in PMU_EVENTS:
|
||||
data[PMU_EVENTS[event]] = val
|
||||
elif event in USDT_EVENTS:
|
||||
name = USDT_EVENTS[event]
|
||||
data[name] = data.get(name, 0) + val
|
||||
# else ignore
|
||||
return data
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 2:
|
||||
print("Usage: parse_usdt_stat.py <usdt_results_dir>")
|
||||
sys.exit(1)
|
||||
root = sys.argv[1]
|
||||
rows = []
|
||||
for fn in sorted(os.listdir(root)):
|
||||
if not fn.endswith('.stat.csv'):
|
||||
continue
|
||||
m = re.match(r'(?P<alloc>hakmem|system)_s(?P<size>\d+)_b(?P<batch>\d+)_c(?P<cycles>\d+)\.stat\.csv', fn)
|
||||
if not m:
|
||||
continue
|
||||
meta = m.groupdict()
|
||||
path = os.path.join(root, fn)
|
||||
stats = parse_stat_file(path)
|
||||
row = {
|
||||
'allocator': meta['alloc'],
|
||||
'size': int(meta['size']),
|
||||
'batch': int(meta['batch']),
|
||||
'cycles_param': int(meta['cycles']),
|
||||
}
|
||||
row.update(stats)
|
||||
# derived
|
||||
total_pops = sum(row.get(k, 0) for k in ('sll_pop','mag_pop','front_pop'))
|
||||
if total_pops > 0:
|
||||
row['front_rate'] = row.get('front_pop',0)/total_pops
|
||||
row['sll_rate'] = row.get('sll_pop',0)/total_pops
|
||||
row['mag_rate'] = row.get('mag_pop',0)/total_pops
|
||||
else:
|
||||
row['front_rate'] = row['sll_rate'] = row['mag_rate'] = 0.0
|
||||
rows.append(row)
|
||||
|
||||
# sort for readability
|
||||
rows.sort(key=lambda r: (r['allocator'], r['size'], r['batch']))
|
||||
out = os.path.join(root, 'summary.csv')
|
||||
# collect headers
|
||||
headers = ['allocator','size','batch','cycles_param'] + list(PMU_EVENTS.values()) + list(USDT_EVENTS.values()) + ['front_rate','sll_rate','mag_rate']
|
||||
# remove duplicates but keep order
|
||||
seen = set()
|
||||
hdr_final = []
|
||||
for h in headers:
|
||||
if h not in seen:
|
||||
hdr_final.append(h)
|
||||
seen.add(h)
|
||||
with open(out, 'w', newline='') as f:
|
||||
w = csv.DictWriter(f, fieldnames=hdr_final)
|
||||
w.writeheader()
|
||||
for r in rows:
|
||||
w.writerow(r)
|
||||
print(out)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user