Skip to content

Commit 5480d2d

Browse files
authored
Merge pull request #23 from NotAShelf/notashelf/push-orrzkvopklqm
treewide: more speed = more good
2 parents b24e720 + 353b78e commit 5480d2d

File tree

12 files changed

+453
-109
lines changed

12 files changed

+453
-109
lines changed

.github/workflows/hotpath-comment.yml

Lines changed: 19 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -13,45 +13,37 @@ jobs:
1313
comment:
1414
runs-on: ubuntu-latest
1515
if: ${{ github.event.workflow_run.conclusion == 'success' }}
16-
16+
1717
steps:
1818
- name: Download profiling results
1919
uses: actions/download-artifact@v4
2020
with:
2121
name: hotpath-results
2222
github-token: ${{ secrets.GITHUB_TOKEN }}
2323
run-id: ${{ github.event.workflow_run.id }}
24-
24+
2525
- name: Read PR number
2626
id: pr
2727
run: echo "number=$(cat pr_number.txt)" >> $GITHUB_OUTPUT
28-
28+
2929
- name: Setup Rust
3030
uses: actions-rust-lang/setup-rust-toolchain@v1
31-
31+
3232
- name: Install hotpath CLI
3333
run: cargo install hotpath
34-
34+
3535
- name: Post timing comparison comment
36-
env:
37-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
38-
run: |
39-
hotpath profile-pr \
40-
--repo ${{ github.repository }} \
41-
--pr-number ${{ steps.pr.outputs.number }} \
42-
--head-json head-timing.json \
43-
--base-json base-timing.json \
44-
--mode timing \
45-
--title "⏱️ Hotpath Timing Profile"
46-
47-
- name: Post allocation comparison comment
48-
env:
49-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
50-
run: |
51-
hotpath profile-pr \
52-
--repo ${{ github.repository }} \
53-
--pr-number ${{ steps.pr.outputs.number }} \
54-
--head-json head-alloc.json \
55-
--base-json base-alloc.json \
56-
--mode alloc \
57-
--title "📊 Hotpath Allocation Profile"
36+
run: |
37+
hotpath profile-pr \
38+
--head-metrics head-timing.json \
39+
--base-metrics base-timing.json \
40+
--github-token ${{ secrets.GITHUB_TOKEN }} \
41+
--pr-number ${{ steps.pr.outputs.number }}
42+
43+
- name: Post allocation comparison comment
44+
run: |
45+
hotpath profile-pr \
46+
--head-metrics head-alloc.json \
47+
--base-metrics base-alloc.json \
48+
--github-token ${{ secrets.GITHUB_TOKEN }} \
49+
--pr-number ${{ steps.pr.outputs.number }}

Cargo.lock

Lines changed: 0 additions & 19 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ path = "src/main.rs"
1414
[dependencies]
1515
hotpath = { optional = true, version = "0.6.0" }
1616
libc = "0.2.177"
17-
nix = { default-features = false, features = [ "fs", "hostname", "feature" ], version = "0.30.1" }
1817

