检测是否在具有异构CPU体系结构的设备上运行

时间:2018-08-25 22:23:35

标签: android linux linux-kernel cpu root

我对此很具体。 我需要知道设备是否具有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的链接。我想知道在这种情况下是否可以考虑我们不是在异构环境中运行。

CPU类

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

FileUtils类

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

2 个答案:

答案 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/87522/why-do-cpuinfo-cur-freq-and-proc-cpuinfo-report-different-numbers

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 
}