A fast, safe, and efficient CBOR serialization library for Swift on any platform.
swiftpackageindex.com/thecoolwinter/CBOR/1.1.1/documentation/cbor
atproto
swift
cbor
1#!/usr/bin/env python3
2"""
3Parse Swift Benchmark markdown (produced by `swift package benchmark ... --format markdown`) and produce compact summary
4markdown tables for Decoding and Encoding using the Time (total CPU) p50 values.
5
6Usage:
7 - Read from stdin:
8 swift package benchmark baseline compare swiftcbor --format markdown --no-progress | python3 bench_compare.py
9 - Or read from file:
10 python3 bench_compare.py benchmark.md
11
12The script prints two markdown tables (Decoding and Encoding) to stdout.
13"""
14
15import sys
16import re
17from pathlib import Path
18
19
20def parse_markdown(text):
21 lines = text.splitlines()
22 results = {"Decoding": {}, "Encoding": {}}
23 mode = None
24 i = 0
25 while i < len(lines):
26 line = lines[i]
27 if line.strip().startswith('## Decoding'):
28 mode = 'Decoding'
29 i += 1
30 continue
31 if line.strip().startswith('## Encoding'):
32 mode = 'Encoding'
33 i += 1
34 continue
35
36 m = re.match(r"###\s+(.+?)\s+metrics", line)
37 if m and mode:
38 bench = m.group(1).strip()
39 # look ahead for Time (total CPU) table
40 j = i + 1
41 while j < len(lines) and not lines[j].strip().startswith('###') and not lines[j].strip().startswith('## '):
42 lh = lines[j]
43 # find the section header line containing "Time (total CPU)"
44 m2 = re.search(r"Time\s*\(total CPU\)\s*(?:\(([^)]+)\))?", lh)
45 if m2:
46 unit = m2.group(1) if m2.group(1) else ''
47 # find the header row that contains p0/p25/p50 etc.
48 k = j + 1
49 while k < len(lines) and lines[k].strip() == '':
50 k += 1
51 header_line_index = None
52 p50_idx = None
53 for t in range(k, min(k + 60, len(lines))):
54 if 'p50' in lines[t]:
55 cols = [c.strip() for c in lines[t].split('|')][1:-1]
56 # locate p50 column
57 try:
58 p50_idx = next(idx for idx, c in enumerate(cols) if c.startswith('p50'))
59 except StopIteration:
60 p50_idx = None
61 header_line_index = t
62 break
63 swift_val = None
64 curr_val = None
65 if header_line_index is not None and p50_idx is not None:
66 # parse following rows to find swiftcbor and Current_run
67 for t in range(header_line_index + 1, header_line_index + 60):
68 if t >= len(lines):
69 break
70 row = lines[t]
71 if not row.strip().startswith('|'):
72 continue
73 cols = [c.strip() for c in row.split('|')][1:-1]
74 if not cols:
75 continue
76 name = cols[0]
77 # defensive check
78 if p50_idx < len(cols):
79 if 'swiftcbor' in name:
80 swift_val = cols[p50_idx]
81 if 'Current_run' in name:
82 curr_val = cols[p50_idx]
83 if swift_val and curr_val:
84 break
85 results[mode][bench] = (swift_val, curr_val, unit)
86 break
87 j += 1
88 i += 1
89 return results
90
91
92def clean_num(s):
93 if s is None:
94 return None
95 s = s.strip().replace(',', '')
96 # find first numeric token
97 m = re.search(r"([0-9]+(?:\.[0-9]+)?)", s)
98 if not m:
99 return None
100 try:
101 return float(m.group(1))
102 except:
103 return None
104
105
106def fmt(n):
107 if n is None:
108 return ''
109 if n >= 1000:
110 return f"{int(round(n)):,}"
111 if n == int(n):
112 return str(int(n))
113 return f"{n:.0f}"
114
115
116def render_table_section(title, rows, preferred_order=None):
117 print(f"### {title} (cpu time)\n")
118 print("| Benchmark | SwiftCBOR (p50) | CBOR (p50) | % Improvement |")
119 print("|---|---:|---:|---:|")
120 keys = []
121 if preferred_order:
122 for k in preferred_order:
123 if k in rows:
124 keys.append(k)
125 # append remaining in alphabetical order
126 for k in sorted(rows.keys()):
127 if k not in keys:
128 keys.append(k)
129 for b in keys:
130 s_p, c_p, unit = rows.get(b, (None, None, ''))
131 sval = clean_num(s_p)
132 cval = clean_num(c_p)
133 s_str = (fmt(sval) + (' ' + unit if unit else '')) if sval is not None else (s_p or '')
134 c_str = (fmt(cval) + (' ' + unit if unit else '')) if cval is not None else (c_p or '')
135 perc = ''
136 if sval is not None and cval is not None and sval != 0:
137 pct = round((sval - cval) / sval * 100)
138 perc = f"**{pct}%**"
139 print(f"| {b} | {s_str} | {c_str} | {perc} |")
140 print("\n")
141
142
143def main(argv):
144 parser = __import__('argparse').ArgumentParser(description='Parse Swift benchmark markdown and print compact p50 tables')
145 parser.add_argument('file', nargs='?', default='-', help='Path to markdown file, or - for stdin (default)')
146 args = parser.parse_args(argv)
147 if args.file == '-':
148 text = sys.stdin.read()
149 else:
150 p = Path(args.file)
151 text = p.read_text()
152
153 results = parse_markdown(text)
154
155 # preferred orders to match your example (best-effort)
156 dec_order = ["Array","Complex Object","Date","Dictionary","Double","Float","Indeterminate String","Int","Int Small","Simple Object","String","String Small"]
157 enc_order = ["Array","Array Small","Bool","Complex Codable Object","Data","Data Small","Dictionary","Dictionary Small","Int","Int Small","Simple Codable Object","String","String Small"]
158
159 render_table_section('Decoding', results.get('Decoding', {}), preferred_order=dec_order)
160 render_table_section('Encoding', results.get('Encoding', {}), preferred_order=enc_order)
161
162
163if __name__ == '__main__':
164 main(sys.argv[1:])