mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
Both arch/src/aarch64/fdt.rs and vmm/src/cpu.rs declared the same ~14 cache info locals (size/line_size/sets for L1D/L1I/L2/L3, plus shared flags for L2/L3), checked for /sys/devices/system/cpu/cpu0/cache, and populated those locals via get_cache_size / get_cache_coherency_line_size / get_cache_number_of_sets / get_cache_shared. Two near-identical ~30-line blocks. Add a CacheTopologyInfo struct in arch/src/aarch64/cache.rs whose field names mirror the existing locals, plus a read_cache_topology() helper that returns None when the sysfs hierarchy is missing and only queries get_cache_shared for L2/L3 when their size is non-zero (preserving current behavior). Both call sites now obtain the info via read_cache_topology() and destructure it back into locals of the same name, so all downstream references are unchanged. Assisted-by: Copilot-CLI:Claude-Opus-4.7 Signed-off-by: Anirudh Rayabharam <anrayabh@microsoft.com>
189 lines
6.2 KiB
Rust
189 lines
6.2 KiB
Rust
// Copyright 2020 Arm Limited (or its affiliates). All rights reserved.
|
|
// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
//
|
|
// Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the THIRD-PARTY file.
|
|
|
|
use std::fs;
|
|
use std::path::Path;
|
|
|
|
use log::warn;
|
|
|
|
#[derive(Copy, Clone)]
|
|
pub enum CacheLevel {
|
|
/// L1 data cache
|
|
L1D = 0,
|
|
/// L1 instruction cache
|
|
L1I = 1,
|
|
/// L2 cache
|
|
L2 = 2,
|
|
/// L3 cache
|
|
L3 = 3,
|
|
}
|
|
|
|
/// NOTE: cache size file directory example,
|
|
/// "/sys/devices/system/cpu/cpu0/cache/index0/size".
|
|
pub fn get_cache_size(cache_level: CacheLevel) -> u32 {
|
|
let mut file_directory: String = "/sys/devices/system/cpu/cpu0/cache".to_string();
|
|
match cache_level {
|
|
CacheLevel::L1D => file_directory += "/index0/size",
|
|
CacheLevel::L1I => file_directory += "/index1/size",
|
|
CacheLevel::L2 => file_directory += "/index2/size",
|
|
CacheLevel::L3 => file_directory += "/index3/size",
|
|
}
|
|
|
|
let file_path = Path::new(&file_directory);
|
|
if file_path.exists() {
|
|
let src = fs::read_to_string(file_directory).expect("File not exists or file corrupted.");
|
|
// The content of the file is as simple as a size, like: "32K"
|
|
let src = src.trim();
|
|
let src_digits: u32 = src[0..src.len() - 1].parse().unwrap();
|
|
let src_unit = &src[src.len() - 1..];
|
|
|
|
src_digits
|
|
* match src_unit {
|
|
"K" => 1u32 << 10,
|
|
"M" => 1u32 << 20,
|
|
"G" => 1u32 << 30,
|
|
_ => 1,
|
|
}
|
|
} else {
|
|
0
|
|
}
|
|
}
|
|
|
|
/// NOTE: coherency_line_size file directory example,
|
|
/// "/sys/devices/system/cpu/cpu0/cache/index0/coherency_line_size".
|
|
pub fn get_cache_coherency_line_size(cache_level: CacheLevel) -> u32 {
|
|
let mut file_directory: String = "/sys/devices/system/cpu/cpu0/cache".to_string();
|
|
match cache_level {
|
|
CacheLevel::L1D => file_directory += "/index0/coherency_line_size",
|
|
CacheLevel::L1I => file_directory += "/index1/coherency_line_size",
|
|
CacheLevel::L2 => file_directory += "/index2/coherency_line_size",
|
|
CacheLevel::L3 => file_directory += "/index3/coherency_line_size",
|
|
}
|
|
|
|
let file_path = Path::new(&file_directory);
|
|
if file_path.exists() {
|
|
let src = fs::read_to_string(file_directory).expect("File not exists or file corrupted.");
|
|
src.trim().parse::<u32>().unwrap()
|
|
} else {
|
|
0
|
|
}
|
|
}
|
|
|
|
/// NOTE: number_of_sets file directory example,
|
|
/// "/sys/devices/system/cpu/cpu0/cache/index0/number_of_sets".
|
|
pub fn get_cache_number_of_sets(cache_level: CacheLevel) -> u32 {
|
|
let mut file_directory: String = "/sys/devices/system/cpu/cpu0/cache".to_string();
|
|
match cache_level {
|
|
CacheLevel::L1D => file_directory += "/index0/number_of_sets",
|
|
CacheLevel::L1I => file_directory += "/index1/number_of_sets",
|
|
CacheLevel::L2 => file_directory += "/index2/number_of_sets",
|
|
CacheLevel::L3 => file_directory += "/index3/number_of_sets",
|
|
}
|
|
|
|
let file_path = Path::new(&file_directory);
|
|
if file_path.exists() {
|
|
let src = fs::read_to_string(file_directory).expect("File not exists or file corrupted.");
|
|
src.trim().parse::<u32>().unwrap()
|
|
} else {
|
|
0
|
|
}
|
|
}
|
|
|
|
/// NOTE: shared_cpu_list file directory example,
|
|
/// "/sys/devices/system/cpu/cpu0/cache/index0/shared_cpu_list".
|
|
pub fn get_cache_shared(cache_level: CacheLevel) -> bool {
|
|
let mut file_directory: String = "/sys/devices/system/cpu/cpu0/cache".to_string();
|
|
let mut result = true;
|
|
|
|
match cache_level {
|
|
CacheLevel::L1D | CacheLevel::L1I => result = false,
|
|
CacheLevel::L2 => file_directory += "/index2/shared_cpu_list",
|
|
CacheLevel::L3 => file_directory += "/index3/shared_cpu_list",
|
|
}
|
|
|
|
if !result {
|
|
return false;
|
|
}
|
|
|
|
let file_path = Path::new(&file_directory);
|
|
if file_path.exists() {
|
|
let src = fs::read_to_string(file_directory).expect("File not exists or file corrupted.");
|
|
let src = src.trim();
|
|
if src.is_empty() {
|
|
result = false;
|
|
} else {
|
|
result = src.contains('-') || src.contains(',');
|
|
}
|
|
} else {
|
|
result = false;
|
|
}
|
|
|
|
result
|
|
}
|
|
|
|
#[derive(Default, Copy, Clone, Debug)]
|
|
pub struct CacheTopologyInfo {
|
|
pub l1_d_cache_size: u32,
|
|
pub l1_d_cache_line_size: u32,
|
|
pub l1_d_cache_sets: u32,
|
|
|
|
pub l1_i_cache_size: u32,
|
|
pub l1_i_cache_line_size: u32,
|
|
pub l1_i_cache_sets: u32,
|
|
|
|
pub l2_cache_size: u32,
|
|
pub l2_cache_line_size: u32,
|
|
pub l2_cache_sets: u32,
|
|
|
|
pub l3_cache_size: u32,
|
|
pub l3_cache_line_size: u32,
|
|
pub l3_cache_sets: u32,
|
|
|
|
pub l2_cache_shared: bool,
|
|
pub l3_cache_shared: bool,
|
|
}
|
|
|
|
/// Reads cache topology information from sysfs for cpu0.
|
|
pub fn read_cache_topology() -> Option<CacheTopologyInfo> {
|
|
let cache_path = Path::new("/sys/devices/system/cpu/cpu0/cache");
|
|
if !cache_path.exists() {
|
|
warn!("Cache topology information is not available in sysfs.");
|
|
return None;
|
|
}
|
|
|
|
let mut info = CacheTopologyInfo {
|
|
l1_d_cache_size: get_cache_size(CacheLevel::L1D),
|
|
l1_d_cache_line_size: get_cache_coherency_line_size(CacheLevel::L1D),
|
|
l1_d_cache_sets: get_cache_number_of_sets(CacheLevel::L1D),
|
|
|
|
l1_i_cache_size: get_cache_size(CacheLevel::L1I),
|
|
l1_i_cache_line_size: get_cache_coherency_line_size(CacheLevel::L1I),
|
|
l1_i_cache_sets: get_cache_number_of_sets(CacheLevel::L1I),
|
|
|
|
l2_cache_size: get_cache_size(CacheLevel::L2),
|
|
l2_cache_line_size: get_cache_coherency_line_size(CacheLevel::L2),
|
|
l2_cache_sets: get_cache_number_of_sets(CacheLevel::L2),
|
|
|
|
l3_cache_size: get_cache_size(CacheLevel::L3),
|
|
l3_cache_line_size: get_cache_coherency_line_size(CacheLevel::L3),
|
|
l3_cache_sets: get_cache_number_of_sets(CacheLevel::L3),
|
|
|
|
l2_cache_shared: false,
|
|
l3_cache_shared: false,
|
|
};
|
|
|
|
if info.l2_cache_size != 0 {
|
|
info.l2_cache_shared = get_cache_shared(CacheLevel::L2);
|
|
}
|
|
if info.l3_cache_size != 0 {
|
|
info.l3_cache_shared = get_cache_shared(CacheLevel::L3);
|
|
}
|
|
|
|
Some(info)
|
|
}
|