Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
refactor: first working version of qemu exporter (poorly) using metri…
…c_generator
  • Loading branch information
bpetit committed Apr 17, 2023
commit 1aa30994039ee73c18d51e6a77f69f51293e5312
6 changes: 3 additions & 3 deletions src/exporters/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ use {

/// General metric definition.
#[derive(Debug)]
struct Metric {
pub struct Metric {
/// `name` is the metric name, it will be used as service field for Riemann.
name: String, // Will be used as service for Riemann
/// `metric_type` mostly used by Prometheus, define is it is a gauge, counter...
Expand Down Expand Up @@ -111,7 +111,7 @@ pub trait Exporter {
/// MetricGenerator is an exporter helper structure to collect Scaphandre metrics.
/// The goal is to provide a standard Vec\<Metric\> that can be used by exporters
/// to avoid code duplication.
struct MetricGenerator {
pub struct MetricGenerator {
/// `data` will be used to store the metrics retrieved.
data: Vec<Metric>,
/// `topology` is the system physical layout retrieve via the sensors crate with
Expand Down Expand Up @@ -160,7 +160,7 @@ struct MetricGenerator {
impl MetricGenerator {
/// Returns a MetricGenerator instance that will host metrics.

fn new(
pub fn new(
topology: Topology,
hostname: String,
_qemu: bool,
Expand Down
79 changes: 33 additions & 46 deletions src/exporters/qemu.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::exporters::Exporter;
use crate::exporters::utils::get_hostname;
use crate::exporters::{Exporter, MetricGenerator};
use crate::sensors::{utils::ProcessRecord, Sensor, Topology};
use std::{fs, io, thread, time};

Expand All @@ -9,7 +10,7 @@ use std::{fs, io, thread, time};
/// to collect and deal with their power consumption metrics, the same way
/// they would do it if they managed bare metal machines.
pub struct QemuExporter {
topology: Topology,
sensor: Box<dyn Sensor>,
}

impl Exporter for QemuExporter {
Expand All @@ -19,17 +20,21 @@ impl Exporter for QemuExporter {
let path = "/var/lib/libvirt/scaphandre";
let cleaner_step = 120;
let mut timer = time::Duration::from_secs(cleaner_step);
loop {
self.iteration(String::from(path));
let step = time::Duration::from_secs(5);
thread::sleep(step);
if timer - step > time::Duration::from_millis(0) {
timer -= step;
} else {
self.topology
.proc_tracker
.clean_terminated_process_records_vectors();
timer = time::Duration::from_secs(cleaner_step);
if let Ok(topology) = self.sensor.generate_topology() {
let mut metric_generator = MetricGenerator::new(topology, get_hostname(), true, false);
loop {
metric_generator.topology.refresh();
self.iteration(String::from(path), &mut metric_generator);
let step = time::Duration::from_secs(5);
thread::sleep(step);
if timer - step > time::Duration::from_millis(0) {
timer -= step;
} else {
metric_generator.topology
.proc_tracker
.clean_terminated_process_records_vectors();
timer = time::Duration::from_secs(cleaner_step);
}
}
}
}
Expand All @@ -42,53 +47,35 @@ impl Exporter for QemuExporter {
impl QemuExporter {
/// Instantiates and returns a new QemuExporter
pub fn new(mut sensor: Box<dyn Sensor>) -> QemuExporter {
let some_topology = *sensor.get_topology();
QemuExporter {
topology: some_topology.unwrap(),
sensor,
}
}

/// Performs processing of metrics, using self.topology
pub fn iteration(&mut self, path: String) {
pub fn iteration(&mut self, path: String, metric_generator: &mut MetricGenerator) {
trace!("path: {}", path);
self.topology.refresh();
let topo_uj_diff = self.topology.get_records_diff();
let topo_stat_diff = self.topology.get_stats_diff();
if let Some(topo_rec_uj) = topo_uj_diff {
debug!("Got topo uj diff: {:?}", topo_rec_uj);
let proc_tracker = self.topology.get_proc_tracker();
let processes = proc_tracker.get_alive_processes();

if let Some(topo_energy) = metric_generator.topology.get_records_diff_power_microwatts() {
let processes = metric_generator.topology.proc_tracker.get_alive_processes();
let qemu_processes = QemuExporter::filter_qemu_vm_processes(&processes);
debug!(
"Number of filtered qemu processes: {}",
qemu_processes.len()
);
for qp in qemu_processes {
info!("Working on {:?}", qp);
if qp.len() > 2 {
let last = qp.first().unwrap();
let previous = qp.get(1).unwrap();
let vm_name = QemuExporter::get_vm_name_from_cmdline(
&last.process.cmdline(proc_tracker).unwrap(),
&last.process.cmdline(&metric_generator.topology.proc_tracker).unwrap(),
);
let time_pdiff = last.process.total_time_jiffies(proc_tracker)
- previous.process.total_time_jiffies(proc_tracker);
if let Some(time_tdiff) = &topo_stat_diff {
let first_domain_path = format!("{path}/{vm_name}/intel-rapl:0:0");
if fs::read_dir(&first_domain_path).is_err() {
match fs::create_dir_all(&first_domain_path) {
Ok(_) => info!("Created {} folder.", &path),
Err(error) => panic!("Couldn't create {}. Got: {}", &path, error),
}
let first_domain_path = format!("{path}/{vm_name}/intel-rapl:0:0");
if fs::read_dir(&first_domain_path).is_err() {
match fs::create_dir_all(&first_domain_path) {
Ok(_) => info!("Created {} folder.", &path),
Err(error) => panic!("Couldn't create {}. Got: {}", &path, error),
}
let tdiff = time_tdiff.total_time_jiffies();
trace!("Time_pdiff={} time_tdiff={}", time_pdiff.to_string(), tdiff);
let ratio = time_pdiff / tdiff;
trace!("Ratio is {}", ratio.to_string());
let uj_to_add = ratio * topo_rec_uj.value.parse::<u64>().unwrap();
trace!("Adding {} uJ", uj_to_add);
}
if let Some(ratio) = metric_generator.topology.get_process_cpu_usage_percentage(last.process.pid) {
let uj_to_add = ratio.value.parse::<f64>().unwrap() * topo_energy.value.parse::<f64>().unwrap() / 100.0;
let complete_path = format!("{path}/{vm_name}/intel-rapl:0");
if let Ok(result) = QemuExporter::add_or_create(&complete_path, uj_to_add) {
if let Ok(result) = QemuExporter::add_or_create(&complete_path, uj_to_add as u64) {
trace!("{:?}", result);
debug!("Updated {}", complete_path);
}
Expand Down
52 changes: 29 additions & 23 deletions tests/integration.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,30 @@
#[cfg(target_os = "linux")]
use scaphandre::exporters::qemu::QemuExporter;
#[cfg(target_os = "linux")]
use scaphandre::sensors::powercap_rapl::PowercapRAPLSensor;
use std::env::current_dir;
use std::fs::{create_dir, read_dir};
//#[cfg(target_os = "linux")]
//use scaphandre::exporters::qemu::QemuExporter;
//#[cfg(target_os = "linux")]
//use scaphandre::sensors::powercap_rapl::PowercapRAPLSensor;
//use std::env::current_dir;
//use std::fs::{create_dir, read_dir};

#[cfg(target_os = "linux")]
#[test]
fn exporter_qemu() {
let sensor = PowercapRAPLSensor::new(1, 1, false);
let mut exporter = QemuExporter::new(Box::new(sensor));
// Create integration_tests directory if it does not exist
let curdir = current_dir().unwrap();
let path = curdir.join("integration_tests");
if !path.is_dir() {
create_dir(&path).expect("Fail to create integration_tests directory");
}
// Convert to std::string::String
let path = path.into_os_string().to_str().unwrap().to_string();
exporter.iteration(path.clone());
let content = read_dir(path);
assert_eq!(content.is_ok(), true);
}
//#[cfg(target_os = "linux")]
//#[test]
//fn exporter_qemu() {
// use scaphandre::{exporters::{MetricGenerator, utils::get_hostname}, sensors::Sensor};
//
// let sensor = PowercapRAPLSensor::new(1, 1, false);
// let mut exporter = QemuExporter::new(Box::new(sensor));
// // Create integration_tests directory if it does not exist
// let curdir = current_dir().unwrap();
// let path = curdir.join("integration_tests");
// if !path.is_dir() {
// create_dir(&path).expect("Fail to create integration_tests directory");
// }
// // Convert to std::string::String
// let path = path.into_os_string().to_str().unwrap().to_string();
// if let Ok(mut topology) = &sensor.generate_topology() {
// let mut metric_generator = MetricGenerator::new(topology, get_hostname(), true, false);
// exporter.iteration(path.clone(), &mut metric_generator);
// let content = read_dir(path);
// assert_eq!(content.is_ok(), true);
// }
//}
//