-
Notifications
You must be signed in to change notification settings - Fork 5k
Reduce Enum.GetEnumName overheads #76162
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
Conversation
Tagging subscribers to this area: @dotnet/area-system-runtime Issue DetailsThis also helps Enum.ToString(), Enum.IsDefined, etc. Many enums are composed of sequential values starting at 0 (half of all enums exposed from corelib, for example). Today when looking up a value, we search the array of values, but if an enum is known to have such sequential values, we can instead just index into the array at the appropriate location. private DayOfWeek _dow = DayOfWeek.Saturday;
[Benchmark]
public string DOWSaturday() => Enum.GetName(_dow);
|
This also helps Enum.ToString(), Enum.IsDefined, etc. Many enums are composed of sequential values starting at 0 (half of all enums in corelib, for example, meet this criteria). Today when looking up a value, we search the array of values, but if an enum is known to have such sequential values, we can instead just index into the array at the appropriate location.
489099b
to
914c15e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you are looking into squeezing more cycles from Enum formatting and parsing, you can try switching on underlying enum CorElementType as the very first thing (using a cached CorElementType for non-generic methods and intrinsic method for the generic methods), and then dispatch to specialized code for each underlying CorElementType.
The benefits of this approach should be:
- Avoid conversions to / from ulong type
- The array of values will be 2x smaller for the most common
int
underlying type - Eliminate generic code duplication for Enum methods since the switch will completely evaporate and the rest of the code will be all shared between different Enum types
This would mimic what the high-performance Enum packages out there use, except they typically do that using generic code stamping of the whole thing. Sharing the code per CorElementType should solve that problem.
@stephentoub Would it possible to also support this for "sequential" enums starting from another value (eg. one), and keep that offset around? I generally prefer to use one for the first value as I don't want a (not nullable) enum field or property to have a (valid) default value if - for some reason - it was not assigned (while it should have been). Perhaps this is not common enough for you to care - and pay the extra cost of keeping an offset around using it where applicable - though, no problem. |
Yeah, I'm not sure it's worth it. That's not to say we'd never do it, but it would add cost for everyone, and enums with sequential values starting at 1 are a lot less common than with values starting at 0. |
Do we have test coverage for both paths? |
@stephentoub, would you consider a PR where the ValuesAreSequentialFromZero bool is replaced with an ulong? (or uint?) whose value would be would be null if the values are not sequential? Not asking you to guarantee that it would be merged of course. |
That's the same as "keep that offset around" that you asked about earlier :) |
Yes |
@stephentoub, yeah indeed. I just meant to say that it's not necessary to have both the offset and the boolean, I wasn't clear enough. If I find a moment, I'll prepare a PR and we'll see how it affects performance (for both cases). |
A |
You can indeed see it that way. As I said, I'll see if I can prepare a PR. If it doesn't meet the bar, that's ok. |
This also helps Enum.ToString(), Enum.IsDefined, etc. Many enums are composed of sequential values starting at 0 (half of all enums exposed from corelib, for example). Today when looking up a value, we search the array of values, but if an enum is known to have such sequential values, we can instead just index into the array at the appropriate location.