Skip to content

Commit 7061f7b

Browse files
Updating the performance comparison slides to use an actual image.
markdown based visual was ugly.
1 parent cadf4d5 commit 7061f7b

File tree

6 files changed

+1237
-74
lines changed

6 files changed

+1237
-74
lines changed

cppcon2025/cppcon_2025_slides.md

Lines changed: 17 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -298,8 +298,10 @@ Player load_player(const std::string& json_str) {
298298

299299
---
300300

301+
# Benefits
302+
301303
- **No manual field mapping**
302-
- **No maintenance burden**
304+
- **No maintenance burden**
303305
- **Handles nested structures automatically**
304306
- **Performance tuned by the library**
305307

@@ -918,37 +920,15 @@ _mm512_cmple_epu8_mask(word, _mm512_set1_epi8(31));
918920

919921
# Current JSON Serialization Landscape
920922

921-
**How fast can popular libraries serialize JSON?**
922-
923-
```
924-
nlohmann::json: ██ 242 MB/s
925-
RapidJSON: █████ 497 MB/s
926-
Serde (Rust): █████████████ 1,343 MB/s
927-
yyjson: ████████████████████ 2,074 MB/s
928-
929-
0 500 1000 1500 2000 2500 MB/s
930-
```
923+
<img src="images/perf_landscape.png" width="85%"/>
931924

932925
---
933926

934927
# How fast are we? ...
935928

936-
```
937-
nlohmann::json: ██ 242 MB/s
938-
RapidJSON: █████ 497 MB/s
939-
Serde (Rust): █████████████ 1,343 MB/s
940-
yyjson: ████████████████████ 2,074 MB/s
941-
simdjson: ██████████████████████████████████ 3,435 MB/s ⭐
929+
<img src="images/perf_with_simdjson.png" width="80%"/>
942930

943-
0 500 1000 1500 2000 2500 3000 3500 MB/s
944-
```
945-
946-
**3.4 GB/s** on the Twitter benchmark - That's:
947-
- **14x faster** than nlohmann
948-
- **2.5x faster** than Rust's Serde
949-
- **66% faster** than hand-optimized yyjson
950-
951-
**How did we achieve this? Let's find out...**
931+
**3.4 GB/s** - 14x faster than nlohmann, 2.5x faster than Serde!
952932

953933
---
954934

@@ -1023,7 +1003,6 @@ for (char c : str) {
10231003
}
10241004
```
10251005

1026-
<<<<<<< HEAD
10271006
**SIMD (16 bytes at once):**
10281007
```cpp
10291008
__m128i chunk = load_16_bytes(str);
@@ -1051,49 +1030,22 @@ if (!needs_escape)
10511030

10521031
**Traditional:**
10531032
```cpp
1054-
std::to_string(value).length(); // Allocates string just to count digits!
1055-
1056-
Optimized:
1057-
fast_digit_count(value); // Bit operations + lookup table, no allocation
1058-
1059-
| Dataset | Baseline | No Fast Digits | Impact | Speedup |
1060-
|---------|------------|----------------|--------|---------|
1061-
| Twitter | 3,231 MB/s | 3,041 MB/s | -6% | 1.06x |
1062-
| CITM | 2,341 MB/s | 1,841 MB/s | -21% | 1.27x |
1063-
1064-
CITM has ~10,000+ numbers needing digit counts!
1065-
1066-
---
1067-
How Fast Digit Counting Works
1068-
1069-
The Problem: Need to know buffer size before converting number to string
1070-
1071-
Traditional Approach:
1072-
```cpp
1073-
size_t digit_count(uint64_t v) {
1074-
return std::to_string(v).length();
1075-
// 1. Allocates memory
1076-
// 2. Converts entire number to string
1077-
// 3. Gets length
1078-
// 4. Deallocates string
1079-
}
1033+
std::to_string(value).length(); // Allocates string just to count!
10801034
```
10811035
1082-
Our Optimization:
1036+
**Optimized:**
10831037
```cpp
1084-
int fast_digit_count(uint64_t x) {
1085-
// Approximate using bit operations (no division!)
1086-
int y = (19 * int_log2(x) >> 6);
1038+
fast_digit_count(value); // Bit operations + lookup table
1039+
```
10871040

1088-
// Refine using lookup table
1089-
static uint64_t table[] = {9, 99, 999, 9999, ...};
1090-
y += x > table[y];
1041+
| Dataset | Baseline | No Fast Digits | **Speedup** |
1042+
|---------|----------|----------------|-------------|
1043+
| Twitter | 3,231 MB/s | 3,041 MB/s | **1.06x** |
1044+
| CITM | 2,341 MB/s | 1,841 MB/s | **1.27x** |
10911045

1092-
return y + 1;
1093-
}
1094-
```
1046+
**CITM has ~10,000+ integers!**
10951047

1096-
Zero allocations, no string conversion, just math!
1048+
---
10971049

10981050
# Optimizations #4 & #5: Branch Hints & Buffer Growth
10991051

@@ -1138,16 +1090,7 @@ if (UNLIKELY(buffer_full)) { // CPU knows this is rare
11381090

11391091
# Library Performance Comparison
11401092

1141-
**Twitter Dataset (631KB):**
1142-
```
1143-
simdjson (reflection): ████████████████████████ 3,435 MB/s ⭐
1144-
yyjson: ██████████████ 2,074 MB/s
1145-
Serde (Rust): █████████ 1,343 MB/s
1146-
RapidJSON: ███ 497 MB/s
1147-
nlohmann::json: ██ 242 MB/s
1148-
```
1149-
1150-
**simdjson achieves the fastest JSON serialization performance!**
1093+
<img src="images/perf_comparison.png" width="85%"/>
11511094

11521095
---
11531096

cppcon2025/cppcon_2025_slides_preview.html

Lines changed: 1128 additions & 0 deletions
Large diffs are not rendered by default.

cppcon2025/generate_charts.py

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
#!/usr/bin/env python3
2+
import matplotlib.pyplot as plt
3+
import numpy as np
4+
5+
# Set up the style
6+
plt.style.use('default')
7+
plt.rcParams['figure.facecolor'] = 'white'
8+
plt.rcParams['axes.facecolor'] = 'white'
9+
plt.rcParams['font.size'] = 12
10+
plt.rcParams['font.weight'] = 'bold'
11+
12+
# Data for the charts
13+
libraries = ['nlohmann::json', 'RapidJSON', 'Serde (Rust)', 'yyjson']
14+
speeds = [242, 497, 1343, 2074]
15+
colors = ['#2E86AB', '#A23B72', '#F18F01', '#C73E1D']
16+
17+
# Chart 1: Current Landscape (without simdjson)
18+
fig, ax = plt.subplots(figsize=(12, 6))
19+
bars = ax.barh(libraries, speeds, color=colors, height=0.6)
20+
ax.set_xlabel('Speed (MB/s)', fontsize=14, fontweight='bold')
21+
ax.set_title('Current JSON Serialization Landscape', fontsize=16, fontweight='bold')
22+
ax.set_xlim(0, 2500)
23+
ax.grid(axis='x', alpha=0.3, linestyle='--')
24+
25+
# Add value labels on bars
26+
for bar, speed in zip(bars, speeds):
27+
ax.text(bar.get_width() + 50, bar.get_y() + bar.get_height()/2,
28+
f'{speed} MB/s', va='center', fontweight='bold')
29+
30+
plt.tight_layout()
31+
plt.savefig('/Users/random_person/Desktop/simdjson_talks/cppcon2025/images/perf_landscape.png',
32+
dpi=150, bbox_inches='tight', facecolor='white')
33+
plt.close()
34+
35+
# Chart 2: With simdjson reveal
36+
libraries_with_simdjson = ['nlohmann::json', 'RapidJSON', 'Serde (Rust)', 'yyjson', 'simdjson']
37+
speeds_with_simdjson = [242, 497, 1343, 2074, 3435]
38+
colors_with_simdjson = ['#2E86AB', '#A23B72', '#F18F01', '#C73E1D', '#00A878']
39+
40+
fig, ax = plt.subplots(figsize=(14, 6)) # Wider figure
41+
bars = ax.barh(libraries_with_simdjson, speeds_with_simdjson, color=colors_with_simdjson, height=0.6)
42+
ax.set_xlabel('Speed (MB/s)', fontsize=14, fontweight='bold')
43+
ax.set_title('JSON Serialization Performance Comparison', fontsize=16, fontweight='bold')
44+
ax.set_xlim(0, 4000) # Extended x-axis limit
45+
ax.grid(axis='x', alpha=0.3, linestyle='--')
46+
47+
# Add value labels on bars
48+
for bar, speed, lib in zip(bars, speeds_with_simdjson, libraries_with_simdjson):
49+
label = f'{speed} MB/s ⭐' if lib == 'simdjson' else f'{speed} MB/s'
50+
ax.text(bar.get_width() + 50, bar.get_y() + bar.get_height()/2,
51+
label, va='center', fontweight='bold')
52+
53+
# Highlight simdjson bar
54+
bars[-1].set_edgecolor('gold')
55+
bars[-1].set_linewidth(3)
56+
57+
plt.tight_layout()
58+
plt.savefig('/Users/random_person/Desktop/simdjson_talks/cppcon2025/images/perf_with_simdjson.png',
59+
dpi=150, bbox_inches='tight', facecolor='white')
60+
plt.close()
61+
62+
# Chart 3: Final comparison (sorted by performance)
63+
libraries_sorted = ['simdjson', 'yyjson', 'Serde (Rust)', 'RapidJSON', 'nlohmann::json']
64+
speeds_sorted = [3435, 2074, 1343, 497, 242]
65+
colors_sorted = ['#00A878', '#C73E1D', '#F18F01', '#A23B72', '#2E86AB']
66+
67+
fig, ax = plt.subplots(figsize=(14, 6)) # Wider figure
68+
bars = ax.barh(libraries_sorted, speeds_sorted, color=colors_sorted, height=0.6)
69+
ax.set_xlabel('Speed (MB/s)', fontsize=14, fontweight='bold')
70+
ax.set_title('Twitter Dataset (631KB) - Serialization Performance', fontsize=16, fontweight='bold')
71+
ax.set_xlim(0, 4000) # Extended x-axis limit
72+
ax.grid(axis='x', alpha=0.3, linestyle='--')
73+
74+
# Add value labels on bars
75+
for bar, speed, lib in zip(bars, speeds_sorted, libraries_sorted):
76+
label = f'{speed} MB/s ⭐' if lib == 'simdjson' else f'{speed} MB/s'
77+
ax.text(bar.get_width() + 50, bar.get_y() + bar.get_height()/2,
78+
label, va='center', fontweight='bold')
79+
80+
# Highlight simdjson bar
81+
bars[0].set_edgecolor('gold')
82+
bars[0].set_linewidth(3)
83+
84+
plt.tight_layout()
85+
plt.savefig('/Users/random_person/Desktop/simdjson_talks/cppcon2025/images/perf_comparison.png',
86+
dpi=150, bbox_inches='tight', facecolor='white')
87+
plt.close()
88+
89+
print("Charts generated successfully!")
90+
print("- perf_landscape.png: Current landscape without simdjson")
91+
print("- perf_with_simdjson.png: Performance comparison with simdjson")
92+
print("- perf_comparison.png: Final sorted comparison")
66.4 KB
Loading
53.3 KB
Loading
64.6 KB
Loading

0 commit comments

Comments
 (0)