Jan 19 2009

Neovolve.BlogEngine.Extensions 1.1 released

Category: .Net | My SoftwareRory Primrose @ 08:10

This release contains bug fixes and added features for CatTagLinker and Snippets BlogEngine.Net extensions. See Neovolve BlogEngine Extensions 1.1 Help for further information. The release can be downloaded from here.

Tags: ,

Jan 14 2009

BlogEngine.Net caching

Category: Applications | .NetRory Primrose @ 07:57

Here is a little tip I forgot the other day (and it did shoot me in the foot). If you are changing the BlogEngine.Net data source directly, don't forget to recycle the application. This is because BlogEngine.Net holds blog data in memory. You will be working with stale data if you change the data source and use the application without restarting it.

Tags:

Jan 12 2009

Guidance on use of <include /> in XML documentation comments

Category: .Net | ApplicationsRory Primrose @ 08:32

I have previously posted about using the include element for my XML documentation in cases where there is duplicated content. After a recent code review, the reviewer commented that the include element made it difficult to read the documentation because large parts of the XML documentation were abstracted out to an XML file. This made me look at ways around this and the affect of the include tag had on the tooling support.

As a quick overview, the include element in XML documentation tells the compiler to go to the specified XML file and run an XPath query (recursively). It pulls in the result of that XPath query and injects the content into the XML documentation being generated for a code element.

Advantages

  • Documentation reuse
  • Removes noise in a code file if the bulk of the documentation points to an included reference

Disadvantages 

Guidance

There is a tug of war between the reducing noise advantage and the readability disadvantage so the decision between the two must be made with respect to the code and its readers/consumers.

The disadvantages listed are primarily regarding the tooling support. With the issues stated for Visual Studio and ReSharper, they are only issues for when the interpretation of the XML documentation is done from the source directly (meaning intellisense within the same solution), rather than the compiler generated XML documentation file. The StyleCop issue is a bigger disadvantage especially if you are using the tool for strict validation as part of a continuous integration process.

To satisfy all but the readability disadvantage, I suggest that you avoid using an include to:

  1. Define XML documentation structure required by StyleCop (summary, param and returns elements)
  2. Define content that affect StyleCop validation (summary, param and returns elements)
  3. Define XML documentation structure parsed by Visual Studio intellisense (exception element)
  4. Define content that affect Visual Studio and ReSharper intellisense (summary, param and returns elements)

The include element is very useful for moving remarks and code examples out of the code file to reduce noise. When reading the code file, these items are not normally required for the readability of the file and don't affect intellisense.

Note: The StyleCop issues should be fixed in the next version. There is no indication about intellisense fixes to Visual Studio or ReSharper. The use of the include element may change as these issues are fixed.

Tags: ,

Jan 12 2009

Tracing Performance Tips

Category: .NetRory Primrose @ 07:18

I have recently been working with tracing performance and have posted several tidbits of information. Here is the overview.

  1. Use TraceSource instead of Trace
  2. Disable global locking
  3. Clear the default listener in configuration
  4. Don't collect stacktrace information if not required
  5. Create TraceSource instances once per name and cache for reuse. I have encountered memory leaks from creating large numbers of instances of the same TraceSource name.
  6. Create a unique TraceSource and TraceListener for each logical part/tier/layer of the application (locking performance and data segregation)
  7. Use thread safe listeners if possible
  8. Check TraceSource.Switch.ShouldTrace before calculating any expensive information to provide to the trace message

On a side note, don't forget to turn off code coverage for running load tests.

Tags: ,

Jan 8 2009

Don't trace the callstack if you don't need to

Category: .NetRory Primrose @ 10:04

Here is another performance tip with tracing. In configuration, there is the opportunity to define some tracing options. These options determine the actions taken by TraceListener when it writes the footer of the trace record for a given message. One of the options is to output the Callstack.

It takes a bit of work to calculate the callstack. If you don't need that information, then don't configure your listeners to calculate it.

To demonstrate the difference, I created two load tests that each ran a unit test that used its own specific TraceSource. The reason for two separate load tests was to avoid a locking issue that would impact the results.

Here is the configuration I used:

