Profiling an app on a server. What options do you have?

Alexey Totin

Baseline conditions: You have a server running a .NET web application. It appears the application has an issue: It doesn’t work as fast as expected, it consumes more and more memory over time, it has any other performance/memory issue of your choice, whatever. It doesn’t really matter what exact issue it has, the workflow is always the same:

  1. Profile the app in order to get performance/memory data.
  2. Analyse the data to determine the issue.

Though step 2 seems to be the most important here, communication with our users shows that you might easily get stuck in step 1. In most cases, installing a profiling tool like dotTrace or dotMemory to the server is not an option at all. Server environment may impose many restrictions: no GUI, security policies, etc. So, what options do you have? In this article, we’ll take a look at all possible ways of profiling a .NET application on a server using the dotTrace + dotMemory toolset.

TL;DR, here is a short summary:

Pros Not cons but features
Remote profiling
  • Easy to configure/use – you profile via the dotTrace/dotMemory GUI
  • Snapshots are automatically uploaded to your local machine
  • dotTrace/dotMemory remote agent must be run on the server
  • Communication via network is required
Console tools
  • No network communication required
  • Ability to create a number of predefined profiling configs and run them on demand
  • The tools must be copied to the server
  • Resulting snapshots must be manually copied from the server to the machine with dotTrace/dotMemory
Memory dumps (only memory profiling)
  • Nothing should be installed to the server
  • No profiling overhead
  • Memory dumps contain less data than dotMemory snapshots

Remote profiling

Remote profiling
Remote profiling is the best choice when it comes to a sudden performance drop / memory issue.

How it works: dotTrace / dotMemory is running on your local machine, the remote agent is running on the server, both communicating via TCP, as easy as that. The best thing about remote profiling is that you still work with the easy to use dotTrace/dotMemory GUI and the collected snapshots are automatically copied to and opened in dotTrace/dotMemory.

So, that’s what you should do to make it work (the instructions are almost exactly the same for both dotTrace/dotMemory):

  1. On the server, do the following:
    1. Copy the archive from the dotTrace/dotMemory installation directory on your local computer, to any directory on the server. For your convenience linking to the archive is available right on the dotTrace/dotMemory remote profiling page:
      Link to Remote Agent
    2. Unpack the archive on the server.
    3. Start RemoteAgent.exe from the console on the server.
    4. Ensure that inbound connections to Remote Agent are not blocked by the firewall.
  2. On the local computer, run dotTrace as a standalone application. The dotTrace Home window will open.
  3. In the right panel, choose the Remote tab.
  4. In the central panel, specify the address of the remote agent service in Remote Agent URL.
    By default, the URL is net.tcp://[remote_computer_IP_address]:9100/RemoteAgent
  5. Click Connect to establish connection with the remote host.

Remote profiling

Once you get a snapshot, it will be automatically uploaded and opened in the current dotTrace/dotMemory instance.

Profiling via console tools

Profiling via console tools

Console tools are the best if you need to automate profiling: e.g., you should profile your web app from time to time. Another possible scenario is when you don’t have access to the server but some other person does, so you can simply provide him/her with profiling tools and a batch file.

How does it work? In short, you copy console tools to the server and either run the app under profiling (the app pool will be restarted) or attach the tool to the running application pool (w3wp.exe). But when it comes to getting snapshots, things are a little bit different for memory and performance profiling. Let’s take a look at the details.

Performance profiling

  1. Download the zip archive with the ConsoleProfiler.exe tool and copy/unpack it to the server.
  2. Now, you should start profiling of the application pool that hosts your application: you can either attach to an already running app pool or start a new one under profiling. Starting the new one doesn’t give you any advantages over attaching, so, in this article, we’ll take a look only at the latter (you can though still find all the details in the dotTrace documentation).
    To attach ConsoleProfiler.exe to the running app pool:
    ConsoleProfiler.exe attach 1234 --save-to-snapshot.dtp
    Where 1234 is the process ID of the corresponding w3wp.exe process
  3. When it comes to taking performance snapshots, things get more a bit more complicated. Unlike dotMemory, you cannot take a snapshot instantly, as it simply doesn’t make any sense: you should see how your app behaves on a time interval. So, you have two options:
    1. Get a snapshot by timeout:
      ConsoleProfiler.exe attach 1234 --save-to=snapshot.dtp --timeout=5m
      Here the snapshot will be taken after 5 minutes, then the profiler will detach from the process.
      dotTrace profiling a server with console tools
    2. Get a snapshot on process exit. The ConsoleProfiler.exe tool will take a snapshot once the profiled application successfully finishes its work (so, if the app is “killed”, no snapshot is collected). To make this happen, you can, for example, Recycle the corresponding application pool in the IIS Manager.
      Getting snapshot on process exit
  4. Copy the resulting snapshot to the computer with installed dotTrace and open the snapshot.

Memory Profiling

