-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
[LibraryImportGenerator] Add/use CustomTypeMarshaller implementations for string marshalling #67635
Conversation
Tagging subscribers to this area: @dotnet/interop-contrib Issue DetailsWe still need #66623 to go through API review. This change has the string marshallers as they are currently proposed.
Adding the ANSI string marshaller makes it so that we do not always allocate for ANSI strings (~40-50% improvement for marshalling a string by value if it fits within the buffer such that we don't need to allocate). This also makes
|
Note regarding the This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, to please make sure the API implementation in the src *.cs file is documented with triple slash comments, so the PR reviewers can sign off that change. |
f4bd41d
to
cff2b5d
Compare
src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/AnsiStringMarshaller.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/AnsiStringMarshaller.cs
Show resolved
Hide resolved
src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/AnsiStringMarshaller.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/AnsiStringMarshaller.cs
Outdated
Show resolved
Hide resolved
...libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Utf16StringMarshaller.cs
Outdated
Show resolved
Hide resolved
...libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Utf16StringMarshaller.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Utf8StringMarshaller.cs
Outdated
Show resolved
Hide resolved
// + 1 for number of characters in case left over high surrogate is ? | ||
// * <MaxByteCountPerChar> (3 for UTF-8) | ||
// +1 for null terminator | ||
if (buffer.Length >= (str.Length + 1) * MaxByteCountPerChar + 1) |
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.
We don't want to use Encoding.UTF8.GetMaxByteCount(str)? What happens if this calculation overflows?
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.
When it used GetMaxByteCount
, it seemed to add a bit of overhead (~5% for our tests that were just marshalling a string by value), so I made it match the built-in system that just does the calculation like this. I didn't try it in the macro/asp.net tests, so maybe it doesn't really show up/matter.
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.
StringToCoTaskMemUTF8
is going to call GetMaxByteCount
anyway. We can inline the logic from StringToCoTaskMemUTF8
here and check again after calling GetMaxByteCount
whether the stack buffer is big enough.
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.
Also, does this need to allocate the memory using CoTaskMemAlloc? If it is possible, it would be a tiny bit faster to use NativeMemory.
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.
For just marshalling by value, it would be possible. For ref, we'd still want CoTaskMemAlloc, since the native side could be expecting that (could transfer ownership / free / replace), so we'd have allocate differently and free accordingly for by value versus ref.
src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Utf8StringMarshaller.cs
Outdated
Show resolved
Hide resolved
...m.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/MarshallingAttributeInfo.cs
Outdated
Show resolved
Hide resolved
9c06e48
to
c5ae13d
Compare
...libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Utf16StringMarshaller.cs
Outdated
Show resolved
Hide resolved
...libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Utf16StringMarshaller.cs
Outdated
Show resolved
Hide resolved
....InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/StringMarshaller.Ansi.cs
Show resolved
Hide resolved
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.
LGTM.
...m.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/MarshallingAttributeInfo.cs
Show resolved
Hide resolved
…erop.SourceGeneration/MarshallingAttributeInfo.cs Co-authored-by: Aaron Robinson <[email protected]>
Potential improvement seen in dotnet/perf-autofiling-issues#4754 |
Contributes to #66623
AnsiStringMarshaller
,Utf16StringMarshaller
, andUtf8StringMarshaller
Adding the ANSI string marshaller makes it so that we do not always allocate for ANSI strings (~40-50% improvement for marshalling a string by value if it fits within the buffer such that we don't need to allocate).
Ran the json/json and platform/plaintext benchmarks, copying over *.dll from Microsoft.NETCore.App in a local build.
Windows
json.benchmarks.yml --scenario json
Before:
After:
platform.benchmarks.yml --scenario plaintext
Requests per second seemed to improve by ~2-3%.Before:
After:
Linux
json.benchmarks.yml --scenario json
Before:
After:
platform.benchmarks.yml --scenario plaintext
Before:
After: