<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: gilnett</title>
    <description>The latest articles on DEV Community by gilnett (@gilnett).</description>
    <link>https://dev.to/gilnett</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4174245%2F972c317f-3429-4eb3-b4aa-8e86b637acf9.png</url>
      <title>DEV Community: gilnett</title>
      <link>https://dev.to/gilnett</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gilnett"/>
    <language>en</language>
    <item>
      <title>Learned Indexes in Rust v0.2: Answering Reddit, Adding Range Queries, and Beating slice::binary_search</title>
      <dc:creator>gilnett</dc:creator>
      <pubDate>Sun, 18 Oct 2026 13:45:12 +0000</pubDate>
      <link>https://dev.to/gilnett/learned-indexes-in-rust-v02-answering-reddit-adding-range-queries-and-beating-pd6</link>
      <guid>https://dev.to/gilnett/learned-indexes-in-rust-v02-answering-reddit-adding-range-queries-and-beating-pd6</guid>
      <description>&lt;p&gt;A few days ago, I published an architectural deep dive exploring a provocative question: &lt;em&gt;What if we could replace comparison-based database trees (like B-Trees) with pure mathematical functions in Rust?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The response from the community across Dev.to and Reddit (&lt;code&gt;r/rust&lt;/code&gt;, &lt;code&gt;r/compsci&lt;/code&gt;, &lt;code&gt;r/database&lt;/code&gt;) was incredible. It sparked great discussions, valid skepticism, and direct questions that deserved real engineering answers rather than theoretical debates.&lt;/p&gt;

&lt;p&gt;Today, I released &lt;strong&gt;&lt;code&gt;learned_index_lab&lt;/code&gt; v0.2.0&lt;/strong&gt;. Before diving into the technical answers, here is a quick refresher on what this project is and what it proves.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. What is Learned Index Lab, and What Does It Prove?
&lt;/h2&gt;

&lt;p&gt;For more than 50 years, database storage engines (B-Trees, B+Trees, LSM-Trees) have relied on comparison-based pointer hierarchies. While reliable, traversing tree nodes introduces severe hardware penalties on modern CPU architectures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pointer Chasing&lt;/strong&gt;: Every jump down a tree incurs memory dereferences across distant heap locations, triggering recurring L1/L2/L3 cache misses.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High Memory Overhead&lt;/strong&gt;: A standard &lt;code&gt;BTreeMap&lt;/code&gt; consumes ~45 MB of node pointers, balancing factors, and metadata for every 1,000,000 keys.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Branch Mispredictions&lt;/strong&gt;: Repetitive binary branch decisions at each node stall deep CPU execution pipelines.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Originated by Kraska et al. (MIT / Google) and formalized by Ferragina &amp;amp; Vinciguerra (PVLDB 2020), &lt;strong&gt;Learned Indexes reframe indexing as a mathematical regression problem&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Given a sorted dataset, the index builder runs a single-pass streaming Piecewise Linear Approximation (PLA) that partitions the data into a tiny set of linear segments (&lt;code&gt;y = ax + b&lt;/code&gt;). During lookup, the CPU executes an in-register arithmetic calculation predicting the exact position within a strict, provable error corridor &lt;code&gt;[approx - ε, approx + ε]&lt;/code&gt;, followed by a tightly bounded local search.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What the benchmarks prove:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zero data loss &amp;amp; 100% exact lookups&lt;/strong&gt; (0 false positives, 0 false negatives).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;99.97% memory reduction&lt;/strong&gt;: Index metadata drops from &lt;strong&gt;45.78 MB down to ~12 KB&lt;/strong&gt; for 1,000,000 keys.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;3x to 4.5x faster lookups&lt;/strong&gt; compared to standard &lt;code&gt;BTreeMap&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. Why v0.2.0? Answering the Community's Questions
&lt;/h2&gt;

&lt;p&gt;The discussions on Reddit and Dev.to raised two critical questions that shaped this release:&lt;/p&gt;

