processortrace 0.0.3

Rust library to set-up Intel processor trace for getting raw trace data.
use env_logger;
use libc;
use std::prelude::v1::*;
use std::process::Command;

use super::{PTInfo, ProcessorTraceController, TraceDump, TraceDumpControl};

use driverkit::{DriverControl, MsrWriter};

#[cfg(target_os = "linux")]
fn pin_thread(core_id: usize) {
    use nix::sched::{sched_setaffinity, CpuSet};
    use nix::unistd::Pid;

    let mut affinity_set = CpuSet::new();
    affinity_set.set(core_id).expect("Can't set PU in core set");

    sched_setaffinity(Pid::from_raw(0i32), &affinity_set).expect("Can't pin app thread to core");
}

#[cfg(not(target_os = "linux"))]
fn pin_thread(_core_id: usize) {
    error!("Pinning threads not supported!");
}

#[test]
fn ptinfo() {
    let _ = env_logger::init();
    let ptinfo = PTInfo::new().unwrap();
    debug!("{:?}", ptinfo);
}

#[inline(never)]
fn foo(i: usize) {
    if i > 200 {
        println!("i = {}", i);
    }
}

#[test]
fn trace_fn() {
    let cpu: usize = 3;
    pin_thread(cpu);
    let mut msr_iface: MsrWriter = MsrWriter::new(cpu);
    let mut controller = ProcessorTraceController::new(&mut msr_iface);
    controller.init();
    controller.attach();

    let dump: TraceDump = controller.trace(|| {
        let mut a = 0;
        for i in 0..200 {
            foo(i);
        }
        println!("a = {}", a);
    });

    dump.save("trace_fn");

    controller.destroy();
}

#[test]
fn trace_raw() {
    let cpu: usize = 2;
    pin_thread(cpu);
    let mut linux_msr: MsrWriter = MsrWriter::new(cpu);

    let mut controller = ProcessorTraceController::new(&mut linux_msr);
    controller.init();
    controller.attach();

    controller.start();
    for i in 0..200 {
        foo(i);
    }
    controller.stop();
    assert!(controller.current_offset() > 0x1000);

    use std::fs::File;
    use std::io::prelude::*;

    let mut file = File::create("trace.dump").unwrap();
    file.write_all(controller.buffer.as_slice() as &[u8])
        .unwrap();

    let pid = unsafe { libc::getpid() };
    let _c = Command::new("cp")
        .arg(format!("/proc/{}/maps", pid))
        .arg("trace.map")
        .output()
        .expect("failed to execute process");

    controller.destroy();
}