Skip to content

Commit 03ac63c

Browse files
authored
Merge pull request #33 from lpgauth/bench-pgo-glazer
PGO-build glazer in bench CI and bump to 0.5.11
2 parents 762b611 + 2c6d02b commit 03ac63c

4 files changed

Lines changed: 125 additions & 45 deletions

File tree

.github/workflows/bench.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,25 @@ jobs:
8282
"$profdata" merge -o pgo-data/merged.profdata "${raw[@]}"
8383
ls -la pgo-data
8484
85+
# PGO the comparison library too, so the benchmark is PGO-vs-PGO instead
86+
# of PGO-torque-vs-plain-glazer. glazer's `make OPTIMIZE=1` target drives
87+
# PGO from bin/pgo-profile.es, which the hex package doesn't ship, so we
88+
# drive its c_src Makefile's PGO=generate/use directly with the same
89+
# payloads the torque pass uses (bench/glazer_pgo_workload.exs). The
90+
# runtime loads deps/glazer/priv/glazer.so (the _build app priv dir is a
91+
# symlink to it), so rebuilding there is what the benchmark picks up.
92+
# CI's g++ is GCC: it writes .gcda and reads them back from the profile
93+
# dir on -fprofile-use with no separate merge step. A later
94+
# `mix compile --force` only forces torque, not the glazer dep, so this
95+
# optimised .so survives into the benchmark step.
96+
- name: Build instrumented glazer & collect PGO profile
97+
run: |
98+
make -C deps/glazer/c_src PGO=generate clean all
99+
mix run bench/glazer_pgo_workload.exs
100+
101+
- name: Rebuild glazer with PGO profile
102+
run: make -C deps/glazer/c_src PGO=use all
103+
85104
# PGO pass 2: rebuild torque with the collected profile, then benchmark.
86105
# --force is mandatory here: mix does not treat a changed RUSTFLAGS as a
87106
# reason to recompile, so a plain `mix compile` is a no-op and the

README.md

Lines changed: 44 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -176,65 +176,65 @@ optimised (PGO) builds: **Torque PGO** (via `scripts/pgo-build.sh`) and
176176

177177
| Library | ips | mean | median | p99 | memory |
178178
|---|---|---|---|---|---|
179-
| **torque** | **404.0K** | **2.48 μs** | **2.29 μs** | **5.75 μs** | 1.56 KB |
180-
| **glazer** | 378.7K | 2.64 μs | 2.38 μs | 7.08 μs | 1.56 KB |
181-
| **jiffy** | 201.3K | 4.97 μs | 4.25 μs | 13.21 μs | **1.55 KB** |
182-
| **simdjsone** | 180.8K | 5.53 μs | 5.21 μs | 12.50 μs | 1.59 KB |
183-
| **otp json** | 140.6K | 7.11 μs | 6.71 μs | 15.38 μs | 7.73 KB |
184-
| **jason** | 109.4K | 9.14 μs | 8.50 μs | 18.83 μs | 9.54 KB |
179+
| **torque** | **413.3K** | **2.42 μs** | **2.29 μs** | **4.04 μs** | 1.56 KB |
180+
| **glazer** | 401.8K | 2.49 μs | 2.38 μs | 4.58 μs | 1.56 KB |
181+
| **jiffy** | 202.5K | 4.94 μs | 4.50 μs | 9.75 μs | **1.55 KB** |
182+
| **simdjsone** | 178.2K | 5.61 μs | 5.25 μs | 12.63 μs | 1.59 KB |
183+
| **otp json** | 147.4K | 6.78 μs | 6.58 μs | 10.58 μs | 7.73 KB |
184+
| **jason** | 113.2K | 8.83 μs | 8.46 μs | 13.96 μs | 9.54 KB |
185185

186186
### Decode (750 KB Twitter)
187187

