Most NVMe thermal monitoring is live-state monitoring: you watch composite temperature and alert when it crosses a threshold. That works while you are looking. It tells you nothing about the 40 minutes last night when a backup job pushed an M.2 drive past its warning threshold and the controller quietly throttled your database.

Two fields in the NVMe SMART/Health Information log close that gap: warning_temp_time (Warning Composite Temperature Time) and critical_comp_time (Critical Composite Temperature Time). They are cumulative counters, in minutes, recording how long the drive has spent above its Warning Composite Temperature Threshold (WCTEMP) and Critical Composite Temperature Threshold (CCTEMP). They are the drive’s own thermal-stress history, kept whether or not anyone was watching.

Because they are cumulative and never decrease, the absolute value is mostly trivia. The rate of change is the signal. This article covers what the counters actually count, how to read them, and the three ways they lie to you.

What these counters are

Both fields live in the SMART/Health Information log (Log Identifier 02h) and are reported by nvme smart-log as “Warning Temperature Time” and “Critical Composite Temperature Time”. smartctl -a exposes the same fields as “Warning Comp. Temperature Time” and “Critical Comp. Temperature Time”.

  • warning_temp_time: cumulative minutes the controller has been operational with composite temperature at or above WCTEMP (and below CCTEMP).
  • critical_comp_time: cumulative minutes with composite temperature at or above CCTEMP.

Two properties of the underlying thresholds matter before you interpret anything:

  1. WCTEMP and CCTEMP are vendor-set per model. They live in Identify Controller data, not in the SMART log, which is why most monitoring tools never show them. Typical consumer drives use WCTEMP around 70-80°C and CCTEMP around 85°C; enterprise drives often run higher.
  2. Composite temperature is not a physical sensor reading. It is an implementation-specific computed value that may not correspond to any single physical point in the NVM subsystem. Per-sensor temperatures (visible via hwmon) can diverge from it.

Netdata collects both counters and exposes them as the contexts nvme.device_warning_composite_temperature_time (dimension wctemp) and nvme.device_critical_composite_temperature_time (dimension cctemp), converting the raw minutes to seconds.

How the counters work

The controller samples its composite temperature against the two thresholds while operational. For each minute the temperature sits at or above WCTEMP, warning_temp_time increments. For each minute at or above CCTEMP, critical_comp_time increments. Neither counter ever decrements, resets on reboot, or clears after the drive cools down.

flowchart TD
  S[Composite temperature sampled while controller operational] --> W{At or above WCTEMP?}
  W -->|no| N[No counter increments]
  W -->|yes| C{At or above CCTEMP?}
  C -->|no| WT[warning_temp_time +1 minute]
  C -->|yes| CT[critical_comp_time +1 minute]
  WT --> TH[Controller throttling to self-protect]
  CT --> CR[Thermal emergency zone, shutdown risk]

One dependency silently disables the whole mechanism: if WCTEMP or CCTEMP is reported as 0h in Identify Controller data, the corresponding counter is always 0 regardless of actual temperature. The NVMe spec revision 1.2 and later recommends controllers report a non-zero WCTEMP; older controllers may report 0h, which forces the counters to read zero forever.

The counters are 32-bit fields. They are specified to saturate at the maximum value rather than wrap, so you will not see them roll over to zero in practice.

A unit note that trips people up: these two counters are in minutes, but the Thermal Management T1/T2 Total Time fields in the same log page are in seconds. Comparing warning_temp_time against thm_temp1_total_time without converting makes one of them look 60 times larger than reality.

Reading the counters manually

# Pull the two thermal-stress counters from the SMART log
nvme smart-log /dev/nvme0 | grep -i "warning_temp_time\|critical_comp_time"

# Get the thresholds they count against (Identify Controller data, not SMART)
nvme id-ctrl /dev/nvme0 | grep -i "^wctemp\|^cctemp"

# Context: how long has the drive been alive?
nvme smart-log /dev/nvme0 | grep "power_on_hours"

nvme id-ctrl reports WCTEMP and CCTEMP in Kelvin; subtract 273.15 for Celsius. If either prints as 0, the matching counter is disabled and will always read zero.

The useful arithmetic:

  • Time in thermal stress as a fraction of drive life. warning_temp_time / (power_on_hours * 60) tells you what percentage of the drive’s powered-on life it has spent throttling. Low single digits on a busy database server is plausible; 10% or more means the drive is routinely thermally constrained and your effective sustained throughput is lower than you think.
  • Rate of change between samples. Read the counter now, read it again in an hour. Any increment means the drive crossed the threshold during that window, even if current temperature looks fine. This is how you catch thermal events that happened between polling intervals or overnight.
  • Warning vs critical ratio. A drive with large warning_temp_time but zero critical_comp_time is throttling as designed and self-protecting. Any non-zero critical_comp_time means the drive entered the zone where the vendor considers continued operation dangerous.

