blob: d5b1c2b770abf1b77670507f804e134221f9eeb4 [file] [log] [blame]
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/compute_pressure/cpuid_base_frequency_parser.h"
#include <stdint.h>
#include <limits>
#include "base/check_op.h"
#include "base/numerics/safe_conversions.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece_forward.h"
#include "third_party/re2/src/re2/re2.h"
#include "third_party/re2/src/re2/stringpiece.h"
namespace content {
int64_t ParseBaseFrequencyFromCpuid(base::StringPiece brand_string) {
// A perfectly accurate number pattern would be quite a bit more complex, as
// we want to capture both integers (1133Mhz) and decimal fractions (1.20Ghz).
// The current pattern is preferred as base::StringToDouble() can catch the
// false positives.
//
// The unit pattern matches the strings "MHz" and "GHz" case-insensitively.
re2::RE2 frequency_re("([0-9.]+)\\s*([GgMm][Hh][Zz])");
// As matches are consumed, `input` will be mutated to reflect the
// non-consumed string.
re2::StringPiece input(brand_string.data(), brand_string.size());
re2::StringPiece number_string; // The frequency number.
re2::StringPiece unit; // MHz or GHz (case-insensitive)
while (
re2::RE2::FindAndConsume(&input, frequency_re, &number_string, &unit)) {
DCHECK_GT(number_string.size(), 0u)
<< "The number pattern should only match non-empty strings";
DCHECK_EQ(unit.size(), 3u)
<< "The unit pattern should match exactly 3 characters";
double number;
if (!base::StringToDouble(
base::StringPiece(number_string.data(), number_string.size()),
&number)) {
continue;
}
DCHECK_GE(number, 0);
double unit_multiplier =
(unit[0] == 'G' || unit[0] == 'g') ? 1'000'000'000 : 1'000'000;
double frequency = number * unit_multiplier;
// Avoid conversion overflows. double can (imprecisely) store larger numbers
// than int64_t.
if (!base::IsValueInRangeForNumericType<int64_t>(frequency))
continue;
int64_t frequency_int = static_cast<int64_t>(frequency);
// It's unlikely that Chrome can run on CPUs with clock speeds below 100MHz.
// This cutoff can catch some bad parses.
static constexpr int64_t kMinimumFrequency = 100'000'000;
if (frequency_int < kMinimumFrequency)
continue;
return frequency_int;
}
return -1;
}
} // namespace content