chromium/chrome/browser/metrics/perf/cpu_identity.cc

// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/metrics/perf/cpu_identity.h"

#include <string.h>

#include <algorithm>  // for std::lower_bound()

#include "base/cpu.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/system/sys_info.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"

namespace metrics {

namespace internal {

const CpuUarchTableEntry kCpuUarchTable[] = {
    // These were found on various sources on the Internet. Main ones are:
    // http://instlatx64.atw.hu/ for CPUID to model name and
    // http://www.cpu-world.com for model name to microarchitecture
    // clang-format off
    {"06_09", "Banias"},
    {"06_0D", "Dothan"},
    {"06_0F", "Merom"},
    {"06_16", "Merom"},
    {"06_17", "Nehalem"},
    {"06_1A", "Nehalem"},
    {"06_1C", "Bonnell"},     // Atom
    {"06_1D", "Nehalem"},
    {"06_1E", "Nehalem"},
    {"06_1F", "Nehalem"},
    {"06_25", "Westmere"},
    {"06_26", "Bonnell"},     // Atom
    {"06_2A", "SandyBridge"},
    {"06_2C", "Westmere"},
    {"06_2D", "SandyBridge"},
    {"06_2E", "Nehalem"},
    {"06_2F", "Westmere"},
    {"06_36", "Saltwell"},    // Atom
    {"06_37", "Silvermont"},
    {"06_3A", "IvyBridge"},
    {"06_3C", "Haswell"},
    {"06_3D", "Broadwell"},
    {"06_3E", "IvyBridge"},
    {"06_3F", "Haswell"},
    {"06_45", "Haswell"},
    {"06_46", "Haswell"},
    {"06_47", "Broadwell"},   // Broadwell-H
    {"06_4C", "Airmont"},     // Braswell
    {"06_4D", "Silvermont"},  // Avoton/Rangely
    {"06_4E", "Skylake"},
    {"06_55", "Skylake"},     // Skylake-X
    {"06_56", "Broadwell"},   // Broadwell-DE
    {"06_5C", "Goldmont"},
    {"06_5E", "Skylake"},
    {"06_5F", "Goldmont"},    // Denverton
    {"06_7A", "GoldmontPlus"},
    {"06_7E", "IceLake"},
    {"06_8C", "Tigerlake"},
    {"06_8D", "Tigerlake"},
    {"06_8E", "Kabylake"},
    {"06_97", "AlderLake"},
    {"06_9A", "AlderLake"},
    {"06_9C", "Tremont"},     // Jasperlake
    {"06_9E", "Kabylake"},
    {"06_A5", "CometLake"},
    {"06_A6", "CometLake"},
    {"06_B7", "RaptorLake"},
    {"06_BA", "RaptorLake"},
    {"06_BE", "Gracemont"},   // Alderlake-N
    {"06_BF", "RaptorLake"},
    {"0F_03", "Prescott"},
    {"0F_04", "Prescott"},
    {"0F_06", "Presler"},
    {"0F_68", "Athlon64"},
    {"0F_6B", "Athlon64"},
    {"10_02", "K10"},
    {"10_04", "K10"},
    {"10_05", "K10"},
    {"10_06", "K10"},
    {"12_01", "Llano"},
    {"14_01", "Bobcat"},
    {"14_02", "Bobcat"},
    {"15_01", "Bulldozer"},
    {"15_10", "Piledriver"},  // AMD Trinity
    {"15_13", "Piledriver"},  // AMD Richland
    {"15_30", "Steamroller"}, // AMD Kaveri
    {"15_38", "Steamroller"}, // AMD Godavari
    {"15_60", "Excavator"},   // AMD Carizzo
    {"15_65", "Excavator"},   // AMD Bristol Ridge
    {"15_70", "Excavator"},   // AMD Stoney Ridge
    {"16_00", "Jaguar"},      // AMD APUs Beema, Mullins, Steppe & Crowned Eagle
    {"16_30", "Puma"},        // AMD APUs Kabini, Temash, Kyoto
    {"17_01", "Zen"},         // AMD Summit Ridge
    {"17_08", "Zen+"},        // AMD Pinacle Ridge
    {"17_11", "Zen"},         // AMD Raven Ridge
    {"17_18", "Zen+"},        // AMD Picasso
    {"17_20", "Zen"},         // AMD Dali
    {"17_60", "Zen2"},        // AMD Renoir
    {"17_68", "Zen2"},        // AMD Lucienne
    {"17_71", "Zen2"},        // AMD Matisse
    {"17_A0", "Zen2"},        // AMD Mendocino
    {"19_50", "Zen3"},        // AMD Cezanne
    // clang-format on
};

const CpuUarchTableEntry* kCpuUarchTableEnd =
    kCpuUarchTable + std::size(kCpuUarchTable);

bool CpuUarchTableCmp(const CpuUarchTableEntry& a,
                      const CpuUarchTableEntry& b) {
  return strcmp(a.family_model, b.family_model) < 0;
}

}  // namespace internal

CPUIdentity::CPUIdentity() : family(0), model(0) {}

CPUIdentity::CPUIdentity(const CPUIdentity& other) = default;

CPUIdentity::~CPUIdentity() {}

std::string GetCpuUarch(const CPUIdentity& cpuid) {
  if (cpuid.vendor != "GenuineIntel" && cpuid.vendor != "AuthenticAMD")
    return std::string();  // Non-Intel or -AMD

  std::string family_model =
      base::StringPrintf("%02X_%02X", cpuid.family, cpuid.model);
  const internal::CpuUarchTableEntry search_elem = {family_model.c_str(), ""};
  auto* bound = std::lower_bound(internal::kCpuUarchTable,
                                 internal::kCpuUarchTableEnd, search_elem,
                                 internal::CpuUarchTableCmp);
  if (bound == internal::kCpuUarchTableEnd ||
      bound->family_model != family_model)
    return std::string();  // Unknown uarch
  return bound->uarch;
}

CPUIdentity GetCPUIdentity() {
  CPUIdentity result = {};
  result.arch = base::SysInfo::OperatingSystemArchitecture();
  result.release =
#if BUILDFLAG(IS_CHROMEOS_ASH)
      base::SysInfo::KernelVersion();
#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
      base::SysInfo::OperatingSystemVersion();
#else
#error "Unsupported configuration"
#endif
  base::CPU cpuid;
  result.vendor = cpuid.vendor_name();
  result.family = cpuid.family();
  result.model = cpuid.model();
  result.model_name = cpuid.cpu_brand();
  return result;
}

std::string SimplifyCPUModelName(const std::string& model_name) {
  std::string result = model_name;
  std::replace(result.begin(), result.end(), ' ', '-');
  base::ReplaceSubstringsAfterOffset(&result, 0, "(R)", "");
  return base::ToLowerASCII(result);
}

}  // namespace metrics