Skip to content
Speed Demon

41,200 souls, one per millisecond of the reference implementation / 41200

Speed Demon

Every millisecond is a soul.

Same task, same data, same machine. We run your code ourselves and rank what comes back.

72-hour performance championship · Halloween weekend

track A · ingest · 3.1M log lines · 312 MB

hel1 · i5-13500 · 12 threads · 8 GB cap

reference implementation

41.20 s · 2,940 MB

souls 41,200 souls

what a serious submission looks like

1.31 s · 210 MB

souls 1,310 souls

sha256 · identical output

31.5× faster · 14.0× leaner · efficiency coefficient K = 6.26

The reference implementation takes 31.5 times longer than a strong submission on the same task and the same machine.

01 the premise

You can't argue with a stopwatch

Most hackathons ask a panel whether they liked your idea. This one starts by measuring whether your code is fast, and only then asks whether it's any good.

Every track hands you the same three things: a task specification, a dataset, and a deliberately naive reference implementation that solves the task correctly and slowly. Your job is to solve it again — correctly and not slowly. Any language. Any approach. The output has to hash identical to the reference, byte for byte, or you don't get a score at all.

Then we run it. Not you. Every submission is built from your Dockerfile and executed on one dedicated machine in Helsinki, pinned to the same cores, capped at the same memory, five runs each, serialized so nothing competes for cache. Your laptop's numbers are for your own iteration. Ours are the ones on the board.

What comes out is an efficiency coefficient — a single number that folds wall time, peak memory, source size, dependency weight and scaling behaviour into one ranking. It is published in full below, with a worked example, before you write a line. That coefficient decides 65% of your score. Human judges decide the rest, because a submission nobody can read is not an engineering achievement.

There is a particular kind of engineer this event is built for: the one who has spent a week making something 40% faster and then had to explain to a room why that mattered. Here it doesn't need explaining. It's the score.

the shape of it

  • task specgiven
  • datasetgiven
  • naive referencegiven
  • a faster oneyours

65%

of your score is measured by machine

on a formula published before kickoff

5

runs per submission

highest and lowest discarded, mean of the middle three

1

machine runs every submission

cores pinned, turbo off, serialized

0

self-reported timings accepted

ever

02 A through E

Five tracks

Each track is one fixed task against one fixed dataset. They stress different muscles on purpose — a parsing specialist and a graph specialist should not be optimising the same loop. Enter as many as you like; three is the minimum to be eligible for the overall title.

A · The parsing track

Ingest

Aggregate 3.1M structured log lines into per-endpoint request counts, p50/p95/p99 latency, and error rates bucketed by hour.

The parsing track, and the one most teams should start with.

The naive version reads lines, splits on delimiters, parses timestamps with a date library, and pushes latencies into a growing list per endpoint before sorting each one at the end. Every part of that is a target.

  • Custom line parsing beats any general-purpose reader, by a lot
  • Percentiles without sorting the whole thing
  • Where most teams discover their allocator
  • Timestamp parsing is usually the second-biggest cost and nobody expects it

312 MB records 3.1M lines reference 41.2 s timeout 412 s

live data preview

space-delimited, one request per line

field type note
ts RFC3339 microsecond precision, monotonic per shard but interleaved across shards
method enum 7 values
endpoint string 1,842 distinct, heavy Zipf tail
status uint16 5xx counts toward the error rate
latency_us uint32 microseconds, not milliseconds

sample rows

ts method endpoint status latency_us
2026-10-30T18:00:00.114982Z GET /v2/orders/{id} 200 1841
2026-10-30T18:00:00.115330Z POST /v2/checkout 503 204117
2026-10-30T18:00:00.115332Z GET /health 200 62

Three consecutive lines from the sample set, unmodified.

B · The trade-off track

Index

Build an inverted index over a 250 MB text corpus, then answer 50,000 boolean and phrase queries.

Build time and query time are measured separately and combined into a single T for scoring, weighted 40/60 toward queries.

Two phases means two optimisation problems that pull against each other: an index that builds fast is rarely one that queries fast. Choosing where to spend is the whole track.

  • Posting-list compression actually pays at this corpus size
  • Intersection order is most of the win on boolean queries
  • Phrase queries need positions, and positions are where your memory goes
  • The build/query split is published in the spec so you can plan the trade

250 MB records 50,000 queries reference 58.7 s timeout 587 s

live data preview

queries.txt — one query per line, prefixed by its kind

field type note
BOOL 62% of queries operators are left-associative, no parentheses
PHRASE "..." 38% of queries adjacent tokens, exact order, stopwords retained

sample bytes

