Coverage Report

Created: 2023-06-07 06:44

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