Skip to content

Commit e66ca9f

Browse files
authored
Merge pull request #97 from arielb1/better-docs
Better docs, also allow spawning its own runtime
2 parents 7d90b79 + a82bbeb commit e66ca9f

File tree

17 files changed

+875
-56
lines changed

17 files changed

+875
-56
lines changed

.github/actions/rust-build/action.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,8 @@ runs:
2424
- name: Run tests
2525
shell: bash
2626
run: |
27-
cargo test --verbose ${{ inputs.flags }}
27+
cargo test --verbose ${{ inputs.flags }}
28+
if [ "${{ inputs.toolchain }}" == nightly -a "${{ inputs.flags }}" == "--all-features" ]; then
29+
# docs use unstable features, run them on nightly
30+
RUSTDOCFLAGS="-D warnings --cfg docsrs" cargo doc --verbose ${{ inputs.flags }}
31+
fi

.github/workflows/build.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ jobs:
1010
toolchain:
1111
- "1.86" # Current MSRV due to 1.85 having problems with the AWS SDK
1212
- stable
13+
- nightly
1314
flags:
1415
- "--all-features"
1516
- "--no-default-features"
@@ -92,4 +93,4 @@ jobs:
9293
- name: Run integration test
9394
shell: bash
9495
working-directory: tests
95-
run: chmod +x simple pollcatch-decoder && LD_LIBRARY_PATH=$PWD ./integration.sh
96+
run: chmod +x simple pollcatch-decoder && LD_LIBRARY_PATH=$PWD ./integration.sh && LD_LIBRARY_PATH=$PWD ./separate_runtime_integration.sh

.github/workflows/format.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ jobs:
2727
- uses: actions/checkout@v4
2828
- uses: dtolnay/rust-toolchain@stable
2929
- uses: Swatinem/rust-cache@v2
30+
- name: Install clippy
31+
shell: bash
32+
run: rustup component add clippy
3033
- name: Run clippy check
3134
id: cargoClippy
3235
shell: bash
@@ -40,6 +43,9 @@ jobs:
4043
- uses: Swatinem/rust-cache@v2
4144
with:
4245
cache-directories: decoder
46+
- name: Install clippy
47+
shell: bash
48+
run: rustup component add clippy
4349
- name: Run clippy check - decoder
4450
id: cargoClippyDecoder
4551
shell: bash

Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,8 @@ s3-no-defaults = ["dep:aws-config", "dep:aws-sdk-s3"]
4747
aws-metadata = ["aws-metadata-no-defaults", "aws-config/default", "reqwest/rustls-tls"]
4848
# A version of the aws-metadata feature that does not enable AWS default features
4949
aws-metadata-no-defaults = ["dep:reqwest", "dep:aws-config", "dep:aws-arn"]
50+
51+
[package.metadata.docs.rs]
52+
all-features = true
53+
targets = ["x86_64-unknown-linux-gnu"]
54+
rustdoc-args = ["--cfg", "docsrs"]

README.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,35 @@ The metadata is not used by the agent directly, and only provided to the reporte
7676
[Fargate]: https://aws.amazon.com/fargate
7777
[IMDS]: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html
7878

79+
### What information the profiler gathers
80+
81+
Memory samples (JFR `profiler.Malloc`) sample allocated memory every
82+
so many bytes of allocated memory, and are matched by `profiler.Free`
83+
to allow detecting if that memory is not free'd.
84+
85+
CPU-time samples (JFR `jdk.ExecutionSample`) sample only threads that
86+
are currently running on a CPU, not threads that are sleeping.
87+
88+
Wall-clock samples (JFR `profiler.WallClockSample`) sample threads
89+
whether they are sleeping or running, and can therefore be
90+
very useful for finding threads that are blocked, for example
91+
on a synchronous lock or a slow system call.
92+
93+
When using Tokio, since tasks are not threads, tasks that are not
94+
currently running will not be sampled by a wall clock sample. However,
95+
a wall clock sample is still very useful in Tokio, since it is what
96+
you want to catch tasks that are blocking a thread by waiting on
97+
synchronous operations.
98+
99+
The default is to do a wall-clock sample every second, and a CPU-time
100+
sample every 100 CPU milliseconds. This can be configured via
101+
[`ProfilerOptionsBuilder`].
102+
103+
Memory samples are not enabled by default, but can be enabled by [`with_native_mem_bytes`].
104+
105+
[`ProfilerOptionsBuilder`]: https://docs.rs/async-profiler-agent/0.1/async_profiler_agent/profiler/struct.ProfilerOptionsBuilder.html
106+
[`with_native_mem_bytes`]: https://docs.rs/async-profiler-agent/0.1/async_profiler_agent/profiler/struct.ProfilerOptionsBuilder.html#method.with_native_mem_bytes
107+
79108
### PollCatch
80109

81110
If you want to find long poll times, and you have `RUSTFLAGS="--cfg tokio_unstable"`, you can

examples/simple/main.rs

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ struct S3BucketArgs {
4040
}
4141

4242
/// Simple program to test the profiler agent
43+
///
44+
/// This program is intended for test purposes ONLY.
4345
#[derive(Debug, Parser)]
4446
#[command(group(
4547
ArgGroup::new("options")
@@ -62,6 +64,9 @@ struct Args {
6264
worker_threads: Option<usize>,
6365
#[arg(long)]
6466
native_mem: Option<String>,
67+
/// Use the spawn_thread API instead of the Tokio API (does not demonstrate stopping)
68+
#[arg(long)]
69+
spawn_into_thread: bool,
6570
}
6671

6772
impl Args {
@@ -95,6 +100,16 @@ pub fn main() -> anyhow::Result<()> {
95100
rt.block_on(main_internal(args))
96101
}
97102

103+
async fn run_slow(args: &Args) {
104+
if let Some(timeout) = args.duration {
105+
tokio::time::timeout(timeout, slow::run())
106+
.await
107+
.unwrap_err();
108+
} else {
109+
slow::run().await;
110+
}
111+
}
112+
98113
async fn main_internal(args: Args) -> Result<(), anyhow::Error> {
99114
set_up_tracing();
100115
tracing::info!("main started");
@@ -104,7 +119,7 @@ async fn main_internal(args: Args) -> Result<(), anyhow::Error> {
104119
let profiler = match (&args.local, args.s3_bucket_args()) {
105120
(Some(local), S3BucketArgs { .. }) => profiler
106121
.with_reporter(LocalReporter::new(local))
107-
.with_custom_agent_metadata(AgentMetadata::Other),
122+
.with_custom_agent_metadata(AgentMetadata::NoMetadata),
108123
#[cfg(feature = "s3-no-defaults")]
109124
(
110125
_,
@@ -133,19 +148,21 @@ async fn main_internal(args: Args) -> Result<(), anyhow::Error> {
133148
.with_profiler_options(profiler_options)
134149
.build();
135150

136-
tracing::info!("starting profiler");
137-
let handle = profiler.spawn_controllable()?;
138-
tracing::info!("profiler started");
139-
140-
if let Some(timeout) = args.duration {
141-
tokio::time::timeout(timeout, slow::run())
142-
.await
143-
.unwrap_err();
151+
if args.spawn_into_thread {
152+
tracing::info!("starting profiler");
153+
std::thread::spawn(move || {
154+
profiler.spawn_thread().unwrap();
155+
});
156+
run_slow(&args).await;
144157
} else {
145-
slow::run().await;
146-
}
158+
tracing::info!("starting profiler");
159+
let handle = profiler.spawn_controllable()?;
160+
tracing::info!("profiler started");
147161

148-
handle.stop().await;
162+
run_slow(&args).await;
163+
164+
handle.stop().await;
165+
}
149166

150167
Ok(())
151168
}

src/asprof/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,18 +108,18 @@ impl super::profiler::ProfilerEngine for AsProf {
108108
jfr_file_path: &Path,
109109
options: &ProfilerOptions,
110110
) -> Result<(), self::AsProfError> {
111-
tracing::debug!("starting the async-profiler and giving JFR file path: {jfr_file_path:?}");
111+
tracing::debug!("starting profiling session and giving JFR file path: {jfr_file_path:?}");
112112

113113
let args = options.to_args_string(jfr_file_path);
114114

115115
Self::asprof_execute(&args)?;
116-
tracing::debug!("async-profiler started successfully");
116+
tracing::debug!("starting profiling session - success");
117117
Ok(())
118118
}
119119

120120
fn stop_async_profiler() -> Result<(), self::AsProfError> {
121121
Self::asprof_execute("stop")?;
122-
tracing::debug!("async-profiler stopped successfully");
122+
tracing::debug!("stopping profiling session - success");
123123
Ok(())
124124
}
125125
}

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// SPDX-License-Identifier: Apache-2.0
33

44
#![deny(missing_docs)]
5+
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
56

67
//! ## async-profiler Rust agent
78
//! An in-process Rust agent for profiling an application using [async-profiler] and uploading the resulting profiles.

src/metadata/mod.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
pub use std::time::Duration;
77

88
/// Host Metadata, which describes a host that runs a profiling agent. The current set of supported agent metadata is
9-
/// AWS-specific. If you are not running on AWS, you can use [AgentMetadata::Other].
9+
/// AWS-specific. If you are not running on AWS, you can use [AgentMetadata::NoMetadata].
1010
#[derive(Debug, Clone, PartialEq, Eq)]
1111
#[non_exhaustive]
1212
pub enum AgentMetadata {
@@ -43,7 +43,11 @@ pub enum AgentMetadata {
4343
ecs_cluster_arn: String,
4444
},
4545
/// Metadata for a host that is neither an EC2 nor a Fargate
46+
#[deprecated = "Use AgentMetadata::NoMetadata"]
4647
Other,
48+
/// A placeholder when a host has no metadata, or when a reporter does not
49+
/// use metadata.
50+
NoMetadata,
4751
}
4852

4953
/// Metadata associated with a specific individual profiling report
@@ -66,7 +70,7 @@ pub mod aws;
6670
/// [private] dummy metadata to make testing easier
6771
#[cfg(test)]
6872
pub(crate) const DUMMY_METADATA: ReportMetadata<'static> = ReportMetadata {
69-
instance: &AgentMetadata::Other,
73+
instance: &AgentMetadata::NoMetadata,
7074
start: Duration::from_secs(1),
7175
end: Duration::from_secs(2),
7276
reporting_interval: Duration::from_secs(1),

0 commit comments

Comments
 (0)