1918
[dev-dependencies]
2019
criterion = "0.7"

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ on your system: it is pretty _[fast](#benchmarks)_...
4343
- Fast
4444
- Really fast
4545
- Minimal dependencies
46-
- Tiny binary (~410kb)
46+
- Tiny binary (~370kb)
4747
- Actually really fast
4848
- Cool NixOS logo (other, inferior, distros are not supported)
4949
- Reliable detection of following info:
@@ -160,7 +160,8 @@ performance regressions.
160160

161161
> [!NOTE]
162162
> You will need a Nerdfonts patched font installed, and for your terminal
163-
> emulator to support said font. Microfetch uses nerdfonts glyphs by default.
163+
> emulator to support said font. Microfetch uses nerdfonts glyphs by default,
164+
> but this can be changed by [patching the program](#customizing).
164165
165166
Microfetch is packaged in [nixpkgs](https://github.com/nixos/nixpkgs). It can be
166167
installed by adding `pkgs.microfetch` to your `environment.systemPackages`.

benches/benchmark.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use criterion::{Criterion, criterion_group, criterion_main};
22
use microfetch_lib::{
3+
UtsName,
34
colors::print_dots,
45
desktop::get_desktop_info,
56
release::{get_os_pretty_name, get_system_info},
@@ -13,7 +14,7 @@ use microfetch_lib::{
1314
};
1415

1516
fn main_benchmark(c: &mut Criterion) {
16-
let utsname = nix::sys::utsname::uname().expect("lol");
17+
let utsname = UtsName::uname().expect("Failed to get uname");
1718
c.bench_function("user_info", |b| {
1819
b.iter(|| get_username_and_hostname(&utsname));
1920
});

nix/package.nix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ in
2020
(fs.fileFilter (file: builtins.any file.hasExt ["rs"]) (s + /src))
2121
(s + /Cargo.lock)
2222
(s + /Cargo.toml)
23+
(s + /benches)
2324
];
2425
};
2526

src/lib.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,45 @@
11
pub mod colors;
22
pub mod desktop;
33
pub mod release;
4+
pub mod syscall;
45
pub mod system;
56
pub mod uptime;
7+
8+
use std::mem::MaybeUninit;
9+
10+
/// Wrapper for `libc::utsname` with safe accessor methods
11+
pub struct UtsName(libc::utsname);
12+
13+
impl UtsName {
14+
/// Calls `uname` syscall and returns a `UtsName` wrapper
15+
///
16+
/// # Errors
17+
/// Returns an error if the uname syscall fails
18+
pub fn uname() -> Result<Self, std::io::Error> {
19+
let mut uts = MaybeUninit::uninit();
20+
if unsafe { libc::uname(uts.as_mut_ptr()) } != 0 {
21+
return Err(std::io::Error::last_os_error());
22+
}
23+
Ok(Self(unsafe { uts.assume_init() }))
24+
}
25+
26+
#[must_use]
27+
pub const fn nodename(&self) -> &std::ffi::CStr {
28+
unsafe { std::ffi::CStr::from_ptr(self.0.nodename.as_ptr()) }
29+
}
30+
31+
#[must_use]
32+
pub const fn sysname(&self) -> &std::ffi::CStr {
33+
unsafe { std::ffi::CStr::from_ptr(self.0.sysname.as_ptr()) }
34+
}
35+
36+
#[must_use]
37+
pub const fn release(&self) -> &std::ffi::CStr {
38+
unsafe { std::ffi::CStr::from_ptr(self.0.release.as_ptr()) }
39+
}
40+
41+
#[must_use]
42+
pub const fn machine(&self) -> &std::ffi::CStr {
43+
unsafe { std::ffi::CStr::from_ptr(self.0.machine.as_ptr()) }
44+
}
45+
}

src/main.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
mod colors;
22
mod desktop;
33
mod release;
4+
mod syscall;
45
mod system;
56
mod uptime;
67

78
use std::io::{Write, stdout};
89

10+
pub use microfetch_lib::UtsName;
11+
912
use crate::{
1013
colors::print_dots,
1114
desktop::get_desktop_info,
@@ -24,7 +27,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
2427
if Some("--version") == std::env::args().nth(1).as_deref() {
2528
println!("Microfetch {}", env!("CARGO_PKG_VERSION"));
2629
} else {
27-
let utsname = nix::sys::utsname::uname()?;
30+
let utsname = UtsName::uname()?;
2831
let fields = Fields {
2932
user_info: get_username_and_hostname(&utsname),
3033
os_name: get_os_pretty_name()?,

src/release.rs

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
1-
use std::{
2-
fmt::Write as _,
3-
fs::File,
4-
io::{self, Read},
5-
};
1+
use std::{fmt::Write as _, io};
62

7-
use nix::sys::utsname::UtsName;
3+
use crate::{UtsName, syscall::read_file_fast};
84

95
#[must_use]
106
#[cfg_attr(feature = "hotpath", hotpath::measure)]
@@ -28,21 +24,46 @@ pub fn get_system_info(utsname: &UtsName) -> String {
2824
/// Returns an error if `/etc/os-release` cannot be read.
2925
#[cfg_attr(feature = "hotpath", hotpath::measure)]
3026
pub fn get_os_pretty_name() -> Result<String, io::Error> {
31-
// We use a stack-allocated buffer here, which seems to perform MUCH better
32-
// than `BufReader`. In hindsight, I should've seen this coming.
33-
let mut buffer = String::with_capacity(1024);
34-
File::open("/etc/os-release")?.read_to_string(&mut buffer)?;
35-
36-
for line in buffer.lines() {
37-
if let Some(pretty_name) = line.strip_prefix("PRETTY_NAME=") {
38-
if let Some(trimmed) = pretty_name
39-
.strip_prefix('"')
40-
.and_then(|s| s.strip_suffix('"'))
27+
// Fast byte-level scanning for PRETTY_NAME=
28+
const PREFIX: &[u8] = b"PRETTY_NAME=";
29+
30+
let mut buffer = [0u8; 1024];
31+
32+
// Use fast syscall-based file reading
33+
let bytes_read = read_file_fast("/etc/os-release", &mut buffer)?;
34+
let content = &buffer[..bytes_read];
35+
36+
let mut offset = 0;
37+
38+
while offset < content.len() {
39+
let remaining = &content[offset..];
40+
41+
// Find newline or end
42+
let line_end = remaining
43+
.iter()
44+
.position(|&b| b == b'\n')
45+
.unwrap_or(remaining.len());
46+
let line = &remaining[..line_end];
47+
48+
if line.starts_with(PREFIX) {
49+
let value = &line[PREFIX.len()..];
50+
51+
// Strip quotes if present
52+
let trimmed = if value.len() >= 2
53+
&& value[0] == b'"'
54+
&& value[value.len() - 1] == b'"'
4155
{
42-
return Ok(trimmed.to_owned());
43-
}
44-
return Ok(pretty_name.to_owned());
56+
&value[1..value.len() - 1]
57+
} else {
58+
value
59+
};
60+
61+
// Convert to String - should be valid UTF-8
62+
return Ok(String::from_utf8_lossy(trimmed).into_owned());
4563
}
64+
65+
offset += line_end + 1;
4666
}
67+
4768
Ok("Unknown".to_owned())
4869
}

0 commit comments

Comments
 (0)