BOOL indemnity AND (nothing) NOT surety
PHRASE "writ of habeas corpus"
BOOL bail OR bond OR recognizance NOT forfeiture
PHRASE "in the matter of"

Boolean queries use AND / OR / NOT. Phrase queries are quoted and must respect token positions.

C · The correctness track

Join

Parse a hostile multi-megabyte CSV — quoted commas, escaped quotes, embedded newlines, mixed line endings, a UTF-8 BOM on some chunks and not others — join it against a lookup table, emit sorted aggregates.

The fast path here is easy and the edge cases are the actual task.

This is the track where the most submissions will fail the hash gate, and we are telling you that in advance so you budget time for verification rather than discovering it at hour 68.

  • Hash join versus sort-merge, on data where the answer isn't obvious
  • Quoting rules are in the spec and they are not negotiable
  • A parser that's 3× faster and wrong scores zero
  • Most disqualifications will happen here

204 MB records hostile CSV reference 36.9 s timeout 369 s

live data preview

records.csv — bytes as they appear on disk

field type note
id,name,note,region_id,amount 5 columns column count is fixed; everything else about the encoding is not

sample bytes

⟨BOM⟩id,name,note,region_id,amount␍␊
1,"Kaphar, Titus","said ""no"" twice",7,1420.00␍␊
2,"Betts","a note that␊spans two lines",7,88.50␊
3,,"",12,0.00␍␊
4,"trailing space ","comma, quote "" and newline␊together",3,-5.25␊

Every hostile feature in the file is visible in these five lines. ␍␊ marks CRLF, ␊ marks a bare LF, and ⟨BOM⟩ marks a U+FEFF that appears mid-file at some chunk boundaries.

D · The algorithms track

Traverse

A 5M-edge directed weighted graph and 2,000 source-target shortest-path queries.

The one with the highest ceiling — the gap between a competent submission and an excellent one is wider here than anywhere else.

Preprocessing is explicitly allowed and counted inside your timed run, which makes the build-versus-query trade the central decision rather than a footnote.

  • Preprocessing is allowed and it is the whole game
  • Memory layout beats asymptotics at this size, consistently
  • Bidirectional search is table stakes, not a strategy
  • Contraction hierarchies are legal and expensive to get right in 72 hours

180 MB records 5M edges reference 72.4 s timeout 724 s

live data preview

graph.txt — header, then one edge per line: u v w

field type note
n m header node count, edge count
u v w uint32 ×3 tail, head, weight — not sorted by u

sample bytes

1740512 5000000
0 918442 37
918442 0 41
1 7 1200
1739998 62 9

Node ids are dense and 0-indexed. Weights are uint32. The graph is directed; a reverse edge, where one exists, is listed separately.

E · The trade-off is the subject

Compress

Lossless compression of a fixed 100 MB mixed corpus — text, logs, JSON, and a binary blob.

Scored on ratio and decompression throughput together, so you cannot win by being slow and small or fast and fat.

The only track where the speed/size tradeoff is the explicit subject rather than a side effect, and the only one where the coefficient itself changes shape: compressed size replaces peak memory in the M slot.

  • Round-trip must be bit-exact or the submission fails the gate
  • Compressed size replaces peak memory in the coefficient for this track
  • General-purpose compression libraries are banned; write the coder
  • Compression time is measured but weighted at a quarter of decompression time

100 MB records ratio 2.41× reference 29.8 s timeout 298 s

live data preview

corpus.bin — four concatenated segments, offsets fixed

field type note
segment name in file order
bytes uint64 exact, not rounded
content kind what it actually is
ref ratio float what the naive coder achieves on that segment alone

sample rows

segment bytes content ref ratio
prose 31,457,280 English text, UTF-8, long runs 2.94×
logs 27,262,976 the Track A line format, repeated fields 4.11×
json 23,068,672 nested records, high key repetition 3.32×
blob 23,068,672 float32 sensor frames, low entropy per column 1.18×

Segment boundaries are published. They are aligned to 1 MiB, and each segment rewards a different model.

03 what you get, and when

Nothing about the scoring is a surprise

You will not be handed a spec on the day. Everything that decides your score is published before kickoff and frozen. The only thing held back is bytes.

  1. LIVE

    on this page, now

    • schema and real sample rows for all five tracks
    • reference timings and dataset sizes
    • the exact docker build and docker run commands
    • the full efficiency coefficient with a worked example
  2. FROZEN

    Oct 28 · 18:00 UTC · T-48h

    • all five track specifications
    • reference implementations in Go, Python and Rust
    • the complete scoring harness, to run locally
    • nothing about the scoring changes after this moment
  3. SCHEDULED

    Oct 30 · 06:00 UTC · T-12h

    • 10% sample datasets
    • their expected output hashes, so you can verify locally
    • twelve hours is deliberate — enough to check, not enough to overfit to sample bytes
  4. KICKOFF

    Oct 30 · 18:00 UTC · T-0

    • full datasets released
    • the live leaderboard opens
    • clocks start