<?xml version="1.0" encoding="utf-8" ?> 
<configuration> 
  <system.diagnostics> 
    <trace useGlobalLock="false" /> 
    <sources> 
      <source name="WithCallstack" 
              switchValue="All"> 
        <listeners> 
          <clear /> 
          <add type="System.Diagnostics.DefaultTraceListener, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" 
              name="SlimListener" 
              traceOutputOptions="Callstack" /> 
        </listeners> 
      </source> 
      <source name="Slim" 
              switchValue="All"> 
        <listeners> 
          <clear /> 
          <add type="System.Diagnostics.DefaultTraceListener, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" 
              name="SlimListener" /> 
        </listeners> 
      </source> 
    </sources> 
  </system.diagnostics> 
</configuration> 

And here are the unit tests:

using System; 
using System.Diagnostics; 
using Microsoft.VisualStudio.TestTools.UnitTesting; 

namespace TestProject3 
{ 
    /// <summary> 
    /// Summary description for TraceTests 
    /// </summary> 
    [TestClass] 
    public class TraceTests 
    { 
        private const String Message = "this is the message to be written"; 
        private static readonly TraceSource CallstackSource = new TraceSource("WithCallstack"); 
        private static readonly TraceSource SlimSource = new TraceSource("Slim"); 

        /// <summary> 
        /// Callstacks the test. 
        /// </summary> 
        [TestMethod] 
        public void CallstackTest() 
        { 
            CallstackSource.TraceInformation(Message); 
        } 

        /// <summary> 
        /// Slims the test. 
        /// </summary> 
        [TestMethod] 
        public void SlimTest() 
        { 
            SlimSource.TraceInformation(Message); 
        } 

        /// <summary> 
        ///Gets or sets the test context which provides 
        ///information about and functionality for the current test run. 
        ///</summary> 
        public TestContext TestContext 
        { 
            get; 
            set; 
        } 
    } 
} 

With Callstack

The load test that included writing the callstack to the trace record had the following output:

Callstack included

With a total of 92,608 tests executed, the average execution time was 200 milliseconds per test.

Without Callstack

The load test that didn't write the callstack to the trace record had the following output:

Without callstack

With a total of 86,652 tests executed, the average execution time was 59 milliseconds per test.

Including the callstack in a trace record appears to take around four times longer to write a trace record.

Tags: , , ,

Jan 8 2009

Carrying tracing weight you didn't know you had

Category: .NetRory Primrose @ 08:14

Continuing on my performance testing of tracing components, there is another factor I realised that may be impacting the performance I get out of my code.

When the TraceSource.Listeners property is referenced, the collection is initialised using the application configuration. Regardless of whether there is a TraceSource configured for the provided name or what listeners are defined, there is always a default listener that is added to the configured collection of listeners. This is the System.Diagnostics.DefaultTraceListener.

All the tracing methods of this listener implementation call down to an internalWrite method that has the following implementation:

private void internalWrite(string message)
{
    if (Debugger.IsLogging())
    {
        Debugger.Log(0, null, message);
    }
    else if (message == null)
    {
        SafeNativeMethods.OutputDebugString(string.Empty);
    }
    else
    {
        SafeNativeMethods.OutputDebugString(message);
    }
}

This is extra baggage that you probably didn't know you had. If you want lean tracing performance and don't need this debug trace support, the best option is to remove this listener in configuration. All you have to do is add a <clear /> element as the first item in the listeners element for each source you have defined in your configuration.

<?xml version="1.0" encoding="utf-8" ?> 
<configuration> 
  <system.diagnostics>
    <trace useGlobalLock="false" /> 
    <sources> 
      <source name="MySource" 
              switchValue="All"> 
        <listeners>

          <clear />

          <add name="ListenerName" 
              type="MyApplication.LoadTests.LoadTestTraceListener, MyApplication.LoadTests" /> 
        </listeners> 
      </source> 
    </sources>    
  </system.diagnostics> 
</configuration> 

Tags: , , ,

Jan 8 2009

Authoring xml documentation for Visual Studio and Sandcastle

Category: .NetRory Primrose @ 08:02

This page has a great resource for writing xml documentation for code in Visual Studio and Sandcastle. It outlines the differences between the xml support of Visual Studio and Sandcastle. It is a great resource especially because Visual Studio doesn't understand all the xml elements supported by Sandcastle. The document is now a year and a half old, but is still very accurate as the Visual Studio xml documentation schema and Sandcastle support haven't changed much (if at all) since.

