Compare commits

...

18 commits

Author SHA1 Message Date
8c32f5f408
nix: build with Mold linker on x86_64-linux
Some checks are pending
Rust / Test on aarch64-unknown-linux-gnu (push) Waiting to run
Rust / Test on x86_64-unknown-linux-gnu (push) Waiting to run
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I771c36297577aba189058a2183ec2b4a6a6a6964
2025-11-30 17:26:50 +03:00
3ad14a95a6
meta: build with Mold linker on x86_64 Linux
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Id51e62dda1ec2ba895ffdbbd25c2f1256a6a6964
2025-11-30 17:26:49 +03:00
raf
7683e6dfcf
Merge pull request #26 from NotAShelf/dependabot/github_actions/actions/download-artifact-6
chore(deps): bump actions/download-artifact from 4 to 6
2025-11-30 17:03:18 +03:00
raf
96b02c9ed9
Merge pull request #27 from NotAShelf/dependabot/github_actions/actions/upload-artifact-5
chore(deps): bump actions/upload-artifact from 4 to 5
2025-11-30 17:03:11 +03:00
raf
6666644d3a
Merge pull request #28 from NotAShelf/dependabot/github_actions/actions/checkout-6
chore(deps): bump actions/checkout from 4 to 6
2025-11-30 17:03:04 +03:00
ff8af87747
chore: tag 0.4.12
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I54a5f2181efdd42af2fda7cebb88484f6a6a6964
2025-11-30 17:02:31 +03:00
dependabot[bot]
d2a981b070
chore(deps): bump actions/checkout from 4 to 6
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-30 14:01:31 +00:00
dependabot[bot]
5c23cb2665
chore(deps): bump actions/upload-artifact from 4 to 5
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 5.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-30 14:01:27 +00:00
dependabot[bot]
5196ced487
chore(deps): bump actions/download-artifact from 4 to 6
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 4 to 6.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v4...v6)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-30 14:01:24 +00:00
raf
858b2487c4
Merge pull request #25 from NotAShelf/notashelf/push-orrzkvopklqm
treewide: bump deps and update docs
2025-11-30 17:00:52 +03:00
fa8b6b9d68
ci: set up cross comp for Rust builds
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I154d2afb05088e22882985bcd4536f026a6a6964
2025-11-30 16:57:12 +03:00
16a1d5fe3f
ci: set up dependabot for GH actions
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I890272e62db5824a3d866748375d1a9f6a6a6964
2025-11-30 16:55:09 +03:00
8d97a9e8ec
ci: streamline workflows; remove tagged release workflow
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I1432980533dee11b64a53d2ad2f2094d6a6a6964
2025-11-30 15:38:48 +03:00
48c3807148
docs: update hotpath usage instructions
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I8a056b6814bef36e74b4aca56d4aa2686a6a6964
2025-11-30 15:16:03 +03:00
09da1c27d2
chore: bump hotpath
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I1ae1d9b3d25ff220bee51660efc598b76a6a6964
2025-11-30 15:16:02 +03:00
c1a4bc24f4
docs: add note about handwritten assembly
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I6920a416e6169a84469514bae0f207426a6a6964
2025-11-30 15:16:01 +03:00
c3a6d1c93c
treewide: fix commonmark formatting in Rustdoc
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Ie1a13221aded56f903156fdb35abe2ac6a6a6964
2025-11-30 15:16:00 +03:00
6d6ee838bf
chore: bump criterion
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I5623347364c5ed71c99676029f4261026a6a6964
2025-11-30 15:15:59 +03:00
14 changed files with 268 additions and 78 deletions

4
.cargo/config.toml Normal file
View file

@ -0,0 +1,4 @@
# 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"]

14
.github/dependabot.yml vendored Normal file
View file

@ -0,0 +1,14 @@
version: 2
updates:
# Update Cargo deps
- package-ecosystem: cargo
directory: "/"
schedule:
interval: "weekly"
# Update used workflows
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: daily

View file