The final scoring dataset is generated from the same distribution at a seed you have never seen. You can tune. You cannot overfit to specific bytes.

04 how winners are decided

The efficiency coefficient

Raw speed is a blunt instrument. A submission that runs in 0.4 seconds by loading 40 GB into RAM, pulling in six libraries and sprawling across 4,000 lines has not beaten a 0.9-second solution that fits in 200 MB and reads cleanly. K is how we say that with arithmetic instead of opinion.

Everything is a ratio against the reference

Nothing is measured in absolute seconds, and nothing is normalised against the current leader. Every axis is your number divided into the reference implementation's number, on the same machine, in the same batch. A ratio of 1.0 means you matched the naive version. 10.0 means you beat it tenfold.

This matters more than it looks. Because the reference is fixed and published, your score never changes when somebody else submits. The leaderboard reorders around you. Your number does not move.

Every other design we considered — normalising to the field leader, percentile ranking, z-scores — has the property that a stranger's submission at hour 70 silently rewrites your result. That is intolerable in a competition where people are making trade decisions all weekend based on where they stand.

K = (Tref/T)0.40 × (Mref/M)0.20 × (Sref/S)0.15 × (Dref/D)0.15 × (Xref/X)0.10

T 0.40 + M 0.20 + S 0.15 + D 0.15 + X 0.10 = 1.00

Five factors, five exponents, and the exponents sum to exactly 1.0.

That last property is what keeps K readable: K = 6 means "six times the reference, all things considered," and nothing else. It is the weighted geometric mean of your five ratios, which is the correct way to combine normalised ratios — an arithmetic combination would let one axis with a wide natural spread dominate the others regardless of weight.

The exponents are also what stop any single axis from steamrolling the rest. A 100× memory win contributes 100^0.20 = 2.51 to the product. A 100× speed win contributes 100^0.40 = 6.31. The ordering of importance is enforced by the mathematics, not by a promise in the rules.

Five axes, five weights

Each card prints what a 100× win on that axis is actually worth to the product. That is the formula telling you where to spend the weekend — before kickoff, not after results.

T

wall time

weight

0.40

40% of the exponent budget

reference 41.20 s

Mean of the middle three of five runs, highest and lowest discarded. Timed by the harness from process exec to exit, not by any clock inside your program.

This is a performance event, so this is the biggest weight and it is not close.

what a win here buys

1.32
10×
2.51
100×
6.31

a 100× win here contributes 6.31 to the product

M

peak memory

weight

0.20

20% of the exponent budget

reference 2,940 MB

Peak resident set, read from the cgroup's memory.peak after the run terminates. Not self-reported, and not sampled — the kernel's high-water mark, which catches transient spikes your own instrumentation would miss.

Buying speed with unbounded RAM is a real strategy and it should cost you something. On Track E this slot is occupied by compressed size instead, since memory is not the resource under test there.

what a win here buys

1.15
10×
1.58
100×
2.51

a 100× win here contributes 2.51 to the product

S

source size

weight

0.15

15% of the exponent budget

reference 3,180 B

Bytes of source after running your language's canonical formatter, stripping comments, and normalising identifiers to fixed-width tokens.

The identifier step is why this axis is fair: renaming every variable to a single letter changes nothing about your score, so you can write readable code without paying for it. Expect a strong submission to be larger than the reference here. That is the trade, and it is priced rather than punished.

what a win here buys

1.11
10×
1.41
100×
2.00

a 100× win here contributes 2.00 to the product

D

dependency weight

weight

0.15

15% of the exponent budget

reference 1.00

D = 1 + (non-stdlib runtime dependencies) + (vendored source bytes ÷ 50,000). The reference uses none, so D_ref = 1 and every dependency is a straight cost.

Importing the crate that already solves half the task is permitted. It is simply not free, and this is where it gets billed. A zero-dependency submission starts this axis at 1.0 against everyone else's 2.0 or 3.0, which is worth roughly 10–17% on K before any other work.

what a win here buys

1.11
10×
1.41
100×
2.00

a 100× win here contributes 2.00 to the product

X

scaling

weight

0.10

10% of the exponent budget

reference 10.40×

Your runtime at 10× input divided by your runtime at 1×, compared against the reference's own ratio for the same pair. One extra run, no extra work from you.

It catches solutions that only win by holding everything in memory and would fall over on real data. Low weight because it is a sanity check, not a competition — you are not trying to win on X, you are trying not to lose on it.

