Ninja
util.cc
Go to the documentation of this file.
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#include <direct.h>
25#endif
26
27#include <assert.h>
28#include <errno.h>
29#include <fcntl.h>
30#include <stdarg.h>
31#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34#include <sys/stat.h>
35#include <sys/types.h>
36
37#ifndef _WIN32
38#include <unistd.h>
39#include <sys/time.h>
40#endif
41
42#include <algorithm>
43#include <vector>
44
45#if defined(__APPLE__) || defined(__FreeBSD__)
46#include <sys/sysctl.h>
47#elif defined(__SVR4) && defined(__sun)
48#include <unistd.h>
49#include <sys/loadavg.h>
50#elif defined(_AIX) && !defined(__PASE__)
51#include <libperfstat.h>
52#elif defined(__linux__) || defined(__GLIBC__)
53#include <sys/sysinfo.h>
54#include <fstream>
55#include <map>
56#include "string_piece_util.h"
57#endif
58
59#if defined(__FreeBSD__)
60#include <sys/cpuset.h>
61#endif
62
63#include "edit_distance.h"
64
65using namespace std;
66
67void Fatal(const char* msg, ...) {
68 va_list ap;
69 fprintf(stderr, "ninja: fatal: ");
70 va_start(ap, msg);
71 vfprintf(stderr, msg, ap);
72 va_end(ap);
73 fprintf(stderr, "\n");
74#ifdef _WIN32
75 // On Windows, some tools may inject extra threads.
76 // exit() may block on locks held by those threads, so forcibly exit.
77 fflush(stderr);
78 fflush(stdout);
79 ExitProcess(1);
80#else
81 exit(1);
82#endif
83}
84
85void Warning(const char* msg, va_list ap) {
86 fprintf(stderr, "ninja: warning: ");
87 vfprintf(stderr, msg, ap);
88 fprintf(stderr, "\n");
89}
90
91void Warning(const char* msg, ...) {
92 va_list ap;
93 va_start(ap, msg);
94 Warning(msg, ap);
95 va_end(ap);
96}
97
98void Error(const char* msg, va_list ap) {
99 fprintf(stderr, "ninja: error: ");
100 vfprintf(stderr, msg, ap);
101 fprintf(stderr, "\n");
102}
103
104void Error(const char* msg, ...) {
105 va_list ap;
106 va_start(ap, msg);
107 Error(msg, ap);
108 va_end(ap);
109}
110
111void Info(const char* msg, va_list ap) {
112 fprintf(stdout, "ninja: ");
113 vfprintf(stdout, msg, ap);
114 fprintf(stdout, "\n");
115}
116
117void Info(const char* msg, ...) {
118 va_list ap;
119 va_start(ap, msg);
120 Info(msg, ap);
121 va_end(ap);
122}
123
124void CanonicalizePath(string* path, uint64_t* slash_bits) {
125 size_t len = path->size();
126 char* str = 0;
127 if (len > 0)
128 str = &(*path)[0];
129 CanonicalizePath(str, &len, slash_bits);
130 path->resize(len);
131}
132
133static bool IsPathSeparator(char c) {
134#ifdef _WIN32
135 return c == '/' || c == '\\';
136#else
137 return c == '/';
138#endif
139}
140
141void CanonicalizePath(char* path, size_t* len, uint64_t* slash_bits) {
142 // WARNING: this function is performance-critical; please benchmark
143 // any changes you make to it.
144 if (*len == 0) {
145 return;
146 }
147
148 char* start = path;
149 char* dst = start;
150 char* dst_start = dst;
151 const char* src = start;
152 const char* end = start + *len;
153 const char* src_next;
154
155 // For absolute paths, skip the leading directory separator
156 // as this one should never be removed from the result.
157 if (IsPathSeparator(*src)) {
158#ifdef _WIN32
159 // Windows network path starts with //
160 if (src + 2 <= end && IsPathSeparator(src[1])) {
161 src += 2;
162 dst += 2;
163 } else {
164 ++src;
165 ++dst;
166 }
167#else
168 ++src;
169 ++dst;
170#endif
171 dst_start = dst;
172 } else {
173 // For relative paths, skip any leading ../ as these are quite common
174 // to reference source files in build plans, and doing this here makes
175 // the loop work below faster in general.
176 while (src + 3 <= end && src[0] == '.' && src[1] == '.' &&
177 IsPathSeparator(src[2])) {
178 src += 3;
179 dst += 3;
180 }
181 }
182
183 // Loop over all components of the paths _except_ the last one, in
184 // order to simplify the loop's code and make it faster.
185 int component_count = 0;
186 char* dst0 = dst;
187 for (; src < end; src = src_next) {
188#ifndef _WIN32
189 // Use memchr() for faster lookups thanks to optimized C library
190 // implementation. `hyperfine canon_perftest` shows a significant
191 // difference (e,g, 484ms vs 437ms).
192 const char* next_sep =
193 static_cast<const char*>(::memchr(src, '/', end - src));
194 if (!next_sep) {
195 // This is the last component, will be handled out of the loop.
196 break;
197 }
198#else
199 // Need to check for both '/' and '\\' so do not use memchr().
200 // Cannot use strpbrk() because end[0] can be \0 or something else!
201 const char* next_sep = src;
202 while (next_sep != end && !IsPathSeparator(*next_sep))
203 ++next_sep;
204 if (next_sep == end) {
205 // This is the last component, will be handled out of the loop.
206 break;
207 }
208#endif
209 // Position for next loop iteration.
210 src_next = next_sep + 1;
211 // Length of the component, excluding trailing directory.
212 size_t component_len = next_sep - src;
213
214 if (component_len <= 2) {
215 if (component_len == 0) {
216 continue; // Ignore empty component, e.g. 'foo//bar' -> 'foo/bar'.
217 }
218 if (src[0] == '.') {
219 if (component_len == 1) {
220 continue; // Ignore '.' component, e.g. './foo' -> 'foo'.
221 } else if (src[1] == '.') {
222 // Process the '..' component if found. Back up if possible.
223 if (component_count > 0) {
224 // Move back to start of previous component.
225 --component_count;
226 while (--dst > dst0 && !IsPathSeparator(dst[-1])) {
227 // nothing to do here, decrement happens before condition check.
228 }
229 } else {
230 dst[0] = '.';
231 dst[1] = '.';
232 dst[2] = src[2];
233 dst += 3;
234 }
235 continue;
236 }
237 }
238 }
239 ++component_count;
240
241 // Copy or skip component, including trailing directory separator.
242 if (dst != src) {
243 ::memmove(dst, src, src_next - src);
244 }
245 dst += src_next - src;
246 }
247
248 // Handling the last component that does not have a trailing separator.
249 // The logic here is _slightly_ different since there is no trailing
250 // directory separator.
251 size_t component_len = end - src;
252 do {
253 if (component_len == 0)
254 break; // Ignore empty component (e.g. 'foo//' -> 'foo/')
255 if (src[0] == '.') {
256 if (component_len == 1)
257 break; // Ignore trailing '.' (e.g. 'foo/.' -> 'foo/')
258 if (component_len == 2 && src[1] == '.') {
259 // Handle '..'. Back up if possible.
260 if (component_count > 0) {
261 while (--dst > dst0 && !IsPathSeparator(dst[-1])) {
262 // nothing to do here, decrement happens before condition check.
263 }
264 } else {
265 dst[0] = '.';
266 dst[1] = '.';
267 dst += 2;
268 // No separator to add here.
269 }
270 break;
271 }
272 }
273 // Skip or copy last component, no trailing separator.
274 if (dst != src) {
275 ::memmove(dst, src, component_len);
276 }
277 dst += component_len;
278 } while (0);
279
280 // Remove trailing path separator if any, but keep the initial
281 // path separator(s) if there was one (or two on Windows).
282 if (dst > dst_start && IsPathSeparator(dst[-1]))
283 dst--;
284
285 if (dst == start) {
286 // Handle special cases like "aa/.." -> "."
287 *dst++ = '.';
288 }
289
290 *len = dst - start; // dst points after the trailing char here.
291#ifdef _WIN32
292 uint64_t bits = 0;
293 uint64_t bits_mask = 1;
294
295 for (char* c = start; c < start + *len; ++c) {
296 switch (*c) {
297 case '\\':
298 bits |= bits_mask;
299 *c = '/';
301 case '/':
302 bits_mask <<= 1;
303 }
304 }
305
306 *slash_bits = bits;
307#else
308 *slash_bits = 0;
309#endif
310}
311
312static inline bool IsKnownShellSafeCharacter(char ch) {
313 if ('A' <= ch && ch <= 'Z') return true;
314 if ('a' <= ch && ch <= 'z') return true;
315 if ('0' <= ch && ch <= '9') return true;
316
317 switch (ch) {
318 case '_':
319 case '+':
320 case '-':
321 case '.':
322 case '/':
323 return true;
324 default:
325 return false;
326 }
327}
328
329static inline bool IsKnownWin32SafeCharacter(char ch) {
330 switch (ch) {
331 case ' ':
332 case '"':
333 return false;
334 default:
335 return true;
336 }
337}
338
339static inline bool StringNeedsShellEscaping(const string& input) {
340 for (size_t i = 0; i < input.size(); ++i) {
341 if (!IsKnownShellSafeCharacter(input[i])) return true;
342 }
343 return false;
344}
345
346static inline bool StringNeedsWin32Escaping(const string& input) {
347 for (size_t i = 0; i < input.size(); ++i) {
348 if (!IsKnownWin32SafeCharacter(input[i])) return true;
349 }
350 return false;
351}
352
353void GetShellEscapedString(const string& input, string* result) {
354 assert(result);
355
356 if (!StringNeedsShellEscaping(input)) {
357 result->append(input);
358 return;
359 }
360
361 const char kQuote = '\'';
362 const char kEscapeSequence[] = "'\\'";
363
364 result->push_back(kQuote);
365
366 string::const_iterator span_begin = input.begin();
367 for (string::const_iterator it = input.begin(), end = input.end(); it != end;
368 ++it) {
369 if (*it == kQuote) {
370 result->append(span_begin, it);
371 result->append(kEscapeSequence);
372 span_begin = it;
373 }
374 }
375 result->append(span_begin, input.end());
376 result->push_back(kQuote);
377}
378
379
380void GetWin32EscapedString(const string& input, string* result) {
381 assert(result);
382 if (!StringNeedsWin32Escaping(input)) {
383 result->append(input);
384 return;
385 }
386
387 const char kQuote = '"';
388 const char kBackslash = '\\';
389
390 result->push_back(kQuote);
391 size_t consecutive_backslash_count = 0;
392 string::const_iterator span_begin = input.begin();
393 for (string::const_iterator it = input.begin(), end = input.end(); it != end;
394 ++it) {
395 switch (*it) {
396 case kBackslash:
397 ++consecutive_backslash_count;
398 break;
399 case kQuote:
400 result->append(span_begin, it);
401 result->append(consecutive_backslash_count + 1, kBackslash);
402 span_begin = it;
403 consecutive_backslash_count = 0;
404 break;
405 default:
406 consecutive_backslash_count = 0;
407 break;
408 }
409 }
410 result->append(span_begin, input.end());
411 result->append(consecutive_backslash_count, kBackslash);
412 result->push_back(kQuote);
413}
414
415int ReadFile(const string& path, string* contents, string* err) {
416#ifdef _WIN32
417 // This makes a ninja run on a set of 1500 manifest files about 4% faster
418 // than using the generic fopen code below.
419 err->clear();
420 HANDLE f = ::CreateFileA(path.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL,
421 OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
422 if (f == INVALID_HANDLE_VALUE) {
423 err->assign(GetLastErrorString());
424 return -ENOENT;
425 }
426
427 for (;;) {
428 DWORD len;
429 char buf[64 << 10];
430 if (!::ReadFile(f, buf, sizeof(buf), &len, NULL)) {
431 err->assign(GetLastErrorString());
432 contents->clear();
433 ::CloseHandle(f);
434 return -EIO;
435 }
436 if (len == 0)
437 break;
438 contents->append(buf, len);
439 }
440 ::CloseHandle(f);
441 return 0;
442#else
443 FILE* f = fopen(path.c_str(), "rb");
444 if (!f) {
445 err->assign(strerror(errno));
446 return -errno;
447 }
448
449#ifdef __USE_LARGEFILE64
450 struct stat64 st;
451 if (fstat64(fileno(f), &st) < 0) {
452#else
453 struct stat st;
454 if (fstat(fileno(f), &st) < 0) {
455#endif
456 err->assign(strerror(errno));
457 fclose(f);
458 return -errno;
459 }
460
461 // +1 is for the resize in ManifestParser::Load
462 contents->reserve(st.st_size + 1);
463
464 char buf[64 << 10];
465 size_t len;
466 while (!feof(f) && (len = fread(buf, 1, sizeof(buf), f)) > 0) {
467 contents->append(buf, len);
468 }
469 if (ferror(f)) {
470 err->assign(strerror(errno)); // XXX errno?
471 contents->clear();
472 fclose(f);
473 return -errno;
474 }
475 fclose(f);
476 return 0;
477#endif
478}
479
480void SetCloseOnExec(int fd) {
481#ifndef _WIN32
482 int flags = fcntl(fd, F_GETFD);
483 if (flags < 0) {
484 perror("fcntl(F_GETFD)");
485 } else {
486 if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0)
487 perror("fcntl(F_SETFD)");
488 }
489#else
490 HANDLE hd = (HANDLE) _get_osfhandle(fd);
491 if (! SetHandleInformation(hd, HANDLE_FLAG_INHERIT, 0)) {
492 fprintf(stderr, "SetHandleInformation(): %s", GetLastErrorString().c_str());
493 }
494#endif // ! _WIN32
495}
496
497
498const char* SpellcheckStringV(const string& text,
499 const vector<const char*>& words) {
500 const bool kAllowReplacements = true;
501 const int kMaxValidEditDistance = 3;
502
503 int min_distance = kMaxValidEditDistance + 1;
504 const char* result = NULL;
505 for (vector<const char*>::const_iterator i = words.begin();
506 i != words.end(); ++i) {
507 int distance = EditDistance(*i, text, kAllowReplacements,
508 kMaxValidEditDistance);
509 if (distance < min_distance) {
510 min_distance = distance;
511 result = *i;
512 }
513 }
514 return result;
515}
516
517const char* SpellcheckString(const char* text, ...) {
518 // Note: This takes a const char* instead of a string& because using
519 // va_start() with a reference parameter is undefined behavior.
520 va_list ap;
521 va_start(ap, text);
522 vector<const char*> words;
523 const char* word;
524 while ((word = va_arg(ap, const char*)))
525 words.push_back(word);
526 va_end(ap);
527 return SpellcheckStringV(text, words);
528}
529
530#ifdef _WIN32
531string GetLastErrorString() {
532 DWORD err = GetLastError();
533
534 char* msg_buf;
535 FormatMessageA(
536 FORMAT_MESSAGE_ALLOCATE_BUFFER |
537 FORMAT_MESSAGE_FROM_SYSTEM |
538 FORMAT_MESSAGE_IGNORE_INSERTS,
539 NULL,
540 err,
541 MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
542 (char*)&msg_buf,
543 0,
544 NULL);
545
546 if (msg_buf == nullptr) {
547 char fallback_msg[128] = {0};
548 snprintf(fallback_msg, sizeof(fallback_msg), "GetLastError() = %lu", err);
549 return fallback_msg;
550 }
551
552 string msg = msg_buf;
553 LocalFree(msg_buf);
554 return msg;
555}
556
557void Win32Fatal(const char* function, const char* hint) {
558 if (hint) {
559 Fatal("%s: %s (%s)", function, GetLastErrorString().c_str(), hint);
560 } else {
561 Fatal("%s: %s", function, GetLastErrorString().c_str());
562 }
563}
564#endif
565
566bool islatinalpha(int c) {
567 // isalpha() is locale-dependent.
568 return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
569}
570
571string StripAnsiEscapeCodes(const string& in) {
572 string stripped;
573 stripped.reserve(in.size());
574
575 for (size_t i = 0; i < in.size(); ++i) {
576 if (in[i] != '\33') {
577 // Not an escape code.
578 stripped.push_back(in[i]);
579 continue;
580 }
581
582 // Only strip CSIs for now.
583 if (i + 1 >= in.size()) break;
584 if (in[i + 1] != '[') continue; // Not a CSI.
585 i += 2;
586
587 // Skip everything up to and including the next [a-zA-Z].
588 while (i < in.size() && !islatinalpha(in[i]))
589 ++i;
590 }
591 return stripped;
592}
593
594#if defined(__linux__) || defined(__GLIBC__)
595std::pair<int64_t, bool> readCount(const std::string& path) {
596 std::ifstream file(path.c_str());
597 if (!file.is_open())
598 return std::make_pair(0, false);
599 int64_t n = 0;
600 file >> n;
601 if (file.good())
602 return std::make_pair(n, true);
603 return std::make_pair(0, false);
604}
605
606struct MountPoint {
607 int mountId;
608 int parentId;
609 StringPiece deviceId;
610 StringPiece root;
611 StringPiece mountPoint;
612 vector<StringPiece> options;
613 vector<StringPiece> optionalFields;
614 StringPiece fsType;
615 StringPiece mountSource;
616 vector<StringPiece> superOptions;
617 bool parse(const string& line) {
618 vector<StringPiece> pieces = SplitStringPiece(line, ' ');
619 if (pieces.size() < 10)
620 return false;
621 size_t optionalStart = 0;
622 for (size_t i = 6; i < pieces.size(); i++) {
623 if (pieces[i] == "-") {
624 optionalStart = i + 1;
625 break;
626 }
627 }
628 if (optionalStart == 0)
629 return false;
630 if (optionalStart + 3 != pieces.size())
631 return false;
632 mountId = atoi(pieces[0].AsString().c_str());
633 parentId = atoi(pieces[1].AsString().c_str());
634 deviceId = pieces[2];
635 root = pieces[3];
636 mountPoint = pieces[4];
637 options = SplitStringPiece(pieces[5], ',');
638 optionalFields =
639 vector<StringPiece>(&pieces[6], &pieces[optionalStart - 1]);
640 fsType = pieces[optionalStart];
641 mountSource = pieces[optionalStart + 1];
642 superOptions = SplitStringPiece(pieces[optionalStart + 2], ',');
643 return true;
644 }
645 string translate(string& path) const {
646 // path must be sub dir of root
647 if (path.compare(0, root.len_, root.str_, root.len_) != 0) {
648 return string();
649 }
650 path.erase(0, root.len_);
651 if (path == ".." || (path.length() > 2 && path.compare(0, 3, "../") == 0)) {
652 return string();
653 }
654 return mountPoint.AsString() + "/" + path;
655 }
656};
657
658struct CGroupSubSys {
659 int id;
660 string name;
661 vector<string> subsystems;
662 bool parse(string& line) {
663 size_t first = line.find(':');
664 if (first == string::npos)
665 return false;
666 line[first] = '\0';
667 size_t second = line.find(':', first + 1);
668 if (second == string::npos)
669 return false;
670 line[second] = '\0';
671 id = atoi(line.c_str());
672 name = line.substr(second + 1);
673 vector<StringPiece> pieces =
674 SplitStringPiece(StringPiece(line.c_str() + first + 1), ',');
675 for (size_t i = 0; i < pieces.size(); i++) {
676 subsystems.push_back(pieces[i].AsString());
677 }
678 return true;
679 }
680};
681
682map<string, string> ParseMountInfo(map<string, CGroupSubSys>& subsystems) {
683 map<string, string> cgroups;
684 ifstream mountinfo("/proc/self/mountinfo");
685 if (!mountinfo.is_open())
686 return cgroups;
687 while (!mountinfo.eof()) {
688 string line;
689 getline(mountinfo, line);
690 MountPoint mp;
691 if (!mp.parse(line))
692 continue;
693 if (mp.fsType == "cgroup") {
694 for (size_t i = 0; i < mp.superOptions.size(); i++) {
695 std::string opt = mp.superOptions[i].AsString();
696 auto subsys = subsystems.find(opt);
697 if (subsys == subsystems.end()) {
698 continue;
699 }
700 std::string newPath = mp.translate(subsys->second.name);
701 if (!newPath.empty()) {
702 cgroups.emplace(opt, newPath);
703 }
704 }
705 } else if (mp.fsType == "cgroup2") {
706 // Find cgroup2 entry in format "0::/path/to/cgroup"
707 auto subsys = std::find_if(subsystems.begin(), subsystems.end(),
708 [](const auto& sys) {
709 return sys.first == "" && sys.second.id == 0;
710 });
711 if (subsys == subsystems.end()) {
712 continue;
713 }
714 std::string path = mp.mountPoint.AsString();
715 if (subsys->second.name != "/") {
716 // Append the relative path for the cgroup to the mount point
717 path.append(subsys->second.name);
718 }
719 cgroups.emplace("cgroup2", path);
720 }
721 }
722 return cgroups;
723}
724
725map<string, CGroupSubSys> ParseSelfCGroup() {
726 map<string, CGroupSubSys> cgroups;
727 ifstream cgroup("/proc/self/cgroup");
728 if (!cgroup.is_open())
729 return cgroups;
730 string line;
731 while (!cgroup.eof()) {
732 getline(cgroup, line);
733 CGroupSubSys subsys;
734 if (!subsys.parse(line))
735 continue;
736 for (size_t i = 0; i < subsys.subsystems.size(); i++) {
737 cgroups.insert(make_pair(subsys.subsystems[i], subsys));
738 }
739 }
740 return cgroups;
741}
742
743int ParseCgroupV1(std::string& path) {
744 std::pair<int64_t, bool> quota = readCount(path + "/cpu.cfs_quota_us");
745 if (!quota.second || quota.first == -1)
746 return -1;
747 std::pair<int64_t, bool> period = readCount(path + "/cpu.cfs_period_us");
748 if (!period.second)
749 return -1;
750 if (period.first == 0)
751 return -1;
752 return quota.first / period.first;
753}
754
755int ParseCgroupV2(std::string& path) {
756 // Read CPU quota from cgroup v2
757 std::ifstream cpu_max(path + "/cpu.max");
758 if (!cpu_max.is_open()) {
759 return -1;
760 }
761 std::string max_line;
762 if (!std::getline(cpu_max, max_line) || max_line.empty()) {
763 return -1;
764 }
765 // Format is "quota period" or "max period"
766 size_t space_pos = max_line.find(' ');
767 if (space_pos == string::npos) {
768 return -1;
769 }
770 std::string quota_str = max_line.substr(0, space_pos);
771 std::string period_str = max_line.substr(space_pos + 1);
772 if (quota_str == "max") {
773 return -1; // No CPU limit set
774 }
775 // Convert quota string to integer
776 char* quota_end = nullptr;
777 errno = 0;
778 int64_t quota = strtoll(quota_str.c_str(), &quota_end, 10);
779 // Check for conversion errors
780 if (errno == ERANGE || quota_end == quota_str.c_str() || *quota_end != '\0' ||
781 quota <= 0) {
782 return -1;
783 }
784 // Convert period string to integer
785 char* period_end = nullptr;
786 errno = 0;
787 int64_t period = strtoll(period_str.c_str(), &period_end, 10);
788 // Check for conversion errors
789 if (errno == ERANGE || period_end == period_str.c_str() ||
790 *period_end != '\0' || period <= 0) {
791 return -1;
792 }
793 return quota / period;
794}
795
796int ParseCPUFromCGroup() {
797 auto subsystems = ParseSelfCGroup();
798 auto cgroups = ParseMountInfo(subsystems);
799
800 // Prefer cgroup v2 if both v1 and v2 should be present
801 const auto cgroup2 = cgroups.find("cgroup2");
802 if (cgroup2 != cgroups.end()) {
803 return ParseCgroupV2(cgroup2->second);
804 }
805
806 const auto cpu = cgroups.find("cpu");
807 if (cpu != cgroups.end()) {
808 return ParseCgroupV1(cpu->second);
809 }
810 return -1;
811}
812#endif
813
815#ifdef _WIN32
816 DWORD cpuCount = 0;
817#ifndef _WIN64
818 // Need to use GetLogicalProcessorInformationEx to get real core count on
819 // machines with >64 cores. See https://stackoverflow.com/a/31209344/21475
820 DWORD len = 0;
821 if (!GetLogicalProcessorInformationEx(RelationProcessorCore, nullptr, &len)
822 && GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
823 std::vector<char> buf(len);
824 int cores = 0;
825 if (GetLogicalProcessorInformationEx(RelationProcessorCore,
826 reinterpret_cast<PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX>(
827 buf.data()), &len)) {
828 for (DWORD i = 0; i < len; ) {
829 auto info = reinterpret_cast<PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX>(
830 buf.data() + i);
831 if (info->Relationship == RelationProcessorCore &&
832 info->Processor.GroupCount == 1) {
833 for (KAFFINITY core_mask = info->Processor.GroupMask[0].Mask;
834 core_mask; core_mask >>= 1) {
835 cores += (core_mask & 1);
836 }
837 }
838 i += info->Size;
839 }
840 if (cores != 0) {
841 cpuCount = cores;
842 }
843 }
844 }
845#endif
846 if (cpuCount == 0) {
847 cpuCount = GetActiveProcessorCount(ALL_PROCESSOR_GROUPS);
848 }
849 JOBOBJECT_CPU_RATE_CONTROL_INFORMATION info;
850 // reference:
851 // https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-jobobject_cpu_rate_control_information
852 if (QueryInformationJobObject(NULL, JobObjectCpuRateControlInformation, &info,
853 sizeof(info), NULL)) {
854 if (info.ControlFlags & (JOB_OBJECT_CPU_RATE_CONTROL_ENABLE |
855 JOB_OBJECT_CPU_RATE_CONTROL_HARD_CAP)) {
856 return cpuCount * info.CpuRate / 10000;
857 }
858 }
859 return cpuCount;
860#else
861 int cgroupCount = -1;
862 int schedCount = -1;
863#if defined(__linux__) || defined(__GLIBC__)
864 cgroupCount = ParseCPUFromCGroup();
865#endif
866 // The number of exposed processors might not represent the actual number of
867 // processors threads can run on. This happens when a CPU set limitation is
868 // active, see https://github.com/ninja-build/ninja/issues/1278
869#if defined(__FreeBSD__)
870 cpuset_t mask;
871 CPU_ZERO(&mask);
872 if (cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, sizeof(mask),
873 &mask) == 0) {
874 return CPU_COUNT(&mask);
875 }
876#elif defined(CPU_COUNT)
877 cpu_set_t set;
878 if (sched_getaffinity(getpid(), sizeof(set), &set) == 0) {
879 schedCount = CPU_COUNT(&set);
880 }
881#endif
882 if (cgroupCount >= 0 && schedCount >= 0) return std::min(cgroupCount, schedCount);
883 if (cgroupCount < 0 && schedCount < 0)
884 return static_cast<int>(sysconf(_SC_NPROCESSORS_ONLN));
885 return std::max(cgroupCount, schedCount);
886#endif
887}
888
889#if defined(_WIN32) || defined(__CYGWIN__)
890static double CalculateProcessorLoad(uint64_t idle_ticks, uint64_t total_ticks)
891{
892 static uint64_t previous_idle_ticks = 0;
893 static uint64_t previous_total_ticks = 0;
894 static double previous_load = -0.0;
895
896 uint64_t idle_ticks_since_last_time = idle_ticks - previous_idle_ticks;
897 uint64_t total_ticks_since_last_time = total_ticks - previous_total_ticks;
898
899 bool first_call = (previous_total_ticks == 0);
900 bool ticks_not_updated_since_last_call = (total_ticks_since_last_time == 0);
901
902 double load;
903 if (first_call || ticks_not_updated_since_last_call) {
904 load = previous_load;
905 } else {
906 // Calculate load.
907 double idle_to_total_ratio =
908 ((double)idle_ticks_since_last_time) / total_ticks_since_last_time;
909 double load_since_last_call = 1.0 - idle_to_total_ratio;
910
911 // Filter/smooth result when possible.
912 if(previous_load > 0) {
913 load = 0.9 * previous_load + 0.1 * load_since_last_call;
914 } else {
915 load = load_since_last_call;
916 }
917 }
918
919 previous_load = load;
920 previous_total_ticks = total_ticks;
921 previous_idle_ticks = idle_ticks;
922
923 return load;
924}
925
926static uint64_t FileTimeToTickCount(const FILETIME & ft)
927{
928 uint64_t high = (((uint64_t)(ft.dwHighDateTime)) << 32);
929 uint64_t low = ft.dwLowDateTime;
930 return (high | low);
931}
932
933double GetLoadAverage() {
934 FILETIME idle_time, kernel_time, user_time;
935 BOOL get_system_time_succeeded =
936 GetSystemTimes(&idle_time, &kernel_time, &user_time);
937
938 double posix_compatible_load;
939 if (get_system_time_succeeded) {
940 uint64_t idle_ticks = FileTimeToTickCount(idle_time);
941
942 // kernel_time from GetSystemTimes already includes idle_time.
943 uint64_t total_ticks =
944 FileTimeToTickCount(kernel_time) + FileTimeToTickCount(user_time);
945
946 double processor_load = CalculateProcessorLoad(idle_ticks, total_ticks);
947 posix_compatible_load = processor_load * GetProcessorCount();
948
949 } else {
950 posix_compatible_load = -0.0;
951 }
952
953 return posix_compatible_load;
954}
955#elif defined(__PASE__)
956double GetLoadAverage() {
957 return -0.0f;
958}
959#elif defined(_AIX)
960double GetLoadAverage() {
961 perfstat_cpu_total_t cpu_stats;
962 if (perfstat_cpu_total(NULL, &cpu_stats, sizeof(cpu_stats), 1) < 0) {
963 return -0.0f;
964 }
965
966 // Calculation taken from comment in libperfstats.h
967 return double(cpu_stats.loadavg[0]) / double(1 << SBITS);
968}
969#elif defined(__UCLIBC__) || (defined(__BIONIC__) && __ANDROID_API__ < 29)
970double GetLoadAverage() {
971 struct sysinfo si;
972 if (sysinfo(&si) != 0)
973 return -0.0f;
974 return 1.0 / (1 << SI_LOAD_SHIFT) * si.loads[0];
975}
976#elif defined(__HAIKU__)
977double GetLoadAverage() {
978 return -0.0f;
979}
980#else
982 double loadavg[3] = { 0.0f, 0.0f, 0.0f };
983 if (getloadavg(loadavg, 3) < 0) {
984 // Maybe we should return an error here or the availability of
985 // getloadavg(3) should be checked when ninja is configured.
986 return -0.0f;
987 }
988 return loadavg[0];
989}
990#endif // _WIN32
991
992std::string GetWorkingDirectory() {
993 std::string ret;
994 char* success = NULL;
995 do {
996 ret.resize(ret.size() + 1024);
997 errno = 0;
998 success = getcwd(&ret[0], ret.size());
999 } while (!success && errno == ERANGE);
1000 if (!success) {
1001 Fatal("cannot determine working directory: %s", strerror(errno));
1002 }
1003 ret.resize(strlen(&ret[0]));
1004 return ret;
1005}
1006
1007bool Truncate(const string& path, size_t size, string* err) {
1008#ifdef _WIN32
1009 int fh = _sopen(path.c_str(), _O_RDWR | _O_CREAT, _SH_DENYNO,
1010 _S_IREAD | _S_IWRITE);
1011 int success = _chsize(fh, size);
1012 _close(fh);
1013#else
1014 int success = truncate(path.c_str(), size);
1015#endif
1016 // Both truncate() and _chsize() return 0 on success and set errno and return
1017 // -1 on failure.
1018 if (success < 0) {
1019 *err = strerror(errno);
1020 return false;
1021 }
1022 return true;
1023}
1024
1025int platformAwareUnlink(const char* filename) {
1026 #ifdef _WIN32
1027 return _unlink(filename);
1028 #else
1029 return unlink(filename);
1030 #endif
1031}
int EditDistance(const StringPiece &s1, const StringPiece &s2, bool allow_replacements, int max_edit_distance)
Definition hash_map.h:26
vector< StringPiece > SplitStringPiece(StringPiece input, char sep)
const char * str_
std::string AsString() const
Convert the slice into a full-fledged std::string, copying the data into a new string.
int GetProcessorCount()
Definition util.cc:814
void GetWin32EscapedString(const string &input, string *result)
Definition util.cc:380
void Error(const char *msg, va_list ap)
Definition util.cc:98
static bool IsKnownShellSafeCharacter(char ch)
Definition util.cc:312
static bool StringNeedsShellEscaping(const string &input)
Definition util.cc:339
int platformAwareUnlink(const char *filename)
Definition util.cc:1025
bool islatinalpha(int c)
Definition util.cc:566
static bool IsKnownWin32SafeCharacter(char ch)
Definition util.cc:329
bool Truncate(const string &path, size_t size, string *err)
Definition util.cc:1007
void GetShellEscapedString(const string &input, string *result)
Definition util.cc:353
std::string GetWorkingDirectory()
a wrapper for getcwd()
Definition util.cc:992
void Warning(const char *msg, va_list ap)
Definition util.cc:85
void Info(const char *msg, va_list ap)
Definition util.cc:111
static bool IsPathSeparator(char c)
Definition util.cc:133
void SetCloseOnExec(int fd)
Mark a file descriptor to not be inherited on exec()s.
Definition util.cc:480
void CanonicalizePath(string *path, uint64_t *slash_bits)
Definition util.cc:124
const char * SpellcheckStringV(const string &text, const vector< const char * > &words)
Definition util.cc:498
string StripAnsiEscapeCodes(const string &in)
Definition util.cc:571
static bool StringNeedsWin32Escaping(const string &input)
Definition util.cc:346
void Fatal(const char *msg,...)
Log a fatal message and exit.
Definition util.cc:67
const char * SpellcheckString(const char *text,...)
Like SpellcheckStringV, but takes a NULL-terminated list.
Definition util.cc:517
int ReadFile(const string &path, string *contents, string *err)
Definition util.cc:415
double GetLoadAverage()
Definition util.cc:981
#define NINJA_FALLTHROUGH
Definition util.h:48
unsigned long long uint64_t
Definition win32port.h:29
signed long long int64_t
A 64-bit integer type.
Definition win32port.h:28