Commit 11748b2a authored by Robert Sesek's avatar Robert Sesek Committed by Chromium LUCI CQ

Add a new Android.ArmCpuPart UMA.

This will record the ARM CPU's implementer and part number values.

Bug: 1164549
Change-Id: I09ea0d852fda6b05c50a16b64bfcde6f4f5f62b6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2615326
Commit-Queue: Robert Sesek <rsesek@chromium.org>
Reviewed-by: default avatarNico Weber <thakis@chromium.org>
Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Reviewed-by: default avatarJesse Doherty <jwd@chromium.org>
Reviewed-by: default avatarAndrew Grieve <agrieve@chromium.org>
Cr-Commit-Position: refs/heads/master@{#843243}
parent 6cbdc4ff
...@@ -35,9 +35,20 @@ ...@@ -35,9 +35,20 @@
#include <asm/hwcap.h> #include <asm/hwcap.h>
#include <sys/auxv.h> #include <sys/auxv.h>
#include "base/files/file_util.h" #include "base/files/file_util.h"
#include "base/numerics/checked_math.h"
#include "base/ranges/algorithm.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
// Temporary definitions until a new hwcap.h is pulled in. // Temporary definitions until a new hwcap.h is pulled in.
#define HWCAP2_MTE (1 << 18) #define HWCAP2_MTE (1 << 18)
#define HWCAP2_BTI (1 << 17) #define HWCAP2_BTI (1 << 17)
struct ProcCpuInfo {
std::string brand;
uint8_t implementer = 0;
uint32_t part_number = 0;
};
#endif #endif
#if defined(ARCH_CPU_X86_FAMILY) #if defined(ARCH_CPU_X86_FAMILY)
...@@ -138,33 +149,68 @@ uint64_t xgetbv(uint32_t xcr) { ...@@ -138,33 +149,68 @@ uint64_t xgetbv(uint32_t xcr) {
#if defined(ARCH_CPU_ARM_FAMILY) && \ #if defined(ARCH_CPU_ARM_FAMILY) && \
(defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)) (defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS))
std::string* CpuInfoBrand() { StringPairs::const_iterator FindFirstProcCpuKey(const StringPairs& pairs,
static std::string* brand = []() { StringPiece key) {
return ranges::find_if(pairs, [key](const StringPairs::value_type& pair) {
return TrimWhitespaceASCII(pair.first, base::TRIM_ALL) == key;
});
}
// Parses information about the ARM processor. Note that depending on the CPU
// package, processor configuration, and/or kernel version, this may only
// report information about the processor on which this thread is running. This
// can happen on heterogeneous-processor SoCs like Snapdragon 808, which has 4
// Cortex-A53 and 2 Cortex-A57. Unfortunately there is not a universally
// reliable way to examine the CPU part information for all cores.
const ProcCpuInfo* ParseProcCpu() {
static const ProcCpuInfo* info = []() {
// This function finds the value from /proc/cpuinfo under the key "model // This function finds the value from /proc/cpuinfo under the key "model
// name" or "Processor". "model name" is used in Linux 3.8 and later (3.7 // name" or "Processor". "model name" is used in Linux 3.8 and later (3.7
// and later for arm64) and is shown once per CPU. "Processor" is used in // and later for arm64) and is shown once per CPU. "Processor" is used in
// earler versions and is shown only once at the top of /proc/cpuinfo // earler versions and is shown only once at the top of /proc/cpuinfo
// regardless of the number CPUs. // regardless of the number CPUs.
const char kModelNamePrefix[] = "model name\t: "; const char kModelNamePrefix[] = "model name";
const char kProcessorPrefix[] = "Processor\t: "; const char kProcessorPrefix[] = "Processor";
std::string contents; std::string cpuinfo;
ReadFileToString(FilePath("/proc/cpuinfo"), &contents); ReadFileToString(FilePath("/proc/cpuinfo"), &cpuinfo);
DCHECK(!contents.empty()); DCHECK(!cpuinfo.empty());
std::istringstream iss(contents); ProcCpuInfo* info = new ProcCpuInfo();
std::string line;
while (std::getline(iss, line)) { StringPairs pairs;
if (line.compare(0, strlen(kModelNamePrefix), kModelNamePrefix) == 0) if (!SplitStringIntoKeyValuePairs(cpuinfo, ':', '\n', &pairs)) {
return new std::string(line.substr(strlen(kModelNamePrefix))); NOTREACHED();
if (line.compare(0, strlen(kProcessorPrefix), kProcessorPrefix) == 0) return info;
return new std::string(line.substr(strlen(kProcessorPrefix))); }
auto model_name = FindFirstProcCpuKey(pairs, kModelNamePrefix);
if (model_name == pairs.end())
model_name = FindFirstProcCpuKey(pairs, kProcessorPrefix);
if (model_name != pairs.end()) {
info->brand =
std::string(TrimWhitespaceASCII(model_name->second, TRIM_ALL));
} }
return new std::string(); auto implementer_string = FindFirstProcCpuKey(pairs, "CPU implementer");
if (implementer_string != pairs.end()) {
// HexStringToUInt() handles the leading whitespace on the value.
uint32_t implementer;
HexStringToUInt(implementer_string->second, &implementer);
if (!CheckedNumeric<uint32_t>(implementer)
.AssignIfValid(&info->implementer)) {
info->implementer = 0;
}
}
auto part_number_string = FindFirstProcCpuKey(pairs, "CPU part");
if (part_number_string != pairs.end())
HexStringToUInt(part_number_string->second, &info->part_number);
return info;
}(); }();
return brand; return info;
} }
#endif // defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || #endif // defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) ||
// defined(OS_LINUX) || defined(OS_CHROMEOS)) // defined(OS_LINUX) || defined(OS_CHROMEOS))
...@@ -290,7 +336,10 @@ void CPU::Initialize() { ...@@ -290,7 +336,10 @@ void CPU::Initialize() {
} }
#elif defined(ARCH_CPU_ARM_FAMILY) #elif defined(ARCH_CPU_ARM_FAMILY)
#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS) #if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
cpu_brand_ = *CpuInfoBrand(); const ProcCpuInfo* info = ParseProcCpu();
cpu_brand_ = info->brand;
implementer_ = info->implementer;
part_number_ = info->part_number;
#if defined(ARCH_CPU_ARM64) #if defined(ARCH_CPU_ARM64)
// Check for Armv8.5-A BTI/MTE support, exposed via HWCAP2 // Check for Armv8.5-A BTI/MTE support, exposed via HWCAP2
......
...@@ -70,6 +70,13 @@ class BASE_EXPORT CPU final { ...@@ -70,6 +70,13 @@ class BASE_EXPORT CPU final {
} }
bool is_running_in_vm() const { return is_running_in_vm_; } bool is_running_in_vm() const { return is_running_in_vm_; }
// The cpuinfo values for ARM cores are from the MIDR_EL1 register, a
// bitfield whose format is described in the core-specific manuals. E.g.,
// ARM Cortex-A57:
// https://developer.arm.com/documentation/ddi0488/h/system-control/aarch64-register-descriptions/main-id-register--el1.
uint8_t implementer() const { return implementer_; }
uint32_t part_number() const { return part_number_; }
// Armv8.5-A extensions for control flow and memory safety. // Armv8.5-A extensions for control flow and memory safety.
bool has_mte() const { return has_mte_; } bool has_mte() const { return has_mte_; }
bool has_bti() const { return has_bti_; } bool has_bti() const { return has_bti_; }
...@@ -142,6 +149,8 @@ class BASE_EXPORT CPU final { ...@@ -142,6 +149,8 @@ class BASE_EXPORT CPU final {
int stepping_ = 0; // processor revision number int stepping_ = 0; // processor revision number
int ext_model_ = 0; int ext_model_ = 0;
int ext_family_ = 0; int ext_family_ = 0;
uint32_t part_number_ = 0; // ARM MIDR part number
uint8_t implementer_ = 0; // ARM MIDR implementer identifier
bool has_mmx_ = false; bool has_mmx_ = false;
bool has_sse_ = false; bool has_sse_ = false;
bool has_sse2_ = false; bool has_sse2_ = false;
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "base/cpu.h" #include "base/cpu.h"
#include "base/containers/contains.h" #include "base/containers/contains.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/strings/string_util.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
...@@ -190,3 +191,18 @@ TEST(CPU, X86FamilyAndModel) { ...@@ -190,3 +191,18 @@ TEST(CPU, X86FamilyAndModel) {
EXPECT_EQ(ext_model, 7); EXPECT_EQ(ext_model, 7);
} }
#endif // defined(ARCH_CPU_X86_FAMILY) #endif // defined(ARCH_CPU_X86_FAMILY)
#if defined(ARCH_CPU_ARM_FAMILY) && \
(defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_CHROMEOS))
TEST(CPU, ARMImplementerAndPartNumber) {
base::CPU cpu;
const std::string& cpu_brand = cpu.cpu_brand();
EXPECT_FALSE(cpu_brand.empty());
EXPECT_EQ(cpu_brand, base::TrimWhitespaceASCII(cpu_brand, base::TRIM_ALL));
EXPECT_GT(cpu.implementer(), 0u);
EXPECT_GT(cpu.part_number(), 0u);
}
#endif // defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_LINUX) ||
// defined(OS_ANDROID) || defined(OS_CHROMEOS))
...@@ -7,8 +7,10 @@ ...@@ -7,8 +7,10 @@
#include <stdio.h> #include <stdio.h>
#include <sys/utsname.h> #include <sys/utsname.h>
#include "base/cpu.h"
#include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h" #include "base/metrics/histogram_macros.h"
#include "build/build_config.h"
namespace { namespace {
...@@ -28,8 +30,26 @@ void ReportKernelVersion() { ...@@ -28,8 +30,26 @@ void ReportKernelVersion() {
} }
} }
// Per the comment in base/cpu.cc's ParseProcCpu(), unfortunately there is not
// a universally reliable way to examine the CPU part information for all
// cores, so the sampling effect of data collection via UMA will have to
// suffice.
void ReportArmCpu() {
#if defined(ARCH_CPU_ARM_FAMILY)
base::CPU cpu;
// Compose the implementer (8 bits) and the part number (12 bits) into a
// single 20-bit number that can be recorded via UMA.
uint32_t composed = cpu.implementer();
composed <<= 12;
composed |= cpu.part_number();
base::UmaHistogramSparse("Android.ArmCpuPart", composed);
#endif
}
} // namespace } // namespace
void ReportSeccompSupport() { void ReportSeccompSupport() {
ReportKernelVersion(); ReportKernelVersion();
ReportArmCpu();
} }
...@@ -3655,6 +3655,27 @@ Unknown properties are collapsed to zero. --> ...@@ -3655,6 +3655,27 @@ Unknown properties are collapsed to zero. -->
<int value="5" label="INSUFFICIENT_RESOURCES"/> <int value="5" label="INSUFFICIENT_RESOURCES"/>
</enum> </enum>
<enum name="ArmCpuPart">
<summary>
Defines a subset of ARM CPU (implementer, part-number) pairs composed as a
20-bit number. This is a non-exhaustive enumeration.
</summary>
<int value="269320" label="ARM Cortex-A8"/>
<int value="269321" label="ARM Cortex-A9"/>
<int value="269326" label="ARM Cortex-A17"/>
<int value="269327" label="ARM Cortex-A15"/>
<int value="269335" label="ARM Cortex-R7"/>
<int value="269336" label="ARM Cortex-R8"/>
<int value="269575" label="ARM Cortex-A57"/>
<int value="269576" label="ARM Cortex-A72"/>
<int value="269577" label="ARM Cortex-A73"/>
<int value="269578" label="ARM Cortex-A75"/>
<int value="269579" label="ARM Cortex-A76"/>
<int value="269580" label="ARM Neoverse N1"/>
<int value="269581" label="ARM Cortex-A77"/>
<int value="269633" label="ARM Cortex-A78"/>
</enum>
<enum name="AshAutoNightLightNotificationState"> <enum name="AshAutoNightLightNotificationState">
<summary> <summary>
Defines the possible states of the Auto Night Light notification as a result Defines the possible states of the Auto Night Light notification as a result
...@@ -30,6 +30,21 @@ reviews. Googlers can read more about this at go/gwsq-gerrit. ...@@ -30,6 +30,21 @@ reviews. Googlers can read more about this at go/gwsq-gerrit.
</summary> </summary>
</histogram> </histogram>
<histogram name="Android.ArmCpuPart" enum="ArmCpuPart"
expires_after="2022-01-01">
<owner>rsesek@chromium.org</owner>
<owner>clank-security@google.com</owner>
<summary>
Reports information about the ARM CPU of a device. This composes the 8-bit
ARM implementer identifier and the 12-bit part number into a single 20-bit
CPU identifier, ranging from [0x00000,0xFFFFF]. Depending on the CPU
package, processor configuration, and/or kernel version, this may only
report information about the processor on which the metric was collected.
This can happen on heterogeneous-processor SoCs. The metric is logged once
every startup.
</summary>
</histogram>
<histogram name="Android.AutofillAssistant.DropOutReason" <histogram name="Android.AutofillAssistant.DropOutReason"
enum="AutofillAssistantDropOutReason" expires_after="2021-06-20"> enum="AutofillAssistantDropOutReason" expires_after="2021-06-20">
<owner>mcarlen@chromium.org</owner> <owner>mcarlen@chromium.org</owner>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment