From: Nico Weber Date: Thu, 10 May 2012 05:20:52 +0000 (-0700) Subject: Switch LineReader from fgets() to just fread(). X-Git-Tag: release-120715~34^2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=e5b244dd656eaa7b99fcbd5abddc94a82d14950c;p=platform%2Fupstream%2Fninja.git Switch LineReader from fgets() to just fread(). fgets() needs to search for a \n in the input, and LineReader's strstr() did the same work again. By using fread() directly, this duplicate work can be saved. (I tried using readline() / fgetln() for the same saving, but those functions are not standard, and were slower than the code in this CL.) Results from running build_log_perftest, on OS X: Before: min 369ms max 372ms avg 370.4ms After: min 243ms max 247ms avg 244.8ms On Windows: Before: min 796ms max 904ms avg 858.0ms After: min 359ms max 375ms avg 371.4ms On Linux: Before: min 161ms max 169ms avg 164.8ms Before: min 130ms max 137ms avg 132.6ms --- diff --git a/src/build_log.cc b/src/build_log.cc index 01fb001..5803ada 100644 --- a/src/build_log.cc +++ b/src/build_log.cc @@ -113,24 +113,52 @@ void BuildLog::Close() { class LineReader { public: - explicit LineReader(FILE* file) : file_(file) {} + explicit LineReader(FILE* file) + : file_(file), buf_end_(buf_), line_start_(buf_), line_end_(NULL) {} // Reads a \n-terminated line from the file passed to the constructor. // On return, *line_start points to the beginning of the next line, and // *line_end points to the \n at the end of the line. If no newline is seen // in a fixed buffer size, *line_end is set to NULL. Returns false on EOF. bool ReadLine(char** line_start, char** line_end) { - if (!fgets(buf_, sizeof(buf_), file_)) - return false; + if (line_start_ >= buf_end_ || !line_end_) { + // Buffer empty, refill. + size_t size_read = fread(buf_, 1, sizeof(buf_), file_); + if (!size_read) + return false; + line_start_ = buf_; + buf_end_ = buf_ + size_read; + } else { + // Advance to next line in buffer. + line_start_ = line_end_ + 1; + } - *line_start = buf_; - *line_end = strchr(buf_, '\n'); + line_end_ = (char*)memchr(line_start_, '\n', buf_end_ - line_start_); + if (!line_end_) { + // No newline. Move rest of data to start of buffer, fill rest. + size_t already_consumed = line_start_ - buf_; + size_t size_rest = (buf_end_ - buf_) - already_consumed; + memmove(buf_, line_start_, size_rest); + + size_t read = fread(buf_ + size_rest, 1, sizeof(buf_) - size_rest, file_); + buf_end_ = buf_ + size_rest + read; + line_start_ = buf_; + line_end_ = (char*)memchr(line_start_, '\n', buf_end_ - line_start_); + } + + *line_start = line_start_; + *line_end = line_end_; return true; } private: FILE* file_; char buf_[256 << 10]; + char* buf_end_; // Points one past the last valid byte in |buf_|. + + char* line_start_; + // Points at the next \n in buf_ after line_start, or NULL. + char* line_end_; }; bool BuildLog::Load(const string& path, string* err) {