188188
| Library | ips | mean | median | p99 | memory |
189189
|---|---|---|---|---|---|
190-
| **torque** | **648.3** | **1.54 ms** | **1.34 ms** | **2.12 ms** | **1.57 KB** |
191-
| **glazer** | 587.5 | 1.70 ms | 1.56 ms | 2.24 ms | 1.58 KB |
192-
| **simdjsone** | 437.9 | 2.28 ms | 1.95 ms | 3.37 ms | 1.59 KB |
193-
| **jiffy** | 278.5 | 3.59 ms | 3.69 ms | 4.00 ms | 2.30 MB |
194-
| **otp json** | 201.3 | 4.97 ms | 5.02 ms | 5.68 ms | 2.48 MB |
195-
| **jason** | 140.3 | 7.13 ms | 7.13 ms | 7.65 ms | 3.54 MB |
190+
| **torque** | **660.7** | **1.51 ms** | **1.33 ms** | 2.21 ms | **1.57 KB** |
191+
| **glazer** | 659.6 | 1.52 ms | 1.43 ms | **1.94 ms** | 1.58 KB |
192+
| **simdjsone** | 413.6 | 2.42 ms | 1.93 ms | 3.75 ms | 1.59 KB |
193+
| **jiffy** | 301.4 | 3.32 ms | 3.39 ms | 3.96 ms | 2.30 MB |
194+
| **otp json** | 205.3 | 4.87 ms | 4.80 ms | 7.52 ms | 2.48 MB |
195+
| **jason** | 151.7 | 6.59 ms | 6.58 ms | 6.97 ms | 3.52 MB |
196196

197197
### Encode (1.2 KB OpenRTB)
198198

199199
| Library | ips | mean | median | p99 | memory |
200200
|---|---|---|---|---|---|
201-
| **torque** [proplist() :: iodata()] | **1360K** | **0.74 μs** | **0.67 μs** | **0.92 μs** | **64 B** |
202-
| **torque** [proplist() :: binary()] | 1340K | 0.75 μs | **0.67 μs** | **0.92 μs** | 88 B |
203-
| **glazer** [map() :: binary()] | 1230K | 0.81 μs | 0.75 μs | 1.00 μs | **64 B** |
204-
| **otp json** [map() :: iodata()] | 1190K | 0.84 μs | 0.79 μs | 1.21 μs | 3928 B |
205-
| **torque** [map() :: iodata()] | 1160K | 0.86 μs | 0.79 μs | 1.04 μs | **64 B** |
206-
| **torque** [map() :: binary()] | 1160K | 0.86 μs | 0.79 μs | 1.04 μs | 88 B |
207-
| **jiffy** [proplist() :: iodata()] | 720K | 1.39 μs | 1.17 μs | 1.79 μs | 120 B |
208-
| **jiffy** [map() :: iodata()] | 610K | 1.65 μs | 1.42 μs | 3.58 μs | 824 B |
209-
| **jason** [map() :: iodata()] | 600K | 1.68 μs | 1.50 μs | 4.21 μs | 3848 B |
210-
| **simdjsone** [proplist() :: iodata()] | 450K | 2.22 μs | 2.04 μs | 2.71 μs | 184 B |
211-
| **jason** [map() :: binary()] | 390K | 2.59 μs | 2.38 μs | 6.42 μs | 3912 B |
212-
| **simdjsone** [map() :: iodata()] | 380K | 2.62 μs | 2.42 μs | 3.33 μs | 888 B |
201+
| **otp json** [map() :: iodata()] | **1180K** | **0.85 μs** | **0.79 μs** | **1.08 μs** | 3928 B |
202+
| **torque** [proplist() :: binary()] | 1110K | 0.90 μs | 0.83 μs | **1.08 μs** | 88 B |
203+
| **torque** [proplist() :: iodata()] | 1080K | 0.92 μs | 0.83 μs | 1.83 μs | **64 B** |
204+
| **torque** [map() :: iodata()] | 1000K | 1.00 μs | 0.96 μs | 1.13 μs | **64 B** |
205+
| **glazer** [map() :: binary()] | 990K | 1.01 μs | 0.92 μs | 1.29 μs | **64 B** |
206+
| **torque** [map() :: binary()] | 980K | 1.02 μs | 0.96 μs | 1.17 μs | 88 B |
207+
| **jiffy** [proplist() :: iodata()] | 640K | 1.57 μs | 1.33 μs | 1.83 μs | 120 B |
208+
| **jason** [map() :: iodata()] | 620K | 1.62 μs | 1.54 μs | 2.63 μs | 3848 B |
209+
| **jiffy** [map() :: iodata()] | 520K | 1.91 μs | 1.75 μs | 2.25 μs | 824 B |
210+
| **simdjsone** [proplist() :: iodata()] | 410K | 2.42 μs | 2.29 μs | 3.00 μs | 184 B |
211+
| **jason** [map() :: binary()] | 380K | 2.63 μs | 2.38 μs | 6.42 μs | 3912 B |
212+
| **simdjsone** [map() :: iodata()] | 340K | 2.94 μs | 2.75 μs | 4.38 μs | 888 B |
213213

