CPU-Kerne konfigurieren

Über den Echtzeit-Knoten TIRS lassen sich die CPU-Kerne eines Zielsystems auslesen und die Aufteilung zwischen Windows und TwinCAT-Echtzeit konfigurieren (Kern-Isolation). Werden Kerne neu isoliert, ist dafür ein Neustart des Zielsystems nötig. Dieser Neustart wird aber nur ausgelöst, wenn die gewünschte Aufteilung nicht bereits auf dem Zielsystem aktiv ist.

Voraussetzungen

Empfohlener Ablauf

1. Verfügbare Kerne ermitteln (optional): ProduceXml auf dem TIRS-Knoten liefert bei Online-Verbindung <AvailabeCPUs>, also die Anzahl der Kerne des Zielsystems. MaxCPUs entspricht genau dieser Kernzahl, denn die vorhandenen Kerne werden aufgeteilt.
2. Konfiguration festlegen: MaxCPUs und Affinity selbst auf die gewünschte Aufteilung setzen (siehe Bitmasken-Tabelle unten). Optional lässt sich CPUs für Detailparameter ergänzen.
3. Anwenden: einen <Methods>-Block mit <SetOnTarget> und <RequestReboot> ergänzen und mit ConsumeXml schreiben.
CPU-Kerne konfigurieren 1:

