sonic-rs Documentation

repository·main·Indexed 21 days ago

https://github.com/cloudwego/sonic-rs

A high-performance Rust JSON library based on SIMD instructions for accelerated parsing and serialization. It provides a faster alternative to serde_json and simd-json by utilizing memory arenas and direct parsing into Rust structs. Key features include Serde integration, untyped JSON manipulation via sonic_rs::Value, high-performance field access with JSON pointers, and lossless precision via RawNumber. The project also includes sonic_number for fast numeric parsing and sonic_simd for portable SIMD APIs across x86, ARM, and WASM.

Tokens
27.5K
Snippets
84
Records
123
Agent score
74%

What's inside sonic-rs

  1. Overview of sonic_simd

    main

    sonic_simd is a portable SIMD (Single Instruction, Multiple Data) library designed to provide low-level SIMD APIs across multiple architectures. It is intended for high-performance computing tasks that require hardware acceleration.

    Supported architectures:

    • x86
    • ARM
    • WASM (WebAssembly)

    For platforms not explicitly supported, the library provides a fallback scalar implementation to ensure code portability and correctness even without hardware acceleration.

  2. Overview of sonic-rs features

    main

    sonic-rs is a fast Rust JSON library based on SIMD. Key features include:

    • Serde Integration: Supports deserializing JSON into Rust structs using serde and serde_json patterns.
    • Untyped JSON: Parse and serialize JSON into a mutable, untyped sonic_rs::Value.
    • High-Performance Field Access: Quickly retrieve specific fields from JSON.
    • Lazy Iteration: Use JSON as a lazy array or object iterator.
    • Specialized Types: Supports LazyValue, Number, and RawNumber (similar to Golang's JsonNumber) by default.
    • Precision: Floating-point parsing precision matches Rust std by default.
  3. Overview of sonic-rs bindings

    main

    The sonic-rs repository provides a collection of bindings for the core sonic-rs library. These bindings allow different interfaces to interact with the high-performance JSON processing engine.

    Key components include:

    • ffi: Low-level APIs for sonic-rs. Warning: These should not be used directly by most developers as they are intended for low-level foreign function interface integration.
    • Other bindings: (The provided content indicates other bindings exist, but specific details for them were not included in this segment).
  4. Core features of sonic-rs

    main

    sonic-rs is a high-performance SIMD-based JSON library with the following capabilities:

    1. Serialization/Deserialization to Structs: Compatible with serde and serde_json traits.
    2. Document Manipulation: Supports serialization/deserialization to a mutable document data structure.
    3. Field Extraction: Ability to get specific fields directly from JSON.
    4. Lazy Iteration: Parse JSON into lazy iterators.
    5. Numeric Handling: Supports LazyValue, Number, and RawNumber (similar to Golang's JsonNumber) by default. Floating-point precision is aligned with the Rust standard library.
    6. SIMD Optimizations: SIMD is specifically used for:
      • Parsing/serializing long JSON strings.
      • Parsing the fractional part of floating-point numbers.
      • Extracting specific elements or fields.
      • Skipping whitespace during parsing.
  5. Performance Optimization Details in Sonic-rs

    main

    Sonic-rs achieves high performance through several low-level optimizations, primarily leveraging SIMD (Single Instruction, Multiple Data) instructions and efficient memory management. Key optimization areas include:

    • On-demand Parsing: Uses SIMD to calculate string bitmaps and skip JSON containers (objects and arrays) by matching bracket counts while respecting escaped characters.
    • SIMD-accelerated Space Skipping: Rapidly skips whitespace ( , \n, \r, \t) using SIMD bitmasks and optimized fast paths for compact or single-space JSON.
    • SIMD Floating-Point Parsing: Accelerates the parsing of floating-point numbers (especially those with long mantissas) by processing ASCII digits in batches.
    • SIMD JSON String Serialization: Uses a 'copy and find' algorithm to quickly copy long strings and only handle escaping when necessary.
    • Memory Pool Allocator: Utilizes an Arena-based allocation strategy (via the bump crate) to pre-allocate memory for the entire JSON document, reducing allocation overhead and improving cache locality.
  6. How SIMD is used for Floating-Point Parsing

    main

    Floating-point parsing is a known bottleneck in JSON parsing. Sonic-rs optimizes this by using SIMD to process ASCII digit characters in batches (e.g., for 16-character digit strings).

    For 64-bit floats (IEEE754), the parser focuses on the 17 significant digits. It uses a switch table to reduce the number of unnecessary SIMD instructions, accelerating the conversion of ASCII digits to numeric values.

  7. How sonic-rs handles document parsing

    main

    When parsing JSON into a document (using sonic_rs::Value), sonic-rs employs several optimizations to outperform other libraries like simd-json:

    • No Intermediate Structures: Unlike simd-json, which parses JSON into a tape before converting to a Rust structure, sonic-rs parses directly into the target structure.
    • Memory Pooling: It uses a memory pool for the entire document, reducing allocations and improving cache friendliness.
    • Efficient Object Representation: For JSON objects, the underlying structure is an array of Key-Value pairs rather than a HashMap or BTreeMap, avoiding the overhead of building a hash table.
  8. How SIMD is used for JSON String Serialization

    main

    When serializing long JSON strings, Sonic-rs employs a 'copy and find' algorithm:

    1. It copies a chunk of the raw string (e.g., 32 bytes) using SIMD.
    2. It uses an escaped_mask to check if any characters in that chunk require escaping (like " or \).
    3. If the mask is zero (no characters need escaping), it moves to the next chunk immediately.
    4. If the mask is non-zero, it identifies the specific character position and handles the escaping logic before continuing.
    // Simplified logic of the copy-and-find algorithm
    while nb >= LANS {
        let v = u8x32::from_slice_unaligned_unchecked(raw);
        v.write_to_slice_unaligned_unchecked(dest);
        let mask = escaped_mask(v);
        if mask == 0 {
            // Fast path: no escaping needed
            nb -= LANS;
            // ... advance pointers ...
        } else {
            // Slow path: handle escaping
            // ... 
        }
    }
  9. How on-demand JSON parsing works

    main

    Sonic-rs optimizes performance by parsing JSON on-demand, which focuses on skipping unnecessary fields without fully traversing the entire structure.

    To skip large JSON containers (Objects or Arrays) efficiently, the library uses a SIMD-accelerated algorithm that:

    1. Calculates a bitmask (instring) to identify bytes inside JSON strings, accounting for escaped characters (e.g., " or \).
    2. Uses bracket matching by XORing the instring mask with the bracket bitmap ([] or {}).
    3. Tracks the count of left and right brackets to identify when a container has closed, allowing the parser to jump directly to the end of the container.
  10. How space skipping is optimized with SIMD

    main

    Sonic-rs uses SIMD instructions to skip whitespace characters ( , \n, \r, \t) in JSON. It employs two primary optimization paths:

    1. Fast Path for Compact/Single Space JSON: For common patterns like "name": "value", the parser checks the next character immediately to avoid heavy SIMD computation.
    2. Bitmap Reuse: For 'pretty' formatted JSON, the parser saves the calculated non-space character bitmap. If the next non-space character is within 64 bytes of the previous skip, it reuses the existing bitmap to avoid redundant SIMD calculations.

    This approach minimizes the overhead of whitespace handling in both compact and human-readable JSON formats.

  11. SIMD-accelerated JSON string serialization

    main

    When serializing long JSON strings, sonic-rs implements a copy and find algorithm using SIMD.

    Instead of checking every character for escaping, the library copies large chunks (e.g., 32 bytes) of the string into the destination buffer using SIMD. It then uses a mask to check if any characters in that chunk require escaping. If no escaped characters are found in the chunk, it moves to the next block immediately. If an escaped character is detected, it falls back to a manual escape routine for that specific segment.

        while nb >= LANS {
            // copy from the JSON string
            let v = {
                let raw = std::slice::from_raw_parts(sptr, LANS);
                u8x32::from_slice_unaligned_unchecked(raw)
            };
            v.write_to_slice_unaligned_unchecked(std::slice::from_raw_parts_mut(dptr, LANS));
            // if find the escaped character, then deal with it
            let mask = escaped_mask(v);
            if mask == 0 {
                nb -= LANS;
                dptr = dptr.add(LANS);
                sptr = sptr.add(LANS);
            } else {
                let cn = mask.trailing_zeros() as usize;
                nb -= cn;
                dptr = dptr.add(cn);
                sptr = sptr.add(cn);
                escape_unchecked(&mut sptr, &mut nb, &mut dptr);
            }
        }