Skip to content

Commit 2d3770a

Browse files
author
Jonathan Woollett-Light
committed
fix: tracing-flame
Adds `tracing-flame` to generate profiles for flamegraphs. Signed-off-by: Jonathan Woollett-Light <jcawl@amazon.co.uk>
1 parent e4c1fdc commit 2d3770a

File tree

5 files changed

+43
-13
lines changed

5 files changed

+43
-13
lines changed

src/api_server/src/request/logger.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ mod tests {
4242
show_level: Some(false),
4343
show_log_origin: Some(false),
4444
new_format: None,
45+
profile_file: None,
4546
};
4647
match vmm_action_from_request(parse_put_logger(&Body::new(body)).unwrap()) {
4748
VmmAction::ConfigureLogger(cfg) => assert_eq!(cfg, expected_cfg),
@@ -61,6 +62,7 @@ mod tests {
6162
show_level: Some(false),
6263
show_log_origin: Some(false),
6364
new_format: None,
65+
profile_file: None,
6466
};
6567
match vmm_action_from_request(parse_put_logger(&Body::new(body)).unwrap()) {
6668
VmmAction::ConfigureLogger(cfg) => assert_eq!(cfg, expected_cfg),

src/firecracker/src/main.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,11 @@ fn main_exitable() -> FcExitCode {
203203
.takes_value(false)
204204
.help("Whether to use the new logging output format."),
205205
)
206+
.arg(
207+
Argument::new("profile-file")
208+
.takes_value(true)
209+
.help("Path to a fifo or a file used for configuring the profiler on startup."),
210+
)
206211
.arg(
207212
Argument::new("metrics-path")
208213
.takes_value(true)
@@ -302,6 +307,7 @@ fn main_exitable() -> FcExitCode {
302307
show_level: Some(arguments.flag_present("show-level")),
303308
show_log_origin: Some(arguments.flag_present("show-log-origin")),
304309
new_format: Some(arguments.flag_present("new-format")),
310+
profile_file: arguments.single_value("profile-file").map(PathBuf::from),
305311
};
306312

307313
if let Err(err) = logger_config.init() {

src/vmm/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ vm-fdt = "0.2.0"
3131
vm-superio = "0.7.0"
3232
tracing = { version = "0.1.37", features = ["attributes"] }
3333
tracing-subscriber = "0.3.17"
34+
tracing-flame = "0.2.0"
3435
tracing-core = "0.1.31"
3536
log = { version = "0.4.17", features = ["serde"] }
3637

src/vmm/src/rpc_interface.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2078,6 +2078,7 @@ mod tests {
20782078
show_level: Some(false),
20792079
show_log_origin: Some(false),
20802080
new_format: Some(false),
2081+
profile_file: None,
20812082
}),
20822083
VmmActionError::OperationNotSupportedPostBoot,
20832084
);

src/vmm/src/vmm_config/mod.rs

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
use core::fmt;
55
use std::convert::{From, TryInto};
66
use std::fs::{File, OpenOptions};
7-
use std::io::{self, LineWriter, Write};
7+
use std::io::{self, BufWriter, LineWriter, Write};
88
use std::os::unix::fs::OpenOptionsExt;
99
use std::path::Path;
1010
use std::str::FromStr;
@@ -14,6 +14,7 @@ use libc::O_NONBLOCK;
1414
use rate_limiter::{BucketUpdate, RateLimiter, TokenBucket};
1515
use serde::{Deserialize, Serialize};
1616
use tracing_core::{Event, Subscriber};
17+
use tracing_flame::FlameLayer;
1718
use tracing_subscriber::fmt::format::{self, FormatEvent, FormatFields};
1819
use tracing_subscriber::fmt::{FmtContext, Layer};
1920
use tracing_subscriber::prelude::*;
@@ -278,6 +279,8 @@ pub struct LoggerConfig {
278279
pub show_log_origin: Option<bool>,
279280
/// Use the new logger format.
280281
pub new_format: Option<bool>,
282+
/// The profile file to output.
283+
pub profile_file: Option<std::path::PathBuf>,
281284
}
282285

283286
/// Error with actions on the `LoggerConfig`.
@@ -294,13 +297,24 @@ pub enum LoggerConfigError {
294297
Write(std::io::Error),
295298
}
296299

300+
macro_rules! registry {
301+
($($x:expr),*) => {
302+
{
303+
tracing_subscriber::registry()
304+
$(
305+
.with($x)
306+
)*
307+
}
308+
}
309+
}
310+
297311
impl LoggerConfig {
298312
const INIT_MESSAGE: &str = concat!("Running Firecracker v", env!("FIRECRACKER_VERSION"), "\n");
299313

300314
/// Initializes the logger.
301315
pub fn init(&self) -> std::result::Result<(), LoggerConfigError> {
302316
let level = tracing::Level::from(self.level.unwrap_or_default());
303-
let level_filter = tracing_subscriber::filter::LevelFilter::from_level(level);
317+
let filter = tracing_subscriber::filter::LevelFilter::from_level(level);
304318

305319
// In case we open a FIFO, in order to not block the instance if nobody is consuming the
306320
// message that is flushed to the two pipes, we are opening it with `O_NONBLOCK` flag.
@@ -320,17 +334,11 @@ impl LoggerConfig {
320334
// Wrap file to satisfy `tracing_subscriber::fmt::MakeWriter`.
321335
let writer = Mutex::new(LineWriter::new(file));
322336

323-
// Initialize the layers.
324-
if self.new_format.unwrap_or_default() {
325-
tracing_subscriber::registry()
326-
.with(level_filter)
327-
.with(new_log(self, writer))
328-
.try_init()
329-
} else {
330-
tracing_subscriber::registry()
331-
.with(level_filter)
332-
.with(old_log(self, writer))
333-
.try_init()
337+
match (self.new_format.unwrap_or_default(), &self.profile_file) {
338+
(true, Some(p)) => registry!(filter, new_log(self, writer), flame(p)).try_init(),
339+
(false, Some(p)) => registry!(filter, old_log(self, writer), flame(p)).try_init(),
340+
(true, None) => registry!(filter, new_log(self, writer)).try_init(),
341+
(false, None) => registry!(filter, old_log(self, writer)).try_init(),
334342
}
335343
.map_err(LoggerConfigError::Init)?;
336344

@@ -369,6 +377,18 @@ fn old_log<S: Subscriber + for<'span> LookupSpan<'span>>(
369377
.with_writer(writer)
370378
}
371379

380+
fn flame<S: Subscriber + for<'span> LookupSpan<'span>>(
381+
profile_file: &std::path::PathBuf,
382+
) -> FlameLayer<S, BufWriter<File>> {
383+
// We can discard the flush guard as
384+
// > This type is only needed when using
385+
// > `tracing::subscriber::set_global_default`, which prevents the drop
386+
// > implementation of layers from running when the program exits.
387+
// See https://docs.rs/tracing-flame/0.2.0/tracing_flame/struct.FlushGuard.html
388+
let (flame_layer, _guard) = FlameLayer::with_file(profile_file).unwrap();
389+
flame_layer
390+
}
391+
372392
// use std::sync::atomic::AtomicUsize;
373393
// use std::sync::atomic::Ordering;
374394
// static GURAD: AtomicUsize = AtomicUsize::new(0);

0 commit comments

Comments
 (0)