OpenJet Engine reaches 78.0 tokens per second in reasoning mode and 106.7 tokens per second across four greedy prompts in the project's published RTX 3090 measurements. Against llama.cpp with MTP speculative decoding enabled, that is 1.53× and 1.69× respectively. The Python code prompt reaches 139.7 tok/s, but the four-prompt mean is the more representative greedy headline.
This post explains what was measured, how the scripts calculate their results, and how to run the comparison yourself. It reports the project's existing measurements; these benchmarks were not rerun for this article. Sources are pinned to OpenJet revision 8f29aff, reviewed on 13 October 2026. This is the documentation revision, not a claim that every published run used that exact commit.
The test setup
The engine README reports back-to-back runs on an otherwise idle NVIDIA RTX 3090 with Qwen3.8-27B Q4_K_M. These are single-conversation measurements. The mixed-quant UD-Q4_K_XL engine is outside this comparison.
| Setting | llama.cpp | OpenJet Engine |
|---|---|---|
| Model | Same Qwen3.8-27B Q4_K_M GGUF | Same Qwen3.8-27B Q4_K_M GGUF |
| Accelerator | RTX 3090; GPU layers set to 99 | RTX 3090; specialized CUDA engine |
| Speculation | MTP, at most 2 drafts | MTP, 3 or 4 drafts; headline results use 4 |
| Attention and KV | Flash attention on; q8_0 keys and values | Default fp16 KV for these short-context speed runs |
| Context capacity in scripts | 16,384 reasoning; 34,000 code workload | 16,384 reasoning; 34,000 code workload |
| Concurrency | One server slot | One sequence |
llama-server runs with --spec-type draft-mtp --spec-draft-n-max 2 --flash-attn on -ctk q8_0 -ctv q8_0 -ngl 99 --parallel 1. OpenJet uses the bundled draft_vocab_32k.bin. Draft depth and KV format differ between the tested configurations; this is a comparison of the project's runtime settings. The README reports that using q8_0 KV instead of fp16 slows OpenJet decode by roughly 1–2% and prefill by 2–7%.
Decode throughput measures output token generation. Prompt throughput, or prefill, measures processing the input. Neither is total request latency: loading the model, processing the prompt and transporting the response are separate costs. The scripts read the server's reported timings or the engine CLI's timing output, rather than dividing output tokens by the entire HTTP request duration.
Reasoning: the everyday coding preset
The thinking benchmark uses thinking enabled with xhigh effort, temperature 1.0, top_p 0.95, top_k 20 and min_p 0. It runs five coding prompts with two seeds, 1000 and 1001, requesting up to 1,024 generated tokens per run.
The tasks cover merging intervals with pytest tests, finding the largest files with Bash, implementing a C ring buffer, explaining mutexes and semaphores, and finding a fragile spot in a pasted CUDA file. The last prompt includes the first 8,000 characters of prefill.cuh. The script renders the same system and user prompt for both engines, including the thinking prefix.
| Measurement | llama.cpp (tok/s) | OpenJet Engine (tok/s) | Speedup |
|---|---|---|---|
| HTTP chat completions, as reported in the README | 50.9 | 78.0 | 1.53× |
| Script comparison, OpenJet CLI with 4 drafts | 50.7 | 77.4 | 1.53× |
The script averages each prompt's throughput over its seeds, then calculates the overall rate as total generated tokens / total decode time. This avoids giving a short response the same weight as a long response. It also prints draft acceptance and tokens per speculative cycle.
The HTTP headline comes from the README's /v1/chat/completions measurements. The checked-in think_bench.py instead calls llama-server's /completion endpoint and compares it with the OpenJet CLI. It reproduces the second row's setup, rather than providing an automated reproduction of the two-server HTTP test.
Greedy decoding: speed depends on the prompt
The code benchmark uses the four prompts in prompts.txt, with thinking disabled and greedy sampling. Each short prompt requests 512 generated tokens. The default is two repetitions, retaining the fastest decode rate for each prompt and engine, then taking the arithmetic mean of those four rates.
| Prompt | llama.cpp (tok/s) | OpenJet, 3 drafts (tok/s) | OpenJet, 4 drafts (tok/s) |
|---|---|---|---|
| Python function | 72.5 | 126.3 | 139.7 |
| Hash map explanation | 64.1 | 107.4 | 106.5 |
| Short story | 52.8 | 66.8 | 70.7 |
| Flask to FastAPI plan | 63.2 | 102.6 | 109.8 |
| Four-prompt mean | 63.1 | 100.8 | 106.7 |
Four drafts deliver 1.93× the baseline on the Python prompt and 1.69× on the mean. They do not win on every prompt: the hash map explanation is slightly faster with three. Predictable continuations allow more drafts to be accepted, so a code-generation maximum should not be presented as a universal rate.
Without speculation, the README reports 40.4 tok/s for llama.cpp and 42.9 tok/s for OpenJet with -d 0. The main benefit comes from speculative verification: OpenJet verifies the current token plus drafts in a persistent CUDA cycle while reusing weight reads. Its 32,768-token draft vocabulary reduces drafting work; verification still uses the full vocabulary.
Longer prompts and conversation reuse
For the context sweep, code_bench.py concatenates repository CUDA source files, truncates them using an approximate characters-per-token ratio, and appends a C++ unit-test task. The measured token counts therefore differ from the requested sizes. It requests 256 generated tokens and records prompt processing and decode separately. The script retains the best prompt and decode rates independently, so a row need not describe one particular run.
| Measured context | llama.cpp decode (tok/s) | OpenJet decode (tok/s) | llama.cpp prefill (tok/s) | OpenJet prefill (tok/s) |
|---|---|---|---|---|
| 1.8K | 57.4 | 84.8 | 1050 | 1595 |
| 3.6K | 56.3 | 95.3 | 1124 | 1595 |
| 7.8K | 54.8 | 85.8 | 1140 | 1533 |
| 15.9K | 55.7 | 86.5 | 1126 | 1466 |
| 29.5K | 52.3 | 72.7 | 1062 | 1236 |
These are the README's published context results. It notes that they predate sequence-token additions to the draft vocabulary and double-buffered attention, which subsequently added 1–8% to OpenJet decode in this workload. The table preserves the measured figures without applying a projected uplift. The condensed README table does not label a draft depth for this sweep; the script prints both three- and four-draft results.
The second-turn test first asks for a C string-reversal function, then appends a source file and asks what its first kernel does. llama.cpp reuses its prompt cache; OpenJet appends with batched prefill. The default script selects the lowest prompt processing time over two repetitions.
| New tokens in the second turn | llama.cpp prompt cache | OpenJet batched append |
|---|---|---|
| 2.7K | 2.41 s | 1.68 s |
| 12K | 10.45 s | 8.10 s |
These times cover processing the new prompt, not the complete second response. They show why prefill and conversation reuse matter when a coding agent pastes a file or receives a large tool result.
Correctness alongside speed
Different arithmetic ordering and rounding can change the winning token when probabilities are close. A generated answer can then diverge even when the next-token distributions are very similar. The project therefore also compares teacher-forced distributions against llama.cpp generating one token at a time with a q8_0 KV cache, using the same GGUF.
The short-context evaluation scores 13,299 positions of repository code and prose after 1,024-token prompts. The reference perplexity is 2.4263. Lower KL divergence indicates distributions closer to the reference.
| Configuration compared with the reference | Top-token agreement | Mean KL (nats) | Perplexity |
|---|---|---|---|
| llama.cpp, batched | 98.68% | 0.0019 | 2.4283 |
| llama.cpp, fp16 KV | 99.17% | 0.0007 | 2.4284 |
| OpenJet, prefill then decode, q8_0 KV | 99.08% | 0.0009 | 2.4274 |
| OpenJet, prefill then decode, fp16 KV | 99.11% | 0.0008 | 2.4273 |
| OpenJet, prefill only, q8_0 KV | 99.01% | 0.0009 | 2.4275 |
At 30K context, OpenJet with q8_0 KV reports 99.65% agreement and KL 0.0007; at 96K, 99.60% and 0.0008. Each long-context test scores 1,999 positions from a single repository-code sequence. These checks support numerical similarity for the tested inputs; they are not a coding-quality evaluation or proof of identical output on every task.
The reference tool stores the 256 most likely tokens per scored position. The README also reports a 2,000-sample test per position for speculative sampling. Greedy verification follows the main model's choice, and sampled verification preserves its distribution; changing the verification batch size can still change floating-point rounding on near-ties.
Run the benchmarks yourself
Follow the engine installation guide for Linux, CUDA and the llama.cpp build. The documented setup uses llama.cpp tag b10246; the published results do not supply a separate exact llama.cpp commit for every run. Place the supported original GGUF at models/Qwen3.8-27B-Q4_K_M.gguf in the repository checkout. From the repository root:
cd megakernel
make
# Reasoning: five prompts, two seeds, up to 1024 tokens.
# Runs llama.cpp, then OpenJet with three and four drafts.
python3 bench/think_bench.py --seeds 2 -n 1024
# Greedy prompts, context sweep and second-turn processing.
python3 bench/code_bench.py --reps 2 -n 256 \
--ctx-sizes 0,2000,4000,8000,16000,30000
# Separate decode baseline with speculation disabled.
python3 bench/bench.py llama --spec 0 -n 512
python3 bench/bench.py mk --draft 0 -n 512At the linked revision, think_bench.py hardcodes the original model path and executable; it has no --model or --mk-bin options. code_bench.py and bench.py do accept those options. Keep the working directory and model path consistent with the commands above. The scripts launch llama-server themselves; run them sequentially with the GPU otherwise idle.
For the distribution comparison, supply local code and prose text files and run:
make tools/llama_ref
tools/llama_ref -m ../models/Qwen3.8-27B-Q4_K_M.gguf \
-f /absolute/path/code.txt -f /absolute/path/prose.txt \
--score-from 1024 -b 1 --ref-out llama.ref
tools/llama_ref -m ../models/Qwen3.8-27B-Q4_K_M.gguf --kld llama.ref
./qwen38_mk -m ../models/Qwen3.8-27B-Q4_K_M.gguf \
--kld llama.ref --score-path mixed --kv q8mixed uses batched prefill for the unscored prompt and the decode kernel for the scored continuation. The corpus and its exact contents affect the result; using your own files reproduces the procedure, not necessarily the published numbers.
What the results establish
For this RTX 3090, model and configuration, the published results show higher decode and prefill throughput with OpenJet Engine, including a 1.53× reasoning improvement with speculative decoding enabled on both sides. The greedy mean, the best individual prompt and the reasoning aggregate measure different workloads and use different aggregation rules.
The repository does not provide a complete run manifest covering GPU clocks, power limits, driver version, model checksum, exact benchmark dates and every engine revision. It also does not publish confidence intervals for the speed tables. Best-of-two greedy results describe favorable observed throughput. Other GPUs, quantizations, concurrent requests and end-to-end agent tasks need their own measurements.
Read the pinned results and correctness notes, inspect the benchmark scripts, or continue to the engine documentation and OpenJet vs llama.cpp comparison.