Skip to content

Commit

Permalink
[libc++][format][2/3] Optimizes c-string arguments. (#101805)
Browse files Browse the repository at this point in the history
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<std::list<_CharT>> 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<std::string>/C_string_len_6                            +0.0381         +0.0408            53            55            53            55
BM_format_to_back_inserter<std::vector<char>>/C_string_len_6                      +0.0287         +0.0315            69            71            69            71
BM_format_to_back_inserter<std::deque<char>>/C_string_len_6                       +0.0503         +0.0530           123           129           123           129
BM_format_to_back_inserter<std::list<char>>/C_string_len_6                        -0.0241         -0.0213           133           130           133           130
BM_format_to_iterator/<std::array> C_string_len_6                                 -0.0075         -0.0049            45            45            45            45
BM_format_to_iterator/<std::string> C_string_len_6                                +0.0311         +0.0340            44            46            44            46
BM_format_to_iterator/<std::vector> C_string_len_6                                +0.0380         +0.0409            43            45            43            45
BM_format_to_iterator/<std::deque> 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<std::string>/string_len_6                              +0.0044         +0.0041            55            56            55            55
BM_format_to_back_inserter<std::vector<char>>/string_len_6                        +0.0128         +0.0128            70            71            70            71
BM_format_to_back_inserter<std::deque<char>>/string_len_6                         +0.0151         +0.0151           126           128           126           128
BM_format_to_back_inserter<std::list<char>>/string_len_6                          -0.0719         -0.0718           140           130           139           129
BM_format_to_iterator/<std::array> string_len_6                                   -0.0323         -0.0324            47            46            47            46
BM_format_to_iterator/<std::string> string_len_6                                  -0.0011         -0.0010            45            44            44            44
BM_format_to_iterator/<std::vector> string_len_6                                  -0.0002         -0.0001            45            45            44            44
BM_format_to_iterator/<std::deque> 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<std::string>/string_view_len_6                         +0.0041         +0.0040            54            54            54            54
BM_format_to_back_inserter<std::vector<char>>/string_view_len_6                   +0.0022         +0.0022            70            70            70            70
BM_format_to_back_inserter<std::deque<char>>/string_view_len_6                    +0.0392         +0.0391           124           129           124           129
BM_format_to_back_inserter<std::list<char>>/string_view_len_6                     -0.0680         -0.0680           139           129           138           129
BM_format_to_iterator/<std::array> string_view_len_6                              -0.0321         -0.0320            47            46            47            46
BM_format_to_iterator/<std::string> string_view_len_6                             -0.0013         -0.0011            45            44            44            44
BM_format_to_iterator/<std::vector> string_view_len_6                             -0.0024         -0.0023            45            44            44            44
BM_format_to_iterator/<std::deque> 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<std::string>/C_string_len_60                           -0.5642         -0.5641           170            74           169            74
BM_format_to_back_inserter<std::vector<char>>/C_string_len_60                     -0.5300         -0.5299           178            84           178            84
BM_format_to_back_inserter<std::deque<char>>/C_string_len_60                      -0.2548         -0.2548           356           265           355           264
BM_format_to_back_inserter<std::list<char>>/C_string_len_60                       -0.1013         -0.1013          1325          1191          1322          1188
BM_format_to_iterator/<std::array> C_string_len_60                                -0.6790         -0.6791           141            45           141            45
BM_format_to_iterator/<std::string> C_string_len_60                               -0.6738         -0.6740           143            47           142            46
BM_format_to_iterator/<std::vector> C_string_len_60                               -0.6807         -0.6808           142            45           142            45
BM_format_to_iterator/<std::deque> 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<std::string>/string_len_60                             +0.0089         +0.0088            73            73            73            73
BM_format_to_back_inserter<std::vector<char>>/string_len_60                       +0.0080         +0.0081            83            84            83            83
BM_format_to_back_inserter<std::deque<char>>/string_len_60                        +0.0005         +0.0002           262           263           262           262
BM_format_to_back_inserter<std::list<char>>/string_len_60                         -0.0384         -0.0380          1236          1188          1232          1186
BM_format_to_iterator/<std::array> string_len_60                                  -0.0288         -0.0288            47            46            47            46
BM_format_to_iterator/<std::string> string_len_60                                 +0.0213         +0.0210            44            45            44            45
BM_format_to_iterator/<std::vector> string_len_60                                 +0.0202         +0.0205            45            45            44            45
BM_format_to_iterator/<std::deque> 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<std::string>/string_view_len_60                        +0.0055         +0.0055            73            73            73            73
BM_format_to_back_inserter<std::vector<char>>/string_view_len_60                  +0.0165         +0.0166            81            83            81            83
BM_format_to_back_inserter<std::deque<char>>/string_view_len_60                   +0.0138         +0.0140           260           263           259           263
BM_format_to_back_inserter<std::list<char>>/string_view_len_60                    -0.0334         -0.0335          1228          1187          1225          1184
BM_format_to_iterator/<std::array> string_view_len_60                             -0.0257         -0.0259            48            46            47            46
BM_format_to_iterator/<std::string> string_view_len_60                            +0.0324         +0.0323            45            46            44            46
BM_format_to_iterator/<std::vector> string_view_len_60                            +0.0174         +0.0177            45            45            44            45
BM_format_to_iterator/<std::deque> 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<std::string>/C_string_len_6000                         -0.9239         -0.9239         11792           898         11763           895
BM_format_to_back_inserter<std::vector<char>>/C_string_len_6000                   -0.9257         -0.9257         11709           870         11679           868
BM_format_to_back_inserter<std::deque<char>>/C_string_len_6000                    -0.4057         -0.4057         25616         15225         25553         15187
BM_format_to_back_inserter<std::list<char>>/C_string_len_6000                     -0.0832         -0.0833        127144        116569        126823        116265
BM_format_to_iterator/<std::array> C_string_len_6000                              -0.9853         -0.9853         10869           160         10843           160
BM_format_to_iterator/<std::string> C_string_len_6000                             -0.9864         -0.9864         10870           148         10841           148
BM_format_to_iterator/<std::vector> C_string_len_6000                             -0.9863         -0.9863         10874           149         10846           148
BM_format_to_iterator/<std::deque> 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<std::string>/string_len_6000                           -0.0029         -0.0034           845           843           843           840
BM_format_to_back_inserter<std::vector<char>>/string_len_6000                     -0.0129         -0.0125           832           821           830           819
BM_format_to_back_inserter<std::deque<char>>/string_len_6000                      +0.0048         +0.0048         15042         15114         15004         15076
BM_format_to_back_inserter<std::list<char>>/string_len_6000                       -0.0017         -0.0017        116266        116072        115967        115768
BM_format_to_iterator/<std::array> string_len_6000                                -0.0257         -0.0256           120           117           120           117
BM_format_to_iterator/<std::string> string_len_6000                               -0.0025         -0.0029           117           117           117           117
BM_format_to_iterator/<std::vector> string_len_6000                               -0.0089         -0.0087           118           116           117           116
BM_format_to_iterator/<std::deque> 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<std::string>/string_view_len_6000                      -0.0081         -0.0083           841           835           839           832
BM_format_to_back_inserter<std::vector<char>>/string_view_len_6000                +0.0089         +0.0088           808           815           806           813
BM_format_to_back_inserter<std::deque<char>>/string_view_len_6000                 +0.0068         +0.0068         15030         15131         14992         15093
BM_format_to_back_inserter<std::list<char>>/string_view_len_6000                  +0.0012         +0.0010        116099        116243        115813        115934
BM_format_to_iterator/<std::array> string_view_len_6000                           -0.0122         -0.0121           118           117           118           116
BM_format_to_iterator/<std::string> string_view_len_6000                          +0.0010         +0.0010           106           107           106           106
BM_format_to_iterator/<std::vector> string_view_len_6000                          -0.0008         -0.0006           106           106           106           106
BM_format_to_iterator/<std::deque> string_view_len_6000                           -0.0549         -0.0548           370           349           369           349
OVERALL_GEOMEAN
  • Loading branch information
mordante authored Oct 6, 2024
1 parent 864fcfc commit 7f65377
Showing 1 changed file with 7 additions and 25 deletions.
32 changes: 7 additions & 25 deletions libcxx/include/__format/formatter_string.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,32 +64,14 @@ struct _LIBCPP_TEMPLATE_VIS formatter<const _CharT*, _CharT> : public __formatte
template <class _FormatContext>
_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);
}
};

Expand Down

0 comments on commit 7f65377

Please sign in to comment.