/* Copyright 2013 10gen Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the GNU Affero General Public License in all respects
* for all of the code used other than as permitted herein. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you do not
* wish to do so, delete this exception statement from your version. If you
* delete this exception statement from all source files in the program,
* then also delete it in the license file.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "mongo/util/file.h"
#include "mongo/util/mongoutils/str.h"
#include "mongo/util/processinfo.h"
namespace mongo {
/**
* Read the first line from a file; return empty string on failure
*/
static string readLineFromFile(const char* fname) {
std::string fstr;
std::ifstream f(fname);
if (f.is_open()) {
std::getline(f, fstr);
}
return fstr;
}
struct ProcPsinfo {
ProcPsinfo() {
FILE* f = fopen("/proc/self/psinfo", "r");
massert(16846,
mongoutils::str::stream() << "couldn't open \"/proc/self/psinfo\": "
<< errnoWithDescription(),
f);
size_t num = fread(&psinfo, sizeof(psinfo), 1, f);
int err = errno;
fclose(f);
massert(16847,
mongoutils::str::stream() << "couldn't read from \"/proc/self/psinfo\": "
<< errnoWithDescription(err),
num == 1);
}
psinfo_t psinfo;
};
struct ProcUsage {
ProcUsage() {
FILE* f = fopen("/proc/self/usage", "r");
massert(16848,
mongoutils::str::stream() << "couldn't open \"/proc/self/usage\": "
<< errnoWithDescription(),
f);
size_t num = fread(&prusage, sizeof(prusage), 1, f);
int err = errno;
fclose(f);
massert(16849,
mongoutils::str::stream() << "couldn't read from \"/proc/self/usage\": "
<< errnoWithDescription(err),
num == 1);
}
prusage_t prusage;
};
ProcessInfo::ProcessInfo(ProcessId pid) : _pid(pid) { }
ProcessInfo::~ProcessInfo() { }
bool ProcessInfo::supported() {
return true;
}
int ProcessInfo::getVirtualMemorySize() {
ProcPsinfo p;
return static_cast(p.psinfo.pr_size / 1024);
}
int ProcessInfo::getResidentSize() {
ProcPsinfo p;
return static_cast(p.psinfo.pr_rssize / 1024);
}
void ProcessInfo::getExtraInfo(BSONObjBuilder& info) {
ProcUsage p;
info.appendNumber("page_faults", static_cast(p.prusage.pr_majf));
}
/**
* Save a BSON obj representing the host system's details
*/
void ProcessInfo::SystemInfo::collectSystemInfo() {
struct utsname unameData;
if (uname(&unameData) == -1) {
log() << "Unable to collect detailed system information: " << strerror(errno) << endl;
}
char buf_64[32];
char buf_native[32];
if (sysinfo(SI_ARCHITECTURE_64, buf_64, sizeof(buf_64)) != -1 &&
sysinfo(SI_ARCHITECTURE_NATIVE, buf_native, sizeof(buf_native)) != -1) {
addrSize = mongoutils::str::equals(buf_64, buf_native) ? 64 : 32;
}
else {
log() << "Unable to determine system architecture: " << strerror(errno) << endl;
}
osType = unameData.sysname;
osName = mongoutils::str::ltrim(readLineFromFile("/etc/release"));
osVersion = unameData.version;
pageSize = static_cast(sysconf(_SC_PAGESIZE));
memSize = pageSize * static_cast(sysconf(_SC_PHYS_PAGES));
numCores = static_cast(sysconf(_SC_NPROCESSORS_CONF));
cpuArch = unameData.machine;
hasNuma = checkNumaEnabled();
BSONObjBuilder bExtra;
bExtra.append("kernelVersion", unameData.release);
bExtra.append("pageSize", static_cast(pageSize));
bExtra.append("numPages", static_cast(sysconf(_SC_PHYS_PAGES)));
bExtra.append("maxOpenFiles", static_cast(sysconf(_SC_OPEN_MAX)));
_extraStats = bExtra.obj();
}
bool ProcessInfo::checkNumaEnabled() {
return false;
}
bool ProcessInfo::blockCheckSupported() {
return true;
}
bool ProcessInfo::blockInMemory(const void* start) {
char x = 0;
if (mincore(static_cast(const_cast(alignToStartOfPage(start))),
getPageSize(),
&x)) {
log() << "mincore failed: " << errnoWithDescription() << endl;
return 1;
}
return x & 0x1;
}
bool ProcessInfo::pagesInMemory(const void* start, size_t numPages, std::vector* out) {
out->resize(numPages);
if (mincore(static_cast(const_cast(alignToStartOfPage(start))),
numPages * getPageSize(),
&out->front())) {
log() << "mincore failed: " << errnoWithDescription() << endl;
return false;
}
for (size_t i = 0; i < numPages; ++i) {
(*out)[i] &= 0x1;
}
return true;
}
}