&lt;h3&gt;
  
  
  Question 1: &lt;em&gt;"Why only compare against &lt;code&gt;BTreeMap&lt;/code&gt;? What about a flat sorted slice using &lt;code&gt;slice::binary_search&lt;/code&gt;?"&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;This was the most frequent critique, and it is 100% valid. &lt;/p&gt;

&lt;p&gt;A contiguous, pre-sorted &lt;code&gt;Vec&amp;lt;u64&amp;gt;&lt;/code&gt; indexed via &lt;code&gt;slice::binary_search&lt;/code&gt; has &lt;strong&gt;0 KB of extra memory overhead&lt;/strong&gt;. It eliminates heap pointer indirection entirely. How does a PGM learned index hold up against standard library binary search on a flat slice?&lt;/p&gt;

&lt;p&gt;To answer this conclusively, I integrated &lt;code&gt;slice::binary_search&lt;/code&gt; as an explicit baseline across all 10-run, 1,000,000-key statistical benchmarks in &lt;code&gt;src/main.rs&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Results (Average across 10 randomized runs, 1M keys, 100k queries):&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Workload Distribution&lt;/th&gt;
&lt;th&gt;Flat &lt;code&gt;slice::binary_search&lt;/code&gt;
&lt;/th&gt;
&lt;th&gt;
&lt;code&gt;PGM-Index&lt;/code&gt; (v0.2.0)&lt;/th&gt;
&lt;th&gt;Speedup vs. Slice&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Dense Sequential Time-Series&lt;/strong&gt; (ε = 32)&lt;/td&gt;
&lt;td&gt;152.7 ns/op&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;63.5 ns/op&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2.41x faster&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Uniform Sparse Random&lt;/strong&gt; (ε = 16)&lt;/td&gt;
&lt;td&gt;150.9 ns/op&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;70.5 ns/op&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2.14x faster&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Clustered Heavy-Tailed Lognormal&lt;/strong&gt; (ε = 16)&lt;/td&gt;
&lt;td&gt;141.0 ns/op&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;48.6 ns/op&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2.90x faster&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Why is PGM over 2x faster than a contiguous binary search?&lt;/strong&gt;&lt;br&gt;
A binary search over 1,000,000 keys requires &lt;code&gt;~log₂(10⁶) ≈ 20&lt;/code&gt; comparisons. Because the jumps cut across 8 MB of contiguous memory, the first 14 to 16 jumps inevitably miss the L1/L2 CPU cache, forcing DRAM cache line fetches.&lt;/p&gt;

&lt;p&gt;With PGM:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The segment array is tiny (3 KB to 48 KB) and stays resident in L1/L2 cache.&lt;/li&gt;
&lt;li&gt;The initial binary search over segments takes only 6 to 9 jumps in fast cache.&lt;/li&gt;
&lt;li&gt;The arithmetic calculation calculates the candidate offset immediately.&lt;/li&gt;
&lt;li&gt;The final local search only inspects &lt;code&gt;2ε = 32&lt;/code&gt; elements (a single 256-byte span fitting inside 4 cache lines).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Memory traffic is cut from &lt;strong&gt;~20 cache line fetches down to 4&lt;/strong&gt;, explaining the 2.1x–2.9x latency win.&lt;/p&gt;




&lt;h3&gt;
  
  
  Question 2: &lt;em&gt;"Point lookups are cool, but real databases need Range Queries and Lower-Bound searches. Can PGM do that?"&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;Point lookups (&lt;code&gt;find(key) -&amp;gt; Option&amp;lt;usize&amp;gt;&lt;/code&gt;) are only half the battle. Real-world analytical systems (ClickHouse zone maps, RocksDB SSTables, Parquet row groups) rely heavily on:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Finding the first key &lt;code&gt;&amp;gt;= target&lt;/code&gt; (predecessor / lower bound).&lt;/li&gt;