what a win here buys

1.07
10×
1.26
100×
1.58

a 100× win here contributes 1.58 to the product

Every factor is capped at 50×

No ratio contributes more than 50 to the product, on any axis.

Without the cap, one pathological result on the cheapest axis — allocating 4 MB where the reference lazily allocates 3 GB, giving a 750× memory ratio — would produce a number that drowns out all the actual performance work in the field. The cap keeps the ranking about engineering rather than about finding the one dimension where the reference happened to be sloppiest.

In practice almost nobody will hit it on time. Several teams will hit it on memory.

raw memory ratio

750×

after the cap

50×

contribution at 0.20

2.19

K becomes points on a fixed curve

K is unbounded in principle, so it maps to a 0–100 speed score logarithmically, against an anchor published now and not adjusted afterwards. K = 25 or better earns full marks. K = 5 earns exactly half. Below K = 1 — slower and heavier than a naive implementation — earns nothing.

The curve is logarithmic because performance work is. Going from 1× to 2× is an afternoon. Going from 12× to 24× is the rest of the weekend and a rewrite. A linear scale would make the first hours worth as much as the last thirty, which is not how any of this works.

100 × ln(K) / ln(25)

clamped to [0, 100]

K = 25100 pts

K = 550 pts

K < 1nothing

0 25 50 75 100 1 2 3.5 5 8 12 18 25
K → · every point plotted from the scoring function itself
1.0 2.0 3.5 5.0 8.0 12.0 18.0 25.0+
speed score 0.0 21.5 38.9 50.0 64.6 77.2 89.8 100.0

Run your own numbers

Every ratio below is your number divided into the reference's. Change one and watch what it buys you. Loaded with Team Nightshade's run.

Efficiency coefficient calculator

^0.40 = 3.972

^0.20 = 1.695

^0.15 = 0.924

^0.15 = 1.000

^0.10 = 1.006

efficiency coefficient

K = 6.26

speed score · 100 × ln(K) / ln(25)

57.0 / 100

Worked example, start to finish

Team Nightshade, Track A. Every number that touches their score, in order. Nothing else feeds in.

axis reference Nightshade ratio exponent contribution
T · wall time 41.20 s 1.31 s 31.45× 0.40 3.972
M · peak memory 2,940 MB 210 MB 14.00× 0.20 1.695
S · source size 3,180 B 5,400 B 0.59× 0.15 0.924
D · dependency weight 1.00 1.00 1.00× 0.15 1.000
X · scaling 10.40 9.80 1.06× 0.10 1.006
K = product 6.26

how K assembles · running product

  1. 1.00
  2. T ×3.972
  3. M ×1.695
  4. S ×0.924
  5. D ×1.000
  6. X ×1.006

S is the only step that costs them — 70% over the reference on source size, paid for a 31× win on wall time. Final K = 6.26

K is computed from raw ratios. The table shows each factor rounded to two places; the product cell shows the raw-product K, not the product of the rounded factors. Those differ in the third decimal.

Note the third row. Nightshade wrote 70% more code than the reference and lost points for it — the optimised parser is genuinely longer than the naive one. They accepted that cost to buy a 31× speedup, which is exactly the trade the coefficient exists to price.

Note also the second row. 14× less memory sounds enormous and contributes 1.695 — less than half what the time ratio contributed. If they had spent those hours on the parser instead, they would have scored higher. That is the formula telling you where to work, and it tells you before kickoff rather than after results.

now the full score

final score raw weight points
Speed score — from K = 6.26 57.0 / 100 0.65 37.05
Judge score — panel average 82.0 / 100 0.35 28.70
Track A total 65.75

What the judges score

35% of every track total, on a 5-point scale across three criteria, averaged across every judge who reviewed the submission.

65% machine 35% judges

15%

Code quality

Would you merge this? Optimised code is allowed to be dense. It is not allowed to be unexplainable. Clear structure, honest error handling, and a comment wherever the trick is not self-evident. A judge should be able to follow why the fast version is fast.

12%

Technique

Is the approach genuinely considered, or brute force that happened to land? A well-chosen data layout scores above hand-written SIMD bolted onto the wrong algorithm. We are looking for evidence of decisions, not effort.

8%

The optimisation log

A required PERF.md narrating how you got there. "Naive was 41 s. Flat array instead of hashmap took it to 8 s. Manual line splitting got 2.1 s. Tried SIMD for the timestamp parse, made it slower, reverted." Measurements, not adjectives. The failed experiments count — they are often the most interesting part and judges are told to reward them.

Judges see your code and your write-up. They do not see the measured leaderboard until after they submit their forms. That order stops a fast number from colouring the read of the code, and it means the two parts of your score genuinely come from two independent places.

