diff options
Diffstat (limited to 'chromium/third_party/webrtc/base/linux.cc')
-rw-r--r-- | chromium/third_party/webrtc/base/linux.cc | 348 |
1 files changed, 348 insertions, 0 deletions
diff --git a/chromium/third_party/webrtc/base/linux.cc b/chromium/third_party/webrtc/base/linux.cc new file mode 100644 index 00000000000..b958543532e --- /dev/null +++ b/chromium/third_party/webrtc/base/linux.cc @@ -0,0 +1,348 @@ +/* + * Copyright 2008 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#if defined(WEBRTC_LINUX) +#include "webrtc/base/linux.h" + +#include <ctype.h> + +#include <errno.h> +#include <sys/utsname.h> +#include <sys/wait.h> + +#include <cstdio> +#include <set> + +#include "webrtc/base/stringencode.h" + +namespace rtc { + +static const char kCpuInfoFile[] = "/proc/cpuinfo"; +static const char kCpuMaxFreqFile[] = + "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq"; + +ProcCpuInfo::ProcCpuInfo() { +} + +ProcCpuInfo::~ProcCpuInfo() { +} + +bool ProcCpuInfo::LoadFromSystem() { + ConfigParser procfs; + if (!procfs.Open(kCpuInfoFile)) { + return false; + } + return procfs.Parse(§ions_); +}; + +bool ProcCpuInfo::GetSectionCount(size_t* count) { + if (sections_.empty()) { + return false; + } + if (count) { + *count = sections_.size(); + } + return true; +} + +bool ProcCpuInfo::GetNumCpus(int* num) { + if (sections_.empty()) { + return false; + } + int total_cpus = 0; +#if defined(__arm__) + // Count the number of blocks that have a "processor" key defined. On ARM, + // there may be extra blocks of information that aren't per-processor. + size_t section_count = sections_.size(); + for (size_t i = 0; i < section_count; ++i) { + int processor_id; + if (GetSectionIntValue(i, "processor", &processor_id)) { + ++total_cpus; + } + } + // Single core ARM systems don't include "processor" keys at all, so return + // that we have a single core if we didn't find any explicitly above. + if (total_cpus == 0) { + total_cpus = 1; + } +#else + // On X86, there is exactly one info section per processor. + total_cpus = static_cast<int>(sections_.size()); +#endif + if (num) { + *num = total_cpus; + } + return true; +} + +bool ProcCpuInfo::GetNumPhysicalCpus(int* num) { + if (sections_.empty()) { + return false; + } + // TODO: /proc/cpuinfo only reports cores that are currently + // _online_, so this may underreport the number of physical cores. +#if defined(__arm__) + // ARM (currently) has no hyperthreading, so just return the same value + // as GetNumCpus. + return GetNumCpus(num); +#else + int total_cores = 0; + std::set<int> physical_ids; + size_t section_count = sections_.size(); + for (size_t i = 0; i < section_count; ++i) { + int physical_id; + int cores; + // Count the cores for the physical id only if we have not counted the id. + if (GetSectionIntValue(i, "physical id", &physical_id) && + GetSectionIntValue(i, "cpu cores", &cores) && + physical_ids.find(physical_id) == physical_ids.end()) { + physical_ids.insert(physical_id); + total_cores += cores; + } + } + + if (num) { + *num = total_cores; + } + return true; +#endif +} + +bool ProcCpuInfo::GetCpuFamily(int* id) { + int cpu_family = 0; + +#if defined(__arm__) + // On some ARM platforms, there is no 'cpu family' in '/proc/cpuinfo'. But + // there is 'CPU Architecture' which can be used as 'cpu family'. + // See http://en.wikipedia.org/wiki/ARM_architecture for a good list of + // ARM cpu families, architectures, and their mappings. + // There may be multiple sessions that aren't per-processor. We need to scan + // through each session until we find the first 'CPU architecture'. + size_t section_count = sections_.size(); + for (size_t i = 0; i < section_count; ++i) { + if (GetSectionIntValue(i, "CPU architecture", &cpu_family)) { + // We returns the first one (if there are multiple entries). + break; + }; + } +#else + GetSectionIntValue(0, "cpu family", &cpu_family); +#endif + if (id) { + *id = cpu_family; + } + return true; +} + +bool ProcCpuInfo::GetSectionStringValue(size_t section_num, + const std::string& key, + std::string* result) { + if (section_num >= sections_.size()) { + return false; + } + ConfigParser::SimpleMap::iterator iter = sections_[section_num].find(key); + if (iter == sections_[section_num].end()) { + return false; + } + *result = iter->second; + return true; +} + +bool ProcCpuInfo::GetSectionIntValue(size_t section_num, + const std::string& key, + int* result) { + if (section_num >= sections_.size()) { + return false; + } + ConfigParser::SimpleMap::iterator iter = sections_[section_num].find(key); + if (iter == sections_[section_num].end()) { + return false; + } + return FromString(iter->second, result); +} + +ConfigParser::ConfigParser() {} + +ConfigParser::~ConfigParser() {} + +bool ConfigParser::Open(const std::string& filename) { + FileStream* fs = new FileStream(); + if (!fs->Open(filename, "r", NULL)) { + return false; + } + instream_.reset(fs); + return true; +} + +void ConfigParser::Attach(StreamInterface* stream) { + instream_.reset(stream); +} + +bool ConfigParser::Parse(MapVector* key_val_pairs) { + // Parses the file and places the found key-value pairs into key_val_pairs. + SimpleMap section; + while (ParseSection(§ion)) { + key_val_pairs->push_back(section); + section.clear(); + } + return (!key_val_pairs->empty()); +} + +bool ConfigParser::ParseSection(SimpleMap* key_val_pair) { + // Parses the next section in the filestream and places the found key-value + // pairs into key_val_pair. + std::string key, value; + while (ParseLine(&key, &value)) { + (*key_val_pair)[key] = value; + } + return (!key_val_pair->empty()); +} + +bool ConfigParser::ParseLine(std::string* key, std::string* value) { + // Parses the next line in the filestream and places the found key-value + // pair into key and val. + std::string line; + if ((instream_->ReadLine(&line)) == SR_EOS) { + return false; + } + std::vector<std::string> tokens; + if (2 != split(line, ':', &tokens)) { + return false; + } + // Removes whitespace at the end of Key name + size_t pos = tokens[0].length() - 1; + while ((pos > 0) && isspace(tokens[0][pos])) { + pos--; + } + tokens[0].erase(pos + 1); + // Removes whitespace at the start of value + pos = 0; + while (pos < tokens[1].length() && isspace(tokens[1][pos])) { + pos++; + } + tokens[1].erase(0, pos); + *key = tokens[0]; + *value = tokens[1]; + return true; +} + +#if !defined(WEBRTC_CHROMIUM_BUILDs) +static bool ExpectLineFromStream(FileStream* stream, + std::string* out) { + StreamResult res = stream->ReadLine(out); + if (res != SR_SUCCESS) { + if (res != SR_EOS) { + LOG(LS_ERROR) << "Error when reading from stream"; + } else { + LOG(LS_ERROR) << "Incorrect number of lines in stream"; + } + return false; + } + return true; +} + +static void ExpectEofFromStream(FileStream* stream) { + std::string unused; + StreamResult res = stream->ReadLine(&unused); + if (res == SR_SUCCESS) { + LOG(LS_WARNING) << "Ignoring unexpected extra lines from stream"; + } else if (res != SR_EOS) { + LOG(LS_WARNING) << "Error when checking for extra lines from stream"; + } +} + +// For caching the lsb_release output (reading it invokes a sub-process and +// hence is somewhat expensive). +static std::string lsb_release_string; +static CriticalSection lsb_release_string_critsec; + +std::string ReadLinuxLsbRelease() { + CritScope cs(&lsb_release_string_critsec); + if (!lsb_release_string.empty()) { + // Have cached result from previous call. + return lsb_release_string; + } + // No cached result. Run lsb_release and parse output. + POpenStream lsb_release_output; + if (!lsb_release_output.Open("lsb_release -idrcs", "r", NULL)) { + LOG_ERR(LS_ERROR) << "Can't run lsb_release"; + return lsb_release_string; // empty + } + // Read in the command's output and build the string. + std::ostringstream sstr; + std::string line; + int wait_status; + + if (!ExpectLineFromStream(&lsb_release_output, &line)) { + return lsb_release_string; // empty + } + sstr << "DISTRIB_ID=" << line; + + if (!ExpectLineFromStream(&lsb_release_output, &line)) { + return lsb_release_string; // empty + } + sstr << " DISTRIB_DESCRIPTION=\"" << line << '"'; + + if (!ExpectLineFromStream(&lsb_release_output, &line)) { + return lsb_release_string; // empty + } + sstr << " DISTRIB_RELEASE=" << line; + + if (!ExpectLineFromStream(&lsb_release_output, &line)) { + return lsb_release_string; // empty + } + sstr << " DISTRIB_CODENAME=" << line; + + // Should not be anything left. + ExpectEofFromStream(&lsb_release_output); + + lsb_release_output.Close(); + wait_status = lsb_release_output.GetWaitStatus(); + if (wait_status == -1 || + !WIFEXITED(wait_status) || + WEXITSTATUS(wait_status) != 0) { + LOG(LS_WARNING) << "Unexpected exit status from lsb_release"; + } + + lsb_release_string = sstr.str(); + + return lsb_release_string; +} +#endif + +std::string ReadLinuxUname() { + struct utsname buf; + if (uname(&buf) < 0) { + LOG_ERR(LS_ERROR) << "Can't call uname()"; + return std::string(); + } + std::ostringstream sstr; + sstr << buf.sysname << " " + << buf.release << " " + << buf.version << " " + << buf.machine; + return sstr.str(); +} + +int ReadCpuMaxFreq() { + FileStream fs; + std::string str; + int freq = -1; + if (!fs.Open(kCpuMaxFreqFile, "r", NULL) || + SR_SUCCESS != fs.ReadLine(&str) || + !FromString(str, &freq)) { + return -1; + } + return freq; +} + +} // namespace rtc + +#endif // defined(WEBRTC_LINUX) |