&lt;li&gt;Scanning a continuous slice of keys within an interval &lt;code&gt;[A, B]&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In v0.2.0, I implemented two zero-allocation APIs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;lower_bound(&amp;amp;self, target: u64) -&amp;gt; usize&lt;/code&gt;&lt;/strong&gt;:
Calculates the predicted lower-bound offset in &lt;code&gt;O(log S + log ε)&lt;/code&gt; time with an automatic fallback guarantee to &lt;code&gt;partition_point&lt;/code&gt; should pathological bounds occur.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;range&amp;lt;R: RangeBounds&amp;lt;u64&amp;gt;&amp;gt;(&amp;amp;self, bounds: R) -&amp;gt; &amp;amp;[u64]&lt;/code&gt;&lt;/strong&gt;:
Accepts any standard Rust range bounds (&lt;code&gt;..&lt;/code&gt;, &lt;code&gt;a..b&lt;/code&gt;, &lt;code&gt;a..=b&lt;/code&gt;, &lt;code&gt;a..&lt;/code&gt;, &lt;code&gt;..b&lt;/code&gt;) and returns a zero-copy slice directly over the underlying sorted buffer.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  3. Code Example: How It Works in Practice
&lt;/h2&gt;

&lt;p&gt;Here is the updated v0.2.0 API in action:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
rust
use learned_index_lab::PgmIndex;

