<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Hft on Jasper</title><link>https://jasper-aa64.github.io/tags/hft/</link><description>Recent content in Hft on Jasper</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Wed, 04 Nov 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://jasper-aa64.github.io/tags/hft/index.xml" rel="self" type="application/rss+xml"/><item><title>Low-Latency Trading — Context Switches, Page Tables and the TLB</title><link>https://jasper-aa64.github.io/posts/low-latency-context-switch-page-table-tlb/</link><pubDate>Wed, 04 Nov 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/posts/low-latency-context-switch-page-table-tlb/</guid><description>Threads are lighter than processes because the TLB and caches stay usable after the switch, not because the switch itself is cheaper. The TLB has no MESI: when any thread in a process changes the page tables, every core still holding that page table gets interrupted, and pinning and isolcpus cannot prevent it, so once a hot-path process is running its address space is read-only.</description></item><item><title>Trading System Notes #21: Measuring Trading-System Performance</title><link>https://jasper-aa64.github.io/posts/trading-system-latency-metrics/</link><pubDate>Tue, 03 Nov 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/posts/trading-system-latency-metrics/</guid><description>What TTT and RTT each cover, why to report p50, p99 and p999 instead of the mean, how marks at thread boundaries separate processing from queueing, and how to use the latency table as a budget.</description></item><item><title>Trading System Notes #20: Measuring Latency with the TSC</title><link>https://jasper-aa64.github.io/posts/tsc-latency-measurement/</link><pubDate>Mon, 02 Nov 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/posts/tsc-latency-measurement/</guid><description>What a TSC reading means, when it is taken, which core it is taken on, how to record timestamps on the hot path, and how ticks become ns: where the frequency comes from and how to calibrate it yourself.</description></item><item><title>Trading System Notes #19: Scheduling Policies, Priority Inversion and Kernel Tuning</title><link>https://jasper-aa64.github.io/posts/scheduling-priority-inversion-kernel-tuning/</link><pubDate>Thu, 29 Oct 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/posts/scheduling-priority-inversion-kernel-tuning/</guid><description>Who runs first and for how long: scheduling classes and time slices, three traps of real-time priorities, two fixes for priority inversion, why HFT often skips PREEMPT_RT, and which knobs a low-latency box turns from BIOS to sysctl.</description></item><item><title>Trading System Notes #18: Thread-Safe Queues</title><link>https://jasper-aa64.github.io/posts/thread-safe-queue/</link><pubDate>Tue, 27 Oct 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/posts/thread-safe-queue/</guid><description>From one mutex to many producers: condition variables and lost wakeups in a blocking queue, rte_ring&amp;rsquo;s two pairs of indices and in-order publishing, Disruptor&amp;rsquo;s availability flags, and whether a full queue should block, drop, or overwrite.</description></item><item><title>Trading System Notes #17: Wait-Free</title><link>https://jasper-aa64.github.io/posts/wait-free-sticky-counter/</link><pubDate>Mon, 26 Oct 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/posts/wait-free-sticky-counter/</guid><description>Wait-free is not a faster lock-free: it turns a failed CAS from &amp;ldquo;try again&amp;rdquo; into &amp;ldquo;I come after you&amp;rdquo;, which bounds every thread&amp;rsquo;s steps, at the cost of more atomics and code that is harder to get right.</description></item><item><title>Low-Latency Trading — perf: How to Use It, What to Read</title><link>https://jasper-aa64.github.io/posts/low-latency-perf-profiling/</link><pubDate>Thu, 22 Oct 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/posts/low-latency-perf-profiling/</guid><description>stat for the totals, record and report to find the function holding 98% of the samples, annotate to see every sample land on the instruction after an add: a chain of adds, each waiting for the last, and splitting it four ways is 3.3 times faster. Without hardware counters, cpu-clock sampling still works; if the report shows only addresses, check the symbol table and the path the program runs from.</description></item><item><title>Trading System Notes #16: Spinlocks</title><link>https://jasper-aa64.github.io/posts/spinlock-implementation/</link><pubDate>Wed, 21 Oct 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/posts/spinlock-implementation/</guid><description>Whether a spinlock is fast depends on what its waiters do: if every attempt is a read-modify-write, they drag the lock&amp;rsquo;s line back and forth. Read before you grab, put PAUSE in the loop, back off after losing, and waiting costs the holder almost nothing.</description></item><item><title>Low-Latency Trading — A Cache Case Study: Repricing 64 Options per Tick</title><link>https://jasper-aa64.github.io/posts/low-latency-cache-case-study/</link><pubDate>Tue, 20 Oct 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/posts/low-latency-cache-case-study/</guid><description>One tick touches 140 cache lines, and most of the time goes into waiting for them. None of the four steps changes the computation; they change when data arrives, where it lands and who holds it: put the misses in flight together, ask for the next batch early, hand back lines that are dead after one read, read one line less across the handoff, and leave the lines the other core will read in L3.</description></item><item><title>Trading System Notes #12: Strength Reduction and Arithmetic Optimization</title><link>https://jasper-aa64.github.io/posts/strength-reduction-arithmetic/</link><pubDate>Thu, 15 Oct 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/posts/strength-reduction-arithmetic/</guid><description>The compiler only makes rewrites it can prove don&amp;rsquo;t change the result, and it does constant multiplies and divides better than you. What&amp;rsquo;s left for you is where it lacks information or where the rewrite changes the result: run-time divisors, signs, floating point. Integer prices are exact and fast.</description></item><item><title>Trading System Notes #13: Type Punning, Function Calls, and Compiler Hints</title><link>https://jasper-aa64.github.io/posts/type-punning-calls-compiler-hints/</link><pubDate>Thu, 15 Oct 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/posts/type-punning-calls-compiler-hints/</guid><description>How far the compiler can optimize depends on what it can see and what it dares to assume: different types are treated as non-overlapping, an invisible function body means arguments go by the calling convention, and helper macros are decisions you make for it, not all of them right.</description></item><item><title>Trading System Notes #14: Prefetching, Cache Warming, and Double Buffering</title><link>https://jasper-aa64.github.io/posts/prefetch-warmup-double-buffer/</link><pubDate>Thu, 15 Oct 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/posts/prefetch-warmup-double-buffer/</guid><description>There are three ways to get data into cache ahead of time, each with a precondition: prefetching needs you to know the address before the hardware does, warming has to happen on the core that reads the data, and double buffering needs a guarantee that the writer never returns to a copy a reader hasn&amp;rsquo;t finished.</description></item><item><title>Trading System Notes #15: SIMD Vectorization and Intrinsics</title><link>https://jasper-aa64.github.io/posts/simd-vectorization-intrinsics/</link><pubDate>Thu, 15 Oct 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/posts/simd-vectorization-intrinsics/</guid><description>One instruction computes a row of numbers only if the compiler knows how wide a register it may use, is sure nothing overlaps, and is allowed to reorder; when it can&amp;rsquo;t get all three, intrinsics let you write it yourself, at the cost of alignment, instruction-set detection and the last few digits of the result.</description></item><item><title>Trading System Notes #10: Pointer and Memory-Access Optimization</title><link>https://jasper-aa64.github.io/posts/pointer-memory-access/</link><pubDate>Mon, 12 Oct 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/posts/pointer-memory-access/</guid><description>In a loop like a[i] = *b, the compiler re-reads *b every iteration, because writing a[i] might change it. Pointer optimization is about letting the compiler read less, and fitting linked structures into nearer caches.</description></item><item><title>Trading System Notes #11: Return Value Optimization and Pure Functions</title><link>https://jasper-aa64.github.io/posts/rvo-pure-functions/</link><pubDate>Mon, 12 Oct 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/posts/rvo-pure-functions/</guid><description>Returning a struct by value is usually free, so there&amp;rsquo;s no need for out-parameters; what to watch are the few patterns that always move or copy. Pure-function attributes are a promise to the compiler: right, and it calls less; wrong, and it&amp;rsquo;s undefined behavior.</description></item><item><title>Trading System Notes #8: CRTP and Static Polymorphism</title><link>https://jasper-aa64.github.io/posts/crtp-static-polymorphism/</link><pubDate>Mon, 12 Oct 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/posts/crtp-static-polymorphism/</guid><description>The base class writes the flow and the subclass fills in the details: virtual functions pick the subclass at run time, CRTP at compile time. What you save is more than one indirect jump: the call inlines completely and the object has no vptr. The price is that Base&lt;A&gt; and Base&lt;B&gt; are unrelated types and can&amp;rsquo;t share a container.</description></item><item><title>Trading System Notes #9: Loop Optimization</title><link>https://jasper-aa64.github.io/posts/loop-optimization/</link><pubDate>Mon, 12 Oct 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/posts/loop-optimization/</guid><description>A dot-product loop reports “vectorized” at -O3, yet its four additions still wait on each other: floating-point addition isn&amp;rsquo;t associative, so the compiler won&amp;rsquo;t reorder it. What loop optimization really asks of you is to spot what blocks the compiler, and to make the changes it won&amp;rsquo;t make for you.</description></item><item><title>Low-Latency Trading — Memory Latency and Bandwidth</title><link>https://jasper-aa64.github.io/posts/low-latency-memory-latency-bandwidth/</link><pubDate>Fri, 09 Oct 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/posts/low-latency-memory-latency-bandwidth/</guid><description>One memory access takes about 100 ns and brings back 64 B. One at a time, that&amp;rsquo;s 0.64 GB/s, yet one core reading sequentially gets 15–60 GB/s. The missing factor is the number of requests in flight. Whether the next load&amp;rsquo;s address has to wait for this load decides whether your code is latency-bound or bandwidth-bound.</description></item><item><title>Trading System Notes #7: Branch Prediction and Branch Optimization</title><link>https://jasper-aa64.github.io/posts/branch-prediction-branch-optimization/</link><pubDate>Fri, 09 Oct 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/posts/branch-prediction-branch-optimization/</guid><description>The front end has to fetch instructions every cycle, but a branch isn&amp;rsquo;t resolved until a dozen-plus cycles later, so the CPU guesses. A right guess costs almost nothing; a wrong one throws away everything after it, about 15–20 cycles. The same if is predictable when the data has a pattern and a coin flip when it&amp;rsquo;s random, and the compiler may already have turned it into a cmov.</description></item><item><title>Low-Latency Trading — MESI Cache Coherence</title><link>https://jasper-aa64.github.io/posts/low-latency-mesi-cache-coherence/</link><pubDate>Sun, 04 Oct 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/posts/low-latency-mesi-cache-coherence/</guid><description>MESI enforces one rule: a cache line has either one core that may write it or any number of cores that may only read it, never both. The four states are the answers to two questions — does anyone else hold this line, and have I changed it? — and every cost in the protocol comes from moving data between layers or waiting for another core to confirm. False sharing, a cached queue cursor and a producer that slows down as readers join are all the same state machine. Coherence still doesn&amp;rsquo;t make a multi-word read atomic, and it says nothing about the order of writes to different addresses; that is what fences are for.</description></item><item><title>Trading System Notes #5: An SPMC Broadcast Ring in Shared Memory</title><link>https://jasper-aa64.github.io/posts/spmc-shared-memory-broadcast-ring/</link><pubDate>Sun, 04 Oct 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/posts/spmc-shared-memory-broadcast-ring/</guid><description>Market data has one producer and several consumers, each of which must see every message, and the producer is the hot path that may not wait for anyone. The answer is a broadcast ring: every slot carries its own sequence stamp, readers keep private cursors, and the producer overwrites the oldest slot without ever reading reader state. The price moves to the readers — overruns are silent, a re-check after reading can&amp;rsquo;t catch a half-written slot unless the writer invalidates the stamp first, and readers that catch up take the line the producer writes next, so every flat-out write costs more. Moving the ring into shared memory adds three more rules: nothing inside it may be a pointer, the first lap pays a page fault every 32 messages, and a restarted reader loses everything unless it saved its cursor.</description></item><item><title>Trading System Notes #6: Alignment, Layout, and Cache and DRAM Geometry</title><link>https://jasper-aa64.github.io/posts/alignment-layout-cache-dram-geometry/</link><pubDate>Sun, 04 Oct 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/posts/alignment-layout-cache-dram-geometry/</guid><description>An access never pays for bytes; it pays for cache lines, and the address decides which lines, which cache set they compete for, and which DRAM channel and bank they live on. Part 1 is alignment: why a double aligned to 8 never straddles a line, why padding exists for arrays, alignas on a type versus a member, and how to get 64-byte and 2 MiB alignment on the heap. Part 2 is layout: lines per access, AoS versus SoA, and denormalization as a way to cut a dependency chain. Part 3 goes into the hardware: L1 picks a set from address bits 6–11, so data 4 KiB apart competes for 8 slots however empty the cache is (measured on an M1); a DRAM bank has one row buffer, 14 ns on a hit and 41 ns on a conflict; a column walk loses at five layers; refresh adds a P99 tail software can&amp;rsquo;t remove; and channels balance only when the hot stride is coprime with the channel count.</description></item><item><title>Trading System Notes #4: Lock-Free Queues and Micro-Batching</title><link>https://jasper-aa64.github.io/posts/lock-free-queue-logger-micro-batching/</link><pubDate>Sun, 20 Sep 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/posts/lock-free-queue-logger-micro-batching/</guid><description>A lock-free SPSC queue works because every shared variable has exactly one writer: each side updates only its own counter and merely reads the other&amp;rsquo;s. The rest is keeping that property from being quietly undone — a shared element count both cores fight over (subtract two counters instead), a full-check that reads the other core on every call (cache the other side&amp;rsquo;s cursor, which can only be wrong in the safe direction), a mirrored mapping that removes the wrap-around seam, and a logger that pushes one character per slot (thirty slots for one log line, five as text runs). It ends with the vocabulary that keeps lock-free claims honest: SPSC is wait-free only through a fail-fast interface, finite steps are not finite time, and a bounded queue must always choose between dropping and blocking.</description></item><item><title>Trading System Notes #3: Memory Pools and Allocators</title><link>https://jasper-aa64.github.io/posts/hot-path-memory-allocators/</link><pubDate>Thu, 17 Sep 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/posts/hot-path-memory-allocators/</guid><description>Every technique in this post does the same thing at a different layer: move an uncertain, kernel-involving operation off the hot path and force it to happen once, upfront, before it can ambush a single request. An object pool replaces malloc&amp;rsquo;s variable-cost search with an always-O(1) free list. mlockall and careful mallopt tuning stop the kernel from quietly taking pages back — and pre-faulting closes the one gap mlock alone leaves open. A hand-rolled arena allocator makes the STL itself cooperate with a custom allocator backed by bump-pointer memory. std::pmr solves the same STL-cooperation problem the standard library&amp;rsquo;s way — trading compile-time speed for runtime flexibility.</description></item><item><title>Trading System Notes #2: Memory Ordering and Cache Lines</title><link>https://jasper-aa64.github.io/posts/memory-ordering-false-sharing-dependency-chains/</link><pubDate>Tue, 15 Sep 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/posts/memory-ordering-false-sharing-dependency-chains/</guid><description>The store buffer and the cache-coherence protocol are one piece of hardware, but they create two unrelated engineering problems. One is correctness: does a thread see the right value, in the right order — solved by memory_order and release/acquire pairing. The other is performance: how many cycles does touching shared or dependent data cost, even when every value read is already correct — solved by cache-line layout and instruction scheduling. Conflating the two is the single most common confusion in this part of systems programming.</description></item><item><title>Trading System Notes #1: CPU Isolation and NUMA</title><link>https://jasper-aa64.github.io/posts/cpu-affinity-core-isolation-numa/</link><pubDate>Wed, 09 Sep 2026 00:00:00 +0000</pubDate><guid>https://jasper-aa64.github.io/posts/cpu-affinity-core-isolation-numa/</guid><description>The enemy of a low-latency system is jitter, not the mean. The goal is to make your hot thread the only thing that will ever run on its core: pinning kills migration cost, the isolation stack evicts the tick / RCU / interrupts one layer at a time, disabling SMT and locking frequency removes the core&amp;rsquo;s own variability, and share-nothing sidesteps NUMA entirely.</description></item></channel></rss>