Skip to content

Commit

Permalink
Slightly Make CPU cache interrogation an opt-in feature
Browse files Browse the repository at this point in the history
This feature has a measurable startup performance
and for most modern CPUs, the cache line size is
64 anyway, so it doesn't make sense burning cycles
to figure it out just for the odd case where the value
is different
  • Loading branch information
geoand committed Jan 23, 2025
1 parent f8ba715 commit 6d9f2f7
Showing 1 changed file with 79 additions and 68 deletions.
147 changes: 79 additions & 68 deletions cpu/src/main/java/io/smallrye/common/cpu/CacheInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -78,84 +78,95 @@ public static int getSmallestInstructionCacheLineSize() {
}

static {
cacheLevels = doPrivileged((PrivilegedAction<CacheLevelInfo[]>) () -> {
try {
String osArch = System.getProperty("os.name", "unknown").toLowerCase(Locale.US);
if (osArch.contains("linux")) {
// try to read /sys fs
final File cpu0 = new File("/sys/devices/system/cpu/cpu0/cache");
if (cpu0.exists()) {
// great!
final File[] files = cpu0.listFiles();
if (files != null) {
ArrayList<File> indexes = new ArrayList<File>();
for (File file : files) {
if (file.getName().startsWith("index")) {
indexes.add(file);
cacheLevels = doPrivileged(new PrivilegedAction<>() {
@Override
public CacheLevelInfo[] run() {
if (determineCacheLevel()) {
try {
String osArch = System.getProperty("os.name", "unknown").toLowerCase(Locale.US);
if (osArch.contains("linux")) {
// try to read /sys fs
final File cpu0 = new File("/sys/devices/system/cpu/cpu0/cache");
if (cpu0.exists()) {
// great!
final File[] files = cpu0.listFiles();
if (files != null) {
ArrayList<File> indexes = new ArrayList<File>();
for (File file : files) {
if (file.getName().startsWith("index")) {
indexes.add(file);
}
}
final CacheLevelInfo[] levelInfoArray = new CacheLevelInfo[indexes.size()];
for (int i = 0; i < indexes.size(); i++) {
File file = indexes.get(i);
int index = parseIntFile(new File(file, "level"));
final CacheType type;
switch (parseStringFile(new File(file, "type"))) {
case "Data":
type = CacheType.DATA;
break;
case "Instruction":
type = CacheType.INSTRUCTION;
break;
case "Unified":
type = CacheType.UNIFIED;
break;
default:
type = CacheType.UNKNOWN;
break;
}
int size = parseIntKBFile(new File(file, "size"));
int lineSize = parseIntFile(new File(file, "coherency_line_size"));
levelInfoArray[i] = new CacheLevelInfo(index, type, size, lineSize);
}
return levelInfoArray;
}
}
final CacheLevelInfo[] levelInfoArray = new CacheLevelInfo[indexes.size()];
for (int i = 0; i < indexes.size(); i++) {
File file = indexes.get(i);
int index = parseIntFile(new File(file, "level"));
final CacheType type;
switch (parseStringFile(new File(file, "type"))) {
case "Data":
type = CacheType.DATA;
break;
case "Instruction":
type = CacheType.INSTRUCTION;
break;
case "Unified":
type = CacheType.UNIFIED;
break;
default:
type = CacheType.UNKNOWN;
break;
} else if (osArch.contains("mac os x")) {
// cache line size
final int lineSize = safeParseInt(parseProcessOutput("/usr/sbin/sysctl", "-n", "hw.cachelinesize"));
if (lineSize != 0) {
// cache sizes
final int l1d = safeParseInt(parseProcessOutput("/usr/sbin/sysctl", "-n", "hw.l1dcachesize"));
final int l1i = safeParseInt(parseProcessOutput("/usr/sbin/sysctl", "-n", "hw.l1icachesize"));
final int l2 = safeParseInt(parseProcessOutput("/usr/sbin/sysctl", "-n", "hw.l2cachesize"));
final int l3 = safeParseInt(parseProcessOutput("/usr/sbin/sysctl", "-n", "hw.l3cachesize"));
ArrayList<CacheLevelInfo> list = new ArrayList<CacheLevelInfo>();
if (l1d != 0) {
list.add(new CacheLevelInfo(1, CacheType.DATA, l1d / 1024, lineSize));
}
if (l1i != 0) {
list.add(new CacheLevelInfo(1, CacheType.INSTRUCTION, l1i / 1024, lineSize));
}
if (l2 != 0) {
list.add(new CacheLevelInfo(2, CacheType.UNIFIED, l2 / 1024, lineSize));
}
if (l3 != 0) {
list.add(new CacheLevelInfo(3, CacheType.UNIFIED, l3 / 1024, lineSize));
}
if (list.size() > 0) {
return list.toArray(new CacheLevelInfo[list.size()]);
}
int size = parseIntKBFile(new File(file, "size"));
int lineSize = parseIntFile(new File(file, "coherency_line_size"));
levelInfoArray[i] = new CacheLevelInfo(index, type, size, lineSize);
}
return levelInfoArray;
} else if (osArch.contains("windows")) {
// TODO: use the wmic utility to get cache line info
}
} catch (Throwable ignored) {
}
} else if (osArch.contains("mac os x")) {
// cache line size
final int lineSize = safeParseInt(parseProcessOutput("/usr/sbin/sysctl", "-n", "hw.cachelinesize"));
if (lineSize != 0) {
// cache sizes
final int l1d = safeParseInt(parseProcessOutput("/usr/sbin/sysctl", "-n", "hw.l1dcachesize"));
final int l1i = safeParseInt(parseProcessOutput("/usr/sbin/sysctl", "-n", "hw.l1icachesize"));
final int l2 = safeParseInt(parseProcessOutput("/usr/sbin/sysctl", "-n", "hw.l2cachesize"));
final int l3 = safeParseInt(parseProcessOutput("/usr/sbin/sysctl", "-n", "hw.l3cachesize"));
ArrayList<CacheLevelInfo> list = new ArrayList<CacheLevelInfo>();
if (l1d != 0) {
list.add(new CacheLevelInfo(1, CacheType.DATA, l1d / 1024, lineSize));
}
if (l1i != 0) {
list.add(new CacheLevelInfo(1, CacheType.INSTRUCTION, l1i / 1024, lineSize));
}
if (l2 != 0) {
list.add(new CacheLevelInfo(2, CacheType.UNIFIED, l2 / 1024, lineSize));
}
if (l3 != 0) {
list.add(new CacheLevelInfo(3, CacheType.UNIFIED, l3 / 1024, lineSize));
}
if (list.size() > 0) {
return list.toArray(new CacheLevelInfo[list.size()]);
}
}
} else if (osArch.contains("windows")) {
// TODO: use the wmic utility to get cache line info
// all has failed
return new CacheLevelInfo[0];
} else {
return new CacheLevelInfo[] { new CacheLevelInfo(0, CacheType.UNKNOWN, 0, 64) };
}
} catch (Throwable ignored) {
}
// all has failed
return new CacheLevelInfo[0];
});
}

private static boolean determineCacheLevel() {
return Boolean.parseBoolean(System.getProperty("smallrye.cpu.determine-cache-level", "false"));
}

static int parseIntFile(final File file) {
return safeParseInt(parseStringFile(file));
}
Expand Down Expand Up @@ -278,4 +289,4 @@ public static void main(String[] args) {
Integer.valueOf(levelInfo.getCacheLineSize()));
}
}
}
}

0 comments on commit 6d9f2f7

Please sign in to comment.