Sunday, 1 March 2026

The mechanics of Memory Analysis using Windows Performance Analyzer and Recorder (WPA/WPR)

When investigating the behaviour of a Windows system, I often use a combination of crash/memory dumps and Event Tracing for Windows (ETW): dumps to view the state and ETW to view the temporal development of a system. I often use WPR (and other trace controllers), WPA, cdb/WinDbg and homebrew tools to view and manipulate the captured data. One area that I had hitherto never explored was most of the “Memory” analysis graphs in WPA – especially the “Resident Set” and “Reference Set” graphs. 

My intention is to describe the mechanics of using ETW events to generate the “Resident Set” and “Reference Set” graphs rather than how to interpret the resulting graphs from a memory performance perspective.

Resident Set

The Resident Set graph, in particular, displays “state” information which I would normally have obtained in a list-like form from a dump file; it was the data manipulation abilities of WPA (grouping, sorting, collapsing, etc.) that made it interesting to me, but I wanted to know what data was used so that I could validate the interpretation of the raw data and compare the results with dump file analysis results (e.g. kernel debugger commands such as “!memusage” and “!vm”).

One way of creating an ETW trace for Resident Set analysis is to use the WPR profile “ResidentSet”; this profile uses the System Keywords: CpuConfig, DiskIO, HardFaults, Loader, Memory, MemoryInfo, ProcessThread, Session, VirtualAllocation, VAMap (keyword “Memory” also sets keyword “Filename” implicitly).

One further event provider is used to provide memory usage information (Win32HeapRanges) alongside a few other providers that are enabled to enhance the presentation of stack information.

By enabling only selected keywords or by filtering the ETW trace to remove information, one can investigate how the ETW trace data is used to create the Resident Set graph.

“Memory” is the only essential keyword; even if the other keywords are not used, a Resident Set graph will still be available in WPA, albeit with fewer “details”. When this keyword is enabled, a number of event types are recorded, the most important of which is named “Memory: PageInMemory” (in the Trace Statistics view of a trace). One event of this type will be logged for every physical page (4 kilobyte) of memory in the system; so 16 gigabytes of physical memory will result in over 4 million events emitted without delay, so many ETW buffers are needed to avoid losing events.

There is, by default, no MOF definition for this type in the WMI/WBEM database/repository, but the event data is essentially a MMPFN_IDENTITY structure, a definition of which can be found in the Windows Research Kernel (WRK); the WRK definition is old, but only a few minor tweaks (new bit field meanings and enumeration values) appear to have been made in the intervening years. The sequence of these events is essentially a parallel to the MMPFN array, which is the basis for the debugger “!memusage” analysis of memory usage.

The MMPFN_IDENTITY structure includes fields that identify a “list” (3 bits that encode: zero, free, standby, modified, modified-no-write, bad, active, transition) and a “use” (4 bits); these “use” values map to ResidentSetPageCategory values used by WPA as shown in the following table:

ResidentSetPageCategory

MMPFN_IDENTITY derived information

AddressingWindowExtensionsPage

MMPFNUSE_AWEPAGE

DriverLockedSystemPage

MMPFNUSE_DRIVERLOCKPAGE

Image

MMPFNUSE_FILE + MMPFN_IDENTITY.u2.e1.Image

KernelStack

MMPFNUSE_KERNELSTACK

LargePage

MMPFNUSE_LARGEPAGE

MapFile

MMPFNUSE_FILE + not MMPFN_IDENTITY.u2.e1.Image

MetaFile

MMPFNUSE_METAFILE

NonPagedPool

MMPFNUSE_NONPAGEDPOOL

PagedPool

MMPFNUSE_PAGEDPOOL

PageTable

MMPFNUSE_PAGETABLE

PageFileMappedSection

MMPFNUSE_PAGEFILEMAPPED

SessionPrivate

MMPFNUSE_SESSIONPRIVATE

StraggleIOPage

MMPFNLIST_TRANSITION

SystemPage

MMPFNUSE_SYSTEMPTE

VirtualAlloc_PreTrace

MMPFNUSE_PROCESSPRIVATE

WsMetaData

MMPFNUSE_WSMETADATA

 

The following ResidentSetPageCategory values reliably (in principle, perhaps not in implementation) combine MMPFN_IDENTITY event information with additional event types as follows:

ResidentSetPageCategory

MMPFN_IDENTITY plus derived information

WPR Keyword

CopyOnWriteImage

MMPFNUSE_PROCESSPRIVATE + MapFile Rundown

VAMap

CopyOnWriteMapFile

MMPFNUSE_PROCESSPRIVATE + MapFile Rundown

VAMap

CopyOnWritePageFileMappedSection

MMPFNUSE_PROCESSPRIVATE + MapFile Rundown

VAMap

VirtualAlloc

MMPFNUSE_PROCESSPRIVATE + VirtualAlloc Rundown

VirtualAllocation

Win32Heap

MMPFNUSE_PROCESSPRIVATE + HeapRange Rundown

Win32HeapRanges

SessionCopyOnWriteImage

MMPFNUSE_SESSIONPRIVATE + MapFile Rundown

VAMap

Driver

MMPFNUSE_SYSTEMPTE + Image Rundown

Loader

 

The following ResidentSetPageCategory values unreliably/incorrectly combine MMPFN_IDENTITY event information with additional event types as follows:

ResidentSetPageCategory

MMPFN_IDENTITY plus derived information

WPR Keyword

UserStack

MMPFNUSE_ PROCESSPRIVATE + Thread Rundown

ProcessThread

DriverFile

MMPFNUSE_FILE + FileName Rundown

Filename

Prefetcher

MMPFNUSE_FILE + FileName Rundown

Filename

RegistryFile

MMPFNUSE_METAFILE + FileName Rundown

Filename

 

The remaining ResidentSetPageCategory values are either not used or just not present in my system:

ResidentSetPageCategory

MMPFN_IDENTITY plus derived information

SystemCache

 

HyperSpace

 

 

The “current” implementation of the ResidentSetPageCategory classification for VirtualAlloc and Win32Heap just use “actual” events (rather than the “Rundown” events, which are also present) and so dramatically underestimates their values (attributing them to VirtualAlloc_PreTrace).

The UserStack classification just uses the StackBase and StackLimit values from Thread Rundown/Create events, which just gives an initial view of the stack virtual address range (the initial stack commit size) and does not take account of the stack reserve size. At the time of the WPR trace, the stack may have grown and this could be determined by combining information from the thread events and the VirtualAlloc Rundown events, but such calculations are not currently performed.

The DriverFile and Prefetcher classification just matches filename extensions against “.sys” and “.pf” – perhaps a reasonable heuristic but normally just an uninteresting subdivision of pages on the standby list.

The current RegistryFile classification is just pure nonsense. Firstly, it uses name matching on the filenames of “MetaFile” pages; in this context, “meta files” are file system metafiles such as $Mft, $LogFile, index files (directories), etc. (and, therefore, not data files such as registry hives). Secondly, it just looks for a few familiar hive names such as “SYSTEM”, “SECURITY” and “DEFAULT”. One could try to rescue this classification by using the “RegistryHive” keyword to obtain a rundown of hive filenames and matching those names against filenames of “MapFile” pages, but one would still have to allow for differences in the filenames (e.g. \Device\HarddiskVolume3\Windows\system32\config\SOFTWARE vs. \SystemRoot\System32\Config\SOFTWARE).

Page Frame Number (PFN) Pages

The ability to group pages based on list, use, process, file, page priority and pool tag means that there are few large counts of pages that cannot be broken down into smaller counts. One such large, opaque, block is the ResidentSetPageCategory SystemPage. There is however an event in a ResidentSet trace that can divide this block: “Memory: KeMemUsage”; this event contains the virtual address of the PFN database and its page count. The PFN database typically forms a large portion of the SystemPage category, so separating it from that category could be helpful. The “Memory: KeMemUsage” event actually contains a “UsageType” field, but currently only one usage type is defined:

ntoskrnl!_PERFINFO_KERNELMEMORY_USAGE_TYPE
    PerfInfoMemUsagePfnMetadata = 0n0
    PerfInfoMemUsageMax = 0n1

Bad Pages

Depending on the duration of the ResidentSet trace, there may be one or more “Memory: MemInfo” events in the trace. These events are the raw data for the WPA “Memory Utilization” graph; they contain interesting summary information (including standby list repurposed counts) and other counts, including the number of “bad” pages. The bad page count is useful because when examining the “Memory: PageInMemory” events, pages with a “list” value of “bad” are likely to be found. The “list” value is represented in 3 bits and all 8 possible values have established meanings but it is possible to overload the meaning of the bad list value. When “!memusage” examines the PFN database, it is able to use “magic” values in other fields of the MMPFN structure to overload the meaning of the “bad” list, but this distinction cannot be deduced from the contents of the MMPFN_IDENTITY structure. “!memusage” describes these pages as “SLIST/Temp”.

Combined Pages

I was not aware of “Combined Pages” until I started looking at this topic; they are described in “Windows Internals, Seventh Edition, Part 1” Chapter 5, Section “Memory combining”. Combined pages can be identified from information in the MMPFN_IDENTITY and WPA does this; when exploring the ResidentSetPageCategory PageFileMappedSection pages (PFMappedSection) one will probably find “CombinedPage” pages. The ResidentSet trace will include a “Memory: MMStat” event that includes statistics about page combining activity.

Non-Tradeable Pages

To be done.

Summary of ResidentSet Tracing and Analysis

The ability to share the raw data with others, store the raw data, combine information from several kernel data structures without groveling through undocumented data and use versatile user interface features to organize data make this a useful feature.

