Skip to content

Commit

Permalink
Added java virtual machine profiling and flamegraph generation
Browse files Browse the repository at this point in the history
  • Loading branch information
lancelui-amzn committed Jul 15, 2024
1 parent eac35b2 commit 5fe4869
Show file tree
Hide file tree
Showing 25 changed files with 581 additions and 104 deletions.
2 changes: 2 additions & 0 deletions EXAMPLE.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,5 @@ Here are some example screenshots showing the comparison of two different perfor
![Compare Kernel Configs](images/kernel_config_compare.png "Comparing Kernel Connfigs")
### Comparing PMU Data
![Compare PMU Data](images/pmu_stat_compare.png "Comparing PMU Data")
### Comparing Flamegraphs
![Compare Flamegraphs](images/flamegraph_compare.png "Comparing Flamegraphs")
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ APerf collects the following performance data:
- Network stats
- Meminfo
- Profile data (if enabled with `--profile` and `perf` binary present)
- JVM profile data with [async-profiler](https://github.com/async-profiler/async-profiler/tree/master) binary

## Requirements
* [Rust toolchain (v1.61.0+)](https://www.rust-lang.org/tools/install)
Expand Down Expand Up @@ -96,8 +97,9 @@ To see a step-by-step example, please see our example [here](./EXAMPLE.md)

`--profile` gather profiling data using the 'perf' binary

`--profile-java` profile JVMs by PID or name using async-profiler (default profiles all JVMs)

`./aperf report -h`
`./aperf record -h`

**Reporter Flags:**

Expand All @@ -111,6 +113,8 @@ To see a step-by-step example, please see our example [here](./EXAMPLE.md)

`-vv, --verbose --verbose` more verbose messages

`./aperf report -h`

## APerf Issues?
Below are some prerequisites for profiling with APerf:
1. Select the [appropriate instance size](https://github.com/aws/aws-graviton-getting-started/blob/main/perfrunbook/debug_hw_perf.md) if you need PMU stats.
Expand Down
Binary file added images/flamegraph_compare.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
31 changes: 25 additions & 6 deletions src/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ cfg_if::cfg_if! {
}
}
pub mod interrupts;
pub mod java_profile;
pub mod kernel_config;
pub mod meminfodata;
pub mod netstat;
Expand All @@ -33,6 +34,7 @@ use cpu_utilization::{CpuUtilization, CpuUtilizationRaw};
use diskstats::{Diskstats, DiskstatsRaw};
use flamegraphs::{Flamegraph, FlamegraphRaw};
use interrupts::{InterruptData, InterruptDataRaw};
use java_profile::{JavaProfile, JavaProfileRaw};
use kernel_config::KernelConfig;
use log::trace;
use meminfodata::{MeminfoData, MeminfoDataRaw};
Expand All @@ -41,6 +43,7 @@ use perf_profile::{PerfProfile, PerfProfileRaw};
use perf_stat::{PerfStat, PerfStatRaw};
use processes::{Processes, ProcessesRaw};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fs::{File, OpenOptions};
use std::ops::Sub;
use sysctldata::SysctlData;
Expand All @@ -50,18 +53,22 @@ use vmstat::{Vmstat, VmstatRaw};
#[derive(Clone, Debug)]
pub struct CollectorParams {
pub collection_time: u64,
pub elapsed_time: u64,
pub data_file_path: String,
pub data_dir: String,
pub run_name: String,
pub profile: HashMap<String, String>,
}

impl CollectorParams {
fn new() -> Self {
CollectorParams {
collection_time: 0,
elapsed_time: 0,
data_file_path: String::new(),
data_dir: String::new(),
run_name: String::new(),
profile: HashMap::new(),
}
}
}
Expand All @@ -73,6 +80,7 @@ pub struct DataType {
pub full_path: String,
pub dir_name: String,
pub is_static: bool,
pub is_profile_option: bool,
pub collector_params: CollectorParams,
}

Expand All @@ -85,6 +93,7 @@ impl DataType {
full_path: String::new(),
dir_name: String::new(),
is_static,
is_profile_option: false,
collector_params: CollectorParams::new(),
}
}
Expand All @@ -93,6 +102,10 @@ impl DataType {
self.file_handle = handle;
}

pub fn is_profile_option(&mut self) {
self.is_profile_option = true;
}

pub fn init_data_type(&mut self, param: InitParams) -> Result<()> {
trace!("Initializing data type...");
let name = format!(
Expand All @@ -106,8 +119,10 @@ impl DataType {
self.dir_name = param.dir_name.clone();
self.collector_params.run_name = param.dir_name.clone();
self.collector_params.collection_time = param.period;
self.collector_params.elapsed_time = 0;
self.collector_params.data_file_path = self.full_path.clone();
self.collector_params.data_dir = param.dir_name.clone();
self.collector_params.profile = param.profile.clone();

self.file_handle = Some(
OpenOptions::new()
Expand All @@ -130,7 +145,7 @@ impl DataType {

pub fn collect_data(&mut self) -> Result<()> {
trace!("Collecting Data...");
self.data.collect_data()?;
self.data.collect_data(&self.collector_params)?;
Ok(())
}

Expand Down Expand Up @@ -193,10 +208,10 @@ macro_rules! data {
}

impl Data {
fn collect_data(&mut self) -> Result<()> {
fn collect_data(&mut self, params: &CollectorParams) -> Result<()> {
match self {
$(
Data::$x(ref mut value) => value.collect_data()?,
Data::$x(ref mut value) => value.collect_data(&params)?,
)*
}
Ok(())
Expand Down Expand Up @@ -286,7 +301,8 @@ data!(
MeminfoDataRaw,
NetstatRaw,
PerfProfileRaw,
FlamegraphRaw
FlamegraphRaw,
JavaProfileRaw
);

processed_data!(
Expand All @@ -303,7 +319,8 @@ processed_data!(
Netstat,
PerfProfile,
Flamegraph,
AperfStat
AperfStat,
JavaProfile
);

macro_rules! noop {
Expand All @@ -315,7 +332,7 @@ pub trait CollectData {
noop!();
Ok(())
}
fn collect_data(&mut self) -> Result<()> {
fn collect_data(&mut self, _params: &CollectorParams) -> Result<()> {
noop!();
Ok(())
}
Expand Down Expand Up @@ -349,6 +366,7 @@ mod tests {
full_path: String::new(),
dir_name: String::new(),
is_static: false,
is_profile_option: false,
collector_params: CollectorParams::new(),
};

Expand Down Expand Up @@ -376,6 +394,7 @@ mod tests {
full_path: String::new(),
dir_name: String::new(),
is_static: false,
is_profile_option: false,
collector_params: CollectorParams::new(),
};

Expand Down
19 changes: 11 additions & 8 deletions src/data/cpu_utilization.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
extern crate ctor;

use crate::data::{CollectData, Data, DataType, ProcessedData, TimeEnum};
use crate::data::{CollectData, CollectorParams, Data, DataType, ProcessedData, TimeEnum};
use crate::visualizer::{DataVisualizer, GetData};
use crate::{PERFORMANCE_DATA, VISUALIZATION_DATA};
use anyhow::Result;
Expand Down Expand Up @@ -36,7 +36,7 @@ impl Default for CpuUtilizationRaw {
}

impl CollectData for CpuUtilizationRaw {
fn collect_data(&mut self) -> Result<()> {
fn collect_data(&mut self, _params: &CollectorParams) -> Result<()> {
self.time = TimeEnum::DateTime(Utc::now());
self.data = String::new();
self.data = std::fs::read_to_string("/proc/stat")?;
Expand Down Expand Up @@ -406,14 +406,15 @@ fn init_cpu_utilization() {
#[cfg(test)]
mod cpu_tests {
use super::{CpuData, CpuUtilization, CpuUtilizationRaw, UtilData};
use crate::data::{CollectData, Data, ProcessedData};
use crate::data::{CollectData, CollectorParams, Data, ProcessedData};
use crate::visualizer::GetData;

#[test]
fn test_collect_data() {
let mut cpu_utilization = CpuUtilizationRaw::new();
let params = CollectorParams::new();

cpu_utilization.collect_data().unwrap();
cpu_utilization.collect_data(&params).unwrap();
assert!(!cpu_utilization.data.is_empty());
}

Expand All @@ -423,9 +424,10 @@ mod cpu_tests {
let mut cpu_util_zero = CpuUtilizationRaw::new();
let mut cpu_util_one = CpuUtilizationRaw::new();
let mut processed_buffer: Vec<ProcessedData> = Vec::<ProcessedData>::new();
let params = CollectorParams::new();

cpu_util_zero.collect_data().unwrap();
cpu_util_one.collect_data().unwrap();
cpu_util_zero.collect_data(&params).unwrap();
cpu_util_one.collect_data(&params).unwrap();

buffer.push(Data::CpuUtilizationRaw(cpu_util_zero));
buffer.push(Data::CpuUtilizationRaw(cpu_util_one));
Expand Down Expand Up @@ -463,9 +465,10 @@ mod cpu_tests {
let mut cpu_util_zero = CpuUtilizationRaw::new();
let mut cpu_util_one = CpuUtilizationRaw::new();
let mut processed_buffer: Vec<ProcessedData> = Vec::<ProcessedData>::new();
let params = CollectorParams::new();

cpu_util_zero.collect_data().unwrap();
cpu_util_one.collect_data().unwrap();
cpu_util_zero.collect_data(&params).unwrap();
cpu_util_one.collect_data(&params).unwrap();

buffer.push(Data::CpuUtilizationRaw(cpu_util_zero));
buffer.push(Data::CpuUtilizationRaw(cpu_util_one));
Expand Down
21 changes: 13 additions & 8 deletions src/data/diskstats.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
extern crate ctor;

use crate::data::constants::*;
use crate::data::{CollectData, Data, DataType, ProcessedData, TimeEnum};
use crate::data::{CollectData, CollectorParams, Data, DataType, ProcessedData, TimeEnum};
use crate::visualizer::{DataVisualizer, GetData, GraphLimitType, GraphMetadata};
use crate::{PERFORMANCE_DATA, VISUALIZATION_DATA};
use anyhow::Result;
Expand Down Expand Up @@ -32,7 +32,7 @@ impl DiskstatsRaw {
}

impl CollectData for DiskstatsRaw {
fn collect_data(&mut self) -> Result<()> {
fn collect_data(&mut self, _params: &CollectorParams) -> Result<()> {
self.time = TimeEnum::DateTime(Utc::now());
self.data = String::new();
self.data = std::fs::read_to_string("/proc/diskstats")?;
Expand Down Expand Up @@ -363,16 +363,17 @@ fn init_diskstats() {
#[cfg(test)]
mod tests {
use super::{DiskstatKeys, Diskstats, DiskstatsRaw, EndDiskValues};
use crate::data::{CollectData, Data, ProcessedData};
use crate::data::{CollectData, CollectorParams, Data, ProcessedData};
use crate::visualizer::GetData;
use std::collections::HashMap;
use strum::IntoEnumIterator;

#[test]
fn test_collect_data() {
let mut diskstats = DiskstatsRaw::new();
let params = CollectorParams::new();

diskstats.collect_data().unwrap();
diskstats.collect_data(&params).unwrap();
assert!(!diskstats.data.is_empty());
}

Expand All @@ -383,7 +384,9 @@ mod tests {
for key in DiskstatKeys::iter() {
key_map.insert(key.to_string(), 0);
}
stat.collect_data().unwrap();
let params = CollectorParams::new();

stat.collect_data(&params).unwrap();
let processed_stat = Diskstats::new()
.process_raw_data(Data::DiskstatsRaw(stat))
.unwrap();
Expand All @@ -407,8 +410,9 @@ mod tests {
let mut buffer: Vec<Data> = Vec::<Data>::new();
let mut diskstat = DiskstatsRaw::new();
let mut processed_buffer: Vec<ProcessedData> = Vec::<ProcessedData>::new();
let params = CollectorParams::new();

diskstat.collect_data().unwrap();
diskstat.collect_data(&params).unwrap();
buffer.push(Data::DiskstatsRaw(diskstat));
processed_buffer.push(
Diskstats::new()
Expand All @@ -428,9 +432,10 @@ mod tests {
let mut diskstat_zero = DiskstatsRaw::new();
let mut diskstat_one = DiskstatsRaw::new();
let mut processed_buffer: Vec<ProcessedData> = Vec::<ProcessedData>::new();
let params = CollectorParams::new();

diskstat_zero.collect_data().unwrap();
diskstat_one.collect_data().unwrap();
diskstat_zero.collect_data(&params).unwrap();
diskstat_one.collect_data(&params).unwrap();
buffer.push(Data::DiskstatsRaw(diskstat_zero));
buffer.push(Data::DiskstatsRaw(diskstat_one));
for buf in buffer {
Expand Down
3 changes: 2 additions & 1 deletion src/data/flamegraphs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,11 +163,12 @@ impl GetData for Flamegraph {
fn init_flamegraph() {
let flamegraph_raw = FlamegraphRaw::new();
let file_name = FLAMEGRAPHS_FILE_NAME.to_string();
let dt = DataType::new(
let mut dt = DataType::new(
Data::FlamegraphRaw(flamegraph_raw.clone()),
file_name.clone(),
false,
);
dt.is_profile_option();
let flamegraph = Flamegraph::new();
let js_file_name = file_name.clone() + ".js";
let mut dv = DataVisualizer::new(
Expand Down
Loading

0 comments on commit 5fe4869

Please sign in to comment.