one_collect 0.1.34811

Cross-platform library for capturing machine-level traces.
Documentation
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

#[cfg(target_os = "linux")]
use one_collect::perf_event::{
    self,
    PerfSession,
    RingBufBuilder,
    RingBufSessionBuilder
};

#[cfg(target_os = "linux")]
use one_collect::Writable;

#[cfg(target_os = "linux")]
struct Utilization {
    per_cpu: Vec<u64>,
    temp: String,
}

#[cfg(target_os = "linux")]
impl Utilization {
    fn create() -> Self {
        #[cfg(target_os = "linux")]
        let cpu_count = perf_event::cpu_count() as usize;
        #[cfg(target_os = "windows")]
        let cpu_count = 1;

        let mut per_cpu = Vec::new();
        per_cpu.resize(cpu_count, 0);

        Self {
            per_cpu,
            temp: String::new(),
        }
    }

    #[cfg(target_os = "linux")]
    fn new(session: &mut PerfSession) -> Writable<Self> {
        let util = Writable::new(Self::create());

        /* CPU is ancillary data for perf_event_open */
        let ancillary = session.ancillary_data();

        /* Clone the writable for callback */
        let session_util = util.clone();

        /* Setup to inc cpu by 1 on each cpu profile */
        session
            .cpu_profile_event()
            .add_callback(move |_| {
                let mut cpu: u32 = 0;

                ancillary.read(|values| {
                    cpu = values.cpu();
                });

                session_util.write(|usage| {
                    usage.per_cpu[cpu as usize] += 1;
                });

                Ok(())
            });

        /* Give back the shared writable */
        util
    }

    fn report(&mut self) {
        let mut all = 0u64;

        println!(concat!(
            "\x1b[H\x1b[J\x1b[4m",
            "CPU│",
            "                    ",
            "Utilization",
            "                    ",
            " │  %\x1b[0m"));

        for (cpu,total) in self.per_cpu.iter().enumerate() {
            Self::print_graph(&mut self.temp, Some(cpu), *total);
            all += total;
        }

        let total = all / self.per_cpu.len() as u64;
        Self::print_graph(&mut self.temp, None, total);

        for total in &mut self.per_cpu {
            *total = 0;
        }
    }

    fn print_graph(
        temp: &mut String,
        cpu: Option<usize>,
        mut total: u64) {
        if total > 100 {
            total = 100;
        }

        let notches = total / 2;
        temp.clear();

        match total {
            /* Gray */
            0..=25 => { temp.push_str("\x1b[1;30;1m"); },

            /* Yellow */
            26..=75 => { temp.push_str("\x1b[1;33m"); },

            /* Red */
            _ => { temp.push_str("\x1b[1;31m"); }
        }

        for _ in 0..notches {
            temp.push('');
        }

        temp.push_str("\x1b[0m");

        for _ in notches..50 {
            temp.push(' ');
        }

        match cpu {
            Some(cpu) => {
                println!("{:3}{}{:2}%", cpu, temp, total);
            },
            None => {
                println!("SUM│ {}{:2}%", temp, total);
            }
        }
    }
}

#[cfg(target_os = "linux")]
fn main() {
    let one_sec = std::time::Duration::from_secs(1);
    let need_permission = "Need permission (run via sudo?)";

    /* Sample 100 times a sec (10 ms interrupts) */
    let freq = 100;
    let cpu = RingBufBuilder::for_profiling(freq);

    /* Build up cpu session */
    let mut session = RingBufSessionBuilder::new()
        .with_page_count(4)
        .with_profiling_events(cpu)
        .build()
        .expect(need_permission);

    let util = Utilization::new(&mut session);

    loop {
        /* Print and reset utilization */
        util.write(|util| { util.report(); });

        /* Profile for 1 second */
        session.enable().expect(need_permission);
        std::thread::sleep(one_sec);
        session.disable().expect(need_permission);

        /* Parse captured data */
        session.parse_all().expect(need_permission);
    }
}

#[cfg(target_os = "windows")]
fn main() {
    println!("Coming soon");
}