@ -1,12 +1,13 @@
name: Hotpath Comment name: hotpath-comment
on: on:
workflow_run: workflow_run:
workflows: ["Hotpath Profile"] workflows: ["hotpath-profile"]
types: types:
- completed - completed
permissions: permissions:
contents: read
pull-requests: write pull-requests: write
jobs: jobs:
@ -15,17 +16,17 @@ jobs:
if: ${{ github.event.workflow_run.conclusion == 'success' }} if: ${{ github.event.workflow_run.conclusion == 'success' }}
steps: steps:
- name: Checkout
uses: actions/checkout@v6
- name: Download profiling results - name: Download profiling results
uses: actions/download-artifact@v4 uses: actions/download-artifact@v6
with: with:
name: hotpath-results name: hotpath-results
path: /tmp/
github-token: ${{ secrets.GITHUB_TOKEN }} github-token: ${{ secrets.GITHUB_TOKEN }}
run-id: ${{ github.event.workflow_run.id }} 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 - name: Setup Rust
uses: actions-rust-lang/setup-rust-toolchain@v1 uses: actions-rust-lang/setup-rust-toolchain@v1
@ -33,17 +34,29 @@ jobs:
run: cargo install hotpath run: cargo install hotpath
- name: Post timing comparison comment - name: Post timing comparison comment
run: | env:
hotpath profile-pr \ GH_TOKEN: ${{ github.token }}
--head-metrics head-timing.json \ run: |
--base-metrics base-timing.json \ set -euo pipefail
--github-token ${{ secrets.GITHUB_TOKEN }} \ HEAD_METRICS=$(cat /tmp/head_timing.json)
--pr-number ${{ steps.pr.outputs.number }} 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"
- name: Post allocation comparison comment - name: Post allocation comparison comment
run: | env:
hotpath profile-pr \ GH_TOKEN: ${{ github.token }}
--head-metrics head-alloc.json \ run: |
--base-metrics base-alloc.json \ set -euo pipefail
--github-token ${{ secrets.GITHUB_TOKEN }} \ HEAD_METRICS=$(cat /tmp/head_alloc.json)
--pr-number ${{ steps.pr.outputs.number }} 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"

View file

@ -1,4 +1,4 @@
name: Hotpath Profile name: hotpath-profile
on: on:
pull_request: pull_request:
@ -13,7 +13,9 @@ jobs:
steps: steps:
- name: Checkout PR HEAD - name: Checkout PR HEAD
uses: actions/checkout@v4 uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Setup Rust - name: Setup Rust
uses: actions-rust-lang/setup-rust-toolchain@v1 uses: actions-rust-lang/setup-rust-toolchain@v1
@ -22,42 +24,42 @@ jobs:
env: env:
HOTPATH_JSON: "true" HOTPATH_JSON: "true"
run: | run: |
cargo run --features='hotpath' 2>&1 | grep '^{"hotpath_profiling_mode"' > head-timing.json cargo run --features='hotpath' 2>&1 | grep '^{"hotpath_profiling_mode"' > /tmp/head_timing.json
- name: Run allocation profiling on HEAD - name: Run allocation profiling on HEAD
env: env:
HOTPATH_JSON: "true" HOTPATH_JSON: "true"
run: | run: |
cargo run --features='hotpath,hotpath-alloc-count-total' 2>&1 | grep '^{"hotpath_profiling_mode"' > head-alloc.json cargo run --features='hotpath,hotpath-alloc' 2>&1 | grep '^{"hotpath_profiling_mode"' > /tmp/head_alloc.json
- name: Checkout base branch - name: Checkout base branch
uses: actions/checkout@v4 run: |
with: git checkout ${{ github.event.pull_request.base.sha }}
ref: ${{ github.event.pull_request.base.sha }}
- name: Run timing profiling on base - name: Run timing profiling on base
env: env:
HOTPATH_JSON: "true" HOTPATH_JSON: "true"
run: | run: |
cargo run --features='hotpath' 2>&1 | grep '^{"hotpath_profiling_mode"' > base-timing.json cargo run --features='hotpath' 2>&1 | grep '^{"hotpath_profiling_mode"' > /tmp/base_timing.json || echo '{}' > /tmp/base_timing.json
- name: Run allocation profiling on base - name: Run allocation profiling on base
env: env:
HOTPATH_JSON: "true" HOTPATH_JSON: "true"
run: | run: |
cargo run --features='hotpath,hotpath-alloc-count-total' 2>&1 | grep '^{"hotpath_profiling_mode"' > base-alloc.json cargo run --features='hotpath,hotpath-alloc' 2>&1 | grep '^{"hotpath_profiling_mode"' > /tmp/base_alloc.json || echo '{}' > /tmp/base_alloc.json
- name: Save PR number - name: Save PR number
run: echo "${{ github.event.number }}" > pr_number.txt run: |
echo '${{ github.event.pull_request.number }}' > /tmp/pr_number.txt
- name: Upload profiling results - name: Upload profiling results
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v5
with: with:
name: hotpath-results name: hotpath-results
path: | path: |
head-timing.json /tmp/head_timing.json
head-alloc.json /tmp/head_alloc.json
base-timing.json /tmp/base_timing.json
base-alloc.json /tmp/base_alloc.json
pr_number.txt /tmp/pr_number.txt
retention-days: 1 retention-days: 1

