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] iOS - Size reduction: many more corelib symbols are materialized/AOT compiled in netcore compared to legacy Mono #56385

Closed
Tracked by #61815
imhameed opened this issue Jul 27, 2021 · 13 comments
Assignees
Labels
area-Codegen-AOT-mono os-ios Apple iOS runtime-mono specific to the Mono runtime tracking This issue is tracking the completion of other related issues.
Milestone

Comments

@imhameed
Copy link
Contributor

imhameed commented Jul 27, 2021

Original description

Seen while investigating size differences between legacy Mono and netcore Mono when used for iOS.

More details are forthcoming--and P7 apparently generates larger binaries than P6. A tsv containing size information for the P6 singleview app is available here: xamarin/xamarin-macios#10249 (comment)

I'll provide P7 and legacy (for comparison) breakdowns soon.

Curent state

We continued to investigate the size reduction issue in .NET 7 and identified the following work items to reflect the problem:

@imhameed imhameed self-assigned this Jul 27, 2021
@dotnet-issue-labeler dotnet-issue-labeler bot added the untriaged New issue has not been triaged by the area owner label Jul 27, 2021
@imhameed imhameed added area-Codegen-AOT-mono os-ios Apple iOS runtime-mono specific to the Mono runtime and removed untriaged New issue has not been triaged by the area owner labels Jul 27, 2021
@dotnet dotnet deleted a comment from dotnet-issue-labeler bot Jul 27, 2021
@SamMonoRT SamMonoRT added this to the 6.0.0 milestone Jul 27, 2021
@SamMonoRT
Copy link
Member

We'll keep working on this, but nothing concrete is expected to be checked in the 6.0.0 timeframe. Moving to 7.0.0

@SamMonoRT SamMonoRT modified the milestones: 6.0.0, 7.0.0 Aug 9, 2021
@imhameed
Copy link
Contributor Author

This is mostly a note to myself to do more followup work. I don't know why the .NET core corelib is resulting in twice as much stuff being compiled.

@imhameed imhameed changed the title iOS - Size reduction: many more corelib symbols are materialized/AOT compiled in netcore compared to legacy Mono [mono] iOS - Size reduction: many more corelib symbols are materialized/AOT compiled in netcore compared to legacy Mono Nov 18, 2021
@imhameed
Copy link
Contributor Author

@eerhardt Do you have any suggestions or ideas on what might be causing the increase in CoreLib size, or any pointers for directions to go when investigating? As far as I know we're doing some .NET-level dead code elimination via the managed linker, but I have no firsthand experience with this tool.

@eerhardt
Copy link
Member

eerhardt commented Jan 11, 2022

One easy way to investigate is to use something like ILSpy to look into both assemblies to see what's in both. However, diffing is hard here because it doesn't diff assemblies. So you'd be able to spot high-level things using this method.

Another approach I've used in the past is to use the API reviewer tool - \\fxcore\tools\ApiReviewer.lnk. This allows you to diff the APIs of assemblies, including internal classes and methods. This can pretty quickly spot where the differences between two assemblies are based on internal types.

Other tools that can be used to investigate where IL size is being used:

https://github.com/dotnet/linker/tree/main/src/analyzer
https://github.com/dotnet/linker/tree/main/src/tlens

@ivanpovazan
Copy link
Member

ivanpovazan commented Jun 15, 2022

After some further analysis the following stats have been gathered by comparing:

  • dotnet - version6.0.301-rtm.22263.15 and
  • legacy mono - version 6.12.0 (later referenced as oldnet)

builds of MySingleView app on iOS.

Analysis

bloaty was used to generate symbols from both binaries respectively:

  • for dotnet
bloaty -d segments,sections,symbols --debug-file=dotnet/bin/iPhone/Release/net6.0-ios/ios-arm64/MySingleView.app.dSYM/Contents/Resources/DWARF/MySingleView dotnet/bin/iPhone/Release/net6.0-ios/ios-arm64/MySingleView.app/MySingleView -n 0 --tsv > ../logs/dotnet_symbols.list
  • for oldnet
bloaty -d segments,sections,symbols --debug-file=oldnet/bin/iPhone/Release/MySingleView.app.dSYM/Contents/Resources/DWARF/MySingleView oldnet/bin/iPhone/Release/MySingleView.app/MySingleView -n 0 --tsv > ../logs/oldnet_symbols.list

Bloaty outputs were then further broken down by a script for easier analysis of the __text section:

Observation

What can be observed from the generated reports is that there are many more symbols in the __text section in the dotnet variant:

  • Total symbols: 28602 -> 16131 (+77%)
  • Total size: 5430112 -> 2952832 (+84%)

However, after inspecting just generic methods it can be seen that there a following difference:

  • Total symbols: 2433 -> 1411 (+72%)
  • Total size: 789836 -> 379432 (+108%)

Since generics take around %15 of the total app size, I was wondering whether some optimisations mentioned here (especially the point regarding usage of gsharedvt versions of a method) could help reduce the app size.

