From 75db069f927ffaf38ac6ef2d8143926b724ca935 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Sun, 23 Feb 2020 16:36:19 +0100 Subject: [PATCH] Optimise Derivation::unparse() In nix-instantiate --dry-run '' -A nixos.tests.simple.x86_64-linux this reduces time spent in unparse() from 9.15% to 4.31%. The main culprit was appending characters one at a time to the destination string. Even though the string has enough capacity, push_back() still needs to check this on every call. --- src/libstore/derivations.cc | 58 ++++++++++++++++++++++++++----------- 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/src/libstore/derivations.cc b/src/libstore/derivations.cc index d9da8769c..205b90e55 100644 --- a/src/libstore/derivations.cc +++ b/src/libstore/derivations.cc @@ -213,15 +213,26 @@ Derivation Store::derivationFromPath(const StorePath & drvPath) } -static void printString(string & res, const string & s) +static void printString(string & res, std::string_view s) +{ + char buf[s.size() * 2 + 2]; + char * p = buf; + *p++ = '"'; + for (auto c : s) + if (c == '\"' || c == '\\') { *p++ = '\\'; *p++ = c; } + else if (c == '\n') { *p++ = '\\'; *p++ = 'n'; } + else if (c == '\r') { *p++ = '\\'; *p++ = 'r'; } + else if (c == '\t') { *p++ = '\\'; *p++ = 't'; } + else *p++ = c; + *p++ = '"'; + res.append(buf, p - buf); +} + + +static void printUnquotedString(string & res, std::string_view s) { res += '"'; - for (const char * i = s.c_str(); *i; i++) - if (*i == '\"' || *i == '\\') { res += "\\"; res += *i; } - else if (*i == '\n') res += "\\n"; - else if (*i == '\r') res += "\\r"; - else if (*i == '\t') res += "\\t"; - else res += *i; + res.append(s); res += '"'; } @@ -239,6 +250,19 @@ static void printStrings(string & res, ForwardIterator i, ForwardIterator j) } +template +static void printUnquotedStrings(string & res, ForwardIterator i, ForwardIterator j) +{ + res += '['; + bool first = true; + for ( ; i != j; ++i) { + if (first) first = false; else res += ','; + printUnquotedString(res, *i); + } + res += ']'; +} + + string Derivation::unparse(const Store & store, bool maskOutputs, std::map * actualInputs) const { @@ -249,10 +273,10 @@ string Derivation::unparse(const Store & store, bool maskOutputs, bool first = true; for (auto & i : outputs) { if (first) first = false; else s += ','; - s += '('; printString(s, i.first); - s += ','; printString(s, maskOutputs ? "" : store.printStorePath(i.second.path)); - s += ','; printString(s, i.second.hashAlgo); - s += ','; printString(s, i.second.hash); + s += '('; printUnquotedString(s, i.first); + s += ','; printUnquotedString(s, maskOutputs ? "" : store.printStorePath(i.second.path)); + s += ','; printUnquotedString(s, i.second.hashAlgo); + s += ','; printUnquotedString(s, i.second.hash); s += ')'; } @@ -261,24 +285,24 @@ string Derivation::unparse(const Store & store, bool maskOutputs, if (actualInputs) { for (auto & i : *actualInputs) { if (first) first = false; else s += ','; - s += '('; printString(s, i.first); - s += ','; printStrings(s, i.second.begin(), i.second.end()); + s += '('; printUnquotedString(s, i.first); + s += ','; printUnquotedStrings(s, i.second.begin(), i.second.end()); s += ')'; } } else { for (auto & i : inputDrvs) { if (first) first = false; else s += ','; - s += '('; printString(s, store.printStorePath(i.first)); - s += ','; printStrings(s, i.second.begin(), i.second.end()); + s += '('; printUnquotedString(s, store.printStorePath(i.first)); + s += ','; printUnquotedStrings(s, i.second.begin(), i.second.end()); s += ')'; } } s += "],"; auto paths = store.printStorePathSet(inputSrcs); // FIXME: slow - printStrings(s, paths.begin(), paths.end()); + printUnquotedStrings(s, paths.begin(), paths.end()); - s += ','; printString(s, platform); + s += ','; printUnquotedString(s, platform); s += ','; printString(s, builder); s += ','; printStrings(s, args.begin(), args.end());