1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
|
#include "util/usage.hh"
#include "util/exception.hh"
#include <fstream>
#include <ostream>
#include <sstream>
#include <set>
#include <string>
#include <string.h>
#include <ctype.h>
#if !defined(_WIN32) && !defined(_WIN64)
#include <sys/resource.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
#endif
namespace util {
#if !defined(_WIN32) && !defined(_WIN64)
namespace {
float FloatSec(const struct timeval &tv) {
return static_cast<float>(tv.tv_sec) + (static_cast<float>(tv.tv_usec) / 1000000.0);
}
float FloatSec(const struct timespec &tv) {
return static_cast<float>(tv.tv_sec) + (static_cast<float>(tv.tv_nsec) / 1000000000.0);
}
const char *SkipSpaces(const char *at) {
for (; *at == ' ' || *at == '\t'; ++at) {}
return at;
}
class RecordStart {
public:
RecordStart() {
clock_gettime(CLOCK_MONOTONIC, &started_);
}
const struct timespec &Started() const {
return started_;
}
private:
struct timespec started_;
};
const RecordStart kRecordStart;
} // namespace
#endif
void PrintUsage(std::ostream &out) {
#if !defined(_WIN32) && !defined(_WIN64)
// Linux doesn't set memory usage in getrusage :-(
std::set<std::string> headers;
headers.insert("VmPeak:");
headers.insert("VmRSS:");
headers.insert("Name:");
std::ifstream status("/proc/self/status", std::ios::in);
std::string header, value;
while ((status >> header) && getline(status, value)) {
if (headers.find(header) != headers.end()) {
out << header << SkipSpaces(value.c_str()) << '\t';
}
}
struct rusage usage;
if (getrusage(RUSAGE_CHILDREN, &usage)) {
perror("getrusage");
return;
}
out << "RSSMax:" << usage.ru_maxrss << " kB" << '\t';
out << "user:" << FloatSec(usage.ru_utime) << "\tsys:" << FloatSec(usage.ru_stime) << '\t';
out << "CPU:" << (FloatSec(usage.ru_utime) + FloatSec(usage.ru_stime));
struct timespec current;
clock_gettime(CLOCK_MONOTONIC, ¤t);
out << "\treal:" << (FloatSec(current) - FloatSec(kRecordStart.Started())) << '\n';
#endif
}
uint64_t GuessPhysicalMemory() {
#if defined(_WIN32) || defined(_WIN64)
return 0;
#elif defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE)
long pages = sysconf(_SC_PHYS_PAGES);
if (pages == -1) return 0;
long page_size = sysconf(_SC_PAGESIZE);
if (page_size == -1) return 0;
return static_cast<uint64_t>(pages) * static_cast<uint64_t>(page_size);
#else
return 0;
#endif
}
namespace {
class SizeParseError : public Exception {
public:
explicit SizeParseError(const std::string &str) throw() {
*this << "Failed to parse " << str << " into a memory size ";
}
};
template <class Num> uint64_t ParseNum(const std::string &arg) {
std::stringstream stream(arg);
Num value;
stream >> value;
UTIL_THROW_IF_ARG(!stream, SizeParseError, (arg), "for the leading number.");
std::string after;
stream >> after;
UTIL_THROW_IF_ARG(after.size() > 1, SizeParseError, (arg), "because there are more than two characters after the number.");
std::string throwaway;
UTIL_THROW_IF_ARG(stream >> throwaway, SizeParseError, (arg), "because there was more cruft " << throwaway << " after the number.");
// Silly sort, using kilobytes as your default unit.
if (after.empty()) after = "K";
if (after == "%") {
uint64_t mem = GuessPhysicalMemory();
UTIL_THROW_IF_ARG(!mem, SizeParseError, (arg), "because % was specified but the physical memory size could not be determined.");
return static_cast<double>(value) * static_cast<double>(mem) / 100.0;
}
std::string units("bKMGTPEZY");
std::string::size_type index = units.find(after[0]);
UTIL_THROW_IF_ARG(index == std::string::npos, SizeParseError, (arg), "the allowed suffixes are " << units << "%.");
for (std::string::size_type i = 0; i < index; ++i) {
value *= 1024;
}
return value;
}
} // namespace
uint64_t ParseSize(const std::string &arg) {
return arg.find('.') == std::string::npos ? ParseNum<double>(arg) : ParseNum<uint64_t>(arg);
}
} // namespace util
|