Skip to content

Bringing down the size of Hello World under 2 MB #80165

@MichalStrehovsky

Description

@MichalStrehovsky

Hello World with Native AOT is currently at around 2.7 MB. I spent a couple hours to see what would it take to bring it down to the same size as Golang (2 MB). It might actually be achievable with our default trimming settings and feature switches with a couple days of BCL/compiler work.

The benefits would be threefold:

  • Our internal efficiency (compiling non-xunit-based tests will get faster and require less disk space, which is not insignificant as long as we have thousands of tiny tests)
  • We can delete reflection disabled mode
  • Bragging rights

The 6686dbc commit has a couple hacks in it around areas of interest. With those hacks, the size of a hello world goes down to 2.16 MB. With InvariantGlobalization and UseSystemResourceKeys it goes further down to 1.53 MB. This is awfully close to what is achievable with reflection disabled mode. We actually regressed the reflection disabled mode because a Hello World now has a generic virtual method call around enums and we need the entirety of the type loader to support that. But I digress.

Should we choose to accept this challenge, we'll need to fix all of the issues in the commit to really reap the benefit. The benefit is elimination of the entire reflection stack that deals with type members (in fact my goal was to get MemberPolicies class out of the hello world).

Here's the problems:

  • Stack frame should not eagerly try to populate the MethodBase, only once it's requested.
  • Type components cache should not try to eagerly populate the members. We use this class to stash details about enums in the GenericCache property. Populating anything else is a waste.
  • Type.IsEnum and IsValueType. We expand these as intrinsics in codegen for RuntimeTypes. Hello world only needs them for RuntimeTypes. IL scanner might need to learn the RyuJITs trick. (This is really only a problem because IL scanner runs. Reduce the number of forced MethodTables #79594 might already help with this to some extent but I didn't check. Would be nice if it did.)
  • Searching for DefaultDllImportSearchPathsAttribute is avoidable if this codepath is only reached from p/invoke resolution.
  • Attribute.Equals and GetHashCode. This is a tough one. .NET Native didn't use a reflection-based implementation. We could restore that. Other alternative is to see if we can eliminate all custom attribute descendants from a hello world. The theory is that if we make generation of custom attributes conditional on the presence of the code to read them, we might be able to get rid of them all. But not sure. Chose not to address this and live with a small increase in size due to FieldInfo reflection. That one is less impactful than Method/ConstructorInfo.
  • Resource manager looking for attributes. I don't have ideas right now but I also didn't look at it in detail.

Cc @dotnet/ilc-contrib

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions