diff --git a/.cargo/config.toml b/.cargo/config.toml deleted file mode 100644 index b7efcee..0000000 --- a/.cargo/config.toml +++ /dev/null @@ -1,4 +0,0 @@ -# https://github.com/rui314/mold?tab=readme-ov-file#how-to-use -[target.'cfg(target_os = "linux")'] -linker = "clang" -rustflags = ["-C", "link-arg=-fuse-ld=mold"] diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index a1067c4..0000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,14 +0,0 @@ -version: 2 -updates: - # Update Cargo deps - - package-ecosystem: cargo - directory: "/" - schedule: - interval: "weekly" - - # Update used workflows - - package-ecosystem: github-actions - directory: "/" - schedule: - interval: daily - diff --git a/.github/workflows/hotpath-comment.yml b/.github/workflows/hotpath-comment.yml index ebeb924..8f83d00 100644 --- a/.github/workflows/hotpath-comment.yml +++ b/.github/workflows/hotpath-comment.yml @@ -1,13 +1,12 @@ -name: hotpath-comment +name: Hotpath Comment on: workflow_run: - workflows: ["hotpath-profile"] + workflows: ["Hotpath Profile"] types: - completed permissions: - contents: read pull-requests: write jobs: @@ -16,17 +15,17 @@ jobs: if: ${{ github.event.workflow_run.conclusion == 'success' }} steps: - - name: Checkout - uses: actions/checkout@v6 - - name: Download profiling results - uses: actions/download-artifact@v6 + uses: actions/download-artifact@v4 with: name: hotpath-results - path: /tmp/ github-token: ${{ secrets.GITHUB_TOKEN }} run-id: ${{ github.event.workflow_run.id }} + - name: Read PR number + id: pr + run: echo "number=$(cat pr_number.txt)" >> $GITHUB_OUTPUT + - name: Setup Rust uses: actions-rust-lang/setup-rust-toolchain@v1 @@ -34,29 +33,17 @@ jobs: run: cargo install hotpath - name: Post timing comparison comment - env: - GH_TOKEN: ${{ github.token }} - run: | - set -euo pipefail - HEAD_METRICS=$(cat /tmp/head_timing.json) - BASE_METRICS=$(cat /tmp/base_timing.json) - PR_NUMBER=$(cat /tmp/pr_number.txt) - hotpath profile-pr \ - --head-metrics "$HEAD_METRICS" \ - --base-metrics "$BASE_METRICS" \ - --github-token "$GH_TOKEN" \ - --pr-number "$PR_NUMBER" + run: | + hotpath profile-pr \ + --head-metrics head-timing.json \ + --base-metrics base-timing.json \ + --github-token ${{ secrets.GITHUB_TOKEN }} \ + --pr-number ${{ steps.pr.outputs.number }} - - name: Post allocation comparison comment - env: - GH_TOKEN: ${{ github.token }} - run: | - set -euo pipefail - HEAD_METRICS=$(cat /tmp/head_alloc.json) - BASE_METRICS=$(cat /tmp/base_alloc.json) - PR_NUMBER=$(cat /tmp/pr_number.txt) - hotpath profile-pr \ - --head-metrics "$HEAD_METRICS" \ - --base-metrics "$BASE_METRICS" \ - --github-token "$GH_TOKEN" \ - --pr-number "$PR_NUMBER" + - name: Post allocation comparison comment + run: | + hotpath profile-pr \ + --head-metrics head-alloc.json \ + --base-metrics base-alloc.json \ + --github-token ${{ secrets.GITHUB_TOKEN }} \ + --pr-number ${{ steps.pr.outputs.number }} diff --git a/.github/workflows/hotpath-profile.yml b/.github/workflows/hotpath-profile.yml index eeca3ec..b367ca2 100644 --- a/.github/workflows/hotpath-profile.yml +++ b/.github/workflows/hotpath-profile.yml @@ -1,4 +1,4 @@ -name: hotpath-profile +name: Hotpath Profile on: pull_request: @@ -13,9 +13,7 @@ jobs: steps: - name: Checkout PR HEAD - uses: actions/checkout@v6 - with: - fetch-depth: 0 + uses: actions/checkout@v4 - name: Setup Rust uses: actions-rust-lang/setup-rust-toolchain@v1 @@ -24,42 +22,42 @@ jobs: env: HOTPATH_JSON: "true" run: | - cargo run --features='hotpath' 2>&1 | grep '^{"hotpath_profiling_mode"' > /tmp/head_timing.json + cargo run --features='hotpath' 2>&1 | grep '^{"hotpath_profiling_mode"' > head-timing.json - name: Run allocation profiling on HEAD env: HOTPATH_JSON: "true" run: | - cargo run --features='hotpath,hotpath-alloc' 2>&1 | grep '^{"hotpath_profiling_mode"' > /tmp/head_alloc.json + cargo run --features='hotpath,hotpath-alloc-count-total' 2>&1 | grep '^{"hotpath_profiling_mode"' > head-alloc.json - name: Checkout base branch - run: | - git checkout ${{ github.event.pull_request.base.sha }} + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.base.sha }} - name: Run timing profiling on base env: HOTPATH_JSON: "true" run: | - cargo run --features='hotpath' 2>&1 | grep '^{"hotpath_profiling_mode"' > /tmp/base_timing.json || echo '{}' > /tmp/base_timing.json + cargo run --features='hotpath' 2>&1 | grep '^{"hotpath_profiling_mode"' > base-timing.json - name: Run allocation profiling on base env: HOTPATH_JSON: "true" run: | - cargo run --features='hotpath,hotpath-alloc' 2>&1 | grep '^{"hotpath_profiling_mode"' > /tmp/base_alloc.json || echo '{}' > /tmp/base_alloc.json + cargo run --features='hotpath,hotpath-alloc-count-total' 2>&1 | grep '^{"hotpath_profiling_mode"' > base-alloc.json - name: Save PR number - run: | - echo '${{ github.event.pull_request.number }}' > /tmp/pr_number.txt + run: echo "${{ github.event.number }}" > pr_number.txt - name: Upload profiling results - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v4 with: name: hotpath-results path: | - /tmp/head_timing.json - /tmp/head_alloc.json - /tmp/base_timing.json - /tmp/base_alloc.json - /tmp/pr_number.txt + head-timing.json + head-alloc.json + base-timing.json + base-alloc.json + pr_number.txt retention-days: 1 diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 5f435fb..e87e1da 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -10,45 +10,12 @@ env: CARGO_TERM_COLOR: always jobs: - test: - name: Test on ${{ matrix.target }} - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - include: - - os: ubuntu-latest - target: x86_64-unknown-linux-gnu - - os: ubuntu-latest - target: aarch64-unknown-linux-gnu + build: + + runs-on: ubuntu-latest steps: - name: "Checkout" - uses: actions/checkout@v6 - - - name: "Setup Rust toolchain" - uses: actions-rust-lang/setup-rust-toolchain@v1 - with: - target: ${{ matrix.target }} - - - name: "Install cross-compilation tools" - if: matrix.target == 'aarch64-unknown-linux-gnu' - run: | - sudo apt-get update - sudo apt-get install -y gcc-aarch64-linux-gnu - - - name: "Configure linker for aarch64" - if: matrix.target == 'aarch64-unknown-linux-gnu' - run: | - mkdir -p .cargo - cat >> .cargo/config.toml << EOF - [target.aarch64-unknown-linux-gnu] - linker = "aarch64-linux-gnu-gcc" - EOF - - - name: "Build" - run: cargo build --verbose --target ${{ matrix.target }} - - - name: "Run tests" - if: matrix.target == 'x86_64-unknown-linux-gnu' - run: cargo test --verbose --target ${{ matrix.target }} + uses: actions/checkout@v4 + - name: "Build with Cargo" + run: cargo build --verbose diff --git a/Cargo.lock b/Cargo.lock index 3a23f75..0147746 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,15 +17,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "alloca" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5a7d05ea6aea7e9e64d25b9156ba2fee3fdd659e34e41063cd2fc7cd020d7f4" -dependencies = [ - "cc", -] - [[package]] name = "anes" version = "0.1.6" @@ -280,11 +271,10 @@ dependencies = [ [[package]] name = "criterion" -version = "0.8.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0dfe5e9e71bdcf4e4954f7d14da74d1cdb92a3a07686452d1509652684b1aab" +checksum = "e1c047a62b0cc3e145fa84415a3191f628e980b194c2755aa12300a4e6cbd928" dependencies = [ - "alloca", "anes", "cast", "ciborium", @@ -293,7 +283,6 @@ dependencies = [ "itertools", "num-traits", "oorandom", - "page_size", "plotters", "rayon", "regex", @@ -305,9 +294,9 @@ dependencies = [ [[package]] name = "criterion-plot" -version = "0.8.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5de36c2bee19fba779808f92bf5d9b0fa5a40095c277aba10c458a12b35d21d6" +checksum = "9b1bcc0dc7dfae599d84ad0b1a55f80cde8af3725da8313b528da95ef783e338" dependencies = [ "cast", "itertools", @@ -462,50 +451,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "futures-core" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" - -[[package]] -name = "futures-macro" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "futures-sink" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" - -[[package]] -name = "futures-task" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" - -[[package]] -name = "futures-util" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" -dependencies = [ - "futures-core", - "futures-macro", - "futures-sink", - "futures-task", - "pin-project-lite", - "pin-utils", - "slab", -] - [[package]] name = "getrandom" version = "0.2.16" @@ -557,9 +502,9 @@ checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" [[package]] name = "hotpath" -version = "0.7.5" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08382b985a19a79d95d35e2e201b02cc4b99efe2f47d82f3fd4301bb0005bb68" +checksum = "ef44238d7007bbd3c41ce7dbf3d7a4fb224bbf70d6cf3162479138dda0cd6a9e" dependencies = [ "arc-swap", "base64", @@ -568,15 +513,10 @@ dependencies = [ "colored", "crossbeam-channel", "eyre", - "futures-util", "hdrhistogram", "hotpath-macros", - "libc", - "mach2", - "pin-project-lite", "prettytable-rs", "quanta", - "regex", "serde", "serde_json", "tiny_http", @@ -586,9 +526,9 @@ dependencies = [ [[package]] name = "hotpath-macros" -version = "0.7.5" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d618063f89423ebe079a69f5435a13d4909219d4e359757118b75fd05ae65d0" +checksum = "9e7e3443c6f4e5cc69e6b701f7bfca8a5502f0080e94629413346e7b4518d730" dependencies = [ "proc-macro2", "quote", @@ -818,12 +758,6 @@ version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" -[[package]] -name = "mach2" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dae608c151f68243f2b000364e1f7b186d9c29845f7d2d85bd31b9ad77ad552b" - [[package]] name = "memchr" version = "2.7.4" @@ -832,7 +766,7 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "microfetch" -version = "0.4.12" +version = "0.4.11" dependencies = [ "criterion", "hotpath", @@ -882,16 +816,6 @@ version = "11.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" -[[package]] -name = "page_size" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30d5b2194ed13191c1999ae0704b7839fb18384fa22e49b57eeaa97d79ce40da" -dependencies = [ - "libc", - "winapi", -] - [[package]] name = "percent-encoding" version = "2.3.2" @@ -904,12 +828,6 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - [[package]] name = "plotters" version = "0.3.7" @@ -1182,12 +1100,6 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" -[[package]] -name = "slab" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" - [[package]] name = "smallvec" version = "1.15.1" diff --git a/Cargo.toml b/Cargo.toml index c245c00..e95ef5c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "microfetch" -version = "0.4.12" +version = "0.4.11" edition = "2024" [lib] @@ -12,16 +12,17 @@ name = "microfetch" path = "src/main.rs" [dependencies] -hotpath = { optional = true, version = "0.7.5" } +hotpath = { optional = true, version = "0.6.0" } libc = "0.2.177" [dev-dependencies] -criterion = "0.8.0" +criterion = "0.7" [features] -hotpath = [ "dep:hotpath", "hotpath/hotpath" ] -hotpath-alloc = [ "hotpath/hotpath-alloc" ] -hotpath-off = [ "hotpath/hotpath-off" ] +hotpath = [ "dep:hotpath", "hotpath/hotpath" ] +hotpath-alloc-bytes-total = [ "hotpath/hotpath-alloc-bytes-total" ] +hotpath-alloc-count-total = [ "hotpath/hotpath-alloc-count-total" ] +hotpath-off = [ "hotpath/hotpath-off" ] [[bench]] harness = false diff --git a/README.md b/README.md index f148a61..a40e444 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ on your system: it is pretty _[fast](#benchmarks)_... - Fast - Really fast - Minimal dependencies -- Tiny binary (~370kb [^1]) +- Tiny binary (~370kb) - Actually really fast - Cool NixOS logo (other, inferior, distros are not supported) - Reliable detection of following info: @@ -60,9 +60,6 @@ on your system: it is pretty _[fast](#benchmarks)_... - Did I mention fast? - Respects [`NO_COLOR` spec](https://no-color.org/) -[^1]: With the Mold linker, which is enabled by default in the Flake package, - the binary size is roughly 350kb. That's nearly 20kb reduction in size :) - ## Motivation Fastfetch, as its name probably hinted, is a very fast fetch tool written in C. @@ -85,14 +82,11 @@ Nixpkgs, you are recommended to use it to utilize the binary cache properly. The usage of Rust _is_ nice, however, since it provides us with incredible tooling and a very powerful language that allows for Microfetch to be as fast as possible. Sure C could've been used here as well, but do you think I hate -myself? +myself? [^1] -> [!IMPORTANT] -> **Update as of November 30th, 2025**: -> -> Microfetch now inlines handwritten assembly for even better performance. I -> know I previously said I do not hate myself but I'm beginning to suspect this -> is no longer the case. Enjoy the performance benefits! +[^1]: Okay, maybe a little bit. One of the future goals of Microfetch is to + defer to inline Assembly for the costliest functions, but that's for a + future date and until I do that I can pretend to be sane. ## Benchmarks @@ -154,7 +148,7 @@ HOTPATH_JSON=true cargo run --features=hotpath To profile allocations: ```bash -HOTPATH_JSON=true cargo run --features=hotpath,hotpath-alloc +HOTPATH_JSON=true cargo run --features=hotpath,hotpath-alloc-count-total ``` The JSON output can be analyzed with the `hotpath` CLI tool for detailed diff --git a/flake.nix b/flake.nix index 90978a2..ed36872 100644 --- a/flake.nix +++ b/flake.nix @@ -10,12 +10,9 @@ forEachSystem = nixpkgs.lib.genAttrs systems; pkgsForEach = nixpkgs.legacyPackages; in { - packages = forEachSystem (system: let - pkgs = pkgsForEach.${system}; - in { + packages = forEachSystem (system: { default = self.packages.${system}.microfetch; - microfetch = pkgs.callPackage ./nix/package.nix {}; - microfetch-mold = pkgs.callPackage ./nix/package.nix {useMold = true;}; + microfetch = pkgsForEach.${system}.callPackage ./nix/package.nix {}; }); devShells = forEachSystem (system: { diff --git a/nix/package.nix b/nix/package.nix index 052f576..dca3cc2 100644 --- a/nix/package.nix +++ b/nix/package.nix @@ -1,22 +1,14 @@ { lib, - stdenv, - stdenvAdapters, rustPlatform, + stdenvAdapters, llvm, - useMold ? stdenv.isLinux && !stdenv.hostPlatform.isAarch, }: let toml = (lib.importTOML ../Cargo.toml).package; pname = toml.name; inherit (toml) version; - - # Select stdenv based on useMold flag - stdenv = - if useMold - then stdenvAdapters.useMoldLinker llvm.stdenv - else llvm.stdenv; in - rustPlatform.buildRustPackage.override {inherit stdenv;} { + rustPlatform.buildRustPackage.override {stdenv = stdenvAdapters.useMoldLinker llvm.stdenv;} { inherit pname version; src = let fs = lib.fileset; @@ -34,14 +26,7 @@ in cargoLock.lockFile = ../Cargo.lock; enableParallelBuilding = true; - buildNoDefaultFeatures = true; - doCheck = false; - - # Only set RUSTFLAGS for mold if useMold is enabled - env = lib.optionalAttrs useMold { - CARGO_LINKER = "clang"; - RUSTFLAGS = "-C link-arg=-fuse-ld=mold"; - }; + env.RUSTFLAGS = "-C link-arg=-fuse-ld=mold"; meta = { description = "Microscopic fetch script in Rust, for NixOS systems"; diff --git a/nix/shell.nix b/nix/shell.nix index ae65e10..111b803 100644 --- a/nix/shell.nix +++ b/nix/shell.nix @@ -1,31 +1,27 @@ { mkShell, - cargo, - rustc, - mold, - clang, rust-analyzer-unwrapped, rustfmt, clippy, + cargo, taplo, + rustc, rustPlatform, gnuplot, }: mkShell { - name = "microfetch"; strictDeps = true; + nativeBuildInputs = [ cargo rustc - mold - clang rust-analyzer-unwrapped (rustfmt.override {asNightly = true;}) clippy taplo - gnuplot # for Criterion.rs plots + gnuplot # For Criterion.rs plots ]; env.RUST_SRC_PATH = "${rustPlatform.rustLibSrc}"; diff --git a/src/lib.rs b/src/lib.rs index 1e0f9f3..8c8a6ba 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,8 +14,7 @@ impl UtsName { /// Calls `uname` syscall and returns a `UtsName` wrapper /// /// # Errors - /// - /// Returns an error if the `uname` syscall fails + /// Returns an error if the uname syscall fails pub fn uname() -> Result { let mut uts = MaybeUninit::uninit(); if unsafe { libc::uname(uts.as_mut_ptr()) } != 0 { diff --git a/src/syscall.rs b/src/syscall.rs index 0c8634b..2776fe7 100644 --- a/src/syscall.rs +++ b/src/syscall.rs @@ -11,15 +11,11 @@ use std::io; /// Direct syscall to open a file -/// -/// # Returns -/// -/// File descriptor or -1 on error +/// Returns file descriptor or -1 on error /// /// # Safety /// /// The caller must ensure: -/// /// - `path` points to a valid null-terminated C string /// - The pointer remains valid for the duration of the syscall #[inline] @@ -69,10 +65,7 @@ pub unsafe fn sys_open(path: *const u8, flags: i32) -> i32 { } /// Direct syscall to read from a file descriptor -/// -/// # Returns n -/// -/// Number of bytes read or -1 on error +/// Returns number of bytes read or -1 on error /// /// # Safety /// diff --git a/src/uptime.rs b/src/uptime.rs index 095af7d..98c9207 100644 --- a/src/uptime.rs +++ b/src/uptime.rs @@ -1,6 +1,6 @@ use std::{io, mem::MaybeUninit}; -/// Faster integer to string conversion without the formatting overhead. +/// Fast integer to string conversion (no formatting overhead) #[inline] fn itoa(mut n: u64, buf: &mut [u8]) -> &str { if n == 0 { @@ -17,10 +17,9 @@ fn itoa(mut n: u64, buf: &mut [u8]) -> &str { unsafe { std::str::from_utf8_unchecked(&buf[i..]) } } -/// Direct `sysinfo` syscall using inline assembly +/// Direct sysinfo syscall using inline assembly /// /// # Safety -/// /// This function uses inline assembly to make a direct syscall. /// The caller must ensure the sysinfo pointer is valid. #[inline]