Skip to content

Commit f3dacd4

Browse files
committed
Add Rust JSON serialization/deserialization benchmark
Adds a benchmark testing JSON parsing and serialization performance using serde_json. The benchmark processes ~1.3MB of JSON data representing 100 user records with nested structures (profiles, settings, posts). Tests both deserialization (JSON → Rust structs) and serialization (Rust structs → JSON) in a single benchmark cycle.
1 parent ab8bab2 commit f3dacd4

File tree

14 files changed

+16825
-0
lines changed

14 files changed

+16825
-0
lines changed
1.25 MB
Binary file not shown.
705 KB
Binary file not shown.

benchmarks/rust-json/Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../Dockerfile.rust

benchmarks/rust-json/README.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Rust JSON Serialization/Deserialization Benchmark
2+
3+
This benchmark tests JSON parsing and serialization performance using the `serde_json` crate, which is the de facto standard for JSON processing in Rust.
4+
5+
## What it tests
6+
7+
The benchmark performs both deserialization (JSON string → Rust structs) and serialization (Rust structs → JSON string) on a realistic dataset representing API response data with nested structures:
8+
9+
- 100 user records
10+
- Each user has a profile, settings, and multiple posts
11+
- Nested data structures including hashmaps, vectors, and optional fields
12+
- Total input size: ~1.3 MB of JSON data
13+
14+
## Input Data
15+
16+
The `default.input` file contains 100 user records with:
17+
- User metadata (id, username, email, timestamps)
18+
- Profile information (bio, avatar, location, social links)
19+
- User settings (theme, language, notifications, preferences)
20+
- Multiple posts per user (5-15 posts with content, tags, likes)
21+
22+
The input file can be regenerated using `generate_input.py`.
23+
24+
## Implementation
25+
26+
Uses:
27+
- `serde` 1.0 with derive macros for struct serialization
28+
- `serde_json` 1.0 for JSON processing
29+
- Measures full round-trip: parse JSON → serialize back to JSON
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[rust-json] processed 100 users
2+
[rust-json] serialized size: 1175589 bytes

benchmarks/rust-json/benchmark.stdout.expected

Whitespace-only changes.
229 KB
Binary file not shown.

benchmarks/rust-json/default.input

Lines changed: 16534 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
#!/usr/bin/env python3
2+
"""Generate a realistic JSON input file for benchmarking."""
3+
4+
import json
5+
import random
6+
from datetime import datetime, timedelta
7+
8+
def generate_user(user_id):
9+
"""Generate a single user with realistic data."""
10+
return {
11+
"id": user_id,
12+
"username": f"user_{user_id}",
13+
"email": f"user{user_id}@example.com",
14+
"full_name": f"User {user_id} Name",
15+
"is_active": random.choice([True, False]),
16+
"created_at": (datetime.now() - timedelta(days=random.randint(1, 1000))).isoformat(),
17+
"updated_at": (datetime.now() - timedelta(days=random.randint(0, 100))).isoformat(),
18+
"profile": {
19+
"bio": f"This is a bio for user {user_id}. " * random.randint(1, 5),
20+
"avatar_url": f"https://example.com/avatars/{user_id}.jpg",
21+
"location": random.choice(["New York", "London", "Tokyo", "Berlin", "Paris", "Sydney"]),
22+
"website": f"https://user{user_id}.example.com" if random.random() > 0.3 else None,
23+
"social_links": [
24+
f"https://twitter.com/user{user_id}",
25+
f"https://github.com/user{user_id}",
26+
f"https://linkedin.com/in/user{user_id}"
27+
]
28+
},
29+
"settings": {
30+
"theme": random.choice(["light", "dark", "auto"]),
31+
"language": random.choice(["en", "es", "fr", "de", "ja", "zh"]),
32+
"notifications_enabled": random.choice([True, False]),
33+
"privacy_level": random.choice(["public", "friends", "private"]),
34+
"preferences": {
35+
f"pref_{i}": f"value_{i}" for i in range(random.randint(3, 8))
36+
}
37+
},
38+
"posts": [
39+
{
40+
"id": user_id * 1000 + post_id,
41+
"title": f"Post {post_id} by user {user_id}",
42+
"content": f"This is the content of post {post_id}. " * random.randint(10, 50),
43+
"tags": [f"tag{random.randint(1, 20)}" for _ in range(random.randint(1, 5))],
44+
"likes": random.randint(0, 1000),
45+
"comments_count": random.randint(0, 100),
46+
"published_at": (datetime.now() - timedelta(days=random.randint(0, 365))).isoformat()
47+
}
48+
for post_id in range(random.randint(5, 15))
49+
]
50+
}
51+
52+
def main():
53+
# Generate 100 users for a reasonably sized benchmark
54+
users = [generate_user(i) for i in range(1, 101)]
55+
56+
with open("default.input", "w") as f:
57+
json.dump(users, f, indent=2)
58+
59+
print(f"Generated JSON with {len(users)} users")
60+
61+
if __name__ == "__main__":
62+
main()
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
target

0 commit comments

Comments
 (0)