1
1
mirror of https://github.com/orhun/git-cliff.git synced 2024-11-25 13:22:17 +03:00

feat(profiler): support performance profiling via pprof (#768)

* feat: support performance profiling via pprof

This adds support for performance profiling that allows for finding the bottlenecks and performance optimizations.

It can be enabled via `profiler` feature and the `bench` build profile.

```shell
cargo build --profile=bench --features=profiler
```

* refactor(profiling): clean up implementation

* feat(ci): run profiler

* fix(ci): fetch all the history for profiler

* docs(website): add profiling docs

---------

Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>
This commit is contained in:
Amin Yahyaabadi 2024-07-29 01:25:23 -07:00 committed by GitHub
parent c208a9791e
commit 35dc1e46fd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 416 additions and 5 deletions

View File

@ -183,3 +183,21 @@ jobs:
exit 1
fi
done
profiler:
name: Run profiler
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install toolchain
uses: dtolnay/rust-toolchain@stable
- name: Run profiler
run: cargo run --profile bench --features profiler -- --no-exec
- name: Upload report
uses: actions/upload-artifact@v4
with:
name: git-cliff.${{ github.run_id }}-profiler-report
path: git-cliff.**.flamegraph.svg

2
.gitignore vendored
View File

@ -3,3 +3,5 @@
# Backup files generated by rustfmt
**/*.rs.bk
*.flamegraph.svg

277
Cargo.lock generated
View File

@ -23,6 +23,19 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"
[[package]]
name = "ahash"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
dependencies = [
"cfg-if",
"getrandom",
"once_cell",
"version_check",
"zerocopy",
]
[[package]]
name = "aho-corasick"
version = "1.1.3"
@ -102,6 +115,12 @@ version = "1.0.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3"
[[package]]
name = "arrayvec"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
[[package]]
name = "async-compression"
version = "0.4.10"
@ -206,6 +225,12 @@ version = "3.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
[[package]]
name = "bytemuck"
version = "1.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b236fc92302c97ed75b38da1f4917b5cdda4984745740f153a5d3059e48d725e"
[[package]]
name = "bytes"
version = "1.6.0"
@ -223,7 +248,7 @@ dependencies = [
"futures",
"hex",
"libc",
"memmap2",
"memmap2 0.5.10",
"miette",
"reflink-copy",
"serde",
@ -409,6 +434,15 @@ version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
[[package]]
name = "cpp_demangle"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e8227005286ec39567949b33df9896bcadfa6051bccca2488129f108ca23119"
dependencies = [
"cfg-if",
]
[[package]]
name = "cpufeatures"
version = "0.2.12"
@ -462,6 +496,15 @@ dependencies = [
"typenum",
]
[[package]]
name = "debugid"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d"
dependencies = [
"uuid",
]
[[package]]
name = "deranged"
version = "0.3.11"
@ -616,6 +659,18 @@ version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a"
[[package]]
name = "findshlibs"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40b9e59cd0f7e0806cca4be089683ecb6434e602038df21fe6bf6711b2f07f64"
dependencies = [
"cc",
"lazy_static",
"libc",
"winapi",
]
[[package]]
name = "flate2"
version = "1.0.30"
@ -771,7 +826,9 @@ dependencies = [
"indicatif",
"lazy_static",
"log",
"pprof",
"pretty_assertions",
"rand",
"regex",
"secrecy",
"shellexpand",
@ -1252,6 +1309,24 @@ dependencies = [
"unicode-width",
]
[[package]]
name = "inferno"
version = "0.11.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c77a3ae7d4761b9c64d2c030f70746ceb8cfba32dce0325a56792e0a4816c31"
dependencies = [
"ahash",
"indexmap",
"is-terminal",
"itoa",
"log",
"num-format",
"once_cell",
"quick-xml",
"rgb",
"str_stack",
]
[[package]]
name = "instant"
version = "0.1.12"
@ -1421,6 +1496,16 @@ version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5"
[[package]]
name = "lock_api"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
dependencies = [
"autocfg",
"scopeguard",
]
[[package]]
name = "log"
version = "0.4.21"
@ -1442,6 +1527,15 @@ dependencies = [
"libc",
]
[[package]]
name = "memmap2"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322"
dependencies = [
"libc",
]
[[package]]
name = "miette"
version = "5.10.0"
@ -1508,6 +1602,17 @@ dependencies = [
"semver",
]
[[package]]
name = "nix"
version = "0.26.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b"
dependencies = [
"bitflags 1.3.2",
"cfg-if",
"libc",
]
[[package]]
name = "nom"
version = "7.1.3"
@ -1524,6 +1629,16 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
[[package]]
name = "num-format"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3"
dependencies = [
"arrayvec",
"itoa",
]
[[package]]
name = "num-traits"
version = "0.2.19"
@ -1570,6 +1685,29 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
[[package]]
name = "parking_lot"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
dependencies = [
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.9.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
"windows-targets 0.52.5",
]
[[package]]
name = "parse-zoneinfo"
version = "0.3.1"
@ -1724,6 +1862,27 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
[[package]]
name = "pprof"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef5c97c51bd34c7e742402e216abdeb44d415fbe6ae41d56b114723e953711cb"
dependencies = [
"backtrace",
"cfg-if",
"findshlibs",
"inferno",
"libc",
"log",
"nix",
"once_cell",
"parking_lot",
"smallvec",
"symbolic-demangle",
"tempfile",
"thiserror",
]
[[package]]
name = "ppv-lite86"
version = "0.2.17"
@ -1755,6 +1914,15 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "quick-xml"
version = "0.26.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f50b1c63b38611e7d4d7f68b82d3ad0cc71a2ad2e7f61fc10f1328d917c93cd"
dependencies = [
"memchr",
]
[[package]]
name = "quinn"
version = "0.11.2"
@ -1841,6 +2009,15 @@ dependencies = [
"getrandom",
]
[[package]]
name = "redox_syscall"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4"
dependencies = [
"bitflags 2.5.0",
]
[[package]]
name = "redox_users"
version = "0.4.5"
@ -1992,6 +2169,15 @@ dependencies = [
"tower-service",
]
[[package]]
name = "rgb"
version = "0.8.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ade4539f42266ded9e755c605bdddf546242b2c961b03b06a7375260788a0523"
dependencies = [
"bytemuck",
]
[[package]]
name = "ring"
version = "0.17.8"
@ -2180,6 +2366,12 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "sct"
version = "0.7.1"
@ -2374,6 +2566,18 @@ dependencies = [
"xxhash-rust",
]
[[package]]
name = "stable_deref_trait"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
[[package]]
name = "str_stack"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9091b6114800a5f2141aee1d1b9d6ca3592ac062dc5decb3764ec5895a47b4eb"
[[package]]
name = "strsim"
version = "0.11.1"
@ -2386,6 +2590,29 @@ version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
[[package]]
name = "symbolic-common"
version = "12.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16629323a4ec5268ad23a575110a724ad4544aae623451de600c747bf87b36cf"
dependencies = [
"debugid",
"memmap2 0.9.4",
"stable_deref_trait",
"uuid",
]
[[package]]
name = "symbolic-demangle"
version = "12.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48c043a45f08f41187414592b3ceb53fb0687da57209cc77401767fb69d5b596"
dependencies = [
"cpp_demangle",
"rustc-demangle",
"symbolic-common",
]
[[package]]
name = "syn"
version = "1.0.109"
@ -2894,6 +3121,12 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]]
name = "uuid"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314"
[[package]]
name = "vcpkg"
version = "0.2.15"
@ -3022,6 +3255,22 @@ dependencies = [
"rustls-pki-types",
]
[[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.8"
@ -3031,6 +3280,12 @@ dependencies = [
"windows-sys 0.52.0",
]
[[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]]
name = "windows"
version = "0.56.0"
@ -3282,6 +3537,26 @@ version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
[[package]]
name = "zerocopy"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.63",
]
[[package]]
name = "zeroize"
version = "1.7.0"

View File

@ -29,4 +29,5 @@ strip = true
[profile.bench]
opt-level = 3
debug = false
debug = true # used by the profiler
strip = false # keep symbols for the profiler

View File

@ -36,6 +36,9 @@ gitlab = ["remote", "git-cliff-core/gitlab"]
gitea = ["remote", "git-cliff-core/gitea"]
# enable Bitbucket integration
bitbucket = ["remote", "git-cliff-core/bitbucket"]
# performance profiler
profiler = ["dep:pprof", "dep:rand", "profiler-flamegraph"]
profiler-flamegraph = ["pprof/flamegraph"]
[dependencies]
glob.workspace = true
@ -51,6 +54,8 @@ shellexpand = "3.1.0"
update-informer = { version = "1.1.0", optional = true }
indicatif = { version = "0.17.8", optional = true }
env_logger = "0.10.2"
pprof = { version = "0.13", optional = true }
rand = { version = "0.8.4", optional = true }
[dependencies.git-cliff-core]
version = "2.4.0" # managed by release.sh

View File

@ -5,7 +5,12 @@ use git_cliff_core::error::Result;
use std::env;
use std::process;
/// Profiler.
#[cfg(feature = "profiler")]
mod profiler;
fn main() -> Result<()> {
// Parse the command line arguments
let args = Opt::parse();
if args.verbose == 1 {
env::set_var("RUST_LOG", "debug");
@ -15,11 +20,32 @@ fn main() -> Result<()> {
env::set_var("RUST_LOG", "info");
}
logger::init()?;
match git_cliff::run(args) {
Ok(_) => process::exit(0),
// Initialize the profiler guard if the feature is enabled
let mut _profiler_guard = None;
#[cfg(feature = "profiler")]
{
_profiler_guard = profiler::start_profiling();
}
#[cfg(not(feature = "profiler"))]
{
_profiler_guard = Some(());
}
// Run git-cliff
let exit_code = match git_cliff::run(args) {
Ok(_) => 0,
Err(e) => {
log::error!("{}", e);
process::exit(1)
1
}
};
// Report the profiler if the feature is enabled
#[cfg(feature = "profiler")]
{
profiler::finish_profiling(_profiler_guard)?;
}
process::exit(exit_code);
}

52
git-cliff/src/profiler.rs Normal file
View File

@ -0,0 +1,52 @@
use git_cliff_core::error::Result;
/// Creates a profiler guard and returns it.
pub(crate) fn start_profiling() -> Option<pprof::ProfilerGuard<'static>> {
match pprof::ProfilerGuardBuilder::default()
.frequency(1000)
.blocklist(&["libc", "libgcc", "pthread", "vdso"])
.build()
{
Ok(guard) => Some(guard),
Err(e) => {
log::error!("failed to build profiler guard: {e}");
None
}
}
}
/// Reports the profiling results.
pub(crate) fn finish_profiling(
profiler_guard: Option<pprof::ProfilerGuard>,
) -> Result<()> {
match profiler_guard
.expect("failed to retrieve profiler guard")
.report()
.build()
{
Ok(report) => {
#[cfg(feature = "profiler-flamegraph")]
{
use std::fs::File;
let random = rand::random::<u64>();
let file = File::create(format!(
"{}.{random}.flamegraph.svg",
env!("CARGO_PKG_NAME"),
))?;
if let Err(e) = report.flamegraph(file) {
log::error!("failed to create flamegraph file: {e}");
}
}
#[cfg(not(feature = "profiler-flamegraph"))]
{
log::info!("profiling report: {:?}", &report);
}
}
Err(e) => {
log::error!("failed to build profiler report: {e}");
}
}
Ok(())
}

View File

@ -0,0 +1,7 @@
{
"label": "Development",
"position": 12,
"link": {
"type": "generated-index"
}
}

View File

@ -0,0 +1,3 @@
# Contributing
See the contributing guide [on GitHub](https://github.com/orhun/git-cliff/blob/main/CONTRIBUTING.md).

View File

@ -0,0 +1,22 @@
---
sidebar_position: 1
---
# Performance Profiling
**git-cliff** can be built with performance profiling instrumentation, which helps with finding bottlenecks.
The profiler can be enabled via the `profiler` feature and the `bench` build profile.
```bash
cargo build --profile=bench --features=profiler
```
To create a flame graph SVG:
```bash
cargo run --profile=bench --features=profiler
```
e.g.
![flamegraph example](https://github.com/user-attachments/assets/d29339a5-1c82-4630-bcb8-0b3466d8710a)