The overall championship

Per-track winners are decided on that track's total. The overall Speed Demon title requires at least three tracks completed and is decided on the geometric mean of your track totals — not the average.

This is deliberate and it is standard practice in benchmarking. The geometric mean refuses to let one spectacular track carry two mediocre ones. To win overall you have to be good everywhere, which is what "Speed Demon" is supposed to mean.

one spectacular track

90 / 40 / 40

52.4

good everywhere

60 / 60 / 60

60.0

geometric mean · three tracks minimum

05 before K is computed at all

Four gates

These are pass/fail. A submission that fails any of them scores zero on that track, regardless of how fast it ran. They are checked automatically, and they are checked on every one of the five runs.

1

Correctness

SHA-256 of your output file must match the expected hash exactly

Not "close enough", not "same values in a different order" — the spec pins the output format down to line ordering and float formatting precisely so this check can be binary. The 10% sample dataset ships with its expected hash so you can verify locally before you ever submit.

If your submission produces the right answer four times out of five, it fails. Nondeterminism is a correctness bug.

2

The speed floor

within 10× of the fastest correct submission in that track

Required for the overall title. Without this gate somebody eventually submits 200 elegant bytes that take four minutes and wins a performance competition on the source-size axis.

That would be funny exactly once.

3

The timeout

hard kill at 10× the reference implementation's time on that track

A container that hangs is a failed run, not a slow one. The exact ceiling is published per track alongside the reference, so you always know how much rope you have.

Track A: 412 s. Track D: 724 s.

4

The sandbox

no network · dataset read-only · root filesystem read-only

Scratch space is a 1 GB tmpfs at /tmp. We diff the container filesystem after every run.

Writing precomputed answers into the image, phoning home, or attempting to touch the dataset mount is disqualification from the event — not just the track.

06 we run it, not you

One machine, and you know its name

Machine variance between a desktop Ryzen and a fanless laptop is comfortably 5×, before you even reach thermal throttling and background processes. So participants never report a number. You submit a Dockerfile. We build it and run it.

The box

A Hetzner EX44 dedicated server in Helsinki (hel1). Dedicated, not shared — no noisy neighbours, no burst credits, no hypervisor surprises. It is the same physical machine for every submission across the entire event.

hel1

Hetzner EX44 · dedicated

CPU
Intel Core i5-13500 · 14 cores / 20 threads · 6 P-cores @ 4.80 GHz, 8 E-cores @ 3.50 GHz
Cache
544 KiB L1d · 704 KiB L1i · 11.5 MiB L2 · 24 MiB L3
Memory
64 GB DDR4-3200 (2 × 32 GB) · non-ECC
Storage
2 × 512 GB Micron 3500 NVMe · mdadm RAID1
Network
1 Gbit/s (disabled during scoring)
OS
Debian 13 (trixie)
Runtime
Docker · cgroups v2
Location
Helsinki, Finland

Two things we change before scoring starts

no_turbo=1

The CPU governor goes to performance and turbo is disabled

Turbo alone introduces 10–20% variance depending on how long the box has been idle, which is more than the gap between third and seventh place. Sustained clocks, deterministic results. You are optimising against a fixed 2.5 GHz base rather than a boost ceiling that depends on the weather.

--cpuset-cpus=0-11

Containers are pinned to the six P-cores only

This is a hybrid CPU. Mixing P-cores and E-cores in one run makes results depend on how the scheduler felt that second, and on Raptor Lake the P/E performance gap is large enough to swamp real optimisation work. So you get six physical performance cores, twelve hardware threads, and nothing else. Design your parallelism for exactly that. Spawning 20 workers will hurt you.

The exact command

This is not a paraphrase. This is the command, with only the team, commit and track substituted.

scoring harness · verbatim
# build, from your repo root, no network available
docker build --network=none -t speeddemon/$TEAM:$COMMIT .

# pre-warm the dataset into page cache so we measure your code, not the NVMe
vmtouch -t /srv/speeddemon/data/track-$TRACK

# the scored run — repeated 5x, serialized, nothing else running on the box
docker run --rm \
  --cpuset-cpus="0-11" \
  --cpuset-mems="0" \
  --memory=8g --memory-swap=8g \
  --pids-limit=512 \
  --network=none \
  --read-only \
  --tmpfs /tmp:rw,size=1g,exec \
  --ulimit nofile=8192:8192 \
  -v /srv/speeddemon/data/track-$TRACK:/data:ro \
  -v /srv/speeddemon/out/$RUN:/out:rw \
  -e TRACK=$TRACK \
  speeddemon/$TEAM:$COMMIT