Reference Set

The WPR keywords used in a ReferenceSet trace do not differ greatly from those used in a ResidentSet trace; one keyword is omitted (DiskIO) and three additional keywords are added: FootPrint, MemInfoWS and ReferenceSet.

As far as I can tell, the FootPrint keyword just ensures that Memory, Pool and Session rundowns are included in the trace, but other keywords in the ReferenceSet trace trigger these rundowns too. MemInfoWS causes a “Memory: MemInfoExWS” event to be logged twice per second, containing summary information (total counts) for shared pages in each working set; these events do not seem to be used in the “Reference Set” graph.

As would be expected, the ReferenceSet keyword is essential for a reference set analysis. Its effect seems to be, in quick succession, to log a “start” mark, empty all working sets and to log a sequence of “Memory: InMemoryActive” events; it also logs a “stop” mark when the trace is stopped (but before the rundowns begin). Memory: InMemoryActive” events contain the same information as “Memory: PageInMemory” events (a MMPFN_IDENTITY structure) but are only logged for “active” list PFN database entries.

In addition to their rundown behaviour, the keywords Memory, VirtualAllocation and VAMap generate events whenever relevant operations occur (e.g. adding pages to working sets, mapping/unmapping files or pagefile, allocating/freeing virtual memory or pool); these events occur in a ResidentSet trace too, but they can be ignored for Resident Set analysis/graphing.

Column Names

More than 60 column names are available in the Reference Set View Editor. The names often give an indication of how a view “works” (e.g. which event types are used and how information from events is combined to present the view) and not being able to guess what a name means is an indication that one might not have fully understood the purpose of a view.

The first change to the view that I wanted to make was to switch from megabytes to pages as the measure of size; most of the potential column names for page count include the text “w/o Offer” and I had no idea what this might imply. Subsequently, I guessed that this text is related to Video memory offer and reclaim (there is also a column name of “VidMm”, which adds weight to the guess). There is an event provider that could possibly generate events relevant to this activity (Microsoft-Windows-DxgKrnl) but this provider is not included in the “Reference Set” recording profile and the topic is too far from my interests to pursue in more detail.

Some of the column names, such as “COFF Group” (known to me in the context of object/executable file formats) seem irrelevant with respect to event tracing; as would be expected, no values appeared under this (and similar) column names when they were added to a view.

Reaccess

The column name “Reaccess” combined with the potential values in the “Access Reason” (ReferenceSetReferenceReason) and Release Reason” (ReferenceSetReleaseReason) helped me to infer how the Reference Set view possibly works.

ReferenceSetReferenceReason

Related Event

PrivatePageAccess

Memory: PageAccess

SharablePageAccess

Memory: PageAccessEx

PageRangeAccess

Memory: PageRangeAccess

ActiveRundown

Memory: InMemoryActive

PoolAllocate

Pool: Allocate

PoolFree

Pool: Free

PageCombine

Memory: PageCombine

Reclaim

Microsoft-Windows-DxgKrnl

 

ReferenceSetReleaseReason

Related Event

PageRelease

Memory: PageRelease

PageRangeRelease

Memory: PageRangeRelease

VirtualAddressRangeEnd

Memory: VirtualFree (Flags includes MEM_RELEASE)

PageFileMappedSectionDelete

Section: Delete

PageCombine

Memory: PageCombine

VirtualAddressRangeDecommit

Memory: VirtualFree (Flags includes MEM_DECOMMIT)

PoolFree

Pool: Free

PoolAllocate

Pool: Allocate

ProcessEnd

Process: Delete

ThreadEnd

Thread: Delete

RemovedFromWorkingSet

Memory: RemoveFromWS

Offer

Microsoft-Windows-DxgKrnl

 

“Reaccess” seems to mean that a page has been “accessed” (added to a working set) twice without an intervening “release” (removal/eviction from a working set).

The ReferenceSetReferenceReason values cover all of the paths causing a page to be added to a working set plus other values: Reclaim (video memory) and Pool Allocate/Free.

Pool Allocate/Free is orthogonal to working set growth/reduction; my guess is that both “Allocate” and “Free” are included as “access” reasons and both as “release” reasons to “balance the books”. The default keywords used in a Reference Set trace do not include the “Pool” keyword; the “Pool” events in the trace are just the “large”/”big” allocations (size plus overhead greater/equal one page) and frees which are included via the “Memory” keyword.

The ReferenceSetReleaseReason values do not cover all of the paths causing a page to be removed from a working set (if one ignores RemovedFromWorkingSet, which is not enabled in the default capture) but does contain “other” values: Offer (video memory), Pool Allocate/Free (again) and ThreadEnd (presumably included to track user stack releases, but VirtualFree does this better). Missing from the list is the unmapping of files.

