APM Tips

KQL · operations

CPU and available memory per instance as a timechart

Chart process CPU and available memory for each instance in 5-minute bins from the performanceCounters table, with notes on which counters you have.

Updated

performanceCounters operations

let lookback = 24h;
performanceCounters
| where timestamp > ago(lookback)
| where counter in ("% Processor Time Normalized", "Available Bytes")
| summarize
    cpu_pct = avgif(value, counter == "% Processor Time Normalized"),
    available_gb = avgif(value, counter == "Available Bytes") / 1e9
    by bin(timestamp, 5m), cloud_RoleInstance
| order by timestamp asc
| render timechart

Returns: Two lines per instance over the last 24 hours in 5-minute steps, the process CPU divided by the processor count and the machine's available memory in gigabytes.

Pitfalls

  • Which counters exist depends on the SDK and platform. Run performanceCounters | summarize count() by category, counter, instance first and adjust the names.
  • The plain % Processor Time counter for the process isn't divided by the processor count; the Normalized one is. If you only have the plain counter, divide by the core count yourself.
  • Available Bytes is machine memory, shared by every process on the host. For your process alone, chart Private Bytes.
  • Performance counters are never sampled and have no itemCount column, so plain averages are right here.

How it works

When one instance is slower than its siblings, the first suspects are CPU and memory. The performanceCounters table holds them: one row per counter per instance at a regular interval, with the category, counter and instance names split into their own columns and the reading in value.

Line by line

  • where counter in (...) keeps two counters: % Processor Time Normalized (the process’s CPU use divided by the logical processor count, as Microsoft defines it) and Available Bytes (free physical memory on the machine). Both are in Microsoft’s default counter lists for ASP.NET and ASP.NET Core, and in the set the Distros export to this table.
  • avgif(value, counter == "...") averages each counter’s readings separately in the same summarize, so both end up as columns on one row.
  • available_gb divides bytes by 1e9 so memory and CPU sit on comparable scales on one chart.
  • by bin(timestamp, 5m), cloud_RoleInstance gives one point per instance per 5 minutes. cloud_RoleInstance is the machine or container, not the counter’s own instance column, which Microsoft notes usually holds a process or application name.
  • render timechart draws a CPU line and a memory line for each instance.

Which counters do you have?

Microsoft’s own starting point for this table is a list of what is there:

let lookback = 24h;
performanceCounters
| where timestamp > ago(lookback)
| summarize readings = count(), avg_value = avg(value) by category, counter, instance

Classic Windows performance counters appear only where the SDK can read them; cross-platform .NET apps report event counters instead, and some platforms report fewer. The performance counters guide explains which collector produces what, including for console and worker apps.

Reading the chart

CPU pinned near 100 on one instance while the others idle points at that instance’s workload: a stuck thread, a hot partition, a noisy neighbour. Available memory falling steadily until a restart is the shape of a leak. Compare the instance with request latency by cloud role and find which version it runs with cloud role instances and versions.

Variations

  • One measure per chart: drop one of the two avgif() lines; with many instances, two lines each gets crowded.
  • Workspace tables: use AppPerformanceCounters, TimeGenerated, Counter, Category, Instance, Value and AppRoleInstance.

Sources, checked

  1. Application Insights Classic API 2.x (performance counters in Log Analytics)learn.microsoft.com · checked
  2. Application Insights telemetry data model (system and process counters)learn.microsoft.com · checked
  3. Metrics in Application Insights (counters exported by the Distros)learn.microsoft.com · checked
  4. avgif() (Kusto)learn.microsoft.com · checked
  5. Telemetry sampling in Application Insights (types never sampled)learn.microsoft.com · checked
  6. Migrate an Application Insights classic resource to a workspace-based resource (table schemas)learn.microsoft.com · checked