The reference implementation takes 31.5 times longer than a strong submission on the same task and the same machine.
//01the 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
//02A 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
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
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
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
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
Node ids are dense and 0-indexed. Weights are uint32. The graph is directed; a reverse edge, where one exists, is listed separately.
E
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.
//03what 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.
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
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
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
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.
//04how 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.
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.
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.
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.
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.
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.
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
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.
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.00
T
×3.9723.972
M
×1.6956.734
S
×0.9246.220
D
×1.0006.220
X
×1.0066.257
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% machine35% 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
//05before 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.
FAIL
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.
FAIL
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.
FAIL
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.
FAIL
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.
//06we 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.
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
Read from /data
Mounted read-only. The filenames are fixed by the track spec. Do not assume any path outside it exists.
2
Write to /out
Exactly one output file, named by the spec. Anything else you leave behind gets flagged by the filesystem diff.
3
Exit 0
Any non-zero exit is a failed run. Handle your own errors; the harness will not interpret them for you.
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.
//07the 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.
//08pre, during, after
Timeline
All times UTC. The hack runs across Halloween weekend, which is not an accident.
pre, during, after11 beats
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.
//09six ways to win
Prizes
$2,000 total.
$800
Speed Demon
Highest geometric mean across three or more tracks. Fast everywhere, not fast once.
$400
Runner-up
Second on the overall board. Same bar, narrower margin.
$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.
$200
Third place
Third on the overall board.
$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.
$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
//10ten of them
Rules
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.
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.
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.
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.
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.
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.
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.
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.
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
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.
//11find 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
A
B
C
D
E
Systems engineersCache lines, branch prediction, allocator behaviour. The tracks where memory layout beats cleverness.
Data engineersYou have parsed worse CSVs than ours at work, and you have opinions about how the pipeline should have been written.
Search and database folkPosting lists, skip pointers, join strategies. Track B is the one you have been mentally designing for years.
Algorithms peopleCompetitive programming background, and finally a contest where the constant factor counts as much as the complexity class.
Compression and codec nerdsEntropy coding, context modelling, and a track that scores the exact tradeoff you have always had to explain to people.
Anyone with something to proveFive tracks, one reference implementation, and a public number at the end of it. No pitch, no slides, no interpretation.
//12who 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 ◆ Apple ◆ Microsoft ◆ Amazon Web Services ◆ Meta ◆ SpaceX ◆ Oracle ◆ Uber ◆ IBM ◆
Apple, Microsoft, Amazon Web Services, Meta, SpaceX, Oracle, Uber, IBM.
The full named panel for this event is announced when registration opens in October.
//13the short answers
FAQ
01Do 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.
02My 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.
03Can 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.
04What 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.
05Won'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.
06What 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.
07What 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.
08Can 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.
09How 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.
10Why 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.
11Why 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.
12Is 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.
13Where 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.
14Can 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.
15What 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.
We hand you a task, a dataset, and a program that already solves it — correctly, and slowly, on purpose.
You write it again. Faster. Any language.
We run both on our machine, not yours, and compare. That is the whole event.
the same job, twice
the reference
41.20 s
2,940 MB
a strong submission
1.31 s
210 MB
31.5× the wall time, 14.0× the memory, identical output
Everything else on this page is the detail behind these sentences.
You pick a track. There are five. Enter one, or enter all of them.
Each track gives you three things: a task specification, a dataset, and a reference implementation that is correct and deliberately slow.
You solve it again — any language, any approach — and ship it with a Dockerfile.
We build that Dockerfile and run it ourselves, on one machine in Helsinki, 5 times, cores pinned and turbo off. Your laptop's numbers are for your own iteration. Ours are the ones on the board.
what happens to your code
you
01
Pick a track
Spec, dataset, and a slow reference
you
02
Write it faster
Any language, any approach
you
03
Ship a Dockerfile
So it builds the same way for us
us
04
We build and run
5 runs, cores pinned, turbo off
us
05
4 gates
Correctness · The speed floor · The timeout · The sandbox
us
06
One coefficient
65% of your track total
Nothing you measure on your own machine is used. We re-run everything.
Your output has to hash identical to the reference, byte for byte. Four gates decide whether you get a score at all.
If you pass, you get one number: how much faster and leaner you were than the reference. That is 65% of your score. Human judges read your code for the other 35%.
how a track total is built
65%
measured by machine
35%
read by people
A submission nobody can read is not an engineering achievement — which is what the other 35% is for.
Win a track by having the best total on it. Win the championship by being fast across three or more.
Everything else on this page is the detail behind these sentences.
You pick a track. There are five. Enter one, or enter all of them.
Each track gives you three things: a task specification, a dataset, and a reference implementation that is correct and deliberately slow. The reference is published before kickoff and it does not change.
You solve it again. Any language, any approach, any trick you can defend — and you ship it with a Dockerfile, so it builds the same way for us as it does for you.
what happens to your code
you
01
Pick a track
Spec, dataset, and a slow reference
you
02
Write it faster
Any language, any approach
you
03
Ship a Dockerfile
So it builds the same way for us
us
04
We build and run
5 runs, cores pinned, turbo off
us
05
4 gates
Correctness · The speed floor · The timeout · The sandbox
us
06
One coefficient
65% of your track total
Nothing you measure on your own machine is used. We re-run everything.
We build that Dockerfile and run it ourselves, on one machine in Helsinki: 5 runs, cores pinned, turbo off, one submission at a time so nothing competes for cache. Highest and lowest are discarded. Self-reported timings are never accepted.
Before anything is measured, four gates run. Your output has to hash identical to the reference, byte for byte. Fail a gate and you score zero on that track — and we publish which gate you failed.
before anything is measured
1
Correctness
SHA-256 of your output file must match the expected hash exactly
2
The speed floor
within 10× of the fastest correct submission in that track
3
The timeout
hard kill at 10× the reference implementation's time on that track
4
The sandbox
no network · dataset read-only · root filesystem read-only
Fail one and you score zero on that track — and we publish which one you failed.
If you pass, we measure five things: wall time, peak memory, source size, dependency weight and scaling. Each becomes a ratio against the reference, and the ratios multiply into one number — the efficiency coefficient.
Wall time carries the most weight, because this is a performance event. Every axis is capped at 50× so one lucky dimension cannot carry a submission.
the five things we measure
T
wall time
0.40
M
peak memory
0.20
S
source size
0.15
D
dependency weight
0.15
X
scaling
0.10
Each is a ratio against the reference, capped at 50× so one lucky dimension cannot carry a submission.
Because the reference is fixed, your number never moves when somebody else submits. The board reorders around you. Your score does not.
The coefficient is 65% of your track total. Judges read your code and your write-up for the other 35%, on structured forms, without seeing the measured board first.
how a track total is built
65%
measured by machine
35%
read by people
A submission nobody can read is not an engineering achievement — which is what the other 35% is for.
During the 72 hours you can push and get an automated run against the sample dataset, once every 15 minutes. Final scoring runs on a holdout dataset after code freeze. The gap between your sample position and your final one is the price of overfitting.
two boards, one that counts
during the 72 hours
The sample board
Push to a submission branch
Automated run on the sample dataset
One run per team per 15 minutes
Public, so you can watch the field move
practice
after code freeze
The scoring run
Whatever is at your recorded commit
Run on the holdout dataset
Five runs, highest and lowest discarded
Per-axis breakdown published for everyone
this is your score
The gap between your sample position and your final one is the price of overfitting.
Afterwards we publish every team's per-axis breakdown and the scoring dataset, so anyone can reproduce the board.
Win a track by having the best total on it. Win the championship on the geometric mean of three or more tracks — fast everywhere, not fast once.
Everything else on this page is the detail behind these sentences.