This article may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist. To maintain the flow of the article, we've left these URLs in the text, but disabled the links.


MIND


Monitoring Events in Distributed Applications Using Visual Studio Analyzer

Mai-lan Tomsen

This article assumes you're familiar with Visual Basic, ADO, MTS
Download the code (2KB)

One of the trickiest tasks in building distributed applications is analyzing and debugging distributed applications. Visual Studio Analyzer, one of the Visual Studio 6.0 suite of tools, can help you cut even the most complicated application down to size.
If you build distributed applications with technologies such as Microsoft® Internet Information Server (IIS) you face the problem of tracking events over local and remote machines. Visual Studio® Analyzer, which ships with Visual Studio 6.0 Enterprise Edition, simplifies the performance diagnosis of Web-based and other multiprocess/multimachine applications. It allows you to use a single console to view system and component event activity. You can see the response time for events across your entire application. You can also track events, register components and events, and use Analyzer views to track event pairings.

    To help you understand how to use Analyzer, I'll walk you through its core functionality. Registering components, events, and categories and firing events requires a good deal of code, so I'll demonstrate proper implementation with code samples. (Visual Studio doesn't currently provide any automated way to register a component or any Analyzer objects.) By the end of this article, you'll be able to use the Analyzer programming model and console in conjunction with your own Web-based application.

Analyzer and Performance Tuning

      It is important to note that Analyzer provides the infrastructure rather than code-level tools for using an event-driven model to report data about application performance. Analyzer is integrated with the Microsoft Development Environment for your convenience, but it's not designed to show you the line of code causing a memory leak. Instead, Analyzer might show you that there is growing discrepancy between when a function is called and when the function returns. Once you've determined that a function may not be behaving properly, you're back to watching variables change in the debugger. Analyzer works with any development language provided by Visual Studio, and can record events for any remote machine in a Windows NT® security domain.

    Analyzer's fault isolation of components provides a valuable tool for distributed application developers. It's often difficult to debug on an application level because of the lack of tool support in debugging components across the entire application. Analyzer gives you the ability to view all the pieces of your application environment—components, queries, function calls, system processes, and application processes—from a single vantage point. Not only can you track your application-specific events, you can monitor local and remote system statistics as well. Analyzer integrates with the Windows NT Performance Monitor so you can consolidate valuable system data with your application-specific information.

    In addition, Analyzer provides support for popular Microsoft development technologies such as ActiveX® Data Objects (ADO). You can monitor the Analyzer views for your application while running load tests, or record a session for later analysis. Best of all, filters allow you to be very specific about what data you want to record or view.

Analyzer Deployment Model

      Key components in the Analyzer deployment model are views, filters, and events. Analyzer views let you display event pairings (who called the event and who received it) over time. Filters allow you to sort and record the data you need to provide a clear picture of component interaction. Events range from operating system events to Microsoft application events or your own custom events. Analyzer provides a number of predefined events, such as component startup and shutdown, function call and return, and query start and completion. Since Analyzer collects event data by session, it's important to establish the relationships between events to accurately correlate activity in a certain period.

    Analyzer collects event data through an exposed API, stores information in the event log, and displays that data in a project view. A view provides you with a central console for managing event logs, filters, charts, and visual models for your application. Filters can also be saved and exchanged between your projects.

    Figure 1 demonstrates an Analyzer view. This particular view tracks which logs I'm using, which filters I've set up (and which one is recording), and the events in my event log. A view can also chart statistics over time, such as Windows NT Performance Monitor activity that occurs while collecting events on a local machine.

    In addition to charting and event logs, Analyzer also allows you to display visual models of your application. These models allow you to trace events between components within your application, providing a clear picture of how the pieces of your distributed application interact.

    Filters can either define what event data you collect, or restrict the data that's displayed in the view. It's important to either use a recording filter or to capture events judiciously since the event log can fill rapidly and consume excessive disk space and resources. Analyzer's flexibility with filters lets you quickly display event results for the data that interests you, whether it's Windows NT memory usage under stress tests or query performance test with different access methods.

    This flexibility also means you can distinguish the types of events that you want to collect or display. Analyzer comes with predefined filters for commonly used event sources like ADO, SQL Server, and other components. If you prefer, you can also build your own filters using the Analyzer filter syntax and the Edit Text button in the filter editor (see Figure 2).

    Events allow you to report data from your application while your application is executing. An event-driven testing model lets you test the interactions of components in your application. Event logging drains system resources, so it's important to limit the number of events being tracked and focus on generating the right information about application activity. You can register the event in your source component, then specify event parameters when the event is fired.

    At a minimum, events should identify the source machine that originated the event and the target machine that ended up with the event. The data that needs to be supplied depends on the event itself. Single events must provide either source information (machine identity, process, component, and session) or a handle. Paired events must provide this for both source and target. That data will help you use the event logs to track down multiple calls generated by the same source to the same target. In addition, Analyzer uses these values to build the Block Diagram view that displays the relationships between different components. Event source and target values let Analyzer display more meaningful data about the app that's being tested. For more information on what to look for while testing, see the sidebar "Testing Methodology."

Using the Analyzer Framework

      Analyzer essentially acts as a console that centralizes event data for your application. Figure 3 illustrates how Analyzer interacts with components in an application. The application in Figure 3 consists of an ASP page that invokes a business object from Microsoft Transaction Server (MTS). The MTS business object performs some logic and queries a SQL Server database through ADO.

Figure 3: How Analyzer Interacts with Components
      Figure 3: How Analyzer Interacts with Components

      To help you understand how to select which events to trigger, I'll walk you through some of the more interesting component-level events provided by Analyzer. Then I'll give you some code samples that demonstrate how to register components and events and then fire events.

    First, let's consider the scenario for the IIS-based application in Figure 3. This simple application might contain the following possible event sources (along with any custom events I may choose to implement): IIS, MTS, ADO, SQL Server, and System.

    With such a wide variety of event sources, you can trigger any number of events. Tracking too many events, however, results in overflowing event logs and unnecessary data to filter and sort. When selecting events, consider your testing goal. In this case, my goal is to track the impact of using transactions with my MTS component and the performance of ADO.

Selecting Events

      Events show the interaction between client and server for SQL queries and other inter-component communication. Consider a function call between component A, which lives on a business logic server, and component B, which lives on a database server. The function call contains four events:

  • Call event: component A calls component B
  • Enter event: component B handles the function call
  • Leave event: component B passes some value to component A
  • Return event: the return value for the function is returned to component A
      You only really have to track the Call and Return events to determine the amount of time your application took to make that function call. It's important to clearly mark the relationships between components when you're setting up events. If you have complete information about component interaction, you can review your logs with greater understanding of your application's behavior.

    Since system events provide some generic timing information about function calls and component lifetimes, I'm going to focus primarily on application events to get a sense of how the components in my application communicate. I'm especially concerned with the performance of my business component and database access, so the majority of my events pass information about MTS and ADO activity. I also tracked two system events (namely, DEBUG_ EVENT_CALL and DEBUG_EVENT_RETURN) to see how long it would take for my component to make a call to the ADO recordset object.

    For the MTS component, I tracked object lifetime (to gauge the effect of object pooling on my component) and transaction participation. I registered the events in Figure 4 with my component as the event source. I'm also interested in how data access affects overall application performance. To track ADO events, I used the events in Figure 5. Finally, I collected the most basic IIS events: HTTP Get and HTTP Post.

    In combination, these events allow me to track how my component performs under MTS transactions when using ADO as a data access method. If Analyzer shows unusual or slow behavior, I can turn MTS transactions off to test the impact of the transaction participation, or switch to OLE DB to see if the data access method is affecting overall application performance. By collecting events from specific technologies in my Web-based application, I can diagnose behavior from a single console rather than examining individual components out of context with the application. Remember that collecting a lot of events might significantly degrade the performance of your application—you may have to trim event collection according to system resources.

Instrumenting Code Hooks for Analyzer

      After I decided which events to trigger, I inserted Analyzer code hooks in my Visual Basic®-based component, a process known as instrumentation. Adding hooks to your own application is often not necessary, as Microsoft has instrumented many key system technologies. To track events for IIS, I first installed the Analyzer filter using the Internet Service Manager (ISM).

    In Visual Basic, I added references to the Analyzer Automatable Event Source Installer and Analyzer Automatable Inproc Event Creator type libraries. (Programmers using Visual C++® can include the header files vaevt.idl and vaids.h in their projects; programmers using Visual J++® must add COM wrappers for the libraries so that Visual J++ can create classes for each interface. )

    Collecting and displaying events in the Analyzer view requires three steps. The first two only need to be done once per event source on a given machine:

  • Register the source component with Analyzer.
  • Register the event with Analyzer.
  • Add support to the source component to fire the event.

Registering the Source Component

      Analyzer tracks source components by GUID. To register a component with Analyzer, you generate a unique GUID and call the MSVSASourceInstaller object. If you do not register the source, Analyzer will not be able to track event pairings (among other adverse effects).

     Figure 6 shows how I instantiated the Installer object and registered my Visual Basic-based component with Analyzer.

Registering an Event

      After registering my component, I generated another unique GUID to register an event. You can register a stock event (an event provided by Analyzer) or a custom event. You can also optionally register categories for events or use the default categories provided by Analyzer.

    Here's how I registered a system event that marks when a component calls another component:


 ' Register a system event. Pass in the GUID that you
 ' assigned to the source component when registering the component.
 Private Sub MIND_RegisterEvent(ByVal sSourceGUID As String)
     ' In this sample, I'm setting the event to let me know when a function   
     is called (DEBUG_EVENT_CALL.) 
     Dim sDEBUG_EVENT_CALL As String
     sDEBUG_EVENT_CALL = "{6c736d6-bcbf-11d0-8a23-00aa00b58e10}" 'vaids.h
  
     sSourceGUID = "{6F9A9121-E556-11d2-90FF-0080C76205C0}" 'Generated
    
     ' Run the method.
     ' This registers the stock event DEBUG_EVENT_CALL.
     mInstall.RegisterStockEvent sSourceGUID, sDEBUG_EVENT_CALL
 End Sub
      Registering a custom event requires a slightly more complex method call to identify the event correctly. Figure 7 shows how to register a custom event called MyEvent.

Firing Events

      Once you have an event registered with Analyzer, you can fire the event in your code at key points of integration. For example, you can fire an event when a component accesses another component, or when your component performs a long routine that involves multiple function calls or queries a database.

    Analyzer provides optional event parameters that allow you to associate related events. It's better to use the CorrelationID parameter if the event is paired, since it provides the most extensive information about the relationship between the events in the session. The CausalityID is a string that lets you make a basic association, but does not provide any other information about the relationship between the events. When registering your events, remember that the more information you pass in parameters, the more information you see in your Analyzer view.

    Collecting the maximum amount of information at the source component allows you to diagnose bottlenecks and other issues more efficiently in an Analyzer view. For example, adding detail to the source and target values for events allows Analyzer to track multiple calls from the same source to the same target to generate a history of that activity.

    This code demonstrates how to instantiate the Event Source Installer object and begin an Analyzer session:


 ' First instantiate the Analyzer fire event object.
 Private Sub MIND_InstantiateFireEvent()
 Dim mEventInstaller As Object
    Set mEventInstaller = New MSVSAEventSourceInstaller
    End Sub
 ' Begin a session with the event creator object. Pass in the source component
 GUID created when you registered the component.
 Private Sub MIND_BeginSession(ByVal sSourceGUID As String)
    Dim sSession As String
 ' sSession sets up a session with Analyzer
    sSession = "MINDSampleFiringSession1"
 mEventInstaller.BeginSession sSourceGUID, sSessionName
 End Sub
      The code in Figure 8 shows you how to generate an event. Once you finish setting up events for the session, simply close the session and destroy the event installer object.

Analyzer in Your Testing Environment

      Visual Studio Analyzer provides an event framework that you can use with a distributed application. The consolidated Analyzer view gives you the ability to view component interactions and details in the event log, and to chart event activities.

    Currently, instrumenting your code to fire events for Analyzer can be fairly complex, involving a number of optional method calls to register components, default events, custom events, and event categories. I described a programming model for using the Analyzer framework with your application. Once the initial work of setting up components, events, and filters is complete, Analyzer offers an interesting diagnostic spin that can apply to your distributed application.

MSDN
http://msdn.microsoft.com/library/books/pc99/addressingcostofownershipformodems.htm
and
http://msdn.microsoft.com/library/devprods/vs6/vstudio/vstool2/veconevaluatingvisualanalyzerdata.htm

From the June 1999 issue of Microsoft Internet Developer.