20 #elif defined( _WIN32) 34 #include <sys/types.h> 43 #if defined(__APPLE__) || defined(__FreeBSD__) 44 #include <sys/sysctl.h> 45 #elif defined(__SVR4) && defined(__sun) 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> 57 #if defined(__FreeBSD__) 58 #include <sys/cpuset.h> 65 void Fatal(
const char* msg, ...) {
67 fprintf(stderr,
"ninja: fatal: ");
69 vfprintf(stderr, msg, ap);
71 fprintf(stderr,
"\n");
83 void Warning(
const char* msg, va_list ap) {
84 fprintf(stderr,
"ninja: warning: ");
85 vfprintf(stderr, msg, ap);
86 fprintf(stderr,
"\n");
96 void Error(
const char* msg, va_list ap) {
97 fprintf(stderr,
"ninja: error: ");
98 vfprintf(stderr, msg, ap);
99 fprintf(stderr,
"\n");
109 void Info(
const char* msg, va_list ap) {
110 fprintf(stdout,
"ninja: ");
111 vfprintf(stdout, msg, ap);
112 fprintf(stdout,
"\n");
115 void Info(
const char* msg, ...) {
123 size_t len = path->size();
133 return c ==
'/' || c ==
'\\';
146 const int kMaxPathComponents = 60;
147 char* components[kMaxPathComponents];
148 int component_count = 0;
152 const char* src = start;
153 const char* end = start + *len;
178 }
else if (src[1] ==
'.' && (src + 2 == end ||
IsPathSeparator(src[2]))) {
180 if (component_count > 0) {
181 dst = components[component_count - 1];
198 if (component_count == kMaxPathComponents)
199 Fatal(
"path has too many components : %s", path);
200 components[component_count] = dst;
213 *len = dst - start - 1;
218 for (
char* c = start; c < start + *len; ++c) {
236 if (
'A' <= ch && ch <=
'Z')
return true;
237 if (
'a' <= ch && ch <=
'z')
return true;
238 if (
'0' <= ch && ch <=
'9')
return true;
263 for (
size_t i = 0; i < input.size(); ++i) {
270 for (
size_t i = 0; i < input.size(); ++i) {
280 result->append(input);
284 const char kQuote =
'\'';
285 const char kEscapeSequence[] =
"'\\'";
287 result->push_back(kQuote);
289 string::const_iterator span_begin = input.begin();
290 for (string::const_iterator it = input.begin(), end = input.end(); it != end;
293 result->append(span_begin, it);
294 result->append(kEscapeSequence);
298 result->append(span_begin, input.end());
299 result->push_back(kQuote);
306 result->append(input);
310 const char kQuote =
'"';
311 const char kBackslash =
'\\';
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;
320 ++consecutive_backslash_count;
323 result->append(span_begin, it);
324 result->append(consecutive_backslash_count + 1, kBackslash);
326 consecutive_backslash_count = 0;
329 consecutive_backslash_count = 0;
333 result->append(span_begin, input.end());
334 result->append(consecutive_backslash_count, kBackslash);
335 result->push_back(kQuote);
338 int ReadFile(
const string& path,
string* contents,
string* err) {
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());
353 if (!::
ReadFile(f, buf,
sizeof(buf), &len, NULL)) {
354 err->assign(GetLastErrorString());
361 contents->append(buf, len);
366 FILE* f = fopen(path.c_str(),
"rb");
368 err->assign(strerror(errno));
373 if (fstat(fileno(f), &st) < 0) {
374 err->assign(strerror(errno));
380 contents->reserve(st.st_size + 1);
384 while (!feof(f) && (len = fread(buf, 1,
sizeof(buf), f)) > 0) {
385 contents->append(buf, len);
388 err->assign(strerror(errno));
400 int flags = fcntl(fd, F_GETFD);
402 perror(
"fcntl(F_GETFD)");
404 if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0)
405 perror(
"fcntl(F_SETFD)");
408 HANDLE hd = (HANDLE) _get_osfhandle(fd);
409 if (! SetHandleInformation(hd, HANDLE_FLAG_INHERIT, 0)) {
410 fprintf(stderr,
"SetHandleInformation(): %s", GetLastErrorString().c_str());
417 const vector<const char*>& words) {
418 const bool kAllowReplacements =
true;
419 const int kMaxValidEditDistance = 3;
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;
440 vector<const char*> words;
442 while ((word = va_arg(ap,
const char*)))
443 words.push_back(word);
449 string GetLastErrorString() {
450 DWORD err = GetLastError();
454 FORMAT_MESSAGE_ALLOCATE_BUFFER |
455 FORMAT_MESSAGE_FROM_SYSTEM |
456 FORMAT_MESSAGE_IGNORE_INSERTS,
459 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
463 string msg = msg_buf;
468 void Win32Fatal(
const char*
function,
const char* hint) {
470 Fatal(
"%s: %s (%s)",
function, GetLastErrorString().c_str(), hint);
472 Fatal(
"%s: %s",
function, GetLastErrorString().c_str());
479 return (c >=
'a' && c <=
'z') || (c >=
'A' && c <=
'Z');
484 stripped.reserve(in.size());
486 for (
size_t i = 0; i < in.size(); ++i) {
487 if (in[i] !=
'\33') {
489 stripped.push_back(in[i]);
494 if (i + 1 >= in.size())
break;
495 if (in[i + 1] !=
'[')
continue;
505 #if defined(linux) || defined(__GLIBC__) 506 std::pair<int64_t, bool> readCount(
const std::string& path) {
507 std::ifstream file(path.c_str());
509 return std::make_pair(0,
false);
513 return std::make_pair(n,
true);
514 return std::make_pair(0,
false);
523 vector<StringPiece> options;
524 vector<StringPiece> optionalFields;
527 vector<StringPiece> superOptions;
528 bool parse(
const string& line) {
530 if (pieces.size() < 10)
532 size_t optionalStart = 0;
533 for (
size_t i = 6; i < pieces.size(); i++) {
534 if (pieces[i] ==
"-") {
535 optionalStart = i + 1;
539 if (optionalStart == 0)
541 if (optionalStart + 3 != pieces.size())
543 mountId = atoi(pieces[0].AsString().c_str());
544 parentId = atoi(pieces[1].AsString().c_str());
545 deviceId = pieces[2];
547 mountPoint = pieces[4];
550 vector<StringPiece>(&pieces[6], &pieces[optionalStart - 1]);
551 fsType = pieces[optionalStart];
552 mountSource = pieces[optionalStart + 1];
556 string translate(
string& path)
const {
558 if (path.compare(0, root.
len_, root.
str_, root.
len_) != 0) {
561 path.erase(0, root.
len_);
562 if (path ==
".." || (path.length() > 2 && path.compare(0, 3,
"../") == 0)) {
565 return mountPoint.
AsString() +
"/" + path;
569 struct CGroupSubSys {
572 vector<string> subsystems;
573 bool parse(
string& line) {
574 size_t first = line.find(
':');
575 if (first == string::npos)
578 size_t second = line.find(
':', first + 1);
579 if (second == string::npos)
582 id = atoi(line.c_str());
583 name = line.substr(second + 1);
584 vector<StringPiece> pieces =
586 for (
size_t i = 0; i < pieces.size(); i++) {
587 subsystems.push_back(pieces[i].AsString());
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())
598 while (!mountinfo.eof()) {
600 getline(mountinfo, line);
604 if (mp.fsType !=
"cgroup")
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())
611 string newPath = mp.translate(subsys->second.name);
612 if (!newPath.empty())
613 cgroups.insert(make_pair(opt, newPath));
619 map<string, CGroupSubSys> ParseSelfCGroup() {
620 map<string, CGroupSubSys> cgroups;
621 ifstream cgroup(
"/proc/self/cgroup");
622 if (!cgroup.is_open())
625 while (!cgroup.eof()) {
626 getline(cgroup, line);
628 if (!subsys.parse(line))
630 for (
size_t i = 0; i < subsys.subsystems.size(); i++) {
631 cgroups.insert(make_pair(subsys.subsystems[i], subsys));
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())
643 std::pair<int64_t, bool> quota = readCount(cpu->second +
"/cpu.cfs_quota_us");
644 if (!quota.second || quota.first == -1)
646 std::pair<int64_t, bool> period =
647 readCount(cpu->second +
"/cpu.cfs_period_us");
650 if (period.first == 0)
652 return quota.first / period.first;
663 if (!GetLogicalProcessorInformationEx(RelationProcessorCore,
nullptr, &len)
664 && GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
665 std::vector<char> buf(len);
667 if (GetLogicalProcessorInformationEx(RelationProcessorCore,
668 reinterpret_cast<PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX>(
669 buf.data()), &len)) {
670 for (DWORD i = 0; i < len; ) {
671 auto info =
reinterpret_cast<PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
>(
673 if (info->Relationship == RelationProcessorCore &&
674 info->Processor.GroupCount == 1) {
675 for (KAFFINITY core_mask = info->Processor.GroupMask[0].Mask;
676 core_mask; core_mask >>= 1) {
677 cores += (core_mask & 1);
689 cpuCount = GetActiveProcessorCount(ALL_PROCESSOR_GROUPS);
691 JOBOBJECT_CPU_RATE_CONTROL_INFORMATION info;
694 if (QueryInformationJobObject(NULL, JobObjectCpuRateControlInformation, &info,
695 sizeof(info), NULL)) {
696 if (info.ControlFlags & (JOB_OBJECT_CPU_RATE_CONTROL_ENABLE |
697 JOB_OBJECT_CPU_RATE_CONTROL_HARD_CAP)) {
698 return cpuCount * info.CpuRate / 10000;
703 int cgroupCount = -1;
705 #if defined(linux) || defined(__GLIBC__) 706 cgroupCount = ParseCPUFromCGroup();
711 #if defined(__FreeBSD__) 714 if (cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, -1,
sizeof(mask),
716 return CPU_COUNT(&mask);
718 #elif defined(CPU_COUNT) 720 if (sched_getaffinity(getpid(),
sizeof(
set), &
set) == 0) {
721 schedCount = CPU_COUNT(&
set);
724 if (cgroupCount >= 0 && schedCount >= 0)
return std::min(cgroupCount, schedCount);
725 if (cgroupCount < 0 && schedCount < 0)
return sysconf(_SC_NPROCESSORS_ONLN);
726 return std::max(cgroupCount, schedCount);
730 #if defined(_WIN32) || defined(__CYGWIN__) 731 static double CalculateProcessorLoad(
uint64_t idle_ticks,
uint64_t total_ticks)
733 static uint64_t previous_idle_ticks = 0;
734 static uint64_t previous_total_ticks = 0;
735 static double previous_load = -0.0;
737 uint64_t idle_ticks_since_last_time = idle_ticks - previous_idle_ticks;
738 uint64_t total_ticks_since_last_time = total_ticks - previous_total_ticks;
740 bool first_call = (previous_total_ticks == 0);
741 bool ticks_not_updated_since_last_call = (total_ticks_since_last_time == 0);
744 if (first_call || ticks_not_updated_since_last_call) {
745 load = previous_load;
748 double idle_to_total_ratio =
749 ((double)idle_ticks_since_last_time) / total_ticks_since_last_time;
750 double load_since_last_call = 1.0 - idle_to_total_ratio;
753 if(previous_load > 0) {
754 load = 0.9 * previous_load + 0.1 * load_since_last_call;
756 load = load_since_last_call;
760 previous_load = load;
761 previous_total_ticks = total_ticks;
762 previous_idle_ticks = idle_ticks;
767 static uint64_t FileTimeToTickCount(
const FILETIME & ft)
775 FILETIME idle_time, kernel_time, user_time;
776 BOOL get_system_time_succeeded =
777 GetSystemTimes(&idle_time, &kernel_time, &user_time);
779 double posix_compatible_load;
780 if (get_system_time_succeeded) {
781 uint64_t idle_ticks = FileTimeToTickCount(idle_time);
785 FileTimeToTickCount(kernel_time) + FileTimeToTickCount(user_time);
787 double processor_load = CalculateProcessorLoad(idle_ticks, total_ticks);
791 posix_compatible_load = -0.0;
794 return posix_compatible_load;
796 #elif defined(__PASE__) 802 perfstat_cpu_total_t cpu_stats;
803 if (perfstat_cpu_total(NULL, &cpu_stats,
sizeof(cpu_stats), 1) < 0) {
808 return double(cpu_stats.loadavg[0]) / double(1 << SBITS);
810 #elif defined(__UCLIBC__) || (defined(__BIONIC__) && __ANDROID_API__ < 29) 813 if (sysinfo(&si) != 0)
815 return 1.0 / (1 << SI_LOAD_SHIFT) * si.loads[0];
817 #elif defined(__HAIKU__) 823 double loadavg[3] = { 0.0f, 0.0f, 0.0f };
824 if (getloadavg(loadavg, 3) < 0) {
838 case 3:
return "...";
840 const int kMargin = 3;
842 if (result.size() > width) {
843 size_t elide_size = (width - kMargin) / 2;
844 result = result.substr(0, elide_size)
846 + result.substr(result.size() - elide_size, elide_size);
851 bool Truncate(
const string& path,
size_t size,
string* err) {
853 int fh = _sopen(path.c_str(), _O_RDWR | _O_CREAT, _SH_DENYNO,
854 _S_IREAD | _S_IWRITE);
855 int success = _chsize(fh, size);
858 int success = truncate(path.c_str(), size);
863 *err = strerror(errno);
vector< StringPiece > SplitStringPiece(StringPiece input, char sep)
const char * SpellcheckStringV(const string &text, const vector< const char *> &words)
static bool StringNeedsShellEscaping(const string &input)
static bool IsPathSeparator(char c)
std::string AsString() const
Convert the slice into a full-fledged std::string, copying the data into a new string.
const char * SpellcheckString(const char *text,...)
Like SpellcheckStringV, but takes a NULL-terminated list.
void GetWin32EscapedString(const string &input, string *result)
StringPiece represents a slice of a string whose memory is managed externally.
void GetShellEscapedString(const string &input, string *result)
void SetCloseOnExec(int fd)
Mark a file descriptor to not be inherited on exec()s.
static bool IsKnownWin32SafeCharacter(char ch)
signed long long int64_t
A 64-bit integer type.
static bool StringNeedsWin32Escaping(const string &input)
#define NINJA_FALLTHROUGH
int ReadFile(const string &path, string *contents, string *err)
void Info(const char *msg, va_list ap)
static bool IsKnownShellSafeCharacter(char ch)
bool Truncate(const string &path, size_t size, string *err)
string StripAnsiEscapeCodes(const string &in)
void Fatal(const char *msg,...)
Log a fatal message and exit.
void Warning(const char *msg, va_list ap)
void CanonicalizePath(string *path, uint64_t *slash_bits)
void Error(const char *msg, va_list ap)
unsigned long long uint64_t
int EditDistance(const StringPiece &s1, const StringPiece &s2, bool allow_replacements, int max_edit_distance)
string ElideMiddle(const string &str, size_t width)