New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve performance of Enum.Parse/TryParse #2933

Merged
merged 1 commit into from Feb 1, 2016

Conversation

Projects
None yet
4 participants
@stephentoub
Member

stephentoub commented Jan 30, 2016

The allocation profile of Enum.Parse today is fairly poor. While the design of the method returning an Enum requires at least one allocation for the boxed result (the generic TryParse could be overhauled to avoid this, but still has it), additional allocations shouldn't be necessary in the common cases. However, for some reason the current code is boxing a 0 on every call. It's also using string.Trim() to remove whitespace (once for the overall string and then once for each substring), and using String.Split to parse multiple values, which ends up allocating a string[] and an int[] even if there's only one value.

This commit removes all allocations from Enum.Parse other than the boxing of the Enum result and some allocations on the code path where Enum.Parse is handed a string containing a number, in which case additional allocations are involved in using the Convert.ChangeType call.

With an enum like:

[Flags]
enum Colors
{
    Red = 0x1,
    Orange = 0x2,
    Yellow = 0x4,
    Green = 0x8,
    Blue = 0x10
}

using Enum.Parse(typeof(Color), "Red") repeatedly now results in 5x fewer gen0 GCs and is ~15% faster. Using Enum.Parse(typeof(Color), "Red, Orange, Yellow, Green, Blue") repeatedly now results in 23x fewer gen0 GCs is is similarly ~15% faster.

cc: @jkotas, @ellismg

@jkotas

This comment has been minimized.

Show comment
Hide comment
@jkotas

jkotas Jan 30, 2016

Member

LGTM. Very nice improvement.

Member

jkotas commented Jan 30, 2016

LGTM. Very nice improvement.

Improve performance of Enum.Parse/TryParse
The allocation profile of Enum.Parse today is fairly poor.  While the design of the method returning an Enum requires at least one allocation for the boxed result (the generic TryParse could be overhauled to avoid this, but still has it), additional allocations shouldn't be necessary in the common cases.  However, for some reason the current code is boxing a 0 on every call.  It's also using string.Trim() to remove whitespace (once for the overall string and then once for each substring), and using String.Split to parse multiple values, which ends up allocating a string[] and an int[] even if there's only one value.

This commit removes all allocations from Enum.Parse other than the boxing of the Enum result and some allocations on the code path where Enum.Parse is handed a string containing a number, in which case additional allocations are involved in using the Convert.ChangeType call.

With an enum like:
```C#
[Flags]
enum Colors
{
    Red = 0x1,
    Orange = 0x2,
    Yellow = 0x4,
    Green = 0x8,
    Blue = 0x10
}
```
using ```Enum.Parse(typeof(Color), "Red")``` repeatedly now results in 5x fewer gen0 GCs and is ~15% faster.  Using ```Enum.Parse(typeof(Color), "Red, Orange, Yellow, Green, Blue")``` repeatedly now results in 23x fewer gen0 GCs is is similarly ~15% faster.
@stephentoub

This comment has been minimized.

Show comment
Hide comment
@stephentoub

stephentoub Feb 1, 2016

Member

Thanks, @jkotas. Feedback addressed.

Member

stephentoub commented Feb 1, 2016

Thanks, @jkotas. Feedback addressed.

@jkotas

This comment has been minimized.

Show comment
Hide comment
@jkotas

jkotas Feb 1, 2016

Member

👍

Member

jkotas commented Feb 1, 2016

👍

jkotas added a commit that referenced this pull request Feb 1, 2016

Merge pull request #2933 from stephentoub/enum_parse
Improve performance of Enum.Parse/TryParse

@jkotas jkotas merged commit f09b610 into dotnet:master Feb 1, 2016

8 checks passed

CentOS7.1 x64 Checked Build Build finished. 804 tests run, 0 skipped, 0 failed.
Details
FreeBSD x64 Checked Build Build finished. 804 tests run, 0 skipped, 0 failed.
Details
OSX x64 Checked Build and Test Build finished. No test results found.
Details
Ubuntu x64 Checked Build and Test Build finished. No test results found.
Details
Windows_NT x64 Debug Build and Test Build finished. 5588 tests run, 0 skipped, 0 failed.
Details
Windows_NT x64 Release Build and Test Build finished. 5588 tests run, 0 skipped, 0 failed.
Details
Windows_NT x86 Debug Build Build finished. No test results found.
Details
Windows_NT x86 Release Build Build finished. No test results found.
Details

stephentoub added a commit to stephentoub/corert that referenced this pull request Feb 6, 2016

Port dotnet/coreclr#2933 to corert
Improve performance of Enum.Parse/TryParse

stephentoub added a commit to stephentoub/corert that referenced this pull request Feb 6, 2016

Port dotnet/coreclr#2933 to corert
Improve performance of Enum.Parse/TryParse

jkotas added a commit to dotnet/corert that referenced this pull request Feb 7, 2016

@stephentoub stephentoub deleted the stephentoub:enum_parse branch Feb 12, 2016

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment