1
Fork 0
mirror of https://github.com/RGBCube/dix synced 2025-07-26 19:27:45 +00:00

Benches - criterion benchmarks (#5)

* split crate into library and binary

criterion can not benchmark binary crates

* Add store benchmarks

* Add more, not reproducible benchmarks

The benchmarks are currently hardcoded to use a specific system
on my computer. To run the tests yourself, change QUERY_DERIV__OLD in
benches/common.rs

In the future, I would like to pull a specific copy of the
nixos sqlite db from e.g. a github repo to make the benchmarks
reproducible

* Do not hardcode system derivations to use in benchmars

By default, the oldest system is compared to the current system

A specific system can be specified using environment variables (see
benches/common.rs)
This commit is contained in:
Dragyx 2025-05-08 18:23:18 +02:00 committed by GitHub
parent 86564fbdda
commit 5e317983c2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 797 additions and 77 deletions

438
Cargo.lock generated
View file

@ -61,12 +61,47 @@ dependencies = [
"windows-sys", "windows-sys",
] ]
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
]
[[package]]
name = "autocfg"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "2.9.0" version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
[[package]]
name = "bumpalo"
version = "3.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
[[package]]
name = "cast"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.2.21" version = "1.2.21"
@ -76,6 +111,23 @@ dependencies = [
"shlex", "shlex",
] ]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
version = "2.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
dependencies = [
"bitflags 1.3.2",
"textwrap",
"unicode-width",
]
[[package]] [[package]]
name = "clap" name = "clap"
version = "4.5.37" version = "4.5.37"
@ -122,6 +174,88 @@ version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
[[package]]
name = "criterion"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b01d6de93b2b6c65e17c634a26653a29d107b3c98c607c765bf38d041531cd8f"
dependencies = [
"atty",
"cast",
"clap 2.34.0",
"criterion-plot",
"csv",
"itertools",
"lazy_static",
"num-traits",
"oorandom",
"plotters",
"rayon",
"regex",
"serde",
"serde_cbor",
"serde_derive",
"serde_json",
"tinytemplate",
"walkdir",
]
[[package]]
name = "criterion-plot"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2673cc8207403546f45f5fd319a974b1e6983ad1a3ee7e6041650013be041876"
dependencies = [
"cast",
"itertools",
]
[[package]]
name = "crossbeam-deque"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
dependencies = [
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
dependencies = [
"crossbeam-utils",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
[[package]]
name = "csv"
version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf"
dependencies = [
"csv-core",
"itoa",
"ryu",
"serde",
]
[[package]]
name = "csv-core"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d02f3b0da4c6504f86e9cd789d8dbafab48c2321be74e9987593de5a894d93d"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "diff" name = "diff"
version = "0.1.13" version = "0.1.13"
@ -132,9 +266,11 @@ checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
name = "dix" name = "dix"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"clap", "clap 4.5.37",
"criterion",
"diff", "diff",
"env_logger", "env_logger",
"libc",
"log", "log",
"regex", "regex",
"rusqlite", "rusqlite",
@ -142,6 +278,12 @@ dependencies = [
"yansi", "yansi",
] ]
[[package]]
name = "either"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
[[package]] [[package]]
name = "env_filter" name = "env_filter"
version = "0.1.3" version = "0.1.3"
@ -183,6 +325,12 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
[[package]]
name = "half"
version = "1.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403"
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.15.3" version = "0.15.3"
@ -207,12 +355,36 @@ version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "is_terminal_polyfill" name = "is_terminal_polyfill"
version = "1.70.1" version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]]
name = "itertools"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
[[package]] [[package]]
name = "jiff" name = "jiff"
version = "0.2.12" version = "0.2.12"
@ -237,6 +409,28 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "js-sys"
version = "0.3.77"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
dependencies = [
"once_cell",
"wasm-bindgen",
]
[[package]]
name = "lazy_static"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
version = "0.2.172"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
[[package]] [[package]]
name = "libsqlite3-sys" name = "libsqlite3-sys"
version = "0.33.0" version = "0.33.0"
@ -260,18 +454,61 @@ version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "num-traits"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
]
[[package]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.21.3" version = "1.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
[[package]]
name = "oorandom"
version = "11.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e"
[[package]] [[package]]
name = "pkg-config" name = "pkg-config"
version = "0.3.32" version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
[[package]]
name = "plotters"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747"
dependencies = [
"num-traits",
"plotters-backend",
"plotters-svg",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "plotters-backend"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a"
[[package]]
name = "plotters-svg"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670"
dependencies = [
"plotters-backend",
]
[[package]] [[package]]
name = "portable-atomic" name = "portable-atomic"
version = "1.11.0" version = "1.11.0"
@ -305,6 +542,26 @@ dependencies = [
"proc-macro2", "proc-macro2",
] ]
[[package]]
name = "rayon"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
dependencies = [
"either",
"rayon-core",
]
[[package]]
name = "rayon-core"
version = "1.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
dependencies = [
"crossbeam-deque",
"crossbeam-utils",
]
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.11.1" version = "1.11.1"
@ -340,7 +597,7 @@ version = "0.35.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a22715a5d6deef63c637207afbe68d0c72c3f8d0022d7cf9714c442d6157606b" checksum = "a22715a5d6deef63c637207afbe68d0c72c3f8d0022d7cf9714c442d6157606b"
dependencies = [ dependencies = [
"bitflags", "bitflags 2.9.0",
"fallible-iterator", "fallible-iterator",
"fallible-streaming-iterator", "fallible-streaming-iterator",
"hashlink", "hashlink",
@ -348,6 +605,27 @@ dependencies = [
"smallvec", "smallvec",
] ]
[[package]]
name = "rustversion"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
[[package]]
name = "ryu"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
dependencies = [
"winapi-util",
]
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.219" version = "1.0.219"
@ -357,6 +635,16 @@ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]]
name = "serde_cbor"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5"
dependencies = [
"half",
"serde",
]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.219" version = "1.0.219"
@ -368,6 +656,18 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "serde_json"
version = "1.0.140"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
dependencies = [
"itoa",
"memchr",
"ryu",
"serde",
]
[[package]] [[package]]
name = "shlex" name = "shlex"
version = "1.3.0" version = "1.3.0"
@ -397,6 +697,15 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "textwrap"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
dependencies = [
"unicode-width",
]
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "2.0.12" version = "2.0.12"
@ -417,12 +726,28 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "tinytemplate"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc"
dependencies = [
"serde",
"serde_json",
]
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.18" version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
[[package]]
name = "unicode-width"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
[[package]] [[package]]
name = "utf8parse" name = "utf8parse"
version = "0.2.2" version = "0.2.2"
@ -435,6 +760,115 @@ version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "walkdir"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
dependencies = [
"same-file",
"winapi-util",
]
[[package]]
name = "wasm-bindgen"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
dependencies = [
"cfg-if",
"once_cell",
"rustversion",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
dependencies = [
"bumpalo",
"log",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
dependencies = [
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
dependencies = [
"unicode-ident",
]
[[package]]
name = "web-sys"
version = "0.3.77"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
dependencies = [
"windows-sys",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]] [[package]]
name = "windows-sys" name = "windows-sys"
version = "0.59.0" version = "0.59.0"

View file

@ -3,6 +3,15 @@ name = "dix"
version = "0.1.0" version = "0.1.0"
edition = "2024" edition = "2024"
[[bin]]
name = "dix"
path = "src/main.rs"
[lib]
name = "dixlib"
path = "src/lib.rs"
[dependencies] [dependencies]
clap = { version = "4.5.37", features = ["derive"] } clap = { version = "4.5.37", features = ["derive"] }
regex = "1.11.1" regex = "1.11.1"
@ -12,3 +21,19 @@ log = "0.4.20"
env_logger = "0.11.3" env_logger = "0.11.3"
rusqlite = { version = "0.35.0", features = ["bundled"] } rusqlite = { version = "0.35.0", features = ["bundled"] }
diff = "0.1.13" diff = "0.1.13"
[dev-dependencies]
criterion = "0.3"
libc = "0.2"
[[bench]]
name = "store"
harness=false
[[bench]]
name = "print"
harness=false
[[bench]]
name = "util"
harness=false

89
benches/common.rs Normal file
View file

@ -0,0 +1,89 @@
use std::{
env,
fs::{self, DirEntry},
path::PathBuf,
sync::OnceLock,
};
use dixlib::{store, util::PackageDiff};
/// tries to get the path of the oldest nixos system derivation
/// this function is pretty hacky and only used so that
/// you don't have to specify a specific derivation to
/// run the benchmarks
fn get_oldest_nixos_system() -> Option<PathBuf> {
let profile_dir = fs::read_dir("/nix/var/nix/profiles").ok()?;
let files = profile_dir.filter_map(Result::ok).filter_map(|entry| {
entry
.file_type()
.ok()
.and_then(|f| f.is_symlink().then_some(entry.path()))
});
files.min_by_key(|path| {
// extract all digits from the file name and use that as key
let p = path.as_os_str().to_str().unwrap_or_default();
let digits: String = p.chars().filter(|c| c.is_ascii_digit()).collect();
// if we are not able to produce a key (e.g. because the path does not contain digits)
// we put it last
digits.parse::<u32>().unwrap_or(u32::MAX)
})
}
pub fn get_deriv_query() -> &'static PathBuf {
static _QUERY_DERIV: OnceLock<PathBuf> = OnceLock::new();
_QUERY_DERIV.get_or_init(|| {
let path = PathBuf::from(
env::var("DIX_BENCH_NEW_SYSTEM")
.unwrap_or_else(|_| "/run/current-system/system".into()),
);
path
})
}
pub fn get_deriv_query_old() -> &'static PathBuf {
static _QUERY_DERIV: OnceLock<PathBuf> = OnceLock::new();
_QUERY_DERIV.get_or_init(|| {
let path = env::var("DIX_BENCH_OLD_SYSTEM")
.ok()
.map(PathBuf::from)
.or(get_oldest_nixos_system())
.unwrap_or_else(|| PathBuf::from("/run/current-system/system"));
path
})
}
pub fn get_packages() -> &'static (Vec<String>, Vec<String>) {
static _PKGS: OnceLock<(Vec<String>, Vec<String>)> = OnceLock::new();
_PKGS.get_or_init(|| {
let pkgs_before = store::get_packages(std::path::Path::new(get_deriv_query_old()))
.unwrap()
.into_iter()
.map(|(_, name)| name)
.collect::<Vec<String>>();
let pkgs_after = store::get_packages(std::path::Path::new(get_deriv_query()))
.unwrap()
.into_iter()
.map(|(_, name)| name)
.collect::<Vec<String>>();
(pkgs_before, pkgs_after)
})
}
pub fn get_pkg_diff() -> &'static PackageDiff<'static> {
static _PKG_DIFF: OnceLock<PackageDiff> = OnceLock::new();
_PKG_DIFF.get_or_init(|| {
let (pkgs_before, pkgs_after) = get_packages();
PackageDiff::new(pkgs_before, pkgs_after)
})
}
/// prints the old and new NixOs system used for benchmarking
///
/// is used to give information about the old and new system
pub fn print_used_nixos_systems() {
let old = get_deriv_query_old();
let new = get_deriv_query();
println!("old system used {:?}", old);
println!("new system used {:?}", new);
}

