Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extra memory used when attempting to JIT generics that have one or more structs as a generic type parameter or when accessed through an interface. #37143

Open
jmaine opened this issue May 29, 2020 · 3 comments
Labels
area-VM-coreclr tenet-performance Performance related issue
Milestone

Comments

@jmaine
Copy link
Contributor

jmaine commented May 29, 2020

Extra memory used when attempting to JIT generics that have one or more structs as a generic type parameter or when accessed through an interface. The idea is to reduce the number of times a new JITed method is created in both AOT and non-AOT environments. This may also be known as Universal Shared Code.

Description

Extra memory used when attempting to JIT generics that have one or more structs as a generic type parameter or when accessed through an interface. Secondly, it bloats binaries that generated as an AOT binary. Moreover, it bloats the memory used in non-AOT environments.

The proposal is to logically pass the struct into generic methods, methods in generic classes, and methods accessed by interfaces by reference/pointer behind the scenes without changing any source or IL code or boxing the struct on the heap. If done correctly, it can reduce and possibly eliminate quite a number of peeled methods when JITing and/or boxing.

In the case of a generic class with a struct as a type parameter, the JIT will add/use extra information provided in the class to make methods that can, in this case, be reused across multiple structs.

Out of Scope

Any change that requires a change in the IL or source code of any existing programs/libraries.

Configuration

public interface IMyInterface {
     int X;
     int Y;
}
public struct MyStruct : IMyInterface {
   public int X;
   public int Y;
}

public class MyClass {
    public void MyGenericMethod<T>(T paramater) {
         
    }

    public void MyInterfaceMethod(IMyInterface parameter) {

    }
} 

public class MyGenericClass<T> {
    T MyExampleProperty { get; set; }
}

Regression?

This is an enhancement to the .Net Core and Mono JIT.

Questions?

  • Is this request asking to have Universal Shared Generics feature added into the .Net Core's JIT library? Yes.
  • What would be the performance characteristics of the enhancements?
  • It is very likely that primitive structs may not benefit from this enhancement, but larger structs could.
    • What would be the cutoff point where this enhancement starts becoming beneficial?
  • How would we keep expected behavior when modifying structs?
    • Should we do a copy-on-write when a struct is written to when this enhancement is used?
      • Can this copy-on-write feature be implemented to be lazy in nature?
      • What would be the performance characteristics of this copy-on-write feature?
    • Should we only use this enhancement on read-only or effectively read-only structs?

Updates

Alternate solutions:

  • Add trapline code that can jump to the specialized method efficiently.
    • For generics with a single type parameter, use a jump table simular to calling a virtual method to get to the specialized version of the method.
    • For generics with few generic type parameters, use a hash table to find the specialized implementation.
    • Otherwise, use a Universal Shared Generics implementation of the method.
@jmaine jmaine added the tenet-performance Performance related issue label May 29, 2020
@Dotnet-GitSync-Bot Dotnet-GitSync-Bot added area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI untriaged New issue has not been triaged by the area owner labels May 29, 2020
@stephentoub
Copy link
Member

stephentoub commented May 29, 2020

There is a lot of code now, in the core libraries, in ASP.NET, and elsewhere, that relies on the generic specialization done for value types to get good throughput / reduced memory allocation. A blanket change to how this is done would result in massive regressions.

(For AOT and an explosion in the number of instantiations, solutions like Universal Shared Generics exist.)

@jmaine
Copy link
Contributor Author

jmaine commented May 30, 2020

@stephentoub, the idea is not to do a blanket change but to provide a way to be able to use MethodInfo.MakeGenericMethod(Type[]) and Type.MakeGenericType(Type[]) in AOT environments and use Universal Shared Generics where the size of the struct would make it efficient.

@AndyAyersMS AndyAyersMS added area-VM-coreclr and removed area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI labels Jun 1, 2020
@AndyAyersMS
Copy link
Member

Mono already has a feature like this.

For .Net Core, sharing decisions are made by the runtime, so am going to change the area label.

@mangod9 mangod9 removed the untriaged New issue has not been triaged by the area owner label Jun 3, 2020
@mangod9 mangod9 added this to the Future milestone Jun 3, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-VM-coreclr tenet-performance Performance related issue
Projects
None yet
Development

No branches or pull requests

5 participants