Bug 1128472 - Part 2. Linux support. r=gfritzsche

This commit is contained in:
Milan Sreckovic 2015-09-08 14:35:00 +02:00
parent 0eb43cba54
commit 8126e87d73
4 changed files with 147 additions and 16 deletions

View File

@ -78,15 +78,15 @@ Structure::
virtualMaxMB: <number>, // windows-only
isWow64: <bool>, // windows-only
cpu: {
count: <number>, // e.g. 8, or null on failure - logical cpus
cores: <number>, // e.g., 4, or null on failure - physical cores, only on windows & mac
vendor: <string>, // e.g. "GenuineIntel", or null on failure, only on mac
family: <string>, // null on failure, only on windows & mac
model: <string>, // null on failure, only on windows & mac
stepping: <string>, // null on failure, only on windows & mac
count: <number>, // desktop only, e.g. 8, or null on failure - logical cpus
cores: <number>, // desktop only, e.g., 4, or null on failure - physical cores
vendor: <string>, // e.g. "GenuineIntel", or null on failure, only on mac & linux
family: <string>, // desktop only, null on failure
model: <string>, // desktop only, null on failure
stepping: <string>, // desktop only, null on failure
l2cacheKB: <number>, // L2 cache size in KB, only on windows & mac
l3cacheKB: <number>, // L3 cache size in KB, only on windows & mac
speedMHz: <number>, // cpu clock speed in MHz, only on windows & mac
l3cacheKB: <number>, // desktop only, L3 cache size in KB
speedMHz: <number>, // desktop only, cpu clock speed in MHz
extensions: [
<string>,
...

View File

@ -8,11 +8,13 @@ Cu.import("resource://gre/modules/Services.jsm", this);
Cu.import("resource://gre/modules/PromiseUtils.jsm", this);
Cu.import("resource://gre/modules/Task.jsm", this);
Cu.import("resource://testing-common/httpd.js", this);
Cu.import("resource://gre/modules/AppConstants.jsm");
const gIsWindows = ("@mozilla.org/windows-registry-key;1" in Cc);
const gIsMac = ("@mozilla.org/xpcom/mac-utils;1" in Cc);
const gIsAndroid = ("@mozilla.org/android/bridge;1" in Cc);
const gIsGonk = ("@mozilla.org/cellbroadcast/gonkservice;1" in Cc);
const gIsWindows = AppConstants.platform == "win";
const gIsMac = AppConstants.platform == "macosx";
const gIsAndroid = AppConstants.platform == "android";
const gIsGonk = AppConstants.platform == "gonk";
const gIsLinux = AppConstants.platform == "linux";
const Telemetry = Cc["@mozilla.org/base/telemetry;1"].getService(Ci.nsITelemetry);

View File

@ -366,10 +366,10 @@ function checkSystemSection(data) {
Assert.ok(Number.isFinite(data.system.memoryMB), "MemoryMB must be a number.");
if (gIsWindows || gIsMac) {
if (gIsWindows || gIsMac || gIsLinux) {
let EXTRA_CPU_FIELDS = ["cores", "model", "family", "stepping",
"l2cacheKB", "l3cacheKB", "speedMHz"];
if (gIsMac) {
if (gIsMac || gIsLinux) {
EXTRA_CPU_FIELDS.push("vendor");
}
@ -388,14 +388,15 @@ function checkSystemSection(data) {
}
// We insist these are available
for (let f of ["cores", "speedMHz"]) {
for (let f of ["cores"]) {
Assert.ok(!(f in data.system.cpu) ||
Number.isFinite(data.system.cpu[f]),
f + " must be a number if non null.");
}
// These should be numbers if they are not null
for (let f of ["model", "family", "stepping", "l2cacheKB", "l3cacheKB"]) {
for (let f of ["model", "family", "stepping", "l2cacheKB",
"l3cacheKB", "speedMHz"]) {
Assert.ok(!(f in data.system.cpu) ||
data.system.cpu[f] === null ||
Number.isFinite(data.system.cpu[f]),

View File

@ -31,6 +31,13 @@
#ifdef MOZ_WIDGET_GTK
#include <gtk/gtk.h>
#include <unistd.h>
#include <fstream>
#include "mozilla/Tokenizer.h"
#include "nsCharSeparatedTokenizer.h"
#include <map>
#include <string>
#endif
#ifdef MOZ_WIDGET_ANDROID
@ -64,6 +71,30 @@ NS_EXPORT int android_sdk_version;
// only happens well after that point.
uint32_t nsSystemInfo::gUserUmask = 0;
#if defined (MOZ_WIDGET_GTK)
static void
SimpleParseKeyValuePairs(const std::string& aFilename,
std::map<nsCString, nsCString>& aKeyValuePairs)
{
std::ifstream input(aFilename.c_str());
for (std::string line; std::getline(input, line); ) {
nsAutoCString key, value;
nsCCharSeparatedTokenizer tokens(nsDependentCString(line.c_str()), ':');
if (tokens.hasMoreTokens()) {
key = tokens.nextToken();
if (tokens.hasMoreTokens()) {
value = tokens.nextToken();
}
// We want the value even if there was just one token, to cover the
// case where we had the key, and the value was blank (seems to be
// a valid scenario some files.)
aKeyValuePairs[key] = value;
}
}
}
#endif
#if defined(XP_WIN)
namespace {
nsresult
@ -447,6 +478,103 @@ nsSystemInfo::Init()
}
MOZ_ASSERT(sizeof(sysctlValue32) == len);
#elif defined (MOZ_WIDGET_GTK)
// Get vendor, family, model, stepping, physical cores, L3 cache size
// from /proc/cpuinfo file
{
std::map<nsCString, nsCString> keyValuePairs;
SimpleParseKeyValuePairs("/proc/cpuinfo", keyValuePairs);
// cpuVendor from "vendor_id"
cpuVendor.Assign(keyValuePairs[NS_LITERAL_CSTRING("vendor_id")]);
{
// cpuFamily from "cpu family"
Tokenizer::Token t;
Tokenizer p(keyValuePairs[NS_LITERAL_CSTRING("cpu family")]);
if (p.Next(t) && t.Type() == Tokenizer::TOKEN_INTEGER &&
t.AsInteger() <= INT32_MAX) {
cpuFamily = static_cast<int>(t.AsInteger());
}
}
{
// cpuModel from "model"
Tokenizer::Token t;
Tokenizer p(keyValuePairs[NS_LITERAL_CSTRING("model")]);
if (p.Next(t) && t.Type() == Tokenizer::TOKEN_INTEGER &&
t.AsInteger() <= INT32_MAX) {
cpuModel = static_cast<int>(t.AsInteger());
}
}
{
// cpuStepping from "stepping"
Tokenizer::Token t;
Tokenizer p(keyValuePairs[NS_LITERAL_CSTRING("stepping")]);
if (p.Next(t) && t.Type() == Tokenizer::TOKEN_INTEGER &&
t.AsInteger() <= INT32_MAX) {
cpuStepping = static_cast<int>(t.AsInteger());
}
}
{
// physicalCPUs from "cpu cores"
Tokenizer::Token t;
Tokenizer p(keyValuePairs[NS_LITERAL_CSTRING("cpu cores")]);
if (p.Next(t) && t.Type() == Tokenizer::TOKEN_INTEGER &&
t.AsInteger() <= INT32_MAX) {
physicalCPUs = static_cast<int>(t.AsInteger());
}
}
{
// cacheSizeL3 from "cache size"
Tokenizer::Token t;
Tokenizer p(keyValuePairs[NS_LITERAL_CSTRING("cache size")]);
if (p.Next(t) && t.Type() == Tokenizer::TOKEN_INTEGER &&
t.AsInteger() <= INT32_MAX) {
cacheSizeL3 = static_cast<int>(t.AsInteger());
if (p.Next(t) && t.Type() == Tokenizer::TOKEN_WORD &&
t.AsString() != NS_LITERAL_CSTRING("KB")) {
// If we get here, there was some text after the cache size value
// and that text was not KB. For now, just don't report the
// L3 cache.
cacheSizeL3 = -1;
}
}
}
}
{
// Get cpuSpeed from another file.
std::ifstream input("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq");
std::string line;
if (getline(input, line)) {
Tokenizer::Token t;
Tokenizer p(line.c_str());
if (p.Next(t) && t.Type() == Tokenizer::TOKEN_INTEGER &&
t.AsInteger() <= INT32_MAX) {
cpuSpeed = static_cast<int>(t.AsInteger()/1000);
}
}
}
{
// Get cacheSizeL2 from yet another file
std::ifstream input("/sys/devices/system/cpu/cpu0/cache/index2/size");
std::string line;
if (getline(input, line)) {
Tokenizer::Token t;
Tokenizer p(line.c_str(), nullptr, "K");
if (p.Next(t) && t.Type() == Tokenizer::TOKEN_INTEGER &&
t.AsInteger() <= INT32_MAX) {
cacheSizeL2 = static_cast<int>(t.AsInteger());
}
}
}
SetInt32Property(NS_LITERAL_STRING("cpucount"), PR_GetNumberOfProcessors());
#else
SetInt32Property(NS_LITERAL_STRING("cpucount"), PR_GetNumberOfProcessors());
#endif