If one adds RemovedFromWorkingSet events to a trace (via the “WorkingSet” keyword), it is possible to completely eliminate “reaccess” occurrences; if one does not collect RemovedFromWorkingSet events but does use unmap file as a release reason, it is possible to reduce the number of “reaccess” occurrences to a handful (tens of events). On even just short traces, the existing WPA algorithm reports hundreds of thousands of such reaccess occurrences.

Enabling the “WorkingSet” keyword does mean that two additional high volume bursts of events are added to a Reference Set trace: another rundown of the active pages in the PFN database and all of the working set evictions that occur when the working sets are emptied at the start of the trace.

Verifying the accuracy of the working set tracking

A Reference Set trace contains a rundown of the active pages at the start of tracking (after working sets have been emptied) and a full rundown of the PFN database when tracking stops (when the trace is stopped). It is possible to compare the result of “initial state plus tracked page insertions/removals” against “final state” and the inconsistencies should be small; because it takes time to record the initial and final states, some insertions and removals that occur during the rundowns will not be attributed appropriately.

The elimination of “reaccess” occurrences is also a strong sign that the working set tracking is functioning correctly.

Special handling for some events

Some “Memory: PageAccessEx” indicate the conversion of a shared page to a process private page (e.g. when a page in a copy-on-write region is written to), and these events need to be detected if one is to accurately track working set state.

Some other “Memory: PageAccessEx” events indicate a ProcessId of 0; the stack at the time of such events typically looks like this:

MiLogMapFileEvent
 MiMapViewOfImageSection
 MiMapViewOfSection
 MiMapViewOfSectionExCommon
 MmMapViewOfSectionEx
 MiMapProcessExecutable
 MmInitializeProcessAddressSpace
 PspAllocateProcess
 NtCreateUserProcess

The page accesses are being recorded during the creation of the virtual address space of a new process; the ThreadId is that of the thread that called CreateProcess and can be used to “collect” the pages that are accessed. When the “Process: Create” event occurs, the attribution of the collected pages can be transferred to the new process.

The “Memory: PageAccessEx” events include a bit that indicates whether is page is/was in a user working set or a system working set; this user/system distinction must be observed when attributing a page.

Summary of ReferenceSet Tracing and Analysis

There seem to be serious flaws in how WPA attributes and tracks page ownership but the total impression given by the view is probably accurate enough for most practical purposes.

 

Monday, 22 December 2025

Heizkurve / Heizkennlinie Formel

Ich habe kürzlich im Internet nach einer Kombination der Begriffe „Heizkurve“ und „Formel“ gesucht und war von den Ergebnissen enttäuscht – es gab zwar viele Treffer, aber keiner entsprach meinen Erwartungen. Die Suche war ein iterativer Prozess, bei dem ich die Suchbegriffe verfeinert habe (z. B. durch Hinzufügen des Synonyms „Heizkennlinie“). Die besten Ergebnisse deuteten auf eine Formel wie die folgende hin:

TV=T+Sk(TTA)mT_{V}=T+S\cdot{k}\cdot\left(T-T_{A}\right)^{m}

Einige Suchergebnisse verwendeten Kurvenanpassungsverfahren (z.B. Methode der kleinsten Quadrate), um Werte für k und m anhand von Daten aus gedruckten Diagrammen der Heizkurve zu berechnen. Der Zweck von „m“ wurde hinreichend beschrieben (es beschreibt näherungsweise die Nichtlinearität des Zusammenhangs zwischen der Temperaturdifferenz eines Heizkörpers (Bodenheizung, Radiator) und seiner Umgebung und der vom Heizkörper an die Umgebung abgegebenen Energiemenge), doch die Herkunft des Wertes (beispielsweise 0,83) blieb unklar. „k“ war ein noch größeres Rätsel – sein Wert (beispielsweise 1,83) wurde lediglich benötigt, um die vorgeschlagene Formel an die beobachteten Diagramme anzupassen.

Für die meisten praktischen Zwecke sind die Diagramme völlig ausreichend – das Interesse an einer Formel ist hauptsächlich rein intellektueller Natur.

Mir war bekannt, dass es Dokumentationen (Handbücher) für meinen Heizungsregler (Hoval TopTronic, EbV THETA) gibt und dass der Heizungsregler verschiedene Zugriffsebenen für Informationen und Einstellungen bietet (Benutzer, Experte, Hersteller (OEM, Original Equipment Manufacturer)). Durch sorgfältiges Lesen dieser Quellen und Anwendung des Ockhamschen Rasiermessers habe ich die möglichen Auswirkungen verschiedener Einstellungen untersucht.

HEIZKURVE [USER] → S
RAUM TAG [USER]
→ TS
Grenztemperatur für die Sommerabschaltung [SYSTEM 4]

Klimazone [SYSTEM 09]
→ TZ
Gebäudeart [SYSTEM 10]
→ TA Mittelung
Heizsystem (Exponent) [MISCHER 02]
→ m
Raumfaktor [MISCHER 04]
→ F
Adaption der Heizkurve [MISCHER 05]

