Skip to content

Conversation

@johnthcall
Copy link
Contributor

@johnthcall johnthcall commented Aug 4, 2021

This is a followup to #44032 because changing from string,join(",", myList) to string,join(',', myList) could lead to a performance degradation.

The below benchmark includes StringJoinIntList to verify that performance doesn't degrade for joining lists of non-string types.
dotnet/performance@main...johnthcall:StringJoinChar

Method Toolchain Size Mean Error StdDev Ratio RatioSD Allocated
StringJoinStringList main 1 32.72 ns 1.464 ns 1.504 ns 1.00 0.00 40 B
StringJoinStringList pr 1 16.43 ns 0.500 ns 0.555 ns 0.50 0.03 -
StringJoinStringArray main 1 21.87 ns 0.244 ns 0.203 ns 1.00 0.00 32 B
StringJoinStringArray pr 1 10.76 ns 0.257 ns 0.214 ns 0.49 0.01 -
StringJoinClassList main 1 31.72 ns 0.540 ns 0.479 ns 1.00 0.00 40 B
StringJoinClassList pr 1 31.87 ns 0.712 ns 0.595 ns 1.01 0.03 40 B
StringJoinStringList main 10 348.21 ns 8.552 ns 9.506 ns 1.00 0.00 800 B
StringJoinStringList pr 10 112.41 ns 0.977 ns 0.816 ns 0.32 0.01 760 B
StringJoinStringArray main 10 269.76 ns 8.286 ns 9.542 ns 1.00 0.00 792 B
StringJoinStringArray pr 10 111.54 ns 3.982 ns 4.426 ns 0.41 0.03 760 B
StringJoinClassList main 10 200.61 ns 6.895 ns 7.663 ns 1.00 0.00 104 B
StringJoinClassList pr 10 206.18 ns 5.896 ns 6.789 ns 1.03 0.05 104 B
StringJoinStringList main 100 2,848.19 ns 87.952 ns 97.758 ns 1.00 0.00 7,464 B
StringJoinStringList pr 100 1,028.36 ns 45.673 ns 48.869 ns 0.36 0.02 7,424 B
StringJoinStringArray main 100 2,323.68 ns 105.224 ns 121.176 ns 1.00 0.00 7,456 B
StringJoinStringArray pr 100 978.01 ns 28.820 ns 29.596 ns 0.42 0.03 7,424 B
StringJoinClassList main 100 2,679.20 ns 71.741 ns 73.672 ns 1.00 0.00 3,520 B
StringJoinClassList pr 100 2,771.61 ns 64.748 ns 74.563 ns 1.03 0.05 3,520 B
StringJoinStringList main 1000 26,825.18 ns 754.355 ns 838.464 ns 1.00 0.00 74,064 B
StringJoinStringList pr 1000 10,222.33 ns 192.169 ns 160.470 ns 0.38 0.01 74,024 B
StringJoinStringArray main 1000 22,658.73 ns 447.658 ns 478.989 ns 1.00 0.00 74,056 B
StringJoinStringArray pr 1000 10,379.12 ns 219.172 ns 234.512 ns 0.46 0.02 74,024 B
StringJoinClassList main 1000 28,373.95 ns 754.749 ns 807.573 ns 1.00 0.00 39,520 B
StringJoinClassList pr 1000 27,968.16 ns 671.178 ns 772.929 ns 0.99 0.03 39,520 B

@ghost
Copy link

ghost commented Aug 4, 2021

I couldn't figure out the best area label to add to this PR. If you have write-permissions please help me learn by adding exactly one area label.

@ghost ghost added the community-contribution Indicates that the PR has been added by a community member label Aug 4, 2021
@stephentoub
Copy link
Member

The below benchmark includes StringJoinIntList to verify that performance doesn't degrade for joining lists of non-string types

The JIT will optimize the check away for value types. To validate impact here, you'd need to test it against some other reference type.

@stephentoub stephentoub added this to the 6.0.0 milestone Aug 5, 2021
@stephentoub
Copy link
Member

(For anyone following along, this is based on my comment: #44032 (comment))

@johnthcall
Copy link
Contributor Author

@stephentoub I've replaced benchmark StringJoinIntList with StringJoinClassList and updated the description.

@johnthcall johnthcall requested a review from stephentoub August 5, 2021 19:56
Copy link
Member

@stephentoub stephentoub left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. The small 1-3% regression is unfortunate for the T == non-string reference type cases, but I think it's worthwhile for consistency with the other overloads.

@stephentoub
Copy link
Member

cc: @GrabYourPitchforks

@johnthcall
Copy link
Contributor Author

johnthcall commented Aug 6, 2021

Another option would be to add a new overload of Join(char, IEnumerable<String>) to match the Join(String, IEnumerable<String>) method. This would make the type check of T not necessary but would require an an extra JoinCore and the method calls to it to align with the IEnumerable<T> pattern.

@stephentoub
Copy link
Member

Another option

We could consider adding an overload, but it's too late to do that for .NET 6.

Copy link
Member

@GrabYourPitchforks GrabYourPitchforks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: I'd move the null check to be first and the "is string[]?" check to be before the "is List<string>?" check. This makes the "is string[]?" check blazing fast (it's literally a single dereference and comparison) and moves the relatively more expensive "is List<string>?" to the end. The reason that check is more expensive is that the type is unsealed, which means the runtime needs to emit more complicated logic to prepare for walking a hierarchy. Another thing we could consider is an exact type match (if (foo.GetType() == typeof(List<string>))), which would eliminate the hierarchy checks.

@danmoseley
Copy link
Member

Thanks for another perf contribution @johnthcall. We welcome them!

@johnthcall johnthcall deleted the CharStringJoin branch August 11, 2021 03:48
@ghost ghost locked as resolved and limited conversation to collaborators Sep 10, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

community-contribution Indicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants