microsoft / CLRInstrumentationEngine

The CLR Instrumentation Engine is a cooperation profiler that allows running multiple profiling extensions in the same process.
Other
94 stars 48 forks source link

Roadmap question - mocking and injection #252

Closed weltkante closed 4 years ago

weltkante commented 4 years ago

Is there any update to the roadmap, considering all milestones have been reached already? Is there any further open sourcing planned, in particular of the injection system currently used for telemetry?

I'm interested in implementing a mocking backend based on rejit (non-commercial, primarily for internal use, but I wouldn't mind contributing my work to open source efforts either if there is interest).

From the research I've done the telemetry injection from Application Insights gets very close to the needs of a mocking backend. What I need is injecting a callback at the start of the method which can decide between executing the method normally or redirecting the call providing a return value (or throwing an exception) without executing the rest of the method.

Obviously I'd like to make use of CLRIE instead of writing the backend from scratch, but there's also the question of whether more of the injection system is going to be open sourced. In that case it may make sense to wait for it instead of reinventing too much wheel, depending on how the roadmap looks.

So is there anything planned (or am I missing anything thats already there), or should I be basing my work off what is currently available here?

WilliamXieMSFT commented 4 years ago

Hi @weltkante,

Regarding the roadmap, we have the Windows installers now available at: https://github.com/microsoft/CLRInstrumentationEngine/blob/develop/docs/releases.md. We're still contemplating how to best distribute for Linux, but that work is on hold for now.

Your scenario for injecting a callback seems like a good candidate to use CLRIE's ReJIT capabilities; you should be able to start working with what is currently available in the develop branch.

We welcome any contributions you would like to make to the project, and you can ask private questions to clrieowners@microsoft.com or post public GitHub issues with the label "question" as needed.

weltkante commented 4 years ago

So I've been digging through the source for a few days and I'm making good progress, was able to code an extension module and get it loaded, redirecting a .NET method to a native callback, setting up a method to call for installing mocking redirects.

Next step is trying to do managed-to-managed redirects, the relevant code used by Application Insights is not open sourced but I see an incomplete implementation in CManagedRedirectCodeInjector (which isn't used throughout the project) and the basic idea isn't too complex anyways, so I think I'll manage without having an example.

I have some general questions though:

SergeyKanzhelev commented 4 years ago

@weltkante we just discussed this in OpenTelemetry meeting where we are choosing the code injection engine for telemetry. Here is an issue: https://github.com/open-telemetry/opentelemetry-dotnet/issues/584, last comment is a link to the document with some considerations made for Intercept extension.

Would Intercept extension be exactly what you need?

weltkante commented 4 years ago

Not really, its not exactly what I need, since its tailord for logging without affecting the implementation. Mocking needs to (conditionally) skip the normal implementation which needs some trickery to express in the existing registration/dispatch API.

Method rewriting for mocking only requires a callback at the beginning of the method, callbacks at return time and exception time are not needed. However the callback at the beginning of the method must be able to selectively override the implementation and compute a return value (or throw).

The implementation I'm currently thinking of would use the delegate return value for the computed return value and pass a ref bool as first argument to indicate whether the callback has computed a return value. Obviously thats not compatible with existing registration/dispatch logic and also causes a chicken-egg problem when creating the delegates, since they need to be declared in mscorlib but instantiated outside.

If I wanted I could use the existing registration/dispatching infrastructure like this:

It would probably have a measurable performance impact of allcoating (or pooling) argument arrays and syncing it with arguments. So yeah, not an exact match, but could be made working, but for now I'm prototyping to see what I would want if I inserted my own registration/dispatcher logic into mscorlib.

PS: I'm also not happy with the way callbacks are indexed, using a 32 bit string hash seems risky, especially if multiple extensions were to be using the same registration/dispatcher infrastructure for different purposes. There may be a significant risk of hash colissions. I'd prefer if IDs were generated on registration to guarantee uniqueness (just have an interlocked increment of a counter?)