Tags:

Jan 8 2009

Disable Trace UseGlobalLock For Better Tracing Performance

Category: .NetRory Primrose @ 07:58

I have had a performance bottleneck in a load test that I have been running. The load test run against some tracing components which ultimately invoke TraceSource and TraceListener methods. I have been wondering why performance drops through the floor as more and more users come online and the call count increases. I have used Reflector a lot of times to review the implementation of TraceSource and TraceListener to get a feel for what they do. I remembered that global locking may be a problem.

The methods on TraceSource check TraceInternal.UseGlobalLock (also referenced by Trace.UseGlobalLock) which is determined by the system.diagnostics/trace/useGlobalLock configuration value:

<?xml version="1.0" encoding="utf-8" ?> 
<configuration> 

  <system.diagnostics> 

    <trace useGlobalLock="false" /> 

    <sources> 
      <source name="MySource" 
              switchValue="All"> 
        <listeners> 
          <add name="ListenerName" 
              type="MyApplication.LoadTests.LoadTestTraceListener, MyApplication.LoadTests" /> 
        </listeners> 
      </source> 
    </sources>    
  </system.diagnostics> 
</configuration> 

TraceSource checks whether a global lock should be used when a trace message is written.

If global locking is enabled (the default value), then a lock (TraceInternal.critSec) call is made before looping through each listener defined for the source to write the message to the listener. With multiple threads invoking trace methods, each invocation is blocking all the other threads while it is writing its trace message to the collection of trace listeners. This is regardless of where each trace invocation occurs in the application code base.

If global locking is disabled, TraceSource loops through the trace listeners without a lock. It then checks each listener for whether it is thread safe (TraceListener.IsThreadSafe, false by default). If the listener is thread safe, the message is written directly to the listener. Otherwise, a lock is obtained on the listener itself before writing the message. If the application is configured to a single source and listener, then this will actually have the same affect as a global lock. However, if multiple sources and listeners are used, locking on each listener has the advantage that tracing a message in one part of the application will not lock up other threads that write trace messages in another part of the application using a different listener.

Ideally you would use trace listeners that are thread safe but most of the ones out of the box are not. System.Diagnostics.EventSchemaTraceListener and System.Diagnostics.EventProviderTraceListener are the only two provided with the .Net framework that are thread safe.

I find that System.Diagnostics.XmlWriterTraceListener is the best listener for my purposes so this limits the performance that I can get out of tracing. However, I tend to use a unique source and listener per assembly in a solution. While this improves locking performance encountered, this also makes for a good segregation of tracing data that can be merged together if required using SvcTraceView.exe.

On a side note, I created a custom listener to use in my load test because I wanted to be able to test the performance of my tracing components while minimizing the performance "noise" of the .Net framework part of the tracing execution. The listener looks something like this:

using System; 
using System.Diagnostics; 

namespace MyApplication.LoadTests 
{ 
    /// <summary> 
    /// The <see cref="LoadTestTraceListener"/> 
    /// class is used to help run load tests against the tracing components. 
    /// </summary> 
    public class LoadTestTraceListener : TraceListener 
    { 
        /// <summary> 
        /// Writes the provided message to the listener you create in the derived class. 
        /// </summary> 
        /// <param name="message">A message to write.</param> 
        public override void Write(String message) 
        { 
            Debug.WriteLine(message); 
        } 

        /// <summary> 
        /// Writes a message to the listener you create in the derived class, followed by a line terminator. 
        /// </summary> 
        /// <param name="message">A message to write.</param> 
        public override void WriteLine(String message) 
        { 
            Debug.WriteLine(message); 
        }

        /// <summary> 
        /// Gets a value indicating whether the trace listener is thread safe. 
        /// </summary> 
        /// <value></value> 
        /// <returns>true if the trace listener is thread safe; otherwise, false. The default is false. 
        /// </returns> 
        public override Boolean IsThreadSafe 
        { 
            get 
            { 
                return true; 
            } 
        } 
    } 
} 

This listener will output the trace messages in debug mode, but the compiler will not include the debug statements under a release build. It also indicates that the listener is thread safe to improve performance of TraceSource implementations that use this listener when global locking is disabled.

Tags: , , ,