9 static const char rcsid[] __attribute__((used)) =
"$Id: Process.cpp 1653 2016-02-28 19:54:59Z sella $";
12 #include "CommonMacro.h"
27 #include <sys/times.h>
29 #include <sys/prctl.h>
30 #include <sys/types.h>
31 #include <sys/syscall.h>
32 #include <sys/sysinfo.h>
33 #include <sys/resource.h>
41 #define CPU_COUNT_CXX11
43 using namespace sella::util;
45 Process::Process() throw (ProcessException) {
46 struct tms timeSample;
51 ncpu = getProcessorCount();
52 jiffies = ::sysconf(_SC_CLK_TCK);
54 prev = last = Time::clock_monotonic_coarse();
56 lastCPU = times(&timeSample);
57 lastSysCPU = timeSample.tms_stime;
58 lastUserCPU = timeSample.tms_utime;
66 void Process::update(
void) throw (ProcessException) {
67 if (sysinfo(&info) == -1) {
68 memset(&info, 0,
sizeof(info));
70 THROW2(ProcessException,
"sysinfo");
90 uint64_t Process::getUpdateIntervalUsec(
void)
const throw () {
91 struct timespec dst = last;
93 return Time::tstousec(Time::subtractts(dst, prev));
96 uint64_t Process::getUpdateIntervalSec(
void)
const throw () {
97 struct timespec dst = last;
99 return Time::tstosec(Time::subtractts(dst, prev));
102 uint64_t Process::getStartTime(
void)
const throw () {
103 return getStartTime(getPID());
106 uint64_t Process::getUptime(
void)
const throw () {
107 return time(NULL) - getStartTime(getPID());
110 int Process::getCPU(
bool scale)
const throw () {
118 int Process::getUserCPU(
bool scale)
const throw () {
120 return (userCPU / ncpu);
126 int Process::getSystemCPU(
bool scale)
const throw () {
128 return (sysCPU / ncpu);
134 int Process::getMemory(
void)
const throw () {
135 return (getRSS() / getSystemMemory());
138 char Process::getState(
void)
const throw () {
142 uint64_t Process::getFDs(
void)
const throw () {
146 uint64_t Process::getFDSize(
void)
const throw () {
150 uint64_t Process::getVMPeak(
void)
const throw () {
154 uint64_t Process::getVMSize(
void)
const throw () {
158 uint64_t Process::getLocked(
void)
const throw () {
162 uint64_t Process::getRSSHighWaterMark(
void)
const throw () {
166 uint64_t Process::getRSS(
void)
const throw () {
170 uint64_t Process::getData(
void)
const throw () {
174 uint64_t Process::getStack(
void)
const throw () {
178 uint64_t Process::getEXE(
void)
const throw () {
182 uint64_t Process::getLib(
void)
const throw () {
186 uint64_t Process::getPTE(
void)
const throw () {
190 uint64_t Process::getSwap(
void)
const throw () {
194 uint64_t Process::getThreads(
void)
const throw () {
198 uint64_t Process::getVoluntaryContextSwitch(
void)
const throw () {
202 uint64_t Process::getNonVoluntaryContextSwitch(
void)
const throw () {
206 uint64_t Process::getBytesRead(
void)
const throw () {
210 uint64_t Process::getBytesWrite(
void)
const throw () {
214 uint64_t Process::getReadSyscall(
void)
const throw () {
218 uint64_t Process::getWriteSyscall(
void)
const throw () {
222 uint64_t Process::getBytesReadStorage(
void)
const throw () {
226 uint64_t Process::getBytesWriteStorage(
void)
const throw () {
230 int64_t Process::getCancelledBytesWrite(
void)
const throw () {
234 uint64_t Process::getBlockIOWait(
void)
const throw () {
235 return getBlockIOWait(getPID());
238 int Process::getClockTicks(
void)
const throw () {
242 int Process::getProcessorCount(
void)
const throw () {
243 #ifdef CPU_COUNT_CXX11
246 if ((ncpu = std::thread::hardware_concurrency()) < 0) {
247 ncpu = sysconf(_SC_NPROCESSORS_ONLN);
256 if ((file = fopen(
"/proc/cpuinfo",
"r")) != NULL) {
259 while (fgets(line,
sizeof(line), file) != NULL) {
260 if (strncmp(line,
"processor", 9) == 0) {
270 THROW(ProcessException,
"failed to open /proc/self/status");
274 uint64_t Process::getSystemUptime(
void)
const throw () {
278 uint64_t Process::getSystemLoadAverage(
int min)
const throw () {
280 return info.loads[0];
281 }
else if (min == 5) {
282 return info.loads[1];
283 }
else if (min == 15) {
284 return info.loads[2];
290 uint64_t Process::getSystemMemory(
void)
const throw () {
291 return info.totalram;
294 uint64_t Process::getSystemFree(
void)
const throw () {
298 uint64_t Process::getSystemShared(
void)
const throw () {
299 return info.sharedram;
302 uint64_t Process::getSystemBuffer(
void)
const throw () {
303 return info.bufferram;
306 uint64_t Process::getSystemSwap(
void)
const throw () {
307 return info.totalswap;
310 uint64_t Process::getSystemProcesses(
void)
const throw () {
314 uint64_t Process::getSystemTotalHigh(
void)
const throw () {
315 return info.totalhigh;
318 uint64_t Process::getSystemFreeHigh(
void)
const throw () {
319 return info.freehigh;
322 uint64_t Process::getSystemMemUnitSize(
void)
const throw () {
323 return info.mem_unit;
326 std::string Process::getBaseName(
void) throw () {
327 std::string path = getPath();
333 return path.substr(path.rfind(
'/') + 1);
336 std::string Process::getDirName(
void) throw () {
337 std::string path = getPath();
343 return path.substr(0, path.rfind(
'/'));
346 std::string Process::getPath(
void) throw () {
348 char *buf = (
char*) malloc(PATH_MAX);
351 memset(buf, 0, PATH_MAX);
353 if (readlink(
"/proc/self/exe", buf, PATH_MAX - 1) != -1) {
363 void Process::setName(
const std::string &name)
throw (ProcessException) {
365 char buf[16] = { 0 };
367 memset(buf, 0,
sizeof(buf));
368 strncpy(buf, name.c_str(),
sizeof(buf) - 1);
370 if (prctl(PR_SET_NAME, (
unsigned long) buf, 0, 0, 0) != 0) {
371 THROW2(ProcessException,
"prctl");
376 std::string Process::getName(
void) throw (ProcessException) {
377 char buf[16] = { 0 };
380 memset(buf, 0,
sizeof(buf));
382 if (prctl(PR_GET_NAME, (
unsigned long) buf, 0, 0, 0) != 0) {
383 THROW2(ProcessException,
"prctl");
387 return std::string(buf);
390 void Process::setThreadName(pthread_t tid,
const std::string &name)
throw (ProcessException) {
391 char buf[16] = { 0 };
393 memset(buf, 0,
sizeof(buf));
394 strncpy(buf, name.c_str(),
sizeof(buf) - 1);
396 if (pthread_setname_np(tid, buf) != 0) {
397 THROW2(ProcessException,
"pthread_setname_np");
401 std::string Process::getThreadName(pthread_t tid)
throw (ProcessException) {
402 char buf[16] = { 0 };
404 memset(buf, 0,
sizeof(buf));
406 if (pthread_getname_np(tid, buf,
sizeof(buf)) != 0) {
407 THROW2(ProcessException,
"pthread_getname_np");
410 return std::string(buf);
413 void Process::setTitle(
const std::string &title)
throw (ProcessException) {
414 Process::setName(title);
417 pid_t Process::getPID(
void) throw () {
421 pid_t Process::getParentPID(
void) throw () {
425 bool Process::isRunning(pid_t pid)
throw () {
426 return (::kill(pid, 0) == 0);
429 uint64_t Process::getStartTime(pid_t pid)
throw (ProcessException) {
432 char buf[8192] = { 0 };
440 ::snprintf(buf,
sizeof(buf),
"/proc/%lu/stat", static_cast<uint64_t>(pid));
442 if ((fd = ::open(buf, O_RDONLY)) > 0) {
443 if ((len = ::read(fd, buf,
sizeof(buf))) > 0) {
446 for (
char *c = buf; c < &(buf[len]); c++) {
450 if ((n == 21) && (::gettimeofday(&(tv), NULL) == 0) && (::sysinfo(&(info)) == 0)) {
451 return (tv.tv_sec - info.uptime + (::strtol(c + 1, NULL, 10) / sysconf(_SC_CLK_TCK)));
458 THROW(ProcessException,
"failed to read /proc/%lu/stat", pid);
462 THROW(ProcessException,
"failed to open /proc/%lu/stat", pid);
465 uint64_t Process::getBlockIOWait(pid_t pid)
throw (ProcessException) {
468 char buf[8192] = { 0 };
473 ::snprintf(buf,
sizeof(buf),
"/proc/%lu/stat", static_cast<uint64_t>(pid));
475 if ((fd = ::open(buf, O_RDONLY)) > 0) {
476 if ((len = ::read(fd, buf,
sizeof(buf))) > 0) {
479 for (
char *c = buf; c < &(buf[len]); c++) {
484 return ((std::stoull(c + 1, NULL, 10) * 1000L) / sysconf(_SC_CLK_TCK));
491 THROW(ProcessException,
"failed to read /proc/%lu/stat", pid);
495 THROW(ProcessException,
"failed to open /proc/%lu/stat", pid);
498 std::string Process::runCommand(
const std::string &command)
throw (ProcessException) {
502 if ((fp = popen(command.c_str(),
"r"))) {
503 char buf[4096] = { 0 };
505 while (fgets(buf,
sizeof(buf) - 1, fp)) {
511 THROW2(ProcessException,
"popen");
517 std::string Process::stackTrace(
const std::string &executableFilename)
throw () {
518 size_t maxFrames = 63;
519 void *frames[maxFrames + 1];
520 int size = backtrace(frames,
sizeof(frames) /
sizeof(frames[0]));
521 char **symbols = backtrace_symbols(frames, size);
524 size_t funcnamesize = 256;
525 char* funcname = (
char*) malloc(funcnamesize);
527 for (
int i = 1; i < size; i++) {
528 char *begin_name = 0, *begin_offset = 0, *end_offset = 0, *begin_address = 0, *end_address = 0;
530 for (
char *p = symbols[i]; *p; ++p) {
533 }
else if (*p ==
'+') {
535 }
else if (*p ==
')') {
537 }
else if (*p ==
'[' && end_offset) {
539 }
else if (*p ==
'[') {
541 begin_offset = p - 3;
542 }
else if (*p ==
']' && begin_address) {
549 if (begin_name && begin_offset && end_offset && begin_address && end_address && begin_name < begin_offset) {
550 *begin_name++ =
'\0';
551 *begin_offset++ =
'\0';
553 *begin_address++ =
'\0';
556 void *ptr = (
void*) strtol(begin_address + 2, NULL, 16);
558 std::string command = String::sprintf(
"/usr/bin/addr2line -i -s -e %s %s 2> /dev/null", executableFilename.c_str(), begin_address);
559 std::vector<std::string> matches;
561 if ((fp = popen(command.c_str(),
"r"))) {
562 char buf[1024] = { 0 };
564 while (fgets(buf,
sizeof(buf) - 1, fp)) { }
565 String::regex_match(buf,
"^([^:]+):([1-9][0-9]*).*?$", matches);
572 char* ret = abi::__cxa_demangle(begin_name, funcname, &funcnamesize, &status);
580 if (matches.empty()) {
581 stack += String::sprintf(
"#%-2d %012p in %s from %s\n", i, ptr, funcname, symbols[i]);
583 stack += String::sprintf(
"#%-2d %012p in %s at %s:%s\n", i, ptr, funcname, matches[1].c_str(), matches[2].c_str());
586 if (matches.empty()) {
587 stack += String::sprintf(
"#%-2d %012p in %s() from %s\n", i, ptr, begin_name, symbols[i]);
589 stack += String::sprintf(
"#%-2d %012p in %s() at %s:%s\n", i, ptr, begin_name, matches[1].c_str(), matches[2].c_str());
592 }
else if (begin_name && begin_address && end_address) {
593 *begin_name++ =
'\0';
594 *begin_address++ =
'\0';
597 void *ptr = (
void*) strtol(begin_address + 2, NULL, 16);
599 stack += String::sprintf(
"#%-2d %012p in \?\?() from %s\n", i, ptr, symbols[i]);
601 stack += String::sprintf(
"#%-2d %012p in %s\n", i, 0, symbols[i]);
605 stack.erase(stack.size() - 1);
613 void Process::setNice(
int niceness,
int which,
int who)
throw (ProcessException) {
614 if (::setpriority(which, who, niceness) != 0) {
615 THROW2(ProcessException,
"setpriority");
619 int Process::getNice(
int which,
int who)
throw (ProcessException) {
621 int r = ::getpriority(which, who);
623 if (r == -1 && errno != 0) {
624 THROW2(ProcessException,
"getpriority");
630 void Process::setIONice(
int ioclass,
int level,
int which,
int who)
throw (ProcessException) {
631 if (::syscall(SYS_ioprio_set, which, who, IOPRIO_PRIO_VALUE(ioclass, level)) == -1) {
632 THROW2(ProcessException,
"ioprio_set");
636 int Process::getIONice(
int &ioclass,
int &level,
int which,
int who)
throw (ProcessException) {
639 if ((ioprio = ::syscall(SYS_ioprio_get, which, who)) == -1) {
640 THROW2(ProcessException,
"ioprio_get");
643 ioclass = IOPRIO_PRIO_CLASS(ioprio);
644 level = IOPRIO_PRIO_DATA(ioprio);
649 void Process::updateCPU(
void) throw () {
650 struct tms timeSample;
655 last = Time::clock_monotonic_coarse();
656 now = times(&timeSample);
658 if (now <= lastCPU || timeSample.tms_stime < lastSysCPU || timeSample.tms_utime < lastUserCPU) {
663 percent = (timeSample.tms_stime - lastSysCPU) + (timeSample.tms_utime - lastUserCPU);
664 percent /= (now - lastCPU);
669 percent = (timeSample.tms_utime - lastUserCPU);
670 percent /= (now - lastCPU);
675 percent = (timeSample.tms_stime - lastSysCPU);
676 percent /= (now - lastCPU);
683 lastSysCPU = timeSample.tms_stime;
684 lastUserCPU = timeSample.tms_utime;
687 void Process::updateFDs(
void) throw (ProcessException) {
692 if ((dir = opendir(
"/proc/self/fd")) == NULL) {
693 THROW(ProcessException,
"failed to open /proc/self/fd");
696 while ((dp = readdir(dir)) != NULL) {
705 void Process::updateStats(
void) throw (ProcessException) {
708 char buf[8192] = { 0 };
710 if ((fd = ::open(
"/proc/self/status", O_RDONLY)) > 0) {
711 if ((len = ::read(fd, buf,
sizeof(buf))) > 0) {
714 std::vector<std::string> v = String::regex_split(buf,
"(?::\\s+|\n)");
716 for (
size_t i = 0, len = v.size(); i < len; i += 2) {
717 if (v[i] == std::string(
"State")) {
718 stats[0] = v[i + 1].substr(0, 1)[0];
719 }
else if (v[i] == std::string(
"FDSize")) {
720 stats[1] = std::stoull(v[i + 1]);
721 }
else if (v[i] == std::string(
"VmPeak")) {
722 stats[2] = String::dataSize(v[i + 1]);
723 }
else if (v[i] == std::string(
"VmSize")) {
724 stats[3] = String::dataSize(v[i + 1]);
725 }
else if (v[i] == std::string(
"VmLck")) {
726 stats[4] = String::dataSize(v[i + 1]);
727 }
else if (v[i] == std::string(
"VmHWM")) {
728 stats[5] = String::dataSize(v[i + 1]);
729 }
else if (v[i] == std::string(
"VmRSS")) {
730 stats[6] = String::dataSize(v[i + 1]);
731 }
else if (v[i] == std::string(
"VmData")) {
732 stats[7] = String::dataSize(v[i + 1]);
733 }
else if (v[i] == std::string(
"VmStk")) {
734 stats[8] = String::dataSize(v[i + 1]);
735 }
else if (v[i] == std::string(
"VmExe")) {
736 stats[9] = String::dataSize(v[i + 1]);
737 }
else if (v[i] == std::string(
"VmLib")) {
738 stats[10] = String::dataSize(v[i + 1]);
739 }
else if (v[i] == std::string(
"VmPTE")) {
740 stats[11] = String::dataSize(v[i + 1]);
741 }
else if (v[i] == std::string(
"VmSwap")) {
742 stats[12] = String::dataSize(v[i + 1]);
743 }
else if (v[i] == std::string(
"Threads")) {
744 stats[13] = std::stoull(v[i + 1]);
745 }
else if (v[i] == std::string(
"voluntary_ctxt_switches")) {
746 stats[14] = std::stoull(v[i + 1]);
747 }
else if (v[i] == std::string(
"nonvoluntary_ctxt_switches")) {
748 stats[15] = std::stoull(v[i + 1]);
754 THROW(ProcessException,
"failed to read /proc/self/status");
760 THROW(ProcessException,
"failed to open /proc/self/status");
763 void Process::updateIOStats(
void) throw (ProcessException) {
766 char buf[8192] = { 0 };
768 if ((fd = ::open(
"/proc/self/io", O_RDONLY)) > 0) {
769 if ((len = ::read(fd, buf,
sizeof(buf))) > 0) {
772 std::vector<std::string> v = String::regex_split(buf,
"(?::\\s+|\n)");
774 for (
size_t i = 0, len = v.size(); i < len; i += 2) {
775 if (v[i] == std::string(
"rchar")) {
776 iostats[0] = std::stoull(v[i + 1]);
777 }
else if (v[i] == std::string(
"wchar")) {
778 iostats[1] = std::stoull(v[i + 1]);
779 }
else if (v[i] == std::string(
"syscr")) {
780 iostats[2] = std::stoull(v[i + 1]);
781 }
else if (v[i] == std::string(
"syscw")) {
782 iostats[3] = std::stoull(v[i + 1]);
783 }
else if (v[i] == std::string(
"read_bytes")) {
784 iostats[4] = std::stoull(v[i + 1]);
785 }
else if (v[i] == std::string(
"write_bytes")) {
786 iostats[5] = std::stoull(v[i + 1]);
787 }
else if (v[i] == std::string(
"cancelled_write_bytes")) {
788 iostats[6] = std::stoull(v[i + 1]);
794 THROW(ProcessException,
"failed to read /proc/self/io");
800 THROW(ProcessException,
"failed to open /proc/self/io");