Skip to content

Hosting API to enable hot reload at startup #47274

Closed

Description

@lambdageek

Related to #44806 and #45629.

When running without a debugger attached, we need a way to tell the runtime that certain assemblies will be modified with EnC deltas. For Mono we need to do this early enough that we set the right interpreter optimization flags before we execute any managed code from the affected assemblies.

The information given to the runtime should probably include the set of assemblies that will be modified (as opposed to informing the runtime that any assembly at all could potentially be modified).

The current proposal:

Pass an environment variable DOTNET_MODIFIABLE_ASSEMBLIES with the case-insensitive keyword "debug" to enable all debug built assemblies for hot reload. This can be expanded on with other keywords like "all" or a comma separated list of assemblies when there are clear scenarios for the options.

Alternative approaches:

  1. Pass a new MODIFIABLE_ASSEMBLIES property to coreclr_initialize that includes a list of assemblies that the runtime should expect to be modified. The presence of the property would indicate that hot reload support should be enabled. We could pass the property via the .runtimeconfig.dev.json file without any modifications to the (desktop) host. Mobile and wasm workloads would need to adjust their hosts.
  2. Pass an environment variable DOTNET_MODIFIABLE_ASSEMBLIES with the same information. On mobile and wasm workloads, the hosts wouldn't need to be adjusted, MonoVM would consult the environment variable itself. On other workloads the host could interpret the environment variable or leave it to the runtimes.

