2006-05-31 Senganal T <tsenganal@novell.com>
[mono.git] / web / performance
index dfe1e4753739836ff48a198b41856e77d49e1c3d..3760197ed1466cd8e47c5f294adc31dd13a040b1 100644 (file)
@@ -1,19 +1,30 @@
-* Writing performant .NET and Mono applications
+* Writing better performing .NET and Mono applications
+
+<center>
+Miguel de Icaza (miguel@novell.com)<br>
+Ben Maurer (bmaurer@users.sourceforge.net)
+</center>
 
        The following document contains a few hints on how to improve
        the performance of your Mono/.NET applications.
 
        These are just guidelines, and you should still profile your
        code to find the actual performance problems in your
-       application.
+       application. It is never a smart idea to make a change with the
+       hopes of improving the performance of your code without first
+       measuring. In general, these guidelines should serve as ideas
+       to help you figure out `how can I make this method run faster'.
+       
+       It is up to you to figure out, `Which method is running slowly.'
 
 ** Using the Mono profiler
+       
+       So, how does one measure what method are running slowly? A profiler
+       helps with this task. Mono includes a profiler that is built
+       into the runtime system. You can invoke this profiler on your program
+       by running with the --profile flag.
 
-       To obtain memory consumption and measure the time spent on
-       functions and the number of times a function is called in
-       Mono, you can invoke the runtime with the --profile flag, like this:
-
-<pre>
+<pre class="shell">
        mono --profile program.exe
 </pre>
 
        for profiling.  The default Mono profiler will record the time
        spent on a routine, the number of times the routine called,
        the memory consumed by each method broken down by invoker, and
-       the total amount of memory consumed, this is what it looks
-       like:
-<pre>
+       the total amount of memory consumed.
+
+       It does this by asking the JIT to insert a call to the profiler
+       every time a method is entered or left. The profiler times the
+       amount of time elapsed between the beginning and the end of the
+       call. The profiler is also notified of allocations.
+       
+       When the program has finished executing, the profiler prints the
+       data in human readable format. It looks like:
+
+<pre class="shell">
 Total time spent compiling 227 methods (sec): 0.07154
 Slowest method to compile (sec): 0.01893: System.Console::.cctor()
 Time(ms) Count   P/call(ms) Method name
@@ -44,10 +63,48 @@ Total mem Method
 Total memory allocated: 448 KB
 </pre>
 
+       At the top, it shows each method that is called. The data is sorted
+       by the total time that the program spent within the method. Then
+       it shows how many times the method was called, and the average time
+       per call.
+       
+       Below this, it shows the top callers of the method. This is very useful
+       data. If you find, for example, that the method Data::Computate () takes
+       a very long time to run, you can look to see if any of the calls can be
+       avoided.
+       
+       Two warnings must be given about the method data. First,
+       the profiler has an overhead associated with it. As such,
+       a high number of calls to a method may show up as consuming
+       lots of time, when in reality they do not consume much time
+       at all. If you see a method that has a very high number of
+       calls, you may be able to ignore it. However, do consider
+       removing calls if possible, as that will sometimes help
+       performance. This problem is often seen with the use
+       of built in collection types.
+       
+       Secondly, due to the nature of the profiler, recursive calls
+       have extremely large times (because the profiler double counts
+       when the method calls itself). One easy way to see this problem
+       is that if a method is shown as taking more time than the Main
+       method, it is very likely recursive, and causing this problem.
+       
+       Below the method data, allocation data is shown. This shows
+       how much memory each method allocates. The number beside
+       the method is the total amount of memory. Below that, it
+       is broken down into types. Then, the caller data is given. This
+       data is again useful when you want to figure out how to eliminate calls.
+       
        You might want to keep a close eye on the memory consumption
        and on the method invocation counts.   A lot of the
        performance gains in MCS for example came from reducing its