Maximaltemperaturbegrenzung [MISCHER 13]

Temperaturüberhöhung [MISCHER 14]
→ TÜ

Daraus ergab sich folgende Formel:

TV=T+S(TTA)1m(TTZ)m1m+TUT_{V}=T+S\cdot\left(T-T_{A}\right)^{\frac{1}{m}}\cdot\left(T-T_{Z}\right)^{\frac{m-1}{m}}+T_{U}

anfänglich mit T = TS (wird später verfeinert) und wo TV = Vorlauftemperatur, TS = Raum Solltemperatur, TA = Außentemperatur, TZ = Klimazone, TÜ = Temperaturüberhöhung, S = Steilheit, m = Heizsystem (Exponent), F = Raumfaktor.

Die erste zu berücksichtigende Einstellung ist „Heizsystem (Exponent)“ (Parameter 02 in den MISCHER-Einstellungen auf Expertenebene). In manchen Systemen dient dies lediglich als Kennzeichnung für den Heizsystemtyp (z. B. 1 → Fußbodenheizung, 2 → Radiatorenheizung usw.), in anderen ist es eine Zahl zwischen 1,0 und 10,0 (mit empfohlenen Werten wie 1,1 für Fußbodenheizung und 1,3 für Radiatorenheizung). Ich bin der Ansicht, dass der Kehrwert dieses Wertes der „Exponent“ in der Heizkurvenformel ist (der Kehrwert von 0,83 ist 1,2). Dieser Wert wird oft als „m-Wert“ bezeichnet, daher verwende ich in der Formel den Buchstaben „m“.

Eine Möglichkeit zur Neuskalierung des Temperaturdifferenzwertes besteht darin, das Verhältnis zwischen der größten Temperaturdifferenz und ihrem Exponenten zu berechnen. Der maximale Temperaturwert ist TS – die Raum-Solltemperatur; die minimale Temperatur ist wahrscheinlich der Wert des Parameters Klimazone (Parameter 09 in den SYSTEM-Einstellungen auf Expertenebene).

Je nach Heizungsregler ist der Parameter Klimazone entweder ein Index aus einer Liste nummerierter Klimazonen oder eine Temperatur zwischen -20 °C und 0 °C, die die niedrigste zu erwartende Außentemperatur darstellt (Websites wie Klimakarte | BWP | waermepumpe.de liefern solche Schätzwerte – für Grenzach-Wyhlen beträgt der Wert -10,1 °C). Ich verwende TZ zur Darstellung dieses Wertes. Der folgende Term beschreibt die notwendige Reskalierung, um die ursprüngliche Erwartung wiederherzustellen:

(TTZ)m1m(T-T_Z)^{\frac{m-1}{m}}

Es gibt außerdem Experteneinstellungen, die es ermöglichen, die tatsächliche Raumtemperatur in die Berechnung der Vorlauftemperatur einzubeziehen: Raumaufschaltung und Raumfaktor. Es gibt einige Faktoren, die die Nutzung dieser Funktion unratsam machen können (z. B. wenn die Positionierung des Raumfühlers nicht geeignet ist, die Temperatur im Gebäude zu messen). Ist sie jedoch aktiviert, kann sie als Korrektur der Raum-Solltemperatur in die Heizkurvenformel integriert werden. Ich verwende TI für die Raum-Isttemperatur und F für den Raumfaktor als Multiplikator (d. h. Raumfaktor / 100, da er als Prozentsatz angegeben wird). T in der Formel kann nun wie folgt interpretiert werden:

T=TS+(TSTI)FT=T_S+(T_S-T_I)∙F

Es ist zu beachten, dass die Verwendung des Raumfaktors die Vorlauftemperatur senken kann. Beispielsweise ist zu Beginn einer Heizperiode mit reduziertem Betrieb die Raum-Isttemperatur wahrscheinlich höher als die Raum-Solltemperatur. Es ist möglich, dass die berechnete Vorlauftemperatur unter der Minimaltemperaturbegrenzung (Parameter 12 in den MISCHER-Einstellungen auf Expertenniveau, Standardwert 10 °C) liegt. In diesem Fall wird der Wert der Minimaltemperaturbegrenzung verwendet.

Mithilfe der Webanwendung Desmos lassen sich die Parameter anpassen, um die Heizkurve für die aktuellen Gegebenheiten anzuzeigen: https://www.desmos.com/calculator/szgyrui9ng. Im Gegensatz zur üblichen Darstellung von Heizkurven (sinkende Temperaturen nach rechts) verwendet dieser Graph die übliche mathematische Konvention (sinkende Werte nach links).


