From 39b6f6c49cdeeee2c2d9ca72215bf412f382886f Mon Sep 17 00:00:00 2001 From: Scott Lamb Date: Thu, 3 Apr 2025 09:16:04 -0700 Subject: [PATCH] build releases with mimalloc --- .github/workflows/release.yml | 24 ++++++++++++------------ CHANGELOG.md | 5 +++++ server/Cargo.lock | 18 ++++++++++++++++++ server/Cargo.toml | 23 +++++++++++++++++++---- server/base/Cargo.toml | 7 ++++++- server/base/lib.rs | 13 +++++++++++++ server/db/Cargo.toml | 4 +++- server/db/recording.rs | 1 + server/db/testutil.rs | 1 + server/src/main.rs | 1 + 10 files changed, 79 insertions(+), 18 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7956c12..522df31 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -52,16 +52,16 @@ jobs: strategy: matrix: include: - # Note: keep these arches in sync with `Upload Docker Manifest` list. - - arch: x86_64 # as in `uname -m` on Linux. - rust_target: x86_64-unknown-linux-musl # as in - docker_platform: linux/amd64 # as in - - arch: aarch64 - rust_target: aarch64-unknown-linux-musl - docker_platform: linux/arm64 - - arch: armv7l - rust_target: armv7-unknown-linux-musleabihf - docker_platform: linux/arm/v7 + # Note: keep these arches in sync with `Upload Docker Manifest` list. + - arch: x86_64 # as in `uname -m` on Linux. + rust_target: x86_64-unknown-linux-musl # as in + docker_platform: linux/amd64 # as in + - arch: aarch64 + rust_target: aarch64-unknown-linux-musl + docker_platform: linux/arm64 + - arch: armv7l + rust_target: armv7-unknown-linux-musleabihf + docker_platform: linux/arm/v7 fail-fast: false runs-on: ubuntu-latest steps: @@ -90,7 +90,7 @@ jobs: working-directory: server target: ${{ matrix.rust_target }} command: build - args: --release --features bundled + args: --release --features bundled,mimalloc - name: Upload Docker Artifact run: | tag="${DOCKER_TAG}-${{ matrix.arch }}" @@ -115,7 +115,7 @@ jobs: if-no-files-found: error release: - needs: [ base, cross ] + needs: [base, cross] runs-on: ubuntu-latest permissions: contents: write diff --git a/CHANGELOG.md b/CHANGELOG.md index 2896e0b..99d0613 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,11 @@ upgrades, e.g. `v0.6.x` -> `v0.7.x`. The config file format and [API](ref/api.md) currently have no stability guarantees, so they may change even on minor releases, e.g. `v0.7.5` -> `v0.7.6`. +## unreleased + +* Release with `mimalloc` allocator, which is significantly faster than the memory + allocator built into `musl`. + ## v0.7.20 (2025-01-31) * H.265 fixes. diff --git a/server/Cargo.lock b/server/Cargo.lock index 8e7ef8a..a425f42 100644 --- a/server/Cargo.lock +++ b/server/Cargo.lock @@ -284,6 +284,12 @@ dependencies = [ "typenum", ] +[[package]] +name = "cty" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" + [[package]] name = "cursive" version = "0.21.1" @@ -1072,6 +1078,17 @@ version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" +[[package]] +name = "libmimalloc-sys" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b20daca3a4ac14dbdc753c5e90fc7b490a48a9131daed3c9a9ced7b2defd37b" +dependencies = [ + "cc", + "cty", + "libc", +] + [[package]] name = "libredox" version = "0.1.3" @@ -1215,6 +1232,7 @@ dependencies = [ "futures", "jiff", "libc", + "libmimalloc-sys", "nix", "nom", "rusqlite", diff --git a/server/Cargo.toml b/server/Cargo.toml index 74083d9..174a359 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -18,6 +18,7 @@ nightly = ["db/nightly"] bundled = ["rusqlite/bundled", "bundled-ui"] bundled-ui = [] +mimalloc = ["base/mimalloc"] [workspace] members = ["base", "db"] @@ -42,10 +43,16 @@ uuid = { version = "1.1.2", features = ["serde", "std", "v7", "fast-rng"] } base = { package = "moonfire-base", path = "base" } base64 = { workspace = true } blake3 = "1.0.0" -bpaf = { version = "0.9.15", features = ["autocomplete", "bright-color", "derive"]} +bpaf = { version = "0.9.15", features = [ + "autocomplete", + "bright-color", + "derive", +] } bytes = "1" byteorder = "1.0" -cursive = { version = "0.21.1", default-features = false, features = ["termion-backend"] } +cursive = { version = "0.21.1", default-features = false, features = [ + "termion-backend", +] } data-encoding = "2.7.0" db = { package = "moonfire-db", path = "db" } futures = "0.3" @@ -70,7 +77,13 @@ rusqlite = { workspace = true } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" smallvec = { version = "1.7", features = ["union"] } -tokio = { version = "1.24", features = ["macros", "rt-multi-thread", "signal", "sync", "time"] } +tokio = { version = "1.24", features = [ + "macros", + "rt-multi-thread", + "signal", + "sync", + "time", +] } tokio-tungstenite = "0.26.1" toml = "0.8" tracing = { workspace = true, features = ["log"] } @@ -96,7 +109,9 @@ walkdir = "2.3.3" [dev-dependencies] mp4 = { git = "https://github.com/scottlamb/mp4-rust", branch = "moonfire" } -num-rational = { version = "0.4.0", default-features = false, features = ["std"] } +num-rational = { version = "0.4.0", default-features = false, features = [ + "std", +] } reqwest = { version = "0.12.0", default-features = false, features = ["json"] } tempfile = "3.2.0" tracing-test = "0.2.4" diff --git a/server/base/Cargo.toml b/server/base/Cargo.toml index 6aa630e..3d1f2f7 100644 --- a/server/base/Cargo.toml +++ b/server/base/Cargo.toml @@ -9,6 +9,7 @@ publish = false rust-version = "1.82" [features] +mimalloc = ["dep:libmimalloc-sys"] nightly = [] [lib] @@ -16,10 +17,14 @@ path = "lib.rs" [dependencies] ahash = "0.8" -coded = { git = "https://github.com/scottlamb/coded", rev = "2c97994974a73243d5dd12134831814f42cdb0e8"} +coded = { git = "https://github.com/scottlamb/coded", rev = "2c97994974a73243d5dd12134831814f42cdb0e8" } futures = "0.3" jiff = { workspace = true } libc = "0.2" +libmimalloc-sys = { version = "0.1.41", features = [ + "override", + "extended", +], optional = true } nix = { workspace = true, features = ["time"] } nom = "7.0.0" rusqlite = { workspace = true } diff --git a/server/base/lib.rs b/server/base/lib.rs index bf4198d..4ae621d 100644 --- a/server/base/lib.rs +++ b/server/base/lib.rs @@ -75,3 +75,16 @@ impl std::ops::Deref for Condvar { &self.0 } } + +pub fn ensure_malloc_used() { + #[cfg(feature = "mimalloc")] + { + // This is a load-bearing debug line. + // Building `libmimalloc-sys` with the `override` feature will override `malloc` and + // `free` as used through the Rust global allocator, SQLite, and `libc`. But...`cargo` + // doesn't seem to build `libmimalloc-sys` at all if it's not referenced from Rust code. + tracing::debug!("mimalloc version {}", unsafe { + libmimalloc_sys::mi_version() + }) + } +} diff --git a/server/db/Cargo.toml b/server/db/Cargo.toml index 67e3663..a47ad1d 100644 --- a/server/db/Cargo.toml +++ b/server/db/Cargo.toml @@ -27,7 +27,9 @@ itertools = { workspace = true } jiff = { workspace = true } libc = "0.2" nix = { workspace = true, features = ["dir", "feature", "fs", "mman"] } -num-rational = { version = "0.4.0", default-features = false, features = ["std"] } +num-rational = { version = "0.4.0", default-features = false, features = [ + "std", +] } pretty-hex = { workspace = true } protobuf = "3.0" ring = { workspace = true } diff --git a/server/db/recording.rs b/server/db/recording.rs index fe81a5b..fd63973 100644 --- a/server/db/recording.rs +++ b/server/db/recording.rs @@ -656,6 +656,7 @@ mod bench { /// Benchmarks the decoder, which is performance-critical for .mp4 serving. #[bench] fn bench_decoder(b: &mut test::Bencher) { + crate::testutil::init(); let data = include_bytes!("testdata/video_sample_index.bin"); b.bytes = data.len() as u64; b.iter(|| { diff --git a/server/db/testutil.rs b/server/db/testutil.rs index 935dcf5..b4a769f 100644 --- a/server/db/testutil.rs +++ b/server/db/testutil.rs @@ -37,6 +37,7 @@ pub const TEST_VIDEO_SAMPLE_ENTRY_DATA: &[u8] = /// * use a fast but insecure password hashing format. pub fn init() { INIT.call_once(|| { + base::ensure_malloc_used(); base::tracing_setup::install_for_tests(); base::time::testutil::init_zone(); crate::auth::set_test_config(); diff --git a/server/src/main.rs b/server/src/main.rs index da36f18..f5c7a9f 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -77,6 +77,7 @@ fn main() { } base::tracing_setup::install(); base::time::init_zone(jiff::tz::TimeZone::system); + base::ensure_malloc_used(); // Get the program name from the OS (e.g. if invoked as `target/debug/nvr`: `nvr`), // falling back to the crate name if conversion to a path/UTF-8 string fails.