bool cpuinfo_arm_linux_detect_core_clusters_by_heuristic()

in src/arm/linux/clusters.c [56:287]


bool cpuinfo_arm_linux_detect_core_clusters_by_heuristic(
	uint32_t usable_processors,
	uint32_t max_processors,
	struct cpuinfo_arm_linux_processor processors[restrict static max_processors])
{
	uint32_t cluster_processors[3];
	switch (usable_processors) {
		case 10:
			cluster_processors[0] = 4;
			cluster_processors[1] = 4;
			cluster_processors[2] = 2;
			break;
		case 8:
			cluster_processors[0] = 4;
			cluster_processors[1] = 4;
			break;
		case 6:
			cluster_processors[0] = 4;
			cluster_processors[1] = 2;
			break;
#if defined(__ANDROID__) && CPUINFO_ARCH_ARM
		case 5:
			/*
			 * The only processor with 5 cores is Leadcore L1860C (ARMv7, mobile),
			 * but this configuration is not too unreasonable for a virtualized ARM server.
			 */
			cluster_processors[0] = 4;
			cluster_processors[1] = 1;
			break;
#endif
		default:
			return false;
	}

	/*
	 * Assignment of processors to core clusters is done in two passes:
	 * 1. Verify that the clusters proposed by heuristic are compatible with known details about processors.
	 * 2. If verification passed, update core clusters for the processors.
	 */