Für die berechnete Vorlauftemperatur gelten Grenzwerte. Im oberen Bereich begrenzen verschiedene Parameter die Kessel- und Vorlauftemperatur, beispielsweise die Maximaltemperaturbegrenzung (Parameter 13 in den MISCHER-Einstellungen auf Expertenniveau). Im unteren Bereich liegt die „Grenztemperatur für die Sommerabschaltung“ (Parameter 04 in den SYSTEM-Einstellungen auf Expertenniveau). Dieser Parameter ist mit der Gebäudeart (Parameter 10 in den SYSTEM-Einstellungen auf Expertenniveau) kombiniert, welche den Zeitraum für die Mittelung der Außentemperatur festlegt (z. B. 8 Stunden für eine mittelschwere Bauweise).

Neben den einstellbaren Grenzwerten der Vorlauftemperatur gibt es auch praktische Erwägungen, die ihren Wert begrenzen. Mein Wärmeerzeuger hat eine maximale Leistung von 12,0 kWh und eine maximale Gasmenge von 1,3 m³/h (wobei 1 m³ Gas etwa 10,6 kWh entspricht); diese Werte entsprechen einem Wirkungsgrad des Wärmeerzeugers von ca. 90 %. Die Summe der Durchflussmengen durch meine Abgleichventile ergibt einen Wert von ca. 12 Litern pro Minute (ca. 700 Liter bzw. 700 kg bzw. 0,7 m³ Wasser pro Stunde); der Wert von 0,7 m³ ist auch mit der Regelkennlinie der Pumpe kompatibel (Proportionaldruck, Stufe II, 13 W). Unter Anwendung von:

Q=mcTQ=m∙c∙∆T

wo:

Q12000 WQ ≈ 12000 \text{ }W
c4184 Jkg1K1(Wasser bei Raumtemperatur)c ≈ 4184 \text{ }J⋅kg^{-1}\cdot{K^{-1}} \text{ (Wasser bei Raumtemperatur)}
m700 kg/3600 sm ≈ 700 \text{ kg} / 3600 \text{ s}

ergibt eine Temperaturspreizung (∆T) von:

T15 °C∆T≈15 \text{ °C}

Sobald die Differenz zwischen Vorlauf- und Rücklauftemperatur 15 °C erreicht (in meinem Fall), arbeitet der Wärmeerzeuger mit voller Leistung und kann die Vorlauftemperatur nicht weiter erhöhen (vorausgesetzt, die Bedingungen, z. B. Innen- und Außentemperatur, bleiben gleich). Eine Erhöhung der Raum-Solltemperatur der Heizkurve wäre sinnlos, da der Wärmeerzeuger bereits maximal arbeitet.

Es gibt eine zusätzliche Einstellung „Anpassung der Heizkurve“ (Parameter 05 in den MISCHER-Einstellungen auf Expertenebene), die viele der zuvor genannten Einstellungen überschreibt, um „gute“ Werte zu ermitteln. Diese Einstellung soll offenbar für einige Tage aktiviert bleiben, und die ermittelten Werte sollen dann manuell in die anderen Einstellungen übertragen werden, bevor der Anpassungsprozess deaktiviert wird.

Zurück zum Thema Raumfühler: Standardmäßig (Werkseinstellung) handelt es sich lediglich um einen Messwert, der angezeigt werden kann. Wie bereits erwähnt, kann sein Wert in die Berechnung der Vorlauftemperatur einfließen. Darüber hinaus gibt es zwei weitere Verwendungsmöglichkeiten: als Raumthermostat (Parameter 09 in den MISCHER-Einstellungen auf Expertenniveau), um die Heizung bei Erreichen der Raum-Solltemperatur abzuschalten, und als Ersatz für die Außentemperaturmessung (im PID-Regelmodus (Proportional Integral Differential)).

Ein Blick auf die Einstellungen des Heizungsreglers offenbarte mir, dass ich noch weiteren Missverständnissen unterworfen war.

Ich war davon ausgegangen, dass außerhalb der Schaltzeiten die RAUM-NACHT-Temperatur (Absenktemperatur) die Raum-Solltemperatur bestimmt und dass die Vorlauftemperatur entsprechend gesteuert wird. Allerdings gibt es eine Einstellung „Art des reduzierten Betriebs“ (Parameter 01 in den MISCHER-Einstellungen auf der Expertenebene), die die Werte ECO (Abschaltbetrieb frostgesichert) oder ABS (Absenkbetrieb) annehmen kann, wobei ECO die Voreinstellung ist. ECO bedeutet, dass nicht geheizt wird, es sei denn, die Raum-Isttemperatur unterschreitet die Raumfrostschutzgrenze (Parameter 08 in den MISCHER-Einstellungen auf der Expertenebene), die den Standardwert 10 °C hat und in meinem Heizungsregler auf 15 °C eingestellt ist.