fn main() {
    // 1. Prepare sorted dataset (e.g. sensor timestamps or primary IDs)
    let data: Vec&amp;lt;u64&amp;gt; = vec![
        100, 105, 110, 115, 120, 250, 500, 1000, 1500, 2000, 5000, 10000
    ];

    // 2. Build the PGM index with an error bound corridor (epsilon = 16)
    let pgm = PgmIndex::build(data, 16);

    // 3. Exact point lookup (O(log S + log epsilon))
    assert_eq!(pgm.find(1500), Some(8));

    // 4. Predecessor / Lower Bound search (first element &amp;gt;= 1200)
    let lb_idx = pgm.lower_bound(1200);
    println!("Lower bound for 1200 is at index {}: value {}", lb_idx, pgm.data[lb_idx]);
    // Output: index 8, value 1500

    // 5. Zero-copy range query over continuous slice
    let slice = pgm.range(110..=2000);
    println!("Keys in [110, 2000]: {:?}", slice);
    // Output: [110, 115, 120, 250, 500, 1000, 1500, 2000]

    // 6. Memory footprint inspection
    println!("Total segments: {}", pgm.segments.len());
    println!("Index metadata size: {} bytes", pgm.index_only_bytes());
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>rust</category>
      <category>performance</category>
      <category>database</category>
      <category>algorithms</category>
    </item>
    <item>
      <title>Why We've Been Indexing Data Wrong for 50 Years: Replacing B-Trees with Math in Rust</title>
      <dc:creator>gilnett</dc:creator>
      <pubDate>Fri, 16 Oct 2026 00:25:27 +0000</pubDate>
      <link>https://dev.to/gilnett/why-weve-been-indexing-data-wrong-for-50-years-replacing-b-trees-with-math-in-rust-nch</link>
      <guid>https://dev.to/gilnett/why-weve-been-indexing-data-wrong-for-50-years-replacing-b-trees-with-math-in-rust-nch</guid>
      <description>&lt;h1&gt;
  
  
  Why We've Been Indexing Data Wrong for 50 Years: Replacing B-Trees with Math in Rust
&lt;/h1&gt;

&lt;p&gt;For half a century, database engineering has rested on an unspoken consensus: if you need to index sorted data, you use a &lt;strong&gt;B-Tree&lt;/strong&gt;. From relational engines like PostgreSQL and SQLite to modern key-value stores like RocksDB, B-Trees and their variants have been the default choice since the early 1970s.&lt;/p&gt;

&lt;p&gt;They are robust, well-understood, and battle-tested. But in the 50 years since their invention, computer architecture has fundamentally transformed. &lt;/p&gt;

&lt;p&gt;Processors have become astonishingly fast, while RAM latency has barely kept pace. This divergence—often called the &lt;strong&gt;memory wall&lt;/strong&gt;—means the way B-Trees navigate data is increasingly at odds with how modern silicon actually works.&lt;/p&gt;

&lt;p&gt;I spent the past few days implementing and benchmarking a theoretical alternative in pure Rust: a &lt;strong&gt;Piecewise Geometric Model (PGM) Learned Index&lt;/strong&gt;. Here is what I learned about why it works, how it breaks the traditional model, and what it implies for modern software systems.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Silent Bottleneck: Pointer Chasing
&lt;/h2&gt;

&lt;p&gt;To understand why B-Trees struggle on modern hardware, you have to look at what happens at the CPU cache level during a lookup.&lt;/p&gt;

&lt;p&gt;A B-Tree organizes data into hierarchical nodes linked by memory pointers. When searching for a key:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The CPU loads the root node from RAM into cache.&lt;/li&gt;
&lt;li&gt;It scans the node to find the appropriate child branch.&lt;/li&gt;
&lt;li&gt;It follows a pointer to another memory location in RAM, usually causing a cache miss.&lt;/li&gt;
&lt;li&gt;It repeats this process four to six times until reaching the target leaf.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;On a modern CPU, an arithmetic calculation takes a fraction of a nanosecond. Loading an un-cached line from main memory takes around 50 to 100 nanoseconds. &lt;/p&gt;

&lt;p&gt;During a B-Tree search, your processor spends almost none of its time "thinking"—it spends nearly all of its time &lt;strong&gt;waiting for memory buses to deliver data across disparate RAM addresses&lt;/strong&gt;. This phenomenon is known as &lt;strong&gt;pointer chasing&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Furthermore, maintaining this tree structure requires substantial metadata: child pointers, node capacities, and balancing flags. In practice, the index metadata alone often takes up more memory than the actual keys being indexed.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Paradigm Shift: Data is a Function
&lt;/h2&gt;

&lt;p&gt;What is a sorted list of numbers?&lt;/p&gt;

&lt;p&gt;Traditionally, we treat sorted data as an opaque collection of distinct items that must be compared one by one. But mathematically, a sorted array is simply a curve: a &lt;strong&gt;Cumulative Distribution Function (CDF)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you have an array of a million sorted items, the position of any item is roughly proportional to its value. &lt;/p&gt;

&lt;p&gt;In 2018, researchers at MIT and Google (Kraska et al.) asked a provocative question: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Why are we traversing an artificial tree of pointers when we could simply approximate the curve with a mathematical equation?&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you know the slope of the data, you don't need a tree. You can compute the memory address directly using basic algebra:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;y = ax + b&lt;/code&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  How a PGM-Index Actually Works
&lt;/h2&gt;

&lt;p&gt;Pure machine learning models like neural networks are often too slow and lack strict precision guarantees—you cannot afford to "guess roughly" where a database record lives.&lt;/p&gt;

&lt;p&gt;This is where the &lt;strong&gt;Piecewise Geometric Model (PGM)&lt;/strong&gt; comes in. It does not use neural networks; it uses formal geometry.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. The Error Corridor (ε)
&lt;/h3&gt;

&lt;p&gt;Instead of forcing a single complex curve over the entire dataset, a PGM index draws a series of simple linear segments over the data. &lt;/p&gt;

&lt;p&gt;As it scans through the sorted keys in a single pass, it maintains a narrow "corridor" of width ε (for example, 16 or 32 items wide). As long as the incoming data points stay within this corridor, the same straight line continues. The moment the data bends too far, the segment is sealed, and a new straight line begins.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Direct ALU Calculation
&lt;/h3&gt;

&lt;p&gt;When you query a key:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The CPU checks which segment covers the key (a trivial lookup across a tiny array of segments).&lt;/li&gt;
&lt;li&gt;It evaluates the linear equation &lt;code&gt;y = ax + b&lt;/code&gt; using single-cycle arithmetic instructions on the CPU ALU.&lt;/li&gt;
&lt;li&gt;The result is guaranteed by construction to be within ± ε of the true location.&lt;/li&gt;
&lt;li&gt;The CPU performs a tiny local search within that bounded window.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Because that local window is so small, &lt;strong&gt;the entire search window is already loaded in the CPU's L1 cache line&lt;/strong&gt;. The CPU never has to stall waiting for random memory jumps.&lt;/p&gt;




&lt;h2&gt;
  
  
  What This Implies in the Real World
&lt;/h2&gt;

&lt;p&gt;Replacing pointer traversal with affine approximations changes the fundamental economics of indexing:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Radical Memory Shrinkage
&lt;/h3&gt;

&lt;p&gt;In traditional database architectures, storing an index for a million items requires dozens of megabytes of pointer allocations. &lt;/p&gt;

&lt;p&gt;With a PGM index, smooth or predictable data (such as timestamps, auto-increment IDs, or sequential keys) can be modeled by just a few dozen linear equations. An index that previously consumed tens of megabytes shrinks down to a few kilobytes. &lt;/p&gt;

&lt;p&gt;The entire index can live permanently inside the CPU cache, leaving your RAM free for actual application data.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Predictable Low Latency
&lt;/h3&gt;

&lt;p&gt;Because lookups do not depend on walking an arbitrary tree structure, latency becomes deterministic. The CPU performs an ALU calculation, accesses contiguous memory, and finishes the search in a fraction of the time a traditional tree requires.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Lower Infrastructure Costs
&lt;/h3&gt;

&lt;p&gt;Memory is the single most expensive hardware component in large-scale database clusters. Dividing index memory footprints by orders of magnitude allows database nodes to hold significantly more data per machine before needing to scale out or page to disk.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Trade-offs: Where It Fits (and Where It Doesn't)
&lt;/h2&gt;

&lt;p&gt;Learned indexes are not a silver bullet that replaces B-Trees everywhere:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Where they shine&lt;/strong&gt;: Read-heavy workloads, append-only streams, and immutable storage blocks. In modern LSM-Tree storage engines like RocksDB or ClickHouse, data on disk is written once into immutable files (SSTables). Indexing these static blocks with a PGM index provides massive speed and memory benefits without any drawback.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Where B-Trees still hold ground&lt;/strong&gt;: Highly dynamic, random-write workloads with frequent in-place insertions and deletions. Updating a geometric segment on every individual insert requires buffering or rebuild strategies that traditional self-balancing trees handle naturally.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conclusion &amp;amp; Code
&lt;/h2&gt;

&lt;p&gt;Building this in Rust confirmed that modern performance engineering is less about micro-optimizing instructions and more about aligning algorithmic design with the physical realities of memory hierarchies.&lt;/p&gt;

&lt;p&gt;I packaged this implementation as an open-source, zero-dependency Rust crate with full reproducibility tests:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Repository&lt;/strong&gt;: &lt;a href="https://github.com/gilnett/learned_index_lab" rel="noopener noreferrer"&gt;https://github.com/gilnett/learned_index_lab&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Crate&lt;/strong&gt;: &lt;a href="https://crates.io/crates/learned_index_lab" rel="noopener noreferrer"&gt;https://crates.io/crates/learned_index_lab&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are building storage engines, analytical query tools, or high-throughput systems, functional data structures like learned indexes are well worth exploring.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>productivity</category>
      <category>opensource</category>
      <category>architecture</category>
    </item>
    <item>
      <title>wstrace: Linux strace for Windows (in Rust, Zero Drivers)</title>
      <dc:creator>gilnett</dc:creator>
      <pubDate>Sun, 11 Oct 2026 16:49:11 +0000</pubDate>
      <link>https://dev.to/gilnett/wstrace-linux-strace-for-windows-in-rust-zero-drivers-3gil</link>
      <guid>https://dev.to/gilnett/wstrace-linux-strace-for-windows-in-rust-zero-drivers-3gil</guid>
      <description>&lt;p&gt;Ever missed Linux's &lt;code&gt;strace&lt;/code&gt; when debugging on Windows?&lt;/p&gt;

&lt;p&gt;Tools like Sysinternals Process Monitor (ProcMon) are great, but heavy, GUI-only, or reliant on drivers.&lt;/p&gt;

&lt;p&gt;I built &lt;strong&gt;&lt;a href="https://github.com/gilnett/wstrace" rel="noopener noreferrer"&gt;wstrace&lt;/a&gt;&lt;/strong&gt;: a standalone system call and Win32 API monitor in Rust. It runs entirely in user-space using native ETW—&lt;strong&gt;zero kernel drivers required&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I just released &lt;strong&gt;v0.2.0&lt;/strong&gt;. Here is what is new:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;System-Wide Tracing (&lt;code&gt;wstrace all&lt;/code&gt;)&lt;/strong&gt;: Monitor events across the entire system simultaneously.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Output Modes&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Live Stream (&lt;code&gt;-m stream&lt;/code&gt;)&lt;/strong&gt;: Fast stdout terminal stream like Linux &lt;code&gt;strace&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interactive TUI (default)&lt;/strong&gt;: Real-time filtering, search, and clipboard export.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JSON Export (&lt;code&gt;--export-json &amp;lt;file&amp;gt;&lt;/code&gt;)&lt;/strong&gt;: Save captured session traces to a JSON file.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Windows on ARM64 Support&lt;/strong&gt;: Pre-compiled binaries available for both &lt;code&gt;x64&lt;/code&gt; and &lt;code&gt;ARM64&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;GitHub: &lt;strong&gt;&lt;a href="https://github.com/gilnett/wstrace" rel="noopener noreferrer"&gt;github.com/gilnett/wstrace&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>rust</category>
      <category>windows</category>
      <category>devtools</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Building wstrace: A Zero-Driver Windows System &amp; API Monitor in Rust</title>
      <dc:creator>gilnett</dc:creator>
      <pubDate>Fri, 09 Oct 2026 21:51:01 +0000</pubDate>
      <link>https://dev.to/gilnett/building-wstrace-a-zero-driver-windows-system-api-monitor-in-rust-4coa</link>
      <guid>https://dev.to/gilnett/building-wstrace-a-zero-driver-windows-system-api-monitor-in-rust-4coa</guid>
      <description>&lt;p&gt;I built &lt;strong&gt;&lt;a href="https://github.com/gilnett/wstrace" rel="noopener noreferrer"&gt;wstrace&lt;/a&gt;&lt;/strong&gt;, a lightweight terminal-first Windows system and API monitor written in Rust.&lt;/p&gt;

&lt;p&gt;I wanted a quick way to inspect Win32 APIs and syscalls directly from the terminal without needing to install or manage kernel drivers.&lt;/p&gt;

&lt;h3&gt;
  
  
  How it works
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;wstrace&lt;/code&gt; runs purely in user space by tapping into native Windows ETW (Event Tracing for Windows) and Win32 APIs. This keeps it safe, portable, and easy to run on any machine as a single &lt;code&gt;.exe&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It supports two workflows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Interactive TUI&lt;/strong&gt;: Built with Ratatui to navigate processes, search events, and filter activity live.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live stdout stream&lt;/strong&gt;: Outputs directly to the terminal for scripting and CI/CD pipelines.&lt;/li&gt;
&lt;/ul&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
powershell
# Example 1: Stream live execution to terminal
wstrace -m stream run myapp.exe

# Example 2: Attach to a running process and export to JSON
wstrace -m stream --export-json trace.json attach -n myapp.exe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>rust</category>
      <category>opensource</category>
      <category>cli</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
