Files
cloud-hypervisor/arch/src/aarch64/cache.rs
Anirudh Rayabharam 9446dad1d0 arch: aarch64: extract cache topology collection into a helper
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>
2026-07-06 16:31:21 +00:00

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)
}