Add public MethodInvoker and ConstructorInvoker classes - #88415

Merged
steveharter merged 6 commits into
dotnet:mainfrom
steveharter:AddMethodInvoker
Jul 15, 2023
Merged

Add public MethodInvoker and ConstructorInvoker classes#88415
steveharter merged 6 commits into
dotnet:mainfrom
steveharter:AddMethodInvoker

Conversation

@steveharter

@stevehartersteveharter commented Jul 5, 2023

Copy link
Copy Markdown
Contributor

Fixes#85539

Adds fixed-parameter-count and Span-based Invoke APIs for performance, primarily achieved by preventing the object[] allocation for when there are <= 4 parameters. Also, additional, faster, emit-based functions are generated for methods that don't have ref\out parameters and meet other constraints. These are also used by the existing Invoke methods so performance there has increased as well.

Todo

  • Add doc for the new public methods
  • Create PR for Mono to address unboxing a "true nullable" (currently the PR doesn't generate faster emit-based code for Mono). Done - see Enable Mono for using faster invoke stubs #89108
  • Add tests that layer on top of existing ones; currently this PR just adds a handful of new tests for the new APIs.
  • Add the new benchmarks to the performance repo

Benchmarks

Benchmarks for the new APIs. ~2.4- 3.3x faster for the 4 parameter case with no allocs. Also, these improvements would be greater but they are compared to the existing Invoke API which was also made faster here.
MethodMeanErrorStdDevMedianMinMaxGen0Allocated
Method0_NoParms7.230 ns0.0205 ns0.0181 ns7.228 ns7.199 ns7.265 ns--
Method0_NoParms_InvokerEquivalent6.068 ns0.0365 ns0.0342 ns6.066 ns5.994 ns6.123 ns--
StaticMethod4_arrayNotCached_int_string_struct_class41.669 ns0.2680 ns0.2238 ns41.627 ns41.169 ns41.979 ns0.0098104 B
StaticMethod4_int_string_struct_class_InvokerArgsEquivalent17.156 ns0.1327 ns0.1242 ns17.164 ns17.004 ns17.391 ns0.004548 B
StaticMethod4_arrayNotCached_PreBoxed_int_string_struct_class37.078 ns0.2929 ns0.2446 ns37.064 ns36.747 ns37.647 ns0.005356 B
StaticMethod4_arrayNotCached_PreBoxed_int_string_struct_class_InvokerArgsEquivalent11.160 ns0.0615 ns0.0576 ns11.168 ns11.057 ns11.244 ns--
Benchmarks for existing Invoke APIs. Up to 1.4x faster for a property setter. Fewer allocs when >=5 parameters.
| Method | Job | Toolchain | Mean | Error | StdDev | Median | Min | Max | Ratio | RatioSD | Gen0 | Allocated | Alloc Ratio |
|---------------------------------------------------------- |----------- |--------------------------- |-----------:|----------:|----------:|-----------:|-----------:|-----------:|------:|--------:|-------:|----------:|------------:|
| Method0_NoParms | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 7.625 ns | 0.0528 ns | 0.0441 ns | 7.624 ns | 7.549 ns | 7.712 ns | 1.00 | 0.00 | - | - | NA |
| Method0_NoParms | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 9.401 ns | 0.0397 ns | 0.0352 ns | 9.404 ns | 9.327 ns | 9.458 ns | 1.23 | 0.01 | - | - | NA |
| | | | | | | | | | | | | | |
| StaticMethod4_arrayNotCached_int_string_struct_class | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 40.351 ns | 0.5224 ns | 0.4631 ns | 40.182 ns | 39.786 ns | 41.220 ns | 1.00 | 0.00 | 0.0099 | 104 B | 1.00 |
| StaticMethod4_arrayNotCached_int_string_struct_class | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 49.067 ns | 0.9783 ns | 1.0468 ns | 48.853 ns | 47.515 ns | 51.704 ns | 1.22 | 0.03 | 0.0098 | 104 B | 1.00 |
| | | | | | | | | | | | | | |
| StaticMethod5_arrayNotCached_int_string_struct_class_bool | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 56.730 ns | 0.5781 ns | 0.5408 ns | 56.669 ns | 55.909 ns | 57.890 ns | 1.00 | 0.00 | 0.0128 | 136 B | 1.00 |
| StaticMethod5_arrayNotCached_int_string_struct_class_bool | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 74.827 ns | 1.6601 ns | 1.8452 ns | 74.496 ns | 71.119 ns | 78.316 ns | 1.32 | 0.03 | 0.0191 | 200 B | 1.47 |
| | | | | | | | | | | | | | |
| StaticMethod4_int_string_struct_class | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 28.537 ns | 0.2502 ns | 0.2218 ns | 28.585 ns | 28.185 ns | 28.842 ns | 1.00 | 0.00 | - | - | NA |
| StaticMethod4_int_string_struct_class | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 34.938 ns | 0.1109 ns | 0.0983 ns | 34.899 ns | 34.821 ns | 35.179 ns | 1.22 | 0.01 | - | - | NA |
| | | | | | | | | | | | | | |
| StaticMethod4_ByRefParams_int_string_struct_class | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 144.779 ns | 1.0213 ns | 0.9054 ns | 144.673 ns | 142.893 ns | 146.116 ns | 1.00 | 0.00 | 0.0041 | 48 B | 1.00 |
| StaticMethod4_ByRefParams_int_string_struct_class | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 138.456 ns | 0.2052 ns | 0.1714 ns | 138.511 ns | 138.134 ns | 138.783 ns | 0.96 | 0.01 | 0.0043 | 48 B | 1.00 |
| | | | | | | | | | | | | | |
| StaticMethod5_ByRefParams_int_string_struct_class_bool | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 196.652 ns | 1.2706 ns | 1.1885 ns | 196.883 ns | 194.293 ns | 198.425 ns | 1.00 | 0.00 | 0.0063 | 72 B | 1.00 |
| StaticMethod5_ByRefParams_int_string_struct_class_bool | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 193.105 ns | 1.0413 ns | 0.8696 ns | 193.156 ns | 191.592 ns | 194.599 ns | 0.98 | 0.01 | 0.0123 | 136 B | 1.89 |
| | | | | | | | | | | | | | |
| Ctor0_NoParams | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 9.128 ns | 0.0912 ns | 0.0853 ns | 9.137 ns | 9.005 ns | 9.264 ns | 1.00 | 0.00 | 0.0053 | 56 B | 1.00 |
| Ctor0_NoParams | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 11.096 ns | 0.1013 ns | 0.0947 ns | 11.085 ns | 10.965 ns | 11.262 ns | 1.22 | 0.02 | 0.0053 | 56 B | 1.00 |
| | | | | | | | | | | | | | |
| Ctor4_int_string_struct_class | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 32.506 ns | 0.2559 ns | 0.2137 ns | 32.561 ns | 32.026 ns | 32.865 ns | 1.00 | 0.00 | 0.0053 | 56 B | 1.00 |
| Ctor4_int_string_struct_class | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 39.152 ns | 0.2872 ns | 0.2687 ns | 39.151 ns | 38.818 ns | 39.719 ns | 1.20 | 0.01 | 0.0052 | 56 B | 1.00 |
| | | | | | | | | | | | | | |
| Property_Get_int | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 10.565 ns | 0.1276 ns | 0.1131 ns | 10.581 ns | 10.416 ns | 10.833 ns | 1.00 | 0.00 | 0.0023 | 24 B | 1.00 |
| Property_Get_int | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 12.435 ns | 0.0953 ns | 0.0845 ns | 12.432 ns | 12.299 ns | 12.604 ns | 1.18 | 0.01 | 0.0023 | 24 B | 1.00 |
| | | | | | | | | | | | | | |
| Property_Get_class | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 8.091 ns | 0.0468 ns | 0.0415 ns | 8.093 ns | 8.037 ns | 8.178 ns | 1.00 | 0.00 | - | - | NA |
| Property_Get_class | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 10.549 ns | 0.0877 ns | 0.0778 ns | 10.555 ns | 10.411 ns | 10.685 ns | 1.30 | 0.01 | - | - | NA |
| | | | | | | | | | | | | | |
| Property_Set_int | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 16.105 ns | 0.1308 ns | 0.1160 ns | 16.110 ns | 15.916 ns | 16.325 ns | 1.00 | 0.00 | 0.0023 | 24 B | 1.00 |
| Property_Set_int | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 21.829 ns | 0.4245 ns | 0.3971 ns | 21.916 ns | 21.035 ns | 22.320 ns | 1.35 | 0.03 | 0.0022 | 24 B | 1.00 |
| | | | | | | | | | | | | | |
| Property_Set_class | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 13.299 ns | 0.0699 ns | 0.0654 ns | 13.304 ns | 13.209 ns | 13.383 ns | 1.00 | 0.00 | - | - | NA |
| Property_Set_class | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 18.799 ns | 0.1101 ns | 0.1030 ns | 18.764 ns | 18.636 ns | 19.001 ns | 1.41 | 0.01 | - | - | NA |
Benchmarks for NativeAot. ~1.3-1.7x faster when using the new APIs
old 0 args: 1014
new 0 args: 595
old 1 arg: 4860
new 1 arg: 3319
old 2 args:7595
new 2 args:5875
old 5 args:16292
new 5 args:15325

ghost commented Jul 5, 2023

Copy link
Copy Markdown

Note regarding the new-api-needs-documentation label:

This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, 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.

ghost commented Jul 5, 2023

Copy link
Copy Markdown

Tagging subscribers to this area: @dotnet/area-system-reflection
See info in area-owners.md if you want to be subscribed.

Issue Details

[wip]

Author:steveharter
Assignees:steveharter
Labels:

area-System.Reflection

Milestone:-

Comment threadsrc/libraries/System.Private.CoreLib/src/System/Reflection/MethodInvoker.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Reflection/MethodInvoker.cs Outdated
Comment threadsrc/libraries/System.Runtime/ref/System.Runtime.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Reflection/MethodInvoker.cs Outdated
Comment threadbuild Outdated
Comment threadsrc/coreclr/vm/ecalllist.h Outdated

ghost left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Left a few NITs, overall looks good to me.

RuntimeType sigType = _argTypes[i];

// Convert the type if necessary.
// Note that Type.Missing is not supported.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

NIT: By assuming this applyes to all new Invoke methods, this might be good to be added to the public doc

Comment threadsrc/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeType.cs Outdated
@cincuranet

ghost commented Jul 20, 2023

Copy link
Copy Markdown
Contributor

Improvement in dotnet/perf-autofiling-issues#19968.

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[API Proposal]: Add invoker classes for fast invoke APIs

5 participants

@steveharter@cincuranet@jkotas@AaronRobinsonMSFT@buyaa-n
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Add public MethodInvoker and ConstructorInvoker classes - #88415

Merged
steveharter merged 6 commits into
dotnet:mainfrom
steveharter:AddMethodInvoker
Jul 15, 2023
Merged

Add public MethodInvoker and ConstructorInvoker classes#88415
steveharter merged 6 commits into
dotnet:mainfrom
steveharter:AddMethodInvoker

Conversation

@steveharter

@stevehartersteveharter commented Jul 5, 2023

Copy link
Copy Markdown
Contributor

Fixes#85539

Adds fixed-parameter-count and Span-based Invoke APIs for performance, primarily achieved by preventing the object[] allocation for when there are <= 4 parameters. Also, additional, faster, emit-based functions are generated for methods that don't have ref\out parameters and meet other constraints. These are also used by the existing Invoke methods so performance there has increased as well.

Todo

  • Add doc for the new public methods
  • Create PR for Mono to address unboxing a "true nullable" (currently the PR doesn't generate faster emit-based code for Mono). Done - see Enable Mono for using faster invoke stubs #89108
  • Add tests that layer on top of existing ones; currently this PR just adds a handful of new tests for the new APIs.
  • Add the new benchmarks to the performance repo

Benchmarks

Benchmarks for the new APIs. ~2.4- 3.3x faster for the 4 parameter case with no allocs. Also, these improvements would be greater but they are compared to the existing Invoke API which was also made faster here.
MethodMeanErrorStdDevMedianMinMaxGen0Allocated
Method0_NoParms7.230 ns0.0205 ns0.0181 ns7.228 ns7.199 ns7.265 ns--
Method0_NoParms_InvokerEquivalent6.068 ns0.0365 ns0.0342 ns6.066 ns5.994 ns6.123 ns--
StaticMethod4_arrayNotCached_int_string_struct_class41.669 ns0.2680 ns0.2238 ns41.627 ns41.169 ns41.979 ns0.0098104 B
StaticMethod4_int_string_struct_class_InvokerArgsEquivalent17.156 ns0.1327 ns0.1242 ns17.164 ns17.004 ns17.391 ns0.004548 B
StaticMethod4_arrayNotCached_PreBoxed_int_string_struct_class37.078 ns0.2929 ns0.2446 ns37.064 ns36.747 ns37.647 ns0.005356 B
StaticMethod4_arrayNotCached_PreBoxed_int_string_struct_class_InvokerArgsEquivalent11.160 ns0.0615 ns0.0576 ns11.168 ns11.057 ns11.244 ns--
Benchmarks for existing Invoke APIs. Up to 1.4x faster for a property setter. Fewer allocs when >=5 parameters.
| Method | Job | Toolchain | Mean | Error | StdDev | Median | Min | Max | Ratio | RatioSD | Gen0 | Allocated | Alloc Ratio |
|---------------------------------------------------------- |----------- |--------------------------- |-----------:|----------:|----------:|-----------:|-----------:|-----------:|------:|--------:|-------:|----------:|------------:|
| Method0_NoParms | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 7.625 ns | 0.0528 ns | 0.0441 ns | 7.624 ns | 7.549 ns | 7.712 ns | 1.00 | 0.00 | - | - | NA |
| Method0_NoParms | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 9.401 ns | 0.0397 ns | 0.0352 ns | 9.404 ns | 9.327 ns | 9.458 ns | 1.23 | 0.01 | - | - | NA |
| | | | | | | | | | | | | | |
| StaticMethod4_arrayNotCached_int_string_struct_class | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 40.351 ns | 0.5224 ns | 0.4631 ns | 40.182 ns | 39.786 ns | 41.220 ns | 1.00 | 0.00 | 0.0099 | 104 B | 1.00 |
| StaticMethod4_arrayNotCached_int_string_struct_class | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 49.067 ns | 0.9783 ns | 1.0468 ns | 48.853 ns | 47.515 ns | 51.704 ns | 1.22 | 0.03 | 0.0098 | 104 B | 1.00 |
| | | | | | | | | | | | | | |
| StaticMethod5_arrayNotCached_int_string_struct_class_bool | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 56.730 ns | 0.5781 ns | 0.5408 ns | 56.669 ns | 55.909 ns | 57.890 ns | 1.00 | 0.00 | 0.0128 | 136 B | 1.00 |
| StaticMethod5_arrayNotCached_int_string_struct_class_bool | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 74.827 ns | 1.6601 ns | 1.8452 ns | 74.496 ns | 71.119 ns | 78.316 ns | 1.32 | 0.03 | 0.0191 | 200 B | 1.47 |
| | | | | | | | | | | | | | |
| StaticMethod4_int_string_struct_class | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 28.537 ns | 0.2502 ns | 0.2218 ns | 28.585 ns | 28.185 ns | 28.842 ns | 1.00 | 0.00 | - | - | NA |
| StaticMethod4_int_string_struct_class | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 34.938 ns | 0.1109 ns | 0.0983 ns | 34.899 ns | 34.821 ns | 35.179 ns | 1.22 | 0.01 | - | - | NA |
| | | | | | | | | | | | | | |
| StaticMethod4_ByRefParams_int_string_struct_class | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 144.779 ns | 1.0213 ns | 0.9054 ns | 144.673 ns | 142.893 ns | 146.116 ns | 1.00 | 0.00 | 0.0041 | 48 B | 1.00 |
| StaticMethod4_ByRefParams_int_string_struct_class | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 138.456 ns | 0.2052 ns | 0.1714 ns | 138.511 ns | 138.134 ns | 138.783 ns | 0.96 | 0.01 | 0.0043 | 48 B | 1.00 |
| | | | | | | | | | | | | | |
| StaticMethod5_ByRefParams_int_string_struct_class_bool | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 196.652 ns | 1.2706 ns | 1.1885 ns | 196.883 ns | 194.293 ns | 198.425 ns | 1.00 | 0.00 | 0.0063 | 72 B | 1.00 |
| StaticMethod5_ByRefParams_int_string_struct_class_bool | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 193.105 ns | 1.0413 ns | 0.8696 ns | 193.156 ns | 191.592 ns | 194.599 ns | 0.98 | 0.01 | 0.0123 | 136 B | 1.89 |
| | | | | | | | | | | | | | |
| Ctor0_NoParams | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 9.128 ns | 0.0912 ns | 0.0853 ns | 9.137 ns | 9.005 ns | 9.264 ns | 1.00 | 0.00 | 0.0053 | 56 B | 1.00 |
| Ctor0_NoParams | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 11.096 ns | 0.1013 ns | 0.0947 ns | 11.085 ns | 10.965 ns | 11.262 ns | 1.22 | 0.02 | 0.0053 | 56 B | 1.00 |
| | | | | | | | | | | | | | |
| Ctor4_int_string_struct_class | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 32.506 ns | 0.2559 ns | 0.2137 ns | 32.561 ns | 32.026 ns | 32.865 ns | 1.00 | 0.00 | 0.0053 | 56 B | 1.00 |
| Ctor4_int_string_struct_class | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 39.152 ns | 0.2872 ns | 0.2687 ns | 39.151 ns | 38.818 ns | 39.719 ns | 1.20 | 0.01 | 0.0052 | 56 B | 1.00 |
| | | | | | | | | | | | | | |
| Property_Get_int | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 10.565 ns | 0.1276 ns | 0.1131 ns | 10.581 ns | 10.416 ns | 10.833 ns | 1.00 | 0.00 | 0.0023 | 24 B | 1.00 |
| Property_Get_int | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 12.435 ns | 0.0953 ns | 0.0845 ns | 12.432 ns | 12.299 ns | 12.604 ns | 1.18 | 0.01 | 0.0023 | 24 B | 1.00 |
| | | | | | | | | | | | | | |
| Property_Get_class | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 8.091 ns | 0.0468 ns | 0.0415 ns | 8.093 ns | 8.037 ns | 8.178 ns | 1.00 | 0.00 | - | - | NA |
| Property_Get_class | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 10.549 ns | 0.0877 ns | 0.0778 ns | 10.555 ns | 10.411 ns | 10.685 ns | 1.30 | 0.01 | - | - | NA |
| | | | | | | | | | | | | | |
| Property_Set_int | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 16.105 ns | 0.1308 ns | 0.1160 ns | 16.110 ns | 15.916 ns | 16.325 ns | 1.00 | 0.00 | 0.0023 | 24 B | 1.00 |
| Property_Set_int | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 21.829 ns | 0.4245 ns | 0.3971 ns | 21.916 ns | 21.035 ns | 22.320 ns | 1.35 | 0.03 | 0.0022 | 24 B | 1.00 |
| | | | | | | | | | | | | | |
| Property_Set_class | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 13.299 ns | 0.0699 ns | 0.0654 ns | 13.304 ns | 13.209 ns | 13.383 ns | 1.00 | 0.00 | - | - | NA |
| Property_Set_class | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 18.799 ns | 0.1101 ns | 0.1030 ns | 18.764 ns | 18.636 ns | 19.001 ns | 1.41 | 0.01 | - | - | NA |
Benchmarks for NativeAot. ~1.3-1.7x faster when using the new APIs
old 0 args: 1014
new 0 args: 595
old 1 arg: 4860
new 1 arg: 3319
old 2 args:7595
new 2 args:5875
old 5 args:16292
new 5 args:15325

ghost commented Jul 5, 2023

Copy link
Copy Markdown

Note regarding the new-api-needs-documentation label:

This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, 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.

ghost commented Jul 5, 2023

Copy link
Copy Markdown

Tagging subscribers to this area: @dotnet/area-system-reflection
See info in area-owners.md if you want to be subscribed.

Issue Details

[wip]

Author:steveharter
Assignees:steveharter
Labels:

area-System.Reflection

Milestone:-

Comment threadsrc/libraries/System.Private.CoreLib/src/System/Reflection/MethodInvoker.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Reflection/MethodInvoker.cs Outdated
Comment threadsrc/libraries/System.Runtime/ref/System.Runtime.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Reflection/MethodInvoker.cs Outdated
Comment threadbuild Outdated
Comment threadsrc/coreclr/vm/ecalllist.h Outdated

ghost left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Left a few NITs, overall looks good to me.

RuntimeType sigType = _argTypes[i];

// Convert the type if necessary.
// Note that Type.Missing is not supported.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

NIT: By assuming this applyes to all new Invoke methods, this might be good to be added to the public doc

Comment threadsrc/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeType.cs Outdated
@cincuranet

ghost commented Jul 20, 2023

Copy link
Copy Markdown
Contributor

Improvement in dotnet/perf-autofiling-issues#19968.

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[API Proposal]: Add invoker classes for fast invoke APIs

5 participants

@steveharter@cincuranet@jkotas@AaronRobinsonMSFT@buyaa-n
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add public MethodInvoker and ConstructorInvoker classes - #88415

Merged
steveharter merged 6 commits into
dotnet:mainfrom
steveharter:AddMethodInvoker
Jul 15, 2023
Merged

Add public MethodInvoker and ConstructorInvoker classes#88415
steveharter merged 6 commits into
dotnet:mainfrom
steveharter:AddMethodInvoker

Conversation

@steveharter

@stevehartersteveharter commented Jul 5, 2023

Copy link
Copy Markdown
Contributor

Fixes#85539

Adds fixed-parameter-count and Span-based Invoke APIs for performance, primarily achieved by preventing the object[] allocation for when there are <= 4 parameters. Also, additional, faster, emit-based functions are generated for methods that don't have ref\out parameters and meet other constraints. These are also used by the existing Invoke methods so performance there has increased as well.

Todo

  • Add doc for the new public methods
  • Create PR for Mono to address unboxing a "true nullable" (currently the PR doesn't generate faster emit-based code for Mono). Done - see Enable Mono for using faster invoke stubs #89108
  • Add tests that layer on top of existing ones; currently this PR just adds a handful of new tests for the new APIs.
  • Add the new benchmarks to the performance repo

Benchmarks

Benchmarks for the new APIs. ~2.4- 3.3x faster for the 4 parameter case with no allocs. Also, these improvements would be greater but they are compared to the existing Invoke API which was also made faster here.
MethodMeanErrorStdDevMedianMinMaxGen0Allocated
Method0_NoParms7.230 ns0.0205 ns0.0181 ns7.228 ns7.199 ns7.265 ns--
Method0_NoParms_InvokerEquivalent6.068 ns0.0365 ns0.0342 ns6.066 ns5.994 ns6.123 ns--
StaticMethod4_arrayNotCached_int_string_struct_class41.669 ns0.2680 ns0.2238 ns41.627 ns41.169 ns41.979 ns0.0098104 B
StaticMethod4_int_string_struct_class_InvokerArgsEquivalent17.156 ns0.1327 ns0.1242 ns17.164 ns17.004 ns17.391 ns0.004548 B
StaticMethod4_arrayNotCached_PreBoxed_int_string_struct_class37.078 ns0.2929 ns0.2446 ns37.064 ns36.747 ns37.647 ns0.005356 B
StaticMethod4_arrayNotCached_PreBoxed_int_string_struct_class_InvokerArgsEquivalent11.160 ns0.0615 ns0.0576 ns11.168 ns11.057 ns11.244 ns--
Benchmarks for existing Invoke APIs. Up to 1.4x faster for a property setter. Fewer allocs when >=5 parameters.
| Method | Job | Toolchain | Mean | Error | StdDev | Median | Min | Max | Ratio | RatioSD | Gen0 | Allocated | Alloc Ratio |
|---------------------------------------------------------- |----------- |--------------------------- |-----------:|----------:|----------:|-----------:|-----------:|-----------:|------:|--------:|-------:|----------:|------------:|
| Method0_NoParms | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 7.625 ns | 0.0528 ns | 0.0441 ns | 7.624 ns | 7.549 ns | 7.712 ns | 1.00 | 0.00 | - | - | NA |
| Method0_NoParms | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 9.401 ns | 0.0397 ns | 0.0352 ns | 9.404 ns | 9.327 ns | 9.458 ns | 1.23 | 0.01 | - | - | NA |
| | | | | | | | | | | | | | |
| StaticMethod4_arrayNotCached_int_string_struct_class | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 40.351 ns | 0.5224 ns | 0.4631 ns | 40.182 ns | 39.786 ns | 41.220 ns | 1.00 | 0.00 | 0.0099 | 104 B | 1.00 |
| StaticMethod4_arrayNotCached_int_string_struct_class | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 49.067 ns | 0.9783 ns | 1.0468 ns | 48.853 ns | 47.515 ns | 51.704 ns | 1.22 | 0.03 | 0.0098 | 104 B | 1.00 |
| | | | | | | | | | | | | | |
| StaticMethod5_arrayNotCached_int_string_struct_class_bool | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 56.730 ns | 0.5781 ns | 0.5408 ns | 56.669 ns | 55.909 ns | 57.890 ns | 1.00 | 0.00 | 0.0128 | 136 B | 1.00 |
| StaticMethod5_arrayNotCached_int_string_struct_class_bool | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 74.827 ns | 1.6601 ns | 1.8452 ns | 74.496 ns | 71.119 ns | 78.316 ns | 1.32 | 0.03 | 0.0191 | 200 B | 1.47 |
| | | | | | | | | | | | | | |
| StaticMethod4_int_string_struct_class | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 28.537 ns | 0.2502 ns | 0.2218 ns | 28.585 ns | 28.185 ns | 28.842 ns | 1.00 | 0.00 | - | - | NA |
| StaticMethod4_int_string_struct_class | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 34.938 ns | 0.1109 ns | 0.0983 ns | 34.899 ns | 34.821 ns | 35.179 ns | 1.22 | 0.01 | - | - | NA |
| | | | | | | | | | | | | | |
| StaticMethod4_ByRefParams_int_string_struct_class | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 144.779 ns | 1.0213 ns | 0.9054 ns | 144.673 ns | 142.893 ns | 146.116 ns | 1.00 | 0.00 | 0.0041 | 48 B | 1.00 |
| StaticMethod4_ByRefParams_int_string_struct_class | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 138.456 ns | 0.2052 ns | 0.1714 ns | 138.511 ns | 138.134 ns | 138.783 ns | 0.96 | 0.01 | 0.0043 | 48 B | 1.00 |
| | | | | | | | | | | | | | |
| StaticMethod5_ByRefParams_int_string_struct_class_bool | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 196.652 ns | 1.2706 ns | 1.1885 ns | 196.883 ns | 194.293 ns | 198.425 ns | 1.00 | 0.00 | 0.0063 | 72 B | 1.00 |
| StaticMethod5_ByRefParams_int_string_struct_class_bool | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 193.105 ns | 1.0413 ns | 0.8696 ns | 193.156 ns | 191.592 ns | 194.599 ns | 0.98 | 0.01 | 0.0123 | 136 B | 1.89 |
| | | | | | | | | | | | | | |
| Ctor0_NoParams | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 9.128 ns | 0.0912 ns | 0.0853 ns | 9.137 ns | 9.005 ns | 9.264 ns | 1.00 | 0.00 | 0.0053 | 56 B | 1.00 |
| Ctor0_NoParams | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 11.096 ns | 0.1013 ns | 0.0947 ns | 11.085 ns | 10.965 ns | 11.262 ns | 1.22 | 0.02 | 0.0053 | 56 B | 1.00 |
| | | | | | | | | | | | | | |
| Ctor4_int_string_struct_class | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 32.506 ns | 0.2559 ns | 0.2137 ns | 32.561 ns | 32.026 ns | 32.865 ns | 1.00 | 0.00 | 0.0053 | 56 B | 1.00 |
| Ctor4_int_string_struct_class | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 39.152 ns | 0.2872 ns | 0.2687 ns | 39.151 ns | 38.818 ns | 39.719 ns | 1.20 | 0.01 | 0.0052 | 56 B | 1.00 |
| | | | | | | | | | | | | | |
| Property_Get_int | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 10.565 ns | 0.1276 ns | 0.1131 ns | 10.581 ns | 10.416 ns | 10.833 ns | 1.00 | 0.00 | 0.0023 | 24 B | 1.00 |
| Property_Get_int | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 12.435 ns | 0.0953 ns | 0.0845 ns | 12.432 ns | 12.299 ns | 12.604 ns | 1.18 | 0.01 | 0.0023 | 24 B | 1.00 |
| | | | | | | | | | | | | | |
| Property_Get_class | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 8.091 ns | 0.0468 ns | 0.0415 ns | 8.093 ns | 8.037 ns | 8.178 ns | 1.00 | 0.00 | - | - | NA |
| Property_Get_class | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 10.549 ns | 0.0877 ns | 0.0778 ns | 10.555 ns | 10.411 ns | 10.685 ns | 1.30 | 0.01 | - | - | NA |
| | | | | | | | | | | | | | |
| Property_Set_int | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 16.105 ns | 0.1308 ns | 0.1160 ns | 16.110 ns | 15.916 ns | 16.325 ns | 1.00 | 0.00 | 0.0023 | 24 B | 1.00 |
| Property_Set_int | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 21.829 ns | 0.4245 ns | 0.3971 ns | 21.916 ns | 21.035 ns | 22.320 ns | 1.35 | 0.03 | 0.0022 | 24 B | 1.00 |
| | | | | | | | | | | | | | |
| Property_Set_class | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 13.299 ns | 0.0699 ns | 0.0654 ns | 13.304 ns | 13.209 ns | 13.383 ns | 1.00 | 0.00 | - | - | NA |
| Property_Set_class | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 18.799 ns | 0.1101 ns | 0.1030 ns | 18.764 ns | 18.636 ns | 19.001 ns | 1.41 | 0.01 | - | - | NA |
Benchmarks for NativeAot. ~1.3-1.7x faster when using the new APIs
old 0 args: 1014
new 0 args: 595
old 1 arg: 4860
new 1 arg: 3319
old 2 args:7595
new 2 args:5875
old 5 args:16292
new 5 args:15325

ghost commented Jul 5, 2023

Copy link
Copy Markdown

Note regarding the new-api-needs-documentation label:

This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, 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.

ghost commented Jul 5, 2023

Copy link
Copy Markdown

Tagging subscribers to this area: @dotnet/area-system-reflection
See info in area-owners.md if you want to be subscribed.

Issue Details

[wip]

Author:steveharter
Assignees:steveharter
Labels:

area-System.Reflection

Milestone:-

Comment threadsrc/libraries/System.Private.CoreLib/src/System/Reflection/MethodInvoker.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Reflection/MethodInvoker.cs Outdated
Comment threadsrc/libraries/System.Runtime/ref/System.Runtime.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Reflection/MethodInvoker.cs Outdated
Comment threadbuild Outdated
Comment threadsrc/coreclr/vm/ecalllist.h Outdated

ghost left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Left a few NITs, overall looks good to me.

RuntimeType sigType = _argTypes[i];

// Convert the type if necessary.
// Note that Type.Missing is not supported.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

NIT: By assuming this applyes to all new Invoke methods, this might be good to be added to the public doc

Comment threadsrc/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeType.cs Outdated
@cincuranet

ghost commented Jul 20, 2023

Copy link
Copy Markdown
Contributor

Improvement in dotnet/perf-autofiling-issues#19968.

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[API Proposal]: Add invoker classes for fast invoke APIs

5 participants

@steveharter@cincuranet@jkotas@AaronRobinsonMSFT@buyaa-n
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add public MethodInvoker and ConstructorInvoker classes - #88415

Merged
steveharter merged 6 commits into
dotnet:mainfrom
steveharter:AddMethodInvoker
Jul 15, 2023
Merged

Add public MethodInvoker and ConstructorInvoker classes#88415
steveharter merged 6 commits into
dotnet:mainfrom
steveharter:AddMethodInvoker

Conversation

@steveharter

@stevehartersteveharter commented Jul 5, 2023

Copy link
Copy Markdown
Contributor

Fixes#85539

Adds fixed-parameter-count and Span-based Invoke APIs for performance, primarily achieved by preventing the object[] allocation for when there are <= 4 parameters. Also, additional, faster, emit-based functions are generated for methods that don't have ref\out parameters and meet other constraints. These are also used by the existing Invoke methods so performance there has increased as well.

Todo

  • Add doc for the new public methods
  • Create PR for Mono to address unboxing a "true nullable" (currently the PR doesn't generate faster emit-based code for Mono). Done - see Enable Mono for using faster invoke stubs #89108
  • Add tests that layer on top of existing ones; currently this PR just adds a handful of new tests for the new APIs.
  • Add the new benchmarks to the performance repo

Benchmarks

Benchmarks for the new APIs. ~2.4- 3.3x faster for the 4 parameter case with no allocs. Also, these improvements would be greater but they are compared to the existing Invoke API which was also made faster here.
MethodMeanErrorStdDevMedianMinMaxGen0Allocated
Method0_NoParms7.230 ns0.0205 ns0.0181 ns7.228 ns7.199 ns7.265 ns--
Method0_NoParms_InvokerEquivalent6.068 ns0.0365 ns0.0342 ns6.066 ns5.994 ns6.123 ns--
StaticMethod4_arrayNotCached_int_string_struct_class41.669 ns0.2680 ns0.2238 ns41.627 ns41.169 ns41.979 ns0.0098104 B
StaticMethod4_int_string_struct_class_InvokerArgsEquivalent17.156 ns0.1327 ns0.1242 ns17.164 ns17.004 ns17.391 ns0.004548 B
StaticMethod4_arrayNotCached_PreBoxed_int_string_struct_class37.078 ns0.2929 ns0.2446 ns37.064 ns36.747 ns37.647 ns0.005356 B
StaticMethod4_arrayNotCached_PreBoxed_int_string_struct_class_InvokerArgsEquivalent11.160 ns0.0615 ns0.0576 ns11.168 ns11.057 ns11.244 ns--
Benchmarks for existing Invoke APIs. Up to 1.4x faster for a property setter. Fewer allocs when >=5 parameters.
| Method | Job | Toolchain | Mean | Error | StdDev | Median | Min | Max | Ratio | RatioSD | Gen0 | Allocated | Alloc Ratio |
|---------------------------------------------------------- |----------- |--------------------------- |-----------:|----------:|----------:|-----------:|-----------:|-----------:|------:|--------:|-------:|----------:|------------:|
| Method0_NoParms | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 7.625 ns | 0.0528 ns | 0.0441 ns | 7.624 ns | 7.549 ns | 7.712 ns | 1.00 | 0.00 | - | - | NA |
| Method0_NoParms | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 9.401 ns | 0.0397 ns | 0.0352 ns | 9.404 ns | 9.327 ns | 9.458 ns | 1.23 | 0.01 | - | - | NA |
| | | | | | | | | | | | | | |
| StaticMethod4_arrayNotCached_int_string_struct_class | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 40.351 ns | 0.5224 ns | 0.4631 ns | 40.182 ns | 39.786 ns | 41.220 ns | 1.00 | 0.00 | 0.0099 | 104 B | 1.00 |
| StaticMethod4_arrayNotCached_int_string_struct_class | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 49.067 ns | 0.9783 ns | 1.0468 ns | 48.853 ns | 47.515 ns | 51.704 ns | 1.22 | 0.03 | 0.0098 | 104 B | 1.00 |
| | | | | | | | | | | | | | |
| StaticMethod5_arrayNotCached_int_string_struct_class_bool | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 56.730 ns | 0.5781 ns | 0.5408 ns | 56.669 ns | 55.909 ns | 57.890 ns | 1.00 | 0.00 | 0.0128 | 136 B | 1.00 |
| StaticMethod5_arrayNotCached_int_string_struct_class_bool | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 74.827 ns | 1.6601 ns | 1.8452 ns | 74.496 ns | 71.119 ns | 78.316 ns | 1.32 | 0.03 | 0.0191 | 200 B | 1.47 |
| | | | | | | | | | | | | | |
| StaticMethod4_int_string_struct_class | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 28.537 ns | 0.2502 ns | 0.2218 ns | 28.585 ns | 28.185 ns | 28.842 ns | 1.00 | 0.00 | - | - | NA |
| StaticMethod4_int_string_struct_class | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 34.938 ns | 0.1109 ns | 0.0983 ns | 34.899 ns | 34.821 ns | 35.179 ns | 1.22 | 0.01 | - | - | NA |
| | | | | | | | | | | | | | |
| StaticMethod4_ByRefParams_int_string_struct_class | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 144.779 ns | 1.0213 ns | 0.9054 ns | 144.673 ns | 142.893 ns | 146.116 ns | 1.00 | 0.00 | 0.0041 | 48 B | 1.00 |
| StaticMethod4_ByRefParams_int_string_struct_class | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 138.456 ns | 0.2052 ns | 0.1714 ns | 138.511 ns | 138.134 ns | 138.783 ns | 0.96 | 0.01 | 0.0043 | 48 B | 1.00 |
| | | | | | | | | | | | | | |
| StaticMethod5_ByRefParams_int_string_struct_class_bool | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 196.652 ns | 1.2706 ns | 1.1885 ns | 196.883 ns | 194.293 ns | 198.425 ns | 1.00 | 0.00 | 0.0063 | 72 B | 1.00 |
| StaticMethod5_ByRefParams_int_string_struct_class_bool | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 193.105 ns | 1.0413 ns | 0.8696 ns | 193.156 ns | 191.592 ns | 194.599 ns | 0.98 | 0.01 | 0.0123 | 136 B | 1.89 |
| | | | | | | | | | | | | | |
| Ctor0_NoParams | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 9.128 ns | 0.0912 ns | 0.0853 ns | 9.137 ns | 9.005 ns | 9.264 ns | 1.00 | 0.00 | 0.0053 | 56 B | 1.00 |
| Ctor0_NoParams | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 11.096 ns | 0.1013 ns | 0.0947 ns | 11.085 ns | 10.965 ns | 11.262 ns | 1.22 | 0.02 | 0.0053 | 56 B | 1.00 |
| | | | | | | | | | | | | | |
| Ctor4_int_string_struct_class | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 32.506 ns | 0.2559 ns | 0.2137 ns | 32.561 ns | 32.026 ns | 32.865 ns | 1.00 | 0.00 | 0.0053 | 56 B | 1.00 |
| Ctor4_int_string_struct_class | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 39.152 ns | 0.2872 ns | 0.2687 ns | 39.151 ns | 38.818 ns | 39.719 ns | 1.20 | 0.01 | 0.0052 | 56 B | 1.00 |
| | | | | | | | | | | | | | |
| Property_Get_int | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 10.565 ns | 0.1276 ns | 0.1131 ns | 10.581 ns | 10.416 ns | 10.833 ns | 1.00 | 0.00 | 0.0023 | 24 B | 1.00 |
| Property_Get_int | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 12.435 ns | 0.0953 ns | 0.0845 ns | 12.432 ns | 12.299 ns | 12.604 ns | 1.18 | 0.01 | 0.0023 | 24 B | 1.00 |
| | | | | | | | | | | | | | |
| Property_Get_class | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 8.091 ns | 0.0468 ns | 0.0415 ns | 8.093 ns | 8.037 ns | 8.178 ns | 1.00 | 0.00 | - | - | NA |
| Property_Get_class | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 10.549 ns | 0.0877 ns | 0.0778 ns | 10.555 ns | 10.411 ns | 10.685 ns | 1.30 | 0.01 | - | - | NA |
| | | | | | | | | | | | | | |
| Property_Set_int | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 16.105 ns | 0.1308 ns | 0.1160 ns | 16.110 ns | 15.916 ns | 16.325 ns | 1.00 | 0.00 | 0.0023 | 24 B | 1.00 |
| Property_Set_int | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 21.829 ns | 0.4245 ns | 0.3971 ns | 21.916 ns | 21.035 ns | 22.320 ns | 1.35 | 0.03 | 0.0022 | 24 B | 1.00 |
| | | | | | | | | | | | | | |
| Property_Set_class | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 13.299 ns | 0.0699 ns | 0.0654 ns | 13.304 ns | 13.209 ns | 13.383 ns | 1.00 | 0.00 | - | - | NA |
| Property_Set_class | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 18.799 ns | 0.1101 ns | 0.1030 ns | 18.764 ns | 18.636 ns | 19.001 ns | 1.41 | 0.01 | - | - | NA |
Benchmarks for NativeAot. ~1.3-1.7x faster when using the new APIs
old 0 args: 1014
new 0 args: 595
old 1 arg: 4860
new 1 arg: 3319
old 2 args:7595
new 2 args:5875
old 5 args:16292
new 5 args:15325

ghost commented Jul 5, 2023

Copy link
Copy Markdown

Note regarding the new-api-needs-documentation label:

This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, 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.

ghost commented Jul 5, 2023

Copy link
Copy Markdown

Tagging subscribers to this area: @dotnet/area-system-reflection
See info in area-owners.md if you want to be subscribed.

Issue Details

[wip]

Author:steveharter
Assignees:steveharter
Labels:

area-System.Reflection

Milestone:-

Comment threadsrc/libraries/System.Private.CoreLib/src/System/Reflection/MethodInvoker.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Reflection/MethodInvoker.cs Outdated
Comment threadsrc/libraries/System.Runtime/ref/System.Runtime.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Reflection/MethodInvoker.cs Outdated
Comment threadbuild Outdated
Comment threadsrc/coreclr/vm/ecalllist.h Outdated

ghost left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Left a few NITs, overall looks good to me.

RuntimeType sigType = _argTypes[i];

// Convert the type if necessary.
// Note that Type.Missing is not supported.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

NIT: By assuming this applyes to all new Invoke methods, this might be good to be added to the public doc

Comment threadsrc/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeType.cs Outdated
@cincuranet

ghost commented Jul 20, 2023

Copy link
Copy Markdown
Contributor

Improvement in dotnet/perf-autofiling-issues#19968.

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[API Proposal]: Add invoker classes for fast invoke APIs

5 participants

@steveharter@cincuranet@jkotas@AaronRobinsonMSFT@buyaa-n
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Add public MethodInvoker and ConstructorInvoker classes - #88415

Merged
steveharter merged 6 commits into
dotnet:mainfrom
steveharter:AddMethodInvoker
Jul 15, 2023
Merged

Add public MethodInvoker and ConstructorInvoker classes#88415
steveharter merged 6 commits into
dotnet:mainfrom
steveharter:AddMethodInvoker

Conversation

@steveharter

@stevehartersteveharter commented Jul 5, 2023

Copy link
Copy Markdown
Contributor

Fixes#85539

Adds fixed-parameter-count and Span-based Invoke APIs for performance, primarily achieved by preventing the object[] allocation for when there are <= 4 parameters. Also, additional, faster, emit-based functions are generated for methods that don't have ref\out parameters and meet other constraints. These are also used by the existing Invoke methods so performance there has increased as well.

Todo

  • Add doc for the new public methods
  • Create PR for Mono to address unboxing a "true nullable" (currently the PR doesn't generate faster emit-based code for Mono). Done - see Enable Mono for using faster invoke stubs #89108
  • Add tests that layer on top of existing ones; currently this PR just adds a handful of new tests for the new APIs.
  • Add the new benchmarks to the performance repo

Benchmarks

Benchmarks for the new APIs. ~2.4- 3.3x faster for the 4 parameter case with no allocs. Also, these improvements would be greater but they are compared to the existing Invoke API which was also made faster here.
MethodMeanErrorStdDevMedianMinMaxGen0Allocated
Method0_NoParms7.230 ns0.0205 ns0.0181 ns7.228 ns7.199 ns7.265 ns--
Method0_NoParms_InvokerEquivalent6.068 ns0.0365 ns0.0342 ns6.066 ns5.994 ns6.123 ns--
StaticMethod4_arrayNotCached_int_string_struct_class41.669 ns0.2680 ns0.2238 ns41.627 ns41.169 ns41.979 ns0.0098104 B
StaticMethod4_int_string_struct_class_InvokerArgsEquivalent17.156 ns0.1327 ns0.1242 ns17.164 ns17.004 ns17.391 ns0.004548 B
StaticMethod4_arrayNotCached_PreBoxed_int_string_struct_class37.078 ns0.2929 ns0.2446 ns37.064 ns36.747 ns37.647 ns0.005356 B
StaticMethod4_arrayNotCached_PreBoxed_int_string_struct_class_InvokerArgsEquivalent11.160 ns0.0615 ns0.0576 ns11.168 ns11.057 ns11.244 ns--
Benchmarks for existing Invoke APIs. Up to 1.4x faster for a property setter. Fewer allocs when >=5 parameters.
| Method | Job | Toolchain | Mean | Error | StdDev | Median | Min | Max | Ratio | RatioSD | Gen0 | Allocated | Alloc Ratio |
|---------------------------------------------------------- |----------- |--------------------------- |-----------:|----------:|----------:|-----------:|-----------:|-----------:|------:|--------:|-------:|----------:|------------:|
| Method0_NoParms | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 7.625 ns | 0.0528 ns | 0.0441 ns | 7.624 ns | 7.549 ns | 7.712 ns | 1.00 | 0.00 | - | - | NA |
| Method0_NoParms | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 9.401 ns | 0.0397 ns | 0.0352 ns | 9.404 ns | 9.327 ns | 9.458 ns | 1.23 | 0.01 | - | - | NA |
| | | | | | | | | | | | | | |
| StaticMethod4_arrayNotCached_int_string_struct_class | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 40.351 ns | 0.5224 ns | 0.4631 ns | 40.182 ns | 39.786 ns | 41.220 ns | 1.00 | 0.00 | 0.0099 | 104 B | 1.00 |
| StaticMethod4_arrayNotCached_int_string_struct_class | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 49.067 ns | 0.9783 ns | 1.0468 ns | 48.853 ns | 47.515 ns | 51.704 ns | 1.22 | 0.03 | 0.0098 | 104 B | 1.00 |
| | | | | | | | | | | | | | |
| StaticMethod5_arrayNotCached_int_string_struct_class_bool | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 56.730 ns | 0.5781 ns | 0.5408 ns | 56.669 ns | 55.909 ns | 57.890 ns | 1.00 | 0.00 | 0.0128 | 136 B | 1.00 |
| StaticMethod5_arrayNotCached_int_string_struct_class_bool | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 74.827 ns | 1.6601 ns | 1.8452 ns | 74.496 ns | 71.119 ns | 78.316 ns | 1.32 | 0.03 | 0.0191 | 200 B | 1.47 |
| | | | | | | | | | | | | | |
| StaticMethod4_int_string_struct_class | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 28.537 ns | 0.2502 ns | 0.2218 ns | 28.585 ns | 28.185 ns | 28.842 ns | 1.00 | 0.00 | - | - | NA |
| StaticMethod4_int_string_struct_class | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 34.938 ns | 0.1109 ns | 0.0983 ns | 34.899 ns | 34.821 ns | 35.179 ns | 1.22 | 0.01 | - | - | NA |
| | | | | | | | | | | | | | |
| StaticMethod4_ByRefParams_int_string_struct_class | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 144.779 ns | 1.0213 ns | 0.9054 ns | 144.673 ns | 142.893 ns | 146.116 ns | 1.00 | 0.00 | 0.0041 | 48 B | 1.00 |
| StaticMethod4_ByRefParams_int_string_struct_class | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 138.456 ns | 0.2052 ns | 0.1714 ns | 138.511 ns | 138.134 ns | 138.783 ns | 0.96 | 0.01 | 0.0043 | 48 B | 1.00 |
| | | | | | | | | | | | | | |
| StaticMethod5_ByRefParams_int_string_struct_class_bool | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 196.652 ns | 1.2706 ns | 1.1885 ns | 196.883 ns | 194.293 ns | 198.425 ns | 1.00 | 0.00 | 0.0063 | 72 B | 1.00 |
| StaticMethod5_ByRefParams_int_string_struct_class_bool | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 193.105 ns | 1.0413 ns | 0.8696 ns | 193.156 ns | 191.592 ns | 194.599 ns | 0.98 | 0.01 | 0.0123 | 136 B | 1.89 |
| | | | | | | | | | | | | | |
| Ctor0_NoParams | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 9.128 ns | 0.0912 ns | 0.0853 ns | 9.137 ns | 9.005 ns | 9.264 ns | 1.00 | 0.00 | 0.0053 | 56 B | 1.00 |
| Ctor0_NoParams | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 11.096 ns | 0.1013 ns | 0.0947 ns | 11.085 ns | 10.965 ns | 11.262 ns | 1.22 | 0.02 | 0.0053 | 56 B | 1.00 |
| | | | | | | | | | | | | | |
| Ctor4_int_string_struct_class | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 32.506 ns | 0.2559 ns | 0.2137 ns | 32.561 ns | 32.026 ns | 32.865 ns | 1.00 | 0.00 | 0.0053 | 56 B | 1.00 |
| Ctor4_int_string_struct_class | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 39.152 ns | 0.2872 ns | 0.2687 ns | 39.151 ns | 38.818 ns | 39.719 ns | 1.20 | 0.01 | 0.0052 | 56 B | 1.00 |
| | | | | | | | | | | | | | |
| Property_Get_int | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 10.565 ns | 0.1276 ns | 0.1131 ns | 10.581 ns | 10.416 ns | 10.833 ns | 1.00 | 0.00 | 0.0023 | 24 B | 1.00 |
| Property_Get_int | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 12.435 ns | 0.0953 ns | 0.0845 ns | 12.432 ns | 12.299 ns | 12.604 ns | 1.18 | 0.01 | 0.0023 | 24 B | 1.00 |
| | | | | | | | | | | | | | |
| Property_Get_class | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 8.091 ns | 0.0468 ns | 0.0415 ns | 8.093 ns | 8.037 ns | 8.178 ns | 1.00 | 0.00 | - | - | NA |
| Property_Get_class | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 10.549 ns | 0.0877 ns | 0.0778 ns | 10.555 ns | 10.411 ns | 10.685 ns | 1.30 | 0.01 | - | - | NA |
| | | | | | | | | | | | | | |
| Property_Set_int | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 16.105 ns | 0.1308 ns | 0.1160 ns | 16.110 ns | 15.916 ns | 16.325 ns | 1.00 | 0.00 | 0.0023 | 24 B | 1.00 |
| Property_Set_int | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 21.829 ns | 0.4245 ns | 0.3971 ns | 21.916 ns | 21.035 ns | 22.320 ns | 1.35 | 0.03 | 0.0022 | 24 B | 1.00 |
| | | | | | | | | | | | | | |
| Property_Set_class | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 13.299 ns | 0.0699 ns | 0.0654 ns | 13.304 ns | 13.209 ns | 13.383 ns | 1.00 | 0.00 | - | - | NA |
| Property_Set_class | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 18.799 ns | 0.1101 ns | 0.1030 ns | 18.764 ns | 18.636 ns | 19.001 ns | 1.41 | 0.01 | - | - | NA |
Benchmarks for NativeAot. ~1.3-1.7x faster when using the new APIs
old 0 args: 1014
new 0 args: 595
old 1 arg: 4860
new 1 arg: 3319
old 2 args:7595
new 2 args:5875
old 5 args:16292
new 5 args:15325

ghost commented Jul 5, 2023

Copy link
Copy Markdown

Note regarding the new-api-needs-documentation label:

This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, 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.

ghost commented Jul 5, 2023

Copy link
Copy Markdown

Tagging subscribers to this area: @dotnet/area-system-reflection
See info in area-owners.md if you want to be subscribed.

Issue Details

[wip]

Author:steveharter
Assignees:steveharter
Labels:

area-System.Reflection

Milestone:-

Comment threadsrc/libraries/System.Private.CoreLib/src/System/Reflection/MethodInvoker.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Reflection/MethodInvoker.cs Outdated
Comment threadsrc/libraries/System.Runtime/ref/System.Runtime.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Reflection/MethodInvoker.cs Outdated
Comment threadbuild Outdated
Comment threadsrc/coreclr/vm/ecalllist.h Outdated

ghost left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Left a few NITs, overall looks good to me.

RuntimeType sigType = _argTypes[i];

// Convert the type if necessary.
// Note that Type.Missing is not supported.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

NIT: By assuming this applyes to all new Invoke methods, this might be good to be added to the public doc

Comment threadsrc/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeType.cs Outdated
@cincuranet

ghost commented Jul 20, 2023

Copy link
Copy Markdown
Contributor

Improvement in dotnet/perf-autofiling-issues#19968.

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[API Proposal]: Add invoker classes for fast invoke APIs

5 participants

@steveharter@cincuranet@jkotas@AaronRobinsonMSFT@buyaa-n
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add public MethodInvoker and ConstructorInvoker classes - #88415

Merged
steveharter merged 6 commits into
dotnet:mainfrom
steveharter:AddMethodInvoker
Jul 15, 2023
Merged

Add public MethodInvoker and ConstructorInvoker classes#88415
steveharter merged 6 commits into
dotnet:mainfrom
steveharter:AddMethodInvoker

Conversation

@steveharter

@stevehartersteveharter commented Jul 5, 2023

Copy link
Copy Markdown
Contributor

Fixes#85539

Adds fixed-parameter-count and Span-based Invoke APIs for performance, primarily achieved by preventing the object[] allocation for when there are <= 4 parameters. Also, additional, faster, emit-based functions are generated for methods that don't have ref\out parameters and meet other constraints. These are also used by the existing Invoke methods so performance there has increased as well.

Todo

  • Add doc for the new public methods
  • Create PR for Mono to address unboxing a "true nullable" (currently the PR doesn't generate faster emit-based code for Mono). Done - see Enable Mono for using faster invoke stubs #89108
  • Add tests that layer on top of existing ones; currently this PR just adds a handful of new tests for the new APIs.
  • Add the new benchmarks to the performance repo

Benchmarks

Benchmarks for the new APIs. ~2.4- 3.3x faster for the 4 parameter case with no allocs. Also, these improvements would be greater but they are compared to the existing Invoke API which was also made faster here.
MethodMeanErrorStdDevMedianMinMaxGen0Allocated
Method0_NoParms7.230 ns0.0205 ns0.0181 ns7.228 ns7.199 ns7.265 ns--
Method0_NoParms_InvokerEquivalent6.068 ns0.0365 ns0.0342 ns6.066 ns5.994 ns6.123 ns--
StaticMethod4_arrayNotCached_int_string_struct_class41.669 ns0.2680 ns0.2238 ns41.627 ns41.169 ns41.979 ns0.0098104 B
StaticMethod4_int_string_struct_class_InvokerArgsEquivalent17.156 ns0.1327 ns0.1242 ns17.164 ns17.004 ns17.391 ns0.004548 B
StaticMethod4_arrayNotCached_PreBoxed_int_string_struct_class37.078 ns0.2929 ns0.2446 ns37.064 ns36.747 ns37.647 ns0.005356 B
StaticMethod4_arrayNotCached_PreBoxed_int_string_struct_class_InvokerArgsEquivalent11.160 ns0.0615 ns0.0576 ns11.168 ns11.057 ns11.244 ns--
Benchmarks for existing Invoke APIs. Up to 1.4x faster for a property setter. Fewer allocs when >=5 parameters.
| Method | Job | Toolchain | Mean | Error | StdDev | Median | Min | Max | Ratio | RatioSD | Gen0 | Allocated | Alloc Ratio |
|---------------------------------------------------------- |----------- |--------------------------- |-----------:|----------:|----------:|-----------:|-----------:|-----------:|------:|--------:|-------:|----------:|------------:|
| Method0_NoParms | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 7.625 ns | 0.0528 ns | 0.0441 ns | 7.624 ns | 7.549 ns | 7.712 ns | 1.00 | 0.00 | - | - | NA |
| Method0_NoParms | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 9.401 ns | 0.0397 ns | 0.0352 ns | 9.404 ns | 9.327 ns | 9.458 ns | 1.23 | 0.01 | - | - | NA |
| | | | | | | | | | | | | | |
| StaticMethod4_arrayNotCached_int_string_struct_class | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 40.351 ns | 0.5224 ns | 0.4631 ns | 40.182 ns | 39.786 ns | 41.220 ns | 1.00 | 0.00 | 0.0099 | 104 B | 1.00 |
| StaticMethod4_arrayNotCached_int_string_struct_class | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 49.067 ns | 0.9783 ns | 1.0468 ns | 48.853 ns | 47.515 ns | 51.704 ns | 1.22 | 0.03 | 0.0098 | 104 B | 1.00 |
| | | | | | | | | | | | | | |
| StaticMethod5_arrayNotCached_int_string_struct_class_bool | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 56.730 ns | 0.5781 ns | 0.5408 ns | 56.669 ns | 55.909 ns | 57.890 ns | 1.00 | 0.00 | 0.0128 | 136 B | 1.00 |
| StaticMethod5_arrayNotCached_int_string_struct_class_bool | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 74.827 ns | 1.6601 ns | 1.8452 ns | 74.496 ns | 71.119 ns | 78.316 ns | 1.32 | 0.03 | 0.0191 | 200 B | 1.47 |
| | | | | | | | | | | | | | |
| StaticMethod4_int_string_struct_class | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 28.537 ns | 0.2502 ns | 0.2218 ns | 28.585 ns | 28.185 ns | 28.842 ns | 1.00 | 0.00 | - | - | NA |
| StaticMethod4_int_string_struct_class | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 34.938 ns | 0.1109 ns | 0.0983 ns | 34.899 ns | 34.821 ns | 35.179 ns | 1.22 | 0.01 | - | - | NA |
| | | | | | | | | | | | | | |
| StaticMethod4_ByRefParams_int_string_struct_class | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 144.779 ns | 1.0213 ns | 0.9054 ns | 144.673 ns | 142.893 ns | 146.116 ns | 1.00 | 0.00 | 0.0041 | 48 B | 1.00 |
| StaticMethod4_ByRefParams_int_string_struct_class | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 138.456 ns | 0.2052 ns | 0.1714 ns | 138.511 ns | 138.134 ns | 138.783 ns | 0.96 | 0.01 | 0.0043 | 48 B | 1.00 |
| | | | | | | | | | | | | | |
| StaticMethod5_ByRefParams_int_string_struct_class_bool | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 196.652 ns | 1.2706 ns | 1.1885 ns | 196.883 ns | 194.293 ns | 198.425 ns | 1.00 | 0.00 | 0.0063 | 72 B | 1.00 |
| StaticMethod5_ByRefParams_int_string_struct_class_bool | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 193.105 ns | 1.0413 ns | 0.8696 ns | 193.156 ns | 191.592 ns | 194.599 ns | 0.98 | 0.01 | 0.0123 | 136 B | 1.89 |
| | | | | | | | | | | | | | |
| Ctor0_NoParams | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 9.128 ns | 0.0912 ns | 0.0853 ns | 9.137 ns | 9.005 ns | 9.264 ns | 1.00 | 0.00 | 0.0053 | 56 B | 1.00 |
| Ctor0_NoParams | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 11.096 ns | 0.1013 ns | 0.0947 ns | 11.085 ns | 10.965 ns | 11.262 ns | 1.22 | 0.02 | 0.0053 | 56 B | 1.00 |
| | | | | | | | | | | | | | |
| Ctor4_int_string_struct_class | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 32.506 ns | 0.2559 ns | 0.2137 ns | 32.561 ns | 32.026 ns | 32.865 ns | 1.00 | 0.00 | 0.0053 | 56 B | 1.00 |
| Ctor4_int_string_struct_class | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 39.152 ns | 0.2872 ns | 0.2687 ns | 39.151 ns | 38.818 ns | 39.719 ns | 1.20 | 0.01 | 0.0052 | 56 B | 1.00 |
| | | | | | | | | | | | | | |
| Property_Get_int | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 10.565 ns | 0.1276 ns | 0.1131 ns | 10.581 ns | 10.416 ns | 10.833 ns | 1.00 | 0.00 | 0.0023 | 24 B | 1.00 |
| Property_Get_int | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 12.435 ns | 0.0953 ns | 0.0845 ns | 12.432 ns | 12.299 ns | 12.604 ns | 1.18 | 0.01 | 0.0023 | 24 B | 1.00 |
| | | | | | | | | | | | | | |
| Property_Get_class | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 8.091 ns | 0.0468 ns | 0.0415 ns | 8.093 ns | 8.037 ns | 8.178 ns | 1.00 | 0.00 | - | - | NA |
| Property_Get_class | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 10.549 ns | 0.0877 ns | 0.0778 ns | 10.555 ns | 10.411 ns | 10.685 ns | 1.30 | 0.01 | - | - | NA |
| | | | | | | | | | | | | | |
| Property_Set_int | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 16.105 ns | 0.1308 ns | 0.1160 ns | 16.110 ns | 15.916 ns | 16.325 ns | 1.00 | 0.00 | 0.0023 | 24 B | 1.00 |
| Property_Set_int | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 21.829 ns | 0.4245 ns | 0.3971 ns | 21.916 ns | 21.035 ns | 22.320 ns | 1.35 | 0.03 | 0.0022 | 24 B | 1.00 |
| | | | | | | | | | | | | | |
| Property_Set_class | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 13.299 ns | 0.0699 ns | 0.0654 ns | 13.304 ns | 13.209 ns | 13.383 ns | 1.00 | 0.00 | - | - | NA |
| Property_Set_class | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 18.799 ns | 0.1101 ns | 0.1030 ns | 18.764 ns | 18.636 ns | 19.001 ns | 1.41 | 0.01 | - | - | NA |
Benchmarks for NativeAot. ~1.3-1.7x faster when using the new APIs
old 0 args: 1014
new 0 args: 595
old 1 arg: 4860
new 1 arg: 3319
old 2 args:7595
new 2 args:5875
old 5 args:16292
new 5 args:15325

ghost commented Jul 5, 2023

Copy link
Copy Markdown

Note regarding the new-api-needs-documentation label:

This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, 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.

ghost commented Jul 5, 2023

Copy link
Copy Markdown

Tagging subscribers to this area: @dotnet/area-system-reflection
See info in area-owners.md if you want to be subscribed.

Issue Details

[wip]

Author:steveharter
Assignees:steveharter
Labels:

area-System.Reflection

Milestone:-

Comment threadsrc/libraries/System.Private.CoreLib/src/System/Reflection/MethodInvoker.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Reflection/MethodInvoker.cs Outdated
Comment threadsrc/libraries/System.Runtime/ref/System.Runtime.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Reflection/MethodInvoker.cs Outdated
Comment threadbuild Outdated
Comment threadsrc/coreclr/vm/ecalllist.h Outdated

ghost left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Left a few NITs, overall looks good to me.

RuntimeType sigType = _argTypes[i];

// Convert the type if necessary.
// Note that Type.Missing is not supported.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

NIT: By assuming this applyes to all new Invoke methods, this might be good to be added to the public doc

Comment threadsrc/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeType.cs Outdated
@cincuranet

ghost commented Jul 20, 2023

Copy link
Copy Markdown
Contributor

Improvement in dotnet/perf-autofiling-issues#19968.

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[API Proposal]: Add invoker classes for fast invoke APIs

5 participants

@steveharter@cincuranet@jkotas@AaronRobinsonMSFT@buyaa-n
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add public MethodInvoker and ConstructorInvoker classes - #88415

Merged
steveharter merged 6 commits into
dotnet:mainfrom
steveharter:AddMethodInvoker
Jul 15, 2023
Merged

Add public MethodInvoker and ConstructorInvoker classes#88415
steveharter merged 6 commits into
dotnet:mainfrom
steveharter:AddMethodInvoker

Conversation

@steveharter

@stevehartersteveharter commented Jul 5, 2023

Copy link
Copy Markdown
Contributor

Fixes#85539

Adds fixed-parameter-count and Span-based Invoke APIs for performance, primarily achieved by preventing the object[] allocation for when there are <= 4 parameters. Also, additional, faster, emit-based functions are generated for methods that don't have ref\out parameters and meet other constraints. These are also used by the existing Invoke methods so performance there has increased as well.

Todo

  • Add doc for the new public methods
  • Create PR for Mono to address unboxing a "true nullable" (currently the PR doesn't generate faster emit-based code for Mono). Done - see Enable Mono for using faster invoke stubs #89108
  • Add tests that layer on top of existing ones; currently this PR just adds a handful of new tests for the new APIs.
  • Add the new benchmarks to the performance repo

Benchmarks

Benchmarks for the new APIs. ~2.4- 3.3x faster for the 4 parameter case with no allocs. Also, these improvements would be greater but they are compared to the existing Invoke API which was also made faster here.
MethodMeanErrorStdDevMedianMinMaxGen0Allocated
Method0_NoParms7.230 ns0.0205 ns0.0181 ns7.228 ns7.199 ns7.265 ns--
Method0_NoParms_InvokerEquivalent6.068 ns0.0365 ns0.0342 ns6.066 ns5.994 ns6.123 ns--
StaticMethod4_arrayNotCached_int_string_struct_class41.669 ns0.2680 ns0.2238 ns41.627 ns41.169 ns41.979 ns0.0098104 B
StaticMethod4_int_string_struct_class_InvokerArgsEquivalent17.156 ns0.1327 ns0.1242 ns17.164 ns17.004 ns17.391 ns0.004548 B
StaticMethod4_arrayNotCached_PreBoxed_int_string_struct_class37.078 ns0.2929 ns0.2446 ns37.064 ns36.747 ns37.647 ns0.005356 B
StaticMethod4_arrayNotCached_PreBoxed_int_string_struct_class_InvokerArgsEquivalent11.160 ns0.0615 ns0.0576 ns11.168 ns11.057 ns11.244 ns--
Benchmarks for existing Invoke APIs. Up to 1.4x faster for a property setter. Fewer allocs when >=5 parameters.
| Method | Job | Toolchain | Mean | Error | StdDev | Median | Min | Max | Ratio | RatioSD | Gen0 | Allocated | Alloc Ratio |
|---------------------------------------------------------- |----------- |--------------------------- |-----------:|----------:|----------:|-----------:|-----------:|-----------:|------:|--------:|-------:|----------:|------------:|
| Method0_NoParms | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 7.625 ns | 0.0528 ns | 0.0441 ns | 7.624 ns | 7.549 ns | 7.712 ns | 1.00 | 0.00 | - | - | NA |
| Method0_NoParms | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 9.401 ns | 0.0397 ns | 0.0352 ns | 9.404 ns | 9.327 ns | 9.458 ns | 1.23 | 0.01 | - | - | NA |
| | | | | | | | | | | | | | |
| StaticMethod4_arrayNotCached_int_string_struct_class | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 40.351 ns | 0.5224 ns | 0.4631 ns | 40.182 ns | 39.786 ns | 41.220 ns | 1.00 | 0.00 | 0.0099 | 104 B | 1.00 |
| StaticMethod4_arrayNotCached_int_string_struct_class | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 49.067 ns | 0.9783 ns | 1.0468 ns | 48.853 ns | 47.515 ns | 51.704 ns | 1.22 | 0.03 | 0.0098 | 104 B | 1.00 |
| | | | | | | | | | | | | | |
| StaticMethod5_arrayNotCached_int_string_struct_class_bool | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 56.730 ns | 0.5781 ns | 0.5408 ns | 56.669 ns | 55.909 ns | 57.890 ns | 1.00 | 0.00 | 0.0128 | 136 B | 1.00 |
| StaticMethod5_arrayNotCached_int_string_struct_class_bool | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 74.827 ns | 1.6601 ns | 1.8452 ns | 74.496 ns | 71.119 ns | 78.316 ns | 1.32 | 0.03 | 0.0191 | 200 B | 1.47 |
| | | | | | | | | | | | | | |
| StaticMethod4_int_string_struct_class | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 28.537 ns | 0.2502 ns | 0.2218 ns | 28.585 ns | 28.185 ns | 28.842 ns | 1.00 | 0.00 | - | - | NA |
| StaticMethod4_int_string_struct_class | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 34.938 ns | 0.1109 ns | 0.0983 ns | 34.899 ns | 34.821 ns | 35.179 ns | 1.22 | 0.01 | - | - | NA |
| | | | | | | | | | | | | | |
| StaticMethod4_ByRefParams_int_string_struct_class | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 144.779 ns | 1.0213 ns | 0.9054 ns | 144.673 ns | 142.893 ns | 146.116 ns | 1.00 | 0.00 | 0.0041 | 48 B | 1.00 |
| StaticMethod4_ByRefParams_int_string_struct_class | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 138.456 ns | 0.2052 ns | 0.1714 ns | 138.511 ns | 138.134 ns | 138.783 ns | 0.96 | 0.01 | 0.0043 | 48 B | 1.00 |
| | | | | | | | | | | | | | |
| StaticMethod5_ByRefParams_int_string_struct_class_bool | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 196.652 ns | 1.2706 ns | 1.1885 ns | 196.883 ns | 194.293 ns | 198.425 ns | 1.00 | 0.00 | 0.0063 | 72 B | 1.00 |
| StaticMethod5_ByRefParams_int_string_struct_class_bool | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 193.105 ns | 1.0413 ns | 0.8696 ns | 193.156 ns | 191.592 ns | 194.599 ns | 0.98 | 0.01 | 0.0123 | 136 B | 1.89 |
| | | | | | | | | | | | | | |
| Ctor0_NoParams | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 9.128 ns | 0.0912 ns | 0.0853 ns | 9.137 ns | 9.005 ns | 9.264 ns | 1.00 | 0.00 | 0.0053 | 56 B | 1.00 |
| Ctor0_NoParams | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 11.096 ns | 0.1013 ns | 0.0947 ns | 11.085 ns | 10.965 ns | 11.262 ns | 1.22 | 0.02 | 0.0053 | 56 B | 1.00 |
| | | | | | | | | | | | | | |
| Ctor4_int_string_struct_class | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 32.506 ns | 0.2559 ns | 0.2137 ns | 32.561 ns | 32.026 ns | 32.865 ns | 1.00 | 0.00 | 0.0053 | 56 B | 1.00 |
| Ctor4_int_string_struct_class | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 39.152 ns | 0.2872 ns | 0.2687 ns | 39.151 ns | 38.818 ns | 39.719 ns | 1.20 | 0.01 | 0.0052 | 56 B | 1.00 |
| | | | | | | | | | | | | | |
| Property_Get_int | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 10.565 ns | 0.1276 ns | 0.1131 ns | 10.581 ns | 10.416 ns | 10.833 ns | 1.00 | 0.00 | 0.0023 | 24 B | 1.00 |
| Property_Get_int | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 12.435 ns | 0.0953 ns | 0.0845 ns | 12.432 ns | 12.299 ns | 12.604 ns | 1.18 | 0.01 | 0.0023 | 24 B | 1.00 |
| | | | | | | | | | | | | | |
| Property_Get_class | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 8.091 ns | 0.0468 ns | 0.0415 ns | 8.093 ns | 8.037 ns | 8.178 ns | 1.00 | 0.00 | - | - | NA |
| Property_Get_class | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 10.549 ns | 0.0877 ns | 0.0778 ns | 10.555 ns | 10.411 ns | 10.685 ns | 1.30 | 0.01 | - | - | NA |
| | | | | | | | | | | | | | |
| Property_Set_int | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 16.105 ns | 0.1308 ns | 0.1160 ns | 16.110 ns | 15.916 ns | 16.325 ns | 1.00 | 0.00 | 0.0023 | 24 B | 1.00 |
| Property_Set_int | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 21.829 ns | 0.4245 ns | 0.3971 ns | 21.916 ns | 21.035 ns | 22.320 ns | 1.35 | 0.03 | 0.0022 | 24 B | 1.00 |
| | | | | | | | | | | | | | |
| Property_Set_class | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 13.299 ns | 0.0699 ns | 0.0654 ns | 13.304 ns | 13.209 ns | 13.383 ns | 1.00 | 0.00 | - | - | NA |
| Property_Set_class | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 18.799 ns | 0.1101 ns | 0.1030 ns | 18.764 ns | 18.636 ns | 19.001 ns | 1.41 | 0.01 | - | - | NA |
Benchmarks for NativeAot. ~1.3-1.7x faster when using the new APIs
old 0 args: 1014
new 0 args: 595
old 1 arg: 4860
new 1 arg: 3319
old 2 args:7595
new 2 args:5875
old 5 args:16292
new 5 args:15325

ghost commented Jul 5, 2023

Copy link
Copy Markdown

Note regarding the new-api-needs-documentation label:

This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, 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.

ghost commented Jul 5, 2023

Copy link
Copy Markdown

Tagging subscribers to this area: @dotnet/area-system-reflection
See info in area-owners.md if you want to be subscribed.

Issue Details

[wip]

Author:steveharter
Assignees:steveharter
Labels:

area-System.Reflection

Milestone:-

Comment threadsrc/libraries/System.Private.CoreLib/src/System/Reflection/MethodInvoker.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Reflection/MethodInvoker.cs Outdated
Comment threadsrc/libraries/System.Runtime/ref/System.Runtime.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Reflection/MethodInvoker.cs Outdated
Comment threadbuild Outdated
Comment threadsrc/coreclr/vm/ecalllist.h Outdated

ghost left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Left a few NITs, overall looks good to me.

RuntimeType sigType = _argTypes[i];

// Convert the type if necessary.
// Note that Type.Missing is not supported.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

NIT: By assuming this applyes to all new Invoke methods, this might be good to be added to the public doc

Comment threadsrc/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeType.cs Outdated
@cincuranet

ghost commented Jul 20, 2023

Copy link
Copy Markdown
Contributor

Improvement in dotnet/perf-autofiling-issues#19968.

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[API Proposal]: Add invoker classes for fast invoke APIs

5 participants

@steveharter@cincuranet@jkotas@AaronRobinsonMSFT@buyaa-n
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Add public MethodInvoker and ConstructorInvoker classes - #88415

Merged
steveharter merged 6 commits into
dotnet:mainfrom
steveharter:AddMethodInvoker
Jul 15, 2023
Merged

Add public MethodInvoker and ConstructorInvoker classes#88415
steveharter merged 6 commits into
dotnet:mainfrom
steveharter:AddMethodInvoker

Conversation

@steveharter

@stevehartersteveharter commented Jul 5, 2023

Copy link
Copy Markdown
Contributor

Fixes#85539

Adds fixed-parameter-count and Span-based Invoke APIs for performance, primarily achieved by preventing the object[] allocation for when there are <= 4 parameters. Also, additional, faster, emit-based functions are generated for methods that don't have ref\out parameters and meet other constraints. These are also used by the existing Invoke methods so performance there has increased as well.

Todo

  • Add doc for the new public methods
  • Create PR for Mono to address unboxing a "true nullable" (currently the PR doesn't generate faster emit-based code for Mono). Done - see Enable Mono for using faster invoke stubs #89108
  • Add tests that layer on top of existing ones; currently this PR just adds a handful of new tests for the new APIs.
  • Add the new benchmarks to the performance repo

Benchmarks

Benchmarks for the new APIs. ~2.4- 3.3x faster for the 4 parameter case with no allocs. Also, these improvements would be greater but they are compared to the existing Invoke API which was also made faster here.
MethodMeanErrorStdDevMedianMinMaxGen0Allocated
Method0_NoParms7.230 ns0.0205 ns0.0181 ns7.228 ns7.199 ns7.265 ns--
Method0_NoParms_InvokerEquivalent6.068 ns0.0365 ns0.0342 ns6.066 ns5.994 ns6.123 ns--
StaticMethod4_arrayNotCached_int_string_struct_class41.669 ns0.2680 ns0.2238 ns41.627 ns41.169 ns41.979 ns0.0098104 B
StaticMethod4_int_string_struct_class_InvokerArgsEquivalent17.156 ns0.1327 ns0.1242 ns17.164 ns17.004 ns17.391 ns0.004548 B
StaticMethod4_arrayNotCached_PreBoxed_int_string_struct_class37.078 ns0.2929 ns0.2446 ns37.064 ns36.747 ns37.647 ns0.005356 B
StaticMethod4_arrayNotCached_PreBoxed_int_string_struct_class_InvokerArgsEquivalent11.160 ns0.0615 ns0.0576 ns11.168 ns11.057 ns11.244 ns--
Benchmarks for existing Invoke APIs. Up to 1.4x faster for a property setter. Fewer allocs when >=5 parameters.
| Method | Job | Toolchain | Mean | Error | StdDev | Median | Min | Max | Ratio | RatioSD | Gen0 | Allocated | Alloc Ratio |
|---------------------------------------------------------- |----------- |--------------------------- |-----------:|----------:|----------:|-----------:|-----------:|-----------:|------:|--------:|-------:|----------:|------------:|
| Method0_NoParms | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 7.625 ns | 0.0528 ns | 0.0441 ns | 7.624 ns | 7.549 ns | 7.712 ns | 1.00 | 0.00 | - | - | NA |
| Method0_NoParms | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 9.401 ns | 0.0397 ns | 0.0352 ns | 9.404 ns | 9.327 ns | 9.458 ns | 1.23 | 0.01 | - | - | NA |
| | | | | | | | | | | | | | |
| StaticMethod4_arrayNotCached_int_string_struct_class | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 40.351 ns | 0.5224 ns | 0.4631 ns | 40.182 ns | 39.786 ns | 41.220 ns | 1.00 | 0.00 | 0.0099 | 104 B | 1.00 |
| StaticMethod4_arrayNotCached_int_string_struct_class | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 49.067 ns | 0.9783 ns | 1.0468 ns | 48.853 ns | 47.515 ns | 51.704 ns | 1.22 | 0.03 | 0.0098 | 104 B | 1.00 |
| | | | | | | | | | | | | | |
| StaticMethod5_arrayNotCached_int_string_struct_class_bool | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 56.730 ns | 0.5781 ns | 0.5408 ns | 56.669 ns | 55.909 ns | 57.890 ns | 1.00 | 0.00 | 0.0128 | 136 B | 1.00 |
| StaticMethod5_arrayNotCached_int_string_struct_class_bool | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 74.827 ns | 1.6601 ns | 1.8452 ns | 74.496 ns | 71.119 ns | 78.316 ns | 1.32 | 0.03 | 0.0191 | 200 B | 1.47 |
| | | | | | | | | | | | | | |
| StaticMethod4_int_string_struct_class | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 28.537 ns | 0.2502 ns | 0.2218 ns | 28.585 ns | 28.185 ns | 28.842 ns | 1.00 | 0.00 | - | - | NA |
| StaticMethod4_int_string_struct_class | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 34.938 ns | 0.1109 ns | 0.0983 ns | 34.899 ns | 34.821 ns | 35.179 ns | 1.22 | 0.01 | - | - | NA |
| | | | | | | | | | | | | | |
| StaticMethod4_ByRefParams_int_string_struct_class | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 144.779 ns | 1.0213 ns | 0.9054 ns | 144.673 ns | 142.893 ns | 146.116 ns | 1.00 | 0.00 | 0.0041 | 48 B | 1.00 |
| StaticMethod4_ByRefParams_int_string_struct_class | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 138.456 ns | 0.2052 ns | 0.1714 ns | 138.511 ns | 138.134 ns | 138.783 ns | 0.96 | 0.01 | 0.0043 | 48 B | 1.00 |
| | | | | | | | | | | | | | |
| StaticMethod5_ByRefParams_int_string_struct_class_bool | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 196.652 ns | 1.2706 ns | 1.1885 ns | 196.883 ns | 194.293 ns | 198.425 ns | 1.00 | 0.00 | 0.0063 | 72 B | 1.00 |
| StaticMethod5_ByRefParams_int_string_struct_class_bool | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 193.105 ns | 1.0413 ns | 0.8696 ns | 193.156 ns | 191.592 ns | 194.599 ns | 0.98 | 0.01 | 0.0123 | 136 B | 1.89 |
| | | | | | | | | | | | | | |
| Ctor0_NoParams | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 9.128 ns | 0.0912 ns | 0.0853 ns | 9.137 ns | 9.005 ns | 9.264 ns | 1.00 | 0.00 | 0.0053 | 56 B | 1.00 |
| Ctor0_NoParams | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 11.096 ns | 0.1013 ns | 0.0947 ns | 11.085 ns | 10.965 ns | 11.262 ns | 1.22 | 0.02 | 0.0053 | 56 B | 1.00 |
| | | | | | | | | | | | | | |
| Ctor4_int_string_struct_class | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 32.506 ns | 0.2559 ns | 0.2137 ns | 32.561 ns | 32.026 ns | 32.865 ns | 1.00 | 0.00 | 0.0053 | 56 B | 1.00 |
| Ctor4_int_string_struct_class | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 39.152 ns | 0.2872 ns | 0.2687 ns | 39.151 ns | 38.818 ns | 39.719 ns | 1.20 | 0.01 | 0.0052 | 56 B | 1.00 |
| | | | | | | | | | | | | | |
| Property_Get_int | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 10.565 ns | 0.1276 ns | 0.1131 ns | 10.581 ns | 10.416 ns | 10.833 ns | 1.00 | 0.00 | 0.0023 | 24 B | 1.00 |
| Property_Get_int | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 12.435 ns | 0.0953 ns | 0.0845 ns | 12.432 ns | 12.299 ns | 12.604 ns | 1.18 | 0.01 | 0.0023 | 24 B | 1.00 |
| | | | | | | | | | | | | | |
| Property_Get_class | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 8.091 ns | 0.0468 ns | 0.0415 ns | 8.093 ns | 8.037 ns | 8.178 ns | 1.00 | 0.00 | - | - | NA |
| Property_Get_class | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 10.549 ns | 0.0877 ns | 0.0778 ns | 10.555 ns | 10.411 ns | 10.685 ns | 1.30 | 0.01 | - | - | NA |
| | | | | | | | | | | | | | |
| Property_Set_int | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 16.105 ns | 0.1308 ns | 0.1160 ns | 16.110 ns | 15.916 ns | 16.325 ns | 1.00 | 0.00 | 0.0023 | 24 B | 1.00 |
| Property_Set_int | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 21.829 ns | 0.4245 ns | 0.3971 ns | 21.916 ns | 21.035 ns | 22.320 ns | 1.35 | 0.03 | 0.0022 | 24 B | 1.00 |
| | | | | | | | | | | | | | |
| Property_Set_class | Job-MZSTNH | \INVOKE_AFTER\corerun.exe | 13.299 ns | 0.0699 ns | 0.0654 ns | 13.304 ns | 13.209 ns | 13.383 ns | 1.00 | 0.00 | - | - | NA |
| Property_Set_class | Job-UYFZWZ | \INVOKE_BEFORE\corerun.exe | 18.799 ns | 0.1101 ns | 0.1030 ns | 18.764 ns | 18.636 ns | 19.001 ns | 1.41 | 0.01 | - | - | NA |
Benchmarks for NativeAot. ~1.3-1.7x faster when using the new APIs
old 0 args: 1014
new 0 args: 595
old 1 arg: 4860
new 1 arg: 3319
old 2 args:7595
new 2 args:5875
old 5 args:16292
new 5 args:15325

ghost commented Jul 5, 2023

Copy link
Copy Markdown

Note regarding the new-api-needs-documentation label:

This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, 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.

ghost commented Jul 5, 2023

Copy link
Copy Markdown

Tagging subscribers to this area: @dotnet/area-system-reflection
See info in area-owners.md if you want to be subscribed.

Issue Details

[wip]

Author:steveharter
Assignees:steveharter
Labels:

area-System.Reflection

Milestone:-

Comment threadsrc/libraries/System.Private.CoreLib/src/System/Reflection/MethodInvoker.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Reflection/MethodInvoker.cs Outdated
Comment threadsrc/libraries/System.Runtime/ref/System.Runtime.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Reflection/MethodInvoker.cs Outdated
Comment threadbuild Outdated
Comment threadsrc/coreclr/vm/ecalllist.h Outdated

ghost left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Left a few NITs, overall looks good to me.

RuntimeType sigType = _argTypes[i];

// Convert the type if necessary.
// Note that Type.Missing is not supported.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

NIT: By assuming this applyes to all new Invoke methods, this might be good to be added to the public doc

Comment threadsrc/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeType.cs Outdated
@cincuranet

ghost commented Jul 20, 2023

Copy link
Copy Markdown
Contributor

Improvement in dotnet/perf-autofiling-issues#19968.

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[API Proposal]: Add invoker classes for fast invoke APIs

5 participants

@steveharter@cincuranet@jkotas@AaronRobinsonMSFT@buyaa-n