From da70fce0d34033e231c75afa6b18b895be87d90f Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Mon, 18 Nov 2019 05:51:15 -0800 Subject: [PATCH] Replace Folly Format with fmt in logger to reduce binary size Summary: Now that fmt is available in Folly builds (D14813810), use it to reduce binary code size in Folly Logger. This is done by moving most of the formatting logic behind the type-erased `vformat` API. Previously it was instantiated for all combinations of formatting argument types used in calls to `FB_LOGF` and `XLOGF` in a program. The effect of this change can be illustrated by looking at symbol sizes as given by `nm -S -td` for the following test function: ``` void test_log() { FB_LOGF(logger, WARN, "num events: {:06d}, duration: {:6.3f}", 1234, 5.6789); } ``` compiled in `opt` mode. `nm` before: ``` 0000000004236736 0000000000000231 T test_log() 0000000004236992 0000000000001002 W std::__cxx11::basic_string, std::allocator > folly::LogStreamProcessor::formatLogString(folly::Range, int const&, double const&) ``` `nm` after: ``` 0000000004237536 0000000000000231 T test_log() 0000000004237792 0000000000000251 W std::__cxx11::basic_string, std::allocator > folly::LogStreamProcessor::formatLogString(folly::Range, int const&, double const&) 0000000004238048 0000000000000740 W folly::LogStreamProcessor::vformatLogString[abi:cxx11](folly::Range, fmt::v5::format_args, bool&) ``` Before we had one 1002 byte instantiation of `formatLogString`. With this change it was reduced 4x to 251 bytes and non-template function `vformatLogString` was added which is shared among all logging calls. The size of `test_log` remained unchanged. There are even bigger savings from Folly Formatter instantiations which are no longer needed, e.g. ``` 0000000004238032 0000000000001363 W _ZNK5folly13BaseFormatterINS_9FormatterILb0EJRKiRKdEEELb0EJS3_S5_EEclIZNKS7_8appendToINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEENSt9enable_ifIXsr12IsSomeStringIT_EE5valueEvE4typeERSH_EUlNS_5RangeIPKcEEE_EEvSK_ ``` So in total this change results in ~5x per-call/instantiation binary size. It is possible to reduce binary size even further but it is not done in the current diff to keep it manageable. In addition to binary size improvements, switching to fmt will potentially * allow catching errors in format strings at compile time, * simplify future migration to C++20 [`std::format`](http://eel.is/c++draft/format). Reviewed By: simpkins Differential Revision: D15485589 fbshipit-source-id: 06db4436839f11c2c3dbed7b36658e2193343411 --- CMakeLists.txt | 1 + build/fbcode_builder/specs/fbthrift.py | 4 ++-- build/fbcode_builder/specs/fbzmq.py | 3 ++- build/fbcode_builder/specs/fizz.py | 3 ++- build/fbcode_builder/specs/proxygen.py | 3 ++- build/fbcode_builder/specs/rsocket.py | 3 ++- build/fbcode_builder/specs/wangle.py | 3 ++- build/fbcode_builder_config.py | 3 ++- 8 files changed, 15 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e5eecf939..d5873ee0b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,6 +45,7 @@ if(NOT PROXYGEN_GPERF) endif() # Dependencies +find_package(fmt REQUIRED) find_package(folly REQUIRED) find_package(wangle REQUIRED) find_package(Fizz REQUIRED) diff --git a/build/fbcode_builder/specs/fbthrift.py b/build/fbcode_builder/specs/fbthrift.py index fb6777fea..b3342a597 100644 --- a/build/fbcode_builder/specs/fbthrift.py +++ b/build/fbcode_builder/specs/fbthrift.py @@ -5,9 +5,9 @@ from __future__ import division from __future__ import print_function from __future__ import unicode_literals -import specs.folly as folly import specs.fizz as fizz import specs.fmt as fmt +import specs.folly as folly import specs.rsocket as rsocket import specs.sodium as sodium import specs.wangle as wangle @@ -16,7 +16,7 @@ import specs.zstd as zstd def fbcode_builder_spec(builder): return { - 'depends_on': [folly, fizz, fmt, sodium, rsocket, wangle, zstd], + 'depends_on': [fmt, folly, fizz, sodium, rsocket, wangle, zstd], 'steps': [ builder.fb_github_cmake_install('fbthrift/thrift'), ], diff --git a/build/fbcode_builder/specs/fbzmq.py b/build/fbcode_builder/specs/fbzmq.py index f579b25b3..28aa17725 100644 --- a/build/fbcode_builder/specs/fbzmq.py +++ b/build/fbcode_builder/specs/fbzmq.py @@ -6,6 +6,7 @@ from __future__ import print_function from __future__ import unicode_literals import specs.fbthrift as fbthrift +import specs.fmt as fmt import specs.folly as folly import specs.gmock as gmock import specs.sodium as sodium @@ -17,7 +18,7 @@ from shell_quoting import ShellQuoted def fbcode_builder_spec(builder): builder.add_option('zeromq/libzmq:git_hash', 'v4.2.2') return { - 'depends_on': [folly, fbthrift, gmock, sodium, sigar], + 'depends_on': [fmt, folly, fbthrift, gmock, sodium, sigar], 'steps': [ builder.github_project_workdir('zeromq/libzmq', '.'), builder.step('Build and install zeromq/libzmq', [ diff --git a/build/fbcode_builder/specs/fizz.py b/build/fbcode_builder/specs/fizz.py index 4b6fd2200..b7828624f 100644 --- a/build/fbcode_builder/specs/fizz.py +++ b/build/fbcode_builder/specs/fizz.py @@ -5,6 +5,7 @@ from __future__ import division from __future__ import print_function from __future__ import unicode_literals +import specs.fmt as fmt import specs.folly as folly import specs.sodium as sodium @@ -20,7 +21,7 @@ def fbcode_builder_spec(builder): } ) return { - 'depends_on': [folly, sodium], + 'depends_on': [fmt, folly, sodium], 'steps': [ builder.fb_github_cmake_install( 'fizz/fizz/build', diff --git a/build/fbcode_builder/specs/proxygen.py b/build/fbcode_builder/specs/proxygen.py index cec3f9190..ac694792c 100644 --- a/build/fbcode_builder/specs/proxygen.py +++ b/build/fbcode_builder/specs/proxygen.py @@ -5,6 +5,7 @@ from __future__ import division from __future__ import print_function from __future__ import unicode_literals +import specs.fmt as fmt import specs.folly as folly import specs.fizz as fizz import specs.mvfst as mvfst @@ -26,6 +27,6 @@ def fbcode_builder_spec(builder): ) return { - "depends_on": [folly, wangle, fizz, sodium, zstd, mvfst], + "depends_on": [fmt, folly, wangle, fizz, sodium, zstd, mvfst], "steps": [builder.fb_github_cmake_install("proxygen/proxygen", "..")], } diff --git a/build/fbcode_builder/specs/rsocket.py b/build/fbcode_builder/specs/rsocket.py index 689dcbff9..ef9fd7675 100644 --- a/build/fbcode_builder/specs/rsocket.py +++ b/build/fbcode_builder/specs/rsocket.py @@ -6,12 +6,13 @@ from __future__ import print_function from __future__ import unicode_literals import specs.gmock as gmock +import specs.fmt as fmt import specs.folly as folly def fbcode_builder_spec(builder): return { - 'depends_on': [folly], + 'depends_on': [fmt, folly], 'steps': [ builder.fb_github_cmake_install( 'rsocket-cpp/rsocket', diff --git a/build/fbcode_builder/specs/wangle.py b/build/fbcode_builder/specs/wangle.py index c97d2441d..095716ece 100644 --- a/build/fbcode_builder/specs/wangle.py +++ b/build/fbcode_builder/specs/wangle.py @@ -5,6 +5,7 @@ from __future__ import division from __future__ import print_function from __future__ import unicode_literals +import specs.fmt as fmt import specs.folly as folly import specs.fizz as fizz import specs.sodium as sodium @@ -20,7 +21,7 @@ def fbcode_builder_spec(builder): } ) return { - 'depends_on': [folly, fizz, sodium], + 'depends_on': [fmt, folly, fizz, sodium], 'steps': [ builder.fb_github_cmake_install('wangle/wangle/build'), ], diff --git a/build/fbcode_builder_config.py b/build/fbcode_builder_config.py index f0c4a8ba4..2e37e7739 100644 --- a/build/fbcode_builder_config.py +++ b/build/fbcode_builder_config.py @@ -8,6 +8,7 @@ from __future__ import absolute_import, division, print_function, unicode_literals import specs.fizz as fizz +import specs.fmt as fmt import specs.folly as folly import specs.mvfst as mvfst import specs.proxygen_quic as proxygen_quic @@ -22,7 +23,7 @@ from shell_quoting import ShellQuoted def fbcode_builder_spec(builder): return { - "depends_on": [folly, wangle, fizz, sodium, zstd, mvfst, proxygen_quic], + "depends_on": [fmt, folly, wangle, fizz, sodium, zstd, mvfst, proxygen_quic], "steps": [ # Tests for the full build with no QUIC/HTTP3 # Proxygen is the last step, so we are still in its working dir.