<MaxCPUs> und <Affinity> aus einem ProduceXml geben den Stand des Projekts wieder, nicht den des Zielsystems. Bei einem neuen Projekt steht dort nur ein Kern (<Affinity>#x0000000000000001</Affinity>, <MaxCPUs>1</MaxCPUs>). Diese Werte müssen daher aktiv auf die gewünschte Kernzahl gesetzt werden. Ein unverändertes Zurückschreiben des gelesenen XML ist wirkungslos. Für die Anzahl der tatsächlich verfügbaren Kerne dient allein <AvailabeCPUs>.

Was die einzelnen Elemente bewirken

Element

Wirkung

<MaxCPUs NonWindowsCPUs="N">TOTAL</MaxCPUs>

TOTAL ist die Gesamtzahl der Kerne des Zielsystems (<AvailabeCPUs>), die aufgeteilt wird. Gemeint ist nicht die Zahl der von der Echtzeit genutzten Kerne. N (NonWindowsCPUs) legt fest, wie viele davon exklusiv für die Echtzeit isoliert werden. Isoliert werden die N höchsten der über <Affinity> aktivierten Kerne.

<Affinity>

Wählt aus, welche Kerne die Echtzeit belegt, und aktiviert sie. Der Wert ist eine hexadezimale Bitmaske (siehe unten). Erst hierüber werden die Kerne tatsächlich aktiviert.

<CPUs><CPU id="i">…</CPU></CPUs>

Optional. Konfiguriert Detailparameter (LoadLimit, BaseTime, LatencyWarning) je aktiviertem Kern.

<Methods><SetOnTarget>true</SetOnTarget></Methods>

Überträgt die Konfiguration auf das Zielsystem.

<Methods><RequestReboot>true</RequestReboot></Methods>

Fordert den für die Isolation notwendigen Neustart an.

Unbedingt beachten

Vollständiges Beispiel: 3 geteilte Kerne und 1 isolierter Kern (4-Kern-System)

ITcSysManager2 sysMan2 = (ITcSysManager2)sysManager;
sysMan2.SetTargetNetId("192.168.1.100.1.1");

ITcSmTreeItem realtimeSettings = sysMan2.LookupTreeItem("TIRS");

// Optional: read the number of available cores on the target system
string current = realtimeSettings.ProduceXml()

// When online, the result contains e.g. <AvailabeCPUs>4</AvailabeCPUs>
// (the MaxCPUs/Affinity values in it are the project state and must be set explicitly)

// Set the configuration and apply it to the target system:
// MaxCPUs = 4 cores in total on the target, 1 of them isolated (NonWindowsCPUs="1")
// Affinity = activates all 4 cores (bits 0..3 = #x...0f)
string xmlApply = @"<TreeItem>
<RTimeSetDef>
<MaxCPUs NonWindowsCPUs=""1"">4</MaxCPUs>
<Affinity>#x000000000000000f</Affinity>
<Methods>
<SetOnTarget>true</SetOnTarget>
<RequestReboot>true</RequestReboot>
</Methods>
</RTimeSetDef>
</TreeItem>";

realtimeSettings.ConsumeXml(xmlApply);

Nach dem Neustart muss die Anwendung an der entsprechenden Stelle wieder einsteigen.

Ob ein SetOnTarget überhaupt zu einer Umkonfiguration mit Neustart führt, lässt sich vorab über <CpuConfigValidOnTarget> im ProduceXml-Ergebnis prüfen. Der Wert sagt nicht aus, ob die Aufteilung genau übereinstimmt, sondern ob die im Projekt gesetzte Konfiguration durch die auf dem Zielsystem bereits aktive abgedeckt ist. Ist der Wert 1 (true), ist die Konfiguration bereits abgedeckt und es sind keine Änderung und kein Neustart nötig. Ist der Wert 0 (false), würde ein SetOnTarget das Zielsystem umkonfigurieren und neu starten. Maßgeblich sind dabei die über <Affinity> gesetzten RT-Cores, nicht die Zahlen in den Feldern für geteilte und isolierte Kerne. Der Mechanismus verhindert, dass ein ConsumeXml versehentlich einen unnötigen Neustart auslöst.

Bedeutung von TargetCPUInfo im ProduceXml-Ergebnis

Innerhalb von <RTimeSetDef> liefert ProduceXml einen Block <TargetCPUInfo>. Er beschreibt die CPU des Zielsystems sowie den Abgleich zwischen Projekt und Zielsystem. Die Werte stammen vom verbundenen Gerät und stehen daher nur dann in der XML, wenn das Zielsystem online (erreichbar) ist.

<TargetCPUInfo>
<RealTimeCPUs>2</RealTimeCPUs>
<CPUFamily>6</CPUFamily>
<CPUFrequency>1498</CPUFrequency>
<CPUType>86</CPUType>
<AvailabeCPUs>2</AvailabeCPUs>
<NumProcessors>1</NumProcessors>
<CpuConfigValidOnTarget>true</CpuConfigValidOnTarget>
<RTimeCapabilities>1</RTimeCapabilities>
</TargetCPUInfo>

Element

Bedeutung

<RealTimeCPUs>

 

Anzahl der Kerne, die als RT-Core ausgewählt sind – also der in der Kernliste der Echtzeit-Einstellungen (Real-Time, Reiter Settings) in der Spalte RT-Core angehakten Kerne. Sind dort zwei Kerne angehakt, steht in der XML <RealTimeCPUs>2</RealTimeCPUs>. Das entspricht der Anzahl der über <Affinity> gesetzten Bits. Es ist nicht die Anzahl der isolierten Kerne – die steht im Attribut NonWindowsCPUs von <MaxCPUs>.

<CPUFamily>

 

Prozessor-Familie laut Hersteller-Kennung. Bei praktisch allen modernen Intel-Prozessoren (Core i3/i5/i7, Atom, Xeon) ist der Wert 6.

<CPUFrequency>

Taktfrequenz des Prozessors in MHz.

<CPUType>

 

Prozessor-Architektur. 86 steht für x86/x64, also einen üblichen Industrie-PC. Zielsysteme mit anderer Architektur (z. B. ARM-basierte Geräte) melden hier einen abweichenden Wert.

<AvailabeCPUs>

Anzahl der Kerne des Zielsystems, die aufgeteilt werden – der einzige verlässliche Wert für die tatsächlich vorhandene Kernzahl (siehe Hinweis oben). Die Schreibweise ohne zweites „l" ist die tatsächliche Bezeichnung in der XML.

<NumProcessors>

Anzahl der physischen Prozessoren (Pakete/Sockel), nicht der Kerne. Im Beispiel oben: ein Prozessor mit zwei Kernen.

<CpuConfigValidOnTarget>

Gibt an, ob die Projekt-Konfiguration durch die auf dem Zielsystem aktive Aufteilung bereits abgedeckt ist – und damit, ob ein SetOnTarget einen Neustart auslösen würde (siehe Abschnitt oben).

<RTimeCapabilities>

Kennzahl für die Echtzeit-Fähigkeiten des Zielsystems. Für die Kern-Konfiguration über ConsumeXml wird der Wert nicht benötigt.

<CPUType> und <CPUFamily> sind praktisch feste Kennzahlen für „x86-PC mit modernem Intel-Prozessor", dass sie sich bei Änderungen an der Kern-Konfiguration nicht ändern, ist normal. Aussagekräftig sind <AvailabeCPUs> (vorhandene Kerne), <RealTimeCPUs> (als RT-Core ausgewählte Kerne) und <CpuConfigValidOnTarget> (Neustart nötig oder nicht).

Affinity-Bitmaske

<Affinity> ist eine hexadezimale Bitmaske. Bit i steht für den Kern mit id="i":

Genutzte Kerne

Affinity

Kern 0

#x0000000000000001

Kern 0 bis 1

#x0000000000000003

Kern 0 bis 2

#x0000000000000007

Kern 0 bis 3

#x000000000000000f

Kern 0 bis 5

#x000000000000003f

Kern 0 bis 7

#x00000000000000ff

Detailparameter je Kern konfigurieren

ITcSmTreeItem realtimeSettings = systemManager.LookupTreeItem("TIRS");

string xml = @"<TreeItem>
<RTimeSetDef>
<MaxCPUs>3</MaxCPUs>
<Affinity>#x0000000000000007</Affinity>
<CPUs>
<CPU id=""0"">
<LoadLimit>10</LoadLimit>
<BaseTime>10000</BaseTime>
<LatencyWarning>200</LatencyWarning>
</CPU>
<CPU id=""1"">
<LoadLimit>20</LoadLimit>
<BaseTime>5000</BaseTime>
<LatencyWarning>500</LatencyWarning>
</CPU>
<CPU id=""2"">
<LoadLimit>30</LoadLimit>
<BaseTime>3333</BaseTime>
<LatencyWarning>1000</LatencyWarning>
</CPU>
</CPUs>
</RTimeSetDef>
</TreeItem>";

realtimeSettings.ConsumeXml(xml);

<Affinity>#x0000000000000007</Affinity> aktiviert die Kerne 0 bis 2, passend zu den drei <CPU>-Einträgen. Ohne <Methods>-Block bleibt dies eine reine Projekteinstellung. Zum Übertragen auf das Zielsystem ist <SetOnTarget> und <RequestReboot> zu ergänzen.

Task-CPU-Affinität setzen

ITcSmTreeItem tasks = systemManager.LookupTreeItem("TIRT");
ITcSmTreeItem task1 = tasks.CreateChild("TaskA", 1);

task1.ConsumeXml(@"<TreeItem>
<TaskDef>
<CpuAffinity>#x0000000000000001</CpuAffinity>
</TaskDef>
</TreeItem>");

Die Affinität ist eine hexadezimale Bitmaske. Kern 0 entspricht #x0000000000000001, Kern 1 entspricht #x0000000000000002, Kern 2 entspricht #x0000000000000004 und so weiter.