uutils coreutils

repository·main·Indexed 12 days ago

https://github.com/uutils/coreutils

A cross-platform reimplementation of GNU coreutils written in Rust. It aims to be a drop-in replacement for GNU utilities, providing identical output and error codes with improved performance and internationalization support. Includes a differential fuzzing tool called uufuzz for comparing Rust implementations against reference GNU commands.

Tokens
83K
Snippets
345
Records
459
Agent score
97%

What's inside uutils coreutils

  1. Current feature status of uu_cp

    main

    The uu_cp utility (a Rust implementation of the cp command) tracks its feature parity with GNU cp through a list of completed and pending flags.

    Completed features include:

    • File handling: archive, attributes-only, backup, dereference, interactive, link, no-clobber, no-dereference, no-dereference-preserve-links, no-preserve, no-target-directory, one-file-system, parents, paths, preserve, preserve-default-attributes, recursive, reflink, remove-destination, strip-trailing-slashes, suffix, symbolic-link, target-directory, update, verbose.
    • Metadata/System: force (Note: Not implemented on Windows), remove-destination (Note: On Windows, only works for writeable files).
    • General: version.

    Planned/To Do features:

    • cli-symbolic-links
    • context
    • copy-contents
    • sparse
  2. Understand basenc performance characteristics and SIMD acceleration

    main

    uutils' basenc is designed for streaming encoding and decoding, which ensures constant maximum memory usage regardless of input size.

    Memory Usage

    • Release builds typically use less than 3 mebibytes of memory.
    • Memory usage exceeding 10 mebibytes is considered a bug.

    SIMD Acceleration

    Base64 operations utilize SIMD acceleration via the base64-simd crate, automatically detecting the best available CPU instructions (e.g., SSE2, SSSE3, SSE4.1, AVX2).

    Performance gains from SIMD:

    • Base64 encoding: ~3-4x faster than previous implementations.
    • Base64 decoding: ~4-5x faster than previous implementations.
    • Large files (4GB+): Approximately 1.77x faster than GNU coreutils base64.
  3. How yes is implemented for performance

    main

    The yes utility prints a provided string followed by a newline continuously.

    To achieve high throughput, yes avoids a simple println! loop, which is slow due to frequent write syscalls. Instead, it prints an extended string of several bytes per loop iteration to minimize the number of syscalls.

    On Linux, the implementation can further optimize performance by using tee() and splice() for non-pipe output. This avoids the overhead of copying content from RAM during read() and write() syscalls, allowing the utility to approach RAM's bandwidth limits.

  4. How dd operates and optimizes performance

    main

    The dd utility operates in a simple loop: it reads blocksize bytes from an input, optionally performs a conversion, and writes blocksize bytes to an output.

    Performance Optimization

    To achieve maximum throughput when copying files or writing to devices (like .iso files to drives), you should optimize the blocksize. Devices typically have an optimal block size; dd performs best when the blocksize is set to that optimal size or a multiple of it.

  5. Understand wc optimization strategies

    main

    The wc implementation uses different strategies depending on the requested flags to avoid unnecessary work:

    Counting bytes (-c)

    • File size: If a file is provided directly, wc attempts to read the file size from the filesystem without inspecting content.
    • splice(): On Linux, splice() can be used to get the input's length while discarding it directly. To test this, pipe uucat into wc: uucat somefile | wc -c.

    Counting lines (-l) and UTF-8 characters (-m)

    • If the flags are a subset of -clm, the input does not need to be decoded. The input is read in chunks, and the bytecount crate is used to count newlines and/or UTF-8 characters.

    Processing Unicode

    • This is the most general strategy required for counting words (-w), characters (-m), lines (-l), and maximum line length (-L). Individual steps are toggled based on the flags provided.
    • Note: Passing no flags is equivalent to passing -wcl.
  6. Understand uutils platform support tiers

    main

    uutils uses a two-tier system to define platform support and testing guarantees. This helps you understand the reliability of the utilities on your target system:

    • Tier 1: All applicable utilities are compiled and actively tested in the Continuous Integration (CI) pipeline for these platforms. These are the most reliable targets.
    • Tier 2: These platforms are supported, but they are not actively tested in CI. While the project accepts fixes for these platforms, you should expect less stability. Tier 2 includes untested variations of Tier 1 platforms, Redox OS, and BSDs like NetBSD and DragonFlyBSD.
  7. WASI limitations: Encoding and I/O

    main

    The WASI specification imposes specific constraints on data encoding and I/O operations that differ from standard Linux environments:

    • UTF-8 Requirement: All argv entries and filenames must be valid UTF-8. Tests using non-UTF-8 bytes in arguments or filenames are incompatible with WASI.
    • No FIFO/mkfifo: WASI does not support the creation or opening of FIFOs (named pipes). Any test utilizing mkfifo is skipped.
    • No Pipes or Signals: WASI lacks support for Unix signals (e.g., SIGPIPE) and pipe creation. Tests relying on broken pipe detection or pipe-based I/O are skipped.
    • No Subprocess Spawning: WASI cannot spawn child processes. Tests that attempt to shell out to other commands or invoke a second binary are skipped.
    • Stdin Seek Behavior: When stdin is a seekable file, wasmtime does not preserve the file position between the host and the guest. This affects tests validating stdin offset behavior (e.g., after a head command read).
  8. Optimization techniques used in uu_seq

    main

    The uu_seq implementation employs several optimization strategies to achieve performance parity with GNU seq:

    • Buffering stdout: Wrapping stdout in a BufWriter prevents excessive system calls caused by unbuffered writes.
    • Direct string printing: Using stdout.write_all(separator.as_bytes())? is faster than using the write! macro with formatting for simple separators.
    • Fast increment path: For positive integer values with default formatting, uu_seq uses a custom fast path that performs arithmetic directly on u8 arrays (strings) instead of calling the formatting engine. This provides a 10-20x performance gain and supports large increments and equal width.
  9. Proposed performance testing via simulation (Wishlist)

    main

    Because real-world hardware measurements are difficult to reproduce in CI environments, there is a proposal to use CPU simulation for performance regression testing.

    Instead of measuring wall-clock time, the goal is to use tools like [cachegrind] to measure execution "time" in a simulated model. In the Rust ecosystem, [iai] is the recommended implementation for this approach.

  10. Guidelines for designing `factor` microbenchmarks

    main

    When adding new microbenchmarks to factor, follow these specific design principles based on Daniel Lemire's methodology:

    1. Select small, self-contained, deterministic components:
      • Avoid I/O or external data structures.
      • Avoid calls into other components.
      • Ensure behavior is deterministic (no RNG, no concurrency).
      • Target fast execution times (e.g., ~100ns for gcd, ~10µs for factor::table) to maximize sample counts and minimize variability.
    2. Maintain immutability: Benchmarks are immutable once merged. If you must modify an existing benchmark, rename it to avoid comparing new logic against old, incompatible collected values.
    3. Test common cases: Use reproducibly-randomized inputs sampled from the full input space or a specific subset of interest to measure overall performance rather than edge cases.
    4. Use criterion: Utilize the [criterion] framework and criterion::black_box rather than ad-hoc measurement solutions.
  11. Understand locale file resolution and paths

    main

    The location of Fluent (.ftl) files depends on your build mode:

    Development Mode (debug_assertions enabled)

    Paths are resolved relative to the crate source: $CARGO_MANIFEST_DIR/../uu/<utility>/locales/

    Release Mode

    Paths are resolved relative to the executable or standard system paths:

    • <executable_dir>/locales/<utility>/
    • <prefix>/share/locales/<utility>/
    • ~/.local/share/coreutils/locales/<utility>/
    • ~/.cargo/share/coreutils/locales/<utility>/
    • /usr/share/coreutils/locales/<utility>/

    If external files are not found in these locations, the system falls back to the embedded English locales.