1 // Copyright 2011 Google Inc. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "util.h"
16
17 #ifdef __CYGWIN__
18 #include <windows.h>
19 #include <io.h>
20 #elif defined( _WIN32)
21 #include <windows.h>
22 #include <io.h>
23 #include <share.h>
24 #endif
25
26 #include <assert.h>
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <sys/stat.h>
34 #include <sys/types.h>
35
36 #ifndef _WIN32
37 #include <unistd.h>
38 #include <sys/time.h>
39 #endif
40
41 #include <vector>
42
43 #if defined(__APPLE__) || defined(__FreeBSD__)
44 #include <sys/sysctl.h>
45 #elif defined(__SVR4) && defined(__sun)
46 #include <unistd.h>
47 #include <sys/loadavg.h>
48 #elif defined(_AIX) && !defined(__PASE__)
49 #include <libperfstat.h>
50 #elif defined(linux) || defined(__GLIBC__)
51 #include <sys/sysinfo.h>
52 #include <fstream>
53 #include <map>
54 #include "string_piece_util.h"
55 #endif
56
57 #if defined(__FreeBSD__)
58 #include <sys/cpuset.h>
59 #endif
60
61 #include "edit_distance.h"
62
63 using namespace std;
64
Fatal(const char * msg,...)65 void Fatal(const char* msg, ...) {
66 va_list ap;
67 fprintf(stderr, "ninja: fatal: ");
68 va_start(ap, msg);
69 vfprintf(stderr, msg, ap);
70 va_end(ap);
71 fprintf(stderr, "\n");
72 #ifdef _WIN32
73 // On Windows, some tools may inject extra threads.
74 // exit() may block on locks held by those threads, so forcibly exit.
75 fflush(stderr);
76 fflush(stdout);
77 ExitProcess(1);
78 #else
79 exit(1);
80 #endif
81 }
82
Warning(const char * msg,va_list ap)83 void Warning(const char* msg, va_list ap) {
84 fprintf(stderr, "ninja: warning: ");
85 vfprintf(stderr, msg, ap);
86 fprintf(stderr, "\n");
87 }
88
Warning(const char * msg,...)89 void Warning(const char* msg, ...) {
90 va_list ap;
91 va_start(ap, msg);
92 Warning(msg, ap);
93 va_end(ap);
94 }
95
Error(const char * msg,va_list ap)96 void Error(const char* msg, va_list ap) {
97 fprintf(stderr, "ninja: error: ");
98 vfprintf(stderr, msg, ap);
99 fprintf(stderr, "\n");
100 }
101
Error(const char * msg,...)102 void Error(const char* msg, ...) {
103 va_list ap;
104 va_start(ap, msg);
105 Error(msg, ap);
106 va_end(ap);
107 }
108
Info(const char * msg,va_list ap)109 void Info(const char* msg, va_list ap) {
110 fprintf(stdout, "ninja: ");
111 vfprintf(stdout, msg, ap);
112 fprintf(stdout, "\n");
113 }
114
Info(const char * msg,...)115 void Info(const char* msg, ...) {
116 va_list ap;
117 va_start(ap, msg);
118 Info(msg, ap);
119 va_end(ap);
120 }
121
CanonicalizePath(string * path,uint64_t * slash_bits)122 void CanonicalizePath(string* path, uint64_t* slash_bits) {
123 size_t len = path->size();
124 char* str = 0;
125 if (len > 0)
126 str = &(*path)[0];
127 CanonicalizePath(str, &len, slash_bits);
128 path->resize(len);
129 }
130
IsPathSeparator(char c)131 static bool IsPathSeparator(char c) {
132 #ifdef _WIN32
133 return c == '/' || c == '\\';
134 #else
135 return c == '/';
136 #endif
137 }
138
CanonicalizePath(char * path,size_t * len,uint64_t * slash_bits)139 void CanonicalizePath(char* path, size_t* len, uint64_t* slash_bits) {
140 // WARNING: this function is performance-critical; please benchmark
141 // any changes you make to it.
142 if (*len == 0) {
143 return;
144 }
145
146 const int kMaxPathComponents = 60;
147 char* components[kMaxPathComponents];
148 int component_count = 0;
149
150 char* start = path;
151 char* dst = start;
152 const char* src = start;
153 const char* end = start + *len;
154
155 if (IsPathSeparator(*src)) {
156 #ifdef _WIN32
157
158 // network path starts with //
159 if (*len > 1 && IsPathSeparator(*(src + 1))) {
160 src += 2;
161 dst += 2;
162 } else {
163 ++src;
164 ++dst;
165 }
166 #else
167 ++src;
168 ++dst;
169 #endif
170 }
171
172 while (src < end) {
173 if (*src == '.') {
174 if (src + 1 == end || IsPathSeparator(src[1])) {
175 // '.' component; eliminate.
176 src += 2;
177 continue;
178 } else if (src[1] == '.' && (src + 2 == end || IsPathSeparator(src[2]))) {
179 // '..' component. Back up if possible.
180 if (component_count > 0) {
181 dst = components[component_count - 1];
182 src += 3;
183 --component_count;
184 } else {
185 *dst++ = *src++;
186 *dst++ = *src++;
187 *dst++ = *src++;
188 }
189 continue;
190 }
191 }
192
193 if (IsPathSeparator(*src)) {
194 src++;
195 continue;
196 }
197
198 if (component_count == kMaxPathComponents)
199 Fatal("path has too many components : %s", path);
200 components[component_count] = dst;
201 ++component_count;
202
203 while (src != end && !IsPathSeparator(*src))
204 *dst++ = *src++;
205 *dst++ = *src++; // Copy '/' or final \0 character as well.
206 }
207
208 if (dst == start) {
209 *dst++ = '.';
210 *dst++ = '\0';
211 }
212
213 *len = dst - start - 1;
214 #ifdef _WIN32
215 uint64_t bits = 0;
216 uint64_t bits_mask = 1;
217
218 for (char* c = start; c < start + *len; ++c) {
219 switch (*c) {
220 case '\\':
221 bits |= bits_mask;
222 *c = '/';
223 NINJA_FALLTHROUGH;
224 case '/':
225 bits_mask <<= 1;
226 }
227 }
228
229 *slash_bits = bits;
230 #else
231 *slash_bits = 0;
232 #endif
233 }
234
IsKnownShellSafeCharacter(char ch)235 static inline bool IsKnownShellSafeCharacter(char ch) {
236 if ('A' <= ch && ch <= 'Z') return true;
237 if ('a' <= ch && ch <= 'z') return true;
238 if ('0' <= ch && ch <= '9') return true;
239
240 switch (ch) {
241 case '_':
242 case '+':
243 case '-':
244 case '.':
245 case '/':
246 return true;
247 default:
248 return false;
249 }
250 }
251
IsKnownWin32SafeCharacter(char ch)252 static inline bool IsKnownWin32SafeCharacter(char ch) {
253 switch (ch) {
254 case ' ':
255 case '"':
256 return false;
257 default:
258 return true;
259 }
260 }
261
StringNeedsShellEscaping(const string & input)262 static inline bool StringNeedsShellEscaping(const string& input) {
263 for (size_t i = 0; i < input.size(); ++i) {
264 if (!IsKnownShellSafeCharacter(input[i])) return true;
265 }
266 return false;
267 }
268
StringNeedsWin32Escaping(const string & input)269 static inline bool StringNeedsWin32Escaping(const string& input) {
270 for (size_t i = 0; i < input.size(); ++i) {
271 if (!IsKnownWin32SafeCharacter(input[i])) return true;
272 }
273 return false;
274 }
275
GetShellEscapedString(const string & input,string * result)276 void GetShellEscapedString(const string& input, string* result) {
277 assert(result);
278
279 if (!StringNeedsShellEscaping(input)) {
280 result->append(input);
281 return;
282 }
283
284 const char kQuote = '\'';
285 const char kEscapeSequence[] = "'\\'";
286
287 result->push_back(kQuote);
288
289 string::const_iterator span_begin = input.begin();
290 for (string::const_iterator it = input.begin(), end = input.end(); it != end;
291 ++it) {
292 if (*it == kQuote) {
293 result->append(span_begin, it);
294 result->append(kEscapeSequence);
295 span_begin = it;
296 }
297 }
298 result->append(span_begin, input.end());
299 result->push_back(kQuote);
300 }
301
302
GetWin32EscapedString(const string & input,string * result)303 void GetWin32EscapedString(const string& input, string* result) {
304 assert(result);
305 if (!StringNeedsWin32Escaping(input)) {
306 result->append(input);
307 return;
308 }
309
310 const char kQuote = '"';
311 const char kBackslash = '\\';
312
313 result->push_back(kQuote);
314 size_t consecutive_backslash_count = 0;
315 string::const_iterator span_begin = input.begin();
316 for (string::const_iterator it = input.begin(), end = input.end(); it != end;
317 ++it) {
318 switch (*it) {
319 case kBackslash:
320 ++consecutive_backslash_count;
321 break;
322 case kQuote:
323 result->append(span_begin, it);
324 result->append(consecutive_backslash_count + 1, kBackslash);
325 span_begin = it;
326 consecutive_backslash_count = 0;
327 break;
328 default:
329 consecutive_backslash_count = 0;
330 break;
331 }
332 }
333 result->append(span_begin, input.end());
334 result->append(consecutive_backslash_count, kBackslash);
335 result->push_back(kQuote);
336 }
337
ReadFile(const string & path,string * contents,string * err)338 int ReadFile(const string& path, string* contents, string* err) {
339 #ifdef _WIN32
340 // This makes a ninja run on a set of 1500 manifest files about 4% faster
341 // than using the generic fopen code below.
342 err->clear();
343 HANDLE f = ::CreateFileA(path.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL,
344 OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
345 if (f == INVALID_HANDLE_VALUE) {
346 err->assign(GetLastErrorString());
347 return -ENOENT;
348 }
349
350 for (;;) {
351 DWORD len;
352 char buf[64 << 10];
353 if (!::ReadFile(f, buf, sizeof(buf), &len, NULL)) {
354 err->assign(GetLastErrorString());
355 contents->clear();
356 ::CloseHandle(f);
357 return -EIO;
358 }
359 if (len == 0)
360 break;
361 contents->append(buf, len);
362 }
363 ::CloseHandle(f);
364 return 0;
365 #else
366 FILE* f = fopen(path.c_str(), "rb");
367 if (!f) {
368 err->assign(strerror(errno));
369 return -errno;
370 }
371
372 struct stat st;
373 if (fstat(fileno(f), &st) < 0) {
374 err->assign(strerror(errno));
375 fclose(f);
376 return -errno;
377 }
378
379 // +1 is for the resize in ManifestParser::Load
380 contents->reserve(st.st_size + 1);
381
382 char buf[64 << 10];
383 size_t len;
384 while (!feof(f) && (len = fread(buf, 1, sizeof(buf), f)) > 0) {
385 contents->append(buf, len);
386 }
387 if (ferror(f)) {
388 err->assign(strerror(errno)); // XXX errno?
389 contents->clear();
390 fclose(f);
391 return -errno;
392 }
393 fclose(f);
394 return 0;
395 #endif
396 }
397
SetCloseOnExec(int fd)398 void SetCloseOnExec(int fd) {
399 #ifndef _WIN32
400 int flags = fcntl(fd, F_GETFD);
401 if (flags < 0) {
402 perror("fcntl(F_GETFD)");
403 } else {
404 if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0)
405 perror("fcntl(F_SETFD)");
406 }
407 #else
408 HANDLE hd = (HANDLE) _get_osfhandle(fd);
409 if (! SetHandleInformation(hd, HANDLE_FLAG_INHERIT, 0)) {
410 fprintf(stderr, "SetHandleInformation(): %s", GetLastErrorString().c_str());
411 }
412 #endif // ! _WIN32
413 }
414
415
SpellcheckStringV(const string & text,const vector<const char * > & words)416 const char* SpellcheckStringV(const string& text,
417 const vector<const char*>& words) {
418 const bool kAllowReplacements = true;
419 const int kMaxValidEditDistance = 3;
420
421 int min_distance = kMaxValidEditDistance + 1;
422 const char* result = NULL;
423 for (vector<const char*>::const_iterator i = words.begin();
424 i != words.end(); ++i) {
425 int distance = EditDistance(*i, text, kAllowReplacements,
426 kMaxValidEditDistance);
427 if (distance < min_distance) {
428 min_distance = distance;
429 result = *i;
430 }
431 }
432 return result;
433 }
434
SpellcheckString(const char * text,...)435 const char* SpellcheckString(const char* text, ...) {
436 // Note: This takes a const char* instead of a string& because using
437 // va_start() with a reference parameter is undefined behavior.
438 va_list ap;
439 va_start(ap, text);
440 vector<const char*> words;
441 const char* word;
442 while ((word = va_arg(ap, const char*)))
443 words.push_back(word);
444 va_end(ap);
445 return SpellcheckStringV(text, words);
446 }
447
448 #ifdef _WIN32
GetLastErrorString()449 string GetLastErrorString() {
450 DWORD err = GetLastError();
451
452 char* msg_buf;
453 FormatMessageA(
454 FORMAT_MESSAGE_ALLOCATE_BUFFER |
455 FORMAT_MESSAGE_FROM_SYSTEM |
456 FORMAT_MESSAGE_IGNORE_INSERTS,
457 NULL,
458 err,
459 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
460 (char*)&msg_buf,
461 0,
462 NULL);
463 string msg = msg_buf;
464 LocalFree(msg_buf);
465 return msg;
466 }
467
Win32Fatal(const char * function,const char * hint)468 void Win32Fatal(const char* function, const char* hint) {
469 if (hint) {
470 Fatal("%s: %s (%s)", function, GetLastErrorString().c_str(), hint);
471 } else {
472 Fatal("%s: %s", function, GetLastErrorString().c_str());
473 }
474 }
475 #endif
476
islatinalpha(int c)477 bool islatinalpha(int c) {
478 // isalpha() is locale-dependent.
479 return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
480 }
481
StripAnsiEscapeCodes(const string & in)482 string StripAnsiEscapeCodes(const string& in) {
483 string stripped;
484 stripped.reserve(in.size());
485
486 for (size_t i = 0; i < in.size(); ++i) {
487 if (in[i] != '\33') {
488 // Not an escape code.
489 stripped.push_back(in[i]);
490 continue;
491 }
492
493 // Only strip CSIs for now.
494 if (i + 1 >= in.size()) break;
495 if (in[i + 1] != '[') continue; // Not a CSI.
496 i += 2;
497
498 // Skip everything up to and including the next [a-zA-Z].
499 while (i < in.size() && !islatinalpha(in[i]))
500 ++i;
501 }
502 return stripped;
503 }
504
505 #if defined(linux) || defined(__GLIBC__)
readCount(const std::string & path)506 std::pair<int64_t, bool> readCount(const std::string& path) {
507 std::ifstream file(path.c_str());
508 if (!file.is_open())
509 return std::make_pair(0, false);
510 int64_t n = 0;
511 file >> n;
512 if (file.good())
513 return std::make_pair(n, true);
514 return std::make_pair(0, false);
515 }
516
517 struct MountPoint {
518 int mountId;
519 int parentId;
520 StringPiece deviceId;
521 StringPiece root;
522 StringPiece mountPoint;
523 vector<StringPiece> options;
524 vector<StringPiece> optionalFields;
525 StringPiece fsType;
526 StringPiece mountSource;
527 vector<StringPiece> superOptions;
parseMountPoint528 bool parse(const string& line) {
529 vector<StringPiece> pieces = SplitStringPiece(line, ' ');
530 if (pieces.size() < 10)
531 return false;
532 size_t optionalStart = 0;
533 for (size_t i = 6; i < pieces.size(); i++) {
534 if (pieces[i] == "-") {
535 optionalStart = i + 1;
536 break;
537 }
538 }
539 if (optionalStart == 0)
540 return false;
541 if (optionalStart + 3 != pieces.size())
542 return false;
543 mountId = atoi(pieces[0].AsString().c_str());
544 parentId = atoi(pieces[1].AsString().c_str());
545 deviceId = pieces[2];
546 root = pieces[3];
547 mountPoint = pieces[4];
548 options = SplitStringPiece(pieces[5], ',');
549 optionalFields =
550 vector<StringPiece>(&pieces[6], &pieces[optionalStart - 1]);
551 fsType = pieces[optionalStart];
552 mountSource = pieces[optionalStart + 1];
553 superOptions = SplitStringPiece(pieces[optionalStart + 2], ',');
554 return true;
555 }
translateMountPoint556 string translate(string& path) const {
557 // path must be sub dir of root
558 if (path.compare(0, root.len_, root.str_, root.len_) != 0) {
559 return string();
560 }
561 path.erase(0, root.len_);
562 if (path == ".." || (path.length() > 2 && path.compare(0, 3, "../") == 0)) {
563 return string();
564 }
565 return mountPoint.AsString() + "/" + path;
566 }
567 };
568
569 struct CGroupSubSys {
570 int id;
571 string name;
572 vector<string> subsystems;
parseCGroupSubSys573 bool parse(string& line) {
574 size_t first = line.find(':');
575 if (first == string::npos)
576 return false;
577 line[first] = '\0';
578 size_t second = line.find(':', first + 1);
579 if (second == string::npos)
580 return false;
581 line[second] = '\0';
582 id = atoi(line.c_str());
583 name = line.substr(second + 1);
584 vector<StringPiece> pieces =
585 SplitStringPiece(StringPiece(line.c_str() + first + 1), ',');
586 for (size_t i = 0; i < pieces.size(); i++) {
587 subsystems.push_back(pieces[i].AsString());
588 }
589 return true;
590 }
591 };
592
ParseMountInfo(map<string,CGroupSubSys> & subsystems)593 map<string, string> ParseMountInfo(map<string, CGroupSubSys>& subsystems) {
594 map<string, string> cgroups;
595 ifstream mountinfo("/proc/self/mountinfo");
596 if (!mountinfo.is_open())
597 return cgroups;
598 while (!mountinfo.eof()) {
599 string line;
600 getline(mountinfo, line);
601 MountPoint mp;
602 if (!mp.parse(line))
603 continue;
604 if (mp.fsType != "cgroup")
605 continue;
606 for (size_t i = 0; i < mp.superOptions.size(); i++) {
607 string opt = mp.superOptions[i].AsString();
608 map<string, CGroupSubSys>::iterator subsys = subsystems.find(opt);
609 if (subsys == subsystems.end())
610 continue;
611 string newPath = mp.translate(subsys->second.name);
612 if (!newPath.empty())
613 cgroups.insert(make_pair(opt, newPath));
614 }
615 }
616 return cgroups;
617 }
618
ParseSelfCGroup()619 map<string, CGroupSubSys> ParseSelfCGroup() {
620 map<string, CGroupSubSys> cgroups;
621 ifstream cgroup("/proc/self/cgroup");
622 if (!cgroup.is_open())
623 return cgroups;
624 string line;
625 while (!cgroup.eof()) {
626 getline(cgroup, line);
627 CGroupSubSys subsys;
628 if (!subsys.parse(line))
629 continue;
630 for (size_t i = 0; i < subsys.subsystems.size(); i++) {
631 cgroups.insert(make_pair(subsys.subsystems[i], subsys));
632 }
633 }
634 return cgroups;
635 }
636
ParseCPUFromCGroup()637 int ParseCPUFromCGroup() {
638 map<string, CGroupSubSys> subsystems = ParseSelfCGroup();
639 map<string, string> cgroups = ParseMountInfo(subsystems);
640 map<string, string>::iterator cpu = cgroups.find("cpu");
641 if (cpu == cgroups.end())
642 return -1;
643 std::pair<int64_t, bool> quota = readCount(cpu->second + "/cpu.cfs_quota_us");
644 if (!quota.second || quota.first == -1)
645 return -1;
646 std::pair<int64_t, bool> period =
647 readCount(cpu->second + "/cpu.cfs_period_us");
648 if (!period.second)
649 return -1;
650 return quota.first / period.first;
651 }
652 #endif
653
GetProcessorCount()654 int GetProcessorCount() {
655 #ifdef _WIN32
656 DWORD cpuCount = 0;
657 #ifndef _WIN64
658 // Need to use GetLogicalProcessorInformationEx to get real core count on
659 // machines with >64 cores. See https://stackoverflow.com/a/31209344/21475
660 DWORD len = 0;
661 if (!GetLogicalProcessorInformationEx(RelationProcessorCore, nullptr, &len)
662 && GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
663 std::vector<char> buf(len);
664 int cores = 0;
665 if (GetLogicalProcessorInformationEx(RelationProcessorCore,
666 reinterpret_cast<PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX>(
667 buf.data()), &len)) {
668 for (DWORD i = 0; i < len; ) {
669 auto info = reinterpret_cast<PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX>(
670 buf.data() + i);
671 if (info->Relationship == RelationProcessorCore &&
672 info->Processor.GroupCount == 1) {
673 for (KAFFINITY core_mask = info->Processor.GroupMask[0].Mask;
674 core_mask; core_mask >>= 1) {
675 cores += (core_mask & 1);
676 }
677 }
678 i += info->Size;
679 }
680 if (cores != 0) {
681 cpuCount = cores;
682 }
683 }
684 }
685 #endif
686 if (cpuCount == 0) {
687 cpuCount = GetActiveProcessorCount(ALL_PROCESSOR_GROUPS);
688 }
689 JOBOBJECT_CPU_RATE_CONTROL_INFORMATION info;
690 // reference:
691 // https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-jobobject_cpu_rate_control_information
692 if (QueryInformationJobObject(NULL, JobObjectCpuRateControlInformation, &info,
693 sizeof(info), NULL)) {
694 if (info.ControlFlags & (JOB_OBJECT_CPU_RATE_CONTROL_ENABLE |
695 JOB_OBJECT_CPU_RATE_CONTROL_HARD_CAP)) {
696 return cpuCount * info.CpuRate / 10000;
697 }
698 }
699 return cpuCount;
700 #else
701 int cgroupCount = -1;
702 int schedCount = -1;
703 #if defined(linux) || defined(__GLIBC__)
704 cgroupCount = ParseCPUFromCGroup();
705 #endif
706 // The number of exposed processors might not represent the actual number of
707 // processors threads can run on. This happens when a CPU set limitation is
708 // active, see https://github.com/ninja-build/ninja/issues/1278
709 #if defined(__FreeBSD__)
710 cpuset_t mask;
711 CPU_ZERO(&mask);
712 if (cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, sizeof(mask),
713 &mask) == 0) {
714 return CPU_COUNT(&mask);
715 }
716 #elif defined(CPU_COUNT)
717 cpu_set_t set;
718 if (sched_getaffinity(getpid(), sizeof(set), &set) == 0) {
719 schedCount = CPU_COUNT(&set);
720 }
721 #endif
722 if (cgroupCount >= 0 && schedCount >= 0) return std::min(cgroupCount, schedCount);
723 if (cgroupCount < 0 && schedCount < 0) return sysconf(_SC_NPROCESSORS_ONLN);
724 return std::max(cgroupCount, schedCount);
725 #endif
726 }
727
728 #if defined(_WIN32) || defined(__CYGWIN__)
CalculateProcessorLoad(uint64_t idle_ticks,uint64_t total_ticks)729 static double CalculateProcessorLoad(uint64_t idle_ticks, uint64_t total_ticks)
730 {
731 static uint64_t previous_idle_ticks = 0;
732 static uint64_t previous_total_ticks = 0;
733 static double previous_load = -0.0;
734
735 uint64_t idle_ticks_since_last_time = idle_ticks - previous_idle_ticks;
736 uint64_t total_ticks_since_last_time = total_ticks - previous_total_ticks;
737
738 bool first_call = (previous_total_ticks == 0);
739 bool ticks_not_updated_since_last_call = (total_ticks_since_last_time == 0);
740
741 double load;
742 if (first_call || ticks_not_updated_since_last_call) {
743 load = previous_load;
744 } else {
745 // Calculate load.
746 double idle_to_total_ratio =
747 ((double)idle_ticks_since_last_time) / total_ticks_since_last_time;
748 double load_since_last_call = 1.0 - idle_to_total_ratio;
749
750 // Filter/smooth result when possible.
751 if(previous_load > 0) {
752 load = 0.9 * previous_load + 0.1 * load_since_last_call;
753 } else {
754 load = load_since_last_call;
755 }
756 }
757
758 previous_load = load;
759 previous_total_ticks = total_ticks;
760 previous_idle_ticks = idle_ticks;
761
762 return load;
763 }
764
FileTimeToTickCount(const FILETIME & ft)765 static uint64_t FileTimeToTickCount(const FILETIME & ft)
766 {
767 uint64_t high = (((uint64_t)(ft.dwHighDateTime)) << 32);
768 uint64_t low = ft.dwLowDateTime;
769 return (high | low);
770 }
771
GetLoadAverage()772 double GetLoadAverage() {
773 FILETIME idle_time, kernel_time, user_time;
774 BOOL get_system_time_succeeded =
775 GetSystemTimes(&idle_time, &kernel_time, &user_time);
776
777 double posix_compatible_load;
778 if (get_system_time_succeeded) {
779 uint64_t idle_ticks = FileTimeToTickCount(idle_time);
780
781 // kernel_time from GetSystemTimes already includes idle_time.
782 uint64_t total_ticks =
783 FileTimeToTickCount(kernel_time) + FileTimeToTickCount(user_time);
784
785 double processor_load = CalculateProcessorLoad(idle_ticks, total_ticks);
786 posix_compatible_load = processor_load * GetProcessorCount();
787
788 } else {
789 posix_compatible_load = -0.0;
790 }
791
792 return posix_compatible_load;
793 }
794 #elif defined(__PASE__)
GetLoadAverage()795 double GetLoadAverage() {
796 return -0.0f;
797 }
798 #elif defined(_AIX)
GetLoadAverage()799 double GetLoadAverage() {
800 perfstat_cpu_total_t cpu_stats;
801 if (perfstat_cpu_total(NULL, &cpu_stats, sizeof(cpu_stats), 1) < 0) {
802 return -0.0f;
803 }
804
805 // Calculation taken from comment in libperfstats.h
806 return double(cpu_stats.loadavg[0]) / double(1 << SBITS);
807 }
808 #elif defined(__UCLIBC__) || (defined(__BIONIC__) && __ANDROID_API__ < 29)
GetLoadAverage()809 double GetLoadAverage() {
810 struct sysinfo si;
811 if (sysinfo(&si) != 0)
812 return -0.0f;
813 return 1.0 / (1 << SI_LOAD_SHIFT) * si.loads[0];
814 }
815 #elif defined(__HAIKU__)
GetLoadAverage()816 double GetLoadAverage() {
817 return -0.0f;
818 }
819 #else
GetLoadAverage()820 double GetLoadAverage() {
821 double loadavg[3] = { 0.0f, 0.0f, 0.0f };
822 if (getloadavg(loadavg, 3) < 0) {
823 // Maybe we should return an error here or the availability of
824 // getloadavg(3) should be checked when ninja is configured.
825 return -0.0f;
826 }
827 return loadavg[0];
828 }
829 #endif // _WIN32
830
ElideMiddle(const string & str,size_t width)831 string ElideMiddle(const string& str, size_t width) {
832 switch (width) {
833 case 0: return "";
834 case 1: return ".";
835 case 2: return "..";
836 case 3: return "...";
837 }
838 const int kMargin = 3; // Space for "...".
839 string result = str;
840 if (result.size() > width) {
841 size_t elide_size = (width - kMargin) / 2;
842 result = result.substr(0, elide_size)
843 + "..."
844 + result.substr(result.size() - elide_size, elide_size);
845 }
846 return result;
847 }
848
Truncate(const string & path,size_t size,string * err)849 bool Truncate(const string& path, size_t size, string* err) {
850 #ifdef _WIN32
851 int fh = _sopen(path.c_str(), _O_RDWR | _O_CREAT, _SH_DENYNO,
852 _S_IREAD | _S_IWRITE);
853 int success = _chsize(fh, size);
854 _close(fh);
855 #else
856 int success = truncate(path.c_str(), size);
857 #endif
858 // Both truncate() and _chsize() return 0 on success and set errno and return
859 // -1 on failure.
860 if (success < 0) {
861 *err = strerror(errno);
862 return false;
863 }
864 return true;
865 }
866