Snilld

Perplexity open-sourcer Rust-tokenizer med 5x lavere p50-latency

Perplexity AI lægger en ny Rust-implementering af Unigram-tokenization ud i deres pplx-garden-repo. Ifølge MarkTechPost rapporterer de op til ~5x lavere p50-latency end Hugging Face tokenizers ved produktionslængder samt markant lavere CPU-forbrug. Hvis tallene holder, flytter det på virkelige inference-pipelines – især rerankers og embeddings – hvor tokenization ofte er en skjult flaskehals.

28. maj 2026 Peter Munkholm

Tokenization er let at overse, indtil en produktionspipeline pludselig brænder CPU af. Perplexity AI hævder nu, at en ny Rust-implementering af Unigram-tokenizeren skærer p50-latency med cirka 5x i forhold til Hugging Face tokenizers ved reelle inputlængder. Hvis det holder, påvirker det direkte kapacitet, SLA’er og cloud-regninger.

Vi har set mønsteret før: små modeller, store batches – og CPU-siden bliver flaskehalsen. I et reranker-setup målte vi første gang, at GPU’en var færdig på få millisekunder, mens tokenizeren stadig kørte. Ikke sjovt, men lærerigt.

Hvad Perplexity faktisk har gjort

Ifølge en gennemgang hos MarkTechPost har Perplexity reimplementeret Unigram-tokenization i Rust og open-sourcet koden i deres pplx-garden-repo. Målmodellen i deres arbejde er XLM-RoBERTa med et Unigram-vokab på 250K trænet med SentencePiece. Det er almindeligt i produktion til ranking, retrieval og semantisk søgning.

De påstår tre centrale hastighedsgevinster ved produktionslængder: cirka 5x lavere p50-latency end Hugging Face tokenizers (Rust), cirka 2x mod SentencePiece (C++), og cirka 1,5x mod IREE’s tokenizer (C). Derudover nævnes zero steady-state heap-allocations. Og i egen drift skulle CPU-forbruget være faldet med 5–6x, med tocifrede millisekunder barberet af en reranker. Tallene stammer fra Perplexitys egne målinger, gengivet i MarkTechPost – vi efterlyser stadig fulde scripts og hardwaredetaljer.

Nærbillede af en tekniker der monterer en termisk probe på en server‑CPU i et testmiljø — fokus på måling og performance‑diagnostik.

Unigram og den varme sti

Unigram-tokenization, beskrevet af Taku Kudo (2018) og implementeret i SentencePiece, vælger den mest sandsynlige opdeling af input i tokens via en Viterbi-lignende dynamisk programmering over byte-positioner. Hver position ser på mulige fortsættelser i et vokabular-trie, og den bedste sti findes ved at summere log-sandsynligheder.

I praksis er trie-walken ved hver byte-position hot path. På lange inputs bliver det til mange traversal-operationer. Her gør pointer-chasing, cache-misses og unødige allokeringer ondt – især når datastrukturerne ikke spiller med L1\/L2-cache. Når L2 thrashes, forsvinder millisekunderne hurtigt.

Hvorfor den klassiske vej kan være langsom

Hugging Face tokenizers-cratet er fleksibelt, men fleksibilitet koster i hot paths. Ifølge MarkTechPosts gennemgang af Perplexitys analyse er der tre flaskehalse: per-match-allokeringer (bl.a. String::from_utf8 undervejs), AHashMap-opslag i hvert trie-trin, samt nyallokerede DP-\/out-buffere pr. kald, som kan løfte L2-missraten ved lange inputs.

Perplexitys Rust-kode sigter mod at løse det med nul steady-state heap-allokeringer, kraftigt færre allokeringer og en mere kompakt datastruktur for børnesøgninger i triet, så CPU’en ser mere sekventiel hukommelsesadgang og mindre pointer-jagt. Klassisk low-level tuning – og ofte effektivt, når adgangsmønstre er problemet.

Banner

De rapporterede benchmarks og de vigtige forbehold

Headline-tallene er: ~5x mod HF tokenizers, ~2x mod SentencePiece, ~1,5x mod IREE. Men for reproducerbarhed mangler centrale detaljer: CPU- og mikroarkitektur, compiler-flags i Rust og C++, Rust-toolchain, LTO-indstillinger, batch-størrelser og inputlængdefordeling. p50 alene er ikke nok.

