Skip to content

Commit 6b380b9

Browse files
authored
Merge pull request #9 from flavio/multiple-fixes
multiple fixes
2 parents e57facc + c8d7b38 commit 6b380b9

File tree

8 files changed

+113
-50
lines changed

8 files changed

+113
-50
lines changed

.github/dependabot.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: cargo
4+
directory: "/"
5+
schedule:
6+
interval: weekly
7+
open-pull-requests-limit: 10
8+
- package-ecosystem: "github-actions"
9+
directory: "/"
10+
schedule:
11+
interval: "weekly"
12+
open-pull-requests-limit: 10

.github/workflows/tests.yaml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
name: test suite
2+
on: [push, pull_request]
3+
4+
jobs:
5+
test:
6+
name: cargo test
7+
runs-on: ubuntu-latest
8+
steps:
9+
- uses: actions/checkout@v4
10+
- uses: dtolnay/rust-toolchain@stable
11+
- run: |
12+
sudo apt update
13+
sudo apt install -y build-essential libjemalloc-dev
14+
- run: |
15+
make test
16+
make capi

Cargo.toml

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,28 +9,33 @@ edition = "2021"
99
publish = true
1010
license = "Apache-2.0"
1111
authors = [
12-
"Frederic Branczyk <frederic.branczyk@polarsignals.com>",
13-
"Brennan Vincent <brennan.vincent@polarsignals.com>",
12+
"Frederic Branczyk <frederic.branczyk@polarsignals.com>",
13+
"Brennan Vincent <brennan.vincent@polarsignals.com>",
1414
]
1515
repository = "https://github.com/polarsignals/rust-jemalloc-pprof"
1616
keywords = ["jemalloc", "pprof", "memory", "profiling", "observability"]
17-
categories = ["development-tools", "development-tools::profiling", "development-tools::debugging", "memory-management"]
17+
categories = [
18+
"development-tools",
19+
"development-tools::profiling",
20+
"development-tools::debugging",
21+
"memory-management",
22+
]
1823
documentation = "https://docs.rs/jemalloc_pprof/latest/jemalloc_pprof/"
1924
homepage = "https://crates.io/crates/jemalloc_pprof"
2025

2126
[workspace.dependencies]
22-
anyhow = "1.0.66"
23-
flate2 = "1.0.24"
24-
libc = "0.2.138"
25-
once_cell = "1.16.0"
26-
prost = { version = "0.13.1", features = ["no-recursion-limit"] }
27-
tempfile = "3.2.0"
28-
tikv-jemalloc-ctl = { version = "0.5.0", features = ["use_std"] }
29-
tracing = "0.1.37"
30-
tokio = { version = "1.32.0", features = ["time", "sync"] }
31-
paste = "1.0.11"
32-
num = "0.4.0"
33-
errno = "0.3.8"
27+
anyhow = "1"
28+
flate2 = "1.0"
29+
libc = "0.2"
30+
once_cell = "1.19"
31+
prost = { version = "0.13", features = ["no-recursion-limit"] }
32+
tempfile = "3.11"
33+
tikv-jemalloc-ctl = { version = "0.6", features = ["use_std"] }
34+
tracing = "0.1"
35+
tokio = { version = "1", features = ["time", "sync"] }
36+
paste = "1.0"
37+
num = "0.4"
38+
errno = "0.3"
3439
util = { path = "./util", version = "0.4", package = "pprof_util" }
3540
mappings = { path = "./mappings", version = "0.5" }
3641

@@ -44,3 +49,10 @@ once_cell.workspace = true
4449
tracing.workspace = true
4550
tempfile.workspace = true
4651
tokio.workspace = true
52+
53+
[dev-dependencies]
54+
tikv-jemallocator = "0.6"
55+
axum = "0.7"
56+
# re-import tokio to enable all its features. This is required to
57+
# successfully compile the test snipptes that are part of the documentation
58+
tokio = { version = "1", features = ["full"] }

Makefile

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
.PHONY: capi
2+
capi:
3+
cargo build -p capi --release
4+
5+
.PHONY: fmt
6+
fmt:
7+
cargo fmt --all -- --check
8+
9+
.PHONY: lint
10+
lint:
11+
cargo clippy --workspace -- -D warnings
12+
13+
.PHONY: doc
14+
doc:
15+
RUSTDOCFLAGS="--cfg docsrs -D warnings" cargo doc --all-features --no-deps
16+
17+
.PHONY: test
18+
test: fmt lint doc
19+
cargo test --workspace
20+
21+
.PHONY: clean
22+
clean:
23+
cargo clean

