Performance related issues.
Because of disk caching and the nature of managed programs, you can expect a significant variance between identical performance tests, so always run multiple tests and take an average. You may want to throw out the first test in a series, because load and parse times will be much higher if the files read from disk hadn't been cached yet. Performance might also vary significantly depending upon code features used - for example, heavy use of lambda expressions might slow things down.
The following are approximate performance times of this library for very large solutions, to give a rough idea of what to expect. These are averaged over 3 different large solutions each containing 3,000 to 5,000 files, roughly 600,000 lines of code, and 1.5 to 1.8 million total code objects. The tests were run on a machine with an Intel Core i7 920 @ 2.67Ghz, Windows 7 64-bit, running in 32-bit mode with .NET 4.5:
Load time of about 1 second (if files have been cached).
Parse time of about 3 seconds (if files have been cached).
Resolve time of about 8-16 seconds.
Total processing time of about 13-22 seconds.
Memory usage (after processing is complete and garbage is collected) of about 185-225 MB when using Mono Cecil to access metadata in referenced assemblies, or 120-130 MB when using Reflection.
For a medium-size solution with about 800 files, 170,000 lines of code, and 425,000 code objects, the numbers should be around 0.4 seconds to load, 0.9 to parse, 3.5 to resolve, a total time of 5.0, and 50 MB.
For a smaller-size solution with about 300 files, 25,000 lines of code, and 60,000 code objects, the numbers should be about 0.1 seconds to load, 0.1 to parse, 0.5 to resolve, a total time of 0.8, and 26 MB.
The following are some ways in which you might be able to improve the performance of this library for your particular purposes:
If you don't have it, install .NET 4.5 on your machine - it's an in-place upgrade to .NET 4.0 that is MUCH faster. You can still target your own apps for .NET 4.0 (although you should also let your own users know that installing .NET 4.5 will give them a performance boost).
If you don't need it, turn off the default message logging, which writes to the Console and is very slow. You may either set the Log.LogLevel setting in the '.config' file to None, or with 'Log.LogLevel = Log.Level.None;' in your code. The more typical usage would be to leave logging on Minimal or Normal, but to intercept the default logging mechanism so that messages go to your code instead of the Console like this: Log.SetLogWriteLineCallback(LoggingMethod);
If your app shouldn't require more than 2 GB of memory, use 32-bit (x86) mode. The Nova CodeDOM library tends to run about 15% SLOWER in 64-bit mode (30% slower for one of our test cases), while using about 40% more memory (see the next section for more information). Don't assume that your app will perform much better in 64-bit mode - test it to determine its behavior.
If you don't need to resolve symbolic references, then use the LoadOptions.DoNotResolve flag when loading. For example, for code formatting or certain code metrics, references do not need to be resolved. The code object tree will contain UnresolvedRefs instead of LocalRefs, MethodRefs, etc. - refering to unresolved names instead of links to the referenced objects.
If you are only manipulating Solution and/or Project objects, you can use LoadOptions.LoadOnly to prevent parsing of source files in addition to not resolving them.
If you only need to work with types and the signatures of their members, but not the code in method bodies, you may use LoadOptions.DoNotResolveBodies to prevent resolving, or LoadOptions.DoNotParseBodies to prevent parsing them (the Body of all method objects will be null, therefore also leaving nothing to be resolved). These flags can cut Parse times by up to 50%, and Resolve times by about 80%.
The Nova.CodeDOM.dll has a target of AnyCPU. This means that on a 64-bit OS, it will run in 64-bit mode if called by a 64-bit process, or in 32-bit mode if called by a 32-bit process. So, as a user of this library, the mode used is basically under your control. If your product is also a library, building it as AnyCPU will pass this control on to your own users.
Programs aren't guaranteed to run faster in 64-bit mode - they might run faster or slower, depending upon the particular program. The primary reason for running a program in 64-bit mode is to exceed the default 2GB memory limit of 32-bit programs, and a major tradeoff is that because all memory addresses are twice the size, the program will tend to use quite a bit more memory for the same amount of data (which is one reason why performance might actually be slower rather than faster). Another issue is that some bugs and problems are possible in 64-bit mode due to lack of testing in that mode or referenced assemblies that are 32-bit specific. In general, doing 64-bit calculations is not a major reason to use 64-bit mode, because 64-bit CPUs support such operations in 32-bit mode. It is generally a good idea to run a 64-bit OS on a 64-bit CPU in order to exceed the 3 GB physical memory limitation, but this doesn't mean that all of your applications should run in 64-bit mode.
Here are some issues to be aware of when using this library in 64-bit mode:
Memory usage tests of this library with large solutions (up to 5,000 files and 600,000 total lines) indicate that the 2 GB memory limitation should not become a problem until the total source lines are over 5,000,000. So, in the vast majority of cases, 64-bit mode should not be necessary in order to load the solution.
Parse and resolve times actually tend to be slower in 64-bit mode - about 15% overall on average in our tests when using Mono Cecil for metadata and .NET 4.5. File load times are mostly I/O bound, and generally aren't significantly different between modes even when they are cached.
Memory usage tends to be about 40% greater in 64-bit mode when loading identical solutions and using Mono Cecil for metadata. If using Reflection for metadata, it can be 70-80% greater.
If you use Reflection instead of Mono Cecil to load metadata from referenced assemblies, loaded projects that reference DLLs that only support 32-bit mode will fail to load and symbolic references to types in those DLLs will fail to resolve. It is unlikely (although theoretically possible) that a DLL would support 64-bit mode only.
Because of these issues, the Nova.CLI and Nova.Studio executables shipped with this library are built to run as 32-bit apps (x86). If you need 64-bit (AnyCPU) versions for some reason, send an email requesting them to: firstname.lastname@example.org