<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>David Broman's CLR Profiling API Blog</title><link>http://blogs.msdn.com/b/davbr/</link><description>Info about the Common Language Runtime&amp;#39;s Profiling API</description><dc:language>en-US</dc:language><generator>Telligent Evolution Platform Developer Build (Build: 5.6.50428.7875)</generator><item><title>Writing a Profiler of Windows Store apps</title><link>http://blogs.msdn.com/b/davbr/archive/2013/01/09/writing-a-profiler-of-windows-store-apps.aspx</link><pubDate>Wed, 09 Jan 2013 20:48:28 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:10383604</guid><dc:creator>David Broman</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.msdn.com/b/davbr/rsscomments.aspx?WeblogPostID=10383604</wfw:commentRss><comments>http://blogs.msdn.com/b/davbr/archive/2013/01/09/writing-a-profiler-of-windows-store-apps.aspx#comments</comments><description>&lt;p&gt;If you’ve written a profiler that consumes the CLR Profiling API, and are looking to update it to analyze Windows Store apps, then you’ll be interested in this new whitepaper: &lt;/p&gt;  &lt;p&gt;&lt;a href="http://go.microsoft.com/fwlink/?LinkID=271485"&gt;http://go.microsoft.com/fwlink/?LinkID=271485&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;The whitepaper provides recommendations for all the changes you’ll need to make so your profiler can profile Windows Store apps.&amp;#160; As you read through the whitepaper, keep in mind that the source code to &lt;a href="http://blogs.msdn.com/b/davbr/archive/2012/11/19/clrprofiler-4-5-released-includes-windows-store-app-support.aspx"&gt;CLRProfiler 4.5&lt;/a&gt; can also be used to illustrate many of these changes you’ll need to make.&lt;/p&gt;  &lt;p&gt;Happy coding!&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10383604" width="1" height="1"&gt;</description></item><item><title>New sample code for rewriting IL: ILRewrite Profiler</title><link>http://blogs.msdn.com/b/davbr/archive/2012/11/19/new-sample-code-for-rewriting-il-ilrewrite-profiler.aspx</link><pubDate>Mon, 19 Nov 2012 22:14:36 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:10369986</guid><dc:creator>David Broman</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.msdn.com/b/davbr/rsscomments.aspx?WeblogPostID=10369986</wfw:commentRss><comments>http://blogs.msdn.com/b/davbr/archive/2012/11/19/new-sample-code-for-rewriting-il-ilrewrite-profiler.aspx#comments</comments><description>&lt;p&gt;In my &lt;a href="http://blogs.msdn.com/b/davbr/archive/2012/11/19/clrprofiler-4-5-released-includes-windows-store-app-support.aspx"&gt;previous post&lt;/a&gt;, I mentioned the new home for CLRProfiler, where you can find its latest version, 4.5: &lt;a title="http://clrprofiler.codeplex.com/" href="http://clrprofiler.codeplex.com/"&gt;http://clrprofiler.codeplex.com/&lt;/a&gt;.&amp;#160; On the same CodePlex site you can also find a new sample, &lt;strong&gt;ILRewrite&lt;/strong&gt;.&amp;#160; ILRewrite contains sample code demonstrating the following:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Parsing a stream of IL bytes into a linked list of editable structures &lt;/li&gt;    &lt;li&gt;Writing that linked list back out into a new stream of IL bytes &lt;/li&gt;    &lt;li&gt;Using the metadata API to add AssemblyRefs, TypeRefs, and MemberRefs to modules you instrument &lt;/li&gt;    &lt;li&gt;Using the metadata API to add brand new methods into mscorlib.dll &lt;/li&gt;    &lt;li&gt;Using the new RequestReJIT and RequestRevert APIs. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Click on the &lt;strong&gt;ILRewrite10Source &lt;/strong&gt;download from the &lt;strong&gt;Downloads&lt;/strong&gt; &lt;strong&gt;tab&lt;/strong&gt;.&amp;#160; You can find some basic documentation on the &lt;strong&gt;Documentation tab&lt;/strong&gt;, and more detailed documentation in the &lt;strong&gt;readme.txt&lt;/strong&gt; distributed as part of the source.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10369986" width="1" height="1"&gt;</description></item><item><title>CLRProfiler 4.5 released: includes Windows Store app support</title><link>http://blogs.msdn.com/b/davbr/archive/2012/11/19/clrprofiler-4-5-released-includes-windows-store-app-support.aspx</link><pubDate>Mon, 19 Nov 2012 22:12:34 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:10369985</guid><dc:creator>David Broman</dc:creator><slash:comments>3</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.msdn.com/b/davbr/rsscomments.aspx?WeblogPostID=10369985</wfw:commentRss><comments>http://blogs.msdn.com/b/davbr/archive/2012/11/19/clrprofiler-4-5-released-includes-windows-store-app-support.aspx#comments</comments><description>&lt;p&gt;You can find CLRProfiler 4.5 at its new home on CodePlex: &lt;a title="http://clrprofiler.codeplex.com/" href="http://clrprofiler.codeplex.com/"&gt;http://clrprofiler.codeplex.com/&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;If you’re interested in &lt;em&gt;using&lt;/em&gt; CLRProfiler to diagnose memory issues with your managed app, including managed Windows Store apps, all you need is the &lt;strong&gt;CLRProfiler45Binaries&lt;/strong&gt; download from the &lt;strong&gt;Downloads&lt;/strong&gt; &lt;strong&gt;tab&lt;/strong&gt;.&amp;#160; &lt;font color="#ff0000"&gt;Please be sure to read the installation instructions first&lt;/font&gt;.&amp;#160; You will find a link to the installation instructions from the Downloads tab.&lt;/p&gt;  &lt;p&gt;If you’re interested in &lt;em&gt;writing &lt;/em&gt;your own profiler to diagnose Windows Store apps, you may find CLRProfiler 4.5 useful as an example.&amp;#160; You’ll want the &lt;strong&gt;CLRProfiler45Source&lt;/strong&gt; download from the &lt;strong&gt;Downloads&lt;/strong&gt; &lt;strong&gt;tab&lt;/strong&gt;.&amp;#160; (Note, in early December we expect also to release a white paper documenting what you’ll need to know about writing a profiler that analyzes Windows Store apps.)&lt;/p&gt;  &lt;p&gt;In the coming weeks we expect to publish more complete information on CLRProfiler 4.5, but I wanted to get this small post out there now so you’re aware that CLRProfiler 4.5 is available.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10369985" width="1" height="1"&gt;</description></item><item><title>GC Heap and Alignment Padding</title><link>http://blogs.msdn.com/b/davbr/archive/2011/12/29/gc-heap-and-alignment-padding.aspx</link><pubDate>Thu, 29 Dec 2011 19:48:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:10251839</guid><dc:creator>David Broman</dc:creator><slash:comments>1</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.msdn.com/b/davbr/rsscomments.aspx?WeblogPostID=10251839</wfw:commentRss><comments>http://blogs.msdn.com/b/davbr/archive/2011/12/29/gc-heap-and-alignment-padding.aspx#comments</comments><description>&lt;p&gt;The docs for &lt;a href="http://msdn.microsoft.com/en-US/library/ms231885(v=VS.100).aspx"&gt;GetObjectSize&lt;/a&gt; have recently been updated with this info, but I wanted to mention it here, too, to ensure you were aware of this information.&lt;/p&gt;  &lt;p&gt;Some profilers manually advance through objects on the heap, inspecting their field values, by starting at an ObjectID and moving forward by its size to the next ObjectID, repeating this process, for all the reported generation ranges (via GetGenerationBounds or MovedReferences/SurvivingReferences).&amp;#160; If your profiler doesn’t do this, then this blog entry will be of no interest to you, and you can skip it.&amp;#160; But if your profiler does do this, you need to be aware of the alignment rules that the CLR employs as it allocates and moves objects around on the GC heap.&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;strong&gt;&lt;u&gt;On x86&lt;/u&gt;&lt;/strong&gt;: All objects are 4-byte aligned, except for objects on the large-object-heap, which are always 8-byte aligned.&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;&lt;u&gt;On x64&lt;/u&gt;&lt;/strong&gt;: All objects are always 8-byte aligned, in all generations.&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;And the important point to note is that GetObjectSize does NOT include alignment padding in the size that it reports.&amp;#160; Thus, as your profiler manually skips from object to object by using GetObjectSize() to determine how far to skip, your profiler must manually add in any alignment padding necessary to achieve the alignment rules listed above.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10251839" width="1" height="1"&gt;</description></item><item><title>When is it safe to use ObjectIDs?</title><link>http://blogs.msdn.com/b/davbr/archive/2011/12/29/when-is-it-safe-to-use-objectids.aspx</link><pubDate>Thu, 29 Dec 2011 19:33:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:10251834</guid><dc:creator>David Broman</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.msdn.com/b/davbr/rsscomments.aspx?WeblogPostID=10251834</wfw:commentRss><comments>http://blogs.msdn.com/b/davbr/archive/2011/12/29/when-is-it-safe-to-use-objectids.aspx#comments</comments><description>&lt;p&gt;As mentioned in &lt;a href="http://blogs.msdn.com/b/davbr/archive/2007/12/18/debugging-your-profiler-ii-sos-and-ids.aspx"&gt;this post&lt;/a&gt;, ObjectIDs are really pointers to managed objects on the GC heap.&amp;nbsp; And as you know, objects get collected or move around on the heap during GCs.&amp;nbsp; So how do you safely work with ObjectIDs?&lt;/p&gt;
&lt;p&gt;The overall guidance is that if you plan to dereference an ObjectID or pass it to an ICorProfilerInfo(2,3,4) method, then you must do so either:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;From inside a GC, from a thread doing the GC (e.g., in response to one of the GC callbacks, in which case you're guaranteed that the GC is blocked by this call), OR&lt;/li&gt;
&lt;li&gt;From a callback that gave you the ObjectID (in which case you're guaranteed that the GC is blocked by the callback that gave you the ObjectID)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Of course, taking an ObjectID that you were given and caching it away somewhere is a big no-no, unless you take pains to update all the ObjectIDs in your cache on every GC, by using the SurvivingReferences/MovedReferences callbacks.&amp;nbsp; And even with a well-updated cache such as this, the CLR will still require that you pass ObjectIDs to Info methods only in the above two circumstances, or else you will receive an error HRESULT.&amp;nbsp; This extra checking was added in .NET 4.0.&lt;/p&gt;
&lt;p&gt;The reason for this is that some code paths in the CLR assume that their thread is already blocking the GC (to ensure referenced objects stay put), but there was no enforcement in place to ensure this.&amp;nbsp; So we added this enforcement in .NET 4.0.&amp;nbsp; Without checks like this, it could be possible to cause nondeterministic GC heap corruptions or to reference the wrong memory.&amp;nbsp; For example, calling GetObjectSize on a thread that you create (i.e., not a manage thread) does not intrinsically block the GC, and thus is considered unsafe.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10251834" width="1" height="1"&gt;</description></item><item><title>Metadata Tokens, Run-Time IDs, and Type Loading</title><link>http://blogs.msdn.com/b/davbr/archive/2011/10/17/metadata-tokens-run-time-ids-and-type-loading.aspx</link><pubDate>Tue, 18 Oct 2011 01:29:42 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:10226713</guid><dc:creator>David Broman</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.msdn.com/b/davbr/rsscomments.aspx?WeblogPostID=10226713</wfw:commentRss><comments>http://blogs.msdn.com/b/davbr/archive/2011/10/17/metadata-tokens-run-time-ids-and-type-loading.aspx#comments</comments><description>&lt;h1&gt;Overview&lt;/h1&gt;  &lt;p&gt;In this post, I write about the two primary kinds of IDs your profiler deals with, when each kind is appropriate to use, how to convert between those two types of IDs, and some gotchas with those conversions—particularly in how they may invoke the type loader.&lt;/p&gt;  &lt;h1&gt;The two kinds of IDs&lt;/h1&gt;  &lt;p&gt;Profilers have to deal with two kinds of IDs.&amp;#160; The first kind are IDs from metadata, a.k.a., &lt;strong&gt;metadata tokens&lt;/strong&gt;.&amp;#160; These are the mdToken values, like mdMethodDef or mdTypeDef, which are read straight out of the metadata of managed modules.&amp;#160; These values do not change for a given module from process to process.&amp;#160; They are placed in the module by the language compiler that generates the IL (e.g., csc.exe).&amp;#160; Profilers typically use metadata tokens in order to look up symbolic information from the metadata (e.g., for pretty-printing names of methods or classes), and for performing IL rewriting.&amp;#160; Metadata tokens are also fantastic for deferring symbolic lookup to a post-processing phase.&amp;#160; For example, a sampling profiler could log metadata tokens for classes and functions encountered on a sample at run-time and defer looking up the names of those classes and functions to a post-processing phase that occurs after the profiled process has exited.&amp;#160; This keeps the profiler’s data collection lightweight, and is only possible because metadata tokens don’t change so long as the managed modules defining those tokens don’t change.&lt;/p&gt;  &lt;p&gt;The second kind of IDs are &lt;strong&gt;run-time IDs&lt;/strong&gt;, such as FunctionID or ClassID which are defined in corprof.idl.&amp;#160; These values do change from process to process, and they represent internal data structures that the CLR builds up at run-time as it loads modules, loads types, JIT compiles functions, etc.&amp;#160; Profilers use these values as its main currency between ICorProfilerInfo* and ICorProfilerCallback* methods.&amp;#160; The CLR uses these values when it notifies profilers of various events (ICorProfilerCallback* methods), and the profiler passes these values back into the CLR (ICorProfilerInfo* methods) in order to get further information about them.&amp;#160; These IDs are handy because they are your profiler’s key to unlocking class layout, generated code, object addresses, and everything else that the CLR maintains about the actively executing managed code at run-time.&amp;#160; See &lt;a href="http://blogs.msdn.com/davbr/archive/2007/12/18/debugging-your-profiler-ii-sos-and-ids.aspx"&gt;this post&lt;/a&gt; for more info about what these IDs really are.&lt;/p&gt;  &lt;h1&gt;Converting between metadata tokens and run-time IDs&lt;/h1&gt;  &lt;p&gt;Since metadata tokens are good for some things and run-time IDs are good for others, you will inevitably find yourself in situations where you have one kind of ID handy, but you really need the other kind of ID.&amp;#160; Can you convert from one kind of ID to another?&amp;#160; Yes, but there are some caveats!&lt;/p&gt;  &lt;p&gt;It’s always safe to go this direction: run-time ID –&amp;gt; metadata token.&amp;#160; Just use methods such as GetFunctionInfo2 and GetClassIDInfo2, which take run-time IDs as input, and provide their module + metadata token as (part of) the output.&lt;/p&gt;  &lt;p&gt;However, it is problematic going the opposite direction: metadata token –&amp;gt; run-time ID.&amp;#160; Why?&amp;#160; Because a given type may not be loaded yet, and thus the run-time ID may not exist.&amp;#160; There exist methods on the ICorProfilerInfo* interfaces that go this direction, namely GetFunctionFromToken(AndTypeArgs) and GetClassFromToken(AndTypeArgs).&amp;#160; However, they are dangerous to use (see below), and should be avoided.&amp;#160; Instead, it’s preferable that your profiler build up its own run-time ID –&amp;gt; metadata token map as it encounters run-time IDs, and then performing reverse lookups in that map as necessary.&amp;#160; For example, as your profiler encounters ClassIDs via callbacks like ClassLoadFinished, it goes the “safe” direction (run-time ID –&amp;gt; metadata token), to build up its map.&amp;#160; When it later encounters an mdTypeDef for a class, it checks to see if that mdTypeDef exists yet in its map—if so, your profiler uses that map to find the corresponding ClassID.&amp;#160; Safe and easy.&lt;/p&gt;  &lt;p&gt;“Dave, stop telling us to do impossible things.&amp;#160; You know full well that profilers which attach to a process after it has started up don’t have the benefit of seeing all the ClassLoad* notifications.&amp;#160; Also, if regular NGEN’d images are used, ClassLoad* notifications are not reliably sent.”&lt;/p&gt;  &lt;p&gt;True.&amp;#160; Though you will come across ClassIDs other ways.&amp;#160; Memory profilers will encounter ObjectIDs on the heap, and can call GetClassFromObject to start filling up its map of ClassIDs and thus mdTypeDefs.&amp;#160; Similarly, sampling profilers encounter FunctionIDs during stack walks, and can then get the ClassIDs containing those FunctionIDs and thus build up its map that way.&lt;/p&gt;  &lt;p&gt;“You’re a dreamer, man.&amp;#160; There will still be cases where I have a metadata token, but have not yet encountered the ClassID.&amp;#160; Think about deep inspection of embedded structs!”&lt;/p&gt;  &lt;p&gt;Yes, that is a good example.&amp;#160; You are an astute reader.&amp;#160; Memory profilers that wish to deeply inspect values of classes and structures on the heap need to know the ClassIDs in order to call GetClassLayout.&amp;#160; This works great when you’re dealing with reference types whose fields point to other reference types: as you bounce from object to object, you can take the ObjectID (i.e., the location in memory where the object starts), pass it to GetClassFromObject, and there’s your ClassID.&amp;#160; But what happens when a struct is embedded inside an object?&amp;#160; Sure, you can get the layout of the object, and determine the offset into the object where the embedded struct lives.&amp;#160; But then what?&amp;#160; How to inspect and report on the values of fields &lt;em&gt;inside the embedded struct&lt;/em&gt;?&amp;#160; At this point, all you can get is the mdTypeDef for the struct (from the metadata of the containing class), but you may never have seen the ClassID for that struct.&lt;/p&gt;  &lt;p&gt;“Told you so.”&lt;/p&gt;  &lt;h1&gt;Going from metadata token to run-time ID&lt;/h1&gt;  &lt;h1&gt;&lt;/h1&gt;  &lt;h1&gt;&lt;/h1&gt;  &lt;p&gt;As I mentioned above, the safest way to do this is to build up your own map and do reverse-lookups as necessary.&amp;#160; If that scheme meets your needs, then by all means do that, and stop reading!&amp;#160; But in the cases where this is insufficient, you may need to resort to using GetFunctionFromToken(AndTypeArgs) and GetClassFromToken(AndTypeArgs).&amp;#160; There is no simple, foolproof way to use these APIs safely, but here is your guideline:&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Never call GetFunctionFromToken(AndTypeArgs) and GetClassFromToken(AndTypeArgs) unless you’re certain the relevant types have been loaded.&lt;/strong&gt;&amp;#160; (“Relevant types” include the ClassID containing the FunctionID whose mdMethodDef you pass to GetFunctionFromToken(AndTypeArgs), and the ClassID whose mdTypeDef you pass to GetClassFromToken(AndTypeArgs).)&amp;#160; If these types have not been loaded, &lt;em&gt;you may cause them to be loaded now&lt;/em&gt;!&amp;#160; This is bad because:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;This is an easy way to crash the app.&amp;#160; Trying to load a type at the wrong time could cause cycles, causing infinite loops (depending on what your profiler does in response to class load notifications) or outright crashes.&amp;#160; For example, trying to load a type while its containing assembly is still in an early phase of loading is a great and fun way to crash the CLR. &lt;/li&gt;    &lt;li&gt;You will impact the behavior of the app.&amp;#160; If you’re lucky enough not to crash the app, you’ve still impacted its behavior, by causing types to get loaded in a different order than they normally would.&amp;#160; Any impact to app behavior like this makes it difficult for your users to reproduce problems that they are trying to use your tool to diagnose, or may hide problems that they don’t discover until they run their application outside of your tool. &lt;/li&gt; &lt;/ul&gt;  &lt;h2&gt;Determining whether a class was loaded&lt;/h2&gt;  &lt;p&gt;So how do you know a class has been fully loaded?&lt;/p&gt;  &lt;p&gt;Unfortunately, receiving the &lt;strong&gt;ClassLoadFinished&lt;/strong&gt; callback does not necessarily mean that ClassID has been fully loaded yet, as the MSDN &lt;a href="http://msdn.microsoft.com/en-us/library/ms230794.aspx"&gt;documentation&lt;/a&gt; warns us.&lt;/p&gt;  &lt;p&gt;Basically, the CLR type loader is one of the laziest things on this planet.&amp;#160; It doesn’t want to do anything unless it really, really has to.&amp;#160; The best guideline I can give you is this:&amp;#160; If the app is currently executing managed code that uses a type, then the type is loaded.&amp;#160; For example, if you do a stackwalk, and determine that the app is executing inside of&lt;/p&gt;  &lt;p&gt;MyRetType MyClass::MyFunction(MyArgumentType myArgumentType)&lt;/p&gt;  &lt;p&gt;then you can be reasonably assured that the following are loaded:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;MyClass &lt;/li&gt;    &lt;li&gt;MyArgumentType (if it’s a value-type) &lt;/li&gt;    &lt;li&gt;MyRetType (if it’s a value-type) &lt;/li&gt;    &lt;li&gt;For any class you know is loaded, so should be:      &lt;ul&gt;       &lt;li&gt;its base class &lt;/li&gt;        &lt;li&gt;its value-type fields (not necessarily reference-type fields!) &lt;/li&gt;        &lt;li&gt;implemented interfaces &lt;/li&gt;        &lt;li&gt;value-type generic type arguments (and even reference-type generic type arguments in the case of MyClass) &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;So much for stacks.&amp;#160; What if you encounter an instance of a class on the heap?&amp;#160; Surely the class is loaded then, right?&amp;#160; Well, probably.&amp;#160; If you encounter an object on heap just after GC (inside &lt;strong&gt;GarbageCollectionFinished&lt;/strong&gt;, before you return), it should be safe to inspect the class’s layout, and then peek through ObjectIDs to see the values of their fields.&lt;/p&gt;  &lt;p&gt;But what if you encounter an object earlier than that?&amp;#160; For example, if you receive an &lt;strong&gt;ObjectAllocated&lt;/strong&gt; callback, and call &lt;strong&gt;GetClassFromObject&lt;/strong&gt; on the allocated ObjectID, can you be certain the ClassID has been fully loaded?&amp;#160; Well, usually.&amp;#160; But I have seen cases in the past, with types stored in NGENd images, where the CLR may issue an ObjectAllocated callback &lt;em&gt;just before&lt;/em&gt; the type has been fully loaded from the NGENd image.&amp;#160; I’ve recently tried to get this to happen again but couldn’t, which probably means this is rather unlikely, but not necessarily impossible.&amp;#160; Ugh.&lt;/p&gt;  &lt;p&gt;In general, a lot of the uncertainty above comes from types stored in NGENd modules.&amp;#160; If we actually JIT-compile a function at run-time and load the types it uses from non-NGENd modules, then you can have much greater certainty about the above types being loaded.&amp;#160; You can even make further assumptions about locals and types from signatures of direct callees being loaded. &lt;/p&gt;  &lt;h2&gt;Interlude: Remember the Unloads!&lt;/h2&gt;  &lt;p&gt;Now is a good time remind you that, not only is it dangerous to inspect run-time IDs too early (i.e., before they load); it’s also dangerous to inspect run-time IDs too late (i.e., after they &lt;strong&gt;unload&lt;/strong&gt;).&amp;#160; For example, if you store ClassIDs and FunctionIDs for later use, and use them “too late”, you can easily crash the CLR.&amp;#160; The profiling API does pretty much no validation of anything (in many cases, it’s incapable of doing so without using up significant amounts of memory to maintain lookup tables for everything).&amp;#160; So we generally take any run-time ID that you pass to ICorProfilerInfo* methods, cast it to an internal CLR structure ptr, and go boom if the ID is bad.&lt;/p&gt;  &lt;p&gt;There is no way to just ask the CLR if a FunctionID or ClassID is valid.&amp;#160; Indeed, classes could get unloaded, and new classes loaded, and your ClassID may now refer to a totally different (valid) class.&amp;#160; &lt;/p&gt;  &lt;p&gt;You need to keep track of the unloads yourself.&amp;#160; You are notified when run-time IDs go out of scope (today, this happens at the level of an AppDomain unloading or a collectible assembly unloading—in both cases all IDs “contained” in the unloading thing are now invalid).&amp;#160; Once a run-time ID is out of scope, you are not allowed to pass that run-time ID back to the CLR.&amp;#160; In fact, you should consider whether thread synchronization will be necessary in your profiler to maintain this invariant.&amp;#160; For example, if a run-time ID gets unloaded on thread A, you’re still not allowed to pass that run-time ID back to the CLR on thread B.&amp;#160; So you may need to block on a critical section in thread A during the *UnloadStarted / AppDomainShutdown* callbacks, to prevent them from returning to the CLR until any uses of the contained IDs in thread B are finished.&lt;/p&gt;  &lt;p&gt;Take a look at the &lt;a href="http://msdn.microsoft.com/en-us/library/bb384619.aspx"&gt;docs&lt;/a&gt; is for more info.&lt;/p&gt;  &lt;h1&gt;TypeRefs&lt;/h1&gt;  &lt;p&gt;So far I’ve been talking about how to go from a typeDef to its run-time ID, and by now that should seem hard enough that we don’t need to throw a monkey wrench into the works.&amp;#160; But the sad fact is we’re rarely lucky enough even to have a typeDef.&amp;#160; A class’s fields or even base type, might have their types defined in &lt;em&gt;other modules&lt;/em&gt;, in which case the metadata tells us the fields or base type might actually be typeRefs, and not typeDefs.&amp;#160; Ugh.&amp;#160; Whaddya do with that?!&lt;/p&gt;  &lt;p&gt;I’ll tell you what you &lt;em&gt;don’t&lt;/em&gt; do.&amp;#160; You don’t call the enticingly-named IMetaDataImport::ResolveTypeRef.&amp;#160; On the surface, it seems like ResolveTypeRef would do exactly what you want: starting from a typeRef, please find the referenced module and return an IMetaDataImport on that module, along with the typeDef in that target module to which the typeRef refers.&amp;#160; But the problem lies with how ResolveTypeRef determines the module to which a typeRef refers.&lt;/p&gt;  &lt;p&gt;I think ResolveTypeRef was originally designed for use at build-time (by language compilers), though I don’t know if it’s even used in that scenario anymore.&amp;#160; It is certainly not good for use at run-time, where the loader’s decision on how to locate a referenced assembly can be arbitrarily complex.&amp;#160; Different AppDomains in the same process may have different rules on how to locate the referenced assembly due to varying permission sets, host settings, or assembly versions.&amp;#160; In the limit, the CLR may even &lt;em&gt;call into the user’s managed code&lt;/em&gt; to dynamically influence the decision of where the referenced assembly exists (see &lt;a href="http://msdn.microsoft.com/en-us/library/system.appdomain.assemblyresolve.aspx"&gt;AppDomain.AssemblyResolve Event&lt;/a&gt;).&lt;/p&gt;  &lt;p&gt;ResolveTypeRef doesn’t know about any of this—it was never designed to be used in a running application with all these environmental factors.&amp;#160; It has an extremely simple (and inaccurate) algorithm to iterate through a set of “known modules”, in an arbitrary order, looking for the first one that matches the reference.&amp;#160; What does “known modules” mean?&amp;#160; It’s a set of modules that have been opened into the metadata system, which is NOT the same as the list of modules already loaded by the assembly loader (and thus notified to your profiler).&amp;#160; And it’s certainly not the same as the set of modules installed onto the disk.&lt;/p&gt;  &lt;p&gt;If you absolutely need to resolve refs to defs, your best bet may be to use your own algorithm which will be as accurate as you can make it, under the circumstances, and which will never try to locate a module that hasn’t been loaded yet.&amp;#160; That means that you shouldn’t try to resolve a ref to a def if that def hasn’t actually been loaded into a type by the CLR.&amp;#160; Consider using an algorithm similar to the following:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Get the AssemblyRef from the TypeRef to get to the name, public key token and version of the assembly where the type should reside. &lt;/li&gt;    &lt;li&gt;Enumerate all loaded modules that the Profiling API has notified you of (or via &lt;a href="http://msdn.microsoft.com/en-us/library/dd490890"&gt;EnumModules&lt;/a&gt;) (you can filter out a specific AppDomain at this point if you want). &lt;/li&gt;    &lt;li&gt;In each enumerated module, search for a TypeDef with the same name and namespace as the TypeRef (IMetaDataImport::FindTypeDefByName) &lt;/li&gt;    &lt;li&gt;Pay attention to &lt;strong&gt;type forwarding&lt;/strong&gt;!&amp;#160; Once you find the TypeDef, it may actually be an “exported” type, in which case you will need to follow the trail to the next module.&amp;#160; Read toward the bottom of &lt;a title="http://blogs.msdn.com/b/davbr/archive/2009/09/30/type-forwarding.aspx" href="http://blogs.msdn.com/b/davbr/archive/2009/09/30/type-forwarding.aspx"&gt;http://blogs.msdn.com/b/davbr/archive/2009/09/30/type-forwarding.aspx&lt;/a&gt; for more info. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;The above can be a little bit smarter by paying attention to what order you choose to search through the modules:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;First search for the TypeDef in assemblies which exactly match the name, public key token and version for the AssemblyRef. &lt;/li&gt;    &lt;li&gt;If that fails, then search through assemblies matching name and public key token (where the version is higher than the one supplied – this can happen for Framework assemblies). &lt;/li&gt;    &lt;li&gt;If that fails, then search through all the other assemblies &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;I must warn you that the above scheme is &lt;strong&gt;not tested and not supported.&amp;#160; Use at your own risk!&lt;/strong&gt;&lt;/p&gt;  &lt;h1&gt;Future&lt;/h1&gt;  &lt;p&gt;Although I cannot comment on what will or will not be in any particular future version of the CLR, I can tell you that it is clear to us on the CLR team that we have work to do, to make dealing with metadata tokens and their corresponding run-time type information easier from the profiling API.&amp;#160; After all, it doesn’t take a rocket scientist to read the above and conclude that it does take a rocket scientist to actually follow all this advice.&amp;#160; So for now, enjoy the fact that what you do is really hard, making you difficult to replace, and thus your job all the more secure.&amp;#160; You’re welcome.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Special thanks to David Wrighton and Karel Zikmund, who have helped considerably with all content in this entry around the type system and metadata.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10226713" width="1" height="1"&gt;</description></item><item><title>ReJIT: A How-To Guide</title><link>http://blogs.msdn.com/b/davbr/archive/2011/10/12/rejit-a-how-to-guide.aspx</link><pubDate>Thu, 13 Oct 2011 01:38:38 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:10224320</guid><dc:creator>David Broman</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.msdn.com/b/davbr/rsscomments.aspx?WeblogPostID=10224320</wfw:commentRss><comments>http://blogs.msdn.com/b/davbr/archive/2011/10/12/rejit-a-how-to-guide.aspx#comments</comments><description>&lt;p&gt;By now, you’ve surely downloaded your copy of the .NET 4.5 Developer Preview, and you’ve opened up the brand-spanking new corprof.idl, and searched that file for all the new APIs available in 4.5.&amp;#160; There’s a bunch with “ReJIT” in the name, and all you need to know is how and when to call what.&lt;/p&gt;  &lt;p&gt;If none of the above makes any sense to you, you’ve probably stumbled onto the wrong blog.&amp;#160; Indeed, both “rejit” and “ejit” have other definitions (some rather unfriendly) that are completely unrelated to the CLR.&amp;#160; I’m talking about that ReJIT thing you do when you want to instrument and then JIT-compile code that has already been JIT-compiled before.&lt;/p&gt;  &lt;p&gt;This post is organized in chronological order, telling what your profiler should be doing at the following times in the process:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Startup Time &lt;/li&gt;    &lt;li&gt;ModuleLoadFinished Time &lt;/li&gt;    &lt;li&gt;RequestReJIT Time &lt;/li&gt;    &lt;li&gt;Actual ReJIT Time &lt;/li&gt;    &lt;li&gt;RequestRevert Time &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h2&gt;Startup Time&lt;/h2&gt;  &lt;p&gt;The first thing your profiler will do is get itself loaded on startup of a managed application—the old environment variable way, not the new attach way.&amp;#160; I’m sure you’ve already read up on the &lt;a href="http://blogs.msdn.com/b/davbr/archive/2011/10/10/rejit-limitations-in-net-4-5.aspx"&gt;limitations&lt;/a&gt;!&lt;/p&gt;  &lt;p&gt;Inside your profiler’s Initialize() method, it will of course call SetEventMask().&amp;#160; In that call, your profiler must include (&lt;strong&gt;COR_PRF_ENABLE_REJIT | COR_PRF_DISABLE_ALL_NGEN_IMAGES&lt;/strong&gt;) in the bitmask.&amp;#160; COR_PRF_ENABLE_REJIT is required to use any of the ReJIT APIs later on (they’ll fail immediately otherwise).&amp;#160; COR_PRF_DISABLE_ALL_NGEN_IMAGES causes the CLR’s assembly loader to ignore all NGENd images (even NGEN /Profile images), and thus all code will be JITted from scratch, and all classes loaded from scratch.&amp;#160; If you try to be tricky and specify only COR_PRF_ENABLE_REJIT (without COR_PRF_DISABLE_ALL_NGEN_IMAGES), then SetEventMask will fail.&amp;#160; Conversely, though, you’re perfectly welcome to specify COR_PRF_DISABLE_ALL_NGEN_IMAGES without COR_PRF_ENABLE_REJIT if you want.&lt;/p&gt;  &lt;p&gt;At this time you will likely want to set other flags that control optimizations, particularly &lt;strong&gt;inlining&lt;/strong&gt; (COR_PRF_DISABLE_OPTIMIZATIONS, COR_PRF_DISABLE_INLINING), or at least subscribe to the inlining callbacks (COR_PRF_MONITOR_JIT_COMPILATION).&lt;/p&gt;  &lt;p&gt;Typically, your profiler will also create a new thread at this point, call it your “&lt;strong&gt;ReJIT Thread&lt;/strong&gt;”.&amp;#160; The expected use-case of ReJIT is to perform instrumentation “on demand”, triggered by some user action (like fiddling with dials in your profiler’s out-of-process GUI).&amp;#160; As such, you’ll need an unmanaged thread of your own creation to receive and act on these requests from out-of-process.&amp;#160; Perhaps you already have such a thread to service other kinds of requests.&amp;#160; It’s perfectly acceptable for such a thread to now also act as your ReJIT Thread.&lt;/p&gt;  &lt;h2&gt;ModuleLoadFinished Time&lt;/h2&gt;  &lt;h3&gt;&lt;/h3&gt;  &lt;h3&gt;&lt;/h3&gt;  &lt;h3&gt;&amp;#160;&lt;/h3&gt;  &lt;h3&gt;Metadata Changes&lt;/h3&gt;  &lt;p&gt;As each module loads, you will likely need to add metadata so that your future ReJITs will have the tokens they need.&amp;#160; What you do here heavily depends on the kind of instrumentation you want to do.&amp;#160; I’m assuming you’re doing instrumentation that adds some calls from the user code into brand new profiler helper methods you will add somewhere.&amp;#160; If you plan to instrument mscorlib, you will likely want to add those profiler helper methods into mscorlib (remember, mscorlib is not allowed to contain an AssemblyRef that points to any other assembly!).&amp;#160; Otherwise, perhaps you plan to ship a managed helper assembly that will sit on your user’s disk, and all your profiler helper methods will reside in this on-disk managed helper assembly.&lt;/p&gt;  &lt;p&gt;So…&lt;/p&gt;  &lt;p&gt;IF the module loading is mscorlib AND you plan to &lt;strong&gt;add your profiler helper methods&lt;/strong&gt; into mscorlib, THEN use the metadata APIs now to add those methods.&lt;/p&gt;  &lt;p&gt;IF the module loading contains methods that you might possibly ever want to instrument, THEN use the metadata APIs to &lt;strong&gt;add any AssemblyRefs, TypeRefs, MemberRefs, etc.&lt;/strong&gt;, which point to your profiler helper methods, that you might possibly need later when you potentially instrument methods from this loading module.&amp;#160; The guiding principle here is that metadata changes may be done at ModuleLoadFinished time, and not later.&amp;#160; So you need to assume you might possibly want to ReJIT methods in the loading module &lt;em&gt;eventually&lt;/em&gt;, and proactively add to the loading module whatever metadata you will eventually need (should you actually perform the ReJIT later), and add that metadata &lt;em&gt;now&lt;/em&gt;, just in case.&lt;/p&gt;  &lt;h3&gt;Re-Request Prior ReJITs&lt;/h3&gt;  &lt;p&gt;This won’t make much sense until you’ve read the next section, but I’m placing it here to keep it in chronological order.&amp;#160; If you’ve made a prior call to RequestReJIT for an unshared (non-domain-neutral) ModuleID, AND if you want that request to apply to the mdMethodDef that appears in all other unshared copies of the module, AND if you’re inside ModuleLoadFinished for the load of a new ModuleID that is just such a new unshared copy of the module, THEN you’ll want to explicitly call RequestReJIT on this newly-loaded ModuleID with that mdMethodDef.&amp;#160; Note that this is optional—if you want to treat AppDomains differently and want, say, only one unshared copy of the function to be ReJITted, then you’re perfectly welcome to cause that behavior and not to call RequestReJIT on any new ModuleIDs relating to the module.&amp;#160; Come back and re-read those last two sentences after you’ve read the next section.&lt;/p&gt;  &lt;h2&gt;RequestReJIT Time&lt;/h2&gt;  &lt;p&gt;Now imagine your user has turned some dial on your out-of-process GUI, to request that some functions get instrumented (or re-instrumented (or re-re-instrumented (or …))).&amp;#160; This results in a signal sent to your in-process profiler component.&amp;#160; Your ReJIT Thread now knows it must call &lt;strong&gt;RequestReJIT&lt;/strong&gt;.&amp;#160; You can call this API once in bulk for a list of functions to ReJIT.&amp;#160; Note that functions are expressed in terms of ModuleID + mdMethodDef metadata tokens.&amp;#160; A few things to note about this:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;You request that all instantiations of a generic function (or function on a generic class) get ReJITted with a single ModuleID + mdMethodDef pair.&amp;#160; You cannot request a specific instantiation be ReJITted, or provide instantiation-specific IL.&amp;#160; This is nothing new, as classic first-JIT-instrumentation should never be customized per instantiation either.&amp;#160; But the ReJIT API is designed with this restriction in mind, as you’ll see later on. &lt;/li&gt;    &lt;li&gt;ModuleID is specific to one AppDomain for unshared modules, or the SharedDomain for shared modules.&amp;#160; Thus:      &lt;ul&gt;       &lt;li&gt;If ModuleID is shared, then your request will simultaneously apply to all domains using the shared copy of this module (and thus function) &lt;/li&gt;        &lt;li&gt;If ModuleID is unshared, then your request will apply only to the single AppDomain using this module (and function) &lt;/li&gt;        &lt;li&gt;Therefore, if you want this ReJIT request to apply to &lt;em&gt;all unshared copies&lt;/em&gt; of this function:           &lt;ul&gt;           &lt;li&gt;You’ll need to include all such ModuleIDs in this request. &lt;/li&gt;            &lt;li&gt;And… any &lt;em&gt;future&lt;/em&gt; unshared loads of this module will result in new ModuleIDs.&amp;#160; So as those loads happen, you’ll need to make further calls to RequestReJIT with the new ModuleIDs to ensure those copies get ReJITted as well. &lt;/li&gt;            &lt;li&gt;This is optional, and only need be done if you truly want this ReJIT request to apply to all unshared copies of the function.&amp;#160; You’re perfectly welcome to ReJIT only those unshared copies you want (and / or the shared copy). &lt;/li&gt;            &lt;li&gt;Now you can re-read the “Re-Request Prior ReJITs” section above.&amp;#160; :-) &lt;/li&gt;         &lt;/ul&gt;       &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt; &lt;/ul&gt;  &lt;h2&gt;&lt;/h2&gt;  &lt;h3&gt;&amp;#160;&lt;/h3&gt;  &lt;h3&gt;More on AppDomains&lt;/h3&gt;  &lt;p&gt;This whole shared / multiple unshared business can get confusing.&amp;#160; So to bring it home, consider your user.&amp;#160; If your user expresses instrumentation intent at the level of a class/method name, then you pretty much want to ReJIT every copy of that function (all unshared copies plus the shared copy).&amp;#160; But if your user expresses instrumentation intent at the level of a class/method name &lt;em&gt;plus AppDomain &lt;/em&gt;(think one single AppPool inside ASP.NET), then you’d only want to ReJIT the copy of the function that resides in the single ModuleID associated with that AppDomain.&lt;/p&gt;  &lt;p&gt;The SharedDomain can make that last alternative tricky, though.&amp;#160; Because if the ModuleID ends up belonging to the SharedDomain, and you ReJIT a method in that ModuleID, then all AppDomains that share that module will see your instrumentation (whether you want them to or not).&amp;#160; This is due to the very nature of SharedDomain / domain-neutrality.&amp;#160; There’s only one shared copy of this function to instrument, so if two domains share the function, they both see it, either with or without instrumentation.&amp;#160; It doesn’t make sense to instrument the function from the point of view of only one of those two domains.&lt;/p&gt;  &lt;h3&gt;Pre-ReJIT&lt;/h3&gt;  &lt;p&gt;Obviously, the main coolness of RequestReJIT is that you can call it with a function that has already been JITted.&amp;#160; But one of the niceties of RequestReJIT is that you don’t actually have to wait until a function is first JITted to use it.&amp;#160; You can request a ReJIT on a function that has never been JITted before (I call this “Pre-ReJIT”).&amp;#160; Indeed, with generics, there’s no way to know if all the instantiations that will ever be used in an AppDomain have been JITted or not.&amp;#160; There may always be some important instantiation that has not been JITted yet.&amp;#160; RequestReJIT takes all this into account as follows:&lt;/p&gt;  &lt;p&gt;If a function (or generic instantiation) has already been JITted, it is marked for ReJIT next time it is called.&lt;/p&gt;  &lt;p&gt;If a function (or generic instantiation) has not yet been JITted, then it is marked internally for “Pre-ReJIT”.&amp;#160; This means that once it is called, its original (non-instrumented) IL gets JIT-compiled as usual.&amp;#160; Immediately after, it is then ReJITted.&amp;#160; In this way, a Pre-ReJIT request works exactly like a ReJIT request.&amp;#160; Original IL is compiled first, and then instrumented IL is compiled later.&amp;#160; This ensures we can easily “revert” back to the original code at a later time using the same revert mechanism.&amp;#160; (See below.)&lt;/p&gt;  &lt;h2&gt;Actual ReJIT Time&lt;/h2&gt;  &lt;p&gt;You may have noticed that you have read a whole lot of words so far, but we haven’t yet provided the instrumented IL to the CLR.&amp;#160; This is because the function hasn’t ReJITted yet.&amp;#160; You’ve only &lt;em&gt;requested &lt;/em&gt;that it be ReJITted.&amp;#160; But the actual ReJITting happens the next time the function is called.&amp;#160;&amp;#160; Until then, any threads already executing inside functions you requested to be ReJITted &lt;em&gt;stay&lt;/em&gt; in those functions, and don’t see the instrumented code until they return and call the functions again.&amp;#160; Once a function is finally called for the first time after its RequestReJIT, you get some callbacks.&lt;/p&gt;  &lt;p&gt;IF this is the first generic instantiation to ReJIT, for a given RequestReJIT call (or this is not a generic at all), THEN:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;CLR calls &lt;strong&gt;GetReJITParameters&lt;/strong&gt;       &lt;ul&gt;       &lt;li&gt;This callback passes an ICorProfilerFunctionControl to your profiler.&amp;#160; Inside your implementation of GetReJITParameters (and no later!) you may call into ICorProfilerFunctionControl to provide the instrumented IL and codegen flags that the CLR should use during the ReJIT &lt;/li&gt;        &lt;li&gt;Therefore it is here where you may:          &lt;ul&gt;           &lt;li&gt;Call GetILFunctionBody &lt;/li&gt;            &lt;li&gt;Add any new LocalVarSigTokens to the function’s module’s metadata.&amp;#160; (You may not do any other metadata modifications here, though!) &lt;/li&gt;            &lt;li&gt;Rewrite the IL to your specifications, passing it to ICorProfilerFunctionControl::SetILFunctionBody. &lt;/li&gt;         &lt;/ul&gt;       &lt;/li&gt;        &lt;li&gt;You may NOT call ICorProfilerInfo::SetILFunctionBody for a ReJIT!&amp;#160; This API still exists if you want to do classic first-JIT IL rewriting only. &lt;/li&gt;        &lt;li&gt;Note that GetReJITParameters expresses the function getting compiled in terms of the ModuleID + mdMethodDef pair you previously specified to RequestReJIT, and &lt;em&gt;not &lt;/em&gt;in terms of a FunctionID.&amp;#160; As mentioned before, you may not provide instantiation-specific IL! &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;And then, for all ReJITs (regardless of whether they are for the first generic instantiation or not):&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;CLR calls &lt;strong&gt;ReJITCompilationStarted&lt;/strong&gt; &lt;/li&gt;    &lt;li&gt;CLR calls &lt;strong&gt;ReJITCompilationFinished&lt;/strong&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;These callbacks express the function getting compiled in terms of FunctionID + ReJITID.&amp;#160; (ReJITID is simply a disambiguating value so that each ReJITted version of a function instantiation can be uniquely identified via FunctionID + ReJITID.)&amp;#160; Your profiler doesn’t need to do anything in the above callbacks if it doesn’t want to.&amp;#160; They just notify you that the ReJIT is occurring, and get called for each generic instantiation (or non-generic) that gets ReJITted.&lt;/p&gt;  &lt;p&gt;And of course, for any calls to these functions after they have been ReJITted, there are no further ReJIT compilations or callbacks to your profiler.&amp;#160; This ReJITted version is now the current and only version for all new calls to the function.&lt;/p&gt;  &lt;h3&gt;Versions&lt;/h3&gt;  &lt;p&gt;Your profiler is welcome to call RequestReJIT again on these functions, and the cycle starts again.&amp;#160; The next time a call comes in, they’ll get ReJITted again, and you’ll provide instrumented IL at that time, as usual.&amp;#160; At any given time, only the most recently ReJITted version of a function is active and in use for new calls.&amp;#160; But any prior calls still inside previously ReJITted (or original) versions of the function stay in that version until they return.&lt;/p&gt;  &lt;h2&gt;RequestRevert Time&lt;/h2&gt;  &lt;p&gt;Eventually your user may turn the dial back down, and request that the original, un-instrumented, version of the function be reinstated.&amp;#160; When this happens, your profiler receives this signal from out-of-proc using your nifty cross-proc communication channel, and your ReJIT Thread calls &lt;strong&gt;RequestRevert&lt;/strong&gt;.&lt;/p&gt;  &lt;p&gt;At this time, the CLR sets the original version of the function that it JITted the first time as being the &lt;em&gt;current&lt;/em&gt; version for all future calls.&amp;#160; Any prior calls still executing in various ReJITted versions of the function remain where they’re at until they return.&amp;#160; All new calls go into the version originally JITted (from the original IL).&lt;/p&gt;  &lt;p&gt;Note that RequestRevert allows you to revert back to the original JITted IL, and not back to some previous ReJITted version of the IL.&amp;#160; If you want to revert back to a previous ReJITted version of the IL, you’ll need to do so manually, by using RequestReJIT instead, and providing that IL explicitly to the CLR.&lt;/p&gt;  &lt;h2&gt;Errors&lt;/h2&gt;  &lt;p&gt;If there are any errors with performing the ReJIT, you will be notified by the dedicated callback ICorProfilerCallback4::ReJITError().&amp;#160; Errors can happen at a couple times:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;u&gt;RequestReJIT Time&lt;/u&gt;: These are fundamental errors with the request itself.&amp;#160; This can include bad parameter values, requesting to ReJIT dynamic (Ref.Emit) code, out of memory, etc.&amp;#160; If errors occur here, you’ll get a callback to your implementation of ReJITError(), sandwiched inside your call to RequestReJIT on your ReJIT Thread. &lt;/li&gt;    &lt;li&gt;&lt;u&gt;Actual ReJIT Time&lt;/u&gt;: These are errors we don’t encounter until actually trying to ReJIT the function itself.&amp;#160; When these later errors occur, your implementation of ReJITError() is called on whatever CLR thread encountered the error. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;You’ll note that ReJITError can provide you not only the ModuleID + mdMethodDef pair that caused the error, but optionally a FunctionID as well.&amp;#160; Depending on the nature of the error occurred, the FunctionID may be available, so that your profiler may know the exact generic instantiation involved with the error.&amp;#160; If FunctionID is null, then the error was fundamental to the generic function itself (and thus occurred for all instantiations).&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Ok, that about covers it on how your profiler is expected to use ReJIT.&amp;#160; As you can see, there are several different tasks your profiler needs to do at different times to get everything right.&amp;#160; But I trust you, you’re smart.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10224320" width="1" height="1"&gt;</description></item><item><title>ReJIT Limitations in .NET 4.5</title><link>http://blogs.msdn.com/b/davbr/archive/2011/10/10/rejit-limitations-in-net-4-5.aspx</link><pubDate>Mon, 10 Oct 2011 23:59:02 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:10223010</guid><dc:creator>David Broman</dc:creator><slash:comments>2</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.msdn.com/b/davbr/rsscomments.aspx?WeblogPostID=10223010</wfw:commentRss><comments>http://blogs.msdn.com/b/davbr/archive/2011/10/10/rejit-limitations-in-net-4-5.aspx#comments</comments><description>&lt;p&gt;Anyone who’s read a newspaper in the past few weeks knows that the Profiling API in .NET 4.5 will supported a limited form of ReJIT.&amp;#160; Well, the news might not be that hot, but that’s what I tell myself.&amp;#160; I will be discussing the feature in depth in upcoming posts, but I thought my first post should be about what ReJIT will &lt;em&gt;not&lt;/em&gt; be in 4.5.&amp;#160; Many folks who have asked for this feature have a pre-set list of sub-features in mind that &lt;em&gt;of course &lt;/em&gt;will be supported by ReJIT, they think.&amp;#160; But many of those obvious sub-features will not be available in .NET 4.5.&amp;#160; That’s what this post is about.&lt;/p&gt;  &lt;h2&gt;Is ReJIT For You?&lt;/h2&gt;  &lt;p&gt;If you’re writing a monitoring tool, typically run in production, and…&lt;/p&gt;  &lt;p&gt;If your tool is always on, always monitoring, but needs a way to fine-tune the amount of instrumentation it does without forcing the monitored application to restart, and…&lt;/p&gt;  &lt;p&gt;If your tool instruments potentially everything, including framework assemblies like mscorlib, and you therefore disable the use of NGENd images and are willing to put up with longer startup times as a result, then…&lt;/p&gt;  &lt;p&gt;ReJIT may be for you.&lt;/p&gt;  &lt;p&gt;The ReJIT we plan to release in .NET 4.5 was designed with this scenario in mind.&amp;#160; As such, there are many potential sub-features of ReJIT that will not be available, because they are not essential for this scenario.&lt;/p&gt;  &lt;h2&gt;List those Limitations!&lt;/h2&gt;  &lt;p&gt;&lt;u&gt;ReJIT + Attach? No!&lt;/u&gt;&lt;/p&gt;  &lt;p&gt;In order to enable ReJIT, your profiler must load at startup, and set an immutable flag in your Initialize method that enables the ReJIT functionality.&lt;/p&gt;  &lt;p&gt;&lt;u&gt;ReJIT + &lt;/u&gt;&lt;u&gt;NGEN? No!&lt;/u&gt;&lt;/p&gt;  &lt;p&gt;In order to set that ReJIT flag I just mentioned, you must also set a new flag which completely disables the use of NGENd images.&amp;#160; Kind of similar to the existing COR_PRF_USE_PROFILE_IMAGES flag, except even NGEN /Profile images (should they exist) will be ignored, and everything will be JITted, when you set this new flag.&amp;#160; This includes all framework assemblies like mscorlib.&lt;/p&gt;  &lt;p&gt;&lt;u&gt;Metadata changes in ModuleLoadFinished only&lt;/u&gt;&lt;/p&gt;  &lt;p&gt;If you add any new methods, AssemblyRefs, MemberRefs, etc., your metadata changes must be done during the module’s ModuleLoadFinished callback.&amp;#160; This is not a new limitation, but it could be a surprise to some that it’s still a limitation even with ReJIT.&amp;#160; There is an exception to this.&amp;#160; If you need to create a new LocalVarSigToken, you may do this “late”, at ReJIT time, rather than early at ModuleLoadFinished time.&lt;/p&gt;  &lt;p&gt;&lt;u&gt;Memory reclaimed at AppDomain unload, &lt;em&gt;not&lt;/em&gt; revert&lt;/u&gt;&lt;/p&gt;  &lt;p&gt;ReJIT will include the ability to “revert” back to the original IL from the assembly.&amp;#160; Doing so, however, will not reclaim any memory that was allocated to support the ReJIT (e.g., the instrumented IL, the JITted code, internal bookkeeping, etc.)&amp;#160; This memory will be reclaimed when the containing AppDomain is unloaded.&amp;#160; And if the code is owned by the shared domain, then, well, that memory is never reclaimed.&lt;/p&gt;  &lt;p&gt;&lt;u&gt;ReJIT inlined functions?&amp;#160; No!&lt;/u&gt;&lt;/p&gt;  &lt;p&gt;If function A inlines function B, then you cannot ReJIT function B.&amp;#160; Well, technically you can, you just won’t see the effect of that anytime A (or another inlining caller of B) is called.&amp;#160; The reason is that, even if you create your new, instrumented B’, A still inlined the original B.&amp;#160; So every time A is called, the code from the original B will be executed, and your B’ will be ignored.&lt;/p&gt;  &lt;p&gt;Since your profiler must be loaded at startup, you can work around this by either turning off inlining altogether, or by monitoring it (via the JITInlining callback), so you know which callers to ReJIT.&amp;#160; In the example above, you’d have to rejit A, and could then request that the rejitted A not inline anyone, so that your new B’ would get called.&amp;#160; Note that you’d have to track the inliners recursively, as there can be arbitrarily many levels of inlining.&lt;/p&gt;  &lt;p&gt;&lt;u&gt;ReJIT + managed debugging? No!&lt;/u&gt;&lt;/p&gt;  &lt;p&gt;While not technically disabled, it is not advised or supported to run a managed debugger against a process that also has a ReJITting profiler enabled.&amp;#160; (Native-only debugging is just fine, though.)&lt;/p&gt;  &lt;p&gt;Whatever debugging support there is, is only there for you, the profiler writer, and &lt;em&gt;not &lt;/em&gt;for your profiler’s users.&amp;#160; For example, there is no way for the ReJITting profiler to adjust the instrumented IL map for rejitted code (i.e., no equivalent of SetILInstrumentedCodeMap for ReJIT).&amp;#160; And attempting to step into or set breakpoints in rejitted code will have unpredictable results.&lt;/p&gt;  &lt;p&gt;However, as a profiler writer attempting to debug your own profiler, you should have a good experience debugging other parts of the process.&amp;#160; For example, if rejitted user code calls into an on-disk profiler IL assembly, you could set breakpoints in your profiler’s IL assembly, and step through that code.&lt;/p&gt;  &lt;p&gt;&lt;u&gt;ReJIT dynamic code?&amp;#160; No!&lt;/u&gt;&lt;/p&gt;  &lt;p&gt;Not a new limitation, but just to be explicit, profilers are not allowed to instrument dynamic code generated via the Reflection.Emit namespace, and that includes ReJIT.&lt;/p&gt;  &lt;h2&gt;Why so strict?&lt;/h2&gt;  &lt;p&gt;ReJIT, as originally conceived by the CLR team, involved allowing profilers to attach to running processes and then instrument arbitrary code at any time.&amp;#160; Just that one sentence would eliminate almost all the restrictions mentioned above.&amp;#160; So what happened?&lt;/p&gt;  &lt;p&gt;Reality, that’s what.&lt;/p&gt;  &lt;p&gt;Stuff takes time.&amp;#160; And in this case a &lt;em&gt;lot&lt;/em&gt; of time.&amp;#160; Lifting just about any of the above restrictions may well have increased development or testing time, or general risk, to the point where the entire ReJIT feature might have been jeopardized.&amp;#160; So although it was a painful process, we had to think hard about every sub-feature we wanted to support that had non-trivial cost to implement.&amp;#160; And at the same time, we had to think about actual, real-world, end-to-end scenarios that would be using ReJIT to ensure that we ended up with something that would be useful, if not perfect.&lt;/p&gt;  &lt;p&gt;So we picked the real-world use-case of production monitoring tools that use instrumentation to gather data from various servers in a data center.&amp;#160; “Attach” isn’t interesting to many of these tools (which run all the time), but they do want to dynamically change the level of instrumentation to help diagnose problems as they come up, without having to restart the process.&amp;#160; This scenario fit very nicely with the time we had, and so that’s what we shot for.&lt;/p&gt;  &lt;p&gt;I can’t comment on what we will or will not do in any releases of the CLR after 4.5, but I like to think that ReJIT in .NET 4.5 might simply be a first step toward a richer instrumentation feature set, such that some of these limitations may eventually get lifted.&amp;#160; We won’t know if that’s true until the time comes, though.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10223010" width="1" height="1"&gt;</description></item><item><title>ReJIT for Realz?!</title><link>http://blogs.msdn.com/b/davbr/archive/2011/09/26/rejit-for-realz.aspx</link><pubDate>Mon, 26 Sep 2011 17:01:24 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:10216747</guid><dc:creator>David Broman</dc:creator><slash:comments>1</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.msdn.com/b/davbr/rsscomments.aspx?WeblogPostID=10216747</wfw:commentRss><comments>http://blogs.msdn.com/b/davbr/archive/2011/09/26/rejit-for-realz.aspx#comments</comments><description>&lt;p&gt;Yes!&amp;#160; Check out this new video on channel 9 for the scoop:&lt;/p&gt;  &lt;p&gt;&lt;a title="http://channel9.msdn.com/Shows/Going+Deep/CLR-45-David-Broman-Inside-Re-JIT" href="http://channel9.msdn.com/Shows/Going+Deep/CLR-45-David-Broman-Inside-Re-JIT"&gt;http://channel9.msdn.com/Shows/Going+Deep/CLR-45-David-Broman-Inside-Re-JIT&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;In the upcoming .NET 4.5, we do indeed plan to include a limited form of ReJIT that will allow diagnostic tools to perform IL Rewriting after the code has been JITted—by instructing the CLR, via the Profiling API, to JIT the (now instrumented) method again (i.e., &lt;strong&gt;ReJIT it!&lt;/strong&gt;).&lt;/p&gt;  &lt;p&gt;If you want to play with this feature, it is available in the .NET 4.5 Developer Preview.&amp;#160; You can search for it on the Microsoft Download Center, and you’ll find the .NET 4.5-only link and the full Visual Studio 11 link:&lt;/p&gt;  &lt;p&gt;&lt;a title="http://www.microsoft.com/download/en/details.aspx?id=27537" href="http://www.microsoft.com/download/en/details.aspx?id=27537"&gt;http://www.microsoft.com/download/en/details.aspx?id=27537&lt;/a&gt;    &lt;br /&gt;&lt;a title="http://www.microsoft.com/download/en/details.aspx?displaylang=en&amp;amp;id=27543" href="http://www.microsoft.com/download/en/details.aspx?displaylang=en&amp;amp;id=27543"&gt;http://www.microsoft.com/download/en/details.aspx?displaylang=en&amp;amp;id=27543&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;It will be tough to try it out now, though, as we don’t have docs or samples yet.&amp;#160; And note that there are several limitations, some of which are touched on in the video.&amp;#160; You’ll need to look through corprof.idl and turn on your mind-reading skills to figure it out.&amp;#160; But I will have a lot more to say about the feature and how you can use it in upcoming posts right here.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10216747" width="1" height="1"&gt;</description></item><item><title>CLRProfiler V4 Released</title><link>http://blogs.msdn.com/b/davbr/archive/2011/02/01/clrprofiler-v4-released.aspx</link><pubDate>Tue, 01 Feb 2011 23:31:39 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:10123386</guid><dc:creator>David Broman</dc:creator><slash:comments>10</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.msdn.com/b/davbr/rsscomments.aspx?WeblogPostID=10123386</wfw:commentRss><comments>http://blogs.msdn.com/b/davbr/archive/2011/02/01/clrprofiler-v4-released.aspx#comments</comments><description>&lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;CLRProfiler V4 is now publicly available.&amp;#160; You may download from here: &lt;/p&gt;  &lt;p&gt;&lt;a title="http://www.microsoft.com/downloads/en/details.aspx?FamilyID=be2d842b-fdce-4600-8d32-a3cf74fda5e1" href="http://www.microsoft.com/downloads/en/details.aspx?FamilyID=be2d842b-fdce-4600-8d32-a3cf74fda5e1"&gt;http://www.microsoft.com/downloads/en/details.aspx?FamilyID=be2d842b-fdce-4600-8d32-a3cf74fda5e1&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;This is of interest both to folks who want a free profiler to diagnose memory issues with their managed apps, and for folks who author profilers of their own, and would like to look at source code of a real-world example of a profiler.&lt;/p&gt;  &lt;h2&gt;If you just want to run it…&lt;/h2&gt;  &lt;p&gt;Then the following new features will be of interest to you:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;CLRProfiler V4 allows you to profile managed code that uses .NET 2.0, 3.0, 3.5, or 4.0.&amp;#160; However, you must always have .NET 4.0 installed on your box in order to use CLRProfiler V4, as CLRProfiler itself contains managed code that depends on .NET 4.0 &lt;/li&gt;    &lt;li&gt;CLRProfiler V4 can target &lt;strong&gt;Silverlight 4&lt;/strong&gt; apps. &lt;/li&gt;    &lt;li&gt;CLRProfiler V4 may be used to &lt;strong&gt;attach to and detach from&lt;/strong&gt; live processes, to generate heap graphs.&amp;#160; (Note:&amp;#160; This feature requires the process to be running .NET 4.0, does not work against Silverlight, and does not allow gathering allocation call stacks.) &lt;/li&gt;    &lt;li&gt;CLRProfiler V4 understands &lt;strong&gt;in-process side-by-side CLR instances&lt;/strong&gt;, and can allow you to pick which CLR instance from a given process to profile. &lt;/li&gt; &lt;/ul&gt;  &lt;h2&gt;If you want to write a profiler…&lt;/h2&gt;  &lt;p&gt;Then you may look through the source code for examples of all the above features, including how to target Silverlight, use the attach / detach API, and how to implement the “pick-one” approach for in-process side-by-side CLR instances.&lt;/p&gt;  &lt;p&gt;Also, CLRProfiler V4 consumes the new Enter3/Leave3/Tailcall3 signatures along with FunctionIDMapper2, so you can consult the source for examples of the naked assembly language wrappers.&lt;/p&gt;  &lt;h2&gt;Problems?&lt;/h2&gt;  &lt;p&gt;If you encounter problems with CLRProfiler V4, the best place to go is our forum:&lt;/p&gt;  &lt;p&gt;&lt;a title="http://social.msdn.microsoft.com/forums/en-US/netfxtoolsdev/threads/" href="http://social.msdn.microsoft.com/forums/en-US/netfxtoolsdev/threads/"&gt;http://social.msdn.microsoft.com/forums/en-US/netfxtoolsdev/threads/&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10123386" width="1" height="1"&gt;</description></item><item><title>SigParse uploaded to MSDN Code Gallery</title><link>http://blogs.msdn.com/b/davbr/archive/2010/08/25/sigparse-uploaded-to-msdn-code-gallery.aspx</link><pubDate>Thu, 26 Aug 2010 01:01:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:10054401</guid><dc:creator>David Broman</dc:creator><slash:comments>4</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.msdn.com/b/davbr/rsscomments.aspx?WeblogPostID=10054401</wfw:commentRss><comments>http://blogs.msdn.com/b/davbr/archive/2010/08/25/sigparse-uploaded-to-msdn-code-gallery.aspx#comments</comments><description>&lt;p&gt;A while back I &lt;a href="http://blogs.msdn.com/b/davbr/archive/2005/10/13/sample-a-signature-blob-parser-for-your-profiler.aspx" title="posted"&gt;posted&lt;/a&gt; some sample code written by Rico Mariani to parse CLR metadata signatures.&amp;nbsp; This code is now also available on the MSDN Code Gallery &lt;a href="http://code.msdn.microsoft.com/sigparse" title="SigParse"&gt;SigParse&lt;/a&gt; page.&amp;nbsp; If any of you were nervous about incorporating that source into your product without an official license agreement, please take a look at the MSDN Code Gallery page, where you'll find the source code is now governed by the MICROSOFT PUBLIC LICENSE (Ms-PL).&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10054401" width="1" height="1"&gt;</description></item><item><title>Profilers, in-process side-by-side CLR instances, and a free test harness</title><link>http://blogs.msdn.com/b/davbr/archive/2010/08/25/profilers-in-process-side-by-side-clr-instances-and-a-free-test-harness.aspx</link><pubDate>Wed, 25 Aug 2010 23:43:43 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:10054383</guid><dc:creator>David Broman</dc:creator><slash:comments>5</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.msdn.com/b/davbr/rsscomments.aspx?WeblogPostID=10054383</wfw:commentRss><comments>http://blogs.msdn.com/b/davbr/archive/2010/08/25/profilers-in-process-side-by-side-clr-instances-and-a-free-test-harness.aspx#comments</comments><description>&lt;p&gt;My previous post on &lt;a href="http://blogs.msdn.com/davbr/archive/2008/11/10/new-stuff-in-profiling-api-for-upcoming-clr-4-0.aspx"&gt;New stuff in Profiling API for upcoming CLR 4.0&lt;/a&gt; mentioned that any profiler that implements ICorProfilerCallback3 must be “side-by-side aware”.&amp;#160; This post goes into more detail on how to do this, and how to test it.&lt;/p&gt;  &lt;h1&gt;What are in-process side-by-side CLR instances?&lt;/h1&gt;  &lt;p&gt;To understand this fully, take a look at this CLR Inside Out &lt;a href="http://msdn.microsoft.com/en-us/magazine/ee819091.aspx"&gt;article&lt;/a&gt;.&amp;#160; It will help you understand the “what” and the “why” around this feature.&amp;#160; The simple summary is that, in order to aid with compatibility in certain scenarios, a single process can now have multiple instances of the CLR loaded simultaneously.&amp;#160; What that means today is that, in one process, you can have a V4-based CLR and [either a V1.1-based or V2.0-based CLR (though not both)].&amp;#160; In the future, the possibilities will likely grow as more major versions of the CLR are released.&lt;/p&gt;  &lt;p&gt;The CLR instances are unaware of each other.&amp;#160; If, say, a V2 and V4 CLR are loaded, then any managed code running against V2 CLR will look just like native code to the V4 CLR.&amp;#160; And vice-versa: any managed code running against the V4 CLR will look just like native code to the V2 CLR.&amp;#160; There is no direct communication between these two instances of the CLR.&amp;#160; What is possible is for, say, the V2 managed code to P/Invoke out to native code, which then calls a COM object implemented in V4 managed code.&amp;#160; In that way, one CLR can invoke another, but only in this indirect kind of way with native code in the middle.&lt;/p&gt;  &lt;p&gt;To support in-process side-by-side CLR instances, the CLR team has extended the hosting interfaces via the new “metahost” interface.&amp;#160; The metahost interface provides a way to operate over multiple CLRs that may be loaded into a single process, with each CLR represented by an ICLRRuntimeInfo interface.&amp;#160; If you have implemented the “attach” feature for your profiler, then you are already familiar with the metahost interface.&amp;#160; You can find some profiler-specific information about metahost, along with sample code for implementing attach, in &lt;a href="http://blogs.msdn.com/davbr/archive/2009/11/04/clr-v4-profiler-attach-basics-with-sample-code.aspx"&gt;this blog post&lt;/a&gt;. &lt;/p&gt;  &lt;p&gt;Again, I’d encourage you to read through the CLR Inside Out article linked above, as I don’t plan to repeat its content here.&amp;#160; That will give you context on why the feature of in-process side-by-side CLR instances even exists, and what problems it helps to solve.&amp;#160; What I will talk about is how this situation will appear to your profiler, and how your profiler can deal with it.&lt;/p&gt;  &lt;h1&gt;Profiler’s Point of View&lt;/h1&gt;  &lt;p&gt;When multiple CLR instances are loaded into a single process, and those CLRs each load your profiler, then your profiler DLL will be loaded multiple times, once per CLR instance.&amp;#160; This means your DLL gets LoadLibrary’d multiple times and you’ll receive multiple “CreateInstance” calls to your class factory object.&amp;#160; Depending on how you code your “CreateInstance”, that could mean multiple instances of your ICorProfilerCallback implementation would be generated.&lt;/p&gt;  &lt;p&gt;As you know, when the same DLL is LoadLibrary’d multiple times, it isn’t really “loaded” multiple times.&amp;#160; Windows just increments a reference count on that DLL (to be released via each FreeLibrary call).&amp;#160; Any global or static state in that DLL is shared across all code that executes in that DLL, regardless of how many LoadLibrary calls are made.&amp;#160; This means that, since your class factory’s CreateInstance() call could theoretically be called on two threads at the same time, any access CreateInstance() makes to globals in your DLL should be protected with synchronization primitives like a critical section.&amp;#160; Furthermore, if you allow multiple instances of your ICorProfilerCallback implementation to be created, then if they access any global or static class data, that access will need to be protected as well, if it isn’t already.&lt;/p&gt;  &lt;h1&gt;Pick First, Pick One&lt;/h1&gt;  &lt;p&gt;The easiest way for your profiler to become side-by-side aware is to choose to profile only one CLR at a time, and to add code to enforce that.&amp;#160; This is fairly easy to do, and is a quite reasonable solution to the in-process side-by-side problem.&amp;#160; In fact, the Visual Studio 2010 profiler and the upcoming CLRProfiler V4 update currently choose this approach.&lt;/p&gt;  &lt;p&gt;With &lt;strong&gt;Pick First&lt;/strong&gt;, your class factory CreateInstance simply keeps track of whether it was already called.&amp;#160; First time through, it creates your ICorProfilerCallback implementation and succeeds.&amp;#160; Thereafter, it fails.&amp;#160; The advantage of this approach is that it’s the easiest to implement, and will always do what the user wants in scenarios where only one CLR is loaded.&amp;#160; The disadvantage is that, when multiple CLRs are loaded, although your profiler will operate just fine, the user may be upset if she was trying to profile the second CLR that got loaded, as your profiler provides no way to do that.&lt;/p&gt;  &lt;p&gt;With &lt;strong&gt;Pick One&lt;/strong&gt;, you provide some kind of UI to your user to specify which CLR to profile.&amp;#160; This could be fancy GUI, less-fancy command-line parameters, whatever you like.&amp;#160; The user would specify the CLR in terms of its version, and your profiler would refuse to profile any CLR that didn’t match that version.&amp;#160; While being only slightly more difficult to implement than Pick First, this ensures your user remains in control of what gets profiled.&amp;#160; With this approach, you’d always succeed your CreateInstance method, and then do the version checking inside your ICorProfilerCallback::Initialize() method, which you would succeed or fail, depending on whether your version check passes.&amp;#160; To do your version check, you would first QueryInterface for ICorProfilerInfo3.&amp;#160; If that fails, you know you’re dealing with a CLR based on 2.0 or earlier.&amp;#160; If that succeeds, the CLR is 4.0 or later.&amp;#160; You would then use ICorProfilerInfo3::GetRuntimeInformation to get the specific version information of the CLR to check against what the user selected.&amp;#160; Finally, you now know if you should succeed or fail ICorProfilerCallback::Initialize().&lt;/p&gt;  &lt;p&gt;When you fail either your CreateInstance, ICorProfilerCallback::Initialize, or ICorProfilerCallback3::InitializeForAttach method due to an intentional choice not to profile that CLR (as opposed to encountering some kind of user-serviceable problem), I’d recommend you return the new “CORPROF_E_PROFILER_CANCEL_ACTIVATION” HRESULT. CORPROF_E_PROFILER_CANCEL_ACTIVATION is special in that the new CLR V4 will not log an error to the event log when it receives this HRESULT from the profiler’s CreateInstance or ICorProfilerCallback::Initialize method.&amp;#160; Instead, CLR V4 logs a less-alarming informational message to the event log stating that the profiler has intentionally chosen not to profile that CLR in that process.&amp;#160; Of course, in cases where you fail for an exceptional reason, you should continue to dutifully surface whatever HRESULT describes the problem, and let the CLR treat that as an error so that the user is properly informed of the problem.&lt;/p&gt;  &lt;h1&gt;Pick Many, Pick All&lt;/h1&gt;  &lt;p&gt;You can provide more value to your users—particularly those who may be dealing with in-process side-by-side CLR scenarios more often—if you allow the user to profile multiple CLRs that may be loaded in a given process.&amp;#160; This approach would allow your profiler to provide the most information to the user, including capturing timings of all managed methods (regardless of the governing CLR), present interleaved call stacks including code from all runtimes, analyze all managed heaps from all runtimes, monitor the behavior of all managed code in the process, etc.&amp;#160; Doing this properly will require that you take care to synchronize, or in some cases remove entirely, global state from your DLL.&lt;/p&gt;  &lt;p&gt;Just as a simple example, many profilers use global pointers that point to their ICorProfilerCallback implementation and / or the CLR’s ICorProfilerInfo implementation (e.g., say g_pMyCallback, g_pInfo).&amp;#160; This is no longer acceptable when there could be arbitrarily many of your ICorProfilerCallback implementations instantiated, and CLR’s ICorProfilerInfos lying around.&amp;#160; The key problem is this: if you pass an ID from one CLR to the ICorProfilerInfo of another CLR, you will crash.&amp;#160; Example: CLR #1 informs you about a FunctionID which you pass to CLR #2’s GetFunctionInfo().&amp;#160; Boom.&amp;#160; As many of you know, the CLR is intolerant about bogus IDs.&amp;#160; And from any given CLR’s point of view, an ID from a different CLR is garbage.&lt;/p&gt;  &lt;p&gt;This means you must take care always to communicate with the appropriate CLR.&amp;#160; Thus, you’ll want to reevaluate any reliance your DLL has on global state, and protect or remove it appropriately.&amp;#160; In this section I’ll list some of the things to look out for, and recommended ways to address them.&lt;/p&gt;  &lt;h2&gt;Global Profiler Manager&lt;/h2&gt;  &lt;p&gt;For the most part, communicating with the right CLR is straightforward.&amp;#160; Suppose multiple CLRs get loaded, and that forces multiple instances of your ICorProfilerCallback implementation to be created.&amp;#160; If:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Each ICorProfilerCallback implementation keeps a pointer to the ICorProfilerInfo it was given at initialization time, and &lt;/li&gt;    &lt;li&gt;Each ICorProfilerCallback implementation always uses this pointer to call into ICorProfilerInfo in response to callbacks &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;then you’re mostly there.&amp;#160; Any Info calls you make in response to a callback will always be routed to the appropriate CLR.&amp;#160; Simple, right?&amp;#160; Yeah, but what about the ways your profiler gets control other than ICorProfilerCallback methods?&amp;#160; For example:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Enter/Leave/Tailcall probes &lt;/li&gt;    &lt;li&gt;Callouts you add via instrumentation &lt;/li&gt;    &lt;li&gt;Separate threads you create for sampling, forcing GCs or other reasons &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;An approach I’d recommend is that you create a single-instance, global profiler manager, which gets invoked in the above cases and “figures out” which ICorProfilerCallback implementation (and thus which ICorProfilerInfo pointer) to route the request to.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-00-53-47-metablogapi/2110.image_5F00_051F632D.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-00-53-47-metablogapi/8715.image_5F00_thumb_5F00_01A0D243.png" width="499" height="290" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Diagrams are spiffy.&amp;#160; But the interesting part is how the single global profiler manager figures out which ICorProfilerCallback implementation to talk to.&amp;#160; A diagram that just shows arrows doesn’t really help explain that.&amp;#160; The following sections address this.&lt;/p&gt;  &lt;h2&gt;Enter / Leave / Tailcall / FunctionIDMapper&lt;/h2&gt;  &lt;p&gt;Since Enter, Leave, Tailcall, and FunctionIDMapper are implemented as global C functions, they’re technically part of your global profiler manager.&amp;#160; So they must somehow figure out which CLR invoked them.&amp;#160; The key to this is a new parameter added to the new V4 SetFunctionIDMapper2:&lt;/p&gt;  &lt;pre class="code"&gt;HRESULT SetFunctionIDMapper2(
            [&lt;span style="color: blue"&gt;in&lt;/span&gt;] FunctionIDMapper2 *pFunc,
            &lt;span style="background-color: #ffff00"&gt;[&lt;span style="color: blue"&gt;in] &lt;span style="color: blue"&gt;void *clientData&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;);&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;clientData can be anything you like, though typically it will be a pointer to your ICorProfilerCallback implementation instance that makes the call SetFunctionIDMapper2.&amp;#160; Then, when your mapper function gets called:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;typedef &lt;/span&gt;UINT_PTR &lt;span style="color: blue"&gt;__stdcall &lt;/span&gt;FunctionIDMapper2(
                FunctionID funcId, 
                &lt;span style="color: blue"&gt;&lt;span style="background-color: #ffff00"&gt;&lt;span style="color: blue"&gt;void *clientData&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;,
                BOOL *pbHookFunction);&lt;/pre&gt;