# memory read from the cgroup, not from your process
cat /sys/fs/cgroup/<container>/memory.peak
--cpuset-cpus="0-11"
Twelve threads on six physical P-cores. Hard. Twenty workers will cost you more than they buy.
--memory=8g --memory-swap=8g
Equal values disable swap entirely rather than allowing an equal amount of it — the Docker behaviour people most often get wrong. There is 32 GB of swap on the host and none of it is available to you. Exceeding 8 GB is an OOM kill and a failed run, not a slow one.
--network=none
At build time and at run time. Vendor everything into the image.
--read-only + --tmpfs /tmp
Read-only root with 1 GB of scratch at /tmp if you need spill space.
-v ...:/data:ro
The dataset, mounted read-only. Filenames are fixed by the track spec.
memory.peak
The kernel's high-water mark, read after the run terminates. Not sampled, not self-reported — it catches transient spikes your own instrumentation would miss.

Your Dockerfile contract

Four rules. Nothing else about your image matters to us.

  1. 1

    Read from /data

    Mounted read-only. The filenames are fixed by the track spec. Do not assume any path outside it exists.

  2. 2

    Write to /out

    Exactly one output file, named by the spec. Anything else you leave behind gets flagged by the filesystem diff.

  3. 3

    Exit 0

    Any non-zero exit is a failed run. Handle your own errors; the harness will not interpret them for you.

  4. 4

    Build offline

    We build with --network=none. If your Dockerfile fetches anything — apt, cargo, pip, a curl — the build fails and so does your submission.

Dockerfile — the shape we expect
FROM debian:13-slim
COPY . /app
WORKDIR /app
RUN ./build.sh          # no network available here
ENTRYPOINT ["/app/run"] # reads /data, writes /out, exits 0

Base image choice is yours and is not scored. Build time is not scored either — only the run. If you want to spend six minutes on profile-guided optimisation at build time, that is free.

Timing protocol

5

runs per submission

2

discarded — highest and lowest

3

middle runs, meaned, become your T

5%

spread above this is re-run automatically

2%

reference drift that throws out a whole batch

We run the reference implementation before and after every scoring batch. If the reference drifts by more than 2% across a batch, that batch is thrown out and rescored. That calibration is what lets us say these numbers are comparable and mean it — and because your score is a ratio to the reference rather than an absolute time, mild drift partly cancels out anyway. Runs are strictly serialized. Nothing else executes on the box during scoring.

The live leaderboard

During the 72 hours you can push to a submission branch and get an automated run against the sample dataset, rate-limited to one run per team per 15 minutes. Those results go straight onto a public board so you can watch the field move and know whether your last change was worth it.

Final scoring runs on the holdout dataset after code freeze, and that is the only set that counts. The gap between your sample position and your final position is the price of overfitting.

07 the receipts

What you submit

Per track. A repo we can build without asking you a single question.

$ ls -la ./track-a

6 entries · 5 required

  • Dockerfile

    meets the four rules

    Builds offline from a clean checkout.

  • PERF.md

    worth 8% of your total

    The optimisation log. Every step from naive to final, with the measurement that justified it. The part judges enjoy most.

  • README.md

    prose

    The approach in plain prose, your dependency list if any, and what you would do with another 24 hours.

  • .speed-demon.toml

    machine-readable

    Track letter, team name, language, declared dependency count. So the harness can queue you without a human in the loop.

  • src/

    OSI licence, public at freeze

    Public GitHub repository. One directory per track you entered.

  • demo.mp4 optional

    under 3 min

    Optional and not scored, but the good ones end up in the results write-up and on the archive page.

08 pre, during, after

Timeline

All times UTC. The hack runs across Halloween weekend, which is not an accident.

Pre-event

01

October 2

Registration opens

Join the Discord. Start arguing about languages early.

Pre-event

02

October 26

Team formation closes

1–4 people per team. Solo entries welcome and historically competitive.

Pre-event

03

October 28 · 18:00 UTC

Specs, references and harness published

All five track specifications, reference implementations in Go, Python and Rust, and the complete scoring harness. Run it locally before kickoff. Nothing about the scoring changes after this date.

Pre-event

04

October 30 · 06:00 UTC

Sample datasets

10% samples with their expected hashes. Twelve hours before the gun.

The hack

05

October 30 · 18:00 UTC

Kickoff

Full datasets released. Live leaderboard opens. Clocks start.

The hack

06

October 31

Midnight, and nothing is haunted but the cache

Standings posted, plus a written teardown of every deliberately terrible decision in the reference implementation. No costumes, no call, no ceremony — you have a profiler open and we respect that.

The hack

07

November 2 · 18:00 UTC

Code freeze

Repositories locked at the recorded commit. Scoring queue begins.

