xamarin / xamarin-macios

.NET for iOS, Mac Catalyst, macOS, and tvOS provide open-source bindings of the Apple SDKs for use with .NET managed languages such as C#
Other
2.44k stars 508 forks source link

.NET: SingleView app size #10249

Open rolfbjarne opened 3 years ago

rolfbjarne commented 3 years ago

App sizes are currently significantly bigger with .NET 6 with a very simple hello world app.

Test case

cd tests/dotnet
make compare

This will build a very simple hello world app for both .NET 6 and the old-style Xamarin.iOS and generate a report in markdown format. This can be pasted into the issue (e.g. for each preview) so the progress can be tracked.

Known Issues

Historical

App sizes

Xamarin.iOS

du -hs size-comparison/MySingleView/oldnet/bin/iPhone/Release/MySingleView.app 4.4M size-comparison/MySingleView/oldnet/bin/iPhone/Release/MySingleView.app

.NET 6

du -hs size-comparison/MySingleView/dotnet/bin/iPhone/Release/net6.0-ios/ios-arm64/*.app 27M size-comparison/MySingleView/dotnet/bin/iPhone/Release/net6.0-ios/ios-arm64/MySingleView.app

Assembly sizes

Xamarin.iOS

ls -lahS size-comparison/MySingleView/oldnet/bin/iPhone/Release/MySingleView.app/.dll size-comparison/MySingleView/oldnet/bin/iPhone/Release/MySingleView.app/.exe -rw-r--r-- 1 rolf wheel 397K Dec 9 19:04 size-comparison/MySingleView/oldnet/bin/iPhone/Release/MySingleView.app/mscorlib.dll -rw-r--r-- 1 rolf wheel 54K Dec 9 19:04 size-comparison/MySingleView/oldnet/bin/iPhone/Release/MySingleView.app/Xamarin.iOS.dll -rw-r--r-- 1 rolf wheel 4.5K Dec 9 19:04 size-comparison/MySingleView/oldnet/bin/iPhone/Release/MySingleView.app/MySingleView.exe -rw-r--r-- 1 rolf wheel 4.5K Dec 9 19:05 size-comparison/MySingleView/oldnet/bin/iPhone/Release/MySingleView.app/System.dll

.NET 6

ls -lahS size-comparison/MySingleView/dotnet/bin/iPhone/Release/net6.0-ios/ios-arm64/.app/.dll -rw-r--r-- 1 rolf wheel 1.3M Dec 9 19:05 size-comparison/MySingleView/dotnet/bin/iPhone/Release/net6.0-ios/ios-arm64/MySingleView.app/System.Private.CoreLib.dll -rw-r--r-- 1 rolf wheel 161K Dec 9 19:05 size-comparison/MySingleView/dotnet/bin/iPhone/Release/net6.0-ios/ios-arm64/MySingleView.app/Xamarin.iOS.dll -rw-r--r-- 1 rolf wheel 17K Dec 9 19:05 size-comparison/MySingleView/dotnet/bin/iPhone/Release/net6.0-ios/ios-arm64/MySingleView.app/System.Runtime.dll -rw-r--r-- 1 rolf wheel 16K Dec 9 19:05 size-comparison/MySingleView/dotnet/bin/iPhone/Release/net6.0-ios/ios-arm64/MySingleView.app/System.Runtime.Serialization.Formatters.dll -rw-r--r-- 1 rolf wheel 5.0K Dec 9 19:05 size-comparison/MySingleView/dotnet/bin/iPhone/Release/net6.0-ios/ios-arm64/MySingleView.app/MySingleView.dll


There are multiple issues here:

Additionally the .NET 6 version takes twice as long to compile (22s vs 11s on my machine), but that's a different issue (filed as https://github.com/xamarin/xamarin-macios/issues/10251).

spouliot commented 3 years ago

Shameless plug but you might want to use https://github.com/spouliot/dotnet-tools/tree/master/app-compare to compare the size of the current/dotnet apps

spouliot commented 3 years ago

Additionally the .NET 6 version takes twice as long to compile (22s vs 11s on my machine), but that's a different issue.

Considering most of the device build time comes from the AOT compiler (at least in current form) then a 2x build time increase is not so bad as there's more than 3x more managed code (1,5 MB vs 460 KB) to AOT. IOW we can consider this the "same issue", unless the time increase comes from elsewhere.

marek-safar commented 3 years ago

It looks like you don't have some of the feature switched enabled, see https://github.com/dotnet/runtime/blob/master/docs/workflow/trimming/feature-switches.md. I'm not saying that's all that needs to be done but it's a good start ;-)

spouliot commented 3 years ago

Application Comparer

Directories / Files A B diff %
.//_CodeSignature     CodeResources 4,869 8,167 3,298 67.7%
.//     archived-expanded-entitlements.xcent 392 392 0 0.0%
    embedded.mobileprovision 12,218 12,218 0 0.0%
    Info.plist 1,055 1,055 0 0.0%
    libmonosgen-2.0.dylib 0 3,177,312 3,177,312 -
    libSystem.IO.Compression.Native.dylib 0 827,104 827,104 -
    libSystem.Native.dylib 0 123,040 123,040 -
    libSystem.Net.Security.Native.dylib 0 72,016 72,016 -
    libSystem.Security.Cryptography.Native.Apple.dylib 0 80,656 80,656 -
    libxamarin-debug.dylib 0 623,856 623,856 -
    libxamarin.dylib 0 425,408 425,408 -
    mscorlib.aotdata.arm64 296,872 0 -296,872 -100.0%
    mscorlib.dll 406,528 0 -406,528 -100.0%
    MySingleView 3,748,192 18,281,760 14,533,568 387.7%
    MySingleView.aotdata.arm64 816 1,136 320 39.2%
    MySingleView.dll 0 5,120 5,120 -
    MySingleView.exe 4,608 0 -4,608 -100.0%
    MySingleView.pdb 0 9,720 9,720 -
    PkgInfo 8 8 0 0.0%
    System.aotdata.arm64 752 0 -752 -100.0%
    System.dll 4,608 0 -4,608 -100.0%
    System.Private.CoreLib.aotdata.arm64 0 3,082,504 3,082,504 -
    System.Private.CoreLib.dll 0 1,391,616 1,391,616 -
    System.Runtime.aotdata.arm64 0 504 504 -
    System.Runtime.dll 0 17,408 17,408 -
    System.Runtime.Serialization.Formatters.aotdata.arm64 0 1,144 1,144 -
    System.Runtime.Serialization.Formatters.dll 0 15,872 15,872 -
    Xamarin.iOS.aotdata.arm64 35,048 319,112 284,064 810.5%
    Xamarin.iOS.dll 55,296 163,840 108,544 196.3%
Statistics
Native subtotal 3,748,192 18,281,760 14,533,568 387.7%
    Executable 3,748,192 18,281,760 14,533,568 387.7%
    AOT data *.aotdata 0 0 0 -
Managed *.dll/exe 471,040 1,593,856 1,122,816 238.4%
TOTAL 4,571,262 28,640,968 24,069,706 526.5%
spouliot commented 3 years ago

other issues

update: both issues are fixed with P4

marek-safar commented 3 years ago

@spouliot could you share the binaries?

spouliot commented 3 years ago

@marek-safar yes but likely not today. My main internet connection is down :( and I'm waiting for a new modem to be delivered. Trying to limit myself to low bandwidth (cellular) tasks.

rolfbjarne commented 3 years ago

It looks like you don't have some of the feature switched enabled, see https://github.com/dotnet/runtime/blob/master/docs/workflow/trimming/feature-switches.md. I'm not saying that's all that needs to be done but it's a good start ;-)

https://github.com/xamarin/xamarin-macios/pull/10250 - that shaves off a good chunk.

rolfbjarne commented 3 years ago

@marek-safar

@spouliot could you share the binaries?

dotnet.zip oldnet.zip

That's after https://github.com/xamarin/xamarin-macios/pull/10250, so the runtime switches have been toggled for these apps.

rolfbjarne commented 3 years ago

Additionally the .NET 6 version takes twice as long to compile (22s vs 11s on my machine), but that's a different issue.

Considering most of the device build time comes from the AOT compiler (at least in current form) then a 2x build time increase is not so bad as there's more than 3x more managed code (1,5 MB vs 460 KB) to AOT. IOW we can consider this the "same issue", unless the time increase comes from elsewhere.

I filed https://github.com/xamarin/xamarin-macios/issues/10251 for this: just executing the .NET 6 linker takes longer than linking + AOT compilation + native compilation used to.

spouliot commented 3 years ago

This update was done with today's dotnet 6.0.100-preview.2.21158.2 build and xamarin-macios main 91ce22c57cadd3519ac4433e8d73cbe4be5be7e5. Not quite the final, to be released, P2 bits but close.

Most of the previous comments (e.g. extra files, no ICU in numbers) still applies.

Noticeable/visible changes are:

It's a great improvement, over the original numbers, but there's still work to be done compared to the current SDK size.

Application Comparer

Directories / Files A B diff %
.//_CodeSignature CodeResources 4,869 7,471 2,602 53.4%
.// archived-expanded-entitlements.xcent 392 392 0 0.0%
embedded.mobileprovision 14,271 14,271 0 0.0%
Info.plist 1,058 1,058 0 0.0%
libmonosgen-2.0.dylib 0 3,503,920 3,503,920 -
libSystem.IO.Compression.Native.dylib 0 827,248 827,248 -
libSystem.Native.dylib 0 123,792 123,792 -
libSystem.Net.Security.Native.dylib 0 72,016 72,016 -
libSystem.Security.Cryptography.Native.Apple.dylib 0 80,656 80,656 -
libxamarin-debug.dylib 0 625,472 625,472 -
libxamarin-dotnet-debug.dylib 0 625,600 625,600 -
libxamarin-dotnet.dylib 0 425,984 425,984 -
libxamarin.dylib 0 425,856 425,856 -
mscorlib.aotdata.arm64 296,808 0 -296,808 -100.0%
mscorlib.dll 406,528 0 -406,528 -100.0%
MySingleView 3,748,304 10,213,120 6,464,816 172.5%
MySingleView.aotdata.arm64 816 792 -24 -2.9%
MySingleView.dll 0 4,608 4,608 -
MySingleView.exe 4,608 0 -4,608 -100.0%
MySingleView.pdb 0 10,280 10,280 -
PkgInfo 8 8 0 0.0%
System.aotdata.arm64 752 0 -752 -100.0%
System.dll 4,608 0 -4,608 -100.0%
System.Private.CoreLib.aotdata.arm64 0 623,496 623,496 -
System.Private.CoreLib.dll 0 685,056 685,056 -
Xamarin.iOS.aotdata.arm64 34,856 78,784 43,928 126.0%
Xamarin.iOS.dll 55,296 157,696 102,400 185.2%
Statistics
Native subtotal 3,748,304 10,213,120 6,464,816 172.5%
Executable 3,748,304 10,213,120 6,464,816 172.5%
AOT data *.aotdata 0 0 0 -
Managed *.dll/exe 471,040 847,360 376,320 79.9%
TOTAL 4,573,174 18,507,576 13,934,402 304.7%
eerhardt commented 3 years ago

@spouliot @rolfbjarne - do we know why Xamarin.iOS.dll is 185% larger in .NET 6?

That could contribute a lot to why .NET 6's CoreLib is bigger than mono's mscorlib. More code in higher level assemblies means the possibility of more code being rooted lower in corelib.

spouliot commented 3 years ago

do we know why Xamarin.iOS.dll is 185% larger in .NET 6?

No, at least not yet. I wanted numbers to go along P2 even if we did not have time to look at the results right away - they will have historical value ;-)

Quick guess some of our optimizations were not yet ported/enabled (last time I checked).

That could contribute a lot to why .NET 6's CoreLib is bigger than mono's mscorlib.

That definitively plays its part. Still even if Xamarin.iOS.dll is huge (lots of bindings) there's not a lot of variety in the API being used. I'll dig up more useful data asap

spouliot commented 3 years ago

@eerhardt here's the references diff between the old (current) and new (dotnet) versions of the linked Xamarin.iOS.dll

--- old 2021-03-11 19:54:16.000000000 -0500
+++ new 2021-03-11 19:54:50.000000000 -0500
@@ -1,9 +1,13 @@
 A: Xamarin.iOS, Version=0.0.0.0, Culture=neutral, PublicKeyToken=84e04ff9cfb79065
-   AR: mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e
+   AR: System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e
+      TR: System.AggregateException
+          MR: System.Collections.ObjectModel.ReadOnlyCollection`1<System.Exception> System.AggregateException::get_InnerExceptions()
+          MR: System.Void System.AggregateException::.ctor(System.Collections.Generic.IEnumerable`1<System.Exception>)
       TR: System.AppDomain
           MR: System.AppDomain System.AppDomain::get_CurrentDomain()
           MR: System.Reflection.Assembly[] System.AppDomain::GetAssemblies()
       TR: System.ArgumentException
+          MR: System.Void System.ArgumentException::.ctor(System.String,System.String)
           MR: System.Void System.ArgumentException::.ctor(System.String)
       TR: System.ArgumentNullException
           MR: System.Void System.ArgumentNullException::.ctor(System.String)
@@ -11,28 +15,35 @@
           MR: System.Void System.ArgumentOutOfRangeException::.ctor(System.String)
       TR: System.Array
           MR: !!0[] System.Array::Empty()
-      TR: System.AsyncCallback
+          MR: System.Int32 System.Array::IndexOf(!!0[],!!0)
+          MR: System.Void System.Array::Resize(!!0[]&,System.Int32)
       TR: System.Attribute
+          MR: System.Attribute System.Attribute::GetCustomAttribute(System.Reflection.MemberInfo,System.Type)
           MR: System.Void System.Attribute::.ctor()
       TR: System.AttributeTargets
       TR: System.AttributeUsageAttribute
           MR: System.Void System.AttributeUsageAttribute::.ctor(System.AttributeTargets)
       TR: System.Boolean
+      TR: System.Char
+          MR: System.Boolean System.Char::IsWhiteSpace(System.Char)
+          MR: System.String System.Char::ToString()
       TR: System.Collections.Generic.Dictionary`2
-      TR: System.Collections.Generic.EqualityComparer`1
+      TR: System.Collections.Generic.Dictionary`2/ValueCollection
+      TR: System.Collections.Generic.Dictionary`2/ValueCollection/Enumerator
       TR: System.Collections.Generic.ICollection`1
-      TR: System.Collections.Generic.IDictionary`2
       TR: System.Collections.Generic.IEnumerable`1
       TR: System.Collections.Generic.IEnumerator`1
       TR: System.Collections.Generic.IEqualityComparer`1
+      TR: System.Collections.Generic.IList`1
       TR: System.Collections.Generic.KeyValuePair`2
       TR: System.Collections.Generic.List`1
       TR: System.Collections.Generic.List`1/Enumerator
       TR: System.Collections.IDictionary
-      TR: System.Collections.IEnumerable
       TR: System.Collections.IEnumerator
           MR: System.Boolean System.Collections.IEnumerator::MoveNext()
+      TR: System.Collections.ObjectModel.ReadOnlyCollection`1
       TR: System.Delegate
+          MR: System.Reflection.MethodInfo System.Delegate::get_Method()
       TR: System.Double
           MR: System.Boolean System.Double::Equals(System.Double)
           MR: System.Boolean System.Double::Equals(System.Object)
@@ -40,14 +51,14 @@
           MR: System.Int32 System.Double::CompareTo(System.Object)
           MR: System.Int32 System.Double::GetHashCode()
           MR: System.String System.Double::ToString()
-          MR: System.String System.Double::ToString(System.IFormatProvider)
           MR: System.String System.Double::ToString(System.String,System.IFormatProvider)
-          MR: System.TypeCode System.Double::GetTypeCode()
       TR: System.Enum
-      TR: System.EventArgs
-          MR: System.EventArgs System.EventArgs::Empty
+          MR: System.Type System.Enum::GetUnderlyingType(System.Type)
+      TR: System.Environment
+          MR: System.Int32 System.Environment::get_CurrentManagedThreadId()
+          MR: System.OperatingSystem System.Environment::get_OSVersion()
+          MR: System.String System.Environment::GetEnvironmentVariable(System.String)
       TR: System.EventHandler
-          MR: System.Void System.EventHandler::Invoke(System.Object,System.EventArgs)
       TR: System.Exception
           MR: System.String System.Exception::ToString()
           MR: System.Void System.Exception::.ctor()
@@ -55,16 +66,13 @@
           MR: System.Void System.Exception::.ctor(System.String)
       TR: System.FlagsAttribute
           MR: System.Void System.FlagsAttribute::.ctor()
-      TR: System.Func`1
-      TR: System.Func`2
       TR: System.GC
           MR: System.Void System.GC::SuppressFinalize(System.Object)
-      TR: System.Globalization.CultureInfo
-          MR: System.Globalization.CultureInfo System.Globalization.CultureInfo::get_CurrentCulture()
-      TR: System.IAsyncResult
       TR: System.IComparable
       TR: System.IComparable`1
       TR: System.IConvertible
+          MR: System.Int16 System.IConvertible::ToInt16(System.IFormatProvider)
+          MR: System.Int32 System.IConvertible::ToInt32(System.IFormatProvider)
           MR: System.Int64 System.IConvertible::ToInt64(System.IFormatProvider)
           MR: System.UInt64 System.IConvertible::ToUInt64(System.IFormatProvider)
       TR: System.IDisposable
@@ -73,6 +81,7 @@
       TR: System.IFormatProvider
       TR: System.IFormattable
       TR: System.Int32
+          MR: System.String System.Int32::ToString(System.String)
       TR: System.Int64
           MR: System.Boolean System.Int64::Equals(System.Int64)
           MR: System.Boolean System.Int64::Equals(System.Object)
@@ -81,7 +90,6 @@
           MR: System.Int32 System.Int64::GetHashCode()
           MR: System.String System.Int64::ToString()
           MR: System.String System.Int64::ToString(System.String,System.IFormatProvider)
-          MR: System.TypeCode System.Int64::GetTypeCode()
       TR: System.IntPtr
           MR: System.Boolean System.IntPtr::op_Equality(System.IntPtr,System.IntPtr)
           MR: System.Boolean System.IntPtr::op_Inequality(System.IntPtr,System.IntPtr)
@@ -94,12 +102,22 @@
           MR: System.IntPtr System.IntPtr::op_Subtraction(System.IntPtr,System.Int32)
           MR: System.IntPtr System.IntPtr::Zero
           MR: System.String System.IntPtr::ToString(System.String)
+          MR: System.Void System.IntPtr::.ctor(System.Int32)
           MR: System.Void* System.IntPtr::op_Explicit(System.IntPtr)
       TR: System.InvalidCastException
           MR: System.Void System.InvalidCastException::.ctor(System.String)
+      TR: System.InvalidOperationException
+          MR: System.Void System.InvalidOperationException::.ctor()
+      TR: System.IO.FileNotFoundException
+          MR: System.String System.IO.FileNotFoundException::get_FileName()
+      TR: System.Math
+          MR: System.Int32 System.Math::Max(System.Int32,System.Int32)
       TR: System.MulticastDelegate
+      TR: System.NotImplementedException
+          MR: System.Void System.NotImplementedException::.ctor()
       TR: System.NotSupportedException
-          MR: System.Void System.NotSupportedException::.ctor()
+          MR: System.Void System.NotSupportedException::.ctor(System.String)
+      TR: System.Nullable`1
       TR: System.Object
           MR: System.Boolean System.Object::Equals(System.Object)
           MR: System.Int32 System.Object::GetHashCode()
@@ -109,26 +127,46 @@
           MR: System.Void System.Object::Finalize()
       TR: System.ObjectDisposedException
           MR: System.Void System.ObjectDisposedException::.ctor(System.String)
+      TR: System.OperatingSystem
+          MR: System.PlatformID System.OperatingSystem::get_Platform()
       TR: System.ParamArrayAttribute
           MR: System.Void System.ParamArrayAttribute::.ctor()
+      TR: System.PlatformID
+      TR: System.Reflection.AmbiguousMatchException
+          MR: System.Void System.Reflection.AmbiguousMatchException::.ctor(System.String)
       TR: System.Reflection.Assembly
           MR: System.Boolean System.Reflection.Assembly::op_Equality(System.Reflection.Assembly,System.Reflection.Assembly)
           MR: System.Boolean System.Reflection.Assembly::op_Inequality(System.Reflection.Assembly,System.Reflection.Assembly)
+          MR: System.Reflection.Assembly System.Reflection.Assembly::Load(System.Reflection.AssemblyName)
           MR: System.Reflection.AssemblyName System.Reflection.Assembly::GetName()
+          MR: System.Reflection.AssemblyName[] System.Reflection.Assembly::GetReferencedAssemblies()
           MR: System.Reflection.Module[] System.Reflection.Assembly::GetModules()
+          MR: System.String System.Reflection.Assembly::get_FullName()
+          MR: System.Type System.Reflection.Assembly::GetType(System.String,System.Boolean)
+          MR: System.Type[] System.Reflection.Assembly::GetTypes()
+      TR: System.Reflection.AssemblyInformationalVersionAttribute
+          MR: System.Void System.Reflection.AssemblyInformationalVersionAttribute::.ctor(System.String)
       TR: System.Reflection.AssemblyName
           MR: System.String System.Reflection.AssemblyName::get_Name()
+      TR: System.Reflection.Binder
       TR: System.Reflection.BindingFlags
       TR: System.Reflection.ConstructorInfo
           MR: System.Boolean System.Reflection.ConstructorInfo::op_Equality(System.Reflection.ConstructorInfo,System.Reflection.ConstructorInfo)
+          MR: System.Boolean System.Reflection.ConstructorInfo::op_Inequality(System.Reflection.ConstructorInfo,System.Reflection.ConstructorInfo)
           MR: System.Object System.Reflection.ConstructorInfo::Invoke(System.Object[])
       TR: System.Reflection.CustomAttributeExtensions
+          MR: !!0 System.Reflection.CustomAttributeExtensions::GetCustomAttribute(System.Reflection.MemberInfo,System.Boolean)
           MR: !!0 System.Reflection.CustomAttributeExtensions::GetCustomAttribute(System.Reflection.MemberInfo)
           MR: System.Collections.Generic.IEnumerable`1<!!0> System.Reflection.CustomAttributeExtensions::GetCustomAttributes(System.Reflection.MemberInfo)
+      TR: System.Reflection.DefaultMemberAttribute
+          MR: System.Void System.Reflection.DefaultMemberAttribute::.ctor(System.String)
       TR: System.Reflection.FieldInfo
+          MR: System.Boolean System.Reflection.FieldInfo::get_IsStatic()
           MR: System.Boolean System.Reflection.FieldInfo::op_Equality(System.Reflection.FieldInfo,System.Reflection.FieldInfo)
           MR: System.Object System.Reflection.FieldInfo::GetValue(System.Object)
+          MR: System.Type System.Reflection.FieldInfo::get_FieldType()
       TR: System.Reflection.ICustomAttributeProvider
+          MR: System.Boolean System.Reflection.ICustomAttributeProvider::IsDefined(System.Type,System.Boolean)
           MR: System.Object[] System.Reflection.ICustomAttributeProvider::GetCustomAttributes(System.Type,System.Boolean)
       TR: System.Reflection.InterfaceMapping
           MR: System.Reflection.MethodInfo[] System.Reflection.InterfaceMapping::InterfaceMethods
@@ -136,36 +174,61 @@
       TR: System.Reflection.MemberInfo
           MR: System.Boolean System.Reflection.MemberInfo::IsDefined(System.Type,System.Boolean)
           MR: System.Boolean System.Reflection.MemberInfo::op_Equality(System.Reflection.MemberInfo,System.Reflection.MemberInfo)
+          MR: System.Boolean System.Reflection.MemberInfo::op_Inequality(System.Reflection.MemberInfo,System.Reflection.MemberInfo)
           MR: System.Int32 System.Reflection.MemberInfo::get_MetadataToken()
+          MR: System.Object[] System.Reflection.MemberInfo::GetCustomAttributes(System.Boolean)
           MR: System.Object[] System.Reflection.MemberInfo::GetCustomAttributes(System.Type,System.Boolean)
           MR: System.String System.Reflection.MemberInfo::get_Name()
           MR: System.Type System.Reflection.MemberInfo::get_DeclaringType()
       TR: System.Reflection.MethodBase
           MR: System.Boolean System.Reflection.MethodBase::get_ContainsGenericParameters()
+          MR: System.Boolean System.Reflection.MethodBase::get_IsGenericMethod()
+          MR: System.Boolean System.Reflection.MethodBase::get_IsGenericMethodDefinition()
           MR: System.Boolean System.Reflection.MethodBase::get_IsSpecialName()
           MR: System.Boolean System.Reflection.MethodBase::get_IsStatic()
+          MR: System.Boolean System.Reflection.MethodBase::get_IsVirtual()
           MR: System.Boolean System.Reflection.MethodBase::op_Equality(System.Reflection.MethodBase,System.Reflection.MethodBase)
           MR: System.Boolean System.Reflection.MethodBase::op_Inequality(System.Reflection.MethodBase,System.Reflection.MethodBase)
           MR: System.Object System.Reflection.MethodBase::Invoke(System.Object,System.Object[])
           MR: System.Reflection.ParameterInfo[] System.Reflection.MethodBase::GetParameters()
       TR: System.Reflection.MethodInfo
           MR: System.Boolean System.Reflection.MethodInfo::op_Equality(System.Reflection.MethodInfo,System.Reflection.MethodInfo)
+          MR: System.Boolean System.Reflection.MethodInfo::op_Inequality(System.Reflection.MethodInfo,System.Reflection.MethodInfo)
           MR: System.Reflection.ICustomAttributeProvider System.Reflection.MethodInfo::get_ReturnTypeCustomAttributes()
           MR: System.Reflection.MethodInfo System.Reflection.MethodInfo::GetBaseDefinition()
+          MR: System.Type System.Reflection.MethodInfo::get_ReturnType()
       TR: System.Reflection.Module
           MR: System.Int32 System.Reflection.Module::get_MetadataToken()
           MR: System.Reflection.Assembly System.Reflection.Module::get_Assembly()
           MR: System.Reflection.MethodBase System.Reflection.Module::ResolveMethod(System.Int32)
           MR: System.Type System.Reflection.Module::ResolveType(System.Int32)
       TR: System.Reflection.ParameterInfo
+          MR: System.Boolean System.Reflection.ParameterInfo::get_IsOut()
+          MR: System.Boolean System.Reflection.ParameterInfo::IsDefined(System.Type,System.Boolean)
+          MR: System.Object[] System.Reflection.ParameterInfo::GetCustomAttributes(System.Type,System.Boolean)
+          MR: System.String System.Reflection.ParameterInfo::get_Name()
           MR: System.Type System.Reflection.ParameterInfo::get_ParameterType()
+      TR: System.Reflection.ParameterModifier
       TR: System.Reflection.PropertyInfo
+          MR: System.Boolean System.Reflection.PropertyInfo::get_CanRead()
+          MR: System.Boolean System.Reflection.PropertyInfo::get_CanWrite()
+          MR: System.Boolean System.Reflection.PropertyInfo::op_Equality(System.Reflection.PropertyInfo,System.Reflection.PropertyInfo)
           MR: System.Boolean System.Reflection.PropertyInfo::op_Inequality(System.Reflection.PropertyInfo,System.Reflection.PropertyInfo)
+          MR: System.Reflection.MethodInfo System.Reflection.PropertyInfo::get_GetMethod()
+          MR: System.Reflection.MethodInfo System.Reflection.PropertyInfo::get_SetMethod()
           MR: System.Reflection.MethodInfo System.Reflection.PropertyInfo::GetGetMethod()
+          MR: System.Reflection.MethodInfo System.Reflection.PropertyInfo::GetGetMethod(System.Boolean)
           MR: System.Reflection.MethodInfo System.Reflection.PropertyInfo::GetSetMethod()
+          MR: System.Reflection.MethodInfo System.Reflection.PropertyInfo::GetSetMethod(System.Boolean)
+          MR: System.Type System.Reflection.PropertyInfo::get_PropertyType()
+      TR: System.Reflection.TypeFilter
+          MR: System.Void System.Reflection.TypeFilter::.ctor(System.Object,System.IntPtr)
+      TR: System.Runtime.CompilerServices.CompilationRelaxationsAttribute
+          MR: System.Void System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(System.Int32)
+      TR: System.Runtime.CompilerServices.CompilerGeneratedAttribute
+          MR: System.Void System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor()
       TR: System.Runtime.CompilerServices.ConditionalWeakTable`2
       TR: System.Runtime.CompilerServices.ExtensionAttribute
-          MR: System.Void System.Runtime.CompilerServices.ExtensionAttribute::.ctor()
       TR: System.Runtime.CompilerServices.InternalsVisibleToAttribute
           MR: System.Void System.Runtime.CompilerServices.InternalsVisibleToAttribute::.ctor(System.String)
       TR: System.Runtime.CompilerServices.IsVolatile
@@ -174,10 +237,12 @@
       TR: System.Runtime.CompilerServices.RuntimeCompatibilityAttribute
           MR: System.Void System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor()
       TR: System.Runtime.CompilerServices.RuntimeHelpers
-          MR: System.Int32 System.Runtime.CompilerServices.RuntimeHelpers::get_OffsetToStringData()
+          MR: System.Void System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(System.Array,System.RuntimeFieldHandle)
       TR: System.Runtime.ExceptionServices.ExceptionDispatchInfo
           MR: System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo::Capture(System.Exception)
           MR: System.Void System.Runtime.ExceptionServices.ExceptionDispatchInfo::Throw()
+      TR: System.Runtime.InteropServices.FieldOffsetAttribute
+          MR: System.Int32 System.Runtime.InteropServices.FieldOffsetAttribute::get_Value()
       TR: System.Runtime.InteropServices.GCHandle
           MR: System.IntPtr System.Runtime.InteropServices.GCHandle::op_Explicit(System.Runtime.InteropServices.GCHandle)
           MR: System.IntPtr System.Runtime.InteropServices.GCHandle::ToIntPtr(System.Runtime.InteropServices.GCHandle)
@@ -187,6 +252,7 @@
           MR: System.Runtime.InteropServices.GCHandle System.Runtime.InteropServices.GCHandle::FromIntPtr(System.IntPtr)
           MR: System.Void System.Runtime.InteropServices.GCHandle::Free()
       TR: System.Runtime.InteropServices.GCHandleType
+      TR: System.Runtime.InteropServices.InAttribute
       TR: System.Runtime.InteropServices.Marshal
           MR: System.Int32 System.Runtime.InteropServices.Marshal::ReadInt32(System.IntPtr)
           MR: System.Int32 System.Runtime.InteropServices.Marshal::SizeOf(System.Type)
@@ -200,14 +266,25 @@
           MR: System.Void System.Runtime.InteropServices.Marshal::Copy(System.Byte[],System.Int32,System.IntPtr,System.Int32)
           MR: System.Void System.Runtime.InteropServices.Marshal::FreeHGlobal(System.IntPtr)
           MR: System.Void System.Runtime.InteropServices.Marshal::WriteByte(System.IntPtr,System.Byte)
+          MR: System.Void System.Runtime.InteropServices.Marshal::WriteInt32(System.IntPtr,System.Int32)
+          MR: System.Void System.Runtime.InteropServices.Marshal::WriteIntPtr(System.IntPtr,System.IntPtr)
+      TR: System.Runtime.InteropServices.MarshalAsAttribute
+          MR: System.Int32 System.Runtime.InteropServices.MarshalAsAttribute::SizeConst
+          MR: System.Runtime.InteropServices.UnmanagedType System.Runtime.InteropServices.MarshalAsAttribute::get_Value()
+      TR: System.Runtime.InteropServices.UnmanagedType
+      TR: System.RuntimeFieldHandle
       TR: System.RuntimeTypeHandle
       TR: System.String
           MR: System.Boolean System.String::Equals(System.String,System.String)
           MR: System.Boolean System.String::IsNullOrEmpty(System.String)
+          MR: System.Boolean System.String::op_Equality(System.String,System.String)
           MR: System.Boolean System.String::op_Inequality(System.String,System.String)
+          MR: System.Boolean System.String::StartsWith(System.String,System.StringComparison)
           MR: System.Char System.String::get_Chars(System.Int32)
+          MR: System.Char& modreq(System.Runtime.InteropServices.InAttribute) System.String::GetPinnableReference()
           MR: System.Int32 System.String::get_Length()
           MR: System.Int32 System.String::IndexOf(System.Char)
+          MR: System.Int32 System.String::IndexOfAny(System.Char[])
           MR: System.String System.String::Concat(System.String,System.String,System.String,System.String)
           MR: System.String System.String::Concat(System.String,System.String,System.String)
           MR: System.String System.String::Concat(System.String,System.String)
@@ -217,16 +294,32 @@
           MR: System.String System.String::Format(System.String,System.Object,System.Object)
           MR: System.String System.String::Format(System.String,System.Object)
           MR: System.String System.String::Format(System.String,System.Object[])
+          MR: System.String System.String::Insert(System.Int32,System.String)
+          MR: System.String System.String::Replace(System.String,System.String)
+          MR: System.String System.String::Substring(System.Int32)
+          MR: System.String System.String::Trim()
+          MR: System.String[] System.String::Split(System.Char,System.StringSplitOptions)
+      TR: System.StringComparison
+      TR: System.StringSplitOptions
       TR: System.Text.Encoding
           MR: System.Byte[] System.Text.Encoding::GetBytes(System.String)
           MR: System.Text.Encoding System.Text.Encoding::get_UTF8()
-      TR: System.Threading._ThreadPoolWaitCallback
-          MR: System.Void System.Threading._ThreadPoolWaitCallback::SetDispatcher(System.Func`2<System.Func`1<System.Boolean>,System.Boolean>)
+      TR: System.Text.StringBuilder
+          MR: System.Text.StringBuilder System.Text.StringBuilder::Append(System.Char)
+          MR: System.Text.StringBuilder System.Text.StringBuilder::Append(System.Object)
+          MR: System.Text.StringBuilder System.Text.StringBuilder::Append(System.String)
+          MR: System.Text.StringBuilder System.Text.StringBuilder::AppendFormat(System.String,System.Object,System.Object,System.Object)
+          MR: System.Text.StringBuilder System.Text.StringBuilder::AppendFormat(System.String,System.Object,System.Object)
+          MR: System.Text.StringBuilder System.Text.StringBuilder::AppendFormat(System.String,System.Object)
+          MR: System.Void System.Text.StringBuilder::.ctor()
+          MR: System.Void System.Text.StringBuilder::.ctor(System.String,System.Int32,System.Int32,System.Int32)
       TR: System.Threading.Interlocked
           MR: System.Int32 System.Threading.Interlocked::Decrement(System.Int32&)
       TR: System.Threading.Monitor
           MR: System.Void System.Threading.Monitor::Enter(System.Object,System.Boolean&)
           MR: System.Void System.Threading.Monitor::Exit(System.Object)
+      TR: System.Threading.SendOrPostCallback
+          MR: System.Void System.Threading.SendOrPostCallback::Invoke(System.Object)
       TR: System.Threading.SynchronizationContext
           MR: System.Void System.Threading.SynchronizationContext::.ctor()
           MR: System.Void System.Threading.SynchronizationContext::SetSynchronizationContext(System.Threading.SynchronizationContext)
@@ -234,30 +327,49 @@
           MR: System.Threading.Thread System.Threading.Thread::get_CurrentThread()
       TR: System.Tuple`2
       TR: System.Type
+          MR: System.Boolean System.Type::get_ContainsGenericParameters()
+          MR: System.Boolean System.Type::get_IsAbstract()
           MR: System.Boolean System.Type::get_IsArray()
           MR: System.Boolean System.Type::get_IsByRef()
+          MR: System.Boolean System.Type::get_IsEnum()
+          MR: System.Boolean System.Type::get_IsExplicitLayout()
+          MR: System.Boolean System.Type::get_IsGenericParameter()
           MR: System.Boolean System.Type::get_IsGenericType()
+          MR: System.Boolean System.Type::get_IsGenericTypeDefinition()
           MR: System.Boolean System.Type::get_IsInterface()
+          MR: System.Boolean System.Type::get_IsNested()
           MR: System.Boolean System.Type::get_IsPointer()
+          MR: System.Boolean System.Type::get_IsValueType()
           MR: System.Boolean System.Type::IsAssignableFrom(System.Type)
           MR: System.Boolean System.Type::IsSubclassOf(System.Type)
           MR: System.Boolean System.Type::op_Equality(System.Type,System.Type)
           MR: System.Boolean System.Type::op_Inequality(System.Type,System.Type)
+          MR: System.Int32 System.Type::GetArrayRank()
           MR: System.Reflection.Assembly System.Type::get_Assembly()
           MR: System.Reflection.ConstructorInfo[] System.Type::GetConstructors(System.Reflection.BindingFlags)
           MR: System.Reflection.FieldInfo System.Type::GetField(System.String,System.Reflection.BindingFlags)
+          MR: System.Reflection.FieldInfo[] System.Type::GetFields(System.Reflection.BindingFlags)
           MR: System.Reflection.InterfaceMapping System.Type::GetInterfaceMap(System.Type)
+          MR: System.Reflection.MethodInfo System.Type::GetMethod(System.String,System.Reflection.BindingFlags,System.Reflection.Binder,System.Type[],System.Reflection.ParameterModifier[])
+          MR: System.Reflection.MethodInfo System.Type::GetMethod(System.String)
           MR: System.Reflection.MethodInfo[] System.Type::GetMethods(System.Reflection.BindingFlags)
           MR: System.Reflection.Module System.Type::get_Module()
+          MR: System.Reflection.PropertyInfo System.Type::GetProperty(System.String,System.Reflection.BindingFlags)
           MR: System.Reflection.PropertyInfo[] System.Type::GetProperties()
+          MR: System.Reflection.PropertyInfo[] System.Type::GetProperties(System.Reflection.BindingFlags)
           MR: System.String System.Type::get_AssemblyQualifiedName()
           MR: System.String System.Type::get_FullName()
+          MR: System.String System.Type::get_Namespace()
           MR: System.Type System.Type::get_BaseType()
           MR: System.Type System.Type::GetElementType()
           MR: System.Type System.Type::GetGenericTypeDefinition()
           MR: System.Type System.Type::GetTypeFromHandle(System.RuntimeTypeHandle)
+          MR: System.Type System.Type::MakeByRefType()
+          MR: System.Type System.Type::MakeGenericType(System.Type[])
+          MR: System.Type[] System.Type::FindInterfaces(System.Reflection.TypeFilter,System.Object)
+          MR: System.Type[] System.Type::GetGenericArguments()
+          MR: System.Type[] System.Type::GetGenericParameterConstraints()
           MR: System.Type[] System.Type::GetInterfaces()
-      TR: System.TypeCode
       TR: System.UInt32
       TR: System.UInt64
           MR: System.Boolean System.UInt64::Equals(System.Object)
@@ -267,26 +379,14 @@
           MR: System.Int32 System.UInt64::GetHashCode()
           MR: System.String System.UInt64::ToString()
           MR: System.String System.UInt64::ToString(System.String,System.IFormatProvider)
-          MR: System.TypeCode System.UInt64::GetTypeCode()
       TR: System.ValueType
-   AR: System, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e
-      TR: Mono.SystemDependencyProvider
-          MR: System.Void Mono.SystemDependencyProvider::Initialize()
-A: mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e
+      TR: System.Version
+          MR: System.Boolean System.Version::op_Inequality(System.Version,System.Version)
+          MR: System.Boolean System.Version::op_LessThanOrEqual(System.Version,System.Version)
+          MR: System.Int32 System.Version::get_Build()
+          MR: System.Int32 System.Version::get_Major()
+          MR: System.Int32 System.Version::get_Minor()
+          MR: System.Void System.Version::.ctor(System.Int32,System.Int32)
+      TR: System.Void
+A: System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e
    -
-A: System, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e
-   AR: mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e
-      TR: Mono.DependencyInjector
-          MR: System.Void Mono.DependencyInjector::Register(Mono.ISystemDependencyProvider)
-      TR: Mono.ISystemDependencyProvider
-      TR: System.Object
-          MR: System.Void System.Object::.ctor()
-      TR: System.Runtime.CompilerServices.ExtensionAttribute
-          MR: System.Void System.Runtime.CompilerServices.ExtensionAttribute::.ctor()
-      TR: System.Runtime.CompilerServices.InternalsVisibleToAttribute
-          MR: System.Void System.Runtime.CompilerServices.InternalsVisibleToAttribute::.ctor(System.String)
-      TR: System.Runtime.CompilerServices.RuntimeCompatibilityAttribute
-          MR: System.Void System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor()
-      TR: System.Threading.Monitor
-          MR: System.Void System.Threading.Monitor::Enter(System.Object,System.Boolean&)
-          MR: System.Void System.Threading.Monitor::Exit(System.Object)
spouliot commented 3 years ago

I took a quick look at the assembly last night and what I've seen is largely (still) disabled optimizations.

Only one (dynamic registrar) would have a significant impact on what's required inside System.Private.CoreLib.dll but the recursive effect might be larger.

Update

I missed the most obvious - since I can see the IL of the dotnet version it means the mono-cil-strip was not run against the assembly (which is normally done as Full AOT is used). That's likely the biggest contributor to the extra size of the assembly.

spouliot commented 3 years ago

Numbers from 6.0.1xx-preview3 using 6.0.100-preview.3.21202.5

Notes:

Application Comparer

Directories / Files A B diff %
.//_CodeSignature     CodeResources 4,869 7,583 2,714 55.7%
.//     archived-expanded-entitlements.xcent 392 392 0 0.0%
    embedded.mobileprovision 12,391 12,391 0 0.0%
    Info.plist 1,063 1,063 0 0.0%
    libmonosgen-2.0.dylib 0 6,245,360 6,245,360 -
    libSystem.IO.Compression.Native.dylib 0 827,248 827,248 -
    libSystem.Native.dylib 0 124,480 124,480 -
    libSystem.Net.Security.Native.dylib 0 72,016 72,016 -
    libSystem.Security.Cryptography.Native.Apple.dylib 0 80,992 80,992 -
    libxamarin-dotnet-debug.dylib 0 627,008 627,008 -
    libxamarin-dotnet.dylib 0 428,032 428,032 -
    mscorlib.aotdata.arm64 297,304 0 -297,304 -100.0%
    mscorlib.dll 407,552 0 -407,552 -100.0%
    MySingleView 3,749,104 13,298,528 9,549,424 254.7%
    MySingleView.aotdata.arm64 816 792 -24 -2.9%
    MySingleView.dll 0 4,608 4,608 -
    MySingleView.exe 4,608 0 -4,608 -100.0%
    MySingleView.pdb 0 10,296 10,296 -
    PkgInfo 8 8 0 0.0%
    System.aotdata.arm64 752 0 -752 -100.0%
    System.dll 4,608 0 -4,608 -100.0%
    System.Private.CoreLib.aotdata.arm64 0 653,536 653,536 -
    System.Private.CoreLib.dll 0 721,408 721,408 -
    System.Runtime.CompilerServices.Unsafe.aotdata.arm64 0 7,232 7,232 -
    System.Runtime.CompilerServices.Unsafe.dll 0 6,656 6,656 -
    Xamarin.iOS.aotdata.arm64 35,720 80,912 45,192 126.5%
    Xamarin.iOS.dll 56,320 159,744 103,424 183.6%
Statistics
Native subtotal 3,749,104 13,298,528 9,549,424 254.7%
    Executable 3,749,104 13,298,528 9,549,424 254.7%
    AOT data *.aotdata 0 0 0 -
Managed *.dll/exe 473,088 892,416 419,328 88.6%
TOTAL 4,575,507 23,370,285 18,794,778 410.8%
spouliot commented 3 years ago

Results with the release/6.0.1xx-preview4 branch

Major changes from P3 is that it includes the ICU data file icudt.dat for globalization while removing the .dylib and .pdb.

Application Comparer

Directories / Files Legacy 6.0.1xx-preview4 diff %
.//_CodeSignature     CodeResources 4,869 5,233 364 7.5%
.//     archived-expanded-entitlements.xcent 392 392 0 0.0%
    embedded.mobileprovision 12,391 12,391 0 0.0%
    icudt.dat 0 1,713,152 1,713,152 -
    Info.plist 1,076 1,076 0 0.0%
    mscorlib.aotdata.arm64 297,312 0 -297,312 -100.0%
    mscorlib.dll 407,552 0 -407,552 -100.0%
    MySingleView 3,749,280 13,989,808 10,240,528 273.1%
    MySingleView.aotdata.arm64 816 792 -24 -2.9%
    MySingleView.dll 0 4,608 4,608 -
    MySingleView.exe 4,608 0 -4,608 -100.0%
    PkgInfo 8 8 0 0.0%
    System.aotdata.arm64 752 0 -752 -100.0%
    System.dll 4,608 0 -4,608 -100.0%
    System.Private.CoreLib.aotdata.arm64 0 718,504 718,504 -
    System.Private.CoreLib.dll 0 802,304 802,304 -
    System.Runtime.aotdata.arm64 0 504 504 -
    System.Runtime.dll 0 5,120 5,120 -
    Xamarin.iOS.aotdata.arm64 35,720 80,272 44,552 124.7%
    Xamarin.iOS.dll 56,320 157,696 101,376 180.0%
Statistics
Native subtotal 3,749,280 13,989,808 10,240,528 273.1%
    Executable 3,749,280 13,989,808 10,240,528 273.1%
    AOT data *.aotdata 0 0 0 -
Managed *.dll/exe 473,088 969,728 496,640 105.0%
TOTAL 4,575,704 17,491,860 12,916,156 282.3%
spouliot commented 3 years ago

@marek-safar here's the binlog for the dotnet version. It comes from main (not P4) as this includes the latest (feature switches) changes build-dotnet.binlog.zip

marek-safar commented 3 years ago

@spouliot from the log there is still one optimization disabled (--disable-opt unusedtypechecks) which I think is worth investigating why.

spouliot commented 3 years ago

Another reason (beside stripping which I have working locally) for the native code to be larger might be related to the lack of the LLVM AOT backend.

if ((abi & Abi.LLVM) == Abi.LLVM)
    throw ErrorHelper.CreateError (99, $"Support for LLVM hasn't been implemented yet.");

not sure what's the status on this... it does not seems to be tracked in https://github.com/xamarin/xamarin-macios/issues/8901 @rolfbjarne @marek-safar ?

spouliot commented 3 years ago

@spouliot from the log there is still one optimization disabled (--disable-opt unusedtypechecks) which I think is worth investigating why.

59cdbc6098

The linker will treat type checks as a constant value (false), if the type in question is not instantiated, but we're instantiating types using reflection, which the linker can't see. The result is that the CIKernel_BasicTest/CIKernel_TestFromPrograms tests in monotouch-test fail.

So here we disable this particular linker optimization.

Ref: https://github.com/mono/linker/pull/1595 Ref: https://discord.com/channels/732297728826277939/751137004007456849/776033084431925268

rolfbjarne commented 3 years ago

Another reason (beside stripping which I have working locally) for the native code to be larger might be related to the lack of the LLVM AOT backend.

if ((abi & Abi.LLVM) == Abi.LLVM)
  throw ErrorHelper.CreateError (99, $"Support for LLVM hasn't been implemented yet.");

not sure what's the status on this... it does not seems to be tracked in #8901 @rolfbjarne @marek-safar ?

This is basically just a TODO for our side, I'm not aware of anything the runtime team has to do here.

I've filed https://github.com/xamarin/xamarin-macios/issues/11379 to keep track of it.

spouliot commented 3 years ago

Results with the release/6.0.1xx-preview5 branch, commit ea0097c56837c34a484e06d0abdb2e658ea4556f

Highlights

Directories / Files Legacy preview.5 diff %
.//_CodeSignature     CodeResources 4,869 5,233 364 7.5%
.//     archived-expanded-entitlements.xcent 392 392 0 0.0%
    embedded.mobileprovision 12,391 12,391 0 0.0%
    icudt.dat 0 1,713,152 1,713,152 -
    Info.plist 1,073 1,073 0 0.0%
    mscorlib.aotdata.arm64 297,320 0 -297,320 -100.0%
    mscorlib.dll 407,552 0 -407,552 -100.0%
    MySingleView 3,749,488 7,529,904 3,780,416 100.8%
    MySingleView.aotdata.arm64 816 792 -24 -2.9%
    MySingleView.dll 0 4,608 4,608 -
    MySingleView.exe 4,608 0 -4,608 -100.0%
    PkgInfo 8 8 0 0.0%
    System.aotdata.arm64 752 0 -752 -100.0%
    System.dll 4,608 0 -4,608 -100.0%
    System.Private.CoreLib.aotdata.arm64 0 674,896 674,896 -
    System.Private.CoreLib.dll 0 713,216 713,216 -
    System.Runtime.aotdata.arm64 0 504 504 -
    System.Runtime.dll 0 4,608 4,608 -
    Xamarin.iOS.aotdata.arm64 38,464 44,784 6,320 16.4%
    Xamarin.iOS.dll 57,856 73,216 15,360 26.5%
Statistics
Native subtotal 4,086,840 8,250,880 4,164,040 101.9%
    Executable 3,749,488 7,529,904 3,780,416 100.8%
    AOT data 337,352 720,976 383,624 113.7%
Managed *.dll/exe 474,624 795,648 321,024 67.6%
TOTAL 4,580,197 10,778,777 6,198,580 135.3%

Notes

IL stripping

This is not yet available for net6 builds. Manually using the mono-cil-strip tools hints at the expected size reduction.

Directories / Files Legacy preview.5 diff %
TOTAL 4,580,197 10,459,289 5,879,092 128.4%

See more details

Globalization Impact

The above P5 table is not a perfect comparison as legacy globalization support does not, by default, support for all cultures, i.e. that requires some optional I18N.*.dll assemblies. In contrast the default net6 app supports every cultures (just like other net6 platforms).

The following numbers are when net6 "Invariant Globalization" option is used. However this is, again, not a perfect comparison. The legacy app has support for several cultures included by default.

Directories / Files Legacy preview.5 diff %
TOTAL 4,580,197 8,802,021 4,221,824 92.2%

See more details

AFAICT the closest match for what legacy offered would be using icudt_EFIGS.dat (English, French, Italian, German and Spanish). This is not yet easy to configure but the following numbers are probably the closest approximation to compare, at least for the same feature set.

Directories / Files Legacy preview.5 diff %
TOTAL 4,580,197 9,667,733 5,087,536 111.1%

See more details

filipnavara commented 3 years ago

JFYI there's an unexplained difference in the size of the ICU data files (https://github.com/dotnet/designs/pull/225#discussion_r647159143). Fixing that may shave off another 200kb or so.

spouliot commented 3 years ago

@filipnavara I noticed a decrease on main (P6) in that file size. Not sure if related to your comment or not.

filipnavara commented 3 years ago

Nope, it's still wrong (big) in today's ICU package.

spouliot commented 3 years ago

Nope, it's still wrong (big) in today's ICU package.

Maybe, but I do get a smaller size in main than P5

| icudt.dat | 0 | 1,636,880 | 1,636,880 | -

Still a different size, even larger, does not mean wrong, e.g. there's a issue open wrt missing calendar data.

Anyway I expect the size of those files to vary over times (reduced by optimizations and enlarged to include missing data) and would not assume any future gain (but would gladly accept them).

filipnavara commented 3 years ago

The sizes should not vary across platforms within the same ICU package. They are generated from the same data using the same filters and tools. Currently they do differ, the Android and Browser ones are identical (and smaller) and the iOS ones are tiny bit larger.

> find . -name icudt.dat | xargs ls -l
-rw-r--r--@ 1 filipnavara  staff  1512896 Jun  7 13:03 ./android-arm/native/lib/icudt.dat
-rw-r--r--@ 1 filipnavara  staff  1512896 Jun  7 13:03 ./android-arm64/native/lib/icudt.dat
-rw-r--r--@ 1 filipnavara  staff  1512896 Jun  7 13:03 ./android-x64/native/lib/icudt.dat
-rw-r--r--@ 1 filipnavara  staff  1512896 Jun  7 13:03 ./android-x86/native/lib/icudt.dat
-rw-r--r--@ 1 filipnavara  staff  1512896 Jun  7 13:03 ./browser-wasm/native/lib/icudt.dat
-rw-r--r--@ 1 filipnavara  staff  1516384 Jun  7 13:03 ./ios-arm/native/lib/icudt.dat
-rw-r--r--@ 1 filipnavara  staff  1713152 Jun  7 13:03 ./ios-arm64/native/lib/icudt.dat
-rw-r--r--@ 1 filipnavara  staff  1713152 Jun  7 13:03 ./iossimulator-arm64/native/lib/icudt.dat
-rw-r--r--@ 1 filipnavara  staff  1713152 Jun  7 13:03 ./iossimulator-x64/native/lib/icudt.dat
-rw-r--r--@ 1 filipnavara  staff  1713152 Jun  7 13:03 ./iossimulator-x86/native/lib/icudt.dat
-rw-r--r--@ 1 filipnavara  staff  1713152 Jun  7 13:03 ./maccatalyst-arm64/native/lib/icudt.dat
-rw-r--r--@ 1 filipnavara  staff  1713152 Jun  7 13:03 ./maccatalyst-x64/native/lib/icudt.dat
-rw-r--r--@ 1 filipnavara  staff  1713152 Jun  7 13:03 ./tvos-arm64/native/lib/icudt.dat
-rw-r--r--@ 1 filipnavara  staff  1713152 Jun  7 13:03 ./tvossimulator-arm64/native/lib/icudt.dat
-rw-r--r--@ 1 filipnavara  staff  1713152 Jun  7 13:03 ./tvossimulator-x64/native/lib/icudt.dat
imhameed commented 3 years ago

Another reason (beside stripping which I have working locally) for the native code to be larger might be related to the lack of the LLVM AOT backend.

if ((abi & Abi.LLVM) == Abi.LLVM)
  throw ErrorHelper.CreateError (99, $"Support for LLVM hasn't been implemented yet.");

I built System.Private.CoreLib.dll by hand using a Mono LLVM AOT cross-compiler but there isn't very much of a size difference compared to mini's native codegen. And I haven't yet replicated by hand exactly what we're doing to generate a final executable.

But we're failing to constant-fold some runtime type checks (ThrowHelper.ThrowForUnsupportedNumericVectorBaseType for example) in both modes and I think fixing this would recover at least 300kb of executable code in __text. We're also generating "impossible" function instantiations (like generating T_REF instantiations for functions with type-level parameters that have struct constraints). We're also compiling a lot more code--post-link System.Private.CoreLib.dll yields about 23366 native Mach-O symbols while mscorlib.dll from old Mono produces ~11246.

imhameed commented 3 years ago

Here's the output of "Bloaty McBloatface" run on the netcore non-LLVM SingleView app as of 732c27afb37feb17f1ca161d55d4f92ea115c929:

https://gist.githubusercontent.com/imhameed/f7c1cf3e4061c659413a428a57187b12/raw/772babda28a1bbad644b41dbab76134ea43b1fd1/bloaty-2021-06-30-732c27afb37feb17f1ca161d55d4f92ea115c929.txt

A tsv is also available at https://gist.github.com/imhameed/f7c1cf3e4061c659413a428a57187b12

spouliot commented 3 years ago

Results with the release/6.0.1xx-preview6 branch, commit f60eec00877fe65010edf4332f7818621f02f9d0

Highlights

Directories / Files Legacy preview.6 diff %
.//_CodeSignature     CodeResources 4,869 5,525 656 13.5%
.//     archived-expanded-entitlements.xcent 392 392 0 0.0%
    embedded.mobileprovision 12,391 12,391 0 0.0%
    icudt.dat 0 1,713,152 1,713,152 -
    Info.plist 1,076 1,076 0 0.0%
    mscorlib.aotdata.arm64 284,864 0 -284,864 -100.0%
    mscorlib.dll 407,552 0 -407,552 -100.0%
    MySingleView 3,700,480 7,580,752 3,880,272 104.9%
    MySingleView.aotdata.arm64 1,120 792 -328 -29.3%
    MySingleView.dll 0 4,608 4,608 -
    MySingleView.exe 4,608 0 -4,608 -100.0%
    PkgInfo 8 8 0 0.0%
    runtimeconfig.bin 0 584 584 -
    System.aotdata.arm64 968 0 -968 -100.0%
    System.dll 4,608 0 -4,608 -100.0%
    System.Private.CoreLib.aotdata.arm64 0 677,288 677,288 -
    System.Private.CoreLib.dll 0 721,408 721,408 -
    System.Runtime.aotdata.arm64 0 504 504 -
    System.Runtime.dll 0 4,608 4,608 -
    Xamarin.iOS.aotdata.arm64 36,728 43,816 7,088 19.3%
    Xamarin.iOS.dll 57,344 72,192 14,848 25.9%
Statistics
Native subtotal 4,024,160 8,303,152 4,278,992 106.3%
    Executable 3,700,480 7,580,752 3,880,272 104.9%
    AOT data 323,680 722,400 398,720 123.2%
Managed *.dll/exe 474,112 802,816 328,704 69.3%
TOTAL 4,517,008 10,839,096 6,322,088 140.0%

Notes

spouliot commented 3 years ago

Here's the output of "Bloaty McBloatface" run on the netcore non-LLVM SingleView app as of 732c27a:

@imhameed I had a (non exhaustive) look at the symbols to see how they differ from the ones used with the current/legacy SDK results.

https://paper.dropbox.com/doc/Bloat--BPWd2y8lxnxUPnj7iQgOcRg_Ag-ONpP7jeaYaRSNX2V4RWFa

filipnavara commented 3 years ago

Unrequired EventPipe Support Unrequired Profiler Support Unrequired Interpreter Support Unrequired HotReload Support

Based on the code size these actually look like the stub implementations which is...expected I guess? (unless they get exported too which may not be necessary)

eerhardt commented 3 years ago

System.IO.Strategy.* : multiple implementations are included

@adamsitnik - any thoughts on introducing a feature switch here so only one "IO Strategy" is included?

System.Random : Multiple implementations are included

@stephentoub - same question as IO Strategy above?

spouliot commented 3 years ago

@filipnavara yes, many are stubs are individually not contributing much to the final size. There's so many symbols and almost all (individual) numbers are 0%. Not quite sure how the total of 0 ends up :)

stephentoub commented 3 years ago

System.Random : Multiple implementations are included @stephentoub - same question as IO Strategy above?

Both are used. One is used if the results could have potentially been relied on, e.g. you passed in a seed or you derived from Random (and thus potentially overrode members), in which case you get the same implementation that's been there for 20 years. The other is used if the results needn't be predictable, e.g. you just do new Random(). You could have a feature switch "UseSlowerLowerQualityRandom" and always use the older one, but I'm not sure that's a great idea. ;-)

adamsitnik commented 3 years ago

any thoughts on introducing a feature switch here so only one "IO Strategy" is included?

There are few strategies:

spouliot commented 3 years ago

Both are used.

but not (directly) by the app. Does System.Private.Corlib.dll, by-itself, really needs both ? or any ? :)

TBH there's probably nothing, beside ICU, that's "really big" to make a significant changes in the final app size. Sadly the dotnet-based builds are still 2-3 times larger than the current SDK :(

stephentoub commented 3 years ago

but not (directly) by the app

new Random(42) and new DerivedRandom() use one, new Random() uses the other. This shouldn't require a flag; the linker should be able to figure it out. https://github.com/mono/linker/issues/1794

SamMonoRT commented 3 years ago

@steveisok will help out analyze how we can configure the icu.dat file

lateralusX commented 3 years ago

@spouliot Regarding EventPipe symbols, most of these symbols (except the icalls) are only defined in the diagnostics_tracing component, libmono-component-diagnostics_tracing-static.a and not present in the corresponding stub library, libmono-component-diagnostics_tracing-stub-static.a. Are you linking towards the stub versions of the diagnostics_tracing component? When I build the sample iOS app, enabled IL stripping and link towards stub library I only ended up with a couple of icalls (*_EventPipeInternal_*) that are very thin wrappers around calls into component library (real or stub implementation depending on linking). If I however build using the none stub version of diagnostics_tracing component, I get a list similar to the one presented in the document.

spouliot commented 3 years ago

@lateralusX the data file was made by, and from a build, by @imhameed That was 20 days ago, likely on main (which was then close to preview.6) and not with LLVM.

Some things likely have changed since then... in particular wrt component'ization... Sadly the app size has increased (even with LLVM) since then :(

It's likely worth updating the data to the latest builds from main before getting too deep into anything I mentioned :)

imhameed commented 3 years ago

Here's another run of bloaty against dab0f2ed9a6dce0398143493b85631bdcebcb887 (which uses 6.0.100-rc.1.21378.3): tsv/txt

lateralusX commented 3 years ago

Looks like this app build still includes all components (just looking at the symbols in list above), diagnostics_tracing, hot_reload and debugger. If its a static linked runtime, then build needs to link the stub versions of all components. If its a dynamic linked runtime, then the corresponding component dylibs should not be included in the app bundle.

rolfbjarne commented 3 years ago

Looks like this app build still includes all components

Yes, the components work is still in progress.

imhameed commented 3 years ago

@rolfbjarne is there an issue tracking this components work? Is it https://github.com/xamarin/xamarin-macios/issues/12100?

imhameed commented 3 years ago

@steveisok will help out analyze how we can configure the icu.dat file

@steveisok Is there a tracking issue for ICU-related work? e.g. shrinking libicu itself, or removing stuff from ICU data files? I am aware of only https://github.com/dotnet/runtime/issues/55637

rolfbjarne commented 3 years ago

@rolfbjarne is there an issue tracking this components work? Is it #12100?

Yes, that's the tracking issue.

spouliot commented 3 years ago

Preview 7

Highlights

Directories / Files Legacy preview.7 diff %
.//_CodeSignature     CodeResources 4,869 5,525 656 13.5%
.//     archived-expanded-entitlements.xcent 392 392 0 0.0%
    embedded.mobileprovision 12,391 12,391 0 0.0%
    icudt.dat 0 2,176,304 2,176,304 -
    Info.plist 1,077 1,077 0 0.0%
    mscorlib.aotdata.arm64 284,864 0 -284,864 -100.0%
    mscorlib.dll 407,552 0 -407,552 -100.0%
    MySingleView 3,700,528 7,719,712 4,019,184 108.6%
    MySingleView.aotdata.arm64 1,120 1,064 -56 -5.0%
    MySingleView.dll 0 4,608 4,608 -
    MySingleView.exe 4,608 0 -4,608 -100.0%
    PkgInfo 8 8 0 0.0%
    runtimeconfig.bin 0 696 696 -
    System.aotdata.arm64 968 0 -968 -100.0%
    System.dll 4,608 0 -4,608 -100.0%
    System.Private.CoreLib.aotdata.arm64 0 510,128 510,128 -
    System.Private.CoreLib.dll 0 744,960 744,960 -
    System.Runtime.aotdata.arm64 0 824 824 -
    System.Runtime.dll 0 4,608 4,608 -
    Xamarin.iOS.aotdata.arm64 36,688 33,344 -3,344 -9.1%
    Xamarin.iOS.dll 57,344 72,192 14,848 25.9%
Statistics
Native subtotal 4,024,168 8,265,072 4,240,904 105.4%
    Executable 3,700,528 7,719,712 4,019,184 108.6%
    AOT data 323,640 545,360 221,720 68.5%
Managed *.dll/exe 474,112 826,368 352,256 74.3%
TOTAL 4,517,017 11,287,833 6,770,816 149.9%
imhameed commented 3 years ago

Here's another bloaty report from 9307052231a5d2acdaf18e9211b6d8bec54b8e65: txt, tsv.

https://github.com/xamarin/xamarin-macios/pull/12323, which added support for Mono Components, is in the history of this commit but symbols for interpreter support and hot reload support are still present in the output binary.

EDIT: For posterity, here's the SingleView app on legacy Mono: txt, tsv