我对此很具体。 我需要知道设备是否具有CPU,其CPU具有像ARM's big.LITTLE technology这样的异构内核,例如,一组4个ARM Cortex-A53 +另一组4个功能更强大的ARM Cortex-A72,总共8个内核,基本上是2个同一芯片中的处理器。处理器模型并不重要。
我正在考虑读取所有内核的scaling_max_freq
并分组具有不同最大频率的内核(然后进行比较),但是我注意到在某些设备中,通往不是的任何内核的路径cpu0 实际上是到/ sys / devices / system / cpu / cpu0 / cpufreq / scaling_max_freq
也就是说,如果我尝试读取cpu3的scaling_max_freq,它将是cpu0的scaling_max_freq的链接。我想知道在这种情况下是否可以考虑我们不是在异构环境中运行。
public final class CPU {
// To be formatted with specific core number
private static final String CPU_DIR = "/sys/devices/system/cpu/cpu%d";
private static final String CPUFREQ_DIR = CPU_DIR + "/cpufreq";
public static final String SCALING_MAX_FREQ = CPUFREQ_DIR + "/scaling_max_freq";
private static final String DEFAULT_FREQS = "200000 400000 800000 1200000";
private CPU() {
}
// Here I'd replace 0 with (other) core number
@NonNull
public static synchronized String[] getAvailFreqs() {
String[] split;
String freqs = FileUtils.readFile(format(SCALING_AVAIL_FREQS, 0), DEFAULT_FREQS);
try {
split = freqs.split(" ");
} catch (Exception e) {
split = DEFAULT_FREQS.split(" ");
}
return split;
}
// Here I'd replace 0 with (other) core number
public static synchronized int getMaxFreq() {
try {
return Integer.parseInt(FileUtils.readFile(format(SCALING_MAX_FREQ, 0), "1200000"));
} catch (Exception ignored){}
return 1200000;
}
private static String format(String format, Object arg) {
return String.format(Locale.US, format, arg);
}
}
public final class FileUtils {
private FileUtils() {
}
public static String readFile(String pathname, String defaultOutput) {
return baseReadSingleLineFile(new File(pathname), defaultOutput);
}
public static String readFile(File file, String defaultOutput) {
return baseReadSingleLineFile(file, defaultOutput);
}
// Async
private static String baseReadSingleLineFile(File file, String defaultOutput) {
String ret = defaultOutput;
Thread thread = new Thread(() -> {
if (file.isFile() || file.exists()) {
if (file.canRead()) {
try {
FileInputStream inputStream = new FileInputStream(file);
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String line = reader.readLine(); // Fisrt line
reader.close();
inputStream.close();
ret = line;
} catch (Exception ignored) {}
} else
// Uses cat command
ret = RootUtils.readFile(file, defaultOutput);
}
});
thread.start();
// 3 seconds timeout
long endTimeMillis = System.currentTimeMillis() + 3000;
while (thread.isAlive())
if (System.currentTimeMillis() > endTimeMillis)
return defaultOutput;
return ret;
}
}
答案 0 :(得分:0)
您可以解析$ cat /proc/cpuinfo
中的结果,如“模型名称”中所述:
processor : 0
[...]
model name : Intel(R) Core(TM) i5 CPU M 560 @ 2.67GHz
[...]
processor : 1
[...]
请注意,“ cpu MHz”描述的是当前频率,而不是最大频率。
参考文献:
https://unix.stackexchange.com/questions/146051/number-of-processors-in-proc-cpuinfo
编辑:如果您的操作系统未返回型号名称,则可以将BogoMips用作比较单位(尽管以下说明中的Wikipedia不建议使用BogoMips)。至少您可以使用它来标识您具有异构体系结构。
BogoMips(来自“假”和MIPS)是对CPU的不科学测量 Linux内核启动以校准内部时产生的速度 忙循环。该术语的一个经常被引用的定义是“ 每秒百万次的处理器绝对无法执行任何操作。”
BogoMips是一个值,可用于验证处理器是否 问题是在类似处理器的适当范围内,即 BogoMips代表处理器的时钟频率以及 可能存在的CPU缓存。它不能用于性能 比较不同的CPU。
Here,您可以找到BogoMips评级的完整列表。
答案 1 :(得分:0)
这是我目前在Kotlin的方法:
class CpuManager {
// GOTO: val clusters: List<CpuCluster>
companion object {
private const val CPU_DIR = "/sys/devices/system/cpu/cpu%d"
private const val CPUFREQ_DIR = "$CPU_DIR/cpufreq"
const val SCALING_CUR_FREQ = "$CPUFREQ_DIR/scaling_cur_freq"
const val SCALING_MAX_FREQ = "$CPUFREQ_DIR/scaling_max_freq"
const val SCALING_MIN_FREQ = "$CPUFREQ_DIR/scaling_min_freq"
const val SCALING_AVAIL_FREQS = "$CPUFREQ_DIR/scaling_available_frequencies"
private const val DEFAULT_FREQS = "200000 400000 800000 1200000"
}
private fun getAvailFreqs(cpuCore: Int = 0) : Array<String> {
val freqs = FileUtils.readFile(format(SCALING_AVAIL_FREQS, cpuCore), DEFAULT_FREQS)
return try {
freqs.split(" ").dropLastWhile { it.isEmpty() }.toTypedArray()
} catch (e: Exception) {
DEFAULT_FREQS.split(" ").dropLastWhile { it.isEmpty() }.toTypedArray()
}
}
@JvmOverloads
fun getMaxFreq(cpuCore: Int = 0): Int {
return try {
FileUtils.readFile(format(SCALING_MAX_FREQ, cpuCore), "1200000").toInt()
} catch (ignored: Exception) {
1200000
}
}
private fun format(format: String, arg: Any): String {
return String.format(Locale.US, format, arg)
}
val cpuCount: Int
get() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
return Runtime.getRuntime().availableProcessors()
}
class CpuFilter : FileFilter {
override fun accept(pathname: File): Boolean {
return Pattern.matches("cpu[0-11]+", pathname.name)
}
}
return try {
val dir = File("/sys/devices/system/cpu/")
val files = dir.listFiles(CpuFilter())
files.size
} catch (e: Exception) {
1
}
}
val clusters: List<CpuCluster>
get() {
val cpuCount = this.cpuCount
val clustersList = mutableListOf<CpuCluster>()
val cpuCores = mutableListOf<CpuCore>()
for (i in (0 until cpuCount)) {
val cpuCore = CpuCore(coreNum = i)
cpuCore.availFreqs = getAvailFreqs(i)
//cpuCore.availGovs = getAvailGovs(i)
//cpuCore.governorTunables = getGovernorTunables(cpuCore.currentGov, cpuCore.coreNum)
cpuCores.add(cpuCore)
}
val allFreqs = mutableListOf<Array<Int>>()
for (cpu in 0 until cpuCount) {
val availCpuFreqs = cpuCores[cpu].availFreqs.toIntArray() // Extension function below
availCpuFreqs.sortWith(Comparator { o1, o2 -> o1.compareTo(o2) })
allFreqs.add(availCpuFreqs)
}
val maxFreqs = mutableListOf<Int>()
allFreqs.forEach { freqList ->
val coreMax = freqList[freqList.size - 1]
maxFreqs.add(coreMax)
}
val firstMaxFreq = allFreqs.first().last()
// Here is the logic I suggested
val distinctMaxFreqs = mutableListOf<Int>()
distinctMaxFreqs.add(firstMaxFreq)
maxFreqs.forEach {
if (it != firstMaxFreq && !distinctMaxFreqs.contains(it)) {
distinctMaxFreqs.add(it)
}
}
val clustersCount = distinctMaxFreqs.size
if (clustersCount == 1) {
clustersList.add(CpuCluster(cpuCores))
} else {
distinctMaxFreqs.forEach { maxFreq ->
val cpuClusterCores = mutableListOf<CpuCore>()
cpuCores.forEach {
if (it.maxFreq == maxFreq) {
cpuClusterCores.add(it)
}
}
clustersList.add(CpuCluster(cpuClusterCores))
}
}
return clustersList
}
data class CpuCluster(val cpuCores: List<CpuCore>) {
val totalCpuCount: Int
get() {
return cpuCores.size
}
val range: IntRange
get() {
return if (cpuCores.isNullOrEmpty()) {
0..0
} else {
IntRange(cpuCores.first().coreNum, cpuCores.last().coreNum)
}
}
}
data class CpuCore(val coreNum: Int = 0, var availFreqs: Array<String> = DEFAULT_FREQS.split(" ").toTypedArray(), var availGovs: Array<String> = DEFAULT_GOVERNORS.split(" ").toTypedArray()) {
var governorTunables: ArrayList<GovernorTunable>? = null
val currentGov: String
get() {
return FileUtils.readFile(
"/sys/devices/system/cpu/cpu$coreNum/cpufreq/scaling_governor",
"interactive")
}
val currentFreq: Int
get() {
return try {
FileUtils.readFile(
"/sys/devices/system/cpu/cpu$coreNum/cpufreq/scaling_cur_freq",
"800000")
.toInt()
} catch (e: Exception) { 800000 }
}
val minFreq: Int
get() {
return try {
availFreqs.sortWith(java.util.Comparator { o1, o2 -> o1.toInt().compareTo(o2.toInt()) })
availFreqs.first().toInt()
} catch (e: Exception) { 400000 }
}
val maxFreq: Int
get() {
return try {
availFreqs.sortWith(java.util.Comparator { o1, o2 -> o1.toInt().compareTo(o2.toInt()) })
availFreqs.last().toInt()
} catch (e: Exception) { 800000 }
}
}
}
private fun Array<String>.toIntArray(): Array<Int> {
val list = mutableListOf<Int>()
this.forEach { list.add(it.toInt()) }
return list.toTypedArray()
}
val cpuManager = CpuManager()
val clusters: List<CpuCluster> = cpuManager.clusters
if (clusters.size > 1) {
// Heterogeneous computing architecture
}