Ich war weiter davon ausgegangen, dass das System zur Einschaltzeit mit dem Heizen beginnt. Es gibt jedoch die Einstellung „Einschaltoptimierung“ (Parameter 06 in den MISCHER-Einstellungen auf Expertenebene), die das Heizen vor der Einschaltzeit startet und somit die Interpretation von „Heizbeginn“ zu „Belegungsbeginn“ (d.h. den Zeitpunkt, zu dem die gewünschte Raumtemperatur erreicht ist) ändert. Die Standardeinstellung beträgt 1 Stunde, die tatsächliche Dauer berechnet sich jedoch wie folgt:

(TTATTZ)t\left(\frac{T-T_{A}}{T-T_{Z}}\right)\cdot t

Dabei ist T die Raum-Solltemperatur inklusive Raumeinflussfaktor, TA die Außentemperatur und t die konfigurierte Einschaltoptimierung. Bei mir bedeutet das typischerweise, dass die Heizung 30 bis 40 Minuten früher anspringt als erwartet.

Im Bereich „FUEHLER-ABGL“ (Fühler-Abgleich) finden sich außerdem verschiedene Einstellungen, mit denen sich Temperaturmesswerte korrigieren lassen. Die meisten dieser Einstellungen sind auf Herstellerebene (OEM) angesiedelt, was bedeutet, dass die Werte nur geprüft, aber nicht verändert werden sollten. Lediglich die Korrektur der Raumfühlertemperatur ist eine Einstellung auf Expertenebene.

Ich habe auch eine Funktion des Heizungsreglers übersehen, die es ermöglicht, zusätzliche Informationen anzuzeigen; durch Gedrückthalten einer Taste beim Anzeigen eines Wertes wird ein alternativer, aber verwandter Wert angezeigt – typischerweise der Sollwert anstelle des Istwerts, der normalerweise angezeigt wird.

Zwei verschiedene Dokumente beschreiben die Funktion folgendermaßen:

·         Sämtliche angezeigten Temperaturwerte stellen die momentanen Werte dar. Durch gedrückthalten des Dreh-Drück-Knopfes wird der jeweilige Sollwert angezeigt.

·         Wird bei einer aufgerufener Anlagentemperatur der Drehknopf gedrückt, erscheint der zugehörige Sollwert links neben dem aktuellen Wert (Istwert) im Display. Ausnahme: Außentemperatur gemittelter Wert.

Wednesday, 17 July 2024

Windows high-resolution time stamps (QueryPerformanceCounter)

The Microsoft article “Acquiring high-resolution time stamps” provides a good deal of useful information about high-resolution timing under Windows and Simon Anciaux provided the source code of a routine that matches the Windows 11 QueryPerformanceCounter routine (QueryPerformanceFrequency returning 10mhz bug).

Nonetheless, there is more that can be said and that might provide additional reassurance that one’s understanding of high-resolution timing is accurate.

There is a Windows kernel variable named HalpRegisteredTimers that points to a linked list of registered timers; the routine that registers the timers is passed a pointer to a TIMER_INITIALIZATION_BLOCK (whose format is defined in file nthalext.h). On my PC, 8 timers appear in the list and one can infer some interesting values from the information in the calls to register timers.

The KnownType values are members of the enum KNOWN_TIMER_TYPE (also defined in nthalext.h). In case the names are not immediately recognizable, here are some brief descriptions:

TimerProcessor: the processor Time-Stamp Counter (TSC).

TimerART: the processor Always Running Timer, perhaps mostly commonly encountered in conjunction with “Intel Processor Trace”.

TimerApic: Advanced Programmable Interrupt Controller (APIC).

TimerAcpi: Advanced Configuration and Power Interface (ACPI) power management timer.

TimerCmosRtc: the Real Time Clock (RTC).

TimerHpet: High Precision Event Timer (HPET)

KnownType

Identifier

CounterBitWidth

CounterFrequency

Capabilities

TimerProcessor

0

64

1992000000
(24000000
× 166 / 2)

1991998774
1991998859

TIMER_PER_PROCESSOR
TIMER_COUNTER_READABLE
TIMER_COUNTER_WRITABLE
TIMER_SUPPORTS_ADVANCED_QUERY

TimerART

0

64

24000000

24000038
24000039

TIMER_PER_PROCESSOR
TIMER_COUNTER_READABLE
TIMER_ALWAYS_ON
TIMER_AUXILIARY

TimerApic

0

32

187500
(24000000 / 128)

187500
187497

TIMER_PER_PROCESSOR
TIMER_COUNTER_READABLE
TIMER_ONE_SHOT_CAPABLE
TIMER_PERIODIC_CAPABLE
TIMER_GENERATES_INTERNAL_INTERRUPTS

TimerAcpi

0

24

3579545

TIMER_COUNTER_READABLE

TimerCmosRtc

0

64

2048

TIMER_PSEUDO_PERIODIC_CAPABLE
TIMER_ONE_SHOT_CAPABLE
TIMER_SINGLE_INIT

TimerHpet

