summaryrefslogtreecommitdiffstats
path: root/src/util.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/util.cc')
-rw-r--r--src/util.cc133
1 files changed, 113 insertions, 20 deletions
diff --git a/src/util.cc b/src/util.cc
index 4d0ceae..720ccbd 100644
--- a/src/util.cc
+++ b/src/util.cc
@@ -88,19 +88,33 @@ void Error(const char* msg, ...) {
fprintf(stderr, "\n");
}
-bool CanonicalizePath(string* path, string* err) {
+bool CanonicalizePath(string* path, unsigned int* slash_bits, string* err) {
METRIC_RECORD("canonicalize str");
size_t len = path->size();
char* str = 0;
if (len > 0)
str = &(*path)[0];
- if (!CanonicalizePath(str, &len, err))
+ if (!CanonicalizePath(str, &len, slash_bits, err))
return false;
path->resize(len);
return true;
}
-bool CanonicalizePath(char* path, size_t* len, string* err) {
+#ifdef _WIN32
+static unsigned int ShiftOverBit(int offset, unsigned int bits) {
+ // e.g. for |offset| == 2:
+ // | ... 9 8 7 6 5 4 3 2 1 0 |
+ // \_________________/ \_/
+ // above below
+ // So we drop the bit at offset and move above "down" into its place.
+ unsigned int above = bits & ~((1 << (offset + 1)) - 1);
+ unsigned int below = bits & ((1 << offset) - 1);
+ return (above >> 1) | below;
+}
+#endif
+
+bool CanonicalizePath(char* path, size_t* len, unsigned int* slash_bits,
+ string* err) {
// WARNING: this function is performance-critical; please benchmark
// any changes you make to it.
METRIC_RECORD("canonicalize path");
@@ -118,12 +132,37 @@ bool CanonicalizePath(char* path, size_t* len, string* err) {
const char* src = start;
const char* end = start + *len;
+#ifdef _WIN32
+ unsigned int bits = 0;
+ unsigned int bits_mask = 1;
+ int bits_offset = 0;
+ // Convert \ to /, setting a bit in |bits| for each \ encountered.
+ for (char* c = path; c < end; ++c) {
+ switch (*c) {
+ case '\\':
+ bits |= bits_mask;
+ *c = '/';
+ // Intentional fallthrough.
+ case '/':
+ bits_mask <<= 1;
+ bits_offset++;
+ }
+ }
+ if (bits_offset > 32) {
+ *err = "too many path components";
+ return false;
+ }
+ bits_offset = 0;
+#endif
+
if (*src == '/') {
#ifdef _WIN32
+ bits_offset++;
// network path starts with //
if (*len > 1 && *(src + 1) == '/') {
src += 2;
dst += 2;
+ bits_offset++;
} else {
++src;
++dst;
@@ -139,6 +178,9 @@ bool CanonicalizePath(char* path, size_t* len, string* err) {
if (src + 1 == end || src[1] == '/') {
// '.' component; eliminate.
src += 2;
+#ifdef _WIN32
+ bits = ShiftOverBit(bits_offset, bits);
+#endif
continue;
} else if (src[1] == '.' && (src + 2 == end || src[2] == '/')) {
// '..' component. Back up if possible.
@@ -146,6 +188,11 @@ bool CanonicalizePath(char* path, size_t* len, string* err) {
dst = components[component_count - 1];
src += 3;
--component_count;
+#ifdef _WIN32
+ bits = ShiftOverBit(bits_offset, bits);
+ bits_offset--;
+ bits = ShiftOverBit(bits_offset, bits);
+#endif
} else {
*dst++ = *src++;
*dst++ = *src++;
@@ -157,6 +204,9 @@ bool CanonicalizePath(char* path, size_t* len, string* err) {
if (*src == '/') {
src++;
+#ifdef _WIN32
+ bits = ShiftOverBit(bits_offset, bits);
+#endif
continue;
}
@@ -167,6 +217,9 @@ bool CanonicalizePath(char* path, size_t* len, string* err) {
while (*src != '/' && src != end)
*dst++ = *src++;
+#ifdef _WIN32
+ bits_offset++;
+#endif
*dst++ = *src++; // Copy '/' or final \0 character as well.
}
@@ -176,6 +229,11 @@ bool CanonicalizePath(char* path, size_t* len, string* err) {
}
*len = dst - start - 1;
+#ifdef _WIN32
+ *slash_bits = bits;
+#else
+ *slash_bits = 0;
+#endif
return true;
}
@@ -283,7 +341,38 @@ void GetWin32EscapedString(const string& input, string* result) {
}
int ReadFile(const string& path, string* contents, string* err) {
- FILE* f = fopen(path.c_str(), "r");
+#ifdef _WIN32
+ // This makes a ninja run on a set of 1500 manifest files about 4% faster
+ // than using the generic fopen code below.
+ err->clear();
+ HANDLE f = ::CreateFile(path.c_str(),
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_SEQUENTIAL_SCAN,
+ NULL);
+ if (f == INVALID_HANDLE_VALUE) {
+ err->assign(GetLastErrorString());
+ return -ENOENT;
+ }
+
+ for (;;) {
+ DWORD len;
+ char buf[64 << 10];
+ if (!::ReadFile(f, buf, sizeof(buf), &len, NULL)) {
+ err->assign(GetLastErrorString());
+ contents->clear();
+ return -1;
+ }
+ if (len == 0)
+ break;
+ contents->append(buf, len);
+ }
+ ::CloseHandle(f);
+ return 0;
+#else
+ FILE* f = fopen(path.c_str(), "rb");
if (!f) {
err->assign(strerror(errno));
return -errno;
@@ -302,6 +391,7 @@ int ReadFile(const string& path, string* contents, string* err) {
}
fclose(f);
return 0;
+#endif
}
void SetCloseOnExec(int fd) {
@@ -423,33 +513,34 @@ static double CalculateProcessorLoad(uint64_t idle_ticks, uint64_t total_ticks)
static uint64_t previous_idle_ticks = 0;
static uint64_t previous_total_ticks = 0;
static double previous_load = -0.0;
-
+
uint64_t idle_ticks_since_last_time = idle_ticks - previous_idle_ticks;
uint64_t total_ticks_since_last_time = total_ticks - previous_total_ticks;
-
+
bool first_call = (previous_total_ticks == 0);
bool ticks_not_updated_since_last_call = (total_ticks_since_last_time == 0);
-
+
double load;
if (first_call || ticks_not_updated_since_last_call) {
load = previous_load;
} else {
- //calculate load
- double idle_to_total_ratio = ((double)idle_ticks_since_last_time) / total_ticks_since_last_time;
+ // Calculate load.
+ double idle_to_total_ratio =
+ ((double)idle_ticks_since_last_time) / total_ticks_since_last_time;
double load_since_last_call = 1.0 - idle_to_total_ratio;
-
- //filter/smooth result when possible
+
+ // Filter/smooth result when possible.
if(previous_load > 0) {
load = 0.9 * previous_load + 0.1 * load_since_last_call;
} else {
load = load_since_last_call;
}
}
-
+
previous_load = load;
previous_total_ticks = total_ticks;
previous_idle_ticks = idle_ticks;
-
+
return load;
}
@@ -462,22 +553,24 @@ static uint64_t FileTimeToTickCount(const FILETIME & ft)
double GetLoadAverage() {
FILETIME idle_time, kernel_time, user_time;
- BOOL get_system_time_succeeded = GetSystemTimes(&idle_time, &kernel_time, &user_time);
-
+ BOOL get_system_time_succeeded =
+ GetSystemTimes(&idle_time, &kernel_time, &user_time);
+
double posix_compatible_load;
if (get_system_time_succeeded) {
uint64_t idle_ticks = FileTimeToTickCount(idle_time);
-
- //kernel_time from GetSystemTimes already includes idle_time
- uint64_t total_ticks = FileTimeToTickCount(kernel_time) + FileTimeToTickCount(user_time);
-
+
+ // kernel_time from GetSystemTimes already includes idle_time.
+ uint64_t total_ticks =
+ FileTimeToTickCount(kernel_time) + FileTimeToTickCount(user_time);
+
double processor_load = CalculateProcessorLoad(idle_ticks, total_ticks);
posix_compatible_load = processor_load * GetProcessorCount();
} else {
posix_compatible_load = -0.0;
}
-
+
return posix_compatible_load;
}
#else