README.md

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,14 @@ When adding `tikv-jemallocator` as a dependency, make sure to enable the `profil
2525
```toml
2626
[dependencies]
2727
[target.'cfg(not(target_env = "msvc"))'.dependencies]
28-
tikv-jemallocator = { version = "0.5.4", features = ["profiling", "unprefixed_malloc_on_supported_platforms"] }
28+
tikv-jemallocator = { version = "0.6.0", features = ["profiling", "unprefixed_malloc_on_supported_platforms"] }
2929
```
3030

3131
> Note: We also recommend enabling the `unprefixed_malloc_on_supported_platforms` feature, not strictly necessary, but will influence the rest of the usage.
3232
3333
Then configure the global allocator and configure it with profiling enabled.
3434

35-
```rust
35+
```rust,no_run
3636
#[cfg(not(target_env = "msvc"))]
3737
#[global_allocator]
3838
static ALLOC: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc;
@@ -48,7 +48,7 @@ pub static malloc_conf: &[u8] = b"prof:true,prof_active:true,lg_prof_sample:19\0
4848

4949
We recommend serving the profiling data on an HTTP server such as [axum](https://github.com/tokio-rs/axum), that could look like this, and we'll intentionally include a 4mb allocation to trigger sampling.
5050

51-
```rust
51+
```rust,no_run
5252
#[tokio::main]
5353
async fn main() {
5454
let mut v = vec![];
@@ -88,7 +88,7 @@ fn require_profiling_activated(prof_ctl: &jemalloc_pprof::JemallocProfCtl) -> Re
8888

8989
Then running the application, we can capture a profile and view it the pprof toolchain.
9090

91-
```
91+
```shell
9292
curl localhost:3000/debug/pprof/heap > heap.pb.gz
9393
pprof -http=:8080 heap.pb.gz
9494
```
@@ -116,21 +116,21 @@ functionality is exposed via the `capi` (C API) package.
116116

117117
The following prerequisites are necessary to build the C API package:
118118

119-
* Working Rust and C toolchains. The former can be installed by
120-
following the instructions at https://rustup.rs . The latter can be
119+
- Working Rust and C toolchains. The former can be installed by
120+
following the instructions at <https://rustup.rs> . The latter can be
121121
installed via the distribution's package manager. For example, on
122122
Ubuntu, run `sudo apt install build-essential`.
123-
* `jemalloc` and its development headers. For example, on Ubuntu, run
124-
`sudo apt install jemalloc-dev`.
123+
- `jemalloc` and its development headers. For example, on Ubuntu, run
124+
`sudo apt install libjemalloc-dev`.
125125

126126
Once the prerequisites are installed, the library can be built by
127-
running `cargo build -p capi --release`. There are three files of
127+
running `make capi`. There are three files of
128128
interest:
129129

130-
* The library itself, produced at
130+
- The library itself, produced at
131131
`target/release/libjemalloc_pprof.so`
132-
* A header file, at `capi/include/jemalloc_pprof.h`
133-
* A manual page, at `capi/man/jemalloc_pprof.3`.
132+
- A header file, at `capi/include/jemalloc_pprof.h`
133+
- A manual page, at `capi/man/jemalloc_pprof.3`.
134134

135135
The procedure for installing and using these files depends on your
136136
distribution and build system.
@@ -147,7 +147,7 @@ Once that is done, profiling can be enabled either by setting the
147147
`MALLOC_CONF` variable or by defining a symbol called `malloc_conf` in
148148
the binary. For example:
149149