214214
### Encode (750 KB Twitter)
215215

216216
| Library | ips | mean | median | p99 | memory |
217217
|---|---|---|---|---|---|
218-
| **torque** [proplist() :: binary()] | **1424.6** | **0.70 ms** | **0.68 ms** | **0.84 ms** | 88 B |
219-
| **torque** [proplist() :: iodata()] | 1416.7 | 0.71 ms | **0.68 ms** | 1.11 ms | **64 B** |
220-
| **torque** [map() :: binary()] | 1211.6 | 0.83 ms | 0.81 ms | 1.00 ms | 88 B |
221-
| **torque** [map() :: iodata()] | 1208.4 | 0.83 ms | 0.81 ms | 0.99 ms | **64 B** |
222-
| **glazer** [map() :: binary()] | 1082.5 | 0.92 ms | 0.91 ms | 1.06 ms | **64 B** |
223-
| **jiffy** [proplist() :: iodata()] | 537.1 | 1.86 ms | 1.84 ms | 2.11 ms | 37.7 KB |
224-
| **jiffy** [map() :: iodata()] | 409.0 | 2.45 ms | 2.33 ms | 2.99 ms | 1.06 MB |
225-
| **simdjsone** [proplist() :: iodata()] | 259.1 | 3.86 ms | 3.81 ms | 5.68 ms | 37.7 KB |
226-
| **jason** [map() :: iodata()] | 258.9 | 3.86 ms | 3.62 ms | 5.88 ms | 4.96 MB |
227-
| **otp json** [map() :: iodata()] | 252.7 | 3.96 ms | 4.14 ms | 6.63 ms | 5.40 MB |
228-
| **simdjsone** [map() :: iodata()] | 229.7 | 4.35 ms | 4.34 ms | 4.67 ms | 1.06 MB |
229-
| **jason** [map() :: binary()] | 130.4 | 7.67 ms | 7.70 ms | 8.35 ms | 4.96 MB |
218+
| **torque** [proplist() :: iodata()] | **1156.0** | **0.87 ms** | **0.85 ms** | **1.06 ms** | **64 B** |
219+
| **torque** [proplist() :: binary()] | 1154.1 | **0.87 ms** | **0.85 ms** | **1.06 ms** | 88 B |
220+
| **torque** [map() :: binary()] | 1045.4 | 0.96 ms | 0.95 ms | 1.13 ms | 88 B |
221+
| **torque** [map() :: iodata()] | 1040.4 | 0.96 ms | 0.96 ms | 1.13 ms | **64 B** |
222+
| **glazer** [map() :: binary()] | 1033.3 | 0.97 ms | 0.96 ms | 1.08 ms | **64 B** |
223+
| **jiffy** [proplist() :: iodata()] | 469.5 | 2.13 ms | 2.10 ms | 2.51 ms | 37.7 KB |
224+
| **jiffy** [map() :: iodata()] | 347.6 | 2.88 ms | 2.96 ms | 3.90 ms | 1.06 MB |
225+
| **simdjsone** [proplist() :: iodata()] | 254.7 | 3.93 ms | 3.87 ms | 5.44 ms | 37.7 KB |
226+
| **otp json** [map() :: iodata()] | 251.8 | 3.97 ms | 4.13 ms | 6.44 ms | 5.40 MB |
227+
| **jason** [map() :: iodata()] | 233.5 | 4.28 ms | 4.03 ms | 6.50 ms | 4.96 MB |
228+
| **simdjsone** [map() :: iodata()] | 215.1 | 4.65 ms | 4.76 ms | 5.22 ms | 1.06 MB |
229+
| **jason** [map() :: binary()] | 127.9 | 7.82 ms | 7.84 ms | 8.43 ms | 4.96 MB |
230230

231231
### Parse (1.2 KB OpenRTB)
232232