Vi vil se p50, p95 og p99, samt throughput ved forskellige trådantal, CPU-udnyttelse og gerne L2-missrater fra hardware-counters. En CPU-matrix (AMD vs. Intel, E-cores vs. P-cores) er også relevant – optimeringer kan skifte profil med kerne-layout eller NUMA-topologi.

Operations routing board i en teknisk niche — farvekodede baner indikerer workflow og en amber indikator viser pres på en pipeline.

Hvorfor det her betyder noget i drift

Holder resultaterne, betyder det mindre CPU per request, flere requests per server og lavere cloud-udgifter. I scenarier med små modeller – embeddings, klassifikatorer, rerankers – hvor GPU-tiden er nede i få millisekunder, fylder tokenization relativt mere. Skærer man 5x i p50 på tokenization, kan E2E-latency rykke sig mærkbart, især ved hård batching.

Vi har set en tokenizer-optimering alene halvere CPU-omkostninger i et anonymiseret produktionsflow. Ikke fordi modellen ændrede sig, men fordi resten af systemet fik luft: hurtigere køtømning, færre context-switches og lavere GC-tryk i applikationslaget. De gevinster ses først, når graferne flader ud i Grafana.

Arkitektur og workflows hvor det batter

Tokenization-optimering flytter mest, når GPU’en ikke dominerer tidsbudgettet: rerankers med hundredvis af kandidater per forespørgsel, embeddings-pipelines med store batches eller klassifikatorer i streaming-setup. Her kan CPU’en bukke under, selvom modellen er lille.

Men der er en tradeoff. En Rust-baseret tokenizer kræver bindings til Python\/Java\/Go, eller også kører den som sidecar-service. Begge virker, men kræver ingeniørarbejde: FFI-determinisme, memory-sikkerhed i grænseflader, cross-platform CI og fornuftig telemetri. Ekstra tests på tværs af compiler-versioner er en god idé – små driftsfejl kan snige sig ind ved toolchain-opdateringer.

Hvordan vi ville vurdere den i et rigtigt miljø

Start med en lille, nådesløs benchmark på jeres egne data. Reproducer Perplexitys workload så tæt som muligt: samme vokab-størrelse (250K, hvis det matcher), lignende inputlængder og jeres batch-størrelser. Mål p50, p95 og p99, CPU-udnyttelse og L2-missrate hvis muligt. Test single-thread og multi-thread, og inkluder worst-case-kørsler.

Næste skridt er en A\/B i staging. Sæt den nye tokenizer ind bag et feature flag. Log tidsbudget pr. fase: preproc, tokenization, batching, GPU compute, postproc. Hold øje med fejl og determinisme – især på multibyte-skriftsprog. Kør også langvarig load for at se memory- og varmeprofiler over timer, ikke kun minutter.

Tæt nærbillede af et sløret performance-print med håndtegnede timing-barrer og et markør‑tab ved 'tokenize' — symbol på hvor tid forsvinder i pipeline.

Hvad vi stadig mangler at få bekræftet

Vi har endnu ikke set fuldt benchmark-script, compiler-flags eller CPU-model fra Perplexity. MarkTechPost gengiver resultaterne, men uafhængig validering kræver, at repoet indeholder opskriften til at genskabe tallene. Vi vil også se versionsnumre for HF tokenizers, SentencePiece og IREE-tokenizer – og at builds er optimale for hver.

En CPU-model-matrix og batch-\/længde-sweeps vil klæde sagen. Vokab-størrelser betyder noget: 250K er tungt; hvordan ser tallene ud ved 30K–50K? Hvad med edge cases som arabisk, kinesisk og blandet unicode-støj? Hvis zero steady-state heap allocations er målet, bør memory-profiler bekræfte det under langvarig, varieret belastning.

Risici og modargumenter

Fem gange hurtigere kan være sandt under bestemte betingelser. Hvis workloaden domineres af korte inputs, eller hvis GPU allerede sluger ~95% af latency, kan gevinsten i E2E være lille. Bruger I i forvejen en stramt optimeret SentencePiece-C++-build med pinned memory og forvarmede buffere, kan afstanden være mindre end 2x.

Banner

Et 250K-vokab favoriserer kompakte, sekventielle datastrukturer. På mindre vokab kan overhead fra mere avancerede tries være lavere. Cross-lang edge cases kan afsløre determinismeproblemer, især hvis bindingslaget snubler på encodings. Det er ikke en påstand her – men en kendt faldgrube.

