diff --git a/src/libstore-tests/derivation-parser-bench.cc b/src/libstore-tests/derivation-parser-bench.cc index ef698b205..61c9807a6 100644 --- a/src/libstore-tests/derivation-parser-bench.cc +++ b/src/libstore-tests/derivation-parser-bench.cc @@ -28,6 +28,27 @@ static void BM_ParseRealDerivationFile(benchmark::State & state, const std::stri state.SetBytesProcessed(state.iterations() * content.size()); } +// Benchmark unparsing real derivation files +static void BM_UnparseRealDerivationFile(benchmark::State & state, const std::string & filename) +{ + // Read the file once + std::ifstream file(filename); + std::stringstream buffer; + buffer << file.rdbuf(); + std::string content = buffer.str(); + + auto store = openStore("dummy://"); + ExperimentalFeatureSettings xpSettings; + auto drv = parseDerivation(*store, std::string(content), "test", xpSettings); + + for (auto _ : state) { + auto unparsed = drv.unparse(*store, /*maskOutputs=*/false); + benchmark::DoNotOptimize(unparsed); + assert(unparsed.size() == content.size()); + } + state.SetBytesProcessed(state.iterations() * content.size()); +} + // Register benchmarks for actual test derivation files if they exist BENCHMARK_CAPTURE( BM_ParseRealDerivationFile, @@ -37,3 +58,11 @@ BENCHMARK_CAPTURE( BM_ParseRealDerivationFile, firefox, getEnvNonEmpty("_NIX_TEST_UNIT_DATA").value_or(NIX_UNIT_TEST_DATA) + "/derivation/firefox.drv"); +BENCHMARK_CAPTURE( + BM_UnparseRealDerivationFile, + hello, + getEnvNonEmpty("_NIX_TEST_UNIT_DATA").value_or(NIX_UNIT_TEST_DATA) + "/derivation/hello.drv"); +BENCHMARK_CAPTURE( + BM_UnparseRealDerivationFile, + firefox, + getEnvNonEmpty("_NIX_TEST_UNIT_DATA").value_or(NIX_UNIT_TEST_DATA) + "/derivation/firefox.drv"); diff --git a/src/libstore/derivations.cc b/src/libstore/derivations.cc index 1afc343d7..a1831efc6 100644 --- a/src/libstore/derivations.cc +++ b/src/libstore/derivations.cc @@ -498,28 +498,33 @@ Derivation parseDerivation( */ static void printString(std::string & res, std::string_view s) { - boost::container::small_vector buffer; - buffer.reserve(s.size() * 2 + 2); - char * buf = buffer.data(); - 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); + res.reserve(res.size() + s.size() * 2 + 2); + res += '"'; + static constexpr auto chunkSize = 1024; + std::array buffer; + while (!s.empty()) { + auto chunk = s.substr(0, /*n=*/chunkSize); + s.remove_prefix(chunk.size()); + char * buf = buffer.data(); + char * p = buf; + for (auto c : chunk) + 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; + res.append(buf, p - buf); + } + res += '"'; } static void printUnquotedString(std::string & res, std::string_view s)