Skip to content
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

[mono][aot] Enable dedup by default for iOS #81319

Merged
merged 28 commits into from
Feb 17, 2023

Conversation

kotlarmilos
Copy link
Member

@kotlarmilos kotlarmilos commented Jan 28, 2023

This PR enables dedup feature by default for iOS.

Current implementation uses dedup_methods hash table for storing extra methods which are emitted in a dedup AOT image. Previously, cfg->skip flag in dedup_skip_methods is used for indicating if a method should be emitted in an AOT image. As some of the code pointers could point outside the range of methods for an AOT image, only inflated instances are deduplicated.

Detailed analysis and limitations are added to the tracking issue.

@kotlarmilos kotlarmilos added this to the 8.0.0 milestone Jan 28, 2023
@kotlarmilos kotlarmilos self-assigned this Jan 28, 2023
@kotlarmilos kotlarmilos changed the title [mono][aot] Enable dedup in HelloiOS app in non-LLVM debug configuration. [mono][aot] Enable dedup in HelloiOS app in non-LLVM debug configuration Jan 28, 2023
@kotlarmilos kotlarmilos added the os-ios Apple iOS label Jan 28, 2023
@ghost
Copy link

ghost commented Jan 28, 2023

Tagging subscribers to 'os-ios': @steveisok, @akoeplinger
See info in area-owners.md if you want to be subscribed.

Issue Details

This PR enables dedup feature in HelloiOS application in non-LLVM debug configuration. It contributes to #80419 by demonstrating the feature on iOS platform.

Current implementation uses dedup_methods hash table for storing extra methods which are emitted in a dedup AOT image. Previously, cfg->skip flag in dedup_skip_methods is used for indicating if a method should be emitted in an AOT image. As some of the code pointers could point outside the range of methods for an AOT image, only inflated instances are deduplicated.

To enable it in release mode and with LLVM, the following should be resolved:

  • Current implementation doesn't cover cases where both shared method and its inflated instances could be deduplicated. During the compilation, the shared method is emitted in corresponding AOT image while inflated instances are emitted in dedup AOT image. During the runtime, the shared method can't be retrieved as it was searched in the dedup AOT image.
  • LLVM compilation/optimizations could affect the AOT image, so vtables in some cases can't be retrieved.
  • In release mode, type properties could be invalid due to inconsistent/missing data in the dedup AOT image.
  • By leveraging cfg->skip implementation, other methods in addition to inflated instances might be deduplicated.

Detailed analysis of the above-mentioned challenges and list of tasks will be added to the tracking issue. Size reduction in HelloiOS application in non-LLVM debug configuration should be ~ 1.9M with osx-arm64 host and xcode 14.2.

Author: kotlarmilos
Assignees: kotlarmilos
Labels:

area-Codegen-AOT-mono, os-ios

Milestone: 8.0.0

@kotlarmilos
Copy link
Member Author

Added changes for LLVM and release configurations.

@kotlarmilos kotlarmilos changed the title [mono][aot] Enable dedup in HelloiOS app in non-LLVM debug configuration [mono][aot] Enable dedup in HelloiOS app Jan 31, 2023
@kotlarmilos
Copy link
Member Author

Preliminary SOD measurements for HelloiOS application using 73da129 snapshot with osx-arm64 host and Xcode 14.2.

HelloiOS configuration Baseline Dedup enabled
llvm release 27,30 MB 26,20 MB
llvm debug 31,40 MB 30,10 MB
nollvm release 27,70 MB 26,90 MB
nollvm debug 33,00 MB 31,30 MB

Baseline measurements might differ from the dashboard report due to the particular snapshot and Xcode version. The measurements will be repeated for a MAUI application. /cc: @ivanpovazan @LeVladIonescu

@kotlarmilos
Copy link
Member Author

