00001 #include "util/usage.hh"
00002
00003 #include "util/exception.hh"
00004
00005 #include <fstream>
00006 #include <ostream>
00007 #include <sstream>
00008 #include <set>
00009 #include <string>
00010 #include <cstring>
00011 #include <cctype>
00012 #include <ctime>
00013 #if defined(_WIN32) || defined(_WIN64)
00014
00015
00016 # define WIN32_LEAN_AND_MEAN
00017 # include <windows.h>
00018
00019
00020 typedef struct
00021 {
00022 DWORD dwLength;
00023 DWORD dwMemoryLoad;
00024 DWORDLONG ullTotalPhys;
00025 DWORDLONG ullAvailPhys;
00026 DWORDLONG ullTotalPageFile;
00027 DWORDLONG ullAvailPageFile;
00028 DWORDLONG ullTotalVirtual;
00029 DWORDLONG ullAvailVirtual;
00030 DWORDLONG ullAvailExtendedVirtual;
00031 } lMEMORYSTATUSEX;
00032
00033 typedef int WINBOOL;
00034 typedef WINBOOL (WINAPI *PFN_MS_EX) (lMEMORYSTATUSEX*);
00035 #else
00036 #include <sys/resource.h>
00037 #include <sys/time.h>
00038 #include <unistd.h>
00039 #endif
00040
00041 #if defined(__MACH__) || defined(__FreeBSD__) || defined(__APPLE__)
00042 #include <sys/types.h>
00043 #include <sys/sysctl.h>
00044 #endif
00045
00046 namespace util {
00047 namespace {
00048
00049 #if defined(__MACH__)
00050 typedef struct timeval Wall;
00051 Wall GetWall() {
00052 struct timeval tv;
00053 gettimeofday(&tv, NULL);
00054 return tv;
00055 }
00056 #elif defined(_WIN32) || defined(_WIN64)
00057 typedef time_t Wall;
00058 Wall GetWall() {
00059 return time(NULL);
00060 }
00061 #else
00062 typedef struct timespec Wall;
00063 Wall GetWall() {
00064 Wall ret;
00065 clock_gettime(CLOCK_MONOTONIC, &ret);
00066 return ret;
00067 }
00068 #endif
00069
00070
00071 #ifdef __GNUC__
00072 double Subtract(time_t first, time_t second) __attribute__ ((unused));
00073 double DoubleSec(time_t tv) __attribute__ ((unused));
00074 #if !defined(_WIN32) && !defined(_WIN64)
00075 double Subtract(const struct timeval &first, const struct timeval &second) __attribute__ ((unused));
00076 double Subtract(const struct timespec &first, const struct timespec &second) __attribute__ ((unused));
00077 double DoubleSec(const struct timeval &tv) __attribute__ ((unused));
00078 double DoubleSec(const struct timespec &tv) __attribute__ ((unused));
00079 #endif
00080 #endif
00081
00082
00083 #ifdef __clang__
00084 #pragma clang diagnostic push
00085 #pragma clang diagnostic ignored "-Wunused-function"
00086 #endif
00087
00088 double Subtract(time_t first, time_t second) {
00089 return difftime(first, second);
00090 }
00091 double DoubleSec(time_t tv) {
00092 return static_cast<double>(tv);
00093 }
00094 #if !defined(_WIN32) && !defined(_WIN64)
00095 double Subtract(const struct timeval &first, const struct timeval &second) {
00096 return static_cast<double>(first.tv_sec - second.tv_sec) + static_cast<double>(first.tv_usec - second.tv_usec) / 1000000.0;
00097 }
00098 double Subtract(const struct timespec &first, const struct timespec &second) {
00099 return static_cast<double>(first.tv_sec - second.tv_sec) + static_cast<double>(first.tv_nsec - second.tv_nsec) / 1000000000.0;
00100 }
00101 double DoubleSec(const struct timeval &tv) {
00102 return static_cast<double>(tv.tv_sec) + (static_cast<double>(tv.tv_usec) / 1000000.0);
00103 }
00104 double DoubleSec(const struct timespec &tv) {
00105 return static_cast<double>(tv.tv_sec) + (static_cast<double>(tv.tv_nsec) / 1000000000.0);
00106 }
00107 #endif
00108 #ifdef __clang__
00109 #pragma clang diagnostic pop
00110 #endif
00111
00112 class RecordStart {
00113 public:
00114 RecordStart() {
00115 started_ = GetWall();
00116 }
00117
00118 const Wall &Started() const {
00119 return started_;
00120 }
00121
00122 private:
00123 Wall started_;
00124 };
00125
00126 const RecordStart kRecordStart;
00127
00128 const char *SkipSpaces(const char *at) {
00129 for (; *at == ' ' || *at == '\t'; ++at) {}
00130 return at;
00131 }
00132 }
00133
00134 double WallTime() {
00135 return Subtract(GetWall(), kRecordStart.Started());
00136 }
00137
00138 double CPUTime() {
00139 #if defined(_WIN32) || defined(_WIN64)
00140 return 0.0;
00141 #else
00142 struct rusage usage;
00143 if (getrusage(RUSAGE_SELF, &usage))
00144 return 0.0;
00145 return DoubleSec(usage.ru_utime) + DoubleSec(usage.ru_stime);
00146 #endif
00147 }
00148
00149 uint64_t RSSMax() {
00150 #if defined(_WIN32) || defined(_WIN64)
00151 return 0;
00152 #else
00153 struct rusage usage;
00154 if (getrusage(RUSAGE_SELF, &usage))
00155 return 0;
00156 return static_cast<uint64_t>(usage.ru_maxrss) * 1024;
00157 #endif
00158 }
00159
00160 void PrintUsage(std::ostream &out) {
00161 #if !defined(_WIN32) && !defined(_WIN64)
00162
00163 std::set<std::string> headers;
00164 headers.insert("VmPeak:");
00165 headers.insert("VmRSS:");
00166 headers.insert("Name:");
00167
00168 std::ifstream status("/proc/self/status", std::ios::in);
00169 std::string header, value;
00170 while ((status >> header) && getline(status, value)) {
00171 if (headers.find(header) != headers.end()) {
00172 out << header << SkipSpaces(value.c_str()) << '\t';
00173 }
00174 }
00175
00176 struct rusage usage;
00177 if (getrusage(RUSAGE_SELF, &usage)) {
00178 perror("getrusage");
00179 return;
00180 }
00181 out << "RSSMax:" << usage.ru_maxrss << " kB" << '\t';
00182 out << "user:" << DoubleSec(usage.ru_utime) << "\tsys:" << DoubleSec(usage.ru_stime) << '\t';
00183 out << "CPU:" << (DoubleSec(usage.ru_utime) + DoubleSec(usage.ru_stime));
00184 out << '\t';
00185 #endif
00186
00187 out << "real:" << WallTime() << '\n';
00188 }
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210 uint64_t GuessPhysicalMemory() {
00211 #if defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE)
00212 {
00213 long pages = sysconf(_SC_PHYS_PAGES);
00214 long page_size = sysconf(_SC_PAGESIZE);
00215 if (pages != -1 && page_size != -1)
00216 return static_cast<uint64_t>(pages) * static_cast<uint64_t>(page_size);
00217 }
00218 #endif
00219 #ifdef HW_PHYSMEM
00220 {
00221 unsigned int physmem;
00222 size_t len = sizeof physmem;
00223 static int mib[2] = { CTL_HW, HW_PHYSMEM };
00224
00225 if (sysctl (mib, sizeof(mib) / sizeof(mib[0]), &physmem, &len, NULL, 0) == 0
00226 && len == sizeof (physmem))
00227 return static_cast<uint64_t>(physmem);
00228 }
00229 #endif
00230
00231 #if defined(_WIN32) || defined(_WIN64)
00232 {
00233 PFN_MS_EX pfnex;
00234 HMODULE h = GetModuleHandle (TEXT("kernel32.dll"));
00235
00236 if (!h)
00237 return 0;
00238
00239
00240 if ((pfnex = (PFN_MS_EX) GetProcAddress (h, "GlobalMemoryStatusEx")))
00241 {
00242 lMEMORYSTATUSEX lms_ex;
00243 lms_ex.dwLength = sizeof lms_ex;
00244 if (!pfnex (&lms_ex))
00245 return 0;
00246 return lms_ex.ullTotalPhys;
00247 }
00248
00249
00250
00251 else
00252 {
00253 MEMORYSTATUS ms;
00254 GlobalMemoryStatus (&ms);
00255 return ms.dwTotalPhys;
00256 }
00257 }
00258 #endif
00259 return 0;
00260 }
00261
00262 namespace {
00263 class SizeParseError : public Exception {
00264 public:
00265 explicit SizeParseError(const std::string &str) throw() {
00266 *this << "Failed to parse " << str << " into a memory size ";
00267 }
00268 };
00269
00270 template <class Num> uint64_t ParseNum(const std::string &arg) {
00271 std::stringstream stream(arg);
00272 Num value;
00273 stream >> value;
00274 UTIL_THROW_IF_ARG(!stream, SizeParseError, (arg), "for the leading number.");
00275 std::string after;
00276 stream >> after;
00277 UTIL_THROW_IF_ARG(after.size() > 1, SizeParseError, (arg), "because there are more than two characters after the number.");
00278 std::string throwaway;
00279 UTIL_THROW_IF_ARG(stream >> throwaway, SizeParseError, (arg), "because there was more cruft " << throwaway << " after the number.");
00280
00281
00282 if (after.empty()) after = "K";
00283 if (after == "%") {
00284 uint64_t mem = GuessPhysicalMemory();
00285 UTIL_THROW_IF_ARG(!mem, SizeParseError, (arg), "because % was specified but the physical memory size could not be determined.");
00286 return static_cast<uint64_t>(static_cast<double>(value) * static_cast<double>(mem) / 100.0);
00287 }
00288
00289 if (after == "k") after = "K";
00290 std::string units("bKMGTPEZY");
00291 std::string::size_type index = units.find(after[0]);
00292 UTIL_THROW_IF_ARG(index == std::string::npos, SizeParseError, (arg), "the allowed suffixes are " << units << "%.");
00293 for (std::string::size_type i = 0; i < index; ++i) {
00294 value *= 1024;
00295 }
00296 return static_cast<uint64_t>(value);
00297 }
00298
00299 }
00300
00301 uint64_t ParseSize(const std::string &arg) {
00302 return arg.find('.') == std::string::npos ? ParseNum<double>(arg) : ParseNum<uint64_t>(arg);
00303 }
00304
00305 }