It’s a little bit easier with memory profiling: first of all, here you can instantly get a snapshot, and second, with the dotMemory.exe tool you can get snapshots by sending commands to stdin.

  1. Download the zip archive with the dotMemory.exe tool and copy/unpack it to the server.
  2. Now, you have two options for getting a memory snapshot:
    1. Attach dotMemory.exe to the running application pool and instantly get a snapshot:
      dotMemory.exe get-snapshot 1234 --save-to-dir=C:\Snapshots
      Where 1234 is the process ID of the corresponding w3wp.exe process
    2. Run the application pool under profiling (if the pool is already running, it will be restarted):
      dotMemory.exe start-iis --trigger-timer=30s --open-url=localhost/myapp --use-browser=Chrome
      Where --open-url=localhost/myapp is the URL of your application.
      In case you’ve chosen to run the app pool, you cannot instantly get a snapshot. Instead, you should:

      • get a snapshot by condition: e.g. when --trigger-timer=30s is specified, snapshots are taken each 30 s
      • get a snapshot by sending a command to stdin: ##dotMemory["get-snapshot"]
      • As with dotTrace, get a snapshot on process exit (e.g. recycle app pool in the IIS Manager)

    For more details on how to work with the dotMemory console profiler, please refer to the dotMemory documentation.

  3. Copy the resulting snapshot to the computer with installed dotTrace and open the snapshot.

Memory dumps (only memory profiling)

Taking memory dumps

But what if, for some reason, copying and running third-party tools on the server is not possible at all. Well, if it is about memory then your last resort is memory dumps.
It can be taken with a number of tools, with the two most popular being Task Manager (comes with the operating system) and Process Explorer.

Get memory dump

When creating a dump of a 32-bit application with Task Manager, make sure you use a 32-bit version of the tool that can be found in C:\Windows\SysWOW64\taskmgr.exe.

Now, all you have to do is simply copy the dump to your computer and open it in dotMemory using the Import Dump command.

Importing memory dumps in dotMemory

That’s it! We hope this post was useful and helped you to better understand what the possible options you have are when it comes to profiling an app running on a server. If you still have any concerns or your profiling scenario cannot be covered by any of the tools mentioned above, please tell us in the comments to this post.

Comments below can no longer be edited.

16 Responses to Profiling an app on a server. What options do you have?

  1. Luiz says:

    February 13, 2018

    Is there a roadmap to bring dotTrace/dotMemory to the UNIX environment?

    • Alexey Totin says:

      February 13, 2018

      Hi Luiz,
      we’re currently working on adding the Mono + Linux support. But there is no exact release date yet.

      • Luiz says:

        February 14, 2018

        awesome! thank you for letting me know 🙂

      • David says:

        February 28, 2018

        It’s really a great new !
        Thx 🙂

  2. Mike says:

    February 16, 2018

    What about dotnet core support?

    • Alexey Totin says:

      February 16, 2018

      Hi Mike,
      Actually, it is supported on Windows. Or your question is about other OSs?

  3. Shrike says:

    March 2, 2018

    Let me ask you here about dotTrace – it has Time measurement settings: Real time (performance counter), thread time, real time (CPU instruction).

    First question – what does it mean “performance counter” here? You mean Windows Performance Counters? Then I wonder how is it possible to use them for measuring thread times…

    Then dotTrace also has “Use profiler API” checkbox on the same Profile Options page. What happens when it’s unset – how does dotTrace work in this case? Do you use ETW events?

    • Alexey Totin says:

      March 2, 2018

      Yes, Windows performance counters are used in that case. ETW is used only in the Timeline profiling mode.
      “Use profiler API” should be enabled only if you use the profiling API to control the session, e.g. run “get snapshot” command right from your code.
      You can find more details in the documentation:

      • Shrike says:

        March 2, 2018

        Thanks for reply.
        But still I’m not sure that I understand how perf counters can help in measuring of thread time. I read the doc at but it’s very brief in describing how DT actually works.
        AFAIR PerfCounters can be read not more often then once a second.
        So what and how PerfCounters are used to get thread times?

        It’d be nice to have description of all underlying technologies that used in each mode and their metrics in terms of resolution and overhead.

  4. Naing Ye Aung says:

    February 18, 2020

    Is there any way to profile .net core 2.2 app on server?

    • Alexey Totin says:

      February 20, 2020

      yes, the instructions from this article apply to .NET Core 2.2 as well.
      For the full list of supported frameworks, please refer to

      • ivan says:

        May 21, 2020

        Sorry, but now it not possible with Docker container.
        Running inside container and on the host show this result (running as root):

        Unable to find the process with the PID {}: Maybe it is not a .NET/.NET Core 3.0+ process or administrative rights are required to attach to this process.

        • Alexey Totin says:

          May 22, 2020

          Hi Ivan,
          .NET Core 1.0 – 3.1 must be fully supported in Docker as well, so this may be a bug. Could you please contact dotTrace support (the ‘Submit request’ button on this page:


Subscribe to .NET Tools updates