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 |