summaryrefslogtreecommitdiff
path: root/src/energy/rapl.rs
blob: a570d5caf1f9a47cc427dd94a3ac178e8bfd16da (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#![allow(unused)]
use std::fs;
use std::io;
use std::path::Path;

/// Check if RAPL sysfs interface is available
pub fn is_rapl_available() -> bool {
    Path::new("/sys/class/powercap/intel-rapl/intel-rapl:0").exists()
}

/// Read current package energy counter value in joules
pub fn read_package_energy() -> io::Result<f64> {
    let energy_path = "/sys/class/powercap/intel-rapl/intel-rapl:0/energy_uj";
    let energy_str = fs::read_to_string(energy_path)?;
    let energy_uj = energy_str
        .trim()
        .parse::<u64>()
        .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;

    // Convert from microjoules to joules
    Ok(energy_uj as f64 / 1_000_000.0)
}

/// Read energy counter for a specific domain (core, uncore, dram)
pub fn read_domain_energy(domain_idx: usize) -> io::Result<f64> {
    let domain_path = format!(
        "/sys/class/powercap/intel-rapl/intel-rapl:0:{}/energy_uj",
        domain_idx
    );

    if !Path::new(&domain_path).exists() {
        return Err(io::Error::new(
            io::ErrorKind::NotFound,
            format!("Domain {} not available", domain_idx),
        ));
    }

    let energy_str = fs::read_to_string(domain_path)?;
    let energy_uj = energy_str
        .trim()
        .parse::<u64>()
        .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;

    // Convert from microjoules to joules
    Ok(energy_uj as f64 / 1_000_000.0)
}

/// Get domain name
pub fn get_domain_name(domain_idx: usize) -> io::Result<String> {
    let name_path = format!(
        "/sys/class/powercap/intel-rapl/intel-rapl:0:{}/name",
        domain_idx
    );

    if !Path::new(&name_path).exists() {
        return Err(io::Error::new(
            io::ErrorKind::NotFound,
            format!("Domain {} not available", domain_idx),
        ));
    }

    let name = fs::read_to_string(name_path)?;
    Ok(name.trim().to_string())
}

/// List all available RAPL domains with their indices
pub fn list_domains() -> io::Result<Vec<(usize, String)>> {
    let base_path = "/sys/class/powercap/intel-rapl/intel-rapl:0";
    let mut domains = Vec::new();

    // Add package domain (always index 0)
    let pkg_name_path = format!("{}/name", base_path);
    let pkg_name = fs::read_to_string(pkg_name_path)?.trim().to_string();
    domains.push((0, pkg_name));

    // Check for subdomains
    for i in 0..10 {
        let domain_path = format!("{}/intel-rapl:0:{}", base_path, i);
        if Path::new(&domain_path).exists() {
            let name_path = format!("{}/name", domain_path);
            if let Ok(name) = fs::read_to_string(name_path) {
                domains.push((i, name.trim().to_string()));
            }
        } else {
            break;
        }
    }

    Ok(domains)
}