&lt;p&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;the CLR passes that clientData right back to you.&amp;#160; Now your global profiler manager can associate this FunctionID with the correct ICorProfilerCallback implementation.&amp;#160; You can store this association in a hash table or use the FunctionIDMapper as it was intended, and return an ID of your own, typically a index into an array you build up which would contain the correct ICorProfilerCallback implementation (as well as the FunctionID you remapped), rather than using a hash table.&lt;/p&gt;

&lt;p&gt;Now, the next time your Enter/Leave/Tailcall probes are called, your global profiler manager will be able to map the FunctionID provided (or, your remapped client ID assuming your FunctionIDMapper returned one), to the appropriate ICorProfilerCallback implementation.&lt;/p&gt;

&lt;h2&gt;Instrumentation&lt;/h2&gt;

&lt;p&gt;Some profilers rewrite IL to call into a managed helper library that ships with the profiler, and that managed library may then P/Invoke back into the native profiler code.&amp;#160; In such cases, how can the native profiler code know which CLR instance did the P/Invoke?&amp;#160; The target of the P/Invoke would likely be your global profiler manager, which then needs to determine which ICorProfilerCallback implementation to route the call to.&amp;#160; This knowledge is required if the native profiler code needs to call any ICorProfilerInfo methods to do further inspection on any of the parameters the managed helper library passed in the P/Invoke.&amp;#160; So how does the global profiler manager figure out the right CLR?&lt;/p&gt;