86
benches/print.rs Normal file
View file

@ -0,0 +1,86 @@
mod common;
use std::{fs::File, os::fd::AsRawFd};
use common::{get_pkg_diff, print_used_nixos_systems};
use criterion::{Criterion, black_box, criterion_group, criterion_main};
use dixlib::print;
/// reroutes stdout and stderr to the null device before
/// executing `f`
fn suppress_output<F: FnOnce()>(f: F) {
let stdout = std::io::stdout();
let stderr = std::io::stderr();
// Save original FDs
let orig_stdout_fd = stdout.as_raw_fd();
let orig_stderr_fd = stderr.as_raw_fd();
// Open /dev/null and get its FD
let devnull = File::create("/dev/null").unwrap();
let null_fd = devnull.as_raw_fd();
// Redirect stdout and stderr to /dev/null
let _ = unsafe { libc::dup2(null_fd, orig_stdout_fd) };
let _ = unsafe { libc::dup2(null_fd, orig_stderr_fd) };
f();
let _ = unsafe { libc::dup2(orig_stdout_fd, 1) };
let _ = unsafe { libc::dup2(orig_stderr_fd, 2) };
}
pub fn bench_print_added(c: &mut Criterion) {
print_used_nixos_systems();
let diff = get_pkg_diff();
c.bench_function("print_added", |b| {
b.iter(|| {
suppress_output(|| {
print::print_added(
black_box(&diff.added),
black_box(&diff.pkg_to_versions_post),
30,
);
});
});
});
}
pub fn bench_print_removed(c: &mut Criterion) {
print_used_nixos_systems();
let diff = get_pkg_diff();
c.bench_function("print_removed", |b| {
b.iter(|| {
suppress_output(|| {
print::print_removed(
black_box(&diff.removed),
black_box(&diff.pkg_to_versions_pre),
30,
);
});
});
});
}
pub fn bench_print_changed(c: &mut Criterion) {
print_used_nixos_systems();
let diff = get_pkg_diff();
c.bench_function("print_changed", |b| {
b.iter(|| {
suppress_output(|| {
print::print_changes(
black_box(&diff.changed),
black_box(&diff.pkg_to_versions_pre),
black_box(&diff.pkg_to_versions_post),
30,
);
});
});
});
}
criterion_group!(
benches,
bench_print_added,
bench_print_removed,
bench_print_changed
);
criterion_main!(benches);

