• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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