&lt;p&gt;One way is to take advantage of a new method in the .NET Framework, &lt;a href="http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.runtimeenvironment.getruntimeinterfaceasobject.aspx"&gt;System.Runtime.InteropService.RuntimeEnvironment.GetRuntimeInterfaceAsObject&lt;/a&gt;.&amp;#160; That returns the ICLRRuntimeInfo (i.e., the interface metahost uses to describe a given CLR version’s instance, as mentioned above) for the CLR instance that managed the calling code.&amp;#160; If your managed helper library passes that ICLRRuntimeInfo pointer to your native global profiler manager, then your native code can use that ICLRRuntimeInfo to determine which CLR version did the P/Invoke, and thus which ICorProfilerCallback implementation to route that call to.&lt;/p&gt;

&lt;p&gt;Another option is that you can do version-specific instrumentation.&amp;#160; When your profiler receives JITCompilationStarted and then calls SetILFunctionBody, your profiler knows which CLR is managing that particular method (because you receive these notifications on the appropriate ICorProfilerCallback interface).&amp;#160; Your profiler could then add specific markers to the instrumented code (e.g., adding integer constants like 1 or 2 or 4 to indicate the CLR version, or really any other plan you can think up).&amp;#160; Then, when the instrumented code gets invoked, it can pass your special values to the P/Invoke, which your global profiler manager can inspect to determine which CLR instance was in control.&lt;/p&gt;

&lt;h2&gt;DoStackSnapshot&lt;/h2&gt;

&lt;p&gt;If you’re writing a sampling profiler, or any profiler that needs to occasionally take snapshots of the stack (without building a shadow stack via Enter/Leave/Tailcall), then you use the DoStackSnapshot (DSS) API.&amp;#160; If your profiler implements the “Pick Many” or “Pick All” approach, then it can provide your users with the advantage of seeing more complete stacks, including managed code from all runtimes.&amp;#160; Remember that code managed by one CLR looks like native code to another CLR.&amp;#160; So by having your profiler simultaneously load against all runtimes, the profiler can then provide the most complete view of the stack.&amp;#160; Otherwise, chains of frames managed by a CLR the profiler is not loaded against would look like native code, with the profiler unable to report anything useful about those frames (such as function names).&lt;/p&gt;

&lt;p&gt;&lt;a href="http://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-00-53-47-metablogapi/4276.image1_5F00_31CAADB7.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-00-53-47-metablogapi/8715.image1_5F00_thumb_5F00_38118445.png" width="499" height="336" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;A pick-all, “mixed-mode” (i.e., native + managed) profiler can assemble the frames managed by various CLRs, along with native frames, into a single stack view by using an algorithm like the following.&amp;#160; (Note that a complete algorithm for doing a mixed-mode stack walk is out of scope of this post.&amp;#160; More information on mixed-mode stack walking can be found &lt;a href="http://blogs.msdn.com/davbr/archive/2005/10/06/profiler-stack-walking-basics-and-beyond.aspx"&gt;here&lt;/a&gt;.)&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Global Profiler Manager begins an unmanaged walk of the stack starting at its thread’s current register context. &lt;/li&gt;

  &lt;li&gt;Global Profiler Manager cycles through all ICorProfilerCallback implementations, having each one call into its CLR’s ICorProfilerInfo::GetFunctionFromIP with the IP of that stack frame. 
    &lt;ul&gt;
      &lt;li&gt;Note: I mentioned above that you should never pass a profiler ID (e.g., FunctionID, ClassID) to the wrong CLR’s ICorProfilerInfo, as that will easily cause an AV.&amp;#160; However, it is always safe to pass any IP address to GetFunctionFromIP(). &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;

  &lt;li&gt;If ICorProfilerInfo::GetFunctionFromIP succeeds with a FunctionID, that means this frame is managed, and you’ve found the CLR that manages it.&amp;#160; You may call DoStackSnapshot from this CLR’s ICorProfilerInfo2 to perform a complete stack walk starting at this frame.&amp;#160; &lt;strong&gt;See below for details.&lt;/strong&gt; &lt;/li&gt;

  &lt;li&gt;If ICorProfilerInfo::GetFunctionFromIP fails, continue cycling through the other CLRs’ ICorProfilerInfo::GetFunctionFromIP until you find one that works. &lt;/li&gt;

  &lt;li&gt;If none of the GetFunctionFromIP calls succeed, then this really is a native frame.&amp;#160; Your Global Profiler Manager will need to use whatever native stack walking techniques you have to identify the frame, and then walk past it to the calling frame, and go back to step 2. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Step 3 above occurs when your Global Profiler Manager finds a frame managed by a particular CLR, and has the corresponding profiler instance call DoStackSnapshot (on the corresponding CLR), seeded with that frame, to perform a walk from that point.&amp;#160; Your Global Profiler Manager will effectively repeat the above algorithm recursively, inside native blocks reported by that DoStackSnapshot.&amp;#160; Here are the details:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;You now have a view of the stack with information from all frames managed by this CLR. &lt;/li&gt;

  &lt;li&gt;All frames &lt;em&gt;not &lt;/em&gt;managed by this CLR appear as blocks of native frames.&amp;#160; Some of these frames really are native, and some are managed by a different CLR. &lt;/li&gt;

  &lt;li&gt;For each block of native frames, repeat the algorithm above (i.e., calling GetFunctionFromIP / DoStackSnapshot from each CLR to find the CLR that manages it (if any), or to walk to the next frame and retry otherwise). &lt;/li&gt;

  &lt;li&gt;Stitch together the frames from all CLRs, using SP as your guide on where each frame should be sorted. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By the time you’re done, any frame for which you were unable to find a CLR that manages it really is native.&amp;#160; The rest of the frames are managed, and you should now have information from the appropriate CLR to identify them.&lt;/p&gt;

&lt;p&gt;A pick-all, managed-only profiler has a simpler job:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Global Profiler Manager cycles through all ICorProfilerCallback implementations, having each one call into its CLR’s DoStackSnapshot to perform an unseeded walk. &lt;/li&gt;

  &lt;li&gt;Global Profiler Manager stitches together all managed frames found by the above walks using SP as its guide on where each frame should be sorted. &lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;Side-by-side and Profiler Backward Compatibility&lt;/h1&gt;

&lt;p&gt;Now that I’ve covered how a V4 profiler can properly support in-process side-by-side CLR instances, you may be wondering what happens if an older V2 profiler encounters multiple CLRs.&amp;#160; As I covered in a previous &lt;a href="http://blogs.msdn.com/davbr/archive/2009/05/26/run-your-v2-profiler-binary-on-clr-v4.aspx"&gt;post&lt;/a&gt;, V2 profilers will not even be loaded by V4 CLR by default—but users may set the “COMPLUS_ProfAPI_ProfilerCompatibilitySetting” environment variable to allow a V2 profiler to be loaded by a V4 CLR.&amp;#160; What happens then?&lt;/p&gt;

&lt;p&gt;The V4 CLR attempts some low-cost heroics to try to shield the V2 profiler from pain caused by in-process side-by-side CLR instances.&amp;#160; However, it’s far from perfect.&amp;#160; As I mentioned from that previous &lt;a href="http://blogs.msdn.com/davbr/archive/2009/05/26/run-your-v2-profiler-binary-on-clr-v4.aspx"&gt;post&lt;/a&gt;, COMPLUS_ProfAPI_ProfilerCompatibilitySetting may be set to one of the following three values: EnableV2Profiler, DisableV2Profiler (default), and PreventLoad.&amp;#160; In fact, I mentioned that “PreventLoad” would be explained in more detail in a future post.&amp;#160; Well, this is that post.&amp;#160; And it’s only a year later.&amp;#160; Yowza, time flies.&lt;/p&gt;

&lt;p&gt;The quick summary of the “low cost heroics” is that, if V4 CLR detects that V2 CLR has already been loaded, then V4 CLR will protectively refuse to load the V2 profiler (since it was already loaded by the V2 CLR).&amp;#160; The caveat with this plan is that it doesn’t work so well when the CLRs are loaded in the other order.&amp;#160; If V4 CLR loads first, it has no idea if a V2 CLR will ever load.&amp;#160; So it optimistically loads the V2 profiler and hopes for the best.&amp;#160; If a V2 CLR does load later, then the V2 profiler will likely fail in some horrible AV’ish kind of way.&lt;/p&gt;

&lt;p&gt;It’s also worth noting how the V4 CLR decides whether a profiler is a V2 or V4 profiler in the first place.&amp;#160; The V4 CLR will QI for ICorProfilerCallback3.&amp;#160; If it works, it’s a V4 profiler; else it’s a V2 (or even older) profiler.&amp;#160; This means the V4 CLR actually has to LoadLibrary your DLL, use your class factory to create an instance of your ICorProfilerCallback implementation, and then QI for ICorProfilerCallback3.&lt;/p&gt;

&lt;p&gt;The following table details the behavior of whether and how a V2 profiler gets loaded depending on the setting of COMPLUS_ProfAPI_ProfilerCompatibilitySetting, and the order in which the CLRs get loaded.&lt;/p&gt;

&lt;table border="1" cellspacing="0" cellpadding="2" width="491"&gt;&lt;tbody&gt;
    &lt;tr style="background-color: #0080ff"&gt;
      &lt;td valign="top" width="169"&gt;&lt;font color="#ffffff"&gt;ProfilerCompatibilitySetting&lt;/font&gt;&lt;/td&gt;

      &lt;td valign="top" width="71"&gt;&lt;font color="#ffffff"&gt;CLR Load Order&lt;/font&gt;&lt;/td&gt;

      &lt;td valign="top" width="249"&gt;&lt;font color="#ffffff"&gt;Result&lt;/font&gt;&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="169"&gt;EnableV2Profiler&lt;/td&gt;

      &lt;td valign="top" width="71"&gt;V2, V4 &lt;/td&gt;

      &lt;td valign="top" width="249"&gt;V2 loads profiler, V4 does not load profiler. &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="169"&gt;EnableV2Profiler&lt;/td&gt;

      &lt;td valign="top" width="71"&gt;V4, V2 &lt;/td&gt;

      &lt;td valign="top" width="249"&gt;V4 loads profiler, V2 loads profiler &lt;font color="#ff0000"&gt;(profiler will likely AV due to active use of multiple callback instances)&lt;/font&gt; &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="169"&gt;DisableV2Profiler (default) &lt;/td&gt;

      &lt;td valign="top" width="71"&gt;V2, V4 &lt;/td&gt;

      &lt;td valign="top" width="249"&gt;V2 loads profiler, V4 queries then releases the V2 profiler interface but never unloads the profiler DLL &lt;font color="#ff0000"&gt;(profiler may possibly AV on V4 instantiation)&lt;/font&gt; &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="169"&gt;DisableV2Profiler (default) &lt;/td&gt;

      &lt;td valign="top" width="71"&gt;V4, V2 &lt;/td&gt;

      &lt;td valign="top" width="249"&gt;V4 queries then releases the profiler interface but never unloads the profiler DLL, V2 loads the profiler.&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="169"&gt;PreventLoad&lt;/td&gt;

      &lt;td valign="top" width="71"&gt;V2, V4 &lt;/td&gt;

      &lt;td valign="top" width="249"&gt;V2 loads profiler, V4 does not load profiler. &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="169"&gt;PreventLoad&lt;/td&gt;

      &lt;td valign="top" width="71"&gt;V4, V2 &lt;/td&gt;

      &lt;td valign="top" width="249"&gt;V4 does not load profiler, V2 loads profiler. &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;We’re now in a better position to see the point of setting COMPLUS_ProfAPI_ProfilerCompatibilitySetting=&lt;strong&gt;PreventLoad&lt;/strong&gt;.&amp;#160; If a user is encountering a scenario with in-process side-by-side CLR instances, particularly where V4 CLR loads first, then a V2 profiler is likely to AV.&amp;#160; PreventLoad tells V4 CLR not to load any profilers whatsoever, regardless of whatever version they happen to be.&amp;#160; Of course, V2 CLR totally ignores COMPLUS_ProfAPI_ProfilerCompatibilitySetting (since that environment variable appeared after CLR V2 shipped!), so V2 CLR will happily load the V2 profiler.&amp;#160; Thus, PreventLoad allows the user to use a V2 profiler to profile the V2 CLR, without allowing a V4 CLR to spoil the fun. &lt;/p&gt;

&lt;h1&gt;Free Test Harness&lt;/h1&gt;

&lt;p&gt;In-process side-by-side scenarios may be hard to test, so we have a harness you can use that will force multiple CLRs to get loaded:&lt;/p&gt;

&lt;p&gt;Download &lt;a href="http://code.msdn.microsoft.com/RunSxS"&gt;RunSxS&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;RunSxS has many options to customize its behavior, though you’ll probably want to start with something simple.&amp;#160; Here’s an example sequence of steps you can try out:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Open an ([elevated], if necessary) command prompt of the appropriate bitness. &lt;/li&gt;

  &lt;li&gt;Register your profiler, if necessary. &lt;/li&gt;

  &lt;li&gt;Set the usual environment variables, including COR_ENABLE_PROFILING, COR_PROFILER, and optionally COR_PROFILER_PATH. &lt;/li&gt;

  &lt;li&gt;You do not need to set COMPLUS_ProfAPI_ProfilerCompatibilitySetting unless you’re trying to test out your old V2 profiler. &lt;/li&gt;

  &lt;li&gt;Have some sample V2 CLR and V4 CLR applications handy (we’ll call them AppV2.exe and AppV4.exe). &lt;/li&gt;

  &lt;li&gt;Execute some of the RunSxS command-lines below. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here are some RunSxS command-lines to try out.&amp;#160; This one deterministically loads V2 CLR (and thus your V2 profiler), and then V4 CLR (and thus your V4 profiler):&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;RunSxS /st v2.0.50727 c:\Path\To\AppV2.exe &amp;quot;appv2arg1 appv2arg2&amp;quot; v4.0.30319 c:\Path\To\AppV4.exe &amp;quot;appv4arg1 appv4arg2&amp;quot; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, reverse the order:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;RunSxS /st v4.0.30319 c:\Path\To\AppV4.exe &amp;quot;appv4arg1 appv4arg2&amp;quot; v2.0.50727 c:\Path\To\AppV2.exe &amp;quot;appv2arg1 appv2arg2&amp;quot; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This one will simultaneously launch a V2 &amp;amp; V4 app on separate threads, so you can see how your profiler fares with multi-threaded loading.&amp;#160; Try to catch some nondeterministic bugs:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;RunSxS v2.0.50727 c:\Path\To\AppV2.exe &amp;quot;appv2arg1 appv2arg2&amp;quot; v4.0.30319 c:\Path\To\AppV4.exe &amp;quot;appv4arg1 appv4arg2&amp;quot; &lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;Is it over yet?!&lt;/h1&gt;