Post-event

08

November 2–4

Scoring runs

Every submission built and run five times on the holdout dataset. Full per-axis breakdowns published for every team, including the ones that failed a gate and exactly which gate.

Post-event

09

November 3–12

Judging window

Each submission reviewed independently by multiple judges on structured forms. Written feedback to every team, not just the winners.

Post-event

10

November 10

Write-Up side quest closes

Deadline for the $300 write-up prize. Top three, $100 each.

Post-event

11

November 13

Winners announced

Per-track winners, the overall Speed Demon, side quest results, and the full scoring dataset published so anyone can reproduce the board.

09 six ways to win

Prizes

$2,000 total.

  1. $800

    Speed Demon

    Highest geometric mean across three or more tracks. Fast everywhere, not fast once.

  2. $400

    Runner-up

    Second on the overall board. Same bar, narrower margin.

  3. $300

    Write-Up side quest

    $100 × 3. Publish a post about your optimisation journey — the profiler reading you misread, the rewrite that made it slower, the two-line change that halved it. Tag Hackathon Raptors. Judged on insight, not audience size.

  4. $200

    Third place

    Third on the overall board.

  5. $200

    Highest K anywhere

    The single largest efficiency coefficient recorded in the event, on any track. Specialists welcome — you do not need three tracks for this one.

  6. $100

    The lean award

    Best K achieved with the smallest normalised source. For the submission that was fast because it was well designed, not because it was enormous.

total pool · $2,000

10 ten of them

Rules

  1. 01

    Any language

    If it builds in a Linux container offline and runs on x86-64, it is eligible. Assembly is eligible. Your own compiler is eligible. The coefficient does not care what you wrote it in, and neither do we.

  2. 02

    Dependencies are allowed and priced

    This is not a standard-library purity contest. Import what you want — the D axis charges you for it. What is banned, per track, is the library that solves the entire task: no general-purpose compression codec in Track E, no ready-made search engine in Track B, no analytics dataframe library in Tracks A or C. Those are listed explicitly in each track spec, by name.

  3. 03

    Correct output or no score

    SHA-256 must match. The specs pin down ordering and formatting so this is unambiguous. Verify locally against the sample before you submit.

  4. 04

    No precomputed answers

    The scoring dataset is generated at a seed you have never seen. Shipping cached results, or code that recognises the input and short-circuits, is disqualification from the event.

  5. 05

    New code only

    All project code written during the 72-hour window. Reading up on algorithms, sketching designs, and preparing your environment beforehand are all fine and expected. Code committed before kickoff disqualifies the submission.

  6. 06

    AI tools are expected

    Claude Code, Cursor, Codex, Copilot, local models — bring whatever you use. We do not gatekeep on how the code was produced. We gatekeep on whether it survives five runs on our hardware and whether PERF.md shows a human understood what was happening. Both are hard to fake, which is rather the point of measuring instead of judging.

  7. 07

    Team size 1–4

    Solo entries are welcome and have won this kind of event before. Find teammates on the Raptors Discord before or during.

  8. 08

    Source public at code freeze

    Public GitHub repo under an OSI-approved licence. Anonymous usernames are fine; the team must be reachable for written follow-up during judging.

  9. 09

    The harness is the referee

    Its numbers are final. If you believe a run was mis-measured you have 48 hours after publication to request a re-run, and we will do it. What we will not do is accept a timing from your machine as evidence.

  10. 10

    The formula does not change after kickoff

    Every weight, cap, anchor and gate on this page is frozen from October 28. If we find a flaw in the coefficient during the event, it gets documented publicly and fixed for the next edition. It does not get patched mid-competition.

11 find your track

Who this is for

If you have ever opened a flame graph at 1am out of curiosity rather than obligation, this is your hackathon.

Audience segments mapped to tracks
who you are ABCDE
Systems engineers Cache lines, branch prediction, allocator behaviour. The tracks where memory layout beats cleverness.
Data engineers You have parsed worse CSVs than ours at work, and you have opinions about how the pipeline should have been written.
Search and database folk Posting lists, skip pointers, join strategies. Track B is the one you have been mentally designing for years.
Algorithms people Competitive programming background, and finally a contest where the constant factor counts as much as the complexity class.
Compression and codec nerds Entropy coding, context modelling, and a track that scores the exact tradeoff you have always had to explain to people.
Anyone with something to prove Five tracks, one reference implementation, and a public number at the end of it. No pitch, no slides, no interpretation.

12 who reads your code

Judges

The 35% that is not measured is decided by senior engineers who have shipped and maintained performance-critical systems — database internals, distributed infrastructure, compilers and runtimes. People who have argued about a profiler reading in a real code review.

