Cycles: Avoid some expensive operations in header expansions

Basically gather lines as-is during traversal, avoiding allocating
memory for all the lines in headers.

Brings additional performance improvement abut 20%.
This commit is contained in:
Sergey Sharybin 2017-08-02 20:23:14 +02:00
parent a280697e77
commit f879cac032

@ -771,12 +771,21 @@ bool path_remove(const string& path)
struct SourceReplaceState {
typedef map<string, string> ProcessedMapping;
/* Base director for all relative include headers. */
string base;
/* Result of processed files. */
ProcessedMapping processed_files;
/* Set of files which are considered "precompiled" and which are replaced
* with and empty string on a subsequent occurrence in include statement.
*/
set<string> precompiled_headers;
};
static string path_source_replace_includes_recursive(
const string& source,
const string& source_filepath,
SourceReplaceState *state);
static string line_directive(const SourceReplaceState& state,
const string& path,
const int line)
@ -798,6 +807,44 @@ static string line_directive(const SourceReplaceState& state,
return string_printf("#line %d \"%s\"", line, escaped_path.c_str());
}
static string path_source_handle_preprocessor(
const string& preprocessor_line,
const string& source_filepath,
const size_t line_number,
SourceReplaceState *state)
{
string result = preprocessor_line;
string token = string_strip(
preprocessor_line.substr(1, preprocessor_line.size() - 1));
if(string_startswith(token, "include")) {
token = string_strip(token.substr(7, token.size() - 7));
if(token[0] == '"') {
const size_t n_start = 1;
const size_t n_end = token.find("\"", n_start);
const string filename = token.substr(n_start, n_end - n_start);
const bool is_precompiled = string_endswith(token, "// PRECOMPILED");
string filepath = path_join(state->base, filename);
if(!path_exists(filepath)) {
filepath = path_join(path_dirname(source_filepath),
filename);
}
if(is_precompiled) {
state->precompiled_headers.insert(filepath);
}
string text;
if(path_read_text(filepath, text)) {
text = path_source_replace_includes_recursive(
text, filepath, state);
/* Use line directives for better error messages. */
result = line_directive(*state, filepath, 1) + "\n"
+ text + "\n"
+ line_directive(*state, source_filepath, line_number + 1);
}
}
}
return result;
}
/* Our own little c preprocessor that replaces #includes with the file
* contents, to work around issue of OpenCL drivers not supporting
* include paths with spaces in them.
@ -821,42 +868,42 @@ static string path_source_replace_includes_recursive(
}
/* Perform full file processing. */
string result = "";
vector<string> lines;
string_split(lines, source, "\n", false);
for(size_t i = 0; i < lines.size(); ++i) {
const string& line = lines[i];
if(line[0] == '#') {
string token = string_strip(line.substr(1, line.size() - 1));
if(string_startswith(token, "include")) {
token = string_strip(token.substr(7, token.size() - 7));
if(token[0] == '"') {
const size_t n_start = 1;
const size_t n_end = token.find("\"", n_start);
const string filename = token.substr(n_start, n_end - n_start);
const bool is_precompiled = string_endswith(token, "// PRECOMPILED");
string filepath = path_join(state->base, filename);
if(!path_exists(filepath)) {
filepath = path_join(path_dirname(source_filepath),
filename);
}
if(is_precompiled) {
state->precompiled_headers.insert(filepath);
}
string text;
if(path_read_text(filepath, text)) {
text = path_source_replace_includes_recursive(
text, filepath, state);
/* Use line directives for better error messages. */
result += line_directive(*state, filepath, 1)
+ token.replace(0, n_end + 1, "\n" + text + "\n")
+ line_directive(*state, source_filepath, i + 1) +
"\n";
continue;
}
}
const size_t source_length = source.length();
size_t index = 0;
size_t line_number = 0, column_number = 1;
bool inside_preprocessor = false;
string preprocessor_line = "";
while(index < source_length) {
const char ch = source[index];
if(ch == '\n') {
if(inside_preprocessor) {
result += path_source_handle_preprocessor(preprocessor_line,
source_filepath,
line_number,
state);
}
inside_preprocessor = false;
preprocessor_line = "";
column_number = 0;
++line_number;
}
result += line + "\n";
else if(ch == '#' && column_number == 1) {
inside_preprocessor = true;
}
if(inside_preprocessor) {
preprocessor_line += ch;
}
else {
result += ch;
}
++index;
++column_number;
}
if(inside_preprocessor) {
result += path_source_handle_preprocessor(preprocessor_line,
source_filepath,
line_number,
state);
}
/* Store result for further reuse. */
state->processed_files[source_filepath] = result;