36
benches/store.rs Normal file
View file

@ -0,0 +1,36 @@
mod common;
use criterion::{Criterion, black_box, criterion_group, criterion_main};
use dixlib::store;
// basic benchmarks using the current system
//
// problem: this is not reproducible at all
// since this is very depending on the current
// system and the nature of the system in general
//
// we might want to think about using a copy of the sqlite
// db to benchmark instead to make the results comparable
pub fn bench_get_packages(c: &mut Criterion) {
c.bench_function("get_packages", |b| {
b.iter(|| store::get_packages(black_box(common::get_deriv_query())));
});
}
pub fn bench_get_closure_size(c: &mut Criterion) {
c.bench_function("get_closure_size", |b| {
b.iter(|| store::get_closure_size(black_box(common::get_deriv_query())));
});
}
pub fn bench_get_dependency_graph(c: &mut Criterion) {
c.bench_function("get_dependency_graph", |b| {
b.iter(|| store::get_dependency_graph(black_box(common::get_deriv_query())));
});
}
criterion_group!(
benches,
bench_get_packages,
bench_get_closure_size,
bench_get_dependency_graph
);
criterion_main!(benches);

15
benches/util.rs Normal file
View file

@ -0,0 +1,15 @@
mod common;
use common::get_packages;
use criterion::{Criterion, black_box, criterion_group, criterion_main};
use dixlib::util::PackageDiff;
pub fn bench_package_diff(c: &mut Criterion) {
let (pkgs_before, pkgs_after) = get_packages();
c.bench_function("PackageDiff::new", |b| {
b.iter(|| PackageDiff::new(black_box(pkgs_before), black_box(pkgs_after)));
});
}
criterion_group!(benches, bench_package_diff);
criterion_main!(benches);

