• Marcus Holland-Moritz's avatar
    Refactor folly::to<> · ad2f872b
    Marcus Holland-Moritz authored
    Summary:
    This is the main diff of the series. Its main purpose is to make
    the internals of folly::to<> propagate error codes instead of
    throwing exceptions. Along with this, it makes the following
    changes:
    
    - Move most of the string-to-int implementation out of the header file
    
    - Unify error/exception strings across conversion routines
    
    - Introduce a ConversionError class that derives from std::range_error
    
    - Capture an error code in ConversionError in addition to a string
    
    - Optimize tolower() calls in Conv.cpp
    
    - Introduce ConversionResult<>, which is used as the internal result wrapper
    
    - Get rid of all error checking macros
    
    There are quite a few benefits here.
    
    == Faster conversions ==
    
    For a large set of conversions, the performance is unchanged. I've removed
    all benchmarks that were unchanged from the table below for simplicity.
    
    A few things stand out:
    
    - `follyAtoiMeasure` is consistently faster, sometimes by quite a large margin
    
    - The cost of throwing exceptions is significantly reduced, as throwing them
      further down on the call stack will reduce the amount of stack unwinding
    
    - String-to-boolean and string-to-float conversions are significantly faster
      when passing in a string representation (e.g. "off" or "infinity") thanks
      to the optimized tolower_ascii() call (column `New+Ascii` in the table)
    
    - Conversions between int and float are significantly faster and almost back
      at the performance of before the undefined behaviour fix
    
    - All string-to-(int|float|bool) conversions are consistently faster
    
    The columns in the table are as follows:
    
      Original:  Original code before the undefined behaviour fix
      Fix UB:    Code with the undefined behaviour fix; this impacts mostly the
                 float <-> int conversions, but appears to have a small effect
                 on some other benchmarks
      New:       New code introduced by this diff, but without the tolower_ascii()
                 optimization
      New+Ascii: New code, including the tolower_ascii() optimization
    
      ===========================================================================================
                                                       Original   Fix UB     New        New+Ascii
      folly/test/ConvBenchmark.cpp                     time/iter  time/iter  time/iter  time/iter
      ===========================================================================================
      handwrittenAtoiMeasure(1)                           3.95ns     3.95ns     3.95ns     3.95ns
      follyAtoiMeasure(1)                                 6.08ns     6.08ns     3.95ns     3.95ns
      -------------------------------------------------------------------------------------------
      handwrittenAtoiMeasure(2)                           5.47ns     5.47ns     5.47ns     5.47ns
      follyAtoiMeasure(2)                                 5.77ns     5.77ns     3.95ns     3.95ns
      -------------------------------------------------------------------------------------------
      handwrittenAtoiMeasure(3)                           6.08ns     6.08ns     6.08ns     6.08ns
      follyAtoiMeasure(3)                                 6.08ns     6.08ns     4.25ns     4.25ns
      -------------------------------------------------------------------------------------------
      handwrittenAtoiMeasure(4)                           6.99ns     6.99ns     6.99ns     6.99ns
      follyAtoiMeasure(4)                                 6.99ns     6.99ns     4.56ns     4.56ns
      -------------------------------------------------------------------------------------------
      handwrittenAtoiMeasure(5)                           7.90ns     8.20ns     7.90ns     7.90ns
      follyAtoiMeasure(5)                                 7.29ns     7.29ns     4.86ns     4.86ns
      -------------------------------------------------------------------------------------------
      handwrittenAtoiMeasure(6)                           8.81ns     9.42ns     8.81ns     8.81ns
      follyAtoiMeasure(6)                                 7.29ns     7.29ns     4.86ns     4.86ns
      -------------------------------------------------------------------------------------------
      handwrittenAtoiMeasure(7)                           9.72ns    10.63ns     9.72ns     9.72ns
      follyAtoiMeasure(7)                                 7.60ns     7.60ns     5.16ns     5.16ns
      -------------------------------------------------------------------------------------------
      handwrittenAtoiMeasure(8)                          10.63ns    11.85ns    10.63ns    10.63ns
      follyAtoiMeasure(8)                                 8.51ns     8.51ns     6.08ns     6.08ns
      -------------------------------------------------------------------------------------------
      handwrittenAtoiMeasure(9)                          11.54ns    13.07ns    11.54ns    11.54ns
      follyAtoiMeasure(9)                                 8.81ns     8.81ns     6.08ns     6.08ns
      -------------------------------------------------------------------------------------------
      handwrittenAtoiMeasure(10)                         12.46ns    14.28ns    12.46ns    12.46ns
      follyAtoiMeasure(10)                                8.81ns     8.81ns     6.38ns     6.38ns
      -------------------------------------------------------------------------------------------
      handwrittenAtoiMeasure(11)                         13.37ns    15.50ns    13.37ns    13.37ns
      follyAtoiMeasure(11)                                9.12ns     9.12ns     6.38ns     6.38ns
      -------------------------------------------------------------------------------------------
      handwrittenAtoiMeasure(12)                         14.28ns    16.71ns    14.28ns    14.28ns
      follyAtoiMeasure(12)                               10.03ns    10.03ns     7.29ns     7.29ns
      -------------------------------------------------------------------------------------------
      handwrittenAtoiMeasure(13)                         15.19ns    17.92ns    15.19ns    15.19ns
      follyAtoiMeasure(13)                               10.33ns    10.33ns     7.60ns     7.60ns
      -------------------------------------------------------------------------------------------
      handwrittenAtoiMeasure(14)                         16.10ns    19.14ns    16.10ns    16.10ns
      follyAtoiMeasure(14)                               10.33ns    10.33ns     7.60ns     7.60ns
      -------------------------------------------------------------------------------------------
      handwrittenAtoiMeasure(15)                         17.01ns    20.36ns    17.01ns    17.01ns
      follyAtoiMeasure(15)                               10.63ns    10.63ns     7.90ns     7.90ns
      -------------------------------------------------------------------------------------------
      handwrittenAtoiMeasure(16)                         17.92ns    21.57ns    17.92ns    17.92ns
      follyAtoiMeasure(16)                               11.55ns    11.55ns     8.81ns     8.81ns
      -------------------------------------------------------------------------------------------
      handwrittenAtoiMeasure(17)                         18.84ns    22.79ns    18.84ns    18.84ns
      follyAtoiMeasure(17)                               11.85ns    11.85ns     8.81ns     8.81ns
      -------------------------------------------------------------------------------------------
      handwrittenAtoiMeasure(18)                         19.75ns    24.00ns    19.75ns    19.75ns
      follyAtoiMeasure(18)                               11.85ns    11.85ns     9.12ns     9.12ns
      -------------------------------------------------------------------------------------------
      handwrittenAtoiMeasure(19)                         20.66ns    25.22ns    20.66ns    20.66ns
      follyAtoiMeasure(19)                               12.16ns    12.16ns     9.11ns     9.11ns
      -------------------------------------------------------------------------------------------
      stringToBoolNumClassic                             12.76ns    12.76ns    11.96ns    12.15ns
      stringToBoolNumClassicError                         3.19us     3.18us     1.58us     1.58us
      stringToBoolStrClassic                             17.92ns    17.92ns    15.50ns     7.60ns
      stringToBoolStrClassicError                         3.21us     3.18us     1.57us     1.57us
      -------------------------------------------------------------------------------------------
      stringToFloatNumClassic                            32.96ns    32.81ns    32.10ns    31.12ns
      stringToFloatNumClassicError                        2.73us     2.69us     1.65us     1.66us
      stringToFloatStrClassic                            37.37ns    38.58ns    36.76ns    16.71ns
      stringToFloatStrClassicError                        2.87us     2.87us     1.60us     1.59us
      stringToDoubleNumClassic                           31.30ns    31.82ns    29.77ns    29.17ns
      stringToDoubleNumClassicError                       2.69us     2.66us     1.65us     1.66us
      stringToDoubleStrClassic                           37.67ns    37.67ns    35.84ns    16.71ns
      stringToDoubleStrClassicError                       2.87us     2.86us     1.58us     1.58us
      -------------------------------------------------------------------------------------------
      stringToCharSignedClassic                          16.71ns    18.08ns    15.49ns    14.59ns
      stringToCharSignedClassicError                      3.87us     3.82us     1.61us     1.61us
      stringToCharUnsignedClassic                        15.49ns    15.19ns    12.46ns    12.66ns
      stringToCharUnsignedClassicError                    2.73us     2.70us     1.62us     1.62us
      stringToIntSignedClassic                           21.26ns    19.44ns    17.92ns    18.40ns
      stringToIntSignedClassicError                       3.94us     3.89us     1.64us     1.64us
      stringToIntUnsignedClassic                         17.93ns    18.53ns    15.50ns    15.50ns
      stringToIntUnsignedClassicError                     2.72us     2.71us     1.62us     1.61us
      stringToLongLongSignedClassic                      34.63ns    30.58ns    27.04ns    27.04ns
      stringToLongLongSignedClassicError                  3.94us     3.90us     1.63us     1.63us
      stringToLongLongUnsignedClassic                    51.04ns    47.96ns    46.44ns    46.68ns
      stringToLongLongUnsignedClassicError                2.73us     2.71us     1.61us     1.61us
      -------------------------------------------------------------------------------------------
      ptrPairToCharSignedClassic                          5.16ns     5.16ns     3.34ns     3.65ns
      ptrPairToCharSignedClassicError                     3.56us     3.54us     1.61us     1.61us
      ptrPairToCharUnsignedClassic                        2.43ns     2.43ns     2.13ns     2.13ns
      ptrPairToCharUnsignedClassicError                   2.63us     2.63us     1.61us     1.61us
      ptrPairToIntSignedClassic                           6.99ns     6.99ns     5.16ns     5.16ns
      ptrPairToIntSignedClassicError                      4.08us     4.06us     1.61us     1.61us
      ptrPairToIntUnsignedClassic                         4.25ns     4.56ns     3.34ns     3.34ns
      ptrPairToIntUnsignedClassicError                    2.70us     2.70us     1.60us     1.60us
      ptrPairToLongLongSignedClassic                     12.16ns    12.16ns     9.72ns     9.72ns
      ptrPairToLongLongSignedClassicError                 4.06us     4.06us     1.61us     1.61us
      ptrPairToLongLongUnsignedClassic                   29.13ns    29.13ns    27.61ns    27.61ns
      ptrPairToLongLongUnsignedClassicError               2.71us     2.72us     1.63us     1.64us
      -------------------------------------------------------------------------------------------
      intToCharSignedClassic                            405.02ps   506.35ps   405.02ps   405.02ps
      intToCharSignedClassicError                         2.10us     2.09us     1.63us     1.64us
      intToCharUnsignedClassic                          303.79ps   303.78ps   303.77ps   303.77ps
      intToCharUnsignedClassicError                       2.10us     2.09us     1.63us     1.64us
      intToIntSignedClassic                             405.02ps   405.02ps   405.01ps   405.01ps
      intToIntSignedClassicError                          1.99us     1.98us     1.72us     1.72us
      intToIntUnsignedClassic                           405.03ps   405.03ps   379.71ps   379.71ps
      intToIntUnsignedClassicError                        2.09us     2.09us     1.63us     1.63us
      -------------------------------------------------------------------------------------------
      intToFloatClassic                                 545.11ps     3.34ns     1.23ns     1.23ns
      intToFloatClassicError                              1.67us     2.37us     1.73us     1.72us
      -------------------------------------------------------------------------------------------
      floatToFloatClassic                               759.47ps   759.47ps   759.45ps   759.45ps
      floatToFloatClassicError                            6.45us     6.44us     1.77us     1.77us
      -------------------------------------------------------------------------------------------
      floatToIntClassic                                 637.82ps     2.89ns     1.50ns     1.50ns
      floatToIntClassicError                              1.92us     2.61us     1.82us     1.83us
      ===========================================================================================
    
    == Improved build times ==
    
    I've checked this with gcc 4.9.3, and compile times for both ConvTest and
    ConvBenchmark are reduced by roughly 10%:
    
      ====================================
                        original  new code
      ------------------------------------
      ConvTest.o         14.788s   13.361s
      ConvBenchmark.o    16.148s   14.578s
      ====================================
    
    == Smaller binary size ==
    
    Again, checked with gcc 4.9.3, stripped binaries are slightly smaller with
    the new code:
    
      ====================================
                        original  new code
      ------------------------------------
      conv_test           761704    749384
      conv_benchmark      539632    510928
      ====================================
    
    == Ability to add new non-throwing interfaces ==
    
    This change sticks to the original API that will throw an exception in case
    of an error. A subsequent diff will introduce non-throwing interfaces with
    a minimum of additional code.
    
    Reviewed By: ericniebler
    
    Differential Revision: D3433856
    
    fbshipit-source-id: 9bc976ebc181fe2f172ae47c78edf407e9ee7bb0
    ad2f872b
DynamicParserTest.cpp 16 KB