From 4d8984420788d6253d2fd9bfa3ada92be8bfd73b Mon Sep 17 00:00:00 2001 From: Jade Lovelace Date: Thu, 22 Aug 2024 21:02:52 -0700 Subject: [PATCH] build: remove about 30 cpu-sec of compile time by explicit instantiation Apparently the fmt contraption has some extremely popular overloads, and the boost stuff in there gets built approximately infinite times in every compilation unit. Change-Id: Ideba2db7d6bf8559e4d91974bab636f5ed106198 --- src/libutil/fmt.cc | 14 ++++++++++++++ src/libutil/fmt.hh | 13 +++++++++++-- src/libutil/meson.build | 1 + src/libutil/serialise.cc | 25 +++++++++++++++++++++++++ src/libutil/serialise.hh | 14 +------------- 5 files changed, 52 insertions(+), 15 deletions(-) create mode 100644 src/libutil/fmt.cc diff --git a/src/libutil/fmt.cc b/src/libutil/fmt.cc new file mode 100644 index 000000000..400fb7ea0 --- /dev/null +++ b/src/libutil/fmt.cc @@ -0,0 +1,14 @@ +#include "fmt.hh" // IWYU pragma: keep + +template class boost::basic_format; + +namespace nix { + +// Explicit instantiation saves about 30 cpu-seconds of compile time +template HintFmt::HintFmt(const std::string &, const Uncolored &s); +template HintFmt::HintFmt(const std::string &, const std::string &s); +template HintFmt::HintFmt(const std::string &, const uint64_t &, const char * const &); + +HintFmt::HintFmt(const std::string & literal) : HintFmt("%s", Uncolored(literal)) {} + +} diff --git a/src/libutil/fmt.hh b/src/libutil/fmt.hh index d015f7e5f..7589e51e2 100644 --- a/src/libutil/fmt.hh +++ b/src/libutil/fmt.hh @@ -3,7 +3,6 @@ #include #include -#include #include // Darwin and FreeBSD stdenv do not define _GNU_SOURCE but do have _Unwind_Backtrace. #if __APPLE__ || __FreeBSD__ @@ -12,6 +11,9 @@ #include #include "ansicolor.hh" +// Explicit instantiation in fmt.cc +extern template class boost::basic_format; + namespace nix { /** @@ -157,7 +159,9 @@ public: * Format the given string literally, without interpolating format * placeholders. */ - HintFmt(const std::string & literal) : HintFmt("%s", Uncolored(literal)) {} + // Moved out of line because it was instantiating the template below in + // every file in the project. + HintFmt(const std::string & literal); /** * Interpolate the given arguments into the format string. @@ -193,6 +197,11 @@ public: } }; +// Explicit instantiations in fmt.cc +extern template HintFmt::HintFmt(const std::string &, const Uncolored &s); +extern template HintFmt::HintFmt(const std::string &, const std::string &s); +extern template HintFmt::HintFmt(const std::string &, const uint64_t &, const char * const &); + std::ostream & operator<<(std::ostream & os, const HintFmt & hf); } diff --git a/src/libutil/meson.build b/src/libutil/meson.build index 7c0e45e4b..e7f986363 100644 --- a/src/libutil/meson.build +++ b/src/libutil/meson.build @@ -17,6 +17,7 @@ libutil_sources = files( 'experimental-features.cc', 'file-descriptor.cc', 'file-system.cc', + 'fmt.cc', 'git.cc', 'hash.cc', 'hilite.cc', diff --git a/src/libutil/serialise.cc b/src/libutil/serialise.cc index a6dd7e200..4eda1b7e7 100644 --- a/src/libutil/serialise.cc +++ b/src/libutil/serialise.cc @@ -9,6 +9,31 @@ namespace nix { +template +T readNum(Source & source) +{ + unsigned char buf[8]; + source(charptr_cast(buf), sizeof(buf)); + + auto n = readLittleEndian(buf); + + if (n > (uint64_t) std::numeric_limits::max()) + throw SerialisationError("serialised integer %d is too large for type '%s'", n, typeid(T).name()); + + return (T) n; +} + +template bool readNum(Source & source); + +template unsigned char readNum(Source & source); + +template unsigned int readNum(Source & source); + +template unsigned long readNum(Source & source); +template long readNum(Source & source); + +template unsigned long long readNum(Source & source); +template long long readNum(Source & source); void BufferedSink::operator () (std::string_view data) { diff --git a/src/libutil/serialise.hh b/src/libutil/serialise.hh index d6a22b3e9..9ad8018d0 100644 --- a/src/libutil/serialise.hh +++ b/src/libutil/serialise.hh @@ -450,19 +450,7 @@ inline Sink & operator<<(Sink & sink, const Error & ex) MakeError(SerialisationError, Error); template -T readNum(Source & source) -{ - unsigned char buf[8]; - source(charptr_cast(buf), sizeof(buf)); - - auto n = readLittleEndian(buf); - - if (n > (uint64_t) std::numeric_limits::max()) - throw SerialisationError("serialised integer %d is too large for type '%s'", n, typeid(T).name()); - - return (T) n; -} - +T readNum(Source & source); inline unsigned int readInt(Source & source) {