(UPDATE: I have updated the numbers for generics since they were not precise enough ie I did not take into account generics with T1, T2, T3, T4 types - this does not drastically change the overall analysis.)

@vargaz what do you think?

@ivanpovazan
Copy link
Member

ivanpovazan commented Jun 22, 2022

Mostly note to myself.

Further analysis has been performed on the output generated by bloaty as described in my previous comment by running script

The script reads the bloaty dotnet and oldnet reports and processes their symbols by:

  • categorising them into:
    • CORLIB - Symbols from: System.Private.CoreLib or mscorlib
    • MONLIB - Symbols from: mono (which start with mono prefix or come from /mono/ path)
    • SYSIOS - Symbols from: Microsoft.iOS or Xamarin.iOS
    • OTHERS - Symbols not from any of the above
  • sorting them by name in each of the categories
  • diffing symbols between dotnet and oldnet for all categories except OTHERS (too much noise)
  • generating diff reports

Diff reports include symbols that are new in dotnet, sorted by size (decreasing) and can be found here:

Most interesting one is CORLIB category (and its namespace breakdown section) which shows candidates for further investigation .

@marek-safar
Copy link
Contributor

@ivanpovazan which runtime version is this using? There are many methods which I cannot find in main.

@ivanpovazan
Copy link
Member

ivanpovazan commented Jun 23, 2022

@marek-safar 6.0.301-rtm.22263.15 version was used for these measurements (xamarin repo configuration).

UPDATE:
There was an issue with the analysis script not taking into account GSHAREDVT methods (these methods are not decorated with _mscorlib_ nor _corlib_ prefixes and thus were not included in the CORLIB category)

I have corrected the diff_CORLIB report (and the script).
The order of namespace breakdown section is not impacted much, but there noticeable size differences

 --------------------------------------------------------------------------------------------------------------------------------------------
 Symbol namespaces: size/name
 --------------------------------------------------------------------------------------------------------------------------------------------
-238896    System
-177176    System_Numerics
-130484    System_Globalization
-115992    System_Threading
-82100     System_Collections_Generic
-73328     System_Threading_Tasks
-66220     System_Runtime_Intrinsics
-36748     System_Runtime_CompilerServices
-33320     System_Text
-19692     System_IO_Strategies
-16872     System_Buffers
-16448     System_Reflection
-15284     System_IO
+288272    System
+220388    System_Numerics
+137008    System_Globalization
+126072    System_Threading
+115672    System_Collections_Generic
+89896     System_Threading_Tasks
+75748     System_Runtime_Intrinsics
+59796     System_Runtime_CompilerServices
+38192     System_Text
+24316     System_IO_Strategies
+19784     System_Buffers
+18220     System_Collections_Concurrent
+17120     System_Reflection
+15720     System_IO
 10412     System_Text_Unicode
-8204      System_Collections_Concurrent
-7892      System_Runtime_InteropServices
+10052     System_Runtime_InteropServices
 7596      System_Diagnostics
-5972      System_Runtime_Loader
+6504      System_Runtime_Loader
 4452      System_Reflection_Emit
 1020      System_Diagnostics_Tracing
 1016      System_Runtime_Serialization

@ivanpovazan
Copy link
Member

ivanpovazan commented Jun 27, 2022

Here is the first comparison report comparing legacy with .NET 7 Mono for MySingleView app.
Compared versions:

  • Legacy Mono - v6.12.0 - referenced as oldnet
  • .NET Mono - v7.0.100-preview.5.22274.9 - referenced as dotnet

__TEXT,__text section:

  • Total symbols oldnet -> dotnet: 16288 -> 23752 (+68%)
  • Total size oldnet -> dotnet: 2955660 -> 4913276 (+60%)

New diff reports (generated as described in previous comments) and can be found here:

@vargaz
Copy link
Contributor

vargaz commented Jun 28, 2022

The Scalar class is used to implement the fallback code for the vector classes, and Scalar are the gsharedvt versions of these methods. The code in Scalar is designed to be specialized, so the gsharedvt versions are very large/slow.

@marek-safar
Copy link
Contributor

The code in Scalar is designed to be specialized, so the gsharedvt versions are very large/slow.

The code handles only primitive types, everything else throws NotSupportedException. I'm not sure how to best handle this but gsharedvt version should not exist at all or always throw.

@ivanpovazan
Copy link
Member

@marek-safar, agreed.
After discussions with @lambdageek and @vargaz there two paths to tackle this problem.
I have opened the issues:
#71430
#71431
which would try to minimize and prevent generation of unnecessary GSHAREDVTs.

@ivanpovazan
Copy link
Member

Closing this issue as it is outdated and all 3 dependent tasks have been move to the newer - .NET8 tracking issue: #80938

@ghost ghost locked as resolved and limited conversation to collaborators Jun 23, 2023
@radekdoulik radekdoulik modified the milestones: 8.0.0, 9.0.0 Jul 24, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-Codegen-AOT-mono os-ios Apple iOS runtime-mono specific to the Mono runtime tracking This issue is tracking the completion of other related issues.
Projects
None yet
Development

No branches or pull requests

7 participants