13

I'm curious how does a typical C# profiler work?

Are there special hooks in the virtual machine?

Is it easy to scan the byte code for function calls and inject calls to start/stop timer?

Or is it really hard and that's why people pay for tools to do this?

(as a side note i find a bit interesting bec it's so rare - google misses the boat completely on the search "how does a c# profiler work?" doesn't work at all - the results are about air conditioners...)

Aaron Anodide
  • 16,906
  • 15
  • 62
  • 121
  • 2
    This article has lots of good info: http://msdn.microsoft.com/en-us/magazine/cc301725.aspx. Also http://msdn.microsoft.com/en-us/library/bb384547.aspx – Jim Mischel Apr 27 '11 at 21:26
  • Generally a lot of profilers take very frequent snapshots of the stack to see where it's currently at. Then they build statistics using those snapshots. Of course there's the distinct possibility that this isn't the case with C#, so take this with a grain of salt. – Chris Eberle Apr 27 '11 at 21:29
  • When I search Google for that string, it works fine. But note that, when you click your link, the search string in the page title is truncated after 'c': that `#` is probably messing something up, somewhere... – Dan J Apr 27 '11 at 21:30
  • I got the same Google results as @Gabriel but changing it to-- how does a "c#" profiler work --fixed this. I still didn't get any good answers, so good question. Change C# to CLR and Profiler to Profiling and you'll probably get better results. – Michael Greene Apr 27 '11 at 21:34
  • I'm too lazy to read this and convert it to a proper answer, but http://msdn.microsoft.com/en-us/library/ms404386.aspx should be useful to you. – Michael Greene Apr 27 '11 at 21:37
  • 2
    Note that it's not a C# profiler - it's a CLR profiler. Therefore: http://www.google.com/search?q=how+does+a+CLR+oprofiler+work%3F – John Saunders Apr 27 '11 at 21:52
  • What the definition of "typical"? and of "C#"? You means specifically C#, or you mean CLR? – Ira Baxter Apr 27 '11 at 21:54
  • Typically, [profilers suffer from various problems](http://stackoverflow.com/questions/4387895/if-profiler-is-not-the-answer-what-other-choices-do-we-have/4390868#4390868). – Mike Dunlavey Apr 28 '11 at 11:54

4 Answers4

3

There is a free CLR Profiler by Microsoft, version 4.0.

https://www.microsoft.com/downloads/en/details.aspx?FamilyID=be2d842b-fdce-4600-8d32-a3cf74fda5e1

BTW, there's a nice section in the CLR Profiler doc that describes how it works, in detail, page 103. There's source as part of distro.

GregC
  • 7,737
  • 2
  • 53
  • 67
3

Is it easy to scan the byte code for function calls and inject calls to start/stop timer?

Or is it really hard and that's why people pay for tools to do this?

Injecting calls is hard enough that tools are needed to do it.

Not only is it hard, it's a very indirect way to find bottlenecks. The reason is what a bottleneck is is one or a small number of statements in your code that are responsible for a good percentage of time being spent, time that could be reduced significantly - i.e. it's not truly necessary, i.e. it's wasteful. IF you can tell the average inclusive time of one of your routines (including IO time), and IF you can multiply it by how many times it has been called, and divide by the total time, you can tell what percent of time the routine takes. If the percent is small (like 10%) you probably have bigger problems elsewhere. If the percent is larger (like 20% to 99%) you could have a bottleneck inside the routine. So now you have to hunt inside the routine for it, looking at things it calls and how much time they take. Also you want to avoid being confused by recursion (the bugaboo of call graphs).

There are profilers (such as Zoom for Linux, Shark, & others) that work on a different principle. The principle is that there is a function call stack, and during all the time a routine is responsible for (either doing work or waiting for other routines to do work that it requested) it is on the stack. So if it is responsible for 50% of the time (say), then that's the amount of time it is on the stack, regardless of how many times it was called, or how much time it took per call. Not only is the routine on the stack, but the specific lines of code costing the time are also on the stack. You don't need to hunt for them. Another thing you don't need is precision of measurement. If you took 10,000 stack samples, the guilty lines would be measured at 50 +/- 0.5 percent. If you took 100 samples, they would be measured as 50 +/- 5 percent. If you took 10 samples, they would be measured as 50 +/- 16 percent. In every case you find them, and that is your goal. (And recursion doesn't matter. All it means is that a given line can appear more than once in a given stack sample.)

On this subject, there is lots of confusion. At any rate, the profilers that are most effective for finding bottlenecks are the ones that sample the stack, on wall-clock time, and report percent by line. (This is easy to see if certain myths about profiling are put in perspective.)

Community
  • 1
  • 1
Mike Dunlavey
  • 40,059
  • 14
  • 91
  • 135
  • +1! Sounds like we should be writing a new profiler for dotNET with this simple concept in mind. As far as UI goes, I was thinking of WinDirStat, only we'd show time spent in various methods, grouped by namespaces.classes. – GregC Apr 29 '11 at 00:17
  • @GregC: I wrote one ages ago. I just had it collect stack samples when you press both shift keys. Then I had a butterfly view focussed on a line of code, not a function. It started at a line with high %, and you could bump to neighboring lines up & down. It made a nice demo, but I discovered for serious work, it couldn't beat the purely manual method, for a number of reasons, so I let it rest. At any rate, if you do something similar to Zoom, you'll have a winner, IMHO. – Mike Dunlavey Apr 29 '11 at 01:09
  • @GregC: What I mean by not beating the manual method is, sure it's more trouble to collect several samples manually, pick a "hot" line and see the tree down and up from that line. That's a little tedious. But if something catches my eye, I take more samples until it reoccurs, and then I study it to narrate what the program was doing and why. This may mean looking at other data besides the stack. When I fully understand it, I can tell if it's actually wasteful & can be replaced with something better. So finding high % lines is just a lead-in to the process. – Mike Dunlavey Apr 29 '11 at 01:23
1

1) There's no such thing as "typical". People collect profile information by a variety of means: time sampling the PC, inspecting stack traces, capturing execution counts of methods/statements/compiled instructions, inserting probes in code to collect counts and optionally calling contexts to get profile data on a call-context basis. Each of these techniques might be implemented in different ways.

2) There's profiling "C#" and profiling "CLR". In the MS world, you could profile CLR and back-translate CLR instruction locations to C# code. I don't know if Mono uses the same CLR instruction set; if they did not, then you could not use the MS CLR profiler; you'd have to use a Mono IL profiler. Or, you could instrument C# source code to collect the profiling data, and then compile/run/collect that data on either MS, Mono, or somebody's C# compatible custom compiler, or C# running in embedded systems such as WinCE where space is precious and features like CLR-built-ins tend to get left out.

One way to instrument source code is to use source-to-source transformations, to map the code from its initial state to code that contains data-collecting code as well as the original program. This paper on instrumenting code to collect test coverage data shows how a program transformation system can be used to insert test coverage probes by inserting statements that set block-specific boolean flags when a block of code is executed. A counting-profiler substitutes counter-incrementing instructions for those probes. A timing profiler inserts clock-snapshot/delta computations for those probes. Our C# Profiler implements both counting and timing profiling for C# source code both ways; it also collect the call graph data by using more sophisticated probes that collect the execution path. Thus it can produce timing data on call graphs this way. This scheme works anywhere you can get your hands on a halfway decent resolution time value.

Ira Baxter
  • 93,541
  • 22
  • 172
  • 341
1

This is a link to a lengthy article that discusses both instrumentation and sampling methods:

http://smartbear.com/support/articles/aqtime/profiling/

Louis Somers
  • 2,560
  • 3
  • 27
  • 57