Take the 2-minute tour ×
Geographic Information Systems Stack Exchange is a question and answer site for cartographers, geographers and GIS professionals. It's 100% free, no registration required.

I'd like to quantitatively measure the display performance of mosaic datasets, image service layers, raster layers, feature layers, etc. in ArcMap 10.

How can I measure the draw time of a particular layer (or the complete drawing process if that is the only option) in ArcMap? What are the interfaces, objects and events involved? Is the StopWatch class in .NET suitable for accurately measuring this type of operation?

Has anyone already created an ArcMap add-in or extension for this purpose?

share|improve this question
add comment

2 Answers 2

I'm not sure how accurate this is, but I've done this in the past:

Create a LayerExtension class that implements ILayerExtensionDraw. Within the class keep a list of timings. A Timing is a class with a start tick and an end tick property. When BeforeLayerDraw is called for esriDPGeography, instantiate a new timing intance and set the StartTick property to Environment.TickCount. When AfterLayerDraw is called for esriDPGeography set the EndTick to Environment.TickCount and add it to the list.

In looking at this answer, I'd say you're better off using StopWatch than TickCount.

Add the LayerExtension to the layer via ILayerExtensions.Add method. Do not keep a strong reference to the ILayer within the layerextension.

Write a button that lets you add and clear layerextensions from layers in the map.

Write a button that loops through each layer and lists average, max, min etc. drawtimes for each layer.

I've also considered adding other properties to the layerextension to monitor for things like cpu, disk i/o, etc. but never got around to it.

share|improve this answer
    
Nice, thanks! My initial research had me learning in this direction as well, although I wonder if using IActiveViewEvents.BeforeItemDraw and AfterItemDraw (remembering to enable IViewManager.VerboseEvents) as in this answer might be simpler although perhaps there is a performance hit; any thoughts on that? –  blah238 Mar 16 '12 at 23:50
    
Oh -- there is no BeforeItemDraw event... that would put a quick end to that idea! –  blah238 Mar 17 '12 at 1:01
    
Another thought, how do you account for when the user cancels the drawing operation (e.g. by clicking or pushing Escape)? –  blah238 Mar 17 '12 at 1:29
    
I was using this only to benchmark the drawing speeds of several different layers, not for use in production where things like drawing cancel happens. Maybe you could check to see if ITrackCancel.Continue() returns true when AfterLayerDraw gets called. –  Kirk Kuykendall Mar 18 '12 at 1:56
    
I've gotten this working with feature layers but raster layers don't seem to be firing the Before/AfterLayerDraw events. Have you had any luck with raster layers? –  blah238 Mar 22 '12 at 20:07
add comment
up vote 3 down vote accepted

Unfortunately it appears that the ILayerExtensionDraw.BeforeLayerDraw and AfterLayerDraw events are only fired by feature and network layers (see wguidry's post here) and I need to support raster layers, map/image services, mosaic datsets, etc.

So in a nutshell here is what I ended up doing. Thanks @Kirk again for the ideas!

Created the following classes:

  • Timing: Stores the layer name, draw phase and elapsed time for a drawing event
  • TimingSequence: Stores all the timings in a drawing sequence
  • TimingSession: Stores all of the timing sequences in a timing session and manages the Stopwatch.

A timing session is started and stopped by a toggle button. When the timing session starts I enable IViewManager.VerboseEvents and disable it when the timing session ends.

I reset and start the Stopwatch at the start of a drawing sequence as indicated by IActiveViewEvents.ViewRefreshed and instantiate a new TimingSequence object.

Then, as each layer draws for a specific phase, I listen for IActiveViewEvents.AfterItemDraw, stop the Stopwatch, check that ITrackCancel.Continue() returns true (false indicates drawing was canceled) and record the layer name, phase and elapsed time in a new Timing object and add it to the current TimingSequence, and reset/restart the Stopwatch.

I only add a timing sequence to the timing session when IActiveViewEvents.AfterDraw fires in the esriViewForeground phase (the last drawing phase).

When the user ends the timing session by toggling the button again, I report the results (ideally it would be something nicer than an ugly MessageBox as it is now). It seems to be working smoothly though.

Problem: The AfterItemDraw event only seems to fire for layers in the root of the table of contents, not nested sublayers, so if you want individual measurements for a layer it must be moved into the root of the TOC and not within a group layer. See linked question: ArcObjects: AfterItemDraw only fires for layers in the root of TOC

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.