Activity

  1. ghost added
    untriagedNew issue has not been triaged by the area owner
    on Jan 21, 2021
  2. lambdageek commented on Jan 21, 2021

    @lambdageek
    MemberAuthor
  3. added this to the 6.0.0 milestone on Jan 21, 2021
  4. jkotas commented on Jan 21, 2021

    @jkotas
    Member

    My loosely held opinion is that an environment variable is better.

    It assumes that the app in EnC mode is launched by a controller that sets this environment variable for you. Is it a safe assumption to make?

    ComPlus_ModifiableAssemblies

    DOTNET_MODIFIABLE_ASSEMBLIES would be a better name.

  5. vitek-karas commented on Jan 21, 2021

    @vitek-karas
    Member

    Passing additional properties to the runtime through coreclr_initialize is already possible by modifying the .runtimeconfig.json or via .runtimeconfig.dev.json. Using those would not need any host changes. We could also add the env. variable support to the host for this and potentially even command line support if necessary.

    In this sense it would be similar to DOTNET_STARTUP_HOOKS which is an env. variable read by the host and passed to the runtime via the runtime properties. For this one we only allow runtimeconfig and env. variable - there's no command line, at least yet.

    I guess it depends on the needs in this case:

    • Do we need to support something like "lazy attach", so that the app starts without the "controller" which "attaches" much later on?
    • Do we need to support this on "random" app, that is app which was produced using any build configuration without knowing that it will be used this way?

    If we only need to support this in cases where we build the app with hot reload in mind (similar to "Debug" configuration), then using the .runtimeconfig.dev.json and the runtime property would probably be a good fit - with no changes necessary to the host.

  6. lambdageek commented on Jan 21, 2021

    @lambdageek
    MemberAuthor

    Hmm.. using .runtimeconfig.dev.json is appealing, but I don't think the content of that file is passed along to mobile (or wasm) workloads.

  7. vitek-karas commented on Jan 21, 2021

    @vitek-karas
    Member

    Do we pass along the .runtimeconfig.json? That one would also work - if we're really doing a special build for this case.

  8. lambdageek commented on Jan 22, 2021

    @lambdageek
    MemberAuthor

    Do we pass along the .runtimeconfig.json? That one would also work - if we're really doing a special build for this case.

    My understanding is that at this time the mobile embedders don't bundle the json files (or otherwise make the content available). And also apparently they're not using monovm_initialize/coreclr_intialize yet.

    I'm back to mildly preferring to use an environment variable.

    Update: we added work items for XI and XA to make sure they call monovm_initialize dotnet/macios#10504 and dotnet/android#5537, although that still leaves the mobile hosts with funnelling the runtimeconfig properties into the runtime.

  9. lambdageek commented on Jan 22, 2021

    @lambdageek
    MemberAuthor

    It assumes that the app in EnC mode is launched by a controller that sets this environment variable for you. Is it a safe assumption to make?

    I think so. Hot Reload would most likely need a controller that is responsible for launching the app. (That seems the easiest way to guarantee that the controller has a consistent view of the source code, the managed assemblies and queued up EnC deltas)

  10. vitek-karas commented on Jan 22, 2021

    @vitek-karas
    Member

    Will we use managed APIs to actually do the hot-reload editing?
    If true, then how are we going to inject the necessary managed code to the app?
    I'm thinking that maybe something like startup hooks would be a better fit - for both reasons. It could setup the necessary communications channels (all in managed) and also tell the runtime which assemblies should be enabled for "Editing".

  11. lambdageek commented on Jan 22, 2021

    @lambdageek
    MemberAuthor

    Will we use managed APIs to actually do the hot-reload editing?

    Still TBD - it's what I'm prototyping in Mono, but ultimately we'll have to align on a design with @tommcdon.

    I'm thinking that maybe something like startup hooks would be a better fit - for both reasons. It could setup the necessary communications channels (all in managed) and also tell the runtime which assemblies should be enabled for "Editing".

    I can think of reasons why that won't work right now for Mono's hot reload, but I have a harder time thinking of why this wouldn't work in principle.

    Details Assuming we choose the right execution engine (interp, not JIT or AOT), the information that hot reload needs is: don't do inlining of any methods that could change. Which in practice means don't inline methods from a modifiable assembly. So a startup hook out to work to tell the runtime what the modifiable assemblies are. Currently it's all-or-nothing in mono - we turn off all inlining, because there's no flag for modifiable assemblies yet. But it seems reasonable to add such a flag and it shouldn't slow down the interpreter fast path unreasonably.

    Setting up a communication channel through a startup hook, may work, but I'm not certain. The "main assembly" on Xamarin.iOS is the Xamarin Objective C runtime. So setting up a communication channel would have to be done without using any managed iOS functionality. I'm not sure if that's an onerous limitation. Probably it's ok. I think XA works similarly. I suppose worst case the managed startup hook could call into a native library for the bulk of the work. A managed startup hook would work on wasm, I think.

    Mono and all three of those hosts don't have startup hook support right now, so that would need to be done. Xamarin and wasm will require tooling work to bundle the startup hook assemblies into the application bundles (and maybe AOT them for ios).

  12. 21 remaining items

  13. jkotas commented on Feb 18, 2021

    @jkotas
    Member

    We should also clarify how All works together with inlining. Is All going to prevent inlining by turning off optimizations for the whole process?

  14. mikem8361 commented on Feb 18, 2021

    @mikem8361
    Contributor

    they can be used with module paths separated by
    Are we going to actually use this for anything in near future? I sounds like unnecessary complication to me.

    We may want it for testing to enable just a test assembly regardless of how it is built. Hopefully @pranavkm can tell us if specifying individual modules will be useful for dotnet-watch.

  15. jkotas commented on Feb 18, 2021

    @jkotas
    Member

    Are we going to support hot-reload e2e for the release build configuration? If not, we should rather always build the test assemblies for this as debug.

  16. pranavkm commented on Feb 18, 2021

    @pranavkm
    Contributor

    dotnet-watch is aware of the set of projects / assemblies it's building. It would be fairly easy for us to specify the list of assemblies being built as a value to the env variable if that makes a difference. That said, in the ordinary case specifying Debug should suffice. We can provide UX to users telling them hot reload is being disabled because they're building their app in release if that complicates things.

  17. mikem8361 commented on Feb 19, 2021

    @mikem8361
    Contributor

    We should also clarify how All works together with inlining. Is All going to prevent inlining by turning off optimizations for the whole process?

    I don't know if the JIT_FLAG_DEBUG_EnC (set if the module is editable) disables inlining or not. It does prepare for on stack replacement which isn't needed for hot reload but may be needed on Windows for a smooth transition from hot reload edits to debugging/ENC.

    Unless it has noticeable performance impact and since it is opt-in now, I say the "All" option sets the jit ENC flag just like the COMPlus_ForceENC. To keep things simple and consistent I think the "All" option should do this for Windows, Linux and MacOS, etc.

  18. jkotas commented on Feb 19, 2021

    @jkotas
    Member

    the JIT_FLAG_DEBUG_EnC (set if the module is editable) disables inlining or not.

    It does not.

    COMPlus_ForceENC is a testing hack that does not always work correctly. If we just want a hack for testing, we can keep using COMPlus_ForceENC. If we want something that actually works well, it is going to need more work.

    I think we should just enable the Debug policy for now, and worry about other policies only once we have a clear scenario for them.

  19. removed
    untriagedNew issue has not been triaged by the area owner
    on Feb 19, 2021
  20. mikem8361 commented on Feb 19, 2021

    @mikem8361
    Contributor

    Does this env var need to go through an official API review? Should I mark it api-ready-for-review?

    /cc: @stephentoub

  21. stephentoub commented on Feb 20, 2021

    @stephentoub
    Member

    Does this env var need to go through an official API review?

    Today, no. Though we're getting to a point with our environment variables where I do think we should start looking at them with a view to consistency, and potentially adding a tiny more amount of process around them, not to block them but just to help with that consistency. @terrajobst, thoughts?

    Related: #47283

  22. mikem8361 commented on Mar 8, 2021

    @mikem8361
    Contributor

    @lambdageek, have you added this env var to mono yet?

  23. lambdageek commented on Mar 9, 2021

    @lambdageek
    MemberAuthor

    @mikem8361 Nope, got pulled away to work on a couple other things. Hope to return to it later this week.

  24. lambdageek commented on Mar 13, 2021

    @lambdageek
    MemberAuthor

    This is now done for MonoVM and CoreCLR

  25. ghost locked as resolved and limited conversation to collaborators on Apr 12, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

api-suggestionEarly API idea and discussion, it is NOT ready for implementationarea-Host

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions