mirror of
https://github.com/Zenithsiz/ftmemsim.git
synced 2026-02-04 02:08:39 +00:00
Separated other graphs into their own functions.
This commit is contained in:
parent
6ed293c165
commit
e79000c301
@ -30,9 +30,11 @@ pub enum SubCmd {
|
||||
#[clap(name = "page-migrations")]
|
||||
PageMigrations(PageMigrations),
|
||||
|
||||
// TODO: This is no longer a histogram, rename it?
|
||||
#[clap(name = "page-migrations-hist")]
|
||||
PageMigrationsHist(PageMigrationsHist),
|
||||
|
||||
// TODO: This is no longer a histogram, rename it?
|
||||
#[clap(name = "page-migrations-hist-multiple")]
|
||||
PageMigrationsHistMultiple(PageMigrationsHistMultiple),
|
||||
|
||||
|
||||
@ -34,258 +34,10 @@ fn main() -> Result<(), anyhow::Error> {
|
||||
// Then check the sub-command
|
||||
match args.sub_cmd {
|
||||
args::SubCmd::PageMigrations(cmd_args) => self::draw_page_migrations(&cmd_args)?,
|
||||
|
||||
// TODO: This is no longer a histogram, rename it?
|
||||
args::SubCmd::PageMigrationsHist(cmd_args) => {
|
||||
// Parse and build the data
|
||||
let data = self::read_data(&cmd_args.input_file)?;
|
||||
let data = self::page_migrations_hist_data(&data);
|
||||
|
||||
// Finally create and save the plot
|
||||
let mut fg = gnuplot::Figure::new();
|
||||
fg.axes2d()
|
||||
.lines(0..data.len(), &data, &[
|
||||
PlotOption::Caption("Migration count"),
|
||||
PlotOption::Color("black"),
|
||||
])
|
||||
.set_x_range(AutoOption::Fix(0.0), AutoOption::Fix(data.len() as f64))
|
||||
.set_y_range(AutoOption::Fix(0.0), AutoOption::Auto)
|
||||
.set_x_label("Migrations (flattened)", &[])
|
||||
.set_y_label("Migrations", &[]);
|
||||
|
||||
// Then output the plot
|
||||
self::handle_output(&cmd_args.output, &mut fg).context("Unable to handle output")?;
|
||||
},
|
||||
|
||||
// TODO: This is no longer a histogram, rename it?
|
||||
args::SubCmd::PageMigrationsHistMultiple(cmd_args) => {
|
||||
// Create the figure
|
||||
// Note: We do this before parsing the data since we parse
|
||||
// the files in parallel (with a limit, to not load too
|
||||
// many at once)
|
||||
let mut fg = gnuplot::Figure::new();
|
||||
let fg_axes2d = fg.axes2d();
|
||||
|
||||
// Then process all input files
|
||||
// TODO: Process them in parallel with `rayon`? Issue is that we need to add each
|
||||
// plot in order so that the legend stays consistent.
|
||||
for (data_idx, input_file) in cmd_args.input_files.iter().enumerate() {
|
||||
// Parse and build the data
|
||||
let data = self::read_data(input_file).with_context(|| format!("Unable to read {input_file:?}"))?;
|
||||
let data = self::page_migrations_hist_data(&data);
|
||||
|
||||
// Then render the lines
|
||||
let progress = data_idx as f64 / (cmd_args.input_files.len() as f64 - 1.0);
|
||||
|
||||
let color = LinSrgb::new(1.0, 0.0, 0.0).mix(LinSrgb::new(0.0, 1.0, 0.0), progress);
|
||||
let color = format!("#{:x}", color.into_format::<u8>());
|
||||
|
||||
fg_axes2d.lines(0..data.len(), &data, &[
|
||||
PlotOption::Caption(&format!("Migration count ({})", input_file.display())),
|
||||
PlotOption::Color(&color),
|
||||
]);
|
||||
}
|
||||
|
||||
// Finally finish building the graph
|
||||
fg_axes2d
|
||||
.set_x_range(AutoOption::Fix(0.0), AutoOption::Auto)
|
||||
.set_y_range(AutoOption::Fix(0.0), AutoOption::Auto)
|
||||
.set_x_label("Migrations (flattened)", &[])
|
||||
.set_y_label("Migrations", &[]);
|
||||
|
||||
// Then output the plot
|
||||
self::handle_output(&cmd_args.output, &mut fg).context("Unable to handle output")?;
|
||||
},
|
||||
|
||||
args::SubCmd::PageTemperature(cmd_args) => {
|
||||
// Parse the input file
|
||||
let data = self::read_data(&cmd_args.input_file)?;
|
||||
|
||||
let (min_time, max_time) = data
|
||||
.hemem
|
||||
.page_accesses
|
||||
.accesses
|
||||
.iter()
|
||||
.map(|page_access| page_access.time)
|
||||
.minmax()
|
||||
.into_option()
|
||||
.unwrap_or((0, 1));
|
||||
|
||||
// Get all the points
|
||||
struct Point {
|
||||
x: f64,
|
||||
y_avg: f64,
|
||||
y_err: f64,
|
||||
global_cooled: bool,
|
||||
}
|
||||
let mut cur_temps = HashMap::new();
|
||||
let points = data
|
||||
.hemem
|
||||
.page_accesses
|
||||
.accesses
|
||||
.iter()
|
||||
.map(|page_access| {
|
||||
// Update the temperatures
|
||||
// TODO: Optimize global cooling?
|
||||
*cur_temps.entry(page_access.page_ptr).or_insert(0) = page_access.prev_temp;
|
||||
if page_access.caused_cooling {
|
||||
for temp in cur_temps.values_mut() {
|
||||
*temp /= 2;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Optimize this with a moving average?
|
||||
let average_temp = &cur_temps
|
||||
.values()
|
||||
.map(|&temp| temp as f64)
|
||||
.collect::<average::Variance>();
|
||||
Point {
|
||||
x: (page_access.time - min_time) as f64 / (max_time - min_time) as f64,
|
||||
y_avg: average_temp.mean(),
|
||||
y_err: average_temp.error(),
|
||||
global_cooled: page_access.caused_cooling,
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let max_y = points.iter().map(|p| p.y_avg).max_by(f64::total_cmp).unwrap_or(0.0);
|
||||
|
||||
// Finally create and save the plot
|
||||
let mut fg = gnuplot::Figure::new();
|
||||
fg.axes2d()
|
||||
.boxes_set_width(
|
||||
points.iter().map(|p| p.x),
|
||||
points.iter().map(|p| if p.global_cooled { max_y } else { 0.0 }),
|
||||
(0..points.len()).map(|_| 0.1 / (points.len() as f64)),
|
||||
&[
|
||||
PlotOption::Caption("Global cooling"),
|
||||
PlotOption::Color("red"),
|
||||
PlotOption::LineWidth(0.1),
|
||||
],
|
||||
)
|
||||
.lines(points.iter().map(|p| p.x), points.iter().map(|p| p.y_avg), &[
|
||||
PlotOption::Caption("Page migrations (Avg)"),
|
||||
PlotOption::Color("black"),
|
||||
PlotOption::LineStyle(DashType::Solid),
|
||||
PlotOption::LineWidth(1.0),
|
||||
])
|
||||
.fill_between(
|
||||
points.iter().map(|p| p.x),
|
||||
points.iter().map(|p| p.y_avg - p.y_err),
|
||||
points.iter().map(|p| p.y_avg + p.y_err),
|
||||
&[
|
||||
PlotOption::Caption("Page migrations (Error)"),
|
||||
PlotOption::Color("green"),
|
||||
PlotOption::FillAlpha(0.3),
|
||||
PlotOption::FillRegion(FillRegionType::Below),
|
||||
],
|
||||
)
|
||||
.set_x_label("Time (normalized)", &[])
|
||||
.set_y_label("Temperature", &[])
|
||||
.set_x_range(AutoOption::Fix(0.0), AutoOption::Fix(1.0))
|
||||
.set_y_range(AutoOption::Fix(0.0), AutoOption::Fix(max_y));
|
||||
|
||||
// Then output the plot
|
||||
self::handle_output(&cmd_args.output, &mut fg).context("Unable to handle output")?;
|
||||
},
|
||||
|
||||
args::SubCmd::PageTemperatureDensity(cmd_args) => {
|
||||
// Parse the input file
|
||||
let data = self::read_data(&cmd_args.input_file)?;
|
||||
|
||||
let (min_time, max_time) = data
|
||||
.hemem
|
||||
.page_accesses
|
||||
.accesses
|
||||
.iter()
|
||||
.map(|page_access| page_access.time)
|
||||
.minmax()
|
||||
.into_option()
|
||||
.unwrap_or((0, 1));
|
||||
|
||||
// Then index the page pointers.
|
||||
// Note: We do this because the page pointers are very far away, value-wise, which
|
||||
// causes them to display far away in the graph. Since the actual values of the
|
||||
// pages don't matter to us, we just index them by order of appearance.
|
||||
let page_ptr_idxs = data
|
||||
.hemem
|
||||
.page_migrations
|
||||
.migrations
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(idx, (page_ptr, _))| (page_ptr, idx))
|
||||
.collect::<std::collections::BTreeMap<_, _>>();
|
||||
|
||||
|
||||
// Get all the points
|
||||
let mut cur_temps = HashMap::<u64, f64>::new();
|
||||
let points = data
|
||||
.hemem
|
||||
.page_accesses
|
||||
.accesses
|
||||
.iter()
|
||||
.group_by(|page_access| page_access.page_ptr)
|
||||
.into_iter()
|
||||
.map(|(page_ptr, page_accesses)| {
|
||||
// Note: The page accesses will already be sorted by time
|
||||
let mut temps = page_accesses
|
||||
.map(|page_access| {
|
||||
let cur_temp = cur_temps.entry(page_ptr).or_insert(0.0);
|
||||
match page_access.kind {
|
||||
ftmemsim::data::PageAccessKind::Read => *cur_temp += cmd_args.temp_read_weight,
|
||||
ftmemsim::data::PageAccessKind::Write => *cur_temp += cmd_args.temp_write_weight,
|
||||
};
|
||||
|
||||
let time = (page_access.time - min_time) as f64 / (max_time - min_time) as f64;
|
||||
(time, *cur_temp)
|
||||
})
|
||||
.collect::<VecDeque<_>>();
|
||||
|
||||
// Add a temperature at the start and end to ensure that all rectangles are drawn from both ends
|
||||
let last_temp = temps.back().map_or(0.0, |&(_, temp)| temp);
|
||||
temps.push_front((0.0, 0.0));
|
||||
temps.push_back((1.0, last_temp));
|
||||
|
||||
(page_ptr, temps)
|
||||
})
|
||||
.collect::<BTreeMap<_, _>>();
|
||||
|
||||
let max_temp = points
|
||||
.values()
|
||||
.flat_map(|temps| temps.iter().map(|&(_, temp)| temp))
|
||||
.max_by(f64::total_cmp)
|
||||
.unwrap_or(0.0);
|
||||
|
||||
// Finally create and save the plot
|
||||
let mut fg = gnuplot::Figure::new();
|
||||
let fg_axes2d: &mut gnuplot::Axes2D = fg.axes2d();
|
||||
for (&page_ptr, temps) in &points {
|
||||
let page_ptr_idx = *page_ptr_idxs.get(&page_ptr).expect("Page ptr had no index");
|
||||
|
||||
for ((prev_time, prev_temp), (cur_time, cur_temp)) in temps.iter().copied().tuple_windows() {
|
||||
let progress = (prev_temp + cur_temp) / (2.0 * max_temp);
|
||||
let progress = progress.powf(cmd_args.temp_exponent);
|
||||
|
||||
let color = LinSrgb::new(1.0, 0.0, 0.0).mix(LinSrgb::new(0.0, 1.0, 0.0), progress);
|
||||
let color = format!("#{:x}", color.into_format::<u8>());
|
||||
|
||||
fg_axes2d.fill_between([prev_time, cur_time], [page_ptr_idx; 2], [page_ptr_idx + 1; 2], &[
|
||||
PlotOption::Color(&color),
|
||||
PlotOption::FillAlpha(1.0),
|
||||
PlotOption::FillRegion(FillRegionType::Below),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
fg_axes2d
|
||||
.set_x_label("Time (normalized)", &[])
|
||||
.set_y_label("Page (indexed)", &[])
|
||||
.set_x_range(AutoOption::Fix(0.0), AutoOption::Fix(1.0))
|
||||
.set_y_range(AutoOption::Fix(0.0), AutoOption::Fix(page_ptr_idxs.len() as f64));
|
||||
|
||||
// Then output the plot
|
||||
self::handle_output(&cmd_args.output, &mut fg).context("Unable to handle output")?;
|
||||
},
|
||||
args::SubCmd::PageMigrationsHist(cmd_args) => self::draw_page_migrations_hist(cmd_args)?,
|
||||
args::SubCmd::PageMigrationsHistMultiple(cmd_args) => self::draw_page_migrations_hist_multiple(cmd_args)?,
|
||||
args::SubCmd::PageTemperature(cmd_args) => self::draw_page_temperature(cmd_args)?,
|
||||
args::SubCmd::PageTemperatureDensity(cmd_args) => self::draw_page_temperature_density(cmd_args)?,
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -414,6 +166,263 @@ fn draw_page_migrations(cmd_args: &args::PageMigrations) -> Result<(), anyhow::E
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn draw_page_migrations_hist(cmd_args: args::PageMigrationsHist) -> Result<(), anyhow::Error> {
|
||||
// Parse and build the data
|
||||
let data = self::read_data(&cmd_args.input_file)?;
|
||||
let data = self::page_migrations_hist_data(&data);
|
||||
|
||||
// Finally create and save the plot
|
||||
let mut fg = gnuplot::Figure::new();
|
||||
fg.axes2d()
|
||||
.lines(0..data.len(), &data, &[
|
||||
PlotOption::Caption("Migration count"),
|
||||
PlotOption::Color("black"),
|
||||
])
|
||||
.set_x_range(AutoOption::Fix(0.0), AutoOption::Fix(data.len() as f64))
|
||||
.set_y_range(AutoOption::Fix(0.0), AutoOption::Auto)
|
||||
.set_x_label("Migrations (flattened)", &[])
|
||||
.set_y_label("Migrations", &[]);
|
||||
|
||||
// Then output the plot
|
||||
self::handle_output(&cmd_args.output, &mut fg).context("Unable to handle output")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn draw_page_migrations_hist_multiple(cmd_args: args::PageMigrationsHistMultiple) -> Result<(), anyhow::Error> {
|
||||
// Create the figure
|
||||
// Note: We do this before parsing the data since we parse
|
||||
// the files in parallel (with a limit, to not load too
|
||||
// many at once)
|
||||
let mut fg = gnuplot::Figure::new();
|
||||
let fg_axes2d = fg.axes2d();
|
||||
|
||||
// Then process all input files
|
||||
// TODO: Process them in parallel with `rayon`? Issue is that we need to add each
|
||||
// plot in order so that the legend stays consistent.
|
||||
for (data_idx, input_file) in cmd_args.input_files.iter().enumerate() {
|
||||
// Parse and build the data
|
||||
let data = self::read_data(input_file).with_context(|| format!("Unable to read {input_file:?}"))?;
|
||||
let data = self::page_migrations_hist_data(&data);
|
||||
|
||||
// Then render the lines
|
||||
let progress = data_idx as f64 / (cmd_args.input_files.len() as f64 - 1.0);
|
||||
|
||||
let color = LinSrgb::new(1.0, 0.0, 0.0).mix(LinSrgb::new(0.0, 1.0, 0.0), progress);
|
||||
let color = format!("#{:x}", color.into_format::<u8>());
|
||||
|
||||
fg_axes2d.lines(0..data.len(), &data, &[
|
||||
PlotOption::Caption(&format!("Migration count ({})", input_file.display())),
|
||||
PlotOption::Color(&color),
|
||||
]);
|
||||
}
|
||||
|
||||
// Finally finish building the graph
|
||||
fg_axes2d
|
||||
.set_x_range(AutoOption::Fix(0.0), AutoOption::Auto)
|
||||
.set_y_range(AutoOption::Fix(0.0), AutoOption::Auto)
|
||||
.set_x_label("Migrations (flattened)", &[])
|
||||
.set_y_label("Migrations", &[]);
|
||||
|
||||
// Then output the plot
|
||||
self::handle_output(&cmd_args.output, &mut fg).context("Unable to handle output")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn draw_page_temperature(cmd_args: args::PageTemperature) -> Result<(), anyhow::Error> {
|
||||
// Parse the input file
|
||||
let data = self::read_data(&cmd_args.input_file)?;
|
||||
|
||||
let (min_time, max_time) = data
|
||||
.hemem
|
||||
.page_accesses
|
||||
.accesses
|
||||
.iter()
|
||||
.map(|page_access| page_access.time)
|
||||
.minmax()
|
||||
.into_option()
|
||||
.unwrap_or((0, 1));
|
||||
|
||||
// Get all the points
|
||||
struct Point {
|
||||
x: f64,
|
||||
y_avg: f64,
|
||||
y_err: f64,
|
||||
global_cooled: bool,
|
||||
}
|
||||
let mut cur_temps = HashMap::new();
|
||||
let points = data
|
||||
.hemem
|
||||
.page_accesses
|
||||
.accesses
|
||||
.iter()
|
||||
.map(|page_access| {
|
||||
// Update the temperatures
|
||||
// TODO: Optimize global cooling?
|
||||
*cur_temps.entry(page_access.page_ptr).or_insert(0) = page_access.prev_temp;
|
||||
if page_access.caused_cooling {
|
||||
for temp in cur_temps.values_mut() {
|
||||
*temp /= 2;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Optimize this with a moving average?
|
||||
let average_temp = &cur_temps
|
||||
.values()
|
||||
.map(|&temp| temp as f64)
|
||||
.collect::<average::Variance>();
|
||||
Point {
|
||||
x: (page_access.time - min_time) as f64 / (max_time - min_time) as f64,
|
||||
y_avg: average_temp.mean(),
|
||||
y_err: average_temp.error(),
|
||||
global_cooled: page_access.caused_cooling,
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let max_y = points.iter().map(|p| p.y_avg).max_by(f64::total_cmp).unwrap_or(0.0);
|
||||
|
||||
// Finally create and save the plot
|
||||
let mut fg = gnuplot::Figure::new();
|
||||
fg.axes2d()
|
||||
.boxes_set_width(
|
||||
points.iter().map(|p| p.x),
|
||||
points.iter().map(|p| if p.global_cooled { max_y } else { 0.0 }),
|
||||
(0..points.len()).map(|_| 0.1 / (points.len() as f64)),
|
||||
&[
|
||||
PlotOption::Caption("Global cooling"),
|
||||
PlotOption::Color("red"),
|
||||
PlotOption::LineWidth(0.1),
|
||||
],
|
||||
)
|
||||
.lines(points.iter().map(|p| p.x), points.iter().map(|p| p.y_avg), &[
|
||||
PlotOption::Caption("Page migrations (Avg)"),
|
||||
PlotOption::Color("black"),
|
||||
PlotOption::LineStyle(DashType::Solid),
|
||||
PlotOption::LineWidth(1.0),
|
||||
])
|
||||
.fill_between(
|
||||
points.iter().map(|p| p.x),
|
||||
points.iter().map(|p| p.y_avg - p.y_err),
|
||||
points.iter().map(|p| p.y_avg + p.y_err),
|
||||
&[
|
||||
PlotOption::Caption("Page migrations (Error)"),
|
||||
PlotOption::Color("green"),
|
||||
PlotOption::FillAlpha(0.3),
|
||||
PlotOption::FillRegion(FillRegionType::Below),
|
||||
],
|
||||
)
|
||||
.set_x_label("Time (normalized)", &[])
|
||||
.set_y_label("Temperature", &[])
|
||||
.set_x_range(AutoOption::Fix(0.0), AutoOption::Fix(1.0))
|
||||
.set_y_range(AutoOption::Fix(0.0), AutoOption::Fix(max_y));
|
||||
|
||||
// Then output the plot
|
||||
self::handle_output(&cmd_args.output, &mut fg).context("Unable to handle output")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn draw_page_temperature_density(cmd_args: args::PageTemperatureDensity) -> Result<(), anyhow::Error> {
|
||||
// Parse the input file
|
||||
let data = self::read_data(&cmd_args.input_file)?;
|
||||
|
||||
let (min_time, max_time) = data
|
||||
.hemem
|
||||
.page_accesses
|
||||
.accesses
|
||||
.iter()
|
||||
.map(|page_access| page_access.time)
|
||||
.minmax()
|
||||
.into_option()
|
||||
.unwrap_or((0, 1));
|
||||
|
||||
// Then index the page pointers.
|
||||
// Note: We do this because the page pointers are very far away, value-wise, which
|
||||
// causes them to display far away in the graph. Since the actual values of the
|
||||
// pages don't matter to us, we just index them by order of appearance.
|
||||
let page_ptr_idxs = data
|
||||
.hemem
|
||||
.page_migrations
|
||||
.migrations
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(idx, (page_ptr, _))| (page_ptr, idx))
|
||||
.collect::<std::collections::BTreeMap<_, _>>();
|
||||
|
||||
|
||||
// Get all the points
|
||||
let mut cur_temps = HashMap::<u64, f64>::new();
|
||||
let points = data
|
||||
.hemem
|
||||
.page_accesses
|
||||
.accesses
|
||||
.iter()
|
||||
.group_by(|page_access| page_access.page_ptr)
|
||||
.into_iter()
|
||||
.map(|(page_ptr, page_accesses)| {
|
||||
// Note: The page accesses will already be sorted by time
|
||||
let mut temps = page_accesses
|
||||
.map(|page_access| {
|
||||
let cur_temp = cur_temps.entry(page_ptr).or_insert(0.0);
|
||||
match page_access.kind {
|
||||
ftmemsim::data::PageAccessKind::Read => *cur_temp += cmd_args.temp_read_weight,
|
||||
ftmemsim::data::PageAccessKind::Write => *cur_temp += cmd_args.temp_write_weight,
|
||||
};
|
||||
|
||||
let time = (page_access.time - min_time) as f64 / (max_time - min_time) as f64;
|
||||
(time, *cur_temp)
|
||||
})
|
||||
.collect::<VecDeque<_>>();
|
||||
|
||||
// Add a temperature at the start and end to ensure that all rectangles are drawn from both ends
|
||||
let last_temp = temps.back().map_or(0.0, |&(_, temp)| temp);
|
||||
temps.push_front((0.0, 0.0));
|
||||
temps.push_back((1.0, last_temp));
|
||||
|
||||
(page_ptr, temps)
|
||||
})
|
||||
.collect::<BTreeMap<_, _>>();
|
||||
|
||||
let max_temp = points
|
||||
.values()
|
||||
.flat_map(|temps| temps.iter().map(|&(_, temp)| temp))
|
||||
.max_by(f64::total_cmp)
|
||||
.unwrap_or(0.0);
|
||||
|
||||
// Finally create and save the plot
|
||||
let mut fg = gnuplot::Figure::new();
|
||||
let fg_axes2d: &mut gnuplot::Axes2D = fg.axes2d();
|
||||
for (&page_ptr, temps) in &points {
|
||||
let page_ptr_idx = *page_ptr_idxs.get(&page_ptr).expect("Page ptr had no index");
|
||||
|
||||
for ((prev_time, prev_temp), (cur_time, cur_temp)) in temps.iter().copied().tuple_windows() {
|
||||
let progress = (prev_temp + cur_temp) / (2.0 * max_temp);
|
||||
let progress = progress.powf(cmd_args.temp_exponent);
|
||||
|
||||
let color = LinSrgb::new(1.0, 0.0, 0.0).mix(LinSrgb::new(0.0, 1.0, 0.0), progress);
|
||||
let color = format!("#{:x}", color.into_format::<u8>());
|
||||
|
||||
fg_axes2d.fill_between([prev_time, cur_time], [page_ptr_idx; 2], [page_ptr_idx + 1; 2], &[
|
||||
PlotOption::Color(&color),
|
||||
PlotOption::FillAlpha(1.0),
|
||||
PlotOption::FillRegion(FillRegionType::Below),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
fg_axes2d
|
||||
.set_x_label("Time (normalized)", &[])
|
||||
.set_y_label("Page (indexed)", &[])
|
||||
.set_x_range(AutoOption::Fix(0.0), AutoOption::Fix(1.0))
|
||||
.set_y_range(AutoOption::Fix(0.0), AutoOption::Fix(page_ptr_idxs.len() as f64));
|
||||
|
||||
// Then output the plot
|
||||
self::handle_output(&cmd_args.output, &mut fg).context("Unable to handle output")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Computes the data to use fr the `page-migrations-hist` graph
|
||||
fn page_migrations_hist_data(data: &ftmemsim::data::Data) -> Vec<usize> {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user