4
src/lib.rs Normal file
View file

@ -0,0 +1,4 @@
pub mod error;
pub mod print;
pub mod store;
pub mod util;

View file

@ -1,19 +1,14 @@
mod print;
mod util;
use clap::Parser; use clap::Parser;
use core::str; use core::str;
use dixlib::print;
use dixlib::store;
use dixlib::util::PackageDiff;
use log::{debug, error}; use log::{debug, error};
use std::{ use std::{
collections::{HashMap, HashSet}, collections::{HashMap, HashSet},
thread, thread,
}; };
use yansi::Paint; use yansi::Paint;
mod error;
mod store;
use error::AppError;
// Use type alias for Result with our custom error type
type Result<T> = std::result::Result<T, AppError>;
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
#[command(name = "dix")] #[command(name = "dix")]
@ -145,42 +140,15 @@ fn main() {
} }
}; };
// Map from packages of the first closure to their version let PackageDiff {
let mut pre = HashMap::<&str, HashSet<&str>>::new(); pkg_to_versions_pre: pre,
let mut post = HashMap::<&str, HashSet<&str>>::new(); pkg_to_versions_post: post,
pre_keys: _,
for p in &package_list_pre { post_keys: _,
match util::get_version(&**p) { added,
Ok((name, version)) => { removed,
pre.entry(name).or_default().insert(version); changed,
} } = PackageDiff::new(&package_list_pre, &package_list_post);
Err(e) => {
debug!("Error parsing package version: {e}");
}
}
}
for p in &package_list_post {
match util::get_version(&**p) {
Ok((name, version)) => {
post.entry(name).or_default().insert(version);
}
Err(e) => {
debug!("Error parsing package version: {e}");
}
}
}
// Compare the package names of both versions
let pre_keys: HashSet<&str> = pre.keys().copied().collect();
let post_keys: HashSet<&str> = post.keys().copied().collect();
// Difference gives us added and removed packages
let added: HashSet<&str> = &post_keys - &pre_keys;
let removed: HashSet<&str> = &pre_keys - &post_keys;
// Get the intersection of the package names for version changes
let changed: HashSet<&str> = &pre_keys & &post_keys;
debug!("Added packages: {}", added.len()); debug!("Added packages: {}", added.len());
debug!("Removed packages: {}", removed.len()); debug!("Removed packages: {}", removed.len());

View file

