Open rolfbjarne opened 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
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.
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 ;-)
oldnet/bin/iPhone/Release/MySingleView.app
dotnet/bin/iPhone/Release/net6.0-ios/ios-arm64/MySingleView.app
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% |
other issues
MySingleView.pdb
, should not be copied to release .app~otool -L MySingleView
does not show libicu*
nor is there any data files. AFAIK those are required for globalization of net5+ apps (and the existing oldnet
app has globalization support)~update: both issues are fixed with P4
@spouliot could you share the binaries?
@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.
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.
@marek-safar
@spouliot could you share the binaries?
That's after https://github.com/xamarin/xamarin-macios/pull/10250, so the runtime switches have been toggled for these apps.
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.
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:
System.Runtime.dll
System.Runtime.Serialization.Formatters.dll
System.Private.CoreLib.dll
It's a great improvement, over the original numbers, but there's still work to be done compared to the current SDK size.
/Users/poupou/git/master/xamarin-macios/tests/dotnet/size-comparison/MySingleView/oldnet/bin/iPhone/Release/MySingleView.app
/Users/poupou/git/master/xamarin-macios/tests/dotnet/size-comparison/MySingleView/dotnet/bin/iPhone/Release/net6.0-ios/ios-arm64/MySingleView.app
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% |
@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.
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
@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)
I took a quick look at the assembly last night and what I've seen is largely (still) disabled optimizations.
System.Reflection
API.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.
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.
Numbers from 6.0.1xx-preview3
using 6.0.100-preview.3.21202.5
Notes:
/Users/poupou/git/net6/p3/xamarin-macios/tests/dotnet/size-comparison/MySingleView/oldnet/bin/iPhone/Release/MySingleView.app
/Users/poupou/git/net6/p3/xamarin-macios/tests/dotnet/size-comparison/MySingleView/dotnet/bin/iPhone/Release/net6.0-ios/ios-arm64/MySingleView.app
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% |
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
.
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% |
@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
@spouliot from the log there is still one optimization disabled (--disable-opt unusedtypechecks) which I think is worth investigating why.
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 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
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.
Results with the release/6.0.1xx-preview5
branch, commit ea0097c56837c34a484e06d0abdb2e658ea4556f
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% |
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
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
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.
@filipnavara I noticed a decrease on main
(P6) in that file size. Not sure if related to your comment or not.
Nope, it's still wrong (big) in today's ICU package.
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).
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
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.
Here's the output of "Bloaty McBloatface" run on the netcore non-LLVM SingleView app as of 732c27afb37feb17f1ca161d55d4f92ea115c929:
A tsv is also available at https://gist.github.com/imhameed/f7c1cf3e4061c659413a428a57187b12
Results with the release/6.0.1xx-preview6 branch, commit f60eec00877fe65010edf4332f7818621f02f9d0
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% |
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
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)
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?
@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 :)
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. ;-)
any thoughts on introducing a feature switch here so only one "IO Strategy" is included?
There are few strategies:
Net5CompatFileStreamStrategy
- used as a backward compat switch. It's disabled by default, can be enabled via app compat switch (it should be available at compile time) and env var. Perhaps linker could respect only the app compat switch in case of mobile apps (I am newbie to mobile, but I would not expect env vars to be a thing for mobile apps) and remove it when it's not requested in the config file?UnixFileStreamStrategy
- enabled by default, can be removed if app compat switch requested .NET 5 mode.BufferedFileStreamStrategy
- used when buffering is enabled (the default for FileStream
) as a wrapper for UnixFileStreamStrategy
, contains all the buffering logic.DerivedFileStreamStrategy
- used when there is a custom type that derives from FileStream
, as a wrapper for BufferedFileStreamStrategy
or UnixFileStreamStrategy
depending on whether buffering was requested . If there is no type that derives from FileStream
, there is no need for it. Could linker handle that?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 :(
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
@steveisok will help out analyze how we can configure the icu.dat file
@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.
@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 :)
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.
Looks like this app build still includes all components
Yes, the components work is still in progress.
@rolfbjarne is there an issue tracking this components work? Is it https://github.com/xamarin/xamarin-macios/issues/12100?
@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 is there an issue tracking this components work? Is it #12100?
Yes, that's the tracking issue.
release/6.0.1xx-preview7
icudt.dat
gained about 400 KB - but main
is 200 KB smaller (than p7)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% |
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
App sizes are currently significantly bigger with .NET 6 with a very simple hello world app.
Test case
xamarin-macios
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
System.Reflection
API (see below)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).