Judges review anonymised submissions on structured forms, independently, without seeing the measured leaderboard. That order matters: it stops a fast number from colouring the read of the code, and it means the two parts of your score genuinely come from two different places.

Interested in judging this one? Get in touch.

the split

35%

decided by people, on structured forms, without seeing the board

The Speed Demon panel is drawn from the Hackathon Raptors judging pool, which across recent events has included staff and principal engineers from:

Apple, Microsoft, Amazon Web Services, Meta, SpaceX, Oracle, Uber, IBM.

The full named panel for this event is announced when registration opens in October.

13 the short answers

FAQ

01 Do I have to enter all five tracks?
No. Enter one if you want. Per-track prizes and the highest-K prize are open to anyone. Only the overall championship requires three or more, because “Speed Demon” should mean broadly fast rather than narrowly lucky.
02 My laptop is much faster than an i5-13500. Does that hurt me?
Not at all — you never submit a timing. Build and tune wherever you like. Just be aware that optimisations tuned to your cache sizes may not transfer, and that you get twelve threads on six physical cores at fixed clocks. The harness ships on October 28 so you can run locally under the same limits.
03 Can I use a library that does most of the work?
Sometimes. Each track spec bans the specific class of library that trivialises that task — the compression codec, the search engine, the dataframe. Everything else is permitted, and the D axis charges you 15% weight for the privilege. A zero-dependency submission starts with a real advantage there.
04 What if my optimised code is longer than the reference?
It almost certainly will be, and that is priced into the formula rather than punished by it. In the worked example above, the winning approach was 70% larger and still scored K = 6.26. Source size is 15%, wall time is 40%. Spend lines where they buy you time.
05 Won't everyone just write it in C or Rust?
Many will. But K is a ratio against a reference implementing the same task, not against other teams' languages — and the memory, source and dependency axes are where a well-designed Go or Java submission takes points back from a sprawling C one. Assembly, incidentally, tends to lose badly on source size.
06 What exactly is the 10× scaling run?
After your scored runs we execute your container once more against a dataset ten times larger, with the same 8 GB cap. X is your time ratio between the two, compared to the reference's ratio. A solution that scales linearly gets roughly the same X as the reference and no penalty. A solution that holds everything in memory either scales badly or gets OOM-killed, and the 10% weight makes that visible without dominating your score.
07 What happens if my container gets OOM-killed?
That run fails. Fail the scored runs and you score zero on the track; fail only the 10× scaling run and you take the worst possible X ratio but keep the rest of your coefficient. Memory discipline is part of the event.
08 Can I submit multiple attempts?
Yes, against the sample dataset, once per 15 minutes per team, until code freeze. The final scoring run uses whatever is at your recorded commit at 18:00 UTC on November 2.
09 How is source size measured, exactly?
Canonical formatter for your language, comments stripped, identifiers normalised to fixed-width tokens, then bytes counted. The identifier normalisation is the important part: renaming your variables to single letters changes nothing, so write readable code. The exact measurement script ships with the harness on October 28.
10 Why the geometric mean for the overall title?
Because the arithmetic mean lets one enormous result carry a mediocre record. It is the standard choice for aggregating normalised benchmark ratios, for exactly this reason. A team scoring 90/40/40 should not beat a team scoring 60/60/60, and under the geometric mean it does not.
11 Why cap the axes at 50×?
Because the reference implementation is naive by design, and on some axes naive is very naive. Without a cap, the team that noticed the reference allocates 3 GB where 4 MB would do could post a memory ratio in the hundreds and win on a single observation. The cap makes that a strong result rather than a decisive one.
12 Is this just competitive programming?
No. There is no clever-trick puzzle to spot, and the algorithm is usually obvious within an hour. The difficulty is engineering — memory layout, I/O strategy, parallelism, and the discipline to measure before changing things. Competitive programmers do well here, but so do people who have spent years making production systems faster.
13 Where do the datasets come from?
Synthetic, generated from published generators that ship with the harness so you can produce as much extra training data as you want. The scoring set uses the same generators at an unpublished seed. Realistic distributions, no personal data, no licensing questions.
14 Can I use multiple threads?
Yes, up to the twelve you are given. Parallelism is a legitimate and expected strategy. Just remember that the memory cap is shared across all of them and that oversubscribing twelve threads with twenty workers costs you more than it buys.
15 What if two teams tie?
Ties on the final total are broken by raw K, then by wall time, then by earliest submission commit. In practice a tie to three decimal places has never happened.

72 hours. one number.

Every millisecond is a soul

Five tracks. One reference implementation to beat. One machine in Helsinki that does not care how good your idea sounded.

1.31s

what the board rewards