/azp run runtime-extra-platforms

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@kotlarmilos kotlarmilos changed the title [mono][aot] Enable dedup in HelloiOS app [mono][aot] Enable dedup by default for iOS and tvOS Feb 2, 2023
/* Use a set of wrappers/instances which work and useful */
switch (method->wrapper_type) {
case MONO_WRAPPER_RUNTIME_INVOKE:
#ifdef TARGET_WASM
return TRUE;
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is this skipped ?

Copy link
Member Author

Choose a reason for hiding this comment

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

Current implementation dedup methods based on a set of predefined rules. During the compilation, shared methods are emitted in corresponding AOT image while inflated instances are emitted in dedup AOT image. During the runtime, the shared method can't be retrieved as it was searched in the dedup AOT image.

Here is an example. During the compilation, the following runtime invoke wrappers are emitted in the dedup AOT image, while generic wrapper (wrapper runtime-invoke) void object:runtime_invoke_dynamic (intptr,intptr,intptr,intptr) is emitted in a corresponding AOT image.

(wrapper runtime-invoke) object <Module>:runtime_invoke_byte__this___int (object,intptr,intptr,intptr)
(wrapper runtime-invoke) object <Module>:runtime_invoke_void__this___int_byte (object,intptr,intptr,intptr)
(wrapper runtime-invoke) object <Module>:runtime_invoke_int__this___int (object,intptr,intptr,intptr)
(wrapper runtime-invoke) object <Module>:runtime_invoke_void__this___int_int (object,intptr,intptr,intptr)
(wrapper runtime-invoke) object <Module>:runtime_invoke_int__this___int_int (object,intptr,intptr,intptr)
(wrapper runtime-invoke) object <Module>:runtime_invoke_void__this___int_int_int (object,intptr,intptr,intptr)
(wrapper runtime-invoke) object <Module>:runtime_invoke_uint16__this___int (object,intptr,intptr,intptr)
(wrapper runtime-invoke) object <Module>:runtime_invoke_void__this___int_uint16 (object,intptr,intptr,intptr)
(wrapper runtime-invoke) object <Module>:runtime_invoke_bool__this___int (object,intptr,intptr,intptr)
(wrapper runtime-invoke) object <Module>:runtime_invoke_void__this___int_byte (object,intptr,intptr,intptr)
(wrapper runtime-invoke) object <Module>:runtime_invoke_sbyte__this___int (object,intptr,intptr,intptr)
(wrapper runtime-invoke) object <Module>:runtime_invoke_void__this___int_sbyte (object,intptr,intptr,intptr)
(wrapper runtime-invoke) object <Module>:runtime_invoke_char__this___int (object,intptr,intptr,intptr)
(wrapper runtime-invoke) object <Module>:runtime_invoke_void__this___int_uint16 (object,intptr,intptr,intptr)
(wrapper runtime-invoke) object <Module>:runtime_invoke_int16__this___int (object,intptr,intptr,intptr)
(wrapper runtime-invoke) object <Module>:runtime_invoke_void__this___int_int16 (object,intptr,intptr,intptr)
(wrapper runtime-invoke) object <Module>:runtime_invoke_uint__this___int (object,intptr,intptr,intptr)
(wrapper runtime-invoke) object <Module>:runtime_invoke_void__this___int_uint (object,intptr,intptr,intptr)
(wrapper runtime-invoke) object <Module>:runtime_invoke_long__this___int (object,intptr,intptr,intptr)
(wrapper runtime-invoke) object <Module>:runtime_invoke_void__this___int_long (object,intptr,intptr,intptr)
(wrapper runtime-invoke) object <Module>:runtime_invoke_ulong__this___int (object,intptr,intptr,intptr)
(wrapper runtime-invoke) object <Module>:runtime_invoke_void__this___int_long (object,intptr,intptr,intptr)
(wrapper runtime-invoke) object <Module>:runtime_invoke_intptr__this___int (object,intptr,intptr,intptr)
(wrapper runtime-invoke) object <Module>:runtime_invoke_void__this___int_intptr (object,intptr,intptr,intptr)
(wrapper runtime-invoke) object <Module>:runtime_invoke_uintptr__this___int (object,intptr,intptr,intptr)
(wrapper runtime-invoke) object <Module>:runtime_invoke_void__this___int_intptr (object,intptr,intptr,intptr)
(wrapper runtime-invoke) object <Module>:runtime_invoke_single__this___int (object,intptr,intptr,intptr)
(wrapper runtime-invoke) object <Module>:runtime_invoke_void__this___int_single (object,intptr,intptr,intptr)
(wrapper runtime-invoke) object <Module>:runtime_invoke_double__this___int (object,intptr,intptr,intptr)
(wrapper runtime-invoke) object <Module>:runtime_invoke_void__this___int_double (object,intptr,intptr,intptr)

During the runtime, (wrapper runtime-invoke) void object:runtime_invoke_dynamic (intptr,intptr,intptr,intptr) was searched in the dedup AOT image as it is RUNTIME_INVOKE_WRAPPER, but not emitted in the dedup AOT image.

@vargaz
Copy link
Contributor

vargaz commented Feb 14, 2023

Looks ok, but the restrictions should be investigated.

@kotlarmilos
Copy link
Member Author

Looks ok, but the restrictions should be investigated.

Good point. The current restrictions are applied based on iOS-related CI jobs and HelloiOS sample application. The idea was to rollout a single platform at the time, and that is why such strict restrictions are applied. After enabling the dedup by default on iOS, we could first improve size profiling in Mono AOT compiler as outlined in #82101, to get an insight what else could be deduplicated, before enabling the dedup for other platforms and including additional methods.

@kotlarmilos
Copy link
Member Author

/azp run runtime-ioslike

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@@ -6589,6 +6589,8 @@ emit_and_reloc_code (MonoAotCompile *acfg, MonoMethod *method, guint8 *code, gui
direct_call_target = symbol;
patch_info->type = MONO_PATCH_INFO_NONE;
} else if ((m_class_get_image (patch_info->data.method->klass) == acfg->image) && !got_only && is_direct_callable (acfg, method, patch_info)) {
// FIXME: Currently it only works for wasm. On other platforms it fails as some callees require initialization.
#ifdef TARGET_WASM
MonoCompile *callee_cfg = (MonoCompile *)g_hash_table_lookup (acfg->method_to_cfg, cmethod);
Copy link
Contributor

Choose a reason for hiding this comment

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

Note that emit_and_reloc_code () is never used on wasm, so this shouldn't be neccessary.

Copy link
Member Author

Choose a reason for hiding this comment

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

Ok, disabled for now. I've added a tracking issue for it as additional size savings might be achieved - #82224

@steveisok steveisok requested a review from lateralusX February 15, 2023 19:16
@kotlarmilos
Copy link
Member Author

/azp run runtime-ioslike

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@kotlarmilos
Copy link
Member Author

Functional and library tests on a device have passed. Failures shouldn't be relevant.

Copy link
Member

@ivanpovazan ivanpovazan left a comment

Choose a reason for hiding this comment

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

LGTM!

@kotlarmilos kotlarmilos merged commit 65f5ad0 into dotnet:main Feb 17, 2023
@kotlarmilos kotlarmilos deleted the improvement/dedup-ios branch February 20, 2023 09:32
@ghost ghost locked as resolved and limited conversation to collaborators Mar 22, 2023
Sign up for free to 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.

4 participants