233233
| Library | ips | mean | median | p99 |
234234
|---|---|---|---|---|
235-
| **torque** parse(unique_keys) | **572.6K** | **1.75 μs** | 1.46 μs | **4.83 μs** |
236-
| **torque** parse | 510.3K | 1.96 μs | 1.46 μs | 6.29 μs |
237-
| **simdjsone** parse | 304.0K | 3.29 μs | **1.21 μs** | 5.33 μs |
235+
| **torque** parse(unique_keys) | **542.0K** | **1.84 μs** | 1.46 μs | **5.63 μs** |
236+
| **torque** parse | 522.8K | 1.91 μs | 1.46 μs | 6.00 μs |
237+
| **simdjsone** parse | 306.3K | 3.27 μs | **1.21 μs** | 5.83 μs |
238238

239239
### Extract 5 fields from raw JSON (1.2 KB OpenRTB)
240240

@@ -245,11 +245,11 @@ selective extraction skips materializing the whole document.
245245

246246
| Library | ips | mean | median | p99 |
247247
|---|---|---|---|---|
248-
| **torque** parse + get_many | **476.1K** | **2.10 μs** | 1.75 μs | **4.75 μs** |
249-
| **torque** parse + get x5 | 434.6K | 2.30 μs | 1.92 μs | 5.96 μs |
250-
| **torque** parse(unique_keys) + get_many | 417.8K | 2.39 μs | 1.75 μs | 8.08 μs |
251-
| **simdjsone** parse + get x5 | 415.8K | 2.41 μs | **1.67 μs** | 6.50 μs |
252-
| **glazer** decode + find x5 | 317.7K | 3.15 μs | 2.79 μs | 8.54 μs |
248+
| **torque** parse + get_many | **436.6K** | **2.29 μs** | **1.79 μs** | **6.21 μs** |
249+
| **torque** parse(unique_keys) + get_many | 429.5K | 2.33 μs | **1.79 μs** | 6.67 μs |
250+
| **torque** parse + get x5 | 409.8K | 2.44 μs | 2.00 μs | 6.67 μs |
251+
| **simdjsone** parse + get x5 | 374.9K | 2.67 μs | **1.79 μs** | 7.21 μs |
252+
| **glazer** decode + find x5 | 344.9K | 2.90 μs | 2.75 μs | 6.71 μs |
253253

254254
Run benchmarks locally:
255255

bench/glazer_pgo_workload.exs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# PGO training workload for the glazer NIF.
2+
#
3+
# Mirror of bench/pgo_workload.exs but driving glazer instead of torque, so a
4+
# glazer PGO build (deps/glazer c_src Makefile PGO=generate/use) collects
5+
# branch/call-frequency data over the same representative payloads the README
6+
# benchmark uses — keeping the glazer-vs-torque comparison apples-to-apples
7+
# (both libraries profiled against equivalent decode/encode/find workloads).
8+
#
9+
# Run with an instrumented glazer.so loaded: MIX_ENV=bench mix run this file.
10+
11+
small_json =
12+
~s({"id":"req-0001","site":{"domain":"example.com","page":"https://example.com/articles/x","cat":["IAB1","IAB2-3"],"publisher":{"id":"pub-12345"}},"device":{"devicetype":2,"ua":"Mozilla/5.0 Macintosh; Intel Mac OS X 10_15_7 Chrome/120.0.0.0","ip":"203.0.113.42","geo":{"country":"US","lat":40.7128,"lon":-74.006,"zip":"10001"},"connectiontype":2},"user":{"id":"u-abcdef","name":"cafe resume"},"imp":[{"id":"imp-1","banner":{"w":300,"h":250},"bidfloor":0.5},{"id":"imp-2","video":{"mimes":["video/mp4"],"maxduration":30},"bidfloor":2.0}],"regs":{"coppa":0},"ext":null,"test":true})
13+
14+
record = fn i ->
15+
~s({"metadata":{"result_type":"recent","iso_language_code":"en"},"id":#{505_874_924_000_000_000 + i},"id_str":"#{505_874_924_000_000_000 + i}","text":"Sample tweet #{i} lorem ipsum dolor sit amet consectetur adipiscing elit","truncated":false,"in_reply_to_status_id":null,"user":{"id":#{1_000_000 + i},"screen_name":"username_#{i}","location":"San Francisco, CA","url":null,"followers_count":#{rem(i * 1337, 100_000)},"verified":false,"lang":"en","profile_image_url":"http://pbs.twimg.com/profile_images/#{i}/photo.jpeg"},"geo":null,"retweet_count":#{rem(i * 3, 1000)},"favorite_count":#{rem(i * 7, 2000)},"entities":{"hashtags":[{"text":"elixir","indices":[15,22]}],"urls":[],"user_mentions":[{"screen_name":"user_#{i}","id":#{2_000_000 + i}}]},"favorited":false,"lang":"en"})
16+
end
17+
18+
large_json =
19+
~s({"statuses":[) <>
20+
Enum.map_join(1..200, ",", record) <>
21+
~s(],"search_metadata":{"count":200,"completed_in":0.035,"max_id":505874924095815681,"query":"%23elixir"}})
22+
23+
small_term = :glazer_json.decode(small_json)
24+
large_term = :glazer_json.decode(large_json)
25+
26+
paths =
27+
Enum.map(
28+
[
29+
".id",
30+
".site.domain",
31+
".site.page",
32+
".device.ip",
33+
".device.geo.country",
34+
".user.id",
35+
".regs.coppa"
36+
],
37+
&:glazer.compile_path/1
38+
)
39+
40+
IO.puts("glazer PGO workload: small=#{byte_size(small_json)}B large=#{byte_size(large_json)}B")
41+
42+
decode = fn ->
43+
:glazer_json.decode(small_json)
44+
:glazer_json.decode(large_json)
45+
end
46+
47+
encode = fn ->
48+
:glazer_json.encode(small_term)
49+
:glazer_json.encode(large_term)
50+
end
51+
52+
find = fn ->
53+
d = :glazer_json.decode(small_json)
54+
Enum.each(paths, &:glazer.find(d, &1))
55+
end
56+
57+
Enum.each(1..5_000, fn _ -> decode.() end)
58+
Enum.each(1..5_000, fn _ -> encode.() end)
59+
Enum.each(1..10_000, fn _ -> find.() end)
60+
61+
IO.puts("glazer PGO workload complete")

mix.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"earmark_parser": {:hex, :earmark_parser, "1.4.44", "f20830dd6b5c77afe2b063777ddbbff09f9759396500cdbe7523efd58d7a339c", [:mix], [], "hexpm", "4778ac752b4701a5599215f7030989c989ffdc4f6df457c5f36938cc2d2a2750"},
77
"erlex": {:hex, :erlex, "0.2.9", "7debbbaa9f4f368b8cd648983e0f1d7963028508e9c59e9d4ed504e94ef52a55", [:mix], [], "hexpm", "8cfffc0ec7159e6d73de2ab28a588064de80f88b2798d5cbe4482cbbc200178b"},
88
"ex_doc": {:hex, :ex_doc, "0.40.3", "4a972ffe64bc07dc605af487e98fc19b72a4185f55ca031b94c0552d6071c1d9", [:mix], [{:earmark_parser, "~> 1.4.44", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "2756e357742fecd9749b489b85d67c9ce99c465f2e75728d9e6dc8d704b973de"},
9-
"glazer": {:hex, :glazer, "0.5.7", "ebf8dfc855d905110b84fd0e62f3fac28bfbf39152c09205974a141363644c79", [:rebar3], [], "hexpm", "fa78ffe5fd162a50a61bba21489aa78c148dbe07289a3765e21edc7ab7c3209a"},
9+
"glazer": {:hex, :glazer, "0.5.11", "c6f4bf32c3da539351d4e3811484ffe0ba341a871dc2ce47ddb5284c78f5166f", [:rebar3], [], "hexpm", "f5abec34de2f4cec226632f0db25567d4c6ffc0fd2e7ed5d285df81afb5582f8"},
1010
"jason": {:hex, :jason, "1.4.5", "2e3a008590b0b8d7388c20293e9dcc9cf3e5d642fd2a114e4cbbb52e595d940a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "b0c823996102bcd0239b3c2444eb00409b72f6a140c1950bc8b457d836b30684"},
1111
"jiffy": {:hex, :jiffy, "2.0.0", "1d7605ee31c4fd9b454725d744716b59e2abd88297862c8931b605c83b076480", [:rebar3], [], "hexpm", "73f58877ccaae14e14601c95928e2913fd1c1ef28e6ef4f274a8d62819f9e04f"},
1212
"makeup": {:hex, :makeup, "1.2.1", "e90ac1c65589ef354378def3ba19d401e739ee7ee06fb47f94c687016e3713d1", [:mix], [{:nimble_parsec, "~> 1.4", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "d36484867b0bae0fea568d10131197a4c2e47056a6fbe84922bf6ba71c8d17ce"},

0 commit comments

Comments
 (0)