Граф коммитов

1 Коммитов

Автор SHA1 Сообщение Дата
Jonathan Peppers 1ae8fb1cd5 [core] improve Color & Clamp performance (#8884)
* [core] improve Color & Clamp performance

When profiling startup of a HelloForms app on a Pixel 3 XL, I noticed:

    Total(ms) Self(ms)      Calls Method name
            3        1        572 Xamarin.Forms.Internals.NumericExtensions:Clamp (double,double,double)

This method is called multiple times for every `Color` created and
~142 are created on startup. This is why it shows up 572 times for an
app with a single `Label`.

I found there is a `Math.Clamp` implementation in corefx:

6662a0f2fd/src/libraries/System.Private.CoreLib/src/System/Math.cs (L224-L225)

The only difference is this version can throw an exception, so we
could return the incoming value instead. That would be bad to change!

If I rework `NumericExtensions` to use corefx's implementation it is a
bit faster, I did a BenchmarkDotNet comparison running with Mono on
macOS:

     Method |      Mean |    Error |   StdDev |
    ------- |----------:|---------:|---------:|
     Clamp2 |  53.89 ns | 0.668 ns | 0.522 ns |
     Clamp1 |  61.84 ns | 1.270 ns | 2.289 ns |
     Color2 | 112.50 ns | 2.643 ns | 3.705 ns |
     Color1 | 129.03 ns | 2.603 ns | 4.760 ns |

Maybe every `Color` is ~13% faster?

Code for the benchmark is here:

https://github.com/jonathanpeppers/Benchmarks/blob/clamp/Benchmarks/Clamp.cs

Additionally, I reworked the list of default `Color` fields so that
they call a new private constructor that does less math and avoids
`Clamp` completely. We should still keep the original change, as it
would help any cases where the `Color.To*` methods would be used in
apps.

I seem to be able to see a small difference in a Release build running
on a Pixel 3 XL:

    Before:
    12-18 13:04:27.154  1490  1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +606ms
    12-18 13:04:30.851  1490  1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +589ms
    12-18 13:04:34.601  1490  1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +587ms
    12-18 13:04:38.352  1490  1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +575ms
    12-18 13:04:42.084  1490  1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +583ms
    12-18 13:04:45.802  1490  1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +573ms
    12-18 13:04:49.566  1490  1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +592ms
    12-18 13:04:53.284  1490  1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +583ms
    12-18 13:04:57.015  1490  1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +594ms
    12-18 13:05:00.715  1490  1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +581ms
    Average(ms): 586.3
    Std Err(ms): 3.05886689260364
    Std Dev(ms): 9.67298643990917

    After:
    12-18 13:08:16.677  1490  1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +593ms
    12-18 13:08:20.377  1490  1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +577ms
    12-18 13:08:24.107  1490  1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +583ms
    12-18 13:08:27.827  1490  1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +576ms
    12-18 13:08:31.574  1490  1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +586ms
    12-18 13:08:35.324  1490  1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +584ms
    12-18 13:08:39.056  1490  1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +587ms
    12-18 13:08:42.773  1490  1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +586ms
    12-18 13:08:46.523  1490  1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +584ms
    12-18 13:08:50.256  1490  1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +587ms
    Average(ms): 584.3
    Std Err(ms): 1.56382721409865
    Std Dev(ms): 4.94525586350753

This change seems low risk and would help all platforms.

* One last tweak byte -> int

Doing some reading: https://stackoverflow.com/a/43158214/132442

It seems `int` performs even better than `byte`. I did another test
run with just this change:

    Before:
    12-18 13:37:23.347  1490  1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +576ms
    12-18 13:37:27.079  1490  1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +575ms
    12-18 13:37:30.828  1490  1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +581ms
    12-18 13:37:34.578  1490  1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +588ms
    12-18 13:37:38.296  1490  1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +572ms
    12-18 13:37:42.046  1490  1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +579ms
    12-18 13:37:45.781  1490  1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +576ms
    12-18 13:37:49.526  1490  1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +586ms
    12-18 13:37:53.276  1490  1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +586ms
    12-18 13:37:57.009  1490  1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +582ms
    Average(ms): 580.1
    Std Err(ms): 1.70912583243924
    Std Dev(ms): 5.40473043833928

    After:
    12-18 13:35:38.745  1490  1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +572ms
    12-18 13:35:42.459  1490  1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +572ms
    12-18 13:35:46.209  1490  1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +581ms
    12-18 13:35:49.974  1490  1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +581ms
    12-18 13:35:53.724  1490  1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +574ms
    12-18 13:35:57.474  1490  1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +580ms
    12-18 13:36:01.207  1490  1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +573ms
    12-18 13:36:04.957  1490  1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +568ms
    12-18 13:36:08.707  1490  1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +566ms
    12-18 13:36:12.407  1490  1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +565ms
    Average(ms): 573.2
    Std Err(ms): 1.87853370714738
    Std Dev(ms): 5.94044517598546
2020-01-05 16:36:09 -08:00