The three ways these counters lie

A persistent zero does not mean the drive never got hot. This is the most common misreading. Many drives never implement warning_temp_time at all: the counter reads 0 for the drive’s entire life even on heavily abused hardware. Other drives report WCTEMP as 0h, which disables the counter by spec. Before trusting a zero, confirm the drive reports a non-zero WCTEMP via nvme id-ctrl. If it does not, you have no thermal-history counter and must rely on live temperature monitoring alone.

A static non-zero value is history, not a current problem. The counters never decrease. A value of 4,200 minutes might reflect a summer cooling failure two years ago that was fixed the same week. A non-zero value with a zero rate of change tells you the drive was thermally stressed at some point in its life, which is relevant context for interpreting wear (high temperature history accelerates NAND degradation and appears in the “Silent Data Degradation” failure pattern), but it is not an active incident.

The counters and critical_warning bit 1 can disagree. Critical warning bit 1 (temperature threshold exceeded) is a live-ish flag set by firmware; the time counters are the accumulated record. There are field reports of firmware bugs, including after firmware updates, that assert bit 1 on cool drives while the time counters correctly stay at zero. If bit 1 is set but current composite temperature is well below WCTEMP and neither counter is incrementing, suspect firmware before you suspect cooling, and check for a firmware update.

What the values tell you operationally

ObservationMeaningResponse
warning_temp_time incrementing during known heavy loadDrive crosses WCTEMP under workload and throttles to copeTICKET. Fix cooling or spread load; throttling is silently taxing latency
warning_temp_time incrementing with no explanationThermal events you are not seeing live: overnight jobs, seasonal ambient riseTICKET. Correlate the increment window with workload and ambient temperature
critical_comp_time incrementingDrive entered the critical thermal zoneUrgent investigation. Verify cooling, fans, heatsink contact immediately
Critical warning bit 1 sustained > 5 minutes AND critical_comp_time increasingActive, non-self-resolving thermal emergencyPAGE. Reduce load now; the drive is near autonomous shutdown
Both counters zero, WCTEMP reported as 0hCounters not implemented, zero is meaninglessRely on live composite temperature monitoring instead
Non-zero but flat for monthsResolved historical eventContext only. Note it when interpreting wear and media errors

High temperature history also changes how you read endurance data. NAND retention and endurance degrade faster at elevated temperature, so a drive with large accumulated thermal-stress minutes deserves more scrutiny of media_errors and available_spare than its percentage_used alone would suggest.

Signals to watch in production

SignalWhy it mattersWarning sign
warning_temp_time rate of changeThe actionable form of the counter: is the drive entering thermal stress nowAny sustained increase
critical_comp_time rate of changeMinutes spent above CCTEMP, the danger zoneAny non-zero increase
Composite temperature (nvme.device_composite_temperature)Live state the counters integrate overApproaching WCTEMP under normal load
Critical warning bit 1 (temp_threshold dimension)The drive’s own threshold-crossing assertionSustained assertion plus rising critical_comp_time
Thermal management transitions (thm_temp1_trans_count, thm_temp2_trans_count)How often the controller actually throttled; TMT total time (in seconds) quantifies the performance costRising transition counts
Throughput and latency during counter incrementsConfirms throttling is the cause of a slowdown, not GC or media issuesThroughput drop correlated with temperature rise
power_on_hoursDenominator for computing what fraction of drive life was spent hotNeeded for any meaningful ratio

The thermal death spiral pattern chains these together: temperature rises, warning_temp_time starts accumulating, throughput declines, latency climbs, TMT transitions increment, and finally bit 1 asserts. Catching the pattern at the second step, from the counter rate, is much cheaper than catching it at the last one.

How Netdata helps

  • Netdata charts both counters as nvme.device_warning_composite_temperature_time and nvme.device_critical_composite_temperature_time, converting the raw minute counters to seconds, so increments are visible on the dashboard instead of requiring manual nvme smart-log diffs.
  • Because the charts are continuous, you can see exactly when an increment happened and overlay it against the workload window, which is the information you need to attribute a thermal event to a backup job, a compaction, or an ambient cooling failure.
  • The composite temperature chart (nvme.device_composite_temperature) on the same dashboard gives the live state; counter rate plus live temperature together distinguish “throttling right now” from “was hot earlier”.
  • Critical warning bit 1 is broken out as the temp_threshold dimension of nvme.device_critical_warnings_state, so you can alert on the escalation path the playbook defines: sustained bit 1 plus rising critical_comp_time.
  • Thermal management transition charts (nvme.device_thermal_mgmt_temp1_transitions_rate, nvme.device_thermal_mgmt_temp2_transitions_rate and the corresponding total-time charts) quantify how often the drive throttled and for how long, closing the loop between thermal stress and observed performance.