performance.net-4.0perfview

How can I see me expensive methods in PerfView


I have created a simple console app and execute it from PerfView via Run Command -> PerfMonTest.exe

I get the log file and see the process of the app. It is expensive as expected (99% CPU ), but when I want to drill down into the expensive methods they are not shown in the list of expensive methods.

Is there something I can do to make them visible?

Here is the view when I selected the process. I would expect CallExpensive and CallCheap in the list:

enter image description here

Selecting the Main Methods doesnt give me the chace to drill further into the called methods

enter image description here

Here is the app:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace PerfMonTest
{
    class Program
    {
        static void Main(string[] args)
        {
            for (int i = 0; i <= 2000; i++)
            {
                CallExpensive(1000);
                CallCheap(1000);
                CallCheap(400);
            }

        }

        public static void CallExpensive(int expense)
        {
            for (int i = 0; i <= expense; i++)
            {
                DateTime checkTime = DateTime.Now;
                string val = "10" + i.ToString();
            }
        }

        public static void CallCheap(int expense)
        {
            for (int i = 0; i <= expense; i++)
            {
                int j = 2;
            }
        }
    }
}

Solution

  • From the screenshots it looks like, you didn't load symbols. If you do, you'll see that most of the time is spent in DateTime.Now.

    If you click on Main in the By Name view, you'll go to the Callers view, which will tell you which methods called Main. If you want to drill into what methods Main is calling, you need to go to the Callees view. If you do that, you'll see the break down of what Main calls.

    However, in this particular case the logic of CallExpensive and CallCheap is so simple, that the methods will be inlined (in release mode). Because the methods are inlined, they don't appear as part of the calls made from Main as the code has been folded into Main itself.

    You can verify that the methods are inlined by attaching a debugger after the methods have run and look at the method descriptors for the type. Here's the output I got:

    0:004> !dumpmt -md 004737c0
    EEClass:         00471278
    Module:          00472e94
    Name:            ConsoleApplication1.Program
    mdToken:         02000002
    File:            C:\temp\ConsoleApplication1\ConsoleApplication1\bin\Release\ConsoleApplication1.exe
    BaseSize:        0xc
    ComponentSize:   0x0
    Slots in VTable: 8
    Number of IFaces in IFaceMap: 0
    --------------------------------------
    MethodDesc Table
       Entry MethodDe    JIT Name
    72064a00 71d66728 PreJIT System.Object.ToString()
    72058830 71d66730 PreJIT System.Object.Equals(System.Object)
    72058400 71d66750 PreJIT System.Object.GetHashCode()
    72051790 71d66764 PreJIT System.Object.Finalize()
    0047c01d 004737b8   NONE ConsoleApplication1.Program..ctor()
    004d0050 00473794    JIT ConsoleApplication1.Program.Main(System.String[])
    0047c015 004737a0   NONE ConsoleApplication1.Program.CallExpensive(Int32)
    0047c019 004737ac   NONE ConsoleApplication1.Program.CallCheap(Int32)
    

    The fact that CallExpensive and CallCheap have NONE listed in the JIT column indicates that they were inlined (or not called at all, but that's not the case here).