150-
``` shell
150+
```shell
151151
export MALLOC_CONF="prof:true,prof_active:true,lg_prof_sample:19"
152152
```
153153

@@ -160,7 +160,7 @@ enabled, a profile may be dumped in pprof format via the
160160
This program allocates between 1 and 10 MiB every 100 milliseconds,
161161
and dumps a profile to the file `my_profile` every 2 seconds.
162162

163-
``` c
163+
```c
164164
#include <assert.h>
165165
#include <errno.h>
166166
#include <unistd.h>
@@ -283,11 +283,11 @@ repeatedly_dump(void *ignored)
283283
fprintf(stderr, "errno: %d\n", errno);
284284
continue;
285285
}
286-
if (buf) {
286+
if (buf) {
287287
FILE *file = fopen("my_profile", "w");
288288
assert(file);
289289

290-
fwrite(buf, sizeof(char), len, file);
290+
fwrite(buf, sizeof(char), len, file);
291291
fclose(file);
292292
printf("dumped pprof of size %lu\n", len);
293293
free(buf);

capi/src/lib.rs

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ use std::ptr::null_mut;
66

77
use errno::{set_errno, Errno};
88
use libc::{c_char, c_int, c_void, size_t};
9+
use mappings::MAPPINGS;
910
use tempfile::NamedTempFile;
10-
use util::{parse_jeheap, MAPPINGS};
11+
use util::parse_jeheap;
1112

1213
pub const JP_SUCCESS: c_int = 0;
1314
pub const JP_FAILURE: c_int = -1;
@@ -27,7 +28,7 @@ extern "C" {
2728
enum Error {
2829
Io(std::io::Error),
2930
Mallctl(c_int),
30-
Anyhow(anyhow::Error),
31+
ParseProfile(),
3132
}
3233

3334
impl From<std::io::Error> for Error {
@@ -36,12 +37,6 @@ impl From<std::io::Error> for Error {
3637
}
3738
}
3839

39-
impl From<anyhow::Error> for Error {
40-
fn from(e: anyhow::Error) -> Self {
41-
Self::Anyhow(e)
42-
}
43-
}
44-
4540
fn dump_pprof_inner() -> Result<Vec<u8>, Error> {
4641
let f = NamedTempFile::new()?;
4742
let path = CString::new(f.path().as_os_str().as_bytes().to_vec()).unwrap();
@@ -62,7 +57,8 @@ fn dump_pprof_inner() -> Result<Vec<u8>, Error> {
6257
}
6358

6459
let dump_reader = BufReader::new(f);
65-
let profile = parse_jeheap(dump_reader, MAPPINGS.as_deref())?;
60+
let profile =
61+
parse_jeheap(dump_reader, MAPPINGS.as_deref()).map_err(|_| Error::ParseProfile())?;
6662
let pprof = profile.to_pprof(("inuse_space", "bytes"), ("space", "bytes"), None);
6763
Ok(pprof)
6864
}
@@ -78,7 +74,9 @@ fn dump_pprof_inner() -> Result<Vec<u8>, Error> {
7874
/// If `JP_FAILURE` is returned, the values pointed to by `buf_out` and `n_out`
7975
/// are unspecified.
8076
///
81-
/// SAFETY: You probably don't want to call this from Rust.
77+
/// # Safety
78+
///
79+
/// You probably don't want to call this from Rust.
8280
/// Use the Rust API instead.
8381
#[no_mangle]
8482
pub unsafe extern "C" fn dump_jemalloc_pprof(buf_out: *mut *mut u8, n_out: *mut size_t) -> c_int {
@@ -97,6 +95,13 @@ pub unsafe extern "C" fn dump_jemalloc_pprof(buf_out: *mut *mut u8, n_out: *mut
9795
return JP_FAILURE;
9896
}
9997
};
98+
99+
// Disable clippy warning.
100+
// usize is defined to be the same as uintptr_t (AKA have the same representation as a pointer),
101+
// which is different from size_t, which is the maximum size of an array.
102+
// This is not usually an issue, except on some platforms like CHERI which store extra information in the pointer.
103+
// On those platforms, usize will be 128 bits, while size_t is 64 bit.
104+
#[allow(clippy::useless_conversion)]
100105
let len: size_t = buf.len().try_into().expect("absurd length");
101106
let p = if len > 0 {
102107
// leak is ok, consumer is responsible for freeing

src/lib.rs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,8 @@ pub async fn deactivate_jemalloc_profiling() {
6767
}
6868

6969
/// Per-process singleton for controlling jemalloc profiling.
70-
pub static PROF_CTL: Lazy<Option<Arc<Mutex<JemallocProfCtl>>>> = Lazy::new(|| {
71-
if let Some(ctl) = JemallocProfCtl::get() {
72-
Some(Arc::new(Mutex::new(ctl)))
73-
} else {
74-
None
75-
}
76-
});
70+
pub static PROF_CTL: Lazy<Option<Arc<Mutex<JemallocProfCtl>>>> =
71+
Lazy::new(|| JemallocProfCtl::get().map(|ctl| Arc::new(Mutex::new(ctl))));
7772

7873
/// Metadata about a jemalloc heap profiler.
7974
#[derive(Copy, Clone, Debug)]

util/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -294,12 +294,12 @@ pub fn parse_jeheap<R: BufRead>(
294294
// number is the inverse probability of a byte being sampled.
295295
let sampling_rate: f64 = str::parse(first_line.trim_start_matches("heap_v2/"))?;
296296

297-
while let Some(line) = lines.next() {
297+
for line in &mut lines {
298298
let line = line?;
299299
let line = line.trim();
300300

301301
let words: Vec<_> = line.split_ascii_whitespace().collect();
302-
if words.len() > 0 && words[0] == "@" {
302+
if !words.is_empty() && words[0] == "@" {
303303
if cur_stack.is_some() {
304304
bail!("Stack without corresponding weight!")
305305
}

0 commit comments

Comments
 (0)