| OLD | NEW |
| 1 // Copyright (c) 2006, Google Inc. | 1 // Copyright (c) 2006, Google Inc. |
| 2 // All rights reserved. | 2 // All rights reserved. |
| 3 // | 3 // |
| 4 // Redistribution and use in source and binary forms, with or without | 4 // Redistribution and use in source and binary forms, with or without |
| 5 // modification, are permitted provided that the following conditions are | 5 // modification, are permitted provided that the following conditions are |
| 6 // met: | 6 // met: |
| 7 // | 7 // |
| 8 // * Redistributions of source code must retain the above copyright | 8 // * Redistributions of source code must retain the above copyright |
| 9 // notice, this list of conditions and the following disclaimer. | 9 // notice, this list of conditions and the following disclaimer. |
| 10 // * Redistributions in binary form must reproduce the above | 10 // * Redistributions in binary form must reproduce the above |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 49 #include <sys/sysctl.h> | 49 #include <sys/sysctl.h> |
| 50 #elif defined __sun__ // Solaris | 50 #elif defined __sun__ // Solaris |
| 51 #include <procfs.h> // for, e.g., prmap_t | 51 #include <procfs.h> // for, e.g., prmap_t |
| 52 #elif defined(PLATFORM_WINDOWS) | 52 #elif defined(PLATFORM_WINDOWS) |
| 53 #include <process.h> // for getpid() (actually, _getpid()) | 53 #include <process.h> // for getpid() (actually, _getpid()) |
| 54 #include <shlwapi.h> // for SHGetValueA() | 54 #include <shlwapi.h> // for SHGetValueA() |
| 55 #include <tlhelp32.h> // for Module32First() | 55 #include <tlhelp32.h> // for Module32First() |
| 56 #endif | 56 #endif |
| 57 #include "base/sysinfo.h" | 57 #include "base/sysinfo.h" |
| 58 #include "base/commandlineflags.h" | 58 #include "base/commandlineflags.h" |
| 59 #include "base/dynamic_annotations.h" // for RunningOnValgrind |
| 59 #include "base/logging.h" | 60 #include "base/logging.h" |
| 60 #include "base/cycleclock.h" | 61 #include "base/cycleclock.h" |
| 61 | 62 |
| 62 #ifdef PLATFORM_WINDOWS | 63 #ifdef PLATFORM_WINDOWS |
| 63 #ifdef MODULEENTRY32 | 64 #ifdef MODULEENTRY32 |
| 64 // In a change from the usual W-A pattern, there is no A variant of | 65 // In a change from the usual W-A pattern, there is no A variant of |
| 65 // MODULEENTRY32. Tlhelp32.h #defines the W variant, but not the A. | 66 // MODULEENTRY32. Tlhelp32.h #defines the W variant, but not the A. |
| 66 // In unicode mode, tlhelp32.h #defines MODULEENTRY32 to be | 67 // In unicode mode, tlhelp32.h #defines MODULEENTRY32 to be |
| 67 // MODULEENTRY32W. These #undefs are the only way I see to get back | 68 // MODULEENTRY32W. These #undefs are the only way I see to get back |
| 68 // access to the original, ascii struct (and related functions). | 69 // access to the original, ascii struct (and related functions). |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 103 // It's not safe to call getenv() in the malloc hooks, because they | 104 // It's not safe to call getenv() in the malloc hooks, because they |
| 104 // might be called extremely early, before libc is done setting up | 105 // might be called extremely early, before libc is done setting up |
| 105 // correctly. In particular, the thread library may not be done | 106 // correctly. In particular, the thread library may not be done |
| 106 // setting up errno. So instead, we use the built-in __environ array | 107 // setting up errno. So instead, we use the built-in __environ array |
| 107 // if it exists, and otherwise read /proc/self/environ directly, using | 108 // if it exists, and otherwise read /proc/self/environ directly, using |
| 108 // system calls to read the file, and thus avoid setting errno. | 109 // system calls to read the file, and thus avoid setting errno. |
| 109 // /proc/self/environ has a limit of how much data it exports (around | 110 // /proc/self/environ has a limit of how much data it exports (around |
| 110 // 8K), so it's not an ideal solution. | 111 // 8K), so it's not an ideal solution. |
| 111 const char* GetenvBeforeMain(const char* name) { | 112 const char* GetenvBeforeMain(const char* name) { |
| 112 #if defined(HAVE___ENVIRON) // if we have it, it's declared in unistd.h | 113 #if defined(HAVE___ENVIRON) // if we have it, it's declared in unistd.h |
| 113 const int namelen = strlen(name); | 114 if (__environ) { // can exist but be NULL, if statically linked |
| 114 for (char** p = __environ; *p; p++) { | 115 const int namelen = strlen(name); |
| 115 if (!memcmp(*p, name, namelen) && (*p)[namelen] == '=') // it's a match | 116 for (char** p = __environ; *p; p++) { |
| 116 return *p + namelen+1; // point after = | 117 if (!memcmp(*p, name, namelen) && (*p)[namelen] == '=') // it's a match |
| 118 return *p + namelen+1; // point after = |
| 119 } |
| 120 return NULL; |
| 117 } | 121 } |
| 118 return NULL; | 122 #endif |
| 119 #elif defined(PLATFORM_WINDOWS) | 123 #if defined(PLATFORM_WINDOWS) |
| 120 // TODO(mbelshe) - repeated calls to this function will overwrite the | 124 // TODO(mbelshe) - repeated calls to this function will overwrite the |
| 121 // contents of the static buffer. | 125 // contents of the static buffer. |
| 122 static char envbuf[1024]; // enough to hold any envvar we care about | 126 static char envvar_buf[1024]; // enough to hold any envvar we care about |
| 123 if (!GetEnvironmentVariableA(name, envbuf, sizeof(envbuf)-1)) | 127 if (!GetEnvironmentVariableA(name, envvar_buf, sizeof(envvar_buf)-1)) |
| 124 return NULL; | 128 return NULL; |
| 125 return envbuf; | 129 return envvar_buf; |
| 126 #else | 130 #endif |
| 127 // static is ok because this function should only be called before | 131 // static is ok because this function should only be called before |
| 128 // main(), when we're single-threaded. | 132 // main(), when we're single-threaded. |
| 129 static char envbuf[16<<10]; | 133 static char envbuf[16<<10]; |
| 130 if (*envbuf == '\0') { // haven't read the environ yet | 134 if (*envbuf == '\0') { // haven't read the environ yet |
| 131 int fd = safeopen("/proc/self/environ", O_RDONLY); | 135 int fd = safeopen("/proc/self/environ", O_RDONLY); |
| 132 // The -2 below guarantees the last two bytes of the buffer will be \0\0 | 136 // The -2 below guarantees the last two bytes of the buffer will be \0\0 |
| 133 if (fd == -1 || // unable to open the file, fall back onto libc | 137 if (fd == -1 || // unable to open the file, fall back onto libc |
| 134 saferead(fd, envbuf, sizeof(envbuf) - 2) < 0) { // error reading file | 138 saferead(fd, envbuf, sizeof(envbuf) - 2) < 0) { // error reading file |
| 135 RAW_VLOG(1, "Unable to open /proc/self/environ, falling back " | 139 RAW_VLOG(1, "Unable to open /proc/self/environ, falling back " |
| 136 "on getenv(\"%s\"), which may not work", name); | 140 "on getenv(\"%s\"), which may not work", name); |
| 137 if (fd != -1) safeclose(fd); | 141 if (fd != -1) safeclose(fd); |
| 138 return getenv(name); | 142 return getenv(name); |
| 139 } | 143 } |
| 140 safeclose(fd); | 144 safeclose(fd); |
| 141 } | 145 } |
| 142 const int namelen = strlen(name); | 146 const int namelen = strlen(name); |
| 143 const char* p = envbuf; | 147 const char* p = envbuf; |
| 144 while (*p != '\0') { // will happen at the \0\0 that terminates the buffer | 148 while (*p != '\0') { // will happen at the \0\0 that terminates the buffer |
| 145 // proc file has the format NAME=value\0NAME=value\0NAME=value\0... | 149 // proc file has the format NAME=value\0NAME=value\0NAME=value\0... |
| 146 const char* endp = (char*)memchr(p, '\0', sizeof(envbuf) - (p - envbuf)); | 150 const char* endp = (char*)memchr(p, '\0', sizeof(envbuf) - (p - envbuf)); |
| 147 if (endp == NULL) // this entry isn't NUL terminated | 151 if (endp == NULL) // this entry isn't NUL terminated |
| 148 return NULL; | 152 return NULL; |
| 149 else if (!memcmp(p, name, namelen) && p[namelen] == '=') // it's a match | 153 else if (!memcmp(p, name, namelen) && p[namelen] == '=') // it's a match |
| 150 return p + namelen+1; // point after = | 154 return p + namelen+1; // point after = |
| 151 p = endp + 1; | 155 p = endp + 1; |
| 152 } | 156 } |
| 153 return NULL; // env var never found | 157 return NULL; // env var never found |
| 154 #endif | |
| 155 } | 158 } |
| 156 | 159 |
| 157 // This takes as an argument an environment-variable name (like | 160 // This takes as an argument an environment-variable name (like |
| 158 // CPUPROFILE) whose value is supposed to be a file-path, and sets | 161 // CPUPROFILE) whose value is supposed to be a file-path, and sets |
| 159 // path to that path, and returns true. If the env var doesn't exist, | 162 // path to that path, and returns true. If the env var doesn't exist, |
| 160 // or is the empty string, leave path unchanged and returns false. | 163 // or is the empty string, leave path unchanged and returns false. |
| 161 // The reason this is non-trivial is that this function handles munged | 164 // The reason this is non-trivial is that this function handles munged |
| 162 // pathnames. Here's why: | 165 // pathnames. Here's why: |
| 163 // | 166 // |
| 164 // If we're a child process of the 'main' process, we can't just use | 167 // If we're a child process of the 'main' process, we can't just use |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 199 // CyclesPerSecond() | 202 // CyclesPerSecond() |
| 200 // NumCPUs() | 203 // NumCPUs() |
| 201 // It's important this not call malloc! -- they may be called at | 204 // It's important this not call malloc! -- they may be called at |
| 202 // global-construct time, before we've set up all our proper malloc | 205 // global-construct time, before we've set up all our proper malloc |
| 203 // hooks and such. | 206 // hooks and such. |
| 204 // ---------------------------------------------------------------------- | 207 // ---------------------------------------------------------------------- |
| 205 | 208 |
| 206 static double cpuinfo_cycles_per_second = 1.0; // 0.0 might be dangerous | 209 static double cpuinfo_cycles_per_second = 1.0; // 0.0 might be dangerous |
| 207 static int cpuinfo_num_cpus = 1; // Conservative guess | 210 static int cpuinfo_num_cpus = 1; // Conservative guess |
| 208 | 211 |
| 209 static void SleepForMilliseconds(int milliseconds) { | 212 void SleepForMilliseconds(int milliseconds) { |
| 210 #ifdef PLATFORM_WINDOWS | 213 #ifdef PLATFORM_WINDOWS |
| 211 _sleep(milliseconds); // Windows's _sleep takes milliseconds argument | 214 _sleep(milliseconds); // Windows's _sleep takes milliseconds argument |
| 212 #else | 215 #else |
| 213 // Sleep for a few milliseconds | 216 // Sleep for a few milliseconds |
| 214 struct timespec sleep_time; | 217 struct timespec sleep_time; |
| 215 sleep_time.tv_sec = milliseconds / 1000; | 218 sleep_time.tv_sec = milliseconds / 1000; |
| 216 sleep_time.tv_nsec = (milliseconds % 1000) * 1000000; | 219 sleep_time.tv_nsec = (milliseconds % 1000) * 1000000; |
| 217 while (nanosleep(&sleep_time, &sleep_time) != 0 && errno == EINTR) | 220 while (nanosleep(&sleep_time, &sleep_time) != 0 && errno == EINTR) |
| 218 ; // Ignore signals and wait for the full interval to elapse. | 221 ; // Ignore signals and wait for the full interval to elapse. |
| 219 #endif | 222 #endif |
| 220 } | 223 } |
| 221 | 224 |
| 222 // Helper function estimates cycles/sec by observing cycles elapsed during | 225 // Helper function estimates cycles/sec by observing cycles elapsed during |
| 223 // sleep(). Using small sleep time decreases accuracy significantly. | 226 // sleep(). Using small sleep time decreases accuracy significantly. |
| 224 static int64 EstimateCyclesPerSecond(const int estimate_time_ms) { | 227 static int64 EstimateCyclesPerSecond(const int estimate_time_ms) { |
| 225 assert(estimate_time_ms > 0); | 228 assert(estimate_time_ms > 0); |
| 226 if (estimate_time_ms <= 0) | 229 if (estimate_time_ms <= 0) |
| 227 return 1; | 230 return 1; |
| 228 double multiplier = 1000.0 / (double)estimate_time_ms; // scale by this much | 231 double multiplier = 1000.0 / (double)estimate_time_ms; // scale by this much |
| 229 | 232 |
| 230 const int64 start_ticks = CycleClock::Now(); | 233 const int64 start_ticks = CycleClock::Now(); |
| 231 SleepForMilliseconds(estimate_time_ms); | 234 SleepForMilliseconds(estimate_time_ms); |
| 232 const int64 guess = int64(multiplier * (CycleClock::Now() - start_ticks)); | 235 const int64 guess = int64(multiplier * (CycleClock::Now() - start_ticks)); |
| 233 return guess; | 236 return guess; |
| 234 } | 237 } |
| 235 | 238 |
| 239 // ReadIntFromFile is only called on linux and cygwin platforms. |
| 240 #if defined(__linux__) || defined(__CYGWIN__) || defined(__CYGWIN32__) |
| 241 // Helper function for reading an int from a file. Returns true if successful |
| 242 // and the memory location pointed to by value is set to the value read. |
| 243 static bool ReadIntFromFile(const char *file, int *value) { |
| 244 bool ret = false; |
| 245 int fd = open(file, O_RDONLY); |
| 246 if (fd != -1) { |
| 247 char line[1024]; |
| 248 char* err; |
| 249 memset(line, '\0', sizeof(line)); |
| 250 read(fd, line, sizeof(line) - 1); |
| 251 const int temp_value = strtol(line, &err, 10); |
| 252 if (line[0] != '\0' && (*err == '\n' || *err == '\0')) { |
| 253 *value = temp_value; |
| 254 ret = true; |
| 255 } |
| 256 close(fd); |
| 257 } |
| 258 return ret; |
| 259 } |
| 260 #endif |
| 261 |
| 236 // WARNING: logging calls back to InitializeSystemInfo() so it must | 262 // WARNING: logging calls back to InitializeSystemInfo() so it must |
| 237 // not invoke any logging code. Also, InitializeSystemInfo() can be | 263 // not invoke any logging code. Also, InitializeSystemInfo() can be |
| 238 // called before main() -- in fact it *must* be since already_called | 264 // called before main() -- in fact it *must* be since already_called |
| 239 // isn't protected -- before malloc hooks are properly set up, so | 265 // isn't protected -- before malloc hooks are properly set up, so |
| 240 // we make an effort not to call any routines which might allocate | 266 // we make an effort not to call any routines which might allocate |
| 241 // memory. | 267 // memory. |
| 242 | 268 |
| 243 static void InitializeSystemInfo() { | 269 static void InitializeSystemInfo() { |
| 244 static bool already_called = false; // safe if we run before threads | 270 static bool already_called = false; // safe if we run before threads |
| 245 if (already_called) return; | 271 if (already_called) return; |
| 246 already_called = true; | 272 already_called = true; |
| 247 | 273 |
| 248 // I put in a never-called reference to EstimateCyclesPerSecond() here | 274 bool saw_mhz = false; |
| 249 // to silence the compiler for OS's that don't need it | 275 |
| 250 if (0) EstimateCyclesPerSecond(0); | 276 if (RunningOnValgrind()) { |
| 277 // Valgrind may slow the progress of time artificially (--scale-time=N |
| 278 // option). We thus can't rely on CPU Mhz info stored in /sys or /proc |
| 279 // files. Thus, actually measure the cps. |
| 280 cpuinfo_cycles_per_second = EstimateCyclesPerSecond(100); |
| 281 saw_mhz = true; |
| 282 } |
| 251 | 283 |
| 252 #if defined(__linux__) || defined(__CYGWIN__) || defined(__CYGWIN32__) | 284 #if defined(__linux__) || defined(__CYGWIN__) || defined(__CYGWIN32__) |
| 253 char line[1024]; | 285 char line[1024]; |
| 254 char* err; | 286 char* err; |
| 287 int freq; |
| 288 |
| 289 // If the kernel is exporting the tsc frequency use that. There are issues |
| 290 // where cpuinfo_max_freq cannot be relied on because the BIOS may be |
| 291 // exporintg an invalid p-state (on x86) or p-states may be used to put the |
| 292 // processor in a new mode (turbo mode). Essentially, those frequencies |
| 293 // cannot always be relied upon. The same reasons apply to /proc/cpuinfo as |
| 294 // well. |
| 295 if (!saw_mhz && |
| 296 ReadIntFromFile("/sys/devices/system/cpu/cpu0/tsc_freq_khz", &freq)) { |
| 297 // The value is in kHz (as the file name suggests). For example, on a |
| 298 // 2GHz warpstation, the file contains the value "2000000". |
| 299 cpuinfo_cycles_per_second = freq * 1000.0; |
| 300 saw_mhz = true; |
| 301 } |
| 255 | 302 |
| 256 // If CPU scaling is in effect, we want to use the *maximum* frequency, | 303 // If CPU scaling is in effect, we want to use the *maximum* frequency, |
| 257 // not whatever CPU speed some random processor happens to be using now. | 304 // not whatever CPU speed some random processor happens to be using now. |
| 258 bool saw_mhz = false; | 305 if (!saw_mhz && |
| 259 const char* pname0 = "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq"; | 306 ReadIntFromFile("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq", |
| 260 int fd0 = open(pname0, O_RDONLY); | 307 &freq)) { |
| 261 if (fd0 != -1) { | 308 // The value is in kHz. For example, on a 2GHz machine, the file |
| 262 memset(line, '\0', sizeof(line)); | 309 // contains the value "2000000". |
| 263 read(fd0, line, sizeof(line)); | 310 cpuinfo_cycles_per_second = freq * 1000.0; |
| 264 const int max_freq = strtol(line, &err, 10); | 311 saw_mhz = true; |
| 265 if (line[0] != '\0' && (*err == '\n' || *err == '\0')) { | |
| 266 // The value is in kHz. For example, on a 2GHz machine, the file | |
| 267 // contains the value "2000000". Historically this file contained no | |
| 268 // newline, but at some point the kernel started appending a newline. | |
| 269 cpuinfo_cycles_per_second = max_freq * 1000.0; | |
| 270 saw_mhz = true; | |
| 271 } | |
| 272 close(fd0); | |
| 273 } | 312 } |
| 274 | 313 |
| 275 // Read /proc/cpuinfo for other values, and if there is no cpuinfo_max_freq. | 314 // Read /proc/cpuinfo for other values, and if there is no cpuinfo_max_freq. |
| 276 const char* pname = "/proc/cpuinfo"; | 315 const char* pname = "/proc/cpuinfo"; |
| 277 int fd = open(pname, O_RDONLY); | 316 int fd = open(pname, O_RDONLY); |
| 278 if (fd == -1) { | 317 if (fd == -1) { |
| 279 perror(pname); | 318 perror(pname); |
| 280 cpuinfo_cycles_per_second = EstimateCyclesPerSecond(1000); | 319 if (!saw_mhz) { |
| 320 cpuinfo_cycles_per_second = EstimateCyclesPerSecond(1000); |
| 321 } |
| 281 return; // TODO: use generic tester instead? | 322 return; // TODO: use generic tester instead? |
| 282 } | 323 } |
| 283 | 324 |
| 284 double bogo_clock = 1.0; | 325 double bogo_clock = 1.0; |
| 326 bool saw_bogo = false; |
| 285 int num_cpus = 0; | 327 int num_cpus = 0; |
| 286 line[0] = line[1] = '\0'; | 328 line[0] = line[1] = '\0'; |
| 287 int chars_read = 0; | 329 int chars_read = 0; |
| 288 do { // we'll exit when the last read didn't read anything | 330 do { // we'll exit when the last read didn't read anything |
| 289 // Move the next line to the beginning of the buffer | 331 // Move the next line to the beginning of the buffer |
| 290 const int oldlinelen = strlen(line); | 332 const int oldlinelen = strlen(line); |
| 291 if (sizeof(line) == oldlinelen + 1) // oldlinelen took up entire line | 333 if (sizeof(line) == oldlinelen + 1) // oldlinelen took up entire line |
| 292 line[0] = '\0'; | 334 line[0] = '\0'; |
| 293 else // still other lines left to save | 335 else // still other lines left to save |
| 294 memmove(line, line + oldlinelen+1, sizeof(line) - (oldlinelen+1)); | 336 memmove(line, line + oldlinelen+1, sizeof(line) - (oldlinelen+1)); |
| 295 // Terminate the new line, reading more if we can't find the newline | 337 // Terminate the new line, reading more if we can't find the newline |
| 296 char* newline = strchr(line, '\n'); | 338 char* newline = strchr(line, '\n'); |
| 297 if (newline == NULL) { | 339 if (newline == NULL) { |
| 298 const int linelen = strlen(line); | 340 const int linelen = strlen(line); |
| 299 const int bytes_to_read = sizeof(line)-1 - linelen; | 341 const int bytes_to_read = sizeof(line)-1 - linelen; |
| 300 assert(bytes_to_read > 0); // because the memmove recovered >=1 bytes | 342 assert(bytes_to_read > 0); // because the memmove recovered >=1 bytes |
| 301 chars_read = read(fd, line + linelen, bytes_to_read); | 343 chars_read = read(fd, line + linelen, bytes_to_read); |
| 302 line[linelen + chars_read] = '\0'; | 344 line[linelen + chars_read] = '\0'; |
| 303 newline = strchr(line, '\n'); | 345 newline = strchr(line, '\n'); |
| 304 } | 346 } |
| 305 if (newline != NULL) | 347 if (newline != NULL) |
| 306 *newline = '\0'; | 348 *newline = '\0'; |
| 307 | 349 |
| 308 if (!saw_mhz && strncmp(line, "cpu MHz", sizeof("cpu MHz")-1) == 0) { | 350 // When parsing the "cpu MHz" and "bogomips" (fallback) entries, we only |
| 351 // accept postive values. Some environments (virtual machines) report zero, |
| 352 // which would cause infinite looping in WallTime_Init. |
| 353 if (!saw_mhz && strncasecmp(line, "cpu MHz", sizeof("cpu MHz")-1) == 0) { |
| 309 const char* freqstr = strchr(line, ':'); | 354 const char* freqstr = strchr(line, ':'); |
| 310 if (freqstr) { | 355 if (freqstr) { |
| 311 cpuinfo_cycles_per_second = strtod(freqstr+1, &err) * 1000000.0; | 356 cpuinfo_cycles_per_second = strtod(freqstr+1, &err) * 1000000.0; |
| 312 if (freqstr[1] != '\0' && *err == '\0') | 357 if (freqstr[1] != '\0' && *err == '\0' && cpuinfo_cycles_per_second > 0) |
| 313 saw_mhz = true; | 358 saw_mhz = true; |
| 314 } | 359 } |
| 315 } else if (strncmp(line, "bogomips", sizeof("bogomips")-1) == 0) { | 360 } else if (strncasecmp(line, "bogomips", sizeof("bogomips")-1) == 0) { |
| 316 const char* freqstr = strchr(line, ':'); | 361 const char* freqstr = strchr(line, ':'); |
| 317 if (freqstr) | 362 if (freqstr) { |
| 318 bogo_clock = strtod(freqstr+1, &err) * 1000000.0; | 363 bogo_clock = strtod(freqstr+1, &err) * 1000000.0; |
| 319 if (freqstr == NULL || freqstr[1] == '\0' || *err != '\0') | 364 if (freqstr[1] != '\0' && *err == '\0' && bogo_clock > 0) |
| 320 bogo_clock = 1.0; | 365 saw_bogo = true; |
| 321 } else if (strncmp(line, "processor", sizeof("processor")-1) == 0) { | 366 } |
| 367 } else if (strncasecmp(line, "processor", sizeof("processor")-1) == 0) { |
| 322 num_cpus++; // count up every time we see an "processor :" entry | 368 num_cpus++; // count up every time we see an "processor :" entry |
| 323 } | 369 } |
| 324 } while (chars_read > 0); | 370 } while (chars_read > 0); |
| 325 close(fd); | 371 close(fd); |
| 326 | 372 |
| 327 if (!saw_mhz) { | 373 if (!saw_mhz) { |
| 328 // If we didn't find anything better, we'll use bogomips, but | 374 if (saw_bogo) { |
| 329 // we're not happy about it. | 375 // If we didn't find anything better, we'll use bogomips, but |
| 330 cpuinfo_cycles_per_second = bogo_clock; | 376 // we're not happy about it. |
| 377 cpuinfo_cycles_per_second = bogo_clock; |
| 378 } else { |
| 379 // If we don't even have bogomips, we'll use the slow estimation. |
| 380 cpuinfo_cycles_per_second = EstimateCyclesPerSecond(1000); |
| 381 } |
| 331 } | 382 } |
| 332 if (cpuinfo_cycles_per_second == 0.0) { | 383 if (cpuinfo_cycles_per_second == 0.0) { |
| 333 cpuinfo_cycles_per_second = 1.0; // maybe unnecessary, but safe | 384 cpuinfo_cycles_per_second = 1.0; // maybe unnecessary, but safe |
| 334 } | 385 } |
| 335 if (num_cpus > 0) { | 386 if (num_cpus > 0) { |
| 336 cpuinfo_num_cpus = num_cpus; | 387 cpuinfo_num_cpus = num_cpus; |
| 337 } | 388 } |
| 338 | 389 |
| 339 #elif defined __FreeBSD__ | 390 #elif defined __FreeBSD__ |
| 340 // For this sysctl to work, the machine must be configured without | 391 // For this sysctl to work, the machine must be configured without |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 451 #endif // else OS_LINUX | 502 #endif // else OS_LINUX |
| 452 } | 503 } |
| 453 | 504 |
| 454 // ---------------------------------------------------------------------- | 505 // ---------------------------------------------------------------------- |
| 455 | 506 |
| 456 #if defined __linux__ || defined __FreeBSD__ || defined __sun__ || defined __CYG
WIN__ || defined __CYGWIN32__ | 507 #if defined __linux__ || defined __FreeBSD__ || defined __sun__ || defined __CYG
WIN__ || defined __CYGWIN32__ |
| 457 static void ConstructFilename(const char* spec, pid_t pid, | 508 static void ConstructFilename(const char* spec, pid_t pid, |
| 458 char* buf, int buf_size) { | 509 char* buf, int buf_size) { |
| 459 CHECK_LT(snprintf(buf, buf_size, | 510 CHECK_LT(snprintf(buf, buf_size, |
| 460 spec, | 511 spec, |
| 461 pid ? pid : getpid()), buf_size); | 512 static_cast<int>(pid ? pid : getpid())), buf_size); |
| 462 } | 513 } |
| 463 #endif | 514 #endif |
| 464 | 515 |
| 465 // A templatized helper function instantiated for Mach (OS X) only. | 516 // A templatized helper function instantiated for Mach (OS X) only. |
| 466 // It can handle finding info for both 32 bits and 64 bits. | 517 // It can handle finding info for both 32 bits and 64 bits. |
| 467 // Returns true if it successfully handled the hdr, false else. | 518 // Returns true if it successfully handled the hdr, false else. |
| 468 #ifdef __MACH__ // Mac OS X, almost certainly | 519 #ifdef __MACH__ // Mac OS X, almost certainly |
| 469 template<uint32_t kMagic, uint32_t kLCSegment, | 520 template<uint32_t kMagic, uint32_t kLCSegment, |
| 470 typename MachHeader, typename SegmentCommand> | 521 typename MachHeader, typename SegmentCommand> |
| 471 static bool NextExtMachHelper(const mach_header* hdr, | 522 static bool NextExtMachHelper(const mach_header* hdr, |
| (...skipping 292 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 764 // Best-effort attempt to get the inode from the filename. I think the | 815 // Best-effort attempt to get the inode from the filename. I think the |
| 765 // two middle ints are major and minor device numbers, but I'm not sure. | 816 // two middle ints are major and minor device numbers, but I'm not sure. |
| 766 sscanf(mapinfo->pr_mapname, "ufs.%*d.%*d.%ld", &inode_from_mapname); | 817 sscanf(mapinfo->pr_mapname, "ufs.%*d.%*d.%ld", &inode_from_mapname); |
| 767 | 818 |
| 768 if (pid_ == 0) { | 819 if (pid_ == 0) { |
| 769 CHECK_LT(snprintf(object_path.buf_, Buffer::kBufSize, | 820 CHECK_LT(snprintf(object_path.buf_, Buffer::kBufSize, |
| 770 "/proc/self/path/%s", mapinfo->pr_mapname), | 821 "/proc/self/path/%s", mapinfo->pr_mapname), |
| 771 Buffer::kBufSize); | 822 Buffer::kBufSize); |
| 772 } else { | 823 } else { |
| 773 CHECK_LT(snprintf(object_path.buf_, Buffer::kBufSize, | 824 CHECK_LT(snprintf(object_path.buf_, Buffer::kBufSize, |
| 774 "/proc/%d/path/%s", pid_, mapinfo->pr_mapname), | 825 "/proc/%d/path/%s", |
| 826 static_cast<int>(pid_), mapinfo->pr_mapname), |
| 775 Buffer::kBufSize); | 827 Buffer::kBufSize); |
| 776 } | 828 } |
| 777 ssize_t len = readlink(object_path.buf_, current_filename_, PATH_MAX); | 829 ssize_t len = readlink(object_path.buf_, current_filename_, PATH_MAX); |
| 778 CHECK_LT(len, PATH_MAX); | 830 CHECK_LT(len, PATH_MAX); |
| 779 if (len < 0) | 831 if (len < 0) |
| 780 len = 0; | 832 len = 0; |
| 781 current_filename_[len] = '\0'; | 833 current_filename_[len] = '\0'; |
| 782 | 834 |
| 783 if (start) *start = mapinfo->pr_vaddr; | 835 if (start) *start = mapinfo->pr_vaddr; |
| 784 if (end) *end = mapinfo->pr_vaddr + mapinfo->pr_size; | 836 if (end) *end = mapinfo->pr_vaddr + mapinfo->pr_size; |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 875 start, end, r,w,x,p, offset, | 927 start, end, r,w,x,p, offset, |
| 876 static_cast<int>(dev/256), static_cast<int>(dev%256), | 928 static_cast<int>(dev/256), static_cast<int>(dev%256), |
| 877 inode, filename); | 929 inode, filename); |
| 878 return (rc < 0 || rc >= bufsize) ? 0 : rc; | 930 return (rc < 0 || rc >= bufsize) ? 0 : rc; |
| 879 } | 931 } |
| 880 | 932 |
| 881 namespace tcmalloc { | 933 namespace tcmalloc { |
| 882 | 934 |
| 883 // Helper to add the list of mapped shared libraries to a profile. | 935 // Helper to add the list of mapped shared libraries to a profile. |
| 884 // Fill formatted "/proc/self/maps" contents into buffer 'buf' of size 'size' | 936 // Fill formatted "/proc/self/maps" contents into buffer 'buf' of size 'size' |
| 885 // and return the actual size occupied in 'buf'. | 937 // and return the actual size occupied in 'buf'. We fill wrote_all to true |
| 938 // if we successfully wrote all proc lines to buf, false else. |
| 886 // We do not provision for 0-terminating 'buf'. | 939 // We do not provision for 0-terminating 'buf'. |
| 887 int FillProcSelfMaps(char buf[], int size) { | 940 int FillProcSelfMaps(char buf[], int size, bool* wrote_all) { |
| 888 ProcMapsIterator::Buffer iterbuf; | 941 ProcMapsIterator::Buffer iterbuf; |
| 889 ProcMapsIterator it(0, &iterbuf); // 0 means "current pid" | 942 ProcMapsIterator it(0, &iterbuf); // 0 means "current pid" |
| 890 | 943 |
| 891 uint64 start, end, offset; | 944 uint64 start, end, offset; |
| 892 int64 inode; | 945 int64 inode; |
| 893 char *flags, *filename; | 946 char *flags, *filename; |
| 894 int bytes_written = 0; | 947 int bytes_written = 0; |
| 948 *wrote_all = true; |
| 895 while (it.Next(&start, &end, &flags, &offset, &inode, &filename)) { | 949 while (it.Next(&start, &end, &flags, &offset, &inode, &filename)) { |
| 896 bytes_written += it.FormatLine(buf + bytes_written, size - bytes_written, | 950 const int line_length = it.FormatLine(buf + bytes_written, |
| 897 start, end, flags, offset, inode, filename, | 951 size - bytes_written, |
| 898 0); | 952 start, end, flags, offset, |
| 953 inode, filename, 0); |
| 954 if (line_length == 0) |
| 955 *wrote_all = false; // failed to write this line out |
| 956 else |
| 957 bytes_written += line_length; |
| 958 |
| 899 } | 959 } |
| 900 return bytes_written; | 960 return bytes_written; |
| 901 } | 961 } |
| 902 | 962 |
| 903 // Dump the same data as FillProcSelfMaps reads to fd. | 963 // Dump the same data as FillProcSelfMaps reads to fd. |
| 904 // It seems easier to repeat parts of FillProcSelfMaps here than to | 964 // It seems easier to repeat parts of FillProcSelfMaps here than to |
| 905 // reuse it via a call. | 965 // reuse it via a call. |
| 906 void DumpProcSelfMaps(RawFD fd) { | 966 void DumpProcSelfMaps(RawFD fd) { |
| 907 ProcMapsIterator::Buffer iterbuf; | 967 ProcMapsIterator::Buffer iterbuf; |
| 908 ProcMapsIterator it(0, &iterbuf); // 0 means "current pid" | 968 ProcMapsIterator it(0, &iterbuf); // 0 means "current pid" |
| 909 | 969 |
| 910 uint64 start, end, offset; | 970 uint64 start, end, offset; |
| 911 int64 inode; | 971 int64 inode; |
| 912 char *flags, *filename; | 972 char *flags, *filename; |
| 913 ProcMapsIterator::Buffer linebuf; | 973 ProcMapsIterator::Buffer linebuf; |
| 914 while (it.Next(&start, &end, &flags, &offset, &inode, &filename)) { | 974 while (it.Next(&start, &end, &flags, &offset, &inode, &filename)) { |
| 915 int written = it.FormatLine(linebuf.buf_, sizeof(linebuf.buf_), | 975 int written = it.FormatLine(linebuf.buf_, sizeof(linebuf.buf_), |
| 916 start, end, flags, offset, inode, filename, | 976 start, end, flags, offset, inode, filename, |
| 917 0); | 977 0); |
| 918 RawWrite(fd, linebuf.buf_, written); | 978 RawWrite(fd, linebuf.buf_, written); |
| 919 } | 979 } |
| 920 } | 980 } |
| 921 | 981 |
| 922 } // namespace tcmalloc | 982 } // namespace tcmalloc |
| OLD | NEW |