proc_stats.cc
1 // Copyright 2013, Beeri 15. All rights reserved.
2 // Author: Roman Gershman (romange@gmail.com)
3 //
4 #include "util/proc_stats.h"
5 
6 #include <mutex>
7 #include "base/walltime.h"
8 #include "strings/stringpiece.h"
9 #include "strings/numbers.h"
10 #include "strings/strip.h"
11 
12 #include <unistd.h>
13 #include <time.h>
14 
15 namespace util {
16 
17 size_t find_nth(StringPiece str, char c, uint32 index) {
18  for (size_t i = 0; i < str.size(); ++i) {
19  if (str[i] == c) {
20  if (index-- == 0)
21  return i;
22  }
23  }
24  return StringPiece::npos;
25 }
26 
27 
28 static std::once_flag cpu_once;
29 
30 static int CPU_NUM = 0;
31 
32 static void InitCpuInfo() {
33  FILE* f = fopen("/proc/cpuinfo", "r");
34  const char kModelNameLine[] = "model name";
35  if (f == NULL) {
36  return;
37  }
38  char line[1000];
39  while (fgets(line, sizeof(line), f) != NULL) {
40  const char* sep = strchr(line, ':');
41  if (sep == NULL) {
42  continue;
43  }
44  StringPiece str(line, sep - line);
45  str = absl::StripAsciiWhitespace(str);
46  if (str == kModelNameLine)
47  ++CPU_NUM;
48  }
49  fclose(f);
50 }
51 
52 ProcessStats ProcessStats::Read() {
53  ProcessStats stats;
54  FILE* f = fopen("/proc/self/status", "r");
55  if (f == nullptr)
56  return stats;
57  char* line = nullptr;
58  size_t len = 128;
59  while (getline(&line, &len, f) != -1) {
60  if (!strncmp(line, "VmPeak:", 7)) stats.vm_peak = ParseLeadingUDec32Value(line + 8, 0);
61  else if (!strncmp(line, "VmSize:", 7)) stats.vm_size = ParseLeadingUDec32Value(line + 8, 0);
62  else if (!strncmp(line, "VmRSS:", 6)) stats.vm_size = ParseLeadingUDec32Value(line + 7, 0);
63  }
64  fclose(f);
65  f = fopen("/proc/self/stat", "r");
66  if (f) {
67  long jiffies_per_second = sysconf(_SC_CLK_TCK);
68  uint64 start_since_boot = 0;
69  char buf[512] = {0};
70  size_t bytes_read = fread(buf, 1, sizeof buf, f);
71  if (bytes_read == sizeof buf) {
72  fprintf(stderr, "Buffer is too small %lu\n", sizeof buf);
73  } else {
74  StringPiece str(buf, bytes_read);
75  size_t pos = find_nth(str, ' ', 20);
76  if (pos != StringPiece::npos) {
77  start_since_boot = ParseLeadingUDec64Value(str.data() + pos + 1, 0);
78  start_since_boot /= jiffies_per_second;
79  }
80  }
81  fclose(f);
82  if (start_since_boot > 0) {
83  f = fopen("/proc/stat", "r");
84  if (f) {
85  while (getline(&line, &len, f) != -1) {
86  if (!strncmp(line, "btime ", 6)) {
87  uint64 boot_time = ParseLeadingUDec64Value(line + 6, 0);
88  if (boot_time > 0)
89  stats.start_time_seconds = boot_time + start_since_boot;
90  }
91  }
92  fclose(f);
93  }
94  }
95  }
96  free(line);
97  return stats;
98 }
99 
100 namespace sys {
101 
102 unsigned int NumCPUs() {
103  std::call_once(cpu_once, InitCpuInfo);
104  return CPU_NUM;
105 }
106 
107 } // namespace sys
108 
109 } // namespace util
110 
111 std::ostream& operator<<(std::ostream& os, const util::ProcessStats& stats) {
112  os << "VmPeak: " << stats.vm_peak << "kb, VmSize: " << stats.vm_size
113  << "kb, VmRSS: " << stats.vm_rss << "kb, Start Time: "
114  << base::PrintLocalTime(stats.start_time_seconds);
115  return os;
116 }