From 7f65377880ce6a0e5eaa4cb2591b86b8c8a24ee6 Mon Sep 17 00:00:00 2001 From: Mark de Wever Date: Sun, 6 Oct 2024 21:20:22 +0200 Subject: [PATCH] [libc++][format][2/3] Optimizes c-string arguments. (#101805) The formatter specializations for _CharT* and const _CharT* typically write all elements in a loop. This format's internal functions are optimized for larger writes. Instead of writing one element at a time, convert the range to a basic_string_view and write that instead. For C string of 6 characters this is a bit slower, but for 60 characters it's faster. The improvements for back_inserter> are not as great as the others; it just gets as slow as basic_string_view<_CharT>. omparing libcxx/test/benchmarks/write_string_comparison.bench.out-before to libcxx/test/benchmarks/write_string_comparison.bench.out-after Benchmark Time CPU Time Old Time New CPU Old CPU New ----------------------------------------------------------------------------------------------------------------------------------------------------------------- BM_sprintf/C_string_len_6 -0.0015 +0.0013 5 5 5 5 BM_format/C_string_len_6 +0.0390 +0.0416 53 55 53 55 BM_format_to_back_inserter/C_string_len_6 +0.0381 +0.0408 53 55 53 55 BM_format_to_back_inserter>/C_string_len_6 +0.0287 +0.0315 69 71 69 71 BM_format_to_back_inserter>/C_string_len_6 +0.0503 +0.0530 123 129 123 129 BM_format_to_back_inserter>/C_string_len_6 -0.0241 -0.0213 133 130 133 130 BM_format_to_iterator/ C_string_len_6 -0.0075 -0.0049 45 45 45 45 BM_format_to_iterator/ C_string_len_6 +0.0311 +0.0340 44 46 44 46 BM_format_to_iterator/ C_string_len_6 +0.0380 +0.0409 43 45 43 45 BM_format_to_iterator/ C_string_len_6 +0.0366 +0.0392 48 50 48 50 BM_format/string_len_6 -0.0010 -0.0007 56 55 55 55 BM_format_to_back_inserter/string_len_6 +0.0044 +0.0041 55 56 55 55 BM_format_to_back_inserter>/string_len_6 +0.0128 +0.0128 70 71 70 71 BM_format_to_back_inserter>/string_len_6 +0.0151 +0.0151 126 128 126 128 BM_format_to_back_inserter>/string_len_6 -0.0719 -0.0718 140 130 139 129 BM_format_to_iterator/ string_len_6 -0.0323 -0.0324 47 46 47 46 BM_format_to_iterator/ string_len_6 -0.0011 -0.0010 45 44 44 44 BM_format_to_iterator/ string_len_6 -0.0002 -0.0001 45 45 44 44 BM_format_to_iterator/ string_len_6 +0.0046 +0.0047 51 51 51 51 BM_format/string_view_len_6 +0.0031 +0.0031 54 54 54 54 BM_format_to_back_inserter/string_view_len_6 +0.0041 +0.0040 54 54 54 54 BM_format_to_back_inserter>/string_view_len_6 +0.0022 +0.0022 70 70 70 70 BM_format_to_back_inserter>/string_view_len_6 +0.0392 +0.0391 124 129 124 129 BM_format_to_back_inserter>/string_view_len_6 -0.0680 -0.0680 139 129 138 129 BM_format_to_iterator/ string_view_len_6 -0.0321 -0.0320 47 46 47 46 BM_format_to_iterator/ string_view_len_6 -0.0013 -0.0011 45 44 44 44 BM_format_to_iterator/ string_view_len_6 -0.0024 -0.0023 45 44 44 44 BM_format_to_iterator/ string_view_len_6 +0.0057 +0.0057 51 51 51 51 BM_sprintf/C_string_len_60 -0.0035 -0.0035 4 4 4 4 BM_format/C_string_len_60 -0.5627 -0.5627 169 74 169 74 BM_format_to_back_inserter/C_string_len_60 -0.5642 -0.5641 170 74 169 74 BM_format_to_back_inserter>/C_string_len_60 -0.5300 -0.5299 178 84 178 84 BM_format_to_back_inserter>/C_string_len_60 -0.2548 -0.2548 356 265 355 264 BM_format_to_back_inserter>/C_string_len_60 -0.1013 -0.1013 1325 1191 1322 1188 BM_format_to_iterator/ C_string_len_60 -0.6790 -0.6791 141 45 141 45 BM_format_to_iterator/ C_string_len_60 -0.6738 -0.6740 143 47 142 46 BM_format_to_iterator/ C_string_len_60 -0.6807 -0.6808 142 45 142 45 BM_format_to_iterator/ C_string_len_60 -0.6488 -0.6486 144 51 144 51 BM_format/string_len_60 +0.0118 +0.0117 73 74 73 73 BM_format_to_back_inserter/string_len_60 +0.0089 +0.0088 73 73 73 73 BM_format_to_back_inserter>/string_len_60 +0.0080 +0.0081 83 84 83 83 BM_format_to_back_inserter>/string_len_60 +0.0005 +0.0002 262 263 262 262 BM_format_to_back_inserter>/string_len_60 -0.0384 -0.0380 1236 1188 1232 1186 BM_format_to_iterator/ string_len_60 -0.0288 -0.0288 47 46 47 46 BM_format_to_iterator/ string_len_60 +0.0213 +0.0210 44 45 44 45 BM_format_to_iterator/ string_len_60 +0.0202 +0.0205 45 45 44 45 BM_format_to_iterator/ string_len_60 +0.0124 +0.0124 50 51 50 51 BM_format/string_view_len_60 +0.0093 +0.0093 73 73 73 73 BM_format_to_back_inserter/string_view_len_60 +0.0055 +0.0055 73 73 73 73 BM_format_to_back_inserter>/string_view_len_60 +0.0165 +0.0166 81 83 81 83 BM_format_to_back_inserter>/string_view_len_60 +0.0138 +0.0140 260 263 259 263 BM_format_to_back_inserter>/string_view_len_60 -0.0334 -0.0335 1228 1187 1225 1184 BM_format_to_iterator/ string_view_len_60 -0.0257 -0.0259 48 46 47 46 BM_format_to_iterator/ string_view_len_60 +0.0324 +0.0323 45 46 44 46 BM_format_to_iterator/ string_view_len_60 +0.0174 +0.0177 45 45 44 45 BM_format_to_iterator/ string_view_len_60 +0.0076 +0.0076 50 51 50 51 BM_sprintf/C_string_len_6000 +0.4922 +0.4921 77 115 77 114 BM_format/C_string_len_6000 -0.9239 -0.9239 11780 897 11750 894 BM_format_to_back_inserter/C_string_len_6000 -0.9239 -0.9239 11792 898 11763 895 BM_format_to_back_inserter>/C_string_len_6000 -0.9257 -0.9257 11709 870 11679 868 BM_format_to_back_inserter>/C_string_len_6000 -0.4057 -0.4057 25616 15225 25553 15187 BM_format_to_back_inserter>/C_string_len_6000 -0.0832 -0.0833 127144 116569 126823 116265 BM_format_to_iterator/ C_string_len_6000 -0.9853 -0.9853 10869 160 10843 160 BM_format_to_iterator/ C_string_len_6000 -0.9864 -0.9864 10870 148 10841 148 BM_format_to_iterator/ C_string_len_6000 -0.9863 -0.9863 10874 149 10846 148 BM_format_to_iterator/ C_string_len_6000 -0.9629 -0.9629 11239 417 11212 416 BM_format/string_len_6000 -0.0012 -0.0013 846 845 844 842 BM_format_to_back_inserter/string_len_6000 -0.0029 -0.0034 845 843 843 840 BM_format_to_back_inserter>/string_len_6000 -0.0129 -0.0125 832 821 830 819 BM_format_to_back_inserter>/string_len_6000 +0.0048 +0.0048 15042 15114 15004 15076 BM_format_to_back_inserter>/string_len_6000 -0.0017 -0.0017 116266 116072 115967 115768 BM_format_to_iterator/ string_len_6000 -0.0257 -0.0256 120 117 120 117 BM_format_to_iterator/ string_len_6000 -0.0025 -0.0029 117 117 117 117 BM_format_to_iterator/ string_len_6000 -0.0089 -0.0087 118 116 117 116 BM_format_to_iterator/ string_len_6000 -0.0478 -0.0477 379 361 378 360 BM_format/string_view_len_6000 -0.0092 -0.0091 842 835 840 833 BM_format_to_back_inserter/string_view_len_6000 -0.0081 -0.0083 841 835 839 832 BM_format_to_back_inserter>/string_view_len_6000 +0.0089 +0.0088 808 815 806 813 BM_format_to_back_inserter>/string_view_len_6000 +0.0068 +0.0068 15030 15131 14992 15093 BM_format_to_back_inserter>/string_view_len_6000 +0.0012 +0.0010 116099 116243 115813 115934 BM_format_to_iterator/ string_view_len_6000 -0.0122 -0.0121 118 117 118 116 BM_format_to_iterator/ string_view_len_6000 +0.0010 +0.0010 106 107 106 106 BM_format_to_iterator/ string_view_len_6000 -0.0008 -0.0006 106 106 106 106 BM_format_to_iterator/ string_view_len_6000 -0.0549 -0.0548 370 349 369 349 OVERALL_GEOMEAN --- libcxx/include/__format/formatter_string.h | 32 +++++----------------- 1 file changed, 7 insertions(+), 25 deletions(-) diff --git a/libcxx/include/__format/formatter_string.h b/libcxx/include/__format/formatter_string.h index b29e97847f0ba1..23c880d7c6e844 100644 --- a/libcxx/include/__format/formatter_string.h +++ b/libcxx/include/__format/formatter_string.h @@ -64,32 +64,14 @@ struct _LIBCPP_TEMPLATE_VIS formatter : public __formatte template _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(const _CharT* __str, _FormatContext& __ctx) const { _LIBCPP_ASSERT_INTERNAL(__str, "The basic_format_arg constructor should have prevented an invalid pointer."); - - __format_spec::__parsed_specifications<_CharT> __specs = _Base::__parser_.__get_parsed_std_specifications(__ctx); -# if _LIBCPP_STD_VER >= 23 - if (_Base::__parser_.__type_ == __format_spec::__type::__debug) - return __formatter::__format_escaped_string(basic_string_view<_CharT>{__str}, __ctx.out(), __specs); -# endif - - // When using a center or right alignment and the width option the length - // of __str must be known to add the padding upfront. This case is handled - // by the base class by converting the argument to a basic_string_view. + // Converting the input to a basic_string_view means the data is looped over twice; + // - once to determine the length, and + // - once to process the data. // - // When using left alignment and the width option the padding is added - // after outputting __str so the length can be determined while outputting - // __str. The same holds true for the precision, during outputting __str it - // can be validated whether the precision threshold has been reached. For - // now these optimizations aren't implemented. Instead the base class - // handles these options. - // TODO FMT Implement these improvements. - if (__specs.__has_width() || __specs.__has_precision()) - return __formatter::__write_string(basic_string_view<_CharT>{__str}, __ctx.out(), __specs); - - // No formatting required, copy the string to the output. - auto __out_it = __ctx.out(); - while (*__str) - *__out_it++ = *__str++; - return __out_it; + // This sounds slower than writing the output directly. However internally + // the output algorithms have optimizations for "bulk" operations, which + // makes this faster than a single-pass character-by-character output. + return _Base::format(basic_string_view<_CharT>(__str), __ctx); } };