@ -1,18 +1,18 @@
use crate::error::AppError;
use log::{debug, error};
use regex::Regex;
use std::cmp::Ordering;
use std::{ use std::{
cmp::Ordering,
collections::{HashMap, HashSet}, collections::{HashMap, HashSet},
string::ToString,
sync::OnceLock, sync::OnceLock,
thread,
}; };
use crate::error::AppError;
use log::debug;
use regex::Regex;
// Use type alias for Result with our custom error type // Use type alias for Result with our custom error type
type Result<T> = std::result::Result<T, AppError>; type Result<T> = std::result::Result<T, AppError>;
use std::string::ToString;
#[derive(Eq, PartialEq, Debug)] #[derive(Eq, PartialEq, Debug)]
enum VersionComponent { enum VersionComponent {
Number(u64), Number(u64),
@ -104,29 +104,6 @@ pub fn compare_versions(a: &str, b: &str) -> Ordering {
iter_a.cmp(iter_b) iter_a.cmp(iter_b)
} }
mod test {
#[test]
fn test_version_component_iter() {
use super::VersionComponent::{Number, Text};
use crate::util::VersionComponentIterator;
let v = "132.1.2test234-1-man----.--.......---------..---";
let comp: Vec<_> = VersionComponentIterator::new(v).collect();
assert_eq!(
comp,
[
Number(132),
Number(1),
Number(2),
Text("test".into()),
Number(234),
Number(1),
Text("man".into())
]
);
}
}
/// Parses a nix store path to extract the packages name and version /// Parses a nix store path to extract the packages name and version
/// ///
/// This function first drops the inputs first 44 chars, since that is exactly the length of the /nix/store/... prefix. Then it matches that against our store path regex. /// This function first drops the inputs first 44 chars, since that is exactly the length of the /nix/store/... prefix. Then it matches that against our store path regex.
@ -174,10 +151,96 @@ pub fn get_version<'a>(pack: impl Into<&'a str>) -> Result<(&'a str, &'a str)> {
// Returns a reference to the compiled regex pattern. // Returns a reference to the compiled regex pattern.
// The regex is compiled only once. // The regex is compiled only once.
fn store_path_regex() -> &'static Regex { pub fn store_path_regex() -> &'static Regex {
static REGEX: OnceLock<Regex> = OnceLock::new(); static REGEX: OnceLock<Regex> = OnceLock::new();
REGEX.get_or_init(|| { REGEX.get_or_init(|| {
Regex::new(r"(.+?)(-([0-9].*?))?$") Regex::new(r"(.+?)(-([0-9].*?))?$")
.expect("Failed to compile regex pattern for nix store paths") .expect("Failed to compile regex pattern for nix store paths")
}) })
} }
// TODO: move this somewhere else, this does not really
// belong into this file
pub struct PackageDiff<'a> {
pub pkg_to_versions_pre: HashMap<&'a str, HashSet<&'a str>>,
pub pkg_to_versions_post: HashMap<&'a str, HashSet<&'a str>>,
pub pre_keys: HashSet<&'a str>,
pub post_keys: HashSet<&'a str>,
pub added: HashSet<&'a str>,
pub removed: HashSet<&'a str>,
pub changed: HashSet<&'a str>,
}
impl<'a> PackageDiff<'a> {
pub fn new<S: AsRef<str> + 'a>(pkgs_pre: &'a [S], pkgs_post: &'a [S]) -> Self {
// Map from packages of the first closure to their version
let mut pre = HashMap::<&str, HashSet<&str>>::new();
let mut post = HashMap::<&str, HashSet<&str>>::new();
for p in pkgs_pre {
match get_version(p.as_ref()) {
Ok((name, version)) => {
pre.entry(name).or_default().insert(version);
}
Err(e) => {
debug!("Error parsing package version: {e}");
}
}
}
for p in pkgs_post {
match get_version(p.as_ref()) {
Ok((name, version)) => {
post.entry(name).or_default().insert(version);
}
Err(e) => {
debug!("Error parsing package version: {e}");
}
}
}
// Compare the package names of both versions
let pre_keys: HashSet<&str> = pre.keys().copied().collect();
let post_keys: HashSet<&str> = post.keys().copied().collect();
// Difference gives us added and removed packages
let added: HashSet<&str> = &post_keys - &pre_keys;
let removed: HashSet<&str> = &pre_keys - &post_keys;
// Get the intersection of the package names for version changes
let changed: HashSet<&str> = &pre_keys & &post_keys;
Self {
pkg_to_versions_pre: pre,
pkg_to_versions_post: post,
pre_keys,
post_keys,
added,
removed,
changed,
}
}
}
mod test {
#[test]
fn test_version_component_iter() {
use super::VersionComponent::{Number, Text};
use crate::util::VersionComponentIterator;
let v = "132.1.2test234-1-man----.--.......---------..---";
let comp: Vec<_> = VersionComponentIterator::new(v).collect();
assert_eq!(
comp,
[
Number(132),
Number(1),
Number(2),
Text("test".into()),
Number(234),
Number(1),
Text("man".into())
]
);
}
}