joule_profiler_cli/
lib.rs1use std::collections::HashSet;
2
3use clap::{ArgAction, Parser, ValueEnum};
4
5use anyhow::Result;
6pub use commands::ProfilerCommand;
7use joule_profiler_core::config::{Command, Config, ProfileConfig};
8
9use crate::output::{
10 displayer::Displayer,
11 formats::{
12 OutputFormat, csv::CsvOutput, json::JsonOutput, output_format, terminal::TerminalOutput,
13 },
14};
15
16mod commands;
17mod logging;
18mod output;
19
20#[allow(clippy::struct_excessive_bools)]
22#[derive(Parser, Debug)]
23#[command(name = "joule-profiler")]
24#[command(
25 version,
26 about = "Measure program metrics from various sources like RAPL"
27)]
28pub struct CliArgs {
29 #[arg(short = 'v', long = "verbose", action = ArgAction::Count)]
31 pub verbose: u8,
32
33 #[arg(long = "rapl-path")]
42 pub rapl_path: Option<String>,
43
44 #[arg(short = 's', long = "sockets")]
46 pub sockets: Option<String>,
47
48 #[arg(long, conflicts_with = "csv")]
50 pub json: bool,
51
52 #[arg(long, conflicts_with = "json")]
54 pub csv: bool,
55
56 #[arg(short = 'o', long = "output-file")]
58 pub output_file: Option<String>,
59
60 #[arg(long)]
62 pub gpu: bool,
63
64 #[arg(long)]
66 pub perf: bool,
67
68 #[arg(long = "rapl-backend", value_enum, default_value_t = RaplBackend::Perf)]
70 pub rapl_backend: RaplBackend,
71
72 #[command(subcommand)]
74 pub command: ProfilerCommand,
75}
76
77impl CliArgs {
78 pub fn from_args() -> Self {
79 Self::parse()
80 }
81}
82
83impl From<CliArgs> for Config {
84 fn from(cli_args: CliArgs) -> Self {
85 let command = match cli_args.command {
86 ProfilerCommand::Profile(profile_args) => Command::Profile(ProfileConfig {
87 stdout_file: profile_args.stdout_file,
88 cmd: profile_args.cmd,
89 token_pattern: profile_args.token_pattern,
90 use_root: profile_args.use_root,
91 }),
92
93 ProfilerCommand::ListSensors => Command::ListSensors,
94 };
95
96 Config {
97 command,
98 rapl_path: cli_args.rapl_path,
99 }
100 }
101}
102
103#[derive(Clone, Debug, ValueEnum)]
104pub enum RaplBackend {
105 Perf,
106 Powercap,
107}
108
109pub fn output_format_to_displayer(cli: &CliArgs) -> Result<Box<dyn Displayer>> {
110 let output_format = output_format(cli.json, cli.csv);
111 let output_file = cli.output_file.clone();
112
113 let displayer = match output_format {
114 OutputFormat::Terminal => TerminalOutput.into(),
115 OutputFormat::Json => JsonOutput::new(output_file)?.into(),
116 OutputFormat::Csv => CsvOutput::try_new(output_file)?.into(),
117 };
118
119 Ok(displayer)
120}
121
122pub fn init_logging(verbose: u8) {
123 logging::init_logging(verbose);
124}
125
126pub fn parse_sockets_spec(sockets_spec: Option<&str>) -> Option<HashSet<u32>> {
127 sockets_spec.map(|s| {
128 s.split(',')
129 .filter_map(|x| x.trim().parse::<u32>().ok())
130 .collect()
131 })
132}