-       memory usage, as opposed to changes in the execution path. 
+       memory usage, as opposed to changes in the execution path.
+
+** Profiling without JIT instrumentation
+
+       You might also be interested in using mono --aot to generate
+       precompiled code, and then use a system like `oprofile' to 
+       profile your programs. 
 
 ** Memory Management in the .NET/Mono world.
 
@@ -57,8 +114,85 @@ Total memory allocated: 448 KB
        is a great productivity gain, but if you create thousands of
        objects, that will make the garbage collector do more work,
        and it might slow down your application.
+       
+       Remember, each time you allocate an object, the GC is forced
+       to find space for the object. Each object has an 8 byte overhead
+       (4 to tell what type it is, then 4 for a sync block). If
+       the GC finds that it is running out of room, it will scan every
+       object for pointers, looking for unreferenced objects. If you allocate
+       extra objects, the GC then must take the effort to free the objects.
+       
+       Mono uses the Boehm GC, which is a conservative collector,
+       and this might lead to some memory fragmentation and unlike
+       generational GC systems, it has to scan the entire allocated
+       memory pool.
+       
+*** Boxing
+       The .NET framework provides a rich hierarchy of object types.
+       Each object not only has value information, but also type
+       information associated with it. This type information makes
+       many types of programs easier to write. It also has a cost
+       associated with it. The type information takes up space.
+       
+       In order to reduce the cost of type information, almost every
+       Object Oriented language has the concept of `primitives'.
+       They usually map to types such as integers and booleans. These
+       types do not have any type information associated with them.
+       
+       However, the language also must be able to treat primitives
+       as first class datums -- in the class with objects. Languages
+       handle this issue in different ways. Some choose to make a
+       special class for each primitive, and force the user to do an
+       operation such as:
+<pre class="shell">
+// This is Java
+list.add (new Integer (1));
+System.out.println (list.get (1).intValue ());
+</pre>
+
+       The C# design team was not satisfied with this type 
+       of construct. They added a notion of `boxing' to the language.
+       
+       Boxing preforms the same thing as Java's <code>new Integer (1)</code>.
+       The user is not forced to write the extra code. However,
+       behind the scenes the <em>same thing</em> is being done
+       by the runtime. Each time a primitive is cast to an object,
+       a new object is allocated.
+       
+       You must be careful when casting a primitive to an object.
+       Note that because it is an implicit conversion, you will
+       not see it in your code. For example, boxing is happening here:
+
+<pre class="shell">
+ArrayList foo = new ArrayList ();
+foo.Add (1);
+</pre>
+       
+       In high performance code, this operation can be very costly.
 
-** foreach
+*** Using structs instead of classes for small objects
+
+       For small objects, you might want to consider using value
+       types (structs) instead of object (classes).
+       
+       However, you must be careful that you do not use the struct
+       as an object, in that case it will actually be more costly.
+       
+       As a rule of thumb, only use structs if you have a small
+       number of fields (totaling less than 32 bytes), and
+       need to pass the item `by value'. You should not box the object.
+
+*** Assisting the Garbage Collector
+
+       Although the Garbage Collector will do the right thing in
+       terms of releasing and finalizing objects on time, you can
+       assist the garbage collector by clearing the fields that
+       points to objects.  This means that some objects might be
+       eligible for collection earlier than they would, this can help
+       reduce the memory consumption and reduce the work that the GC
+       has to do.
+
+** Common problems with <tt>foreach</tt>
 
        The <tt>foreach</tt> C# statement handles various kinds of
        different constructs (about seven different code patterns are
@@ -73,24 +207,9 @@ Total memory allocated: 448 KB
        like ArrayList is more efficient than using the ArrayList
        indexer, the pressure introduced due to the extra memory
        requirements and the demands on the garbage collector make it
-       more inneficient.
+       more inefficient.
 
        There is no straight-forward rule on when to use foreach, and
        when to use a manual loop.  The best thing to do is to always
        use foreach, and only when profile shows a problem, replace
        foreach with for loops.
-
-*** Using structs instead of classes for small objects
-
-       For small objects, you might want to consider using value
-       types (structs) instead of object (classes).
-
-** Assisting the Garbage Collector
-
-       Although the Garbage Collector will do the right thing in
-       terms of releasing and finalizing objects on time, you can
-       assist the garbage collector by clearing the fields that
-       points to objects.  This means that some objects might be
-       elegible for collection earlier than they would, this can help
-       reduce the memory consumption and reduce the work that the GC
-       has to do.