0

32

24000000

TIMER_COUNTER_READABLE

TimerHpet

1

31

24000000

TIMER_PSEUDO_PERIODIC_CAPABLE
TIMER_ONE_SHOT_CAPABLE
TIMER_PERIODIC_CAPABLE
TIMER_GENERATES_8259_INTERRUPTS

TimerHpet

2

31

24000000

TIMER_PSEUDO_PERIODIC_CAPABLE
TIMER_ONE_SHOT_CAPABLE
TIMER_GENERATES_8259_INTERRUPTS

 

When registering the timers on my PC, the CounterFrequency of the TimerProcessor, TimerART and TimerApic timers is specified as zero; actual values are determined by comparing these timers to another timer whose nominal frequency is considered to be reliable. Windows has a preference list of which timer should be used as a reference and the first choice is TimerAcpi; on my PC, this timer is available and is used. The timers are compared over a period of one eighth of a second (125 milliseconds).

Section 19.7.3 (“Determining the Processor Base Frequency”) of Intel 64 and IA-32 Architectures Software Developer's Manual Volume 3 contains a table of “Nominal Core Crystal Clock Frequency”; for my PC, the value is 24 MHz. The CPUID instruction with EAX set to 15H (Time Stamp Counter and Nominal Core Crystal Clock Information Leaf) returns the values 2 as the denominator of the TSC/”core crystal clock” ratio and 166 as the numerator of the TSC/”core crystal clock” ratio; the nominal frequency of the core crystal clock in Hz is not enumerated on my CPU.

These values allow a nominal counter frequency for TimerProcessor to be calculated (1992000000 Hz). The other values in the table above (1991998774 and 1991998859) are the results of two runs of the measuring process against the ACPI PM timer.

TimerART runs at the “Nominal Core Crystal Clock Frequency” (24000000 Hz); again, the other values in the table above (24000038 and 24000039) are the results of two runs of the measuring process against the ACPI PM timer. Although there is no instruction to read the ART (Windows determines its value by evaluating (__rdtscp() - __rdmsr(IA32_TSC_ADJUST)) * CPUID.15H:EAX[31:0] / CPUID.15H:EBX[31:0]), it is measured separately.

I have assumed that the APIC timer also has a nominal frequency of 24 MHz and a divider of 128, giving a nominal frequency of 187500 Hz; the other values (187500 and 187497) are the measurement results.

In the simplest case, the value returned by QueryPerformanceCounter is the result of executing the following calculations:

_umul128(__rdtscp(out _), HypervisorSharedUserData.Factor, out ulong qpc);

qpc += HypervisorSharedUserData.Bias;

qpc += SharedUserData.QpcBias;

qpc >>= SharedUserData.Qpc.QpcShift;

SharedUserData is intended as a reference to the KUSER_SHARED_DATA structure; HypervisorSharedUserData is intended as the reference returned by the call NtQuerySystemInformation(SystemHypervisorSharedPageInformation, …); HypervisorSharedUserData.Bias is zero and HypervisorSharedUserData.Factor is the integral result of evaluating:

CpuHz is the measured TimerProcessor frequency and the evaluation is performed as a _udiv128 style calculation.

Auxiliary Counter routines

Windows has a group of functions with names including the string “AuxiliaryCounter”, such as QueryAuxiliaryCounterFrequency, ConvertPerformanceCounterToAuxiliaryCounter. These functions are related to the timer with the capability TIMER_AUXILIARY, if such a timer is present; on my PC, this is TimerART. The documentation for the group of functions is not very informative; I could only find one use of the functions on my PC: in file IntcAudioBus.sys (FileDescription: “Intel® Smart Sound Technology (Intel® SST) Bus”).

TSC synchronization

The Microsoft-Windows-HAL Event Tracing for Windows provider records the synchronization of the TSC values between the processors. Here is a condensed summary from a synchronization run:

The processor cycle counter on processor 1 has been probed by processor 0. A counter delta of -199 was detected. The approximate communication delay between these processors was detected to be 508.

[…]

The processor cycle counter on processor 0 was synchronized against processor 4 using an adjustment of 94 cycles on attempt 0. This resulted in a delta of -13 cycles.

The processor cycle counter on processor 1 was synchronized against processor 0 using an adjustment of 342 cycles on attempt 0. This resulted in a delta of 68 cycles.

[…]

The processor cycle counter on processor 1 has been probed by processor 0. A counter delta of 10 was detected. The approximate communication delay between these processors was detected to be 500.

[…]

The processor's cycle counters have been successfully synchronized from processor 0 within acceptable operating thresholds. The maximum positive delta detected was 10 and the maximum negative delta was -11. Synchronization executed for 7773 microseconds.

If the processors cycle counters can be synchronized to within “acceptable operating thresholds” then it should be impossible for a thread, rescheduled on a different processor, to detect a backwards step in the TSC values.