&lt;p&gt;Yes.&amp;#160; Yes it is.&amp;#160; To recap:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;In order to say your profiler works with V4 CLR, your profiler must be side-by-side-aware, which means it must support pick-first/one or pick-many/all. &lt;/li&gt;

  &lt;li&gt;The latter is harder to implement, but provides your user with the most information when multiple CLRs are loaded. 
    &lt;ul&gt;
      &lt;li&gt;Consider factoring your code so you have a single, global profiler manager, that is distinct from your (multiple) callback implementation instances. &lt;/li&gt;

      &lt;li&gt;Enter/Leave/Tailcall, instrumentation, and stack walking have special considerations &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;

  &lt;li&gt;Older, V2 profilers will probably have issues if multiple CLRs are loaded, though the V4 CLR half-heartedly tries to protect those older profilers. &lt;/li&gt;

  &lt;li&gt;Test, test, test! &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks to Shane Yuan for much of the content and illustrations in this post!&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10054383" width="1" height="1"&gt;</description></item><item><title>CLR V4: Profiler Detach</title><link>http://blogs.msdn.com/b/davbr/archive/2010/02/03/clr-v4-profiler-detach.aspx</link><pubDate>Thu, 04 Feb 2010 02:13:52 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9957933</guid><dc:creator>David Broman</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.msdn.com/b/davbr/rsscomments.aspx?WeblogPostID=9957933</wfw:commentRss><comments>http://blogs.msdn.com/b/davbr/archive/2010/02/03/clr-v4-profiler-detach.aspx#comments</comments><description>&lt;p&gt;I described how profilers may attach to already-running processes in some previous posts (&lt;a href="http://blogs.msdn.com/davbr/archive/2009/11/04/clr-v4-profiler-attach-basics-with-sample-code.aspx"&gt;#1&lt;/a&gt; and &lt;a href="http://blogs.msdn.com/davbr/archive/2010/01/18/clr-v4-profiler-attach-part-2-ok-now-what.aspx"&gt;#2&lt;/a&gt;).&amp;#160; In this post I’m writing about how profilers that are already loaded may detach from a running process before that process exits.&amp;#160; Like Profiler Attach, this is a new feature available starting with CLR V4.&lt;/p&gt;  &lt;p&gt;The Detach feature allows a profiler that the user is finished with to be unloaded.&amp;#160; That means the application may return to its usual behavior and performance characteristics, without a profiler loaded and doing stuff.&amp;#160; Also, since only one profiler may be loaded at a time, detaching a profiler makes room for a different (or the same) profiler to be loaded later on when the user wishes to do more diagnostics.&lt;/p&gt;  &lt;h2&gt;Limitations&lt;/h2&gt;  &lt;p&gt;Not every V4 profiler is allowed to detach from a running process.&amp;#160; The general rule is that a profiler which has caused an irreversible impact in the process it’s profiling should &lt;em&gt;not &lt;/em&gt;attempt to detach.&amp;#160; The CLR catches the following cases:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Profiler set immutable flags (COR_PRF_MONITOR_IMMUTABLE) via SetEventMask. &lt;/li&gt;    &lt;li&gt;Profiler performed IL rewriting via SetILFunctionBody &lt;/li&gt;    &lt;li&gt;Profiler used the Enter/Leave/Tailcall methods to add callouts to its probes &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;If the profiler attempts to detach after doing any of the above, the CLR will disallow the attempt (see below for details).&lt;/p&gt;  &lt;p&gt;That said, there are still other irreversible things the profiler might do to a process (which would also make detaching a bad idea).&amp;#160; Imagine a profiler that allocates memory without cleaning up after itself, creates threads without waiting for them to exit, uses metadata APIs to modify aspects of the running managed code, etc.&amp;#160; Profiler writers need to use good judgment when considering whether to allow their profilers to detach from running processes.&amp;#160; You don’t want to give your customers the experience of noticing the app they profile always behaves weirdly after detaching your profiler.&amp;#160; So do not use the detach feature unless you’ve thought through the ramifications and can ensure the profiler does not leave the application in a noticeably different state.&lt;/p&gt;  &lt;p&gt;By the way, you may notice I said nothing about a profiler needing to load via attach in order for it to be able to use the detach feature.&amp;#160; In fact, any profiler that loads on startup of the application (i.e., via environment variables and not via the AttachProfiler API) is perfectly welcome to use the detach feature—so long as it does not leave an impact on the process as per above.&lt;/p&gt;  &lt;h2&gt;How Detaching Works&lt;/h2&gt;  &lt;p&gt;There’s one, deceptively simple-looking method the profiler calls to detach itself from the running process.&amp;#160; However, detaching is a big responsibility, and profiler writers need to give thoughtful consideration to doing it properly.&amp;#160; The CLR does its part to ensure it doesn’t accidentally call into the profiler via Profiling API methods after the CLR unloads the profiler DLL.&amp;#160; However, if the profiler has set into motion extra threads, Windows callbacks, timer interrupts, etc., then the profiler must “undo” all of these things before it attempts to detach from the running process.&amp;#160; Basically, any way for control to re-enter the profiler DLL must be disabled before detaching, or else your users will experience crashes after trying to detach your profiler.&lt;/p&gt;  &lt;p&gt;So, the sequence works like this:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;The profiler &lt;strong&gt;deactivates all the ways control could enter the profiler&lt;/strong&gt; (aside from the CLR Profiling API itself).&amp;#160; This means removing any Windows callbacks, timer interrupts, hijacking, disabling any other components that may try to call into the profiler DLL, etc.&amp;#160; The profiler must also wait for all threads that it has created (e.g., a sampling thread, inter-process communication threads, a ForceGC thread, etc.) to exit, except for the one thread the profiler will use to call RequestProfilerDetach().&amp;#160; Any threads created by the CLR, of course, should not be tampered with.       &lt;ul&gt;       &lt;li&gt;Your profiler must block here until all those ways control can enter your profiler DLL have truly been deactivated (e.g., just setting a flag to disable sampling may not be enough if your sampling thread is currently performing a sample already in progress).&amp;#160; You must coordinate with all components of your profiler so that your profiler DLL knows that everything is verifiably deactivated, and all profiler-created threads have exited (except for the one thread the profiler will use to call RequestProfilerDetach()). &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt;    &lt;li&gt;If the profiler will use a thread of its own creation to call RequestProfilerDetach() (which is the typical way this API will be called), that thread must own a reference onto the profiler’s DLL, via its own &lt;strong&gt;LoadLibrary()&lt;/strong&gt; call that it makes on the profiler DLL.&amp;#160; This can either be done when the thread starts up, or now, or sometime in between.&amp;#160; But that reference must be added at some point before calling RequestProfilerDetach(). &lt;/li&gt;    &lt;li&gt;Profiler calls ICorProfilerInfo3::&lt;strong&gt;RequestProfilerDetach&lt;/strong&gt;().       &lt;ul&gt;       &lt;li&gt;(A) This causes the CLR to (synchronously) set internal state to avoid making any further calls into the profiler via the ICorProfilerCallback* interfaces, and to refuse any calls from the profiler into ICorProfilerInfo* interfaces (such calls will now fail early with CORPROF_E_PROFILER_DETACHING). &lt;/li&gt;        &lt;li&gt;(B) The CLR also (asynchronously) begins a period safety check on another thread to determine when all pre-existing calls into the profiler via the ICorProfilerCallback* interfaces have returned. &lt;/li&gt;        &lt;li&gt;Note: It is expected that your profiler will not make any more “unsolicited” calls back into the CLR via any interfaces (ICorProfilerInfo*, hosting, metahost, metadata, etc.).&amp;#160; By “unsolicited”, I’m referring to calls that didn’t originate from the CLR via ICorProfilerCallback*.&amp;#160; In other words, it’s ok for the profiler to continue to do its usual stuff in its implementation of ICorProfilerCallback methods (which may include calling into the CLR via ICorProfilerInfo*), as the CLR will wait for those outer ICorProfilerCallback methods to return as per 3B.&amp;#160; But the profiler must not make any other calls into the CLR (i.e., that are not sandwiched inside an ICorProfilerCallback call).&amp;#160; You should already have deactivated any component of your profiler that would make such unsolicited calls in step 1. &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt;    &lt;li&gt;Assuming the above RequestProfilerDetach call was made on a profiler-created thread, that thread must now call &lt;a href="http://msdn.microsoft.com/en-us/library/ms683153(VS.85).aspx"&gt;&lt;strong&gt;FreeLibraryAndExitThread&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;()&lt;/strong&gt;.&amp;#160; (Note: that’s a specialized Windows API that combines FreeLibrary() and ExitThread() in such a way that races can be avoided—do not call FreeLibrary() and ExitThread() separately.) &lt;/li&gt;    &lt;li&gt;On another thread, the CLR continues its &lt;strong&gt;period safety checks&lt;/strong&gt; from 3B above.&amp;#160; Eventually the CLR determines that there are no more ICorProfilerCallback* interface calls currently executing, and it is therefore safe to unload the profiler. &lt;/li&gt;    &lt;li&gt;The CLR calls ICorProfilerCallback3::&lt;strong&gt;ProfilerDetachSucceeded&lt;/strong&gt;.&amp;#160; The profiler can use this signal to know that it’s about to be unloaded.&amp;#160; It’s expected that the profiler will do very little in this callback—probably just notifying the user that the profiler is about to be unloaded.&amp;#160; Any cleanup the profiler needs to do should already have been done during step 1. &lt;/li&gt;    &lt;li&gt;CLR makes the necessary number of &lt;strong&gt;Release&lt;/strong&gt;() calls on ICorProfilerCallback3.&amp;#160; The reference count should go down to 0 at this point, and the profiler may deallocate any memory it had previously allocated to support its callback implementation. &lt;/li&gt;    &lt;li&gt;CLR calls &lt;strong&gt;FreeLibrary&lt;/strong&gt;() on the profiler DLL.&amp;#160; This should be the last reference to the profiler’s DLL, and your DLL will now be unloaded.       &lt;ul&gt;       &lt;li&gt;Note: in some cases, it’s theoretically possible that step 4 doesn’t happen until &lt;em&gt;after&lt;/em&gt; this step, in which case the last reference to the profiler’s DLL will actually be released by your profiler’s thread that called RequestProfilerDetach and then FreeLibraryAndExitThread.&amp;#160; That’s because steps 1-4 happen on your profiler’s thread, and steps 5-8 happen on a dedicated CLR thread (for detaching profilers) sometime after step 3 is completed.&amp;#160; So there’s a race between step 4 and all of steps 5-8.&amp;#160; There’s no harm in this, so long as you’re playing nice by doing your own LoadLibrary and FreeLibraryAndExitThread as described above. &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt;    &lt;li&gt;The CLR adds an Informational entry to the Application Event Log noting that the profiler has been unloaded.&amp;#160; The CLR is now ready to service any profiler attach requests. &lt;/li&gt; &lt;/ol&gt;  &lt;h2&gt;RequestProfilerDetach&lt;/h2&gt;  &lt;p&gt;Let’s dive a little deeper into the method you call to detach your profiler:&lt;/p&gt;  &lt;p&gt;HRESULT RequestProfilerDetach([&lt;span style="color: rgb(0,0,255)"&gt;in&lt;/span&gt;] DWORD dwExpectedCompletionMilliseconds);&lt;/p&gt; &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;  &lt;p&gt;First off, you’ll notice this is on ICorProfilerInfo3, the interface your profiler DLL uses, in the same process as your profilee.&amp;#160; Although the AttachProfiler API is called from outside the process, this detach method is called from in-process.&amp;#160; Why?&amp;#160; Well, the general rule with profilers is that &lt;em&gt;everything &lt;/em&gt;is done in-process.&amp;#160; Attach is an exception because your profiler isn’t in the process yet.&amp;#160; You need to somehow trigger your profiler to load, and you can’t do that from a process in which you have no code executing yet!&amp;#160; So Attach is sort of a boot-strapping API that has to be called from a process of your own making.&lt;/p&gt;  &lt;p&gt;Once your profiler DLL is up and running, it is in charge of everything, from within the same process as the profilee.&amp;#160; And detach is no exception.&amp;#160; Now with that said, it’s probably typical that your profiler will detach in response to an end user action—probably via some GUI that you ship that runs in its own process.&amp;#160; So a case could be made that the CLR team could have made your life easier by providing an out-of-process way to do a detach, so that your GUI could easily trigger a detach, just as it triggered the attach.&amp;#160; However, you could make that same argument about all the ways you might want to control a profiler via a GUI, such as these commands:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Do a GC now and show me the heap &lt;/li&gt;    &lt;li&gt;Dial up or down the sampling frequency &lt;/li&gt;    &lt;li&gt;Change which instrumented methods should log their invocations &lt;/li&gt;    &lt;li&gt;Start / stop monitoring exceptions &lt;/li&gt;    &lt;li&gt;etc. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;The point is, if you have a GUI to control your profiler, then you probably already have an inter-process mechanism for the GUI to communicate with your profiler DLL.&amp;#160; So think of “detach” as yet one more command your GUI will send to your profiler DLL.&lt;/p&gt;  &lt;p&gt;Ok, fine, so your profiler DLL is the one to call RequestProfilerDetach.&amp;#160; What should it specify for “dwExpectedCompletionMilliseconds”?&amp;#160; The purpose of this parameter is for the profiler to give a guess as to how long the CLR should expect to wait until all control has exited the profiler, thus ensuring success of the CLR’s periodic safety checks (step 5).&amp;#160; So consider all of your callback implementations and what they do.&amp;#160; Pick the “longest” one—the one that does the most processing or blocking or complex calls back into the CLR via ICorProfilerInfo or other interfaces.&amp;#160; Roughly how long will that callback implementation take?&amp;#160; That’s the value (in milliseconds) that you specify for this parameter.&lt;/p&gt;  &lt;p&gt;The CLR uses that value in its Sleep() statement that sits between each periodic safety check done as part of step 5.&amp;#160; Although the CLR reserves the right to change the details of this algorithm, currently during step 5 the CLR sleeps dwExpectedCompletionMilliseconds before checking whether all callback methods have popped off all stacks.&amp;#160; If they haven’t, the CLR will sleep an additional dwExpectedCompletionMilliseconds (for a total sleep time of 2*dwExpectedCompletionMilliseconds) and try again.&amp;#160; If callback methods are still on any stacks, then the CLR degrades to a steady-state of sleeping for 10 minutes and retrying, repeating until the profiler may be unloaded.&lt;/p&gt;  &lt;p&gt;Until the profiler can be unloaded, it will be considered “loaded” (though deactivated in the sense that no new callback methods will be called).&amp;#160; This prevents any new profiler from attaching.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Ok, that wraps up how detaching works.&amp;#160; If you remember only one thing from this post, remember that it’s really easy to cause an application you profile to AV after your profiler unloads if you’re not careful.&amp;#160; While the CLR tracks outgoing ICorProfilerCallback* calls, it does not track any other way that control can enter your profiler DLL.&amp;#160; &lt;em&gt;Before&lt;/em&gt; your profiler calls RequestProfilerDetach:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;You must take care to deactivate all other ways control can enter your profiler DLL &lt;/li&gt;    &lt;li&gt;Your profiler must block until all those other ways control can enter your profiler DLL have verifiably been deactivated &lt;/li&gt; &lt;/ul&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9957933" width="1" height="1"&gt;</description></item><item><title>Generics and Your Profiler</title><link>http://blogs.msdn.com/b/davbr/archive/2010/01/28/generics-and-your-profiler.aspx</link><pubDate>Thu, 28 Jan 2010 18:17:38 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9954833</guid><dc:creator>David Broman</dc:creator><slash:comments>6</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.msdn.com/b/davbr/rsscomments.aspx?WeblogPostID=9954833</wfw:commentRss><comments>http://blogs.msdn.com/b/davbr/archive/2010/01/28/generics-and-your-profiler.aspx#comments</comments><description>&lt;p&gt;If you’re writing a profiler that you expect to run against CLR 2.0 or greater, you probably care about generics. Whether you're reporting call stacks or instrumenting code, it's possible the users of your profiler wrote some of that code using generic types. And if not, it's still quite likely they used generic types from libraries they depend on, such as those that ship with the .NET Framework. Reporting as much detail as you can, such as which type arguments were used to instantiate a generic type that appears in a call stack, can help your users diagnose their problems more effectively.&lt;/p&gt;  &lt;h2&gt;Terminology&lt;/h2&gt;  &lt;p&gt;Let's say a C# developer writes code like this: &lt;/p&gt; &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;  &lt;pre class="code"&gt;&lt;span style="color: rgb(0,0,255)"&gt;class&lt;/span&gt; &lt;span style="color: rgb(43,145,175)"&gt;MyClass&lt;/span&gt;&amp;lt;S&amp;gt;
{
    &lt;span style="color: rgb(0,0,255)"&gt;static&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;string&lt;/span&gt; Foo&amp;lt;T&amp;gt;(S instanceOfS, T instanceOfT)
    {
        &lt;span style="color: rgb(0,0,255)"&gt;return&lt;/span&gt; instanceOfS.ToString() + instanceOfT.ToString();
    }
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;Here we have a generic function, MyClass&amp;lt;S&amp;gt;.Foo&amp;lt;T&amp;gt;.&amp;#160; Let's say the developer instantiated MyClass &amp;amp; Foo by making the following function call:&lt;/p&gt;

&lt;pre class="code"&gt;MyClass&amp;lt;&lt;span style="color: rgb(0,0,255)"&gt;int&lt;/span&gt;&amp;gt;.Foo&amp;lt;&lt;span style="color: rgb(0,0,255)"&gt;float&lt;/span&gt;&amp;gt;(4, 8.8);&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;It's important to distinguish between &lt;strong&gt;function &lt;/strong&gt;arguments and &lt;strong&gt;type &lt;/strong&gt;arguments.&amp;#160; The function arguments are the dudes inside the parentheses—4 and 8.8 in the example above.&amp;#160; Type arguments are the things you find inside the angle brackets &amp;lt;&amp;gt;.&amp;#160; Foo is given one type argument, &lt;span style="color: rgb(0,0,255)"&gt;float&lt;/span&gt;.&amp;#160; Foo belongs to class MyClass, which itself is given the type argument, &lt;span style="color: rgb(0,0,255)"&gt;int&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;It’s worth spending a bit of time thinking about this.&amp;#160; When one sees the term “type arguments”, one might mistake that for “argument types”, or “types of the function arguments”, which in the above case would be &lt;span style="color: rgb(0,0,255)"&gt;int &lt;/span&gt;&lt;em&gt;and&lt;/em&gt; &lt;span style="color: rgb(0,0,255)"&gt;float, &lt;/span&gt;since the function takes two function arguments.&amp;#160; But this is not what I mean by “type argument”.&amp;#160; A “type argument” is what the developer provides in place of a generic type parameter that sits inside the angle brackets.&amp;#160; This is irrespective of what function arguments are passed to the function.&amp;#160; For example the generic function Alloc&amp;lt;U&amp;gt;:&lt;/p&gt;

&lt;pre class="code"&gt;    U Alloc&amp;lt;U&amp;gt;() { &lt;span style="color: rgb(0,0,255)"&gt;return&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;new&lt;/span&gt; U(); }&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;takes no function arguments at all, but it still requires a type argument (for the “U”) in order to be instantiated.&lt;/p&gt;

&lt;h2&gt;GetFunctionInfo2&lt;/h2&gt;

&lt;p&gt;So if you were to get the FunctionID for MyClass&amp;lt;&lt;span style="color: rgb(0,0,255)"&gt;int&lt;/span&gt;&amp;gt;.Foo&amp;lt;&lt;span style="color: rgb(0,0,255)"&gt;float&lt;/span&gt;&amp;gt;, and you passed that FunctionID to GetFunctionInfo2, what should you get back in the [out] parameters?&lt;/p&gt;

&lt;pre class="code"&gt;    HRESULT GetFunctionInfo2(
                [&lt;span style="color: rgb(0,0,255)"&gt;in&lt;/span&gt;] FunctionID funcId,
                [&lt;span style="color: rgb(0,0,255)"&gt;in&lt;/span&gt;] COR_PRF_FRAME_INFO frameInfo,
                [&lt;span style="color: rgb(0,0,255)"&gt;out&lt;/span&gt;] ClassID *pClassId,
                [&lt;span style="color: rgb(0,0,255)"&gt;out&lt;/span&gt;] ModuleID *pModuleId,
                [&lt;span style="color: rgb(0,0,255)"&gt;out&lt;/span&gt;] mdToken *pToken,
                [&lt;span style="color: rgb(0,0,255)"&gt;in&lt;/span&gt;] ULONG32 cTypeArgs,
                [&lt;span style="color: rgb(0,0,255)"&gt;out&lt;/span&gt;] ULONG32 *pcTypeArgs,
                [&lt;span style="color: rgb(0,0,255)"&gt;out&lt;/span&gt;] ClassID typeArgs[]);&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;*pClassId: This will be the ClassID for the instantiated MyClass&amp;lt;&lt;span style="color: rgb(0,0,255)"&gt;int&lt;/span&gt;&amp;gt;.&amp;#160; More on this later.&lt;/p&gt;

&lt;p&gt;*pModuleId: module defining the mdMethodDef token returned (see next parameter).&amp;#160; If funcId is a generic function defined in one module, its instantiating type arguments are defined in other modules, and the function is instantiated and called from yet another module, this parameter will always tell you that first module—the one containing the original definition of the generic function (i.e., funcId’s mdMethodDef).&lt;/p&gt;

&lt;p&gt;*pToken: This is the metadata token (mdMethodDef) for MyClass&amp;lt;S&amp;gt;.Foo&amp;lt;T&amp;gt;.&amp;#160; Note that you get the same mdMethodDef for any conceivable instantiation of a generic method.&lt;/p&gt;

&lt;p&gt;typeArgs[]: This is the array of &lt;strong&gt;type arguments&lt;/strong&gt; to MyClass&amp;lt;&lt;span style="color: rgb(0,0,255)"&gt;int&lt;/span&gt;&amp;gt;.Foo&amp;lt;&lt;span style="color: rgb(0,0,255)"&gt;float&lt;/span&gt;&amp;gt;.&amp;#160; So this will be an array of only one element: the ClassID for &lt;span style="color: rgb(0,0,255)"&gt;float&lt;/span&gt;.&amp;#160; (The &lt;span style="color: rgb(0,0,255)"&gt;int&lt;/span&gt; in MyClass&amp;lt;&lt;span style="color: rgb(0,0,255)"&gt;int&lt;/span&gt;&amp;gt; is a type argument to MyClass, not to Foo, and you would only see that when you call GetClassIDInfo2 with MyClass&amp;lt;&lt;span style="color: rgb(0,0,255)"&gt;int&lt;/span&gt;&amp;gt;.)&lt;/p&gt;

&lt;h2&gt;&lt;/h2&gt;

&lt;h2&gt;GetClassIDInfo2&lt;/h2&gt;

&lt;p&gt;OK, someone in parentheses said something about calling GetClassIDInfo2, so let’s do that.&amp;#160; Since we got the ClassID for MyClass&amp;lt;&lt;span style="color: rgb(0,0,255)"&gt;int&lt;/span&gt;&amp;gt; above, let’s pass it to GetClassIDInfo2 to see what we get:&lt;/p&gt;

&lt;pre class="code"&gt;    HRESULT GetClassIDInfo2(
                [&lt;span style="color: rgb(0,0,255)"&gt;in&lt;/span&gt;] ClassID classId,
                [&lt;span style="color: rgb(0,0,255)"&gt;out&lt;/span&gt;] ModuleID *pModuleId,
                [&lt;span style="color: rgb(0,0,255)"&gt;out&lt;/span&gt;] mdTypeDef *pTypeDefToken,
                [&lt;span style="color: rgb(0,0,255)"&gt;out&lt;/span&gt;] ClassID *pParentClassId,
                [&lt;span style="color: rgb(0,0,255)"&gt;in&lt;/span&gt;] ULONG32 cNumTypeArgs,
                [&lt;span style="color: rgb(0,0,255)"&gt;out&lt;/span&gt;] ULONG32 *pcNumTypeArgs,
                [&lt;span style="color: rgb(0,0,255)"&gt;out&lt;/span&gt;] ClassID typeArgs[]);&lt;/pre&gt;

&lt;p&gt;*pModuleId: module defining the mdTypeDef token returned (see next parameter).&amp;#160; If classId is a generic class defined in one module, its instantiating type arguments are defined in other modules, and the class is instantiated in yet another module, this parameter will always tell you that first module—the one containing the definition of the generic class (i.e., classId’s mdTypeDef).&lt;/p&gt;

&lt;p&gt;*pTypeDefToken: This is the metadata token (mdTypeDef) for MyClass&amp;lt;S&amp;gt;.&amp;#160; As with the mdMethodDef in the previous section, you’ll get the same mdTypeDef for any conceivable instantiation of MyClass&amp;lt;S&amp;gt;.&lt;/p&gt;

&lt;p&gt;*pParentClassId: As with any class, this [out] parameter will tell you the base class.&amp;#160; If the base class itself were a generic class, then this would be the ClassID for the fully instantiated base class.&amp;#160; You could then use GetClassIDInfo2 on *pParentClassId to determine its generic type arguments.&lt;/p&gt;

&lt;p&gt;typeArgs: This is the array of type arguments used to instantiate classId, which in the above example is MyClass&amp;lt;&lt;span style="color: rgb(0,0,255)"&gt;int&lt;/span&gt;&amp;gt;.&amp;#160; So in this example, typeArgs will be an array of only one element: the ClassID for &lt;span style="color: rgb(0,0,255)"&gt;int&lt;/span&gt;.&lt;/p&gt;

&lt;h2&gt;COR_PRF_FRAME_INFO&lt;/h2&gt;

&lt;p&gt;You may have noticed I ignored this parameter in my description of GetFunctionInfo2.&amp;#160; You can pass NULL if you want, and nothing really bad will happen to you, but you’ll often get some incomplete results: you won’t get very useful typeArgs coming back, and you’ll often see NULL returned in *pClassId.&lt;/p&gt;

&lt;p&gt;To understand why, it’s necessary to understand an internal optimization the CLR uses around sharing code for generics: If two instantiations of the same generic function would result in identical JITted code, then why not have them share one copy of that code?&amp;#160; The CLR chooses to share code if all of the type parameters are instantiated with reference types.&amp;#160; If you want to read more about this, &lt;a href="http://blogs.msdn.com/carlos/archive/2009/11/09/net-generics-and-code-bloat-or-its-lack-thereof.aspx"&gt;here’s&lt;/a&gt; a place to go.&lt;/p&gt;

&lt;p&gt;For now, the important point is that, once we’re inside JITted code that is shared across different generic instantiations, how can one know which instantiation is the actual one that caused the current invocation?&amp;#160; Well, in many cases, the CLR may not have that data readily lying around.&amp;#160; However, as a profiler, you can capture this information and pass it back to the CLR when it needs it.&amp;#160; This is done through a COR_PRF_FRAME_INFO.&amp;#160; There are two ways your profiler can get a COR_PRF_FRAME_INFO:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;span style="background-color: #00ff00"&gt;Via slow-path Enter/Leave/Tailcall probes&lt;/span&gt; &lt;/li&gt;

  &lt;li&gt;&lt;span style="background-color: #ff0000"&gt;Via your DoStackSnapshot callback&lt;/span&gt; &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I lied.&amp;#160; #1 is really the only way for your profiler to get a COR_PRF_FRAME_INFO.&amp;#160; #2 may seem like a way—at least the profiling API suggests that the CLR gives your profiler a COR_PRF_FRAME_INFO in the DSS callback—but unfortunately the COR_PRF_FRAME_INFO you get there is pretty useless.&amp;#160; I suspect the COR_PRF_FRAME_INFO parameter was added to the signature of the profiler’s DSS callback function so that it could “light up” at some point in the future when we could work on finding out how to create a sufficiently helpful COR_PRF_FRAME_INFO during stack walks.&amp;#160; However, that day has not yet arrived.&amp;#160; So if you want a COR_PRF_FRAME_INFO, you’ll need to grab it—and use it from—your slow-path Enter/Leave/Tailcall probe.&lt;/p&gt;

&lt;p&gt;With a valid COR_PRF_FRAME_INFO, GetFunctionInfo2 will give you helpful, specific ClassIDs in the typeArgs [out] array and pClassId [out] parameter.&amp;#160; If the profiler passes NULL for COR_PRF_FRAME_INFO, here’s what you can expect:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;If you’re using CLR V2, pClassId will point to NULL if the function sits on &lt;em&gt;any&lt;/em&gt; generic class (shared or not).&amp;#160; In CLR V4 this got a little better, and you’ll generally only see pClassId point to NULL if the function sits on a “shared” generic class (instantiated with reference types).&amp;#160; &lt;ul&gt;
      &lt;li&gt;Note: If it’s impossible for the profiler to have a COR_PRF_FRAME_INFO handy to pass to GetFunctionInfo2, and that results in a NULL *pClassID, the profiler can always use the metadata interfaces to find the mdTypeDef token of the class on which the function resides for the purposes of pretty-printing the class name to the user.&amp;#160; Of course, the profiler will not know the specific instantiating type arguments that were used on the class in that case. &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;

  &lt;li&gt;the typeArgs [out] array will contain the ClassID for &lt;strong&gt;System.__Canon&lt;/strong&gt;, rather than the actual instantiating type(s), if the function itself is generic and is instantiated with reference type argument(s). &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s worth noting here that there is a bug in GetFunctionInfo2, in that the [out] pClassId you get for the class containing the function can be wrong with generic virtual functions.&amp;#160; Take a look at &lt;a href="http://social.msdn.microsoft.com/Forums/en-US/netfxtoolsdev/thread/ed6f972f-712a-48df-8cce-74f8951503fa/"&gt;this forum post&lt;/a&gt; for more information and a workaround.&lt;/p&gt;

&lt;h2&gt;&lt;/h2&gt;

&lt;h2&gt;ClassIDs &amp;amp; FunctionIDs vs. Metadata Tokens&lt;/h2&gt;

&lt;p&gt;Although you can infer this from the above, let’s take a breather and review.&amp;#160; When you have multiple generic instantiations of a generic type, that type is defined with one mdTypeDef (metadata token), but you’ll see multiple ClassIDs (one per instantiation).&amp;#160; When you have multiple generic instantiations of a generic method, it’s defined with one mdMethodDef (metadata token), but you’ll see multiple FunctionIDs (one per instantiation).&lt;/p&gt;

&lt;p&gt;For example, if we have code that uses MyClass&amp;lt;&lt;span style="color: rgb(0,0,255)"&gt;int&lt;/span&gt;&amp;gt;.Foo&amp;lt;&lt;span style="color: rgb(0,0,255)"&gt;float&lt;/span&gt;&amp;gt; and MyClass&amp;lt;&lt;span style="color: rgb(0,0,255)"&gt;int&lt;/span&gt;&amp;gt;.Foo&amp;lt;&lt;span style="color: rgb(0,0,255)"&gt;long&lt;/span&gt;&amp;gt;, you will see two JITCompilationStarted/JITCompilationFinished pairs, with two different FunctionIDs (one for each instantiation).&amp;#160; But when you look up the metadata token for those two FunctionIDs via GetFunctionInfo2, you’ll get the same mdMethodDef.&lt;/p&gt;

&lt;p&gt;CLR’s generics sharing optimization complicates this somewhat.&amp;#160; You’ll really only see separate JIT notifications and separate FunctionIDs for different &lt;em&gt;unshared &lt;/em&gt;instantiations, and not necessarily for every different instantiation.&amp;#160; So if instead we have code that uses MyClass&amp;lt;&lt;span style="color: rgb(0,0,255)"&gt;object&lt;/span&gt;&amp;gt;.Foo&amp;lt;&lt;span style="color: rgb(0,0,255)"&gt;string&lt;/span&gt;&amp;gt; and MyClass&amp;lt;&lt;span style="color: rgb(0,0,255)"&gt;SomeClassICreated&lt;/span&gt;&amp;gt;.Foo&amp;lt;&lt;span style="color: rgb(0,0,255)"&gt;AnotherClassICreated&lt;/span&gt;&amp;gt;, you may only see one JITCompilationStarted/JITCompilationFinished pair, with only one FunctionID (representing the instantiation using System.__Canon for the type arguments).&amp;#160; I say “may”, because generics sharing is an internal CLR optimization that can change at any time without affecting the correctness of managed code.&amp;#160; So your profiler cannot rely on a particular scheme the CLR may use to share generic code.&amp;#160; But it would be wise to be aware that sharing &lt;em&gt;can&lt;/em&gt; happen, so your profiler can deal with it appropriately.&lt;/p&gt;

&lt;p&gt;So that covers JIT notifications—what about ClassLoad* notifications in the same example?&amp;#160; Although the CLR shares &lt;em&gt;JITted code&lt;/em&gt; across reference-type instantiations, the CLR still maintains separate loaded &lt;em&gt;types&lt;/em&gt; for each generic instantiation of a generic class.&amp;#160; So in the example from the paragraph above you will see separate ClassLoad* notifications with different ClassIDs for MyClass&amp;lt;&lt;span style="color: rgb(0,0,255)"&gt;object&lt;/span&gt;&amp;gt; and MyClass&amp;lt;&lt;span style="color: rgb(0,0,255)"&gt;SomeClassICreated&lt;/span&gt;&amp;gt;.&amp;#160; In fact, you will also see a separate ClassLoad* notification (with yet another ClassID) for MyClass&amp;lt;&lt;span style="color: rgb(0,0,255)"&gt;System.__Canon&lt;/span&gt;&amp;gt;.&lt;/p&gt;

&lt;p&gt;If you got curious, and ran such a profiler under the debugger, you could use the SOS !dumpmt command with those different ClassIDs to see what you get.&amp;#160; By doing so, you’ll notice something interesting.&amp;#160; !dumpmt shows many values, including “Name”, which will correctly be the specific, fully-instantiated name of the type (different for all three ClassIDs).&amp;#160; !dumpmt also shows a thing called “EEClass”.&amp;#160; And you’ll notice this “EEClass” value is actually the &lt;em&gt;same &lt;/em&gt;for all 3 types.&amp;#160; (Remember from this &lt;a href="http://blogs.msdn.com/davbr/archive/2007/12/18/debugging-your-profiler-ii-sos-and-ids.aspx"&gt;post&lt;/a&gt; that EEClass is NOT the same thing as ClassID!)&amp;#160; That gives you a little window into some additional data sharing optimizations the CLR uses.&amp;#160; Stuff that remains the same across different generic instantiations of a class can be stored in a single place (the EEClass) and that single place can be referenced by the different generic instantiations of the class.&amp;#160; Note that if you also use a value type as the type argument when instantiating MyClass&amp;lt;T&amp;gt; (e.g., MyClass&amp;lt;&lt;span style="color: rgb(0,0,255)"&gt;int&lt;/span&gt;&amp;gt;), and then run !dumpmt on that ClassID, you’ll see an entirely different EEClass value in the output, as the CLR will not be sharing that subset of type data across generic instantiations that use type arguments that are value types.&lt;/p&gt;

&lt;h2&gt;Instrumenting Generic Functions&lt;/h2&gt;

&lt;p&gt;If your profiler performs IL rewriting, it’s important to understand that it must NOT do instantiation-specific IL rewriting.&amp;#160; Huh?&amp;#160; Let’s take an example.&amp;#160; Suppose you’re profiling code that uses MyClass&amp;lt;&lt;span style="color: rgb(0,0,255)"&gt;int&lt;/span&gt;&amp;gt;.Foo&amp;lt;&lt;span style="color: rgb(0,0,255)"&gt;float&lt;/span&gt;&amp;gt; and MyClass&amp;lt;&lt;span style="color: rgb(0,0,255)"&gt;int&lt;/span&gt;&amp;gt;.Foo&amp;lt;&lt;span style="color: rgb(0,0,255)"&gt;long&lt;/span&gt;&amp;gt;.&amp;#160; Your profiler will see two JITCompilationStarted callbacks, and will have two opportunities to rewrite the IL.&amp;#160; Your profiler may call GetFunctionInfo2 on those two FunctionIDs and determine that they’re two different instantiations of the same generic function.&amp;#160; You may then be tempted to make use of the fact that one is instantiated with &lt;span style="color: rgb(0,0,255)"&gt;float&lt;/span&gt;, and the other with &lt;span style="color: rgb(0,0,255)"&gt;long&lt;/span&gt;, and provide different IL for the two different JIT compilations.&amp;#160; The problem with this is that the IL stored in metadata, as well as the IL provided to SetILFunctionBody, is always specified relative to the mdMethodDef.&amp;#160; (Remember, SetILFunctionBody doesn’t take a FunctionID as input; it takes an mdMethodDef.)&amp;#160; And it’s the profiler’s responsibility always to specify the same rewritten IL for any given mdMethodDef no matter how many times it’s JITted.&amp;#160; And a given mdMethodDef can be JITted multiple times due to a number of reasons:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Two threads simultaneously trying to call the same function for the first time (and thus both trying to JIT that function) &lt;/li&gt;

  &lt;li&gt;Strange dependency chains involving class constructors (more on this in the MSDN &lt;a href="http://msdn.microsoft.com/en-us/library/ms230586.aspx"&gt;reference topic&lt;/a&gt;) &lt;/li&gt;

  &lt;li&gt;Multiple AppDomains using the same (non-domain-neutral) function &lt;/li&gt;

  &lt;li&gt;And of course multiple generic instantiations! &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Regardless of the reason, the profiler must always rewrite with exactly the same IL.&amp;#160; Otherwise, an invariant in the CLR will have been broken by the profiler, and you will get strange, undefined behavior as a result.&amp;#160; And no one wants that.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;That’s it!&amp;#160; Hopefully this gives you a good idea of how the CLR Profiling API will behave in the face of generic classes and functions, and what is expected of your profiler.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9954833" width="1" height="1"&gt;</description></item><item><title>Writing a Profiler for Silverlight 4</title><link>http://blogs.msdn.com/b/davbr/archive/2010/01/21/writing-a-profiler-for-silverlight-4.aspx</link><pubDate>Fri, 22 Jan 2010 00:36:36 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9951729</guid><dc:creator>David Broman</dc:creator><slash:comments>5</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.msdn.com/b/davbr/rsscomments.aspx?WeblogPostID=9951729</wfw:commentRss><comments>http://blogs.msdn.com/b/davbr/archive/2010/01/21/writing-a-profiler-for-silverlight-4.aspx#comments</comments><description>&lt;p&gt;The Silverlight 4 beta has been released a while ago (see &lt;a href="http://silverlight.net/getstarted/silverlight-4-beta/"&gt;this&lt;/a&gt;), and one of the new features in Silverlight 4 is the ability to use the very same profiling API that is available for regular CLR-based apps (referred to as “desktop” CLR apps).&amp;#160; In this post I’ll talk about how to create a profiler that uses the CLR profiling API on Silverlight 4.&amp;#160; I assume you are already familiar with creating profilers for the desktop CLR.&lt;/p&gt;  &lt;h2&gt;Getting Started&lt;/h2&gt;  &lt;h3&gt;Requirements&lt;/h3&gt;  &lt;p&gt;Install Silverlight 4 beta!&amp;#160; (See link above.)&amp;#160; It is sufficient to simply install the Windows Silverlight Developer runtime.&amp;#160; You don’t need the full Silverlight 4 Beta Tools for Visual Studio 2010 to write and test your profiler.&lt;/p&gt;  &lt;p&gt;Note that, in order to have full functionality, you and your users will need the Windows Silverlight &lt;strong&gt;Developer&lt;/strong&gt; runtime, and not just the typical Windows Silverlight runtime.&amp;#160; The reason is that some of the profiling API methods require the debugging infrastructure to be completely initialized and available, and that is ensured by installing the Windows Silverlight Developer runtime.&amp;#160; For example, if you attempt to call SetILInstrumentedCodeMap() or GetILToNativeMapping() without a fully initialized debugging infrastructure, then they will fail with CORPROF_E_DEBUGGING_DISABLED.&amp;#160; Your main concern, though, should be that our testing of the profiling API on Silverlight is done with a Developer runtime only.&amp;#160; So we can’t comment on how well or poorly profiling will go without the Developer runtime.&amp;#160; Also, the number of profiling API methods that will fail on Silverlight without the Developer runtime may change at any time without notice (or without us even realizing). &lt;/p&gt;  &lt;p&gt;It is expected that, in most scenarios, it should not be too much of a burden to require the Silverlight Developer runtime, as your users will typically be developers of Silverlight applications (who already need the Developer runtime anyway).&amp;#160; However, it is true that some profiling API-based tools are not really targeted at developers (e.g., some tools may monitor the flow of multi-tiered applications throughout an enterprise, including the end user client Silverlight tier).&amp;#160; So for those of you in that situation, you will need to take care to ensure your users have installed the Developer runtime.&amp;#160; A member of the Silverlight team tells me a good way to do this is to check for the existence of this registry key/value:&lt;/p&gt;  &lt;p&gt;HKEY_LOCAL_MACHINE\software\(Wow6432Node on 64-bit boxes)\microsoft\silverlight\Components\Debugging    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; Version&amp;#160;&amp;#160;&amp;#160; REG_SZ&amp;#160;&amp;#160;&amp;#160; 4.0.50113.0 &lt;/p&gt;  &lt;p&gt;You should also ensure that the above Version string matches the Version value of the runtime which is stored in the grandparent key:&lt;/p&gt;  &lt;p&gt;HKEY_LOCAL_MACHINE\software\(Wow6432Node on 64-bit boxes)\microsoft\silverlight    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; Version&amp;#160;&amp;#160;&amp;#160; REG_SZ&amp;#160;&amp;#160;&amp;#160; 4.0.50113.0 &lt;/p&gt;  &lt;p&gt;If a user had the Developer runtime installed and “upgraded” to a newer end-user runtime the registry will still report the Debugging components but the version will be the old version, which for our purposes is the same as not having a Developer runtime installed at all.&amp;#160; Doing the comparison above ensures you catch that case, and can tell your user to install the latest Developer runtime.&lt;/p&gt;  &lt;h3&gt;Coding and Activation&lt;/h3&gt;  &lt;p&gt;A philosophy we have with enabling the profiling API on Silverlight is that it should be easy to reuse code and binaries from desktop CLR profilers, but we still wanted to ensure that a desktop profiler does not accidentally get activated in a Silverlight app.&amp;#160; To that end, we’ve kept the interfaces and their IIDs the same, but we’ve changed the environment variables.&lt;/p&gt;  &lt;p&gt;So, you will not need to create another copy of your callback interface implementation, or keep separate IIDs around for the Info interfaces you query for.&amp;#160; Your very same CLR V4-desktop-based code will now target Silverlight 4 apps as well.&lt;/p&gt;  &lt;p&gt;In order for your profiler to be activated against Silverlight, you will need to use the following environment variables:&lt;/p&gt;  &lt;table cellspacing="0" cellpadding="2" width="794" border="1"&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td valign="top" width="205"&gt;CORECLR_ENABLE_PROFILING&lt;/td&gt;        &lt;td valign="top" width="587"&gt;same meaning as COR_ENABLE_PROFILING has on desktop&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="210"&gt;CORECLR_PROFILER&lt;/td&gt;        &lt;td valign="top" width="587"&gt;same meaning as COR_PROFILER has on desktop&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="214"&gt;CORECLR_PROFILER_PATH&lt;/td&gt;        &lt;td valign="top" width="587"&gt;same meaning as COR_PROFILER_PATH has on desktop          &lt;br /&gt;(this is optional, if you want to use &lt;a href="http://blogs.msdn.com/davbr/archive/2009/06/16/clr-v4-load-your-profiler-without-using-the-registry.aspx"&gt;registry-free activation&lt;/a&gt;)&lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;  &lt;p&gt;By keeping the environment variables different between Silverlight and desktop, we not only prevent desktop profilers from being accidentally activated in Silverlight apps, but we also prevent a profiler from accidentally getting instantiated twice in some processes.&amp;#160; Imagine: Someone writes a desktop CLR app that renders web pages, and inside one of those web pages is a Silverlight control that hosts Silverlight apps.&amp;#160; Or perhaps Internet Explorer is rendering a Silverlight page in one tab and a page with a CLR Click-Once app in another tab.&amp;#160; If a single set of environment variables controlled both desktop and Silverlight apps, then a profiler would get instantiated twice.&amp;#160; This is not necessarily bad—unless the profiler was not prepared for such an activation.&amp;#160; If you carefully code your profiler to avoid most global state (as would be necessary for enabling profiling of multiple in-process side-by-side CLR instances), then your profiler might well be fully capable of supporting two instances in the same process—one working with the Silverlight runtime, and the other working with a desktop CLR.&amp;#160; In such a case, feel free to set all environment variables (both the CORECLR_* and COR_* flavors) to enable simultaneous profiling of desktop and Silverlight runtimes, if that’s something you’d like to support.&lt;/p&gt;  &lt;h2&gt;Behavioral Differences Between Silverlight and Desktop Profiling&lt;/h2&gt;  &lt;p&gt;Although your very same code may be used to target both Silverlight and Desktop, you will likely need to have some conditional logic to deal with some behavioral differences between the two platforms.&amp;#160; (You may use &lt;a href="http://msdn.microsoft.com/en-us/library/dd490900(VS.100).aspx"&gt;ICorProfilerInfo3::GetRuntimeInformation&lt;/a&gt; to determine whether a given runtime is the desktop CLR (COR_PRF_DESKTOP_CLR) or Silverlight CLR (COR_PRF_CORE_CLR).)&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;No attach / detach on Silverlight&lt;/strong&gt;.&amp;#160; Although the ability to attach to and detach from running processes is a new feature enabled on CLR V4, this feature is not available on Silverlight 4.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Don’t rely on receiving the Shutdown() callback on Silverlight&lt;/strong&gt;.&amp;#160; Really, you can’t rely on Shutdown() on the desktop CLR either, as per the MSDN &lt;a href="http://msdn.microsoft.com/en-us/library/ms230217(VS.100).aspx"&gt;topic&lt;/a&gt;, though this callback looks to be even more unreliable on Silverlight.&amp;#160; Your profiler receives the Shutdown() callback depending on how the CLR is terminated, and it’s looking like Silverlight terminates the CLR in the “abrupt” fashion where most shutdown logic is skipped (including the call to the Shutdown() profiler callback).&amp;#160; So it will be best if you use your DllMain as a backup for ensuring your cleanup code gets run. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;No event logging.&lt;/strong&gt;&amp;#160; Silverlight generally does not use the Windows event log for anything.&amp;#160; When developing (or using) a profiler on the desktop CLR, the event log is useful for detecting and diagnosing problems with loading the profiler.&amp;#160; On Silverlight, these messages are routed to your debugger if you’re debugging the process hosting Silverlight, and the messages are not sent anywhere if you’re not debugging.&amp;#160; That means that, if you’re having issues diagnosing activation problems with your profiler, run the Silverlight process under a debugger like VS or windbg and look in the output window for messages that indicate whether Silverlight attempted to load a profiler, whether the load succeeded, and if not, why.&lt;/p&gt;  &lt;h3&gt;IL Rewriting&lt;/h3&gt;  &lt;p&gt;Doing run-time IL rewriting (or “instrumentation”) on Silverlight has enough differences from desktop that it warrants its own section.&amp;#160; As a review, the APIs involved in IL Rewriting are described &lt;a href="http://blogs.msdn.com/davbr/archive/2007/03/06/creating-an-il-rewriting-profiler.aspx"&gt;here&lt;/a&gt;.&amp;#160; You will generally use these same APIs on Silverlight, but will encounter differences when your rewritten IL tries to do stuff, like call into your own managed helper assembly.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Security&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;First, realize that user Silverlight assemblies generally run under partial trust, with fairly restricted permissions.&amp;#160; (Full trust is reserved for the Microsoft-provided platform code, such as mscorlib.dll.)&amp;#160; So when you instrument partial trust code, keep in mind your rewritten IL will be under those same restrictions.&amp;#160; It is therefore best to avoid doing any security-sensitive operations, or if necessary, moving those operations to new Critical methods you dynamically add to mscorlib, with SafeCritical bridge code in the middle.&amp;#160; Read the security section from this &lt;a href="http://blogs.msdn.com/davbr/archive/2010/01/07/clr-v4-stuff-that-may-break-your-profiler.aspx"&gt;blog post&lt;/a&gt; for more information. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Shipping Managed Helper Code&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Many profilers rewrite user IL to call into managed “helper code” shipped by the profiler vendor.&amp;#160; This helper code is usually a centralized place to perform whatever logging is necessary to record that certain events have occurred (e.g., a call was made, a local variable was modified, etc.).&amp;#160; On Silverlight, you have a couple options on how to ship this helper code.&lt;/p&gt;  &lt;p&gt;&lt;u&gt;Option 1: Pump helper code into mscorlib&lt;/u&gt;&lt;/p&gt;  &lt;p&gt;As you may recall, when profiling desktop CLR apps, it is illegal to add a reference from mscorlib to any other assembly.&amp;#160; Therefore, if your profiler instruments mscorlib methods, then that rewritten IL is forbidden to directly call into a separate helper assembly.&amp;#160; One workaround for this is for all helper code to be added into mscorlib at runtime via IMetaDataEmit.&amp;#160; This workaround is valid on Silverlight as well, and is therefore a perfectly valid option for how to ship your helper code—just pump it into mscorlib at run-time.&amp;#160; You will need to do this sort of thing anyway if any of your helper code needs to run at full-trust (e.g., if it needs to P/Invoke).&lt;/p&gt;  &lt;p&gt;&lt;u&gt;Option 2: Ship separate helper managed module that you inject into the XAP.&lt;/u&gt;&lt;/p&gt;  &lt;p&gt;If your profiler does not need to instrument mscorlib, and can get its work done using partial-trust code (which is preferable), then option 1 is still a reasonable solution.&amp;#160; But your profiler may also do the following, which you may decide is easier to manage:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Develop, compile, and ship a helper managed module containing helper methods that the instrumented code calls into (just like on desktop) &lt;/li&gt;    &lt;li&gt;Get this helper managed module into the XAP somehow (see below) &lt;/li&gt;    &lt;li&gt;Instrument user code to call into your helper managed module, the usual way (using IMetaDataEmit to generate an AssemblyRef and any necessary TypeRefs, MemberRefs, etc., from the user’s module to your helper managed module). &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;For achieving step 2, you have a couple options: &lt;/p&gt;  &lt;p&gt;(2a) (preferred): If at all possible, you may wish to integrate your profiler with Visual Studio so that the build process itself can ensure the profiler's helper managed module finds its way into the XAP.&amp;#160; (More on this below.)&lt;/p&gt;  &lt;p&gt;(2b) (fallback): There will likely be scenarios where profilers will not be able to participate in the build process.&amp;#160; In these cases, the profiler's helper managed module must find its way into the XAP &lt;em&gt;after &lt;/em&gt;the XAP has been built.&amp;#160; In order to do this, you simply treat the XAP file like the zip file it really is:&lt;/p&gt;  &lt;p&gt;(i) Unzip the XAP    &lt;br /&gt;(ii) Add your managed helper module to the XAP     &lt;br /&gt;(iii) Modify the XAP's manifest (this is a special file in every XAP that lists the assemblies contained in the XAP)     &lt;br /&gt;(iv) Rezip the XAP &lt;/p&gt;  &lt;p&gt;For (2a) (getting the VS build system to include your helper managed module in the XAP), here is what I learned from the Silverlight tools folks…&lt;/p&gt;  &lt;p&gt;The items that get added to the XAP at build-time are roughly the following: &lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Built assembly &lt;/li&gt;    &lt;li&gt;AppManifest.xaml &lt;/li&gt;    &lt;li&gt;References marked &lt;strong&gt;CopyLocal&lt;/strong&gt; and their dependencies. If you have enabled “Reduce XAP size by using application cacheing”, assemblies that support this feature will not be included in the XAP (they get their own zip file). &lt;/li&gt;    &lt;li&gt;&lt;span style="background-color: #ffff00"&gt;Any project items marked &lt;strong&gt;Content&lt;/strong&gt;&lt;/span&gt; &lt;/li&gt;    &lt;li&gt;Satellite assemblies built by the project, or picked up by references, that match the &amp;lt;SupportedCultures&amp;gt; property. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;The easiest way to get your helper managed module into the XAP file is probably to add it as a &lt;strong&gt;Content&lt;/strong&gt; file to the project.&amp;#160; For example: &lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Create a new Silverlight project &lt;/li&gt;    &lt;li&gt;Edit the project file to uncomment the &lt;strong&gt;BeforeBuild&lt;/strong&gt; target and add the following to it: &lt;/li&gt; &lt;/ol&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;span style="font-size: 9.5pt; color: blue; font-family: consolas"&gt;&amp;lt;&lt;/span&gt;&lt;span style="font-size: 9.5pt; color: #a31515; font-family: consolas"&gt;Target&lt;/span&gt;&lt;span style="font-size: 9.5pt; color: blue; font-family: consolas"&gt; &lt;/span&gt;&lt;span style="font-size: 9.5pt; color: red; font-family: consolas"&gt;Name&lt;/span&gt;&lt;span style="font-size: 9.5pt; color: blue; font-family: consolas"&gt;=&lt;/span&gt;&lt;span style="font-size: 9.5pt; font-family: consolas"&gt;&amp;quot;&lt;span style="color: blue"&gt;BeforeBuild&lt;/span&gt;&amp;quot;&lt;font color="#0000ff"&gt;&amp;gt;          &lt;br /&gt;&lt;/font&gt;&lt;/span&gt;&lt;span style="font-size: 9.5pt; color: blue; font-family: consolas"&gt;&amp;#160;&amp;#160;&amp;#160; &amp;lt;&lt;/span&gt;&lt;span style="font-size: 9.5pt; color: #a31515; font-family: consolas"&gt;ItemGroup&lt;/span&gt;&lt;span style="font-size: 9.5pt; color: blue; font-family: consolas"&gt;&amp;gt;        &lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 9.5pt; color: blue; font-family: consolas"&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;&lt;/span&gt;&lt;span style="font-size: 9.5pt; color: #a31515; font-family: consolas"&gt;ContentWithTargetPath&lt;/span&gt;&lt;span style="font-size: 9.5pt; color: blue; font-family: consolas"&gt; &lt;/span&gt;&lt;span style="font-size: 9.5pt; color: red; font-family: consolas"&gt;Include&lt;/span&gt;&lt;span style="font-size: 9.5pt; color: blue; font-family: consolas"&gt;=&lt;/span&gt;&lt;span style="font-size: 9.5pt; font-family: consolas"&gt;&amp;quot;&lt;span style="color: blue"&gt;PathToMyHelperManagedModule.Dll&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt; /&amp;gt;          &lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 9.5pt; color: blue; font-family: consolas"&gt;&amp;#160;&amp;#160;&amp;#160; &amp;lt;/&lt;/span&gt;&lt;span style="font-size: 9.5pt; color: #a31515; font-family: consolas"&gt;ItemGroup&lt;/span&gt;&lt;span style="font-size: 9.5pt; color: blue; font-family: consolas"&gt;&amp;gt;        &lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 9.5pt; color: blue; font-family: consolas"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="font-size: 9.5pt; color: #a31515; font-family: consolas"&gt;Target&lt;/span&gt;&lt;span style="font-size: 9.5pt; color: blue; font-family: consolas"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;The key here is that we’re adding the DLL to the &lt;strong&gt;ContentWithTargetPath&lt;/strong&gt; item collection, the contents of which get added to the XAP file.&amp;#160; You should also be able to leverage msbuild if you like.&amp;#160;&amp;#160; &lt;/p&gt;  &lt;h2&gt;IE8 &amp;amp; child processes&lt;/h2&gt;  &lt;p&gt;Starting with Internet Explorer 8, tabs may be rendered via child processes, and not the iexplore.exe that was originally spawned by the user.&amp;#160; Some profiler products use a GUI shell to spawn the profilee (in this case the profilee would be iexplore.exe) and then communicate with the profiler DLL inside that process to allow the user to view and control information about the running application.&amp;#160; With IE8, the iexplore.exe that’s spawned by your shell may not be the process rendering the Silverlight control (and thus loading your profiler DLL).&amp;#160; So if you use such an architecture, and if your GUI shell needs to know the process ID of the process actually rendering the Silverlight application (and thus loading your profiler), this wouldn’t work out so well.&amp;#160; Thus, instead of directly spawning iexplore.exe, your shell should instead use &lt;a href="http://msdn.microsoft.com/en-us/library/aa767962(VS.85).aspx"&gt;IELaunchURL&lt;/a&gt;() to spawn IE and tell you the real ID of the process actually rendering the Silverlight app.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;There you go!&amp;#160; If you’ve ever thought about modifying your profiler to target Silverlight, now is the time to download the Silverlight 4 Beta and give it a whirl.&amp;#160; Hopefully you should be able to keep most of your code intact, only customizing specific code paths that need to be different on Silverlight.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9951729" width="1" height="1"&gt;</description></item><item><title>CLR V4: Profiler Attach Part 2: Ok, now what?</title><link>http://blogs.msdn.com/b/davbr/archive/2010/01/18/clr-v4-profiler-attach-part-2-ok-now-what.aspx</link><pubDate>Mon, 18 Jan 2010 22:34:06 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9950025</guid><dc:creator>David Broman</dc:creator><slash:comments>4</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.msdn.com/b/davbr/rsscomments.aspx?WeblogPostID=9950025</wfw:commentRss><comments>http://blogs.msdn.com/b/davbr/archive/2010/01/18/clr-v4-profiler-attach-part-2-ok-now-what.aspx#comments</comments><description>&lt;p&gt;In a previous &lt;a href="http://blogs.msdn.com/davbr/archive/2009/11/04/clr-v4-profiler-attach-basics-with-sample-code.aspx"&gt;post&lt;/a&gt;, I outlined to all you profiler writers how to modify your profiler so it can attach to running processes, and what sorts of limitations your profiler will have when it attaches.&amp;#160; In this post, I answer the question, “My profiler is attached.&amp;#160; What should it do next?”&lt;/p&gt;  &lt;h1&gt;Catch Up&lt;/h1&gt;  &lt;p&gt;A profiler that loads on startup of an application has the option to know the entire history of that application.&amp;#160; By requesting the appropriate callback events, the profiler can know all the classes and modules that have loaded, functions that have JITted, objects that have been allocated, etc.&amp;#160; However, a profiler that loads by attaching to an already-running application is a bit like Dorothy who lands in the middle of Oz and has no idea what’s going on.&amp;#160; She doesn’t have the luxury of arriving at the beginning of time, and watching everyone from the moment of their birth.&amp;#160; She runs into people after they’re fully grown, and is expected to deal gracefully—often by making friends with them.&amp;#160; It would not be socially acceptable for Dorothy to encounter an access violation upon meeting someone new.&lt;/p&gt;  &lt;table cellspacing="0" cellpadding="0" width="797" border="0"&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td valign="top" width="795"&gt;         &lt;p align="center"&gt;&lt;a href="http://blogs.msdn.com/photos/davbr/images/9949892/original.aspx"&gt;&lt;img title="NoBirthAnnouncement" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="444" alt="NoBirthAnnouncement" src="http://blogs.msdn.com/photos/davbr/images/9949892/640x466.aspx" width="609" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;       &lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="795"&gt;         &lt;p align="center"&gt;&lt;font face="Arial" size="1"&gt;Drawing by Magdalena Hermawan&lt;/font&gt;&lt;/p&gt;       &lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;There are two fundamental ways your profiler can catch up on the current state of an application:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Lazy catch-up—as the profiler encounters new IDs, the profiler queries information about those IDs as it needs them, rather than assuming it has a full cache that’s always built up as the IDs are first created.&amp;#160; This is analogous to Dorothy meeting a new grown-up, and gracefully accepting the fact that that person exists. &lt;/li&gt;    &lt;li&gt;Enumeration—for certain kinds of IDs, the profiler can (at attach time) request a complete list of the currently active IDs and query information about them at that time.&amp;#160; Sort of like Dorothy first going to the Oz City Hall and looking up the birth records for everyone. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Lazy catch-up is fairly self-explanatory.&amp;#160; For example, if your sampling profiler encounters an IP in a FunctionID you’ve never seen before, just look up whatever info you need about that FunctionID the first time you encounter it, rather than assuming you’d already built up a cache when the function was first JITted.&amp;#160; And if you discover that FunctionID resides in a module you’ve never seen before, then just look up whatever info you need about that ModuleID at that point, rather than assuming you already have a complete cache of all modules.&amp;#160; Many of you are already doing something like this today if you support sampling against regular NGENd images (since you don’t get JIT notifications of those functions anyway).&lt;/p&gt;  &lt;p&gt;Enumeration, on the other hand, has some caveats and is worthwhile to describe in more detail.&lt;/p&gt;  &lt;h1&gt;Enumeration via Enum* APIs&lt;/h1&gt;  &lt;p&gt;Some kinds of IDs have new enumerator methods as part of the profiling API.&amp;#160; In particular:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;ICorProfilerInfo3::EnumModules &lt;/li&gt;    &lt;li&gt;ICorProfilerInfo3::EnumJITedFunctions &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Your profiler calls these methods, and they return a standard enumerator you use to iterate through all of the currently-loaded IDs of that type.&amp;#160; It’s worth noting that EnumJITedFunctions only enumerates FunctionIDs for which you would receive JITCompilationStarted/Finished events, and will not include FunctionIDs from NGENd modules.&lt;/p&gt;  &lt;p&gt;The primary caveat with using these enumerators is that you’re iterating through a snapshot of the IDs while the process is active and running.&amp;#160; (Imagine Dorothy looking through a copy of birth records while babies are still getting born in Oz, who weren’t yet in the copy of records Dorothy is reading.)&amp;#160; This means there are races your profiler needs to be resilient to.&lt;/p&gt;  &lt;h2&gt;Race #1: When to enumerate?&amp;#160; ProfilerAttachComplete()&lt;/h2&gt;  &lt;p&gt;As you may recall, once your profiler is attached to the process, the CLR calls InitializeForAttach() on your profiler.&amp;#160; After your profiler returns from InitializeForAttach(), the CLR turns on callbacks into your profiler.&amp;#160; So if your profiler requested COR_PRF_MONITOR_MODULE_LOADS (by calling SetEventMask() at some point inside your implementation of InitializeForAttach), then as modules start loading and unloading after InitializeForAttach() returns, your profiler will receive the corresponding events.&amp;#160; The thing is, “after InitializeForAttach() returns” is a vague phrase.&amp;#160; And modules can load or unload at totally arbitrary times with respect to the timing of when your profiler attaches and calls EnumModules().&amp;#160; The thing to avoid here is a hole: a ModuleID your profiler does not find in the enumeration, and for which your profiler receives no ModuleLoad event.&amp;#160; This can happen if your profiler calls the enumeration API too soon (i.e., before CLR has enabled event callbacks for your profiler).&lt;/p&gt;  &lt;p&gt;Bad timeline (loading; enumerating too soon):&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Profiler attaches &lt;/li&gt;    &lt;li&gt;Profiler calls EnumModules &lt;/li&gt;    &lt;li&gt;Module starts to load &lt;/li&gt;    &lt;li&gt;ModuleID is now enumerable &lt;/li&gt;    &lt;li&gt;ModuleLoadFinished event would fire here if events were enabled (but they’re not yet!) &lt;/li&gt;    &lt;li&gt;CLR enables events &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;The problem is that the profiler calls EnumModules too early.&amp;#160; If your profiler only calls EnumModules after CLR enables events, then you’re assured of either seeing a ModuleID via EnumModules or via a ModuleLoad event.&amp;#160; In the above scenario, your profiler might as well have never done enumeration at all, since it will still not be notified of the ModuleID before it comes across that ModuleID in action later on.&amp;#160; It gets even worse for modules that unload:&lt;/p&gt;  &lt;p&gt;Bad timeline (unloading; enumerating too soon):&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Module loads &lt;/li&gt;    &lt;li&gt;ModuleID is now enumerable &lt;/li&gt;    &lt;li&gt;Profiler attaches &lt;/li&gt;    &lt;li&gt;Profiler calls EnumModules (includes the ModuleID) &lt;/li&gt;    &lt;li&gt;Module starts to unload &lt;/li&gt;    &lt;li&gt;ModuleUnloadStarted event would fire here if events were enabled (but they’re not yet!) &lt;/li&gt;    &lt;li&gt;CLR enables events &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;In the above case, the profiler discovers a ModuleID via EnumModules, but has no idea that the module is now in the process of unloading.&amp;#160; So the profiler might query information about the stale ModuleID, potentially causing an AV.&amp;#160; Again, this is caused because the profiler called the enumeration API too soon (i.e., before the CLR enabled event callbacks).&lt;/p&gt;  &lt;p&gt;The solution is for the profiler to call enumeration APIs only after events have been enabled.&amp;#160; Since events are enabled at some point “after InitializeForAttach() returns”, it was necessary for the CLR to provide a new API to notify the profiler that event callbacks have actually been enabled: ICorProfilerCallback3::ProfilerAttachComplete().&amp;#160; &lt;strong&gt;The best place for your profiler to call the enumeration APIs is inside its implementation of ProfilerAttachComplete.&lt;/strong&gt;&amp;#160; Since events are enabled &lt;em&gt;just before &lt;/em&gt;the CLR calls ProfilerAttachComplete, your profiler is assured that events are enabled by the time it calls the enumeration API (from inside ProfilerAttachComplete).&amp;#160; This eliminates any potential holes in catch-up information your profiler queries.&lt;/p&gt;  &lt;h2&gt;Race #2: Duplicates&lt;/h2&gt;  &lt;p&gt;When your profiler calls the Enum* methods, the CLR creates a snapshot of all “enumerable” IDs of the specified type, and gives your profiler an enumerator over those.&amp;#160; In the CLR we had a choice.&amp;#160; We could either consider an ID to be “enumerable” before or after the corresponding load finished event (or JITCompilationFinished event) would normally be issued.&amp;#160; Consider for a moment what we &lt;em&gt;didn’t&lt;/em&gt; do.&amp;#160; We didn’t consider IDs to be enumerable after the event.&amp;#160; If so, that would have led to holes.&amp;#160; A profiler could have attached and grabbed an enumeration in the middle and never been notified about the ID.&lt;/p&gt;  &lt;p&gt;Bad timeline (loading):&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Module starts to load &lt;/li&gt;    &lt;li&gt;ModuleLoadFinished event would fire here if events were enabled (but they’re not yet—no profiler is attached!) &lt;/li&gt;    &lt;li&gt;Profiler attaches &lt;/li&gt;    &lt;li&gt;CLR enables events, calls ProfilerAttachComplete() &lt;/li&gt;    &lt;li&gt;Profiler calls EnumModules &lt;/li&gt;    &lt;li&gt;ModuleID is now enumerable &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Because 2 comes before 6, it’s possible for a profiler to attach and grab an enumeration in the middle, and thus never hear about a ModuleID (even though the profiler avoided Race #1 from the previous section).&amp;#160; Again, an even worse problem occurs for module unloading.&amp;#160; Suppose the CLR were to change an ID’s enumerable status to false after sending the unload event.&amp;#160; That would also lead to holes:&lt;/p&gt;  &lt;p&gt;Bad timeline (unloading):&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Module loads, event would fire if profiler were attached (but it’s not), then ModuleID becomes enumerable &lt;/li&gt;    &lt;li&gt;Module starts to unload &lt;/li&gt;    &lt;li&gt;ModuleUnloadStarted event would fire here if events were enabled (but they’re not yet—no profiler is attached!) &lt;/li&gt;    &lt;li&gt;Profiler attaches &lt;/li&gt;    &lt;li&gt;CLR enables events, calls ProfilerAttachComplete() &lt;/li&gt;    &lt;li&gt;Profiler calls EnumModules (ModuleID is still enumerable, so profiler discovers ModuleID at this point) &lt;/li&gt;    &lt;li&gt;ModuleID is no longer enumerable &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Because 3 comes before 7, a profiler could attach in the middle, grab an enumeration, discover the ModuleID via the enumeration, and have no idea that module was in the process of unloading.&amp;#160; If the profiler were to use that ModuleID later on, an AV could result.&amp;#160; The above led to the following golden rule:&lt;/p&gt;  &lt;table cellspacing="0" cellpadding="2" width="868" border="4"&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td valign="top" width="860"&gt;&lt;span style="background-color: #00ff00"&gt;&lt;strong&gt;Golden rule: An ID’s enumerability status shall change &lt;em&gt;before&lt;/em&gt; the corresponding load/unload event is fired.&lt;/strong&gt;&lt;/span&gt;&lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;  &lt;p&gt;In other words, an ID becomes enumerable &lt;em&gt;before&lt;/em&gt; the LoadFinished (or JITCompilationFinished) event.&amp;#160; And an ID ceases to be enumerable &lt;em&gt;before&lt;/em&gt; the UnloadStarted event.&amp;#160; Or you can think of it as, “The event is always last”.&amp;#160; This eliminates any potential holes.&amp;#160; So to be even more explicit, here’s the enumerability vs. event ordering:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;ID available in enumerations snapped now &lt;/li&gt;    &lt;li&gt;LoadFinished &lt;/li&gt;    &lt;li&gt;ID no longer in enumerations snapped now &lt;/li&gt;    &lt;li&gt;UnloadStarted &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;If an ID is present, the profiler will discover the ID via the enumerator or a LoadFinished event (or both).&amp;#160; If an ID is not present, the profiler will either not see the ID via the enumerator or will see an UnloadStarted event (or both).&amp;#160; In all cases, the event is more recent, and so the profiler should always trust an event over an enumeration that was generated prior.&amp;#160; (More on that last point later.)&lt;/p&gt;  &lt;p&gt;The astute reader will notice that what we’ve done here is trade one race for another.&amp;#160; We’ve eliminated holes, but the cost is that the profiler must deal with duplicates.&amp;#160; For example:&lt;/p&gt;  &lt;p&gt;Good timeline (loading with duplicate):&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Module starts to load &lt;/li&gt;    &lt;li&gt;ModuleID is now enumerable &lt;/li&gt;    &lt;li&gt;Profiler attaches &lt;/li&gt;    &lt;li&gt;CLR enables events, calls ProfilerAttachComplete() &lt;/li&gt;    &lt;li&gt;Profiler calls EnumModules &lt;/li&gt;    &lt;li&gt;Profiler receives ModuleLoadFinished &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;At first it might seem a little strange.&amp;#160; The enumerator contains the ModuleID, so the profiler sees that the module is loaded.&amp;#160; But then the profiler receives a ModuleLoadFinished event, which might seem odd, since the enumerator implied the module was already loaded.&amp;#160; This is what I mean by “duplicate”—the profiler is notified of a ModuleID twice (once via the enumeration, and once via the event).&amp;#160; The profiler will need to be resilient to this.&amp;#160; Although it’s a bit awkward, it’s better than the alternative of a hole, since the profiler would have no way to know the hole occurred.&amp;#160; Unloading has a similar situation:&lt;/p&gt;  &lt;p&gt;Good timeline (unloading with duplicate):&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Module loads, event would have fired if profiler were attached (but it’s not), ModuleID becomes enumerable &lt;/li&gt;    &lt;li&gt;Module starts to unload &lt;/li&gt;    &lt;li&gt;ModuleID is no longer enumerable &lt;/li&gt;    &lt;li&gt;Profiler attaches &lt;/li&gt;    &lt;li&gt;CLR enables events, calls ProfilerAttachComplete() &lt;/li&gt;    &lt;li&gt;Profiler calls EnumModules &lt;/li&gt;    &lt;li&gt;Profiler receives ModuleUnloadStarted event &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;In step 6, the profiler does not see the unloading ModuleID (since it’s no longer enumerable).&amp;#160; But in step 7 the profiler is notified that the ModuleID is unloading.&amp;#160; Perhaps it’s a bit awkward that the profiler would be told that a seemingly nonexistent ModuleID is unloading.&amp;#160; But again, this is better than the alternative, where a profiler finds an unloading ID in the enumeration, and is never told that the ModuleID got unloaded.&amp;#160; One more case that’s worthwhile to bring out occurs when we move the profiler attach a bit earlier in the sequence.&lt;/p&gt;  &lt;p&gt;Good timeline (unloading without duplicate):&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Module loads, event would fire if profiler were attached, ModuleID becomes enumerable &lt;/li&gt;    &lt;li&gt;Module starts to unload &lt;/li&gt;    &lt;li&gt;Profiler attaches &lt;/li&gt;    &lt;li&gt;CLR enables events, calls ProfilerAttachComplete() &lt;/li&gt;    &lt;li&gt;Profiler calls EnumModules (ModuleID is still present in the enumeration) &lt;/li&gt;    &lt;li&gt;ModuleID is no longer enumerable &lt;/li&gt;    &lt;li&gt;Profiler receives ModuleUnloadStarted event &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Here the profiler discovers the ModuleID exists in step 5 (as the ModuleID is still enumerable at that point), but the profiler almost immediately after discovers that the module is unloading in step 7.&amp;#160; As stated above, events are more recent, and should always take precedence over enumerations that were generated prior.&amp;#160; This could get a bit tricky, though, as the profiler generates an enumeration before it iterates over the enumeration.&amp;#160; In the above sequence, the enumeration is generated in step 5.&amp;#160; However, the profiler could be iterating though the generated enumeration for quite some time, and might not come across the unloading ModuleID until after step 7 (multiple threads means fun for everyone!).&amp;#160; For this reason, it’s important for the profiler to give precedence to events that occur after the enumeration was &lt;em&gt;generated&lt;/em&gt;, even though iteration over that enumeration might occur later.&lt;/p&gt;  &lt;h1&gt;Catching Up on the State of GC Heap&lt;/h1&gt;  &lt;p&gt;If you’re writing a memory profiler, you likely have code that responds to the various GC events.&amp;#160; In order for your memory profiler to attach to a running process, it needs to deal gracefully with the fact that it does not yet have a cache of objects on the heap.&amp;#160; One straightforward way for the profiler to deal with this is to force a GC at attach time.&lt;/p&gt;  &lt;h2&gt;GC Already in Progress&lt;/h2&gt;  &lt;p&gt;Remember that your profiler attaches at a completely arbitrary point during process execution, possibly while a GC is already in progress.&amp;#160; This means that, once the profiler has enabled callback events, the profiler may start seeing GC callbacks (e.g., MovedReferences, ObjectReferences) from the middle of that GC, without seeing a GarbageCollectionStarted() first.&amp;#160; Your profiler should be resilient to this situation, preferably by ignoring GC callbacks until the first full GC and / or profiler-induced GC begins.&amp;#160; The profiler can do this by ignoring all GC callbacks until it sees the first GarbageCollectionStarted() callback OR by ignoring all GC callbacks until it sees the first GarbageCollectionStarted() callback after calling ForceGC().&lt;/p&gt;  &lt;h2&gt;Inducing Your First GC&lt;/h2&gt;  &lt;p&gt;It may be beneficial to program your profiler such that, upon attaching to the process, the profiler induces a first full GC automatically—call this the “catch-up” GC.&amp;#160; This will allow your profiler to use events like RootReferences2 and ObjectReferences during that initial “catch-up” GC, in order to build up its cache of objects from scratch.&amp;#160; After that initial catch-up GC, your profiler should then be able to deal with successive GCs the usual way.&lt;/p&gt;  &lt;p&gt;It’s worth reiterating a limitation I stated in the first attach post (linked above): the ObjectAllocated() callback is unavailable to profilers that attach to running processes.&amp;#160; Therefore, any logic your profiler has that assumes it gets all the ObjectAllocated() callbacks will need to be addressed.&amp;#160; Any objects newly allocated since the last GC may still be unknown to your profiler until it comes across their references via GC callbacks during the next GC (unless your profiler comes across those objects in other ways—example: as parameters to methods you hook with the Enter/Leave/Tailcall probes).&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;OK, that about covers the first steps your profiler should take once it attaches to a running process.&amp;#160; It will either need to use lazy catch-up or the catch-up enumerations (or, quite likely, a combination of both).&amp;#160; When using the enumerations, be careful to avoid holes (by calling the enumeration methods from inside ProfilerAttachComplete()), and be resilient to receiving information duplicated across the enumeration and the load / unload events.&amp;#160; For memory profilers, be wary of GCs already in progress at the time your profiler attaches, and consider inducing your own GC at attach-time to build your initial cache of GC objects.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9950025" width="1" height="1"&gt;</description></item><item><title>CLR V4: Stuff That May Break Your Profiler</title><link>http://blogs.msdn.com/b/davbr/archive/2010/01/07/clr-v4-stuff-that-may-break-your-profiler.aspx</link><pubDate>Thu, 07 Jan 2010 19:05:44 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9945335</guid><dc:creator>David Broman</dc:creator><slash:comments>1</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.msdn.com/b/davbr/rsscomments.aspx?WeblogPostID=9945335</wfw:commentRss><comments>http://blogs.msdn.com/b/davbr/archive/2010/01/07/clr-v4-stuff-that-may-break-your-profiler.aspx#comments</comments><description>&lt;p&gt;When CLR V2 came out, we made a big decision.&amp;#160; If your profiler has not been upgraded for V2 (i.e., if your profiler does not support ICorProfilerCallback2), then the CLR will not allow your profiler to run.&amp;#160; Why?&amp;#160; CLR V2 had some radical differences from V1.&amp;#160; Generics is a great example.&amp;#160; There were also some serious changes to the class loader, NGEN, and more.&amp;#160; A profiler that wasn’t designed for CLR V2 was more likely to fail than succeed.&lt;/p&gt;  &lt;p&gt;CLR V4 is a different story.&amp;#160; There are certainly changes in V4 that may break older profilers (that’s what this post is all about!) but we made a bet that V2 profilers were more likely to &lt;em&gt;succeed &lt;/em&gt;than fail when run against V4.&amp;#160; So we’ve decided to allow V2 profilers to be loaded by CLR V4.&amp;#160; Below are the caveats profiler writers need to be aware of when allowing their older profilers to run against V4.&lt;/p&gt;  &lt;p&gt;You should also read this post another way.&amp;#160; When you do refurbish your profiler to work against V4, you need to get the following right.&lt;/p&gt;  &lt;p&gt;The following changes are organized into the following sections:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;The Big Ones &lt;/li&gt;    &lt;li&gt;Profiling Infrastructure &lt;/li&gt;    &lt;li&gt;Loader / DLLs &lt;/li&gt;    &lt;li&gt;Type System &lt;/li&gt;    &lt;li&gt;Security &lt;/li&gt;    &lt;li&gt;Exception Handling &lt;/li&gt; &lt;/ul&gt;  &lt;h1&gt;The Big Ones&lt;/h1&gt;  &lt;p&gt;In this section are the big caveats you need to know about.&amp;#160; I wanted to put them up front so you will have read them by the time you inevitably fall asleep midway through the post:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;No Love By Default &lt;/li&gt;    &lt;li&gt;In-Process Side-by-Side CLR Instances &lt;/li&gt; &lt;/ul&gt;  &lt;h2&gt;No Love by Default&lt;/h2&gt;  &lt;p&gt;As I mentioned in a previous post, although you &lt;em&gt;can&lt;/em&gt; load an older profiler into V4, you can’t do so by default.&amp;#160; Because of the caveats of running an older profiler against CLR V4, the profiler user must opt in to this by setting the &lt;strong&gt;COMPLUS_ProfAPI_ProfilerCompatibilitySetting&lt;/strong&gt; environment variable appropriately.&amp;#160; See this &lt;a href="http://blogs.msdn.com/davbr/archive/2009/05/26/run-your-v2-profiler-binary-on-clr-v4.aspx"&gt;post&lt;/a&gt; for more information.&lt;/p&gt;  &lt;p&gt;It’s worth stressing that this environment variable does &lt;em&gt;not&lt;/em&gt; turn on some kind of compatibility &lt;em&gt;mode&lt;/em&gt; that protects an older profiler from all the changes in V4.&amp;#160; This environment variable causes the CLR to add minimal protection for older profilers from just a couple changes, such as multiple in-process side-by-side CLR instances (see below).&amp;#160; But the vast majority of the changes mentioned in this post will affect the profiler as-is, and there is no protection from them.&amp;#160; So it’s best to update your profiler to work against V4 natively without needing to use the &lt;strong&gt;COMPLUS_ProfAPI_ProfilerCompatibilitySetting&lt;/strong&gt; environment variable.&lt;/p&gt;  &lt;h2&gt;In-Process Side-by-Side CLR Instances&lt;/h2&gt;  &lt;p&gt;CLR V4 can be loaded alongside other versions of the CLR, all living together in the same process.&amp;#160; For now, that means you can have one CLR V4 instance plus one CLR V1.1 &lt;strong&gt;or&lt;/strong&gt; V2 instance all running in the same process.&amp;#160; In future releases, the list of possibilities will grow (e.g., V2, V4, V5, V6, etc. running together).&amp;#160; This will result in multiple instances of your callback object being created and used simultaneously.&amp;#160; This sort of thing is sure to mess with your profiler’s mind, particularly due to any global state you might have in your profiler DLL, or any communication you do between your profiler DLL and an out-of-process GUI shell.&amp;#160; There will be blog entries and MSDN topics on this in the future to give you more information, though for now you can take a look here:&lt;/p&gt;  &lt;p&gt;&lt;a title="http://blogs.msdn.com/davbr/archive/2008/11/10/new-stuff-in-profiling-api-for-upcoming-clr-4-0.aspx" href="http://blogs.msdn.com/davbr/archive/2008/11/10/new-stuff-in-profiling-api-for-upcoming-clr-4-0.aspx"&gt;http://blogs.msdn.com/davbr/archive/2008/11/10/new-stuff-in-profiling-api-for-upcoming-clr-4-0.aspx&lt;/a&gt;&lt;/p&gt;  &lt;h1&gt;Profiling Infrastructure&lt;/h1&gt;  &lt;p&gt;In this section are changes to the profiling API and infrastructure itself that may impact your profiler:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;FreeLibrary &lt;/li&gt;    &lt;li&gt;Enter/Leave/Tailcall &lt;/li&gt;    &lt;li&gt;CORPROF_E_UNSUPPORTED_CALL_SEQUENCE &lt;/li&gt;    &lt;li&gt;SetILInstrumentedCodeMap &lt;/li&gt; &lt;/ul&gt;  &lt;h2&gt;FreeLibrary&lt;/h2&gt;  &lt;p&gt;In CLR V1 and V2, your profiler DLL would never be explicitly unloaded by the CLR.&amp;#160; In V4, however, the CLR will FreeLibrary your profiler DLL if your profiler chooses to detach before process shutdown.&amp;#160; This may be an issue if your product is split into DLLs with various interdependencies between them and your profiler DLL.&amp;#160; Although this won’t affect older profilers, as they cannot request to detach before process shutdown, this is something to be wary of when you upgrade your profiler, if you choose to take advantage of the Detach feature.&lt;/p&gt;  &lt;h2&gt;Enter/Leave/Tailcall&lt;/h2&gt;  &lt;h3&gt;&lt;/h3&gt;  &lt;h3&gt;New Signatures&lt;/h3&gt;  &lt;p&gt;We have made some enhancements to the Enter/Leave/Tailcall interface to cut down on code size of the JITted / NGENd code.&amp;#160; This required updating the signatures.&amp;#160; While the older signatures still work (Enter/Leave/Tailcall and Enter2/Leave2/Tailcall2), they must now go through another code layer before reaching your profiler (even if you were using fast-path before).&amp;#160; This means you will see some slow-down until you upgrade to the new V4 signatures.&amp;#160; Fast-path (i.e., calling from JITted/NGENd code directly into your profiler) does still exist; you just need to use the latest signatures to enable fast-path.&lt;/p&gt;  &lt;p&gt;An artifact of this change is that your profiler will use different Info methods to install your hooks, depending on whether you want to inspect values in your probes (SetEnterLeaveFunctionHooks3 vs. SetEnterLeaveFunctionHooks3WithInfo).&amp;#160; To help ensure correctness, the CLR will not allow the profiler to install enter/leave/tailcall probes that are inconsistent with the COR_PRF_MONITOR flags you have specified to SetEventMask.&amp;#160; COR_PRF_ENABLE_FUNCTION_ARGS, COR_PRF_ENABLE_FUNCTION_RETVAL, and COR_PRF_ENABLE_FRAME_INFO require SetEnterLeaveFunctionHooks3&lt;strong&gt;WithInfo&lt;/strong&gt;, and if those flags are not set, then you must use SetEnterLeaveFunctionHooks3.&lt;/p&gt;  &lt;p&gt;So you must be sure to call SetEventMask &lt;em&gt;first&lt;/em&gt;, with the appropriate flags to establish whether you want to inspect arguments, return value, or frame information.&amp;#160; Then, you may call SetEnterLeaveFunctionHooks3 or SetEnterLeaveFunctionHooks3WithInfo &lt;em&gt;second&lt;/em&gt;, so the CLR can verify you’re using probes that match the event flags you specified.&amp;#160; If you call SetEventMask and SetEnterLeaveFunctionHooks3(WithInfo) in the wrong order, or with inconsistent information, then the CLR will fail with CORPROF_E_INCONSISTENT_WITH_FLAGS.&lt;/p&gt;  &lt;h3&gt;Placement of the Calls&lt;/h3&gt;  &lt;p&gt;There was another change to the Enter/Leave/Tailcall interface; this one on x86 regarding the placement of the call to the Enter probe relative to the prolog.&amp;#160; In V2, the order was:&lt;/p&gt;  &lt;p&gt;Enter    &lt;br /&gt;Prolog     &lt;br /&gt;Leave     &lt;br /&gt;Epilog&lt;/p&gt;  &lt;p&gt;The above does not have mirror symmetry, and is also inconsistent with how the probes are called on the 64 bit platforms.&amp;#160; In V4, the order is now:&lt;/p&gt;  &lt;p&gt;Prolog    &lt;br /&gt;Enter     &lt;br /&gt;Leave     &lt;br /&gt;Epilog&lt;/p&gt;  &lt;p&gt;This could break your profiler if it makes assumptions about the value of ESP during its Enter probe, and tries to find values on the stack based on those assumptions.&amp;#160; Of course, if your profiler does things the “proper” way and relies on the Enter/Leave/Tailcall interface to locate items such as argument values, then you’re fine.&lt;/p&gt;  &lt;h2&gt;CORPROF_E_UNSUPPORTED_CALL_SEQUENCE&lt;/h2&gt;  &lt;p&gt;As you may recall from this &lt;a href="http://blogs.msdn.com/davbr/archive/2008/12/23/why-we-have-corprof-e-unsupported-call-sequence.aspx"&gt;post&lt;/a&gt;, CLR V2 will fail some ICorProfilerInfo* calls with CORPROF_E_UNSUPPORTED_CALL_SEQUENCE if they are called asynchronously.&amp;#160; In V4, the CLR performs an additional check, related to GC safety, to ensure a given ICorProfilerInfo* call is safe.&amp;#160; If the call is determined to be unsafe, then the call will fail with CORPROF_E_UNSUPPORTED_CALL_SEQUENCE.&amp;#160; Here’s how the check works.&amp;#160; Some ICorProfilerCallback* methods are “unsafe for GC”, in that they cannot deal with a GC occurring while they’re on the stack.&amp;#160; Meanwhile, some ICorProfilerInfo* calls may trigger a GC.&amp;#160; The problem lies in the intersection—if one of those “unsafe for GC” callback methods calls into your profiler, and then your profiler turns around and calls one of those “may trigger a GC” info methods, then that info method will detect the dangerous calls sequence and fail immediately with CORPROF_E_UNSUPPORTED_CALL_SEQUENCE.&lt;/p&gt;  &lt;table cellspacing="0" cellpadding="2" width="400" border="1"&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td valign="top" width="197"&gt;Unsafe-for-GC Callbacks&lt;/td&gt;        &lt;td valign="top" width="201"&gt;May-trigger-GC Infos&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="197"&gt;&lt;font size="1"&gt;ThreadAssignedToOSThread            &lt;br /&gt;ExceptionUnwindFunctionEnter             &lt;br /&gt;ExceptionUnwindFunctionLeave             &lt;br /&gt;ExceptionUnwindFinallyEnter             &lt;br /&gt;ExceptionUnwindFinallyLeave             &lt;br /&gt;ExceptionCatcherEnter             &lt;br /&gt;RuntimeSuspendStarted             &lt;br /&gt;RuntimeSuspendFinished             &lt;br /&gt;RuntimeSuspendAborted             &lt;br /&gt;RuntimeThreadSuspended             &lt;br /&gt;RuntimeThreadResumed             &lt;br /&gt;MovedReferences             &lt;br /&gt;ObjectsAllocatedByClass             &lt;br /&gt;ObjectReferences             &lt;br /&gt;RootReferences(2)             &lt;br /&gt;HandleCreated             &lt;br /&gt;HandleDestroyed             &lt;br /&gt;GarbageCollectionStarted             &lt;br /&gt;GarbageCollectionFinished &lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="202"&gt;&lt;font size="1"&gt;GetILFunctionBodyAllocator            &lt;br /&gt;SetILFunctionBody             &lt;br /&gt;SetILInstrumentedCodeMap             &lt;br /&gt;ForceGC             &lt;br /&gt;GetAppDomainsContainingModule             &lt;br /&gt;GetClassFromToken             &lt;br /&gt;GetClassFromTokenAndTypeArgs             &lt;br /&gt;GetFunctionFromTokenAndTypeArgs             &lt;br /&gt;GetAppDomainInfo             &lt;br /&gt;EnumModules             &lt;br /&gt;RequestProfilerDetach&lt;/font&gt;           &lt;p&gt;&lt;/p&gt;          &lt;p&gt;&lt;font size="1"&gt;&amp;#160;&lt;/font&gt;&lt;/p&gt;       &lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;  &lt;h2&gt;SetILInstrumentedCodeMap&lt;/h2&gt;  &lt;p&gt;Before CLR V4, if the profiler were to delete the map it passed to SetILInstrumentedCodeMap, that could cause AVs later on.&amp;#160; That was a CLR bug, as COM memory management conventions state that [in] parameters are allocated and deallocated by the caller (callee must make a copy if it wants to use the memory later).&amp;#160; This has been fixed in CLR V4, so that profilers should free the instrumented code map after calling SetILInstrumentedCodeMap, and that will no longer cause AVs.&amp;#160; If your profiler is not updated to delete this memory when run against CLR V4, then that will cause a memory leak--though that’s the worst that will happen (you won’t cause an AV by failing to delete memory, of course).&lt;/p&gt;  &lt;h1&gt;Loader / DLLs&lt;/h1&gt;  &lt;p&gt;In this section are changes to how the CLR loads assemblies, as well as the DLLs that make up the CLR itself:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Dynamic Module Names &lt;/li&gt;    &lt;li&gt;DLL Name Changes &lt;/li&gt;    &lt;li&gt;MSCOREE’s Exported Hosting Functions &lt;/li&gt; &lt;/ul&gt;  &lt;h2&gt;Dynamic Module Names&lt;/h2&gt;  &lt;p&gt;In CLR V2, a call to GetModuleInfo would sometimes return an empty name.&amp;#160; In fact, some profilers may have used the base load address and name [out] parameters from GetModuleInfo in order to infer some details about the module in a rather indirect fashion.&amp;#160; In particular:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;In V2, any module created via Reflection.Emit will have a base load address of 0. &lt;/li&gt;    &lt;li&gt;In V2, any module loaded directly by the CLR from disk will have a non-empty Name (and the Name will be the disk path).&amp;#160; All other modules will have an empty Name.      &lt;ul&gt;       &lt;li&gt;Modules loaded from disk include: [name non-empty in V2]          &lt;ul&gt;           &lt;li&gt;Any module loaded via fusion to facilitate execution.&amp;#160; (i.e., normal stuff) &lt;/li&gt;            &lt;li&gt;Any reflection-only-context module loaded from disk (Assembly.ReflectionOnlyLoadFrom) &lt;/li&gt;         &lt;/ul&gt;       &lt;/li&gt;        &lt;li&gt;Modules NOT loaded from disk include: [name empty in V2]          &lt;ul&gt;           &lt;li&gt;RefEmit-generated modules (AppDomain.DefineDynamicAssembly) &lt;/li&gt;            &lt;li&gt;Modules loaded from byte arrays (Assembly.Load) &lt;/li&gt;            &lt;li&gt;Reflection-only context modules loaded from byte arrays (Assembly.ReflectionOnlyLoad) &lt;/li&gt;            &lt;li&gt;Managed SQL modules, and any other host that overrides the module loading mechanism &lt;/li&gt;         &lt;/ul&gt;       &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;In CLR V4, although the behavior of the base load address is not changing, you will now see a non-empty Name, even for non-disk modules!&amp;#160; We will provide the module's &amp;quot;metadata name&amp;quot; in the Name parameter, in the case where it has no disk path.&amp;#160; By “metadata name”, I’m referring to the “Name” column from the Module table inside metadata.&amp;#160; This is also exposed as Module.ScopeName to managed code, and as IMetaDataImport::GetScopeProps’s szName parameter to unmanaged metadata client code.&lt;/p&gt;  &lt;p&gt;For profilers that really need to distinguish between regular disk modules, RefEmit-generated modules, byte array modules, etc., we are introducing &lt;strong&gt;GetModuleInfo2&lt;/strong&gt; in CLR V4.&amp;#160; It has identical behavior to the V4 GetModuleInfo; however, it adds one more [out] parameter that will be filled with bit flags that describe various properties of the module.&amp;#160; Take a look at the corprof.idl that comes with the beta 2 installation to see the goodies.&lt;/p&gt;  &lt;h2&gt;DLL Name Changes&lt;/h2&gt;  &lt;p&gt;Mscorwks.dll has been renamed to clr.dll.&amp;#160; Mscordbc.dll, which used to contain profiling-specific functionality, has disappeared (all of its functionality is now present in clr.dll). Generally, this should not affect you, unless your profiler takes dependencies on the names of these DLLs.&amp;#160; You will be affected, however, while debugging if you use SOS.&amp;#160; Instead of using “.loadby sos mscorwks” you’ll now need to use “.loadby sos clr”.&amp;#160; Bonus: Less characters to type!&lt;/p&gt;  &lt;h2&gt;MSCOREE’s Exported Hosting Functions&lt;/h2&gt;  &lt;p&gt;Some profilers use C exports from mscoree.dll, typically one or more of the &lt;a href="http://msdn.microsoft.com/en-us/library/aa964945%28VS.100%29.aspx"&gt;Hosting Global Static Functions&lt;/a&gt;.&amp;#160; These exports are almost all deprecated in CLR V4 (except for &lt;a href="http://msdn.microsoft.com/en-us/library/dd537633(VS.100).aspx"&gt;CLRCreateInstance&lt;/a&gt;).&amp;#160; CLR V4 has also deprecated the use of CoCreateInstance to instantiate COM objects used for hosting the CLR, such as CLSID_CorRuntimeHost, CLSID_CLRRuntimeHost, CLSID_TypeNameFactory, CLSID_ComCallUnmarshal, etc.&lt;/p&gt;  &lt;p&gt;For compatibility reasons, the deprecated exports will by default execute in a context capped to CLR V2.&amp;#160; For example, calling CorBindToRuntime with a NULL pwszVersion, which historically would bind you to the newest runtime installed on the box, will now bind you to the newest runtime &lt;em&gt;below V4&lt;/em&gt;.&amp;#160; So if both V2 &amp;amp; V4 are installed on the box, CorBindToRuntime with a NULL pwszVersion will bind you to V2.&amp;#160; As another example, if both V2 &amp;amp; V4 runtimes are loaded into a process, GetRealProcAddress will locate the specified function in the V2 runtime.&amp;#160; And if only V4 is loaded into a process, GetRealProcAddress can load the V2 CLR into the process if it is installed.&amp;#160; Similarly, attempting to CoCreateInstance one of the CLR-hosting COM objects will by default cause the CLR V2 to load.&lt;/p&gt;  &lt;p&gt;The reason that the exports from mscoree.dll are now capped to V2 is to ensure that, when a user installs CLR V4, that installation is non-impactful to older, CLR V2-based applications.&amp;#160; For example, a CLR V1.1 managed application on a machine with only CLR V2 installed would roll forward to &amp;quot;the latest&amp;quot; runtime on the box, which happened to be CLR V2.&amp;#160; We want to preserve this behavior even after CLR V4 is installed (i.e., the 1.1 app without a CLR 1.1 on the box should continue to bind against CLR V2, and not CLR V4).&amp;#160; As another example, we want to minimize damage to any old native hosts that were built against older runtimes, but that might end up running inside processes containing managed code that binds to CLR V4 (due to in-process side-by-side CLR instances).&lt;/p&gt;  &lt;p&gt;Although there are ways to modify this behavior away from the default via configuration files, it is recommended that profilers (and hosts!) stop using C exports from mscoree.dll.&amp;#160; Instead, profilers that target CLR V4 should be upgraded to use the new &lt;a href="http://msdn.microsoft.com/en-us/library/dd233134(VS.100).aspx"&gt;CLR V4 Hosting and Metahost interfaces&lt;/a&gt; wherever they had been using mscoree exports.&lt;/p&gt;  &lt;h1&gt;Type System&lt;/h1&gt;  &lt;p&gt;In this section are changes related to how the CLR loads and manages type information:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Collectible Assemblies &lt;/li&gt;    &lt;li&gt;Type Forwarding &lt;/li&gt;    &lt;li&gt;GetClassLayout and Value Type Size &lt;/li&gt;    &lt;li&gt;No More Frozen Strings &lt;/li&gt;    &lt;li&gt;String Layout &lt;/li&gt; &lt;/ul&gt;  &lt;h2&gt;Collectible Assemblies&lt;/h2&gt;  &lt;p&gt;CLR V4 introduces the new feature Collectible Assemblies.&amp;#160; The quick summary of this feature is that it allows the developer to mark a Reflection.Emit-generated assembly as being collectible, and that will tell the GC to collect the assembly, as well as its modules, classes, and code, once they are no longer referenced.&amp;#160; See the MSDN &lt;a href="http://msdn.microsoft.com/en-us/library/dd554932(VS.100).aspx"&gt;docs&lt;/a&gt; for more information and background on the feature itself.&amp;#160; This will affect your profiler in that assemblies, modules, and classes may now unload without AppDomainShutdown callbacks being issued first (because the AppDomain is not shutting down!).&lt;/p&gt;  &lt;p&gt;This makes it all the more important that your profiler synchronize between module unload events, and any threads that may be using data from the unloading modules.&amp;#160; Of course, this is nothing new—AppDomain shutdown always made it possible for modules to unload.&amp;#160; What’s different is that you should expect modules to unload more often in the future, and that you can’t rely on the containing AppDomain to shutdown first.&amp;#160; It’s always good practice to block inside ModuleUnloadStarted while any of your other threads may be using classes or functions from that module.&lt;/p&gt;  &lt;p&gt;Another consideration due to collectible assemblies is the fact that calls to GetAppDomainStaticAddress and GetThreadStaticAddress may give back to you pointers to moveable objects on the GC heap.&amp;#160; This was actually already the case in CLR V2 for some value types living inside movable objects.&amp;#160; Now this will also occur for non-value types in V4 due to collectible assemblies.&amp;#160; All this means to you is that you mustn’t store addresses of statics for use later on, unless you track their movement and update your references to them via the MovedReferences callback.&lt;/p&gt;  &lt;h2&gt;Type Forwarding&lt;/h2&gt;  &lt;p&gt;Expect to see more use of type forwarding in CLR V4.&amp;#160; See this &lt;a href="http://blogs.msdn.com/davbr/archive/2009/09/30/type-forwarding.aspx"&gt;post&lt;/a&gt; for more information.&lt;/p&gt;  &lt;h2&gt;GetClassLayout and Value Type Size&lt;/h2&gt;  &lt;p&gt;Instances of value types have a slightly different layout in memory than reference types.&amp;#160; Whereas reference type instances have “header information” at the beginning, value type instances do not (unless they are boxed).&amp;#160; Unfortunately, CLR V2 had a bug where GetClassLayout would return, via the pulClassSize [out] parameter, the full boxed size of the value type, including the header.&amp;#160; Fortunately, the field offsets returned by GetClassLayout were always correct.&amp;#160; But any math the profiler did based on pulClassSize would be wrong for unboxed value type instances.&lt;/p&gt;  &lt;p&gt;In CLR V4 this has been fixed, and pulClassSize gives the real size (including header for reference types, and excluding the header for value types).&amp;#160; So if your profiler was working around this problem in CLR V2, you’ll need to undo the workaround when running against CLR V4.&lt;/p&gt;  &lt;h2&gt;No More Frozen Strings&lt;/h2&gt;  &lt;p&gt;In CLR V2, profilers could use EnumModuleFrozenObjects to enumerate over frozen strings present in a module.&amp;#160; This API still functions, but it will now always give you an enumerator over the empty set since there are no longer frozen strings to iterate over.&amp;#160; Also, in CLR V2, you may have noticed that GetGenerationBounds would sometimes give you generation 2 ranges inside NGENd modules (due to frozen strings).&amp;#160; You will no longer find this to be the case in CLR V4.&lt;/p&gt;  &lt;h2&gt;String Layout&lt;/h2&gt;  &lt;p&gt;As an optimization, in CLR V4 we have removed the buffer length field from the layout of string objects in memory.&amp;#160; This makes the GetStringLayout method’s pBufferLengthOffset parameter kind of pointless in CLR V4 (it now just gives you the same value as the pStringLengthOffset parameter).&amp;#160; As a result, it is best for your profiler to now use GetStringLayout2, which no longer has the pBufferLengthOffset parameter.&lt;/p&gt;  &lt;h1&gt;Security&lt;/h1&gt;  &lt;p&gt;In this section are changes related to security:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Introduction to Security Changes &lt;/li&gt;    &lt;li&gt;Transparent code in fully-trusted assemblies &lt;/li&gt;    &lt;li&gt;Conditional APTCA &lt;/li&gt; &lt;/ul&gt;  &lt;h2&gt;Introduction to Security Changes&lt;/h2&gt;  &lt;p&gt;What follows is a pathetically reduced summary of how security is changing in CLR V4, for the purpose of putting into perspective how your profiler may behave differently as a result.&amp;#160; Please note that my blog is &lt;em&gt;not &lt;/em&gt;the place to go for getting general information about managed security.&amp;#160; Check out &lt;a title="http://blogs.msdn.com/shawnfa/" href="http://blogs.msdn.com/shawnfa/"&gt;http://blogs.msdn.com/shawnfa/&lt;/a&gt; and &lt;a title="http://blogs.msdn.com/clrteam/archive/tags/Security/default.aspx" href="http://blogs.msdn.com/clrteam/archive/tags/Security/default.aspx"&gt;http://blogs.msdn.com/clrteam/archive/tags/Security/default.aspx&lt;/a&gt;.&amp;#160; Also, there’s a CLR Inside Out article with a great overview of all the security changes in V4: &lt;a title="http://msdn.microsoft.com/en-us/magazine/ee677170.aspx" href="http://msdn.microsoft.com/en-us/magazine/ee677170.aspx"&gt;http://msdn.microsoft.com/en-us/magazine/ee677170.aspx&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;Ok, having said that…&amp;#160; CLR V4 introduces a new, simpler security model.&amp;#160; First off, the policy is simplified.&amp;#160; Basically, any run-of-the-mill, unhosted managed app will now run with all its assemblies granted full trust.&amp;#160; This is the case even if you run the app off of a network share.&amp;#160; A host can modify this, but there are some limitations:&amp;#160; GAC’d assemblies will always be fully trusted, the host can only specify a single partial-trust security grant set at the AppDomain level (and not customize partial-trust grant sets per assembly), and code groups are now deprecated.&amp;#160; It’s possible to revert back to the old CAS policy, but that’s outside the scope of this blog entry—by default the old CAS policy is now history.&lt;/p&gt;  &lt;p&gt;Security enforcement has moved to a simpler model as well, known as Level 2 Security Transparency.&amp;#160; Rather than using LinkDemands, the JIT looks at annotations on types and methods that describe themselves as Transparent, SafeCritical, and Critical.&amp;#160; Transparent code cannot perform security-sensitive operations, whereas Critical code can.&amp;#160; Transparent code cannot call critical code directly.&amp;#160; That’s where SafeCritical code comes in: it can do everything Critical code can do &lt;em&gt;and &lt;/em&gt;allows transparent callers.&amp;#160; This makes SafeCritical code pretty dangerous to write, and it must do thoughtful validation of parameters and careful calls into other Critical code, to ensure it’s not being used maliciously.&lt;/p&gt;  &lt;p&gt;“Nifty, Dave.&amp;#160; But how is this going to break my profiler?”&lt;/p&gt;  &lt;h2&gt;Transparent code in fully-trusted assemblies&lt;/h2&gt;  &lt;p&gt;If you perform IL rewriting of mscorlib, you’re used to having full permissions granted to your rewritten IL.&amp;#160; However, in CLR V4, some code in mscorlib is now annotated as Transparent.&amp;#160; So if you instrument a transparent method in mscorlib, it will remain transparent and will be blocked from performing security-sensitive operations you may be used to, such as P/Invokes.&lt;/p&gt;  &lt;p&gt;The recommended way to attack this problem is to isolate any code that needs to perform security-sensitive operations into new Critical methods you create.&amp;#160; You should then create the minimum necessary SafeCritical bridge code, so that you many instrument Transparent code to call into that bridge code (which in turn calls into your Critical methods).&amp;#160; I must stress that writing SafeCritical code requires thought and attention.&amp;#160; You do not want malicious, untrusted code to exploit your profiler by calling into your SafeCritical code to manipulate your profiler into doing nasty things.&lt;/p&gt;  &lt;p&gt;There is an alternative you can use to help with the issue of instrumenting transparent code in fully-trusted assemblies.&amp;#160; You may pass the COR_PRF_DISABLE_TRANSPARENCY_CHECKS_UNDER_FULL_TRUST flag in your call to SetEventMask().&amp;#160; This will make things work similarly to how they did in V2, in the sense that any code you instrument in mscorlib will run with full trust and be able to perform security-sensitive operations (even if it’s marked as transparent).&amp;#160; The advantage of this approach is that it’s easy.&amp;#160; The disadvantages are that it changes the security behavior of all full trust assemblies when your profiler is loaded (generally you want an application to behave as normally as possible when your profiler is loaded), and it still does not address the issue of partial-trust assemblies (whose transparent code will continue to be transparent).&amp;#160; The reason we added this flag was to reduce the work required to get your profiler up and running on V4.&amp;#160; But it’s best for you to give yourself a work item to deal with security properly (i.e., adding SafeCritical &amp;amp; Critical methods as described above).&lt;/p&gt;  &lt;h2&gt;Conditional APTCA&lt;/h2&gt;  &lt;p&gt;It is impossible to summarize “Conditional APTCA (Allow Partially Trusted Callers Attribute)” into one sentence, but I’m going to do it anyway.&amp;#160; Conditional APTCA is a feature where an assembly with security-sensitive code says, “I &lt;em&gt;may&lt;/em&gt; allow partially-trusted callers”, and then the host makes the final call on a per-AppDomain basis.&amp;#160; If that doesn’t clarify it for you (and how could it, really?) go read the CLR Inside Out article I referenced above.&lt;/p&gt;  &lt;p&gt;Conditional APTCA may affect your profiler in that you may see a sudden lack of “shareability” (i.e., domain neutrality) of managed assemblies you ship alongside your profiler to support instrumentation you perform.&amp;#160; While this is not typically an issue with regular old unhosted apps (which now run with all assemblies granted full trust by default), this can affect hosted scenarios such as ASP.NET.&lt;/p&gt;  &lt;p&gt;As a review, the “shared domain” is a pseudo-domain into which the CLR loads all assemblies that should be loaded as domain neutral (as configured by the host and / or the LoaderOptimizationAttribute).&amp;#160; The application is generally unaware of this shared domain.&amp;#160; As far as the application is concerned, the assemblies are loaded separately into each “real” AppDomain that uses them, and any per-AppDomain information (e.g., values of statics) are duplicated and stored in each AppDomain as expected.&amp;#160; But any shared data that would always be identical across the AppDomains (e.g., JITted code) is stored only once, in the shared domain.&lt;/p&gt;  &lt;p&gt;Shareability of assemblies does not affect the correctness of the application, but can enhance performance by not having to JIT the functions of those assemblies into every (real) AppDomain in which those functions are used.&amp;#160; The CLR must be careful about deciding whether an assembly is truly capable of being loaded shared—the security characteristics must be identical in every AppDomain that might use that assembly.&lt;/p&gt;  &lt;p&gt;That’s where conditional APTCA makes an impact.&amp;#160; As a simplified example, if your profiler’s assembly (call it P) references a conditional APTCA assembly (call it A), then P’s shareability is called into question.&amp;#160; P can only be shared if the host has decided to &lt;em&gt;enable&lt;/em&gt; APTCA for A in all AppDomains, as well as the transitive closure of A’s conditional APTCA dependents.&amp;#160; In other words, the host must enable APTCA for all conditional APTCA assemblies referenced by P (directly or indirectly) in all AppDomains in order to allow P to be shared.&lt;/p&gt;  &lt;h1&gt;Exception Handling&lt;/h1&gt;  &lt;p&gt;In this section are changes related to how the CLR implements exception handling:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;DynamicMethods &lt;/li&gt;    &lt;li&gt;Windows 7 Unhandled Exceptions &lt;/li&gt;    &lt;li&gt;GetNotifiedExceptionClauseInfo on 64-bits &lt;/li&gt;    &lt;li&gt;CLR Exception Code &lt;/li&gt; &lt;/ul&gt;  &lt;h2&gt;DynamicMethods&lt;/h2&gt;  &lt;p&gt;You may have noticed that the CLR “hides” from the profiler any functions created via System.Reflection.Emit.DynamicMethod.&amp;#160; You don’t get JIT notifications for them, and you don’t see frames for them when you call DoStackSnapshot.&amp;#160; This is intentional, because DynamicMethods have no metadata, and the usual things profilers might do with functions (e.g., getting a MethodDef and looking up the name or signature in metadata) will fail miserably with DynamicMethods.&amp;#160; And don’t get me started on trying to instrument those puppies.&amp;#160; Someday in the future, it may be nice to provide limited support for profiling DynamicMethods, but that’s a topic for another time.&lt;/p&gt;  &lt;p&gt;For now, note that, in V2, we accidentally let slip some exception callbacks for DynamicMethod frames.&amp;#160; In particular, your profiler would get ExceptionSearchFunctionLeave and ExceptionUnwindFunctionLeave callbacks for DynamicMethod frames, but not the matching Enter callbacks!&amp;#160; This made maintaining shadow stacks unnecessarily difficult, as one would expect the search or unwind phase to enter a function before leaving it.&amp;#160; In V4, we’re now properly hiding the ExceptionSearchFunctionLeave and ExceptionUnwindFunctionLeave callbacks callbacks for DynamicMethod frames, so that the callbacks are now balanced.&amp;#160; Note that the story is still not perfect—the CLR still intentionally does notify the profiler of ExceptionThrown, even when the exception is thrown from a DynamicMethod (it’s more important for the profiler to know an exception has occurred, than to have that information be hidden).&amp;#160; There are also still some imbalances with some of the the other exception enter/leave callbacks (ExceptionSearchFilter*, ExceptionUnwindFinally*, ExceptionCatcher*).&amp;#160; But we didn’t want to make too many breaking changes in this area, and the ExceptionSearch/UnwindFunction* callbacks were the only ones essential for maintaining shadow stacks.&amp;#160; So we chose to be rather surgical with this fix.&lt;/p&gt;  &lt;p&gt;Hopefully this shouldn’t break you at all, and if anything should make your life better.&lt;/p&gt;  &lt;h2&gt;Windows 7 Unhandled Exceptions&lt;/h2&gt;  &lt;p&gt;In Windows 7, if an exception goes unhandled, then the DLLMain’s DLL_PROCESS_DETACH call is omitted.&amp;#160; So if you have any cleanup code here, be warned that it won’t get run in this case.&amp;#160; This actually has nothing to do with CLR V4—it occurs on CLR V2 as well.&amp;#160; Just thought I’d mention.&lt;/p&gt;  &lt;h2&gt;GetNotifiedExceptionClauseInfo on 64-bits&lt;/h2&gt;  &lt;p&gt;A minor improvement has been made to the behavior of GetNotifiedExceptionClauseInfo during nested exceptions on x64.&lt;/p&gt;  &lt;pre class="code"&gt;    &lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;static&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;void&lt;/span&gt; Foo()
    {
        &lt;span style="color: rgb(0,0,255)"&gt;try
&lt;/span&gt;        {
            &lt;span style="color: rgb(0,0,255)"&gt;throw&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;new&lt;/span&gt; Exception(&lt;span style="color: rgb(163,21,21)"&gt;&amp;quot;outer&amp;quot;&lt;/span&gt;);
        }
        &lt;span style="color: rgb(0,0,255)"&gt;catch&lt;/span&gt; (Exception exOuter)
        {
            &lt;span style="color: rgb(0,0,255)"&gt;try
&lt;/span&gt;            {
                &lt;span style="color: rgb(0,0,255)"&gt;throw&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;new&lt;/span&gt; Exception(&lt;span style="color: rgb(163,21,21)"&gt;&amp;quot;inner&amp;quot;&lt;/span&gt;);
            }
            &lt;span style="color: rgb(0,0,255)"&gt;catch&lt;/span&gt; (Exception exInner)
            {
                &lt;span style="color: rgb(0,128,0)"&gt;// Profiler calls GetNotifiedExceptionClauseInfo 
&lt;/span&gt;            }
        }
    }&lt;/pre&gt;

&lt;p&gt;If your profiler were to call GetNotifiedExceptionClauseInfo from inside the inner catch clause you would see a different value for the stack pointer in CLR V2 and CLR V4.&amp;#160; On CLR V4, you will get the stack pointer for Foo(), which is nice.&amp;#160; This can be used to compare against the SP you get for Foo() when you call DoStackSnapshot, so you can figure out which frame on the stack corresponds to the function containing the catch clause being executed.&amp;#160; In CLR V2, however, your profiler would get the stack pointer of a special “pseudo-stack-frame” the CLR generates for the outer catch clause.&amp;#160; This was silly, because these “pseudo-stack-frames” are a CLR internal implementation detail that is not normally exposed to the profiler.&amp;#160; As such, this stack pointer could not be easily compared against anything you get back from DoStackSnapshot.&lt;/p&gt;

&lt;p&gt;So hopefully this change should not break you, but if anything, should help.&lt;/p&gt;

&lt;h2&gt;CLR Exception Code&lt;/h2&gt;

&lt;p&gt;Windows structured exception handling uses a numerical “code” to identify exception types.&amp;#160; The CLR uses a single code for all managed exceptions.&amp;#160; This code changed in CLR V4.&amp;#160; That's about all I want to say about that.&amp;#160; No need to tell you what the old code and new code are, because your profiler shouldn’t be hard-coding the number anyway.&amp;#160; And if it is, well, you should go tinker around with CLR V4 to see how it’s changed—and consider removing any dependence you have on the CLR’s exception code. &lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;If you made it this far, wow!&amp;#160; You now have a good idea of what things to investigate that could cause problems if your customers try running your V2 profiler against CLR V4.&amp;#160; You also have a “todo” list of things to look at fixing as you upgrade your profiler to support ICorProfilerCallback3 and work properly against CLR V4.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9945335" width="1" height="1"&gt;</description></item><item><title>CLR V4: Profiler Attach Basics With Sample Code</title><link>http://blogs.msdn.com/b/davbr/archive/2009/11/04/clr-v4-profiler-attach-basics-with-sample-code.aspx</link><pubDate>Wed, 04 Nov 2009 17:43:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9917430</guid><dc:creator>David Broman</dc:creator><slash:comments>2</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.msdn.com/b/davbr/rsscomments.aspx?WeblogPostID=9917430</wfw:commentRss><comments>http://blogs.msdn.com/b/davbr/archive/2009/11/04/clr-v4-profiler-attach-basics-with-sample-code.aspx#comments</comments><description>&lt;P&gt;A new feature in CLR V4 is the ability to attach a profiler to a process after that process has already started.&amp;nbsp; The usefulness of this is fairly obvious to anyone who's ever attached a debugger to a running-process: It's helpful when diagnosing hard-to-reproduce problems, and particularly useful when encountering issues in production.&lt;/P&gt;
&lt;P&gt;Please note!&amp;nbsp; You can't just take any profiler you bought and suddenly be able to attach it to a running application.&amp;nbsp; The profiler must be built with "attachability" in mind.&amp;nbsp; So if you're a profiler developer looking to pump some attachability into your product, read on--this article is for you.&amp;nbsp; Everyone else, this article will probably be less useful--but just as riveting.&lt;/P&gt;
&lt;H1&gt;&lt;/H1&gt;
&lt;H1&gt;The Players&lt;/H1&gt;
&lt;P&gt;So how do you get your profiler attached to a running process?&amp;nbsp; The process has already started, and the CLR code which interrogates the environment to determine whether to load a profiler has already run.&amp;nbsp; So how do you kick the process into loading your profiler?&amp;nbsp; The answer: Another process!&lt;/P&gt;
&lt;P&gt;&lt;IMG height=275 src="http://blogs.msdn.com/photos/davbr/images/9778066/500x275.aspx" width=500 mce_src="http://blogs.msdn.com/photos/davbr/images/9778066/500x275.aspx"&gt; &lt;/P&gt;
&lt;P&gt;In order to force your profiler DLL to load into the target profilee process, you'll need to create a "trigger" process to send the attach message to the target profilee.&amp;nbsp; Many profilers already ship with a GUI shell to control launching processes to profile.&amp;nbsp; That shell will typically act as your trigger process as well.&lt;/P&gt;
&lt;H1&gt;Inside the Trigger Process&lt;/H1&gt;
&lt;P&gt;Your trigger uses a simple API method, AttachProfiler, to request the target process to load your profiler.&amp;nbsp; Where is this method defined?&amp;nbsp; Well, it doesn't make much sense to put it on ICorProfilerInfo, since that interface is only available to a profiler after it's been loaded.&amp;nbsp; You could imagine a C export from mscoree.dll.&amp;nbsp; But because of in-process side-by-side CLR instances, we're moving away from mscoree.dll exports to a COM-based interface model called "metahost".&amp;nbsp; &lt;/P&gt;
&lt;H2&gt;Meta-whos-its?&lt;/H2&gt;
&lt;P&gt;Whereas the "hosting" interfaces enable one to host and manage a CLR in a process, the "metahost" interfaces allow one to manage multiple CLRs that may be installed onto a machine or loaded into a single process.&amp;nbsp; Here's a high-level view of how you navigate your way through metahost to find AttachProfiler() (there’s a pointer to actual sample code below).&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Get ICLRMetaHost &lt;/LI&gt;
&lt;LI&gt;Enumerate the CLRs loaded into the target process &lt;/LI&gt;
&lt;LI&gt;Get ICLRRuntimeInfo for the particular CLR in the target process you want to profile &lt;/LI&gt;
&lt;LI&gt;Get the corresponding ICLRProfiling &lt;/LI&gt;
&lt;LI&gt;Call ICLRProfiling::AttachProfiler &lt;/LI&gt;&lt;/UL&gt;
&lt;H2&gt;Users and Integrity&lt;/H2&gt;
&lt;P&gt;The permissions required to attach a profiler are similar to those required to attach a debugger.&amp;nbsp; First, the trigger process must run as the same user as the target profilee OR as an administrator.&amp;nbsp; Second, on OS's that support process integrity levels, the trigger process must be running at an integrity level higher than or equal to that of the target profilee process.&amp;nbsp; For more information about integrity and mandatory labels, &lt;A href="http://msdn.microsoft.com/en-us/library/bb625964.aspx" mce_href="http://msdn.microsoft.com/en-us/library/bb625964.aspx"&gt;here's&lt;/A&gt; some reference from MSDN. &lt;/P&gt;
&lt;H2&gt;Sample Trigger Source Code&lt;/H2&gt;
&lt;P&gt;For some sample code to attach a profiler to a process, take a look at the sample uploaded to the MSDN Code Gallery &lt;A href="http://code.msdn.microsoft.com/ProfilerAttacher/" mce_href="http://code.msdn.microsoft.com/ProfilerAttacher/"&gt;here&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;You'll notice the code attempts to enable the SE_DEBUG_NAME privilege, as this is required to open a process running as another user with PROCESS_ALL_ACCESS.&amp;nbsp; Again, cross-user attach (i.e., trigger runs as a different user than the target profilee process) is only supported when the trigger is run as an administrator.&amp;nbsp; Otherwise, only same-user attach is supported, and would not need to enable the SE_DEBUG_NAME privilege.&lt;/P&gt;
&lt;H1&gt;Inside the Profilee Process&lt;/H1&gt;
&lt;P&gt;Once your trigger has called AttachProfiler(), a message is sent to the target profilee process to load your actual profiler DLL, containing info such as your profiler's GUID.&amp;nbsp; At this point, it's business as usual in the profilee.&amp;nbsp; The profilee locates and loads your profiler DLL, the CLR then calls your class factory object to create an instance of your profiler's ICorProfilerCallback implementation. &lt;/P&gt;
&lt;P&gt;Note that, instead of the CLR calling your Initialize() method, the CLR will call your ICorProfilerCallback3::InitializeForAttach() method.&amp;nbsp; There are two reasons for this difference.&amp;nbsp; First, this ensures that only profilers that have been upgraded to work with CLR V4 and opt into attaching will actually be attached.&amp;nbsp; All other profilers can simply return an error from their InitializeForAttach() method (or won't have an ICorProfilerCallback3 implementation to begin with).&lt;/P&gt;
&lt;P&gt;The second reason is that InitializeForAttach allows for some extra data to be passed from the trigger to your profilee via a blob of binary data.&amp;nbsp; What's that for?&amp;nbsp; Many profiler products pass configuration information from their shell to their startup-loaded profiler DLL via environment variables.&amp;nbsp; After all, the shell has to set COR_PROFILER &amp;amp; COR_ENABLE_PROFILING in the environment anyway, so why not set some more values there to be read by their profiler?&amp;nbsp; This scheme doesn't work for an attaching profiler, since the shell cannot affect the environment of the already-running profilee.&amp;nbsp; Instead, the AttachProfiler API allows the caller to specify a pointer to a buffer containing whatever data the caller wishes.&amp;nbsp; The CLR makes a copy of the data, sends it to the profilee, and then passes a pointer to this data to the profiler DLL via InitializeForAttach.&lt;/P&gt;
&lt;P&gt;The management of the memory containing this binary data follows the usual COM rules.&amp;nbsp; In the trigger process, your trigger code allocates memory for the blob, passes it to AttachProfiler (which will make its own copy of the data), and then your trigger code frees it once AttachProfiler returns.&amp;nbsp; Stack allocation is perfect here; your trigger could just push your own custom structure of data onto the stack and pass a pointer to it in your call to AttachProfiler.&amp;nbsp; Inside the profilee process, your profiler gets access to the blob of data from its InitializeForAttach method.&amp;nbsp; Inside InitializeForAttach, your profiler accesses that memory.&amp;nbsp; If your profiler will need to use that memory later on, your profiler should make a copy of the memory now.&amp;nbsp; After InitializeForAttach returns, the CLR will free the memory. &lt;/P&gt;
&lt;P&gt;From your InitializeForAttach implementation, your profiler will call SetEventMask as usual to announce your intentions, and you're off to the races.&lt;/P&gt;
&lt;H1&gt;Limitations&lt;/H1&gt;
&lt;P&gt;It was impossible to enable all profiling scenarios for attach in the time we had for the V4 release.&amp;nbsp; So only profilers that do &lt;STRONG&gt;sampling &lt;/STRONG&gt;and &lt;STRONG&gt;memory &lt;/STRONG&gt;analysis will function properly after attaching to a live process.&amp;nbsp; Attempts to use other profiling APIs after attach will be met with CORPROF_E_UNSUPPORTED_FOR_ATTACHING_PROFILER.&lt;/P&gt;
&lt;H3&gt;&lt;/H3&gt;
&lt;H2&gt;Specific Callback Limitations&lt;/H2&gt;
&lt;P&gt;When your attaching profiler calls SetEventMask, you will be limited to only those event mask flags present in the COR_PRF_ALLOWABLE_AFTER_ATTACH bitmask (you'll find it in corprof.idl).&amp;nbsp; Any other flags, and SetEventMask will return CORPROF_E_UNSUPPORTED_FOR_ATTACHING_PROFILER.&lt;/P&gt;
&lt;H2&gt;Specific Info Limitations&lt;/H2&gt;
&lt;P&gt;Most of the ICorProfilerInfo* methods are available to your attaching profiler, however some are not--particularly those involved in &lt;STRONG&gt;IL rewriting&lt;/STRONG&gt;.&amp;nbsp; Here's a list of all ICorProfilerInfo* methods NOT supported for attaching profilers:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;GetILFunctionBody &lt;/LI&gt;
&lt;LI&gt;GetILFunctionBodyAllocator &lt;/LI&gt;
&lt;LI&gt;SetILFunctionBody &lt;/LI&gt;
&lt;LI&gt;SetILInstrumentedCodeMap &lt;/LI&gt;
&lt;LI&gt;SetEnterLeaveFunctionHooks* &lt;/LI&gt;
&lt;LI&gt;SetFunctionIDMapper* &lt;/LI&gt;
&lt;LI&gt;GetNotifiedExceptionClauseInfo &lt;/LI&gt;
&lt;LI&gt;All methods related to Enter/Leave/Tailcall &lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;It's expected that future releases of the CLR will enable more API methods for use by attaching profilers.&lt;/P&gt;
&lt;H2&gt;GC Limitations&lt;/H2&gt;
&lt;H3&gt;GC Modes&lt;/H3&gt;
&lt;P&gt;To understand limitations around the GC modes, here's a quick review of the GC modes an app can run under:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;STRONG&gt;Workstation Blocking mode&lt;/STRONG&gt;.&amp;nbsp; The thread that triggered the GC performs the GC while all other threads executing managed code must wait. &lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Workstation Concurrent / Background mode (the default)&lt;/STRONG&gt;.&amp;nbsp; Concurrent GC (V1 &amp;amp; V2) allows portions of a full GC to execute while other threads are allowed to run.&amp;nbsp; Background GC (its replacement in V4) takes it one step further, and also allows an ephemeral GC (i.e., gen 0 or gen 1) to execute while a gen 2 GC is executing. &lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Server mode&lt;/STRONG&gt;.&amp;nbsp; Hosts like ASP.NET may choose to enable server mode which creates a heap + dedicated GC thread per CPU.&amp;nbsp; This allows GCs to be fanned out to multiple threads. &lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Of course, &lt;A href="http://blogs.msdn.com/maoni/" mce_href="http://blogs.msdn.com/maoni/"&gt;Maoni's blog&lt;/A&gt; is required reading for anyone who wants to understand how the GC works.&lt;/P&gt;
&lt;P&gt;The profiling API is able to work against workstation blocking mode and server mode, but not concurrent / background mode.&amp;nbsp; This has been the case in V1 &amp;amp; V2, and remains the case in V4.&amp;nbsp; When the app starts up, if a profiler is configured to load, then the CLR forcibly turns off concurrent / background mode, and you end up in workstation blocking mode (or you end up in server mode if the host requested that instead).&amp;nbsp; Again, this has been the case in V1 &amp;amp; V2, and remains true in V4.&lt;/P&gt;
&lt;P&gt;So here's the catch.&amp;nbsp; What if a V4 app starts up in background GC mode &lt;EM&gt;without&lt;/EM&gt; a profiler loading on startup, and you later attach a profiler to the process?&amp;nbsp; If the profiler specifies COR_PRF_MONITOR_GC in its call to SetEventMask, then the CLR returns the error CORPROF_E_CONCURRENT_GC_NOT_PROFILABLE.&amp;nbsp; In other words, if the profiler is late to the party, then it simply won't work if background GC is on.&amp;nbsp; Since this is the default for client apps, the bottom line is that you can generally successfully attach your memory profiler to server apps (e.g., ASP.NET), but probably not to client apps.&lt;/P&gt;
&lt;P&gt;Of course, you could forcibly turn off concurrent / background mode every time the app starts up via a config file:&lt;/P&gt;
&lt;TABLE class="" border=1&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD class=""&gt;
&lt;P&gt;&amp;lt;configuration&amp;gt; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;runtime&amp;gt; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;gcConcurrent enabled="false"/&amp;gt; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/runtime&amp;gt; &lt;BR&gt;&amp;lt;/configuration&amp;gt; &lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;
&lt;P&gt;But you don't really want to be running your apps with a sub-optimal GC mode all the time, just on the off-chance you might need to attach a memory profiler to it.&amp;nbsp; If you suspect you might need to do some memory profiling of a client app, you should just start up your app with the memory profiler to begin with.&lt;/P&gt;
&lt;H3&gt;ObjectAllocated&lt;/H3&gt;
&lt;P&gt;The ObjectAllocated callback is disallowed for attaching profilers (i.e., COR_PRF_ENABLE_OBJECT_ALLOCATED is not part of the COR_PRF_ALLOWABLE_AFTER_ATTACH mask).&lt;/P&gt;
&lt;H1&gt;Go Forth and Attach&lt;/H1&gt;
&lt;P&gt;All right, dig through that sample trigger code, and see if you can add "attach" to your list of features.&amp;nbsp; In later posts, I'll talk about how to catch up on application state once your profiler attaches, and also how to detach your profiler when it's done with its business.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9917430" width="1" height="1"&gt;</description></item><item><title>CLR V4 Beta 2 Released!</title><link>http://blogs.msdn.com/b/davbr/archive/2009/10/19/clr-v4-beta-2-released.aspx</link><pubDate>Mon, 19 Oct 2009 17:45:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9909270</guid><dc:creator>David Broman</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.msdn.com/b/davbr/rsscomments.aspx?WeblogPostID=9909270</wfw:commentRss><comments>http://blogs.msdn.com/b/davbr/archive/2009/10/19/clr-v4-beta-2-released.aspx#comments</comments><description>&lt;P&gt;All you profiler writers will want to try out your profiler on the latest and greatest!&lt;/P&gt;
&lt;P&gt;Information on getting beta 2 of CLR V4 and Visual Studio 2010 is available &lt;A class="" title=here href="http://msdn.microsoft.com/en-us/vstudio/dd582936.aspx" mce_href="http://msdn.microsoft.com/en-us/vstudio/dd582936.aspx"&gt;here&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;The beta 2 docs for the profiling API start &lt;A class="" title=here href="http://msdn.microsoft.com/en-us/library/ms404386(VS.100).aspx" mce_href="http://msdn.microsoft.com/en-us/library/ms404386(VS.100).aspx"&gt;here&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;There have been some bug fixes between beta 1 &amp;amp; beta 2 that may improve life for your profiler.&amp;nbsp; It's also worth noting that, for those of you dabbling with getting your profiler to attach to a running process, the method to get an instance of the metahost API has been renamed (since beta 1) to &lt;A class="" title=CLRCreateInstance href="http://msdn.microsoft.com/en-us/library/dd537633(VS.100).aspx" mce_href="http://msdn.microsoft.com/en-us/library/dd537633(VS.100).aspx"&gt;CLRCreateInstance&lt;/A&gt;.&amp;nbsp; If you're looking for more information on how to make your profiler attachable, I will be posting an entry on that as soon as I can.&lt;/P&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9909270" width="1" height="1"&gt;</description></item><item><title>Type Forwarding</title><link>http://blogs.msdn.com/b/davbr/archive/2009/09/30/type-forwarding.aspx</link><pubDate>Thu, 01 Oct 2009 03:33:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9901597</guid><dc:creator>David Broman</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.msdn.com/b/davbr/rsscomments.aspx?WeblogPostID=9901597</wfw:commentRss><comments>http://blogs.msdn.com/b/davbr/archive/2009/09/30/type-forwarding.aspx#comments</comments><description>&lt;p&gt;MSDN defines “type forwarding” as moving “a type to another assembly without having to recompile applications that use the original assembly”.&amp;#160; In this post, I’ll talk about examining a particular type in Microsoft’s .NET Framework library that gets forwarded, how you can use type forwarding for your own types, and what type forwarding looks like to consumers of the profiling API.&amp;#160; For some more official background on type forwarding, visit the MSDN &lt;a href="http://msdn.microsoft.com/en-us/library/ms404275(VS.100).aspx"&gt;topic&lt;/a&gt;.&amp;#160; If you Bing type forwarding you’ll find many blogs that talk about it as well.&amp;#160; Yes, that’s right.&amp;#160; I used Bing as a verb.&amp;#160; Get used to it; Bing is awesome.&lt;/p&gt;  &lt;p&gt;Type forwarding is nothing new.&amp;#160; However, in CLR V4, we are enabling type forwarding to work with generic types.&amp;#160; And there has been some new refactoring in System.Core.&amp;#160; This means you should expect to see type forwarding used more often than it had been in the past.&amp;#160; So if you code up a profiler, you should make sure you can deal with type forwarding appropriately.&amp;#160; The good news is that profiler code that uses the profiling API to inspect types generally should not need to change.&amp;#160; But if you do certain kinds of metadata lookups yourself, you may need to be aware of type forwarding.&amp;#160; More on that later.&lt;/p&gt;  &lt;h2&gt;Example: TimeZoneInfo&lt;/h2&gt;  &lt;p&gt;The example I’ll use where the .NET Framework uses type forwarding is the TimeZoneInfo class.&amp;#160; In CLR V4, TimeZoneInfo is now forwarded from System.Core.dll to mscorlib.dll.&amp;#160; If you open the CLR V4 copy of System.Core.dll in ildasm and choose Dump, you'll see the following:&lt;/p&gt;  &lt;table border="1"&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td&gt;         &lt;pre&gt;.class extern /*27000004*/ forwarder System.TimeZoneInfo
{
  .assembly extern mscorlib /*23000001*/ 
}&lt;/pre&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;In each assembly’s metadata is an exported types table.&amp;#160; The above means that System.Core.dll's exported types table includes an entry for System.TimeZoneInfo (indexed by token 27000004).&amp;#160; What's significant is that System.Core.dll no longer has a typeDef for System.TimeZoneInfo, only an exported type.&amp;#160; The fact that the token begins at the left with 0x27 tells you that it's an mdtExportedType (not a mdtTypeDef, which begins at the left with 0x02).&lt;/p&gt;

&lt;p&gt;At run-time, if the CLR type loader encounters this exported type, it knows it must now look in mscorlib for System.TimeZoneInfo.&amp;#160; And by the way, if someday mscorlib chooses to forward the type elsewhere, and thus the type loader found another exported type with name System.TimeZoneInfo in mscorlib, then the type loader would have to make yet another hop to wherever that exported type pointed.&lt;/p&gt;

&lt;h2&gt;Walkthrough 1: Observe the forwarding of System.TimeZoneInfo&lt;/h2&gt;

&lt;p&gt;This walkthrough assumes you have .NET 4.0 Beta 1 installed (see &lt;a href="http://blogs.msdn.com/davbr/archive/2009/05/26/clr-v4-beta-1-released.aspx"&gt;here&lt;/a&gt;) &lt;strong&gt;and&lt;/strong&gt; an older release of .NET, such as .NET 3.5, installed.&lt;/p&gt;

&lt;p&gt;Code up a simple C# app that uses System.TimeZoneInfo:&lt;/p&gt;

&lt;p&gt;&lt;span style="color: rgb(0,0,255)"&gt;namespace&lt;/span&gt; test 

  &lt;br /&gt;{ 

  &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &lt;span style="color: rgb(0,0,255)"&gt;class&lt;/span&gt; &lt;span style="color: rgb(43,145,175)"&gt;Class1 
    &lt;br /&gt;&lt;/span&gt;&amp;#160;&amp;#160;&amp;#160; { 

  &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span style="color: rgb(0,0,255)"&gt;static&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;void&lt;/span&gt; Main(&lt;span style="color: rgb(0,0,255)"&gt;string&lt;/span&gt;[] args) 

  &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; { 

  &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; System.TimeZoneInfo ti = &lt;span style="color: rgb(0,0,255)"&gt;null&lt;/span&gt;; 

  &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; } 

  &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; } 

  &lt;br /&gt;}&lt;/p&gt;

&lt;p&gt;Next, compile this into an exe using a CLR V2-based toolset (e.g., .NET 3.5).&amp;#160; You can use Visual Studio, or just run from the command-line (but be sure your path points to the pre-.NET 4.0 C# compiler!).&amp;#160; Example:&lt;/p&gt;

&lt;table border="1"&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;
        &lt;pre&gt;csc /debug+ /o- /r:&amp;quot;C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\v3.5\System.Core.dll&amp;quot; Class1.cs&lt;/pre&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;Again, be sure you’re using an old csc.exe from, say, a NET 3.5 installation.&amp;#160; To verify, open up Class1.exe in ildasm, and take a look at Main().&amp;#160; It should look something like this:&lt;/p&gt;

&lt;table border="1"&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;
        &lt;pre&gt;.method /*06000001*/ private hidebysig static 
        void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       4 (0x4)
  .maxstack  1
&lt;strong&gt;  .locals /*11000001*/ init ([0] class [&lt;font color="#ff0080"&gt;&lt;span style="background-color: #ffff00"&gt;&lt;font color="#ff0080"&gt;System.Core&lt;/font&gt;&lt;/span&gt;&lt;/font&gt;/*23000002*/]System.TimeZoneInfo/*01000006*/ ti)&lt;/strong&gt;
  IL_0000:  nop
  IL_0001:  ldnull
  IL_0002:  stloc.0
  IL_0003:  ret
} // end of method Class1::Main&lt;/pre&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;The key here is to note that the IL uses a TypeRef for System.TimeZoneInfo (01000006) that points to &lt;strong&gt;System.Core.dll&lt;/strong&gt;.&amp;#160; When you run Class1.exe against a .NET 3.5 runtime, it will find System.TimeZoneInfo in System.Core.dll as usual, and just use that, since System.TimeZoneInfo actually is defined in System.Core.dll in pre-.NET 4.0 frameworks.&amp;#160; However, what happens when you run Class1.exe against .NET 4.0 without recompiling?&amp;#160; Type forwarding would get invoked!&lt;/p&gt;

&lt;p&gt;Note that, if you were to build the above C# code using the .NET 4.0 C# compiler, it would automatically have generated a TypeRef that points to mscorlib.dll instead, so you wouldn't be able to observe the type forwarding at run-time.&lt;/p&gt;

&lt;p&gt;Ok, so how do we run this pre-.NET 4.0 executable against .NET 4.0?&amp;#160; A config file, of course.&amp;#160; Paste the following into a file named Class1.exe.config that sits next to Class1.exe:&lt;/p&gt;

&lt;table border="1"&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;
        &lt;pre&gt;&amp;lt;configuration&amp;gt;
   &amp;lt;startup&amp;gt;
      &amp;lt;supportedRuntime version=&amp;quot;v4.0.20506&amp;quot;/&amp;gt;
   &amp;lt;/startup&amp;gt;
&amp;lt;/configuration&amp;gt;&lt;/pre&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;The above will force Class1.exe to bind against .NET 4.0 Beta 1.&amp;#160; And when it comes time to look for TimeZoneInfo, the CLR will first look in System.Core.dll, find the exported types table entry, and then hop over to mscorlib.dll to load the type.&amp;#160; What does that look like to your profiler?&amp;#160; Make your guess and hold that thought.&amp;#160; First, another walkthrough…&lt;/p&gt;

&lt;h2&gt;Walkthrough 2: Forwarding your own type&lt;/h2&gt;

&lt;p&gt;To experiment with forwarding your own types, the process is:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Create Version 1 of your library 
    &lt;ul&gt;
      &lt;li&gt;Create version 1 of your library assembly that defines your type (MyLibAssemblyA.dll) &lt;/li&gt;

      &lt;li&gt;Create an app that references your type in MyLibAssemblyA.dll (MyClient.exe) &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;

  &lt;li&gt;Create version 2 of your library 
    &lt;ul&gt;
      &lt;li&gt;Recompile MyLibAssemblyA.dll to forward your type elsewhere (MyLibAssemblyB.dll) &lt;/li&gt;

      &lt;li&gt;Don’t recompile MyClient.exe.&amp;#160; Let it still think the type is defined in MyLibAssemblyA.dll. &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Version 1&lt;/h3&gt;

&lt;p&gt;Just make a simple C# DLL that includes your type Foo.&amp;#160; Something like this (MyLibAssemblyA.cs):&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: rgb(0,0,255)"&gt;using&lt;/span&gt; System;
&lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;class&lt;/span&gt; &lt;span style="color: rgb(43,145,175)"&gt;Foo
&lt;/span&gt;{
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;and compile it into MyLibAssemblyA.dll:&lt;/p&gt;

&lt;table border="1"&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;
        &lt;pre&gt;csc /target:library /debug+ /o- MyLibAssemblyA.cs&lt;/pre&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;Then make yourself a client app that references Foo.&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: rgb(0,0,255)"&gt;using&lt;/span&gt; System;
&lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;class&lt;/span&gt; &lt;span style="color: rgb(43,145,175)"&gt;Test
&lt;/span&gt;{
    &lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;static&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;void&lt;/span&gt; Main()
    {
        Foo foo = &lt;span style="color: rgb(0,0,255)"&gt;new&lt;/span&gt; Foo();
        &lt;span style="color: rgb(43,145,175)"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: rgb(0,0,255)"&gt;typeof&lt;/span&gt;(Foo).AssemblyQualifiedName);
    }
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;and compile this into MyClient.exe:&lt;/p&gt;

&lt;table border="1"&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;
        &lt;pre&gt;csc /debug+ /o- /r:MyLibAssemblyA.dll MyClient.cs&lt;/pre&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;When you run MyClient.exe, you get this boring output:&lt;/p&gt;

&lt;table border="1"&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;
        &lt;pre&gt;Foo, MyLibAssemblyA, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null&lt;/pre&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;Ok, time to upgrade!&lt;/p&gt;

&lt;h3&gt;Version 2&lt;/h3&gt;

&lt;p&gt;Time goes by, your library is growing, and its time to split it into two DLLs.&amp;#160; Gotta move Foo into the new DLL.&amp;#160; Save this into MyLibAssemblyB.cs&lt;/p&gt;

&lt;p&gt;&lt;span style="color: rgb(0,0,255)"&gt;using&lt;/span&gt; System; 

  &lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;class&lt;/span&gt; &lt;span style="color: rgb(43,145,175)"&gt;Foo 
    &lt;br /&gt;&lt;/span&gt;{ 

  &lt;br /&gt;}&lt;/p&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;compile that into your new DLL, MyLibAssemblyB.dll:&lt;/p&gt;

&lt;table border="1"&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;
        &lt;pre&gt;csc /target:library /debug+ /o- MyLibAssemblyB.cs&lt;/pre&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;And for the type forward.&amp;#160; MyLibAssemblyA.cs now becomes:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: rgb(0,0,255)"&gt;using&lt;/span&gt; System;
&lt;span style="color: rgb(0,0,255)"&gt;using&lt;/span&gt; System.Runtime.CompilerServices;
[&lt;span style="color: rgb(0,0,255)"&gt;assembly&lt;/span&gt;: &lt;span style="color: rgb(43,145,175)"&gt;TypeForwardedTo&lt;/span&gt;(&lt;span style="color: rgb(0,0,255)"&gt;typeof&lt;/span&gt;(Foo))]&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;compile that into MyLibAssemblyA.dll (overwriting your Version 1 copy of that DLL):&lt;/p&gt;

&lt;table border="1"&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;
        &lt;pre&gt;csc /target:library /debug+ /o- /r:MyLibAssemblyB.dll MyLibAssemblyA.cs&lt;/pre&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;Now, when you rerun MyClient.exe (without recompiling!), it will look for Foo first in MyLibAssemblyA.dll, and then hop over to MyLibAssemblyB.dll:&lt;/p&gt;

&lt;table border="1"&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;
        &lt;pre&gt;Foo, &lt;span style="background-color: #ffff00"&gt;MyLibAssemblyB&lt;/span&gt;, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null&lt;/pre&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;And this all despite the fact that MyClient.exe still believes that Foo lives in MyLibAssemblyA:&lt;/p&gt;

&lt;table border="1"&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;
        &lt;pre&gt;.method /*06000001*/ public hidebysig static 
        void  Main() cil managed
{
  .entrypoint
  // Code size       29 (0x1d)
  .maxstack  1
  .locals /*11000001*/ init ([0] class [MyLibAssemblyA/*23000002*/]Foo/*01000006*/ foo)
  IL_0000:  nop
  IL_0001:  newobj     instance void [MyLibAssemblyA/*23000002*/]Foo/*01000006*/::.ctor() /* 0A000004 */
  IL_0006:  stloc.0
 &lt;strong&gt; IL_0007:  ldtoken    [&lt;span style="background-color: #ffff00"&gt;MyLibAssemblyA&lt;/span&gt;/*23000002*/]Foo/*01000006*/&lt;/strong&gt;
  IL_000c:  call       class [mscorlib/*23000001*/]System.Type/*01000007*/ [mscorlib/*23000001*/]System.Type/*01000007*/::GetTypeFromHandle(valuetype [mscorlib/*23000001*/]System.RuntimeTypeHandle/*01000008*/) /* 0A000005 */
  IL_0011:  callvirt   instance string [mscorlib/*23000001*/]System.Type/*01000007*/::get_AssemblyQualifiedName() /* 0A000006 */
  IL_0016:  call       void [mscorlib/*23000001*/]System.Console/*01000009*/::WriteLine(string) /* 0A000007 */
  IL_001b:  nop
  IL_001c:  ret
} // end of method Test::Main&lt;/pre&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;h2&gt;Profilers&lt;/h2&gt;

&lt;p&gt;What does this look like to profilers?&amp;#160; Types are represented as ClassIDs, and modules as ModuleIDs.&amp;#160; When you query for info about a ClassID (via GetClassIDInfo2()), you get one and only one ModuleID to which it belongs.&amp;#160; So when a ClassID gets forwarded from one ModuleID to another, which does the profiling API report as its real home?&amp;#160; The answer: always the final module to which the type has been forwarded and therefore the module whose metadata contains the TypeDef (and not the exported type table entry).&lt;/p&gt;

&lt;p&gt;This should make life easy for profilers, since they generally expect to be able to find the metadata TypeDef for a type inside the ModuleID that the profiling API claims is the type’s home.&amp;#160; So much of type forwarding will be transparent to your profiler.&lt;/p&gt;

&lt;p&gt;However, type forwarding is important to understand if your profiler needs to follow metadata references directly.&amp;#160; More generally, if your profiler is reading through metadata and expects to come across a typeDef (e.g., perhaps a metadata reference points to a type in that module, or perhaps your profiler expects certain known types to be in certain modules), then your profiler should be prepared to find an mdtExportedType instead, and to deal gracefully with it rather than doing something silly like crashing.&lt;/p&gt;

&lt;p&gt;In any case, whether you think your profiler will be affected by type forwarding, be sure to test, test, test!&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9901597" width="1" height="1"&gt;</description></item><item><title>CLR V4: Load your profiler without using the registry</title><link>http://blogs.msdn.com/b/davbr/archive/2009/06/16/clr-v4-load-your-profiler-without-using-the-registry.aspx</link><pubDate>Tue, 16 Jun 2009 23:36:23 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9763071</guid><dc:creator>David Broman</dc:creator><slash:comments>2</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.msdn.com/b/davbr/rsscomments.aspx?WeblogPostID=9763071</wfw:commentRss><comments>http://blogs.msdn.com/b/davbr/archive/2009/06/16/clr-v4-load-your-profiler-without-using-the-registry.aspx#comments</comments><description>&lt;p&gt;One of the new features in CLR V4 is the ability to load your profiler without needing to register it first.&amp;#160; In V2, we would look at the following environment variables:&lt;/p&gt;  &lt;p&gt;COR_ENABLE_PROFILING=1&lt;/p&gt;  &lt;p&gt;COR_PROFILER={&lt;em&gt;CLSID of profiler&lt;/em&gt;}&lt;/p&gt;  &lt;p&gt;and look up the CLSID from COR_PROFILER in the registry to find the full path to your profiler's DLL.&amp;#160; Just like with any COM server DLL, we look for your profiler's CLSID under HKEY_CLASSES_ROOT, which merges the classes from HKLM and HKCU.&lt;/p&gt;  &lt;p&gt;We mostly follow the same algorithm in V4, so you can continue registering your profiler if you wish.&amp;#160; However, in V4 we look for one more environment variable first:&lt;/p&gt;  &lt;p&gt;COR_PROFILER_PATH=&lt;em&gt;full path to your profiler's DLL&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;If that environment variable is present, we skip the registry look up altogether, and just use the path from COR_PROFILER_PATH to load your DLL.&amp;#160; A couple things to note about this:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;COR_PROFILER_PATH is purely optional.&amp;#160; If you don't specify COR_PROFILER_PATH, we use the old procedure of looking up your profiler's CLSID in the registry to find its path&lt;/li&gt;    &lt;li&gt;If you specify COR_PROFILER_PATH &lt;em&gt;and&lt;/em&gt; register your profiler, then COR_PROFILER_PATH always wins.&amp;#160; Even if COR_PROFILER_PATH points to an invalid path, we will still use COR_PROFILER_PATH, and just fail to load your profiler.&lt;/li&gt;    &lt;li&gt;COR_PROFILER is &lt;em&gt;always required&lt;/em&gt;.&amp;#160; If you specify COR_PROFILER_PATH, we skip the registry look up; however, we still need to know your profiler's CLSID, so we can pass it to your class factory's CreateInstance call.&lt;/li&gt; &lt;/ul&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9763071" width="1" height="1"&gt;</description></item><item><title>What does Dave look like?</title><link>http://blogs.msdn.com/b/davbr/archive/2009/05/28/what-does-dave-look-like.aspx</link><pubDate>Thu, 28 May 2009 20:59:29 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9648266</guid><dc:creator>David Broman</dc:creator><slash:comments>1</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.msdn.com/b/davbr/rsscomments.aspx?WeblogPostID=9648266</wfw:commentRss><comments>http://blogs.msdn.com/b/davbr/archive/2009/05/28/what-does-dave-look-like.aspx#comments</comments><description>&lt;p&gt;Find out on channel 9 as Jon Langdon, Thomas Lai, and I &lt;a href="http://channel9.msdn.com/posts/Charles/CLR-4-Debugging-and-Profiling-Enhancements/"&gt;discuss&lt;/a&gt; some of the new diagnostics features in CLR V4.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9648266" width="1" height="1"&gt;</description></item><item><title>Run your V2 profiler binary on CLR V4</title><link>http://blogs.msdn.com/b/davbr/archive/2009/05/26/run-your-v2-profiler-binary-on-clr-v4.aspx</link><pubDate>Wed, 27 May 2009 04:38:27 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9643160</guid><dc:creator>David Broman</dc:creator><slash:comments>3</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.msdn.com/b/davbr/rsscomments.aspx?WeblogPostID=9643160</wfw:commentRss><comments>http://blogs.msdn.com/b/davbr/archive/2009/05/26/run-your-v2-profiler-binary-on-clr-v4.aspx#comments</comments><description>&lt;p&gt;Ok, you've installed VS 2010 beta 1, along with .NET FX 4.0 beta 1, and you're wondering--can you run your profiler against this new .NET framework without recompiling the profiler?&lt;/p&gt;  &lt;p&gt;Yes, you can!&amp;#160; Though not by default.&amp;#160; Although CLR V4 is much more compatible with CLR V2 than CLR V2 was with CLR V1.1, there are still some differences that can mess with your profiler's mind.&amp;#160; So by default, the CLR V4 runtime refuses to activate V2 profilers.&amp;#160; If you try, you'll see that the CLR will LoadLibrary the profiler, use the class factory to generate an instance of the callback object, try to QI for the new ICorProfilerCallback3, and then when that fails, the CLR will release the callback object and log an event to the event log explaining that you need to set COMPLUS_ProfAPI_ProfilerCompatibilitySetting appropriately as your way of &amp;quot;opting in&amp;quot; to running the older profiler binary against the newer CLR.&amp;#160; This message is meant for your users, as a way of telling them that the profiler vendor (you) may not yet have tested the profiler against CLR V4.&lt;/p&gt;  &lt;p&gt;So, how to use COMPLUS_ProfAPI_ProfilerCompatibilitySetting?&amp;#160; Set it to one of the following 3 values:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;EnableV2Profiler&lt;/li&gt;    &lt;ul&gt;     &lt;li&gt;It enables the V2 profiler to be activated by V4 CLR.&lt;/li&gt;   &lt;/ul&gt;    &lt;li&gt;DisableV2Profiler (default)&lt;/li&gt;    &lt;ul&gt;     &lt;li&gt;V4 CLR refuses to activate the V2 profiler, and logs an event to the event log.&lt;/li&gt;   &lt;/ul&gt;    &lt;li&gt;PreventLoad &lt;/li&gt;    &lt;ul&gt;     &lt;li&gt;V4 CLR does not load the profiler, regardless of the profiler&amp;#8217;s version.&amp;#160; This is useful for preventing problems in certain in-process side-by-side CLR scenarios.&amp;#160; More on that in an upcoming post.&lt;/li&gt;   &lt;/ul&gt; &lt;/ul&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9643160" width="1" height="1"&gt;</description></item><item><title>CLR V4 Beta 1 Released!</title><link>http://blogs.msdn.com/b/davbr/archive/2009/05/26/clr-v4-beta-1-released.aspx</link><pubDate>Wed, 27 May 2009 04:23:54 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9643108</guid><dc:creator>David Broman</dc:creator><slash:comments>1</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.msdn.com/b/davbr/rsscomments.aspx?WeblogPostID=9643108</wfw:commentRss><comments>http://blogs.msdn.com/b/davbr/archive/2009/05/26/clr-v4-beta-1-released.aspx#comments</comments><description>&lt;p&gt;Now is the time to try out your profiler against the new .NET FX 4.0 Beta 1 bits.&amp;#160; I'll be writing about some gotchas, and how to take advantage of the new features.&amp;#160; But first, get started downloading:&lt;/p&gt;  &lt;p&gt;&lt;a title="Visual Studio 2010 Product Page" href="http://www.microsoft.com/visualstudio/products/2010/default.mspx"&gt;Visual Studio 2010 Product Page&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;You can find some reference documentation on the new profiling interfaces here:&lt;/p&gt;  &lt;p&gt;&lt;a title="http://msdn.microsoft.com/en-us/library/ms404386(VS.100).aspx" href="http://msdn.microsoft.com/en-us/library/ms404386(VS.100).aspx"&gt;http://msdn.microsoft.com/en-us/library/ms404386(VS.100).aspx&lt;/a&gt;&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9643108" width="1" height="1"&gt;</description></item><item><title>FunctionHooks.zip re-uploaded</title><link>http://blogs.msdn.com/b/davbr/archive/2009/02/14/functionhooks-zip-re-uploaded.aspx</link><pubDate>Sun, 15 Feb 2009 01:45:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9422797</guid><dc:creator>David Broman</dc:creator><slash:comments>1</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.msdn.com/b/davbr/rsscomments.aspx?WeblogPostID=9422797</wfw:commentRss><comments>http://blogs.msdn.com/b/davbr/archive/2009/02/14/functionhooks-zip-re-uploaded.aspx#comments</comments><description>&lt;P&gt;Jonathan Keljo's &lt;A class="" href="http://blogs.msdn.com/jkeljo/archive/2005/08/11/450506.aspx" mce_href="http://blogs.msdn.com/jkeljo/archive/2005/08/11/450506.aspx"&gt;blog entry&lt;/A&gt; on the enter/leave/tailcall function hooks had a link to sample code that's been broken for a while.&amp;nbsp; You can now find the sample code here: &lt;A class="" href="http://feeblah.members.winisp.net/direct/blog/FunctionHooks.zip" mce_href="http://feeblah.members.winisp.net/direct/blog/FunctionHooks.zip"&gt;FunctionHooks.zip&lt;/A&gt;&lt;/P&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9422797" width="1" height="1"&gt;</description></item></channel></rss>