Teknisk kerne i optimeringerne

Meget kan vindes ved at undgå hash-opslag i den indre loop og i stedet bruge en kompakt trie-repræsentation, fx en double-array trie som kendt fra SentencePiece. Den rammer hukommelsen sekventielt og minimerer pointer-chasing. Kombineret med forudallokerede scratch-buffere og nul ny-allokeringer i steady state falder L2-missraten, og p95\/p99 bliver mere forudsigelige.

Det lyder simpelt, men kræver disciplin: faste buffere, klare livstider, ingen skjulte kopier – og ingen from_utf8 i hot path. Vi har fjernet sådan en konvertering i en anden komponent og set flere millisekunder forsvinde. Små ting, stor effekt.

Hvad man bør måle før man skifter

Tjekliste: Samme inputkorpus på tværs af tokenizers. Identiske compiler-flags og toolchains. Mål p50, p95, p99. Gennemløb per sekund ved 1, 4, 8, 16 tråde. CPU-brug, instruktioner per cyklus, L1\/L2-missrater. Peak RSS og steady-state memory. Kør determinismetests på tværs af sprog og unicode-kanter, inkl. streaming og meget lange dokumenter.

Og vigtigst: mål end-to-end. 5x i tokenization skal oversættes til brugerrelevante millisekunder, ikke kun mikromålinger. For rerankers kan tocifrede millisekunder være forskellen mellem en skarp og en træg søgning.

Hvad betyder det økonomisk

Hvis CPU-udnyttelsen falder 5–6x som rapporteret, kan I vælge færre kerner til samme trafik eller mere trafik på samme hardware. Regnestykket er sjældent lineært, men bevægelsen er klar. Mindre CPU-tryk frigør også headroom til mere aggressiv batching, lavere køtider og strammere SLO’er.

For teams uden budget til flere GPU’er er dette en praktisk vej til skalering. Nogle gange er det hurtigere at optimere tokenization og service-layout end at skaffe endnu et A100-slot i den rigtige region. Vi har stået og justeret pinning og affinitet tidligt om morgenen; en hurtigere tokenizer havde sparet den øvelse.

Hvad konkurrenter vil sige – og hvad vi svarer

Hugging Face vil med rette spørge til fairness: var tokenizers bygget med optimale flags, og var nyeste commits med? SentencePiece-folkene vil påpege, at deres double-array trie har været hurtig længe, og at forskelle kan være workflow-afhængige. IREE-teamet vil fremhæve, at deres tokenizer passer bedst i deres egen toolchain.

Det er legitime spørgsmål. Svaret er benchmark-transparens og reproducerbarhed: samme data, samme flags, samme arkitektur. Vi vil se scripts i repoet – ikke kun grafer i en blog. Indtil da er gevinsterne lovende, men bør måles på egen hardware, før man skifter i produktion.

Hvad man konkret kan gøre i morgen

– Hent repoet, byg med en fast Rust-toolchain, og kør en micro-benchmark på produktionsnære længder. Gem profiler og notér outliers.
– Sæt tokenizeren bag et feature flag i staging. Mål E2E-latency og CPU. Kør 24–48 timers soak. Sammenlign p95\/p99.
– Gennemgå licens og afhængigheder, og tjek kommerciel anvendelse. MIT\/Apache er typisk gnidningsfrit; GPL kræver ekstra omtanke.

Dokumentér resultaterne kort. Den rapport er værdien, når nogen om to måneder spørger, hvorfor I skiftede tokenizer, og om det var indsatsen værd.

Konklusion

Perplexitys Rust-tokenizer ligner en seriøs lav-latens-komponent. På papiret er gevinsterne store mod etablerede implementeringer, og forklaringen – færre allokeringer, kompakt trie, mindre pointer-chasing – er teknisk plausibel. Vi mangler stadig fuld reproducerbarhed og hardware\/flags-detaljer.

Anbefalingen er enkel: mål i jeres egen pipeline, på jeres egen hardware, med jeres egne inputs. Hvis I ser bare halvdelen af den lovede gevinst, er det stadig en markant forskel i drift.

Kilder

    Gør brugeroplevelsen bedre.
    Hvilket firma arbejder du for?