2005-09-22 Chris Toshok <toshok@ximian.com>
[mono.git] / web / performance
index a986656d2e885a63f599da24d4c72039c46c1ba1..3760197ed1466cd8e47c5f294adc31dd13a040b1 100644 (file)
@@ -1,4 +1,9 @@
-* 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.
@@ -19,7 +24,7 @@
        into the runtime system. You can invoke this profiler on your program
        by running with the --profile flag.
 
-<pre>
+<pre class="shell">
        mono --profile program.exe
 </pre>
 
@@ -37,7 +42,7 @@
        When the program has finished executing, the profiler prints the
        data in human readable format. It looks like:
 
-<pre>
+<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
@@ -70,7 +75,7 @@ Total memory allocated: 448 KB
        
        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 comsuming
+       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
@@ -79,12 +84,12 @@ Total memory allocated: 448 KB
        of built in collection types.
        
        Secondly, due to the nature of the profiler, recursive calls
-       have extermely large times (because the profiler double counts
+       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 sown. This shows
+       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
@@ -95,6 +100,12 @@ Total memory allocated: 448 KB
        performance gains in MCS for example came from reducing its
        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.
 
        Since Mono and .NET offer automatic garbage collection, the
@@ -110,8 +121,78 @@ Total memory allocated: 448 KB
        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.
+
+*** 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.
 
-** foreach
+*** 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
@@ -126,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.