View file

@ -10,12 +10,45 @@ env:
CARGO_TERM_COLOR: always CARGO_TERM_COLOR: always
jobs: jobs:
build: test:
name: Test on ${{ matrix.target }}
runs-on: ubuntu-latest 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
steps: steps:
- name: "Checkout" - name: "Checkout"
uses: actions/checkout@v4 uses: actions/checkout@v6
- name: "Build with Cargo"
run: cargo build --verbose - 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 }}

106
Cargo.lock generated
View file

@ -17,6 +17,15 @@ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "alloca"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5a7d05ea6aea7e9e64d25b9156ba2fee3fdd659e34e41063cd2fc7cd020d7f4"
dependencies = [
"cc",
]
[[package]] [[package]]
name = "anes" name = "anes"
version = "0.1.6" version = "0.1.6"
@ -271,10 +280,11 @@ dependencies = [
[[package]] [[package]]
name = "criterion" name = "criterion"
version = "0.7.0" version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1c047a62b0cc3e145fa84415a3191f628e980b194c2755aa12300a4e6cbd928" checksum = "a0dfe5e9e71bdcf4e4954f7d14da74d1cdb92a3a07686452d1509652684b1aab"
dependencies = [ dependencies = [
"alloca",
"anes", "anes",
"cast", "cast",
"ciborium", "ciborium",
@ -283,6 +293,7 @@ dependencies = [
"itertools", "itertools",
"num-traits", "num-traits",
"oorandom", "oorandom",
"page_size",
"plotters", "plotters",
"rayon", "rayon",
"regex", "regex",
@ -294,9 +305,9 @@ dependencies = [
[[package]] [[package]]
name = "criterion-plot" name = "criterion-plot"
version = "0.6.0" version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b1bcc0dc7dfae599d84ad0b1a55f80cde8af3725da8313b528da95ef783e338" checksum = "5de36c2bee19fba779808f92bf5d9b0fa5a40095c277aba10c458a12b35d21d6"
dependencies = [ dependencies = [
"cast", "cast",
"itertools", "itertools",
@ -451,6 +462,50 @@ dependencies = [
"percent-encoding", "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]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.2.16" version = "0.2.16"
@ -502,9 +557,9 @@ checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
[[package]] [[package]]
name = "hotpath" name = "hotpath"
version = "0.6.0" version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef44238d7007bbd3c41ce7dbf3d7a4fb224bbf70d6cf3162479138dda0cd6a9e" checksum = "08382b985a19a79d95d35e2e201b02cc4b99efe2f47d82f3fd4301bb0005bb68"
dependencies = [ dependencies = [
"arc-swap", "arc-swap",
"base64", "base64",
@ -513,10 +568,15 @@ dependencies = [
"colored", "colored",
"crossbeam-channel", "crossbeam-channel",
"eyre", "eyre",
"futures-util",
"hdrhistogram", "hdrhistogram",
"hotpath-macros", "hotpath-macros",
"libc",
"mach2",
"pin-project-lite",
"prettytable-rs", "prettytable-rs",
"quanta", "quanta",
"regex",
"serde", "serde",
"serde_json", "serde_json",
"tiny_http", "tiny_http",
@ -526,9 +586,9 @@ dependencies = [
[[package]] [[package]]
name = "hotpath-macros" name = "hotpath-macros"
version = "0.6.0" version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e7e3443c6f4e5cc69e6b701f7bfca8a5502f0080e94629413346e7b4518d730" checksum = "7d618063f89423ebe079a69f5435a13d4909219d4e359757118b75fd05ae65d0"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -758,6 +818,12 @@ version = "0.4.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
[[package]]
name = "mach2"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dae608c151f68243f2b000364e1f7b186d9c29845f7d2d85bd31b9ad77ad552b"
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.7.4" version = "2.7.4"
@ -766,7 +832,7 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]] [[package]]
name = "microfetch" name = "microfetch"
version = "0.4.11" version = "0.4.12"
dependencies = [ dependencies = [
"criterion", "criterion",
"hotpath", "hotpath",
@ -816,6 +882,16 @@ version = "11.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" 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]] [[package]]
name = "percent-encoding" name = "percent-encoding"
version = "2.3.2" version = "2.3.2"
@ -828,6 +904,12 @@ version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
[[package]]
name = "pin-utils"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]] [[package]]
name = "plotters" name = "plotters"
version = "0.3.7" version = "0.3.7"
@ -1100,6 +1182,12 @@ version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
[[package]]
name = "slab"
version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589"
[[package]] [[package]]
name = "smallvec" name = "smallvec"
version = "1.15.1" version = "1.15.1"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "microfetch" name = "microfetch"
version = "0.4.11" version = "0.4.12"
edition = "2024" edition = "2024"
[lib] [lib]
@ -12,17 +12,16 @@ name = "microfetch"
path = "src/main.rs" path = "src/main.rs"
[dependencies] [dependencies]
hotpath = { optional = true, version = "0.6.0" } hotpath = { optional = true, version = "0.7.5" }
libc = "0.2.177" libc = "0.2.177"
[dev-dependencies] [dev-dependencies]
criterion = "0.7" criterion = "0.8.0"
[features] [features]
hotpath = [ "dep:hotpath", "hotpath/hotpath" ] hotpath = [ "dep:hotpath", "hotpath/hotpath" ]
hotpath-alloc-bytes-total = [ "hotpath/hotpath-alloc-bytes-total" ] hotpath-alloc = [ "hotpath/hotpath-alloc" ]
hotpath-alloc-count-total = [ "hotpath/hotpath-alloc-count-total" ] hotpath-off = [ "hotpath/hotpath-off" ]
hotpath-off = [ "hotpath/hotpath-off" ]
[[bench]] [[bench]]
harness = false harness = false

View file

@ -43,7 +43,7 @@ on your system: it is pretty _[fast](#benchmarks)_...
- Fast - Fast
- Really fast - Really fast
- Minimal dependencies - Minimal dependencies
- Tiny binary (~370kb) - Tiny binary (~370kb [^1])
- Actually really fast - Actually really fast
- Cool NixOS logo (other, inferior, distros are not supported) - Cool NixOS logo (other, inferior, distros are not supported)
- Reliable detection of following info: - Reliable detection of following info:
@ -60,6 +60,9 @@ on your system: it is pretty _[fast](#benchmarks)_...
- Did I mention fast? - Did I mention fast?
- Respects [`NO_COLOR` spec](https://no-color.org/) - 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 ## Motivation
Fastfetch, as its name probably hinted, is a very fast fetch tool written in C. Fastfetch, as its name probably hinted, is a very fast fetch tool written in C.
@ -82,11 +85,14 @@ 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 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 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 possible. Sure C could've been used here as well, but do you think I hate
myself? [^1] myself?
[^1]: Okay, maybe a little bit. One of the future goals of Microfetch is to > [!IMPORTANT]
defer to inline Assembly for the costliest functions, but that's for a > **Update as of November 30th, 2025**:
future date and until I do that I can pretend to be sane. >
> 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!
## Benchmarks ## Benchmarks
@ -148,7 +154,7 @@ HOTPATH_JSON=true cargo run --features=hotpath
To profile allocations: To profile allocations:
```bash ```bash
HOTPATH_JSON=true cargo run --features=hotpath,hotpath-alloc-count-total HOTPATH_JSON=true cargo run --features=hotpath,hotpath-alloc
``` ```
The JSON output can be analyzed with the `hotpath` CLI tool for detailed The JSON output can be analyzed with the `hotpath` CLI tool for detailed

View file

@ -10,9 +10,12 @@
forEachSystem = nixpkgs.lib.genAttrs systems; forEachSystem = nixpkgs.lib.genAttrs systems;
pkgsForEach = nixpkgs.legacyPackages; pkgsForEach = nixpkgs.legacyPackages;
in { in {
packages = forEachSystem (system: { packages = forEachSystem (system: let
pkgs = pkgsForEach.${system};
in {
default = self.packages.${system}.microfetch; default = self.packages.${system}.microfetch;
microfetch = pkgsForEach.${system}.callPackage ./nix/package.nix {}; microfetch = pkgs.callPackage ./nix/package.nix {};
microfetch-mold = pkgs.callPackage ./nix/package.nix {useMold = true;};
}); });
devShells = forEachSystem (system: { devShells = forEachSystem (system: {

View file

@ -1,14 +1,22 @@
{ {
lib, lib,
rustPlatform, stdenv,
stdenvAdapters, stdenvAdapters,
rustPlatform,
llvm, llvm,
useMold ? stdenv.isLinux && !stdenv.hostPlatform.isAarch,
}: let }: let
toml = (lib.importTOML ../Cargo.toml).package; toml = (lib.importTOML ../Cargo.toml).package;
pname = toml.name; pname = toml.name;
inherit (toml) version; inherit (toml) version;
# Select stdenv based on useMold flag
stdenv =
if useMold
then stdenvAdapters.useMoldLinker llvm.stdenv
else llvm.stdenv;
in in
rustPlatform.buildRustPackage.override {stdenv = stdenvAdapters.useMoldLinker llvm.stdenv;} { rustPlatform.buildRustPackage.override {inherit stdenv;} {
inherit pname version; inherit pname version;
src = let src = let
fs = lib.fileset; fs = lib.fileset;
@ -26,7 +34,14 @@ in
cargoLock.lockFile = ../Cargo.lock; cargoLock.lockFile = ../Cargo.lock;
enableParallelBuilding = true; enableParallelBuilding = true;
env.RUSTFLAGS = "-C link-arg=-fuse-ld=mold"; 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";
};
meta = { meta = {
description = "Microscopic fetch script in Rust, for NixOS systems"; description = "Microscopic fetch script in Rust, for NixOS systems";

View file

@ -1,27 +1,31 @@
{ {
mkShell, mkShell,
cargo,
rustc,
mold,
clang,
rust-analyzer-unwrapped, rust-analyzer-unwrapped,
rustfmt, rustfmt,
clippy, clippy,
cargo,
taplo, taplo,
rustc,
rustPlatform, rustPlatform,
gnuplot, gnuplot,
}: }:
mkShell { mkShell {
name = "microfetch";
strictDeps = true; strictDeps = true;
nativeBuildInputs = [ nativeBuildInputs = [
cargo cargo
rustc rustc
mold
clang
rust-analyzer-unwrapped rust-analyzer-unwrapped
(rustfmt.override {asNightly = true;}) (rustfmt.override {asNightly = true;})
clippy clippy
taplo taplo
gnuplot # For Criterion.rs plots gnuplot # for Criterion.rs plots
]; ];
env.RUST_SRC_PATH = "${rustPlatform.rustLibSrc}"; env.RUST_SRC_PATH = "${rustPlatform.rustLibSrc}";

View file

@ -14,7 +14,8 @@ impl UtsName {
/// Calls `uname` syscall and returns a `UtsName` wrapper /// Calls `uname` syscall and returns a `UtsName` wrapper
/// ///
/// # Errors /// # Errors
/// Returns an error if the uname syscall fails ///
/// Returns an error if the `uname` syscall fails
pub fn uname() -> Result<Self, std::io::Error> { pub fn uname() -> Result<Self, std::io::Error> {
let mut uts = MaybeUninit::uninit(); let mut uts = MaybeUninit::uninit();
if unsafe { libc::uname(uts.as_mut_ptr()) } != 0 { if unsafe { libc::uname(uts.as_mut_ptr()) } != 0 {

View file

@ -11,11 +11,15 @@
use std::io; use std::io;
/// Direct syscall to open a file /// Direct syscall to open a file
/// Returns file descriptor or -1 on error ///
/// # Returns
///
/// File descriptor or -1 on error
/// ///
/// # Safety /// # Safety
/// ///
/// The caller must ensure: /// The caller must ensure:
///
/// - `path` points to a valid null-terminated C string /// - `path` points to a valid null-terminated C string
/// - The pointer remains valid for the duration of the syscall /// - The pointer remains valid for the duration of the syscall
#[inline] #[inline]
@ -65,7 +69,10 @@ pub unsafe fn sys_open(path: *const u8, flags: i32) -> i32 {
} }
/// Direct syscall to read from a file descriptor /// Direct syscall to read from a file descriptor
/// Returns number of bytes read or -1 on error ///
/// # Returns n
///
/// Number of bytes read or -1 on error
/// ///
/// # Safety /// # Safety
/// ///

View file

@ -1,6 +1,6 @@
use std::{io, mem::MaybeUninit}; use std::{io, mem::MaybeUninit};
/// Fast integer to string conversion (no formatting overhead) /// Faster integer to string conversion without the formatting overhead.
#[inline] #[inline]
fn itoa(mut n: u64, buf: &mut [u8]) -> &str { fn itoa(mut n: u64, buf: &mut [u8]) -> &str {
if n == 0 { if n == 0 {
@ -17,9 +17,10 @@ fn itoa(mut n: u64, buf: &mut [u8]) -> &str {
unsafe { std::str::from_utf8_unchecked(&buf[i..]) } unsafe { std::str::from_utf8_unchecked(&buf[i..]) }
} }
/// Direct sysinfo syscall using inline assembly /// Direct `sysinfo` syscall using inline assembly
/// ///
/// # Safety /// # Safety
///
/// This function uses inline assembly to make a direct syscall. /// This function uses inline assembly to make a direct syscall.
/// The caller must ensure the sysinfo pointer is valid. /// The caller must ensure the sysinfo pointer is valid.
#[inline] #[inline]