Don't use readonly struct in enumerator#74
Conversation
|
If not mistaken, a readonly field value is only copied when the field is of value type. |
|
Yep, wrong fields :) Should have been the |
|
Replaced with better change than just making it not readonly, improved MoveNext. Before After .method public hidebysig newslot virtual final
instance bool MoveNext() cil managed
{
// Code size 96 (0x60)
.maxstack 3
IL_0000: ldarg.0
IL_0001: ldfld int32 Microsoft.Extensions.Primitives.StringValues/Enumerator::_index
IL_0006: ldc.i4.0
IL_0007: bge.s IL_000b
IL_0009: ldc.i4.0
IL_000a: ret
IL_000b: ldarg.0
IL_000c: ldfld string[] Microsoft.Extensions.Primitives.StringValues/Enumerator::_values
IL_0011: brfalse.s IL_004f
IL_0013: ldarg.0
IL_0014: ldfld int32 Microsoft.Extensions.Primitives.StringValues/Enumerator::_index
IL_0019: ldarg.0
IL_001a: ldfld string[] Microsoft.Extensions.Primitives.StringValues/Enumerator::_values
IL_001f: ldlen
IL_0020: conv.i4
IL_0021: bge.s IL_0046
IL_0023: ldarg.0
IL_0024: ldarg.0
IL_0025: ldfld string[] Microsoft.Extensions.Primitives.StringValues/Enumerator::_values
IL_002a: ldarg.0
IL_002b: ldfld int32 Microsoft.Extensions.Primitives.StringValues/Enumerator::_index
IL_0030: ldelem.ref
IL_0031: stfld string Microsoft.Extensions.Primitives.StringValues/Enumerator::_current
IL_0036: ldarg.0
IL_0037: ldarg.0
IL_0038: ldfld int32 Microsoft.Extensions.Primitives.StringValues/Enumerator::_index
IL_003d: ldc.i4.1
IL_003e: add
IL_003f: stfld int32 Microsoft.Extensions.Primitives.StringValues/Enumerator::_index
IL_0044: ldc.i4.1
IL_0045: ret
IL_0046: ldarg.0
IL_0047: ldc.i4.m1
IL_0048: stfld int32 Microsoft.Extensions.Primitives.StringValues/Enumerator::_index
IL_004d: ldc.i4.0
IL_004e: ret
IL_004f: ldarg.0
IL_0050: ldc.i4.m1
IL_0051: stfld int32 Microsoft.Extensions.Primitives.StringValues/Enumerator::_index
IL_0056: ldarg.0
IL_0057: ldfld string Microsoft.Extensions.Primitives.StringValues/Enumerator::_current
IL_005c: ldnull
IL_005d: cgt.un
IL_005f: ret
} // end of method Enumerator::MoveNextShorter code path for default single value; doesn't duplicate |
|
Also changed the enumerator ctor to take StringValues by Removed the
Made
|
There was a problem hiding this comment.
When is this ever correct? Why not just leave it null, which is equally 'undefined'
There was a problem hiding this comment.
StringValue with 0 and 1 count; where the array is not set. Changed move next to fit the behaviour.
|
@benaadams - this seems innocuous, but is there any big picture impact here other than counting instructions? It's likely |
|
Are we still making |
|
@rynowak yeah, MoveNext is a player aspnet/KestrelHttpServer#528 its (RPS * header count) is half the cost of the current encoding the current headers to ascii (is a higer percentage more with improved version aspnet/KestrelHttpServer#527) |
|
@benaadams - have you tried just using indexing? |
|
@halter73 might want to remeasure |
|
|
|
@rynowak no; will give it a go. Still a high cost enumerator currently though :) And much much worse if any extra fields are added to StringValues. |
|
Still seems to me that making StringValues a class is better: Baseline (dev)Baseline w/ 4 extra fieldsStringValues ref enumeratorStringValues ref enum w/ 4 extra fieldsStringValues classStringValues class w/ 4 extra fields |
Generally only one value
|
@rynowak sped up |
|
Merged for now. If this becomes a class again, we can simplify the enumerator code. |
Ref: http://codeblog.jonskeet.uk/2014/07/16/micro-optimization-the-surprising-inefficiency-of-readonly-fields/