	uint32_t cluster = 0;
	uint32_t expected_cluster_processors = 0;
	uint32_t cluster_start, cluster_flags, cluster_midr, cluster_max_frequency, cluster_min_frequency;
	bool expected_cluster_exists;
	for (uint32_t i = 0; i < max_processors; i++) {
		if (bitmask_all(processors[i].flags, CPUINFO_LINUX_FLAG_VALID)) {
			if (expected_cluster_processors == 0) {
				/* Expect this processor to start a new cluster */

				expected_cluster_exists = !!(processors[i].flags & CPUINFO_LINUX_FLAG_PACKAGE_CLUSTER);
				if (expected_cluster_exists) {
					if (processors[i].package_leader_id != i) {
						cpuinfo_log_debug(
							"heuristic detection of core clusters failed: "
							"processor %"PRIu32" is expected to start a new cluster #%"PRIu32" with %"PRIu32" cores, "
							"but system siblings lists reported it as a sibling of processor %"PRIu32,
							i, cluster, cluster_processors[cluster], processors[i].package_leader_id);
						return false;
					}
				} else {
					cluster_flags = 0;
				}

				cluster_start = i;
				expected_cluster_processors = cluster_processors[cluster++];
			} else {
				/* Expect this processor to belong to the same cluster as processor */

				if (expected_cluster_exists) {
					/*
					 * The cluster suggested by the heuristic was already parsed from system siblings lists.
					 * For all processors we expect in the cluster, check that:
					 * - They have pre-assigned cluster from siblings lists (CPUINFO_LINUX_FLAG_PACKAGE_CLUSTER flag).
					 * - They were assigned to the same cluster based on siblings lists
					 *   (package_leader_id points to the first processor in the cluster).
					 */

					if ((processors[i].flags & CPUINFO_LINUX_FLAG_PACKAGE_CLUSTER) == 0) {
						cpuinfo_log_debug(
							"heuristic detection of core clusters failed: "
							"processor %"PRIu32" is expected to belong to the cluster of processor %"PRIu32", "
							"but system siblings lists did not report it as a sibling of processor %"PRIu32,
							i, cluster_start, cluster_start);
						return false;
					}
					if (processors[i].package_leader_id != cluster_start) {
						cpuinfo_log_debug(
							"heuristic detection of core clusters failed: "
							"processor %"PRIu32" is expected to belong to the cluster of processor %"PRIu32", "
							"but system siblings lists reported it to belong to the cluster of processor %"PRIu32,
							i, cluster_start, cluster_start);
						return false;
					}
				} else {
					/*
					 * The cluster suggest by the heuristic was not parsed from system siblings lists.
					 * For all processors we expect in the cluster, check that:
					 * - They have no pre-assigned cluster from siblings lists.
					 * - If their min/max CPU frequency is known, it is the same.
					 * - If any part of their MIDR (Implementer, Variant, Part, Revision) is known, it is the same.
					 */

					if (processors[i].flags & CPUINFO_LINUX_FLAG_PACKAGE_CLUSTER) {
						cpuinfo_log_debug(
							"heuristic detection of core clusters failed: "
							"processor %"PRIu32" is expected to be unassigned to any cluster, "
							"but system siblings lists reported it to belong to the cluster of processor %"PRIu32,
							i, processors[i].package_leader_id);
						return false;
					}

					if (processors[i].flags & CPUINFO_LINUX_FLAG_MIN_FREQUENCY) {
						if (cluster_flags & CPUINFO_LINUX_FLAG_MIN_FREQUENCY) {
							if (cluster_min_frequency != processors[i].min_frequency) {
								cpuinfo_log_debug(
									"heuristic detection of core clusters failed: "
									"minimum frequency of processor %"PRIu32" (%"PRIu32" KHz) is different than of its expected cluster (%"PRIu32" KHz)",
									i, processors[i].min_frequency, cluster_min_frequency);
								return false;
							}
						} else {
							cluster_min_frequency = processors[i].min_frequency;
							cluster_flags |= CPUINFO_LINUX_FLAG_MIN_FREQUENCY;
						}
					}

					if (processors[i].flags & CPUINFO_LINUX_FLAG_MAX_FREQUENCY) {
						if (cluster_flags & CPUINFO_LINUX_FLAG_MAX_FREQUENCY) {
							if (cluster_max_frequency != processors[i].max_frequency) {
								cpuinfo_log_debug(
									"heuristic detection of core clusters failed: "
									"maximum frequency of processor %"PRIu32" (%"PRIu32" KHz) is different than of its expected cluster (%"PRIu32" KHz)",
									i, processors[i].max_frequency, cluster_max_frequency);
								return false;
							}
						} else {
							cluster_max_frequency = processors[i].max_frequency;
							cluster_flags |= CPUINFO_LINUX_FLAG_MAX_FREQUENCY;
						}
					}

					if (processors[i].flags & CPUINFO_ARM_LINUX_VALID_IMPLEMENTER) {
						if (cluster_flags & CPUINFO_ARM_LINUX_VALID_IMPLEMENTER) {
							if ((cluster_midr & CPUINFO_ARM_MIDR_IMPLEMENTER_MASK) != (processors[i].midr & CPUINFO_ARM_MIDR_IMPLEMENTER_MASK)) {
								cpuinfo_log_debug(
									"heuristic detection of core clusters failed: "
									"CPU Implementer of processor %"PRIu32" (0x%02"PRIx32") is different than of its expected cluster (0x%02"PRIx32")",
									i, midr_get_implementer(processors[i].midr), midr_get_implementer(cluster_midr));
								return false;
							}
						} else {
							cluster_midr = midr_copy_implementer(cluster_midr, processors[i].midr);
							cluster_flags |= CPUINFO_ARM_LINUX_VALID_IMPLEMENTER;
						}
					}

					if (processors[i].flags & CPUINFO_ARM_LINUX_VALID_VARIANT) {
						if (cluster_flags & CPUINFO_ARM_LINUX_VALID_VARIANT) {
							if ((cluster_midr & CPUINFO_ARM_MIDR_VARIANT_MASK) != (processors[i].midr & CPUINFO_ARM_MIDR_VARIANT_MASK)) {
								cpuinfo_log_debug(
									"heuristic detection of core clusters failed: "
									"CPU Variant of processor %"PRIu32" (0x%"PRIx32") is different than of its expected cluster (0x%"PRIx32")",
									i, midr_get_variant(processors[i].midr), midr_get_variant(cluster_midr));
								return false;
							}
						} else {
							cluster_midr = midr_copy_variant(cluster_midr, processors[i].midr);
							cluster_flags |= CPUINFO_ARM_LINUX_VALID_VARIANT;
						}
					}

					if (processors[i].flags & CPUINFO_ARM_LINUX_VALID_PART) {
						if (cluster_flags & CPUINFO_ARM_LINUX_VALID_PART) {
							if ((cluster_midr & CPUINFO_ARM_MIDR_PART_MASK) != (processors[i].midr & CPUINFO_ARM_MIDR_PART_MASK)) {
								cpuinfo_log_debug(
									"heuristic detection of core clusters failed: "
									"CPU Part of processor %"PRIu32" (0x%03"PRIx32") is different than of its expected cluster (0x%03"PRIx32")",
									i, midr_get_part(processors[i].midr), midr_get_part(cluster_midr));
								return false;
							}
						} else {
							cluster_midr = midr_copy_part(cluster_midr, processors[i].midr);
							cluster_flags |= CPUINFO_ARM_LINUX_VALID_PART;
						}
					}

					if (processors[i].flags & CPUINFO_ARM_LINUX_VALID_REVISION) {
						if (cluster_flags & CPUINFO_ARM_LINUX_VALID_REVISION) {
							if ((cluster_midr & CPUINFO_ARM_MIDR_REVISION_MASK) != (processors[i].midr & CPUINFO_ARM_MIDR_REVISION_MASK)) {
								cpuinfo_log_debug(
									"heuristic detection of core clusters failed: "
									"CPU Revision of processor %"PRIu32" (0x%"PRIx32") is different than of its expected cluster (0x%"PRIx32")",
									i, midr_get_revision(cluster_midr), midr_get_revision(processors[i].midr));
								return false;
							}
						} else {
							cluster_midr = midr_copy_revision(cluster_midr, processors[i].midr);
							cluster_flags |= CPUINFO_ARM_LINUX_VALID_REVISION;
						}
					}
				}
			}
			expected_cluster_processors--;
		}
	}

	/* Verification passed, assign all processors to new clusters */
	cluster = 0;
	expected_cluster_processors = 0;
	for (uint32_t i = 0; i < max_processors; i++) {
		if (bitmask_all(processors[i].flags, CPUINFO_LINUX_FLAG_VALID)) {
			if (expected_cluster_processors == 0) {
				/* Expect this processor to start a new cluster */

				cluster_start = i;
				expected_cluster_processors = cluster_processors[cluster++];
			} else {
				/* Expect this processor to belong to the same cluster as processor */

				if (!(processors[i].flags & CPUINFO_LINUX_FLAG_PACKAGE_CLUSTER)) {
					cpuinfo_log_debug("assigned processor %"PRIu32" to cluster of processor %"PRIu32" based on heuristic",
						i, cluster_start);
				}

				processors[i].package_leader_id = cluster_start;
				processors[i].flags |= CPUINFO_LINUX_FLAG_PACKAGE_CLUSTER;
			}
			expected_cluster_processors--;
		}
	}
	return true;
}