CPUSets für die Entwicklung von SpielenCPUSets for game development

EinführungIntroduction

Die universelle Windows-Plattform (UWP) ist das Herzstück einer Vielzahl von elektronischen Geräten für Verbraucher.The Universal Windows Platform (UWP) is at the core of a wide range of consumer electronic devices. Als solches benötigt sie eine allgemeine API, um die Bedürfnisse aller Anwendungsarten zu erfüllen: von Spielen über eingebettete Apps bis hin zu Enterprise-Software, die auf Servern ausgeführt wird.As such, it requires a general purpose API to address the needs of all types of applications from games to embedded apps to enterprise software running on servers. Durch die Nutzung der richtigen Informationen, die von der API bereitgestellt werden, können Sie sicherstellen, dass Ihr Spiel auf jeder Hardware optimal ausgeführt wird.By leveraging the right information provided by the API, you can ensure your game runs at its best on any hardware.

CPUSets-APICPUSets API

Die CPUSets-API bietet Kontrolle darüber, welche CPU-Sätze zur Verfügung stehen, um die Ausführung von Threads darauf zu planen.The CPUSets API provides control over which CPU sets are available for threads to be scheduled on. Zwei Funktionen sind verfügbar, um zu steuern, wo Threads geplant werden:Two functions are available to control where threads are scheduled:

  • SetProcessDefaultCpuSets: Diese Funktion kann zum Angeben der CPU-Sätze verwendet werden, auf denen neue Threads ausgeführt werden können, wenn sie nicht bestimmten CPU-Sätze zugeordnet sind.SetProcessDefaultCpuSets – This function can be used to specify which CPU sets new threads may run on if they are not assigned to specific CPU sets.
  • SetThreadSelectedCpuSets: Mit dieser Funktion können Sie die CPU-Sätze beschränken, auf denen ein bestimmter Thread ausgeführt wird.SetThreadSelectedCpuSets – This function allows you to limit the CPU sets a specific thread may run on.

Wenn die Funktion SetProcessDefaultCpuSets niemals verwendet wird, können neu erstellte Threads auf jeder CPU geplant werden, die für Ihren Prozess verfügbar ist.If the SetProcessDefaultCpuSets function is never used, newly created threads may be scheduled on any CPU set available to your process. Dieser Abschnitt behandelt die Grundlagen der CPUSets-API.This section goes over the basics of the CPUSets API.

GetSystemCpuSetInformationGetSystemCpuSetInformation

Die erste API, die zum Sammeln von Informationen verwendet wird, ist die GetSystemCpuSetInformation-Funktion.The first API used for gathering information is the GetSystemCpuSetInformation function. Diese Funktion füllt Informationen in einem Bereich von SYSTEM_CPU_SET_INFORMATION-Objekten auf, die vom Titel-Code bereitgestellt werden.This function populates information in an array of SYSTEM_CPU_SET_INFORMATION objects provided by title code. Der Speicher für das Ziel muss vom Spielcode zugeordnet werden, dessen Größe durch Aufrufen von GetSystemCpuSetInformation selbst bestimmt wird.The memory for the destination must be allocated by game code, the size of which is determined by calling GetSystemCpuSetInformation itself. Dies erfordert zwei Aufrufe von GetSystemCpuSetInformation, wie im folgenden Beispiel gezeigt.This requires two calls to GetSystemCpuSetInformation as demonstrated in the following example.

unsigned long size;
HANDLE curProc = GetCurrentProcess();
GetSystemCpuSetInformation(nullptr, 0, &size, curProc, 0);

std::unique_ptr<uint8_t[]> buffer(new uint8_t[size]);

PSYSTEM_CPU_SET_INFORMATION cpuSets = reinterpret_cast<PSYSTEM_CPU_SET_INFORMATION>(buffer.get());
  
GetSystemCpuSetInformation(cpuSets, size, &size, curProc, 0);

Jede Instanz von zurückgegebenen SYSTEM_CPU_SET_INFORMATION enthält Informationen zu einer eindeutigen Verarbeitungseinheit, die auch als CPU-Satz bezeichnet wird.Each instance of SYSTEM_CPU_SET_INFORMATION returned contains information about one unique processing unit, also known as a CPU set. Dies bedeutet nicht notwendigerweise, dass er ein eindeutiges physisches Hardwaregerät darstellt.This does not necessarily mean that it represents a unique physical piece of hardware. CPUs, die Hyperthreading nutzen, verfügen über mehrere logische Kerne, die auf einem einzigen physischen Verarbeitungskern ausgeführt werden.CPUs that utilize hyperthreading will have multiple logical cores running on a single physical processing core. Das Planen von mehreren Threads auf verschiedenen logischen Kernen, die sich auf dem gleichen physischen Kern befinden, ermöglicht eine Optimierung von Ressourcen auf Hardware-Ebene, für die andernfalls zusätzliche Arbeit auf der Kernel-Ebene durchgeführt werden müsste.Scheduling multiple threads on different logical cores that reside on the same physical core allows hardware-level resource optimization that would otherwise require extra work to be done at the kernel level. Zwei Threads, die auf separaten logischen Kernen auf dem gleichen physischen Kern geplant sind, müssen die CPU-Zeit teilen, würden aber effizienter ausgeführt werden, als wenn sie auf dem gleichen logischen Kern geplant worden wären.Two threads scheduled on separate logical cores on the same physical core must share CPU time, but would run more efficiently than if they were scheduled to the same logical core.

SYSTEM_CPU_SET_INFORMATIONSYSTEM_CPU_SET_INFORMATION

Die Informationen in jeder Instanz dieser Datenstruktur, die von GetSystemCpuSetInformation zurückgegeben wird, enthalten Informationen zu einer eindeutigen Verarbeitungseinheit, auf der Threads geplant werden können.The information in each instance of this data structure returned from GetSystemCpuSetInformation contains information about a unique processing unit that threads may be scheduled on. Angesichts der möglichen Bandbreite von Zielgeräten gelten möglicherweise viele der Informationen in der SYSTEM_CPU_SET_INFORMATION-Datenstruktur nicht für die Entwicklung von Spielen.Given the possible range of target devices, a lot of the information in the SYSTEM_CPU_SET_INFORMATION data structure may not applicable for game development. Tabelle 1 enthält eine Erläuterung der Datenmember, die für die Entwicklung von Spielen hilfreich sind.Table 1 provides an explanation of data members that are useful for game development.

Tabelle 1. Datenmember, die für die Spieleentwicklung nützlich sind.Table 1. Data members useful for game development.

MembernameMember name DatentypData type BESCHREIBUNGDescription
TypType CPU_SET_INFORMATION_TYPECPU_SET_INFORMATION_TYPE Der Typ der Informationen in der Struktur.The type of information in the structure. Wenn der Wert nicht CpuSetInformation lautet, sollte er ignoriert werden.If the value of this is not CpuSetInformation, it should be ignored.
IdId unsigned longunsigned long Die ID des angegebenen CPU-Satzes.The ID of the specified CPU set. Dies ist die ID, die mit CPU-Satz-Funktionen wie SetThreadSelectedCpuSets verwendet werden sollte.This is the ID that should be used with CPU set functions such as SetThreadSelectedCpuSets.
GruppierenGroup unsigned shortunsigned short Gibt die „Prozessorgruppe“ des CPU-Satzes an.Specifies the “processor group” of the CPU set. Mit Prozessorgruppen kann ein PC mehr als 64 logische Prozessorkerne haben, und ein Austausch von CPUs per Hot-Swap bei laufendem System wird möglich.Processor groups allow a PC to have more than 64 logical cores, and allow for hot swapping of CPUs while the system is running. Es kommt nicht oft vor, dass ein PC kein Server mit mehr als einer Gruppe ist.It is uncommon to see a PC that is not a server with more than one group. Wenn Sie nicht gerade Anwendungen schreiben, die auf großen Servern oder Serverfarmen ausgeführt werden sollen, empfiehlt es sich, CPU-Sätze in einer einzelnen Gruppe zu verwenden, da die meisten Verbraucher-PCs nur eine Prozessorgruppe haben.Unless you are writing applications meant to run on large servers or server farms, it is best to use CPU sets in a single group because most consumer PCs will only have one processor group. Alle anderen Werte in dieser Struktur beziehen sich auf die Gruppe.All other values in this structure are relative to the Group.
LogicalProcessorIndexLogicalProcessorIndex unsigned charunsigned char Zur Gruppe relativer Index des CPU-SatzesGroup relative index of the CPU set
CoreIndexCoreIndex unsigned charunsigned char Zur Gruppe relativer Index des physischen CPU-Kerns, auf dem sich der CPU-Satz befindet.Group relative index of the physical CPU core where the CPU set is located
LastLevelCacheIndexLastLevelCacheIndex unsigned charunsigned char Zur Gruppe relativer Index des letzten Caches, der diesem CPU-Satz zugeordnet ist.Group relative index of the last cache associated with this CPU set. Dies ist der langsamste Cache, es sei denn, das System verwendet NUMA-Knoten, in der Regel den L2- oder L3-Cache.This is the slowest cache unless the system utilizes NUMA nodes, usually the L2 or L3 cache.

Die anderen Datenmember liefern Informationen, von denen es unwahrscheinlich ist, dass sie CPUs in Verbrauchercomputern oder anderen Verbrauchergeräten beschreiben, sodass sie wahrscheinlich nicht hilfreich sein.The other data members provide information that is unlikely to describe CPUs in consumer PCs or other consumer devices and is unlikely to be useful. Die von den zurückgegebenen Daten gelieferten Informationen können dann verwendet werden, um Threads auf verschiedene Weise zu organisieren.The information provided by the data returned can then be used to organize threads in various ways. Im Abschnitt Überlegungen für die Spieleentwicklung dieses Whitepapers sind verschiedene Möglichkeiten beschrieben, wie diese Daten zur Optimierung der Thread-Zuordnung genutzt werden können.The Considerations for game development section of this white paper details a few ways to leverage this data to optimize thread allocation.

Im Folgenden sind einige Beispiele für die Art der Informationen aufgeführt, die von UWP-Anwendungen gesammelt werden, die auf verschiedene Arten von Hardware ausgeführt werden.The following are some examples of the type of information gathered from UWP applications running on various types of hardware.

Tabelle 2. Informationen, die von einer UWP-App zurückgegeben werden, die auf einer Microsoft Lumia 950 ausgeführt wird Dies ist ein Beispiel für ein System, das über mehrere Caches der letzten Ebene verfügt. Die Lumia 950 bietet einen Qualcomm 808 Snapdragon-Prozess, der einen Dual-Core-Arm-und vier-Kern-ARM-Cortex A53 CPUs enthält.Table 2. Information returned from a UWP app running on a Microsoft Lumia 950. This is an example of a system that has multiple last level caches. The Lumia 950 features a Qualcomm 808 Snapdragon process that contains a dual core ARM Cortex A57 and quad core ARM Cortex A53 CPUs.

Tabelle 2

Tabelle 3. Informationen aus einer UWP-APP, die auf einem typischen PC ausgeführt wird. Dies ist ein Beispiel für ein System, das Hyperthreading verwendet. Jeder physische Kern verfügt über zwei logische Kerne, auf die Threads geplant werden können. In diesem Fall enthielt das System eine Intel Xenon-CPU E5-2620.Table 3. Information returned from a UWP app running on a typical PC. This is an example of a system that uses hyperthreading; each physical core has two logical cores onto which threads can be scheduled. In this case, the system contained an Intel Xenon CPU E5-2620.

Tabelle 3

Tabelle 4. Informationen, die von einer UWP-App zurückgegeben werden, die auf einem Quad Core Microsoft Surface pro 4 ausgeführt wird Dieses System verfügte über eine Intel Core i5-6300-CPU.Table 4. Information returned from a UWP app running on a quad core Microsoft Surface Pro 4. This system had an Intel Core i5-6300 CPU.

Tabelle 4

SetThreadSelectedCpuSetsSetThreadSelectedCpuSets

Nachdem nun Informationen zu den CPU-Sätzen verfügbar sind, können sie zum Organisieren von Threads verwendet werden.Now that information about the CPU sets is available, it can be used to organize threads. Das Handle eines mit CreateThread erstellten Threads wird an diese Funktion übergeben, zusammen mit einem Bereich von IDs der CPU-Sätze, auf denen der Thread geplant werden kann.The handle of a thread created with CreateThread is passed to this function along with an array of IDs of the CPU sets that the thread can be scheduled on. Ein Beispiel für die Nutzung wird im folgenden Code veranschaulicht.One example of its usage is demonstrated in the following code.

HANDLE audioHandle = CreateThread(nullptr, 0, AudioThread, nullptr, 0, nullptr);
unsigned long cores [] = { cpuSets[0].CpuSet.Id, cpuSets[1].CpuSet.Id };
SetThreadSelectedCpuSets(audioHandle, cores, 2);

In diesem Beispiel wird ein Thread basierend auf einer Funktion erstellt, die als AudioThread deklariert wird.In this example, a thread is created based on a function declared as AudioThread. Dieser Thread kann dann auf einem von zwei CPU-Sätzen geplant werden.This thread is then allowed to be scheduled on one of two CPU sets. Threadbesitz des CPU-Satzes ist nicht ausschließend.Thread ownership of the CPU set is not exclusive. Threads, die erstellt werden, ohne an einen bestimmten CPU-Satz gebunden zu sein, verwenden möglicherweise Zeit vom AudioThread.Threads that are created without being locked to a specific CPU set may take time from the AudioThread. Ebenso können andere erstellte Threads zu einem späteren Zeitpunkt auch an einen oder beide dieser CPU-Sätze gebunden sein.Likewise, other threads created may also be locked to one or both of these CPU sets at a later time.

SetProcessDefaultCpuSetsSetProcessDefaultCpuSets

Die Umkehrung zu SetThreadSelectedCpuSets ist SetProcessDefaultCpuSets.The converse to SetThreadSelectedCpuSets is SetProcessDefaultCpuSets. Bei der Erstellung von Threads müssen diese nicht an bestimmte CPU-Sätze gebunden werden.When threads are created, they do not need to be locked into certain CPU sets. Wenn Sie nicht möchten, dass diese Threads auf bestimmten CPU-Sätzen ausgeführt werden (z. B. auf von Ihrem Render-Thread oder Audio-Thread verwendeten CPU-Sätzen), können Sie diese Funktion verwenden, um anzugeben, auf welchen Kernen diese Threads geplant werden dürfen.If you do not want these threads to run on specific CPU sets (those used by your render thread or audio thread for example), you can use this function to specify which cores these threads are allowed to be scheduled on.

Überlegungen für die SpieleentwicklungConsiderations for game development

Wie wir bereits gesehen haben, bietet die CPUSets-API viele Informationen und Flexibilität rund um die Planung von Threads.As we've seen, the CPUSets API provides a lot of information and flexibility when it comes to scheduling threads. Anstatt nach dem Bottom-up-Konzept zu versuchen, Anwendungsfälle für diese Daten zu finden, ist es effektiver, den Top-Down-Ansatz zu verwenden, bei dem ermittelt wird, wie die Daten für gängige Szenarien verwendet werden können.Instead of taking the bottom-up approach of trying to find uses for this data, it is more effective to take the top-down approach of finding how the data can be used to accommodate common scenarios.

Arbeiten mit zeitkritischen Threads und HyperthreadingWorking with time critical threads and hyperthreading

Diese Methode ist effektiv, wenn Ihr Spiel einige Threads aufweist, die in Echtzeit zusammen mit anderen Arbeitsthreads ausgeführt werden müssen, die relativ wenig CPU-Zeit in Anspruch nehmen.This method is effective if your game has a few threads that must run in real time along with other worker threads that require relatively little CPU time. Manche Aufgaben, z. B. fortlaufende Hintergrundmusik, müssen für ein optimales Spielerlebnis ohne Unterbrechung ausgeführt werden.Some tasks, like continuous background music, must run without interruption for an optimal gaming experience. Bereits ein einzelner Frame mit Audio-Threadzurückstellung kann eine Störung verursachen, sodass es wichtig ist, dass für jeden Frame die erforderliche Menge an CPU-Zeit zur Verfügung steht.Even a single frame of starvation for an audio thread may cause popping or glitching, so it is critical that it receives the necessary amount of CPU time every frame.

Mithilfe von SetThreadSelectedCpuSets in Verbindung mit SetProcessDefaultCpuSets können Sie sicherstellen, dass Ihre rechenintensiven Threads nicht von Arbeitsthreads unterbrochen werden.Using SetThreadSelectedCpuSets in conjunction with SetProcessDefaultCpuSets can ensure your heavy threads remain uninterrupted by any worker threads. SetThreadSelectedCpuSets kann verwendet werden, um Ihre rechenintensiven Threads bestimmten CPU-Sätzen zuzuweisen.SetThreadSelectedCpuSets can be used to assign your heavy threads to specific CPU sets. SetProcessDefaultCpuSets kann dann verwendet werden, um sicherzustellen, dass alle erstellten nicht zugewiesenen Threads auf anderen CPU-Sätzen geplant werden.SetProcessDefaultCpuSets can then be used to make sure any unassigned threads created are put on other CPU sets. Im Fall von CPUs, die Hyperthreading nutzen, ist es auch wichtig, logische Kerne auf dem gleichen physischen Kern zu berücksichtigen.In the case of CPUs that utilize hyperthreading, it's also important to account for logical cores on the same physical core. Arbeitsthreads sollten nicht auf logischen Kernen ausgeführt werden dürfen, die den gleichen physischen Kern wie ein Thread verwenden, den Sie mit Echtzeit-Reaktionsfähigkeit ausführen möchten.Worker threads should not be allowed to run on logical cores that share the same physical core as a thread that you want to run with real time responsiveness. Der folgende Code veranschaulicht, wie Sie bestimmen, ob ein PC Hyperthreading verwendet.The following code demonstrates how to determine whether a PC uses hyperthreading.

unsigned long retsize = 0;
(void)GetSystemCpuSetInformation( nullptr, 0, &retsize,
    GetCurrentProcess(), 0);
 
std::unique_ptr<uint8_t[]> data( new uint8_t[retsize] );
if ( !GetSystemCpuSetInformation(
    reinterpret_cast<PSYSTEM_CPU_SET_INFORMATION>( data.get() ),
    retsize, &retsize, GetCurrentProcess(), 0) )
{
    // Error!
}
 
std::set<DWORD> cores;
std::vector<DWORD> processors;
uint8_t const * ptr = data.get();
for( DWORD size = 0; size < retsize; ) {
    auto info = reinterpret_cast<const SYSTEM_CPU_SET_INFORMATION*>( ptr );
    if ( info->Type == CpuSetInformation ) {
         processors.push_back( info->CpuSet.Id );
         cores.insert( info->CpuSet.CoreIndex );
    }
    ptr += info->Size;
    size += info->Size;
}
 
bool hyperthreaded = processors.size() != cores.size();

Wenn das System Hyperthreading verwendet, ist es wichtig, dass der Satz von Standard-CPU-Sätzen keine logischen Kerne auf dem gleichen physischen Kern wie Echtzeit-Threads enthält.If the system utilizes hyperthreading, it is important that the set of default CPU sets does not include any logical cores on the same physical core as any real time threads. Wenn das System kein Hyperthreading verwendet, muss nur sichergestellt werden, dass die CPU-Standardsätze nicht den gleichen Kern wie der CPU-Satz enthält, der Ihren Audio-Thread ausführt.If the system is not hyperthreading, it is only necessary to make sure that the default CPU sets do not include the same core as the CPU set running your audio thread.

Ein Beispiel für das Organisieren von Threads basierend auf physischen Kernen finden Sie im CPUSets-Beispiel, das im GitHub-Repository verfügbar ist, das im Abschnitt Zusätzliche Ressourcen verlinkt ist.An example of organizing threads based on physical cores can be found in the CPUSets sample available on the GitHub repository linked in the Additional resources section.

Senken der Kosten der Cache-Kohärenz mit Cache der letzten EbeneReducing the cost of cache coherence with last level cache

Cache-Kohärenz bedeutet, dass gecachter Arbeitsspeicher der gleiche für mehrere Hardwareressourcen ist, die auf dieselben Daten zugreifen.Cache coherency is the concept that cached memory is the same across multiple hardware resources that act on the same data. Wenn Threads auf verschiedenen Kernen geplant sind, aber auf dieselben Daten zugreifen, arbeiten sie möglicherweise mit separaten Kopien dieser Daten in verschiedenen Caches.If threads are scheduled on different cores, but work on the same data, they may be working on separate copies of that data in different caches. Um richtige Ergebnisse zu erhalten, muss die Kohärenz dieser Caches gewährleistet sein.In order to get correct results, these caches must be kept coherent with each other. Die Aufrechterhaltung der Kohärenz zwischen mehreren Caches ist relativ teuer, ist aber erforderlich, damit ein System mit mehreren Kernen ausgeführt werden kann.Maintaining coherency between multiple caches is relatively expensive, but necessary for any multi-core system to operate. Darüber hinaus liegt es völlig außerhalb der Kontrolle des Client-Codes; das zugrunde liegende System arbeitet unabhängig daran, Caches auf dem neuesten Stand zu halten, indem es auf zwischen Kernen freigegebene Speicherressourcen zugreift.Additionally, it is completely out of the control of client code; the underlying system works independently to keep caches up to date by accessing shared memory resources between cores.

Wenn Ihr Spiel mehrere Threads verwendet, die gemeinsam eine besonders große Menge an Daten nutzen, können Sie die Kosten der Cache-Kohärenz minimieren, indem Sie sicherstellen, dass sie auf CPU-Sätzen geplant werden, die einen Cache der letzten Ebene teilen.If your game has multiple threads that share an especially large amount of data, you can minimize the cost of cache coherency by ensuring that they are scheduled on CPU sets that share a last level cache. Der Cache der letzten Ebene ist der langsamste Cache, der für einen Kern auf Systemen zur Verfügung steht, die keine NUMA-Knoten verwenden.The last level cache is the slowest cache available to a core on systems that do not utilize NUMA nodes. Es kommt äußerst selten vor, dass ein Spiele-PC NUMA-Knoten nutzt.It is extremely rare for a gaming PC to utilize NUMA nodes. Wenn Kerne keinen Cache der letzten Ebene teilen, müsste zur Aufrechterhaltung der Kohärenz auf Speicherressourcen höherer Ebene und somit langsamere Speicherressourcen zugegriffen werden.If cores do not share a last level cache, maintaining coherency would require accessing higher level, and therefore slower, memory resources. Durch eine Bindung von zwei Threads an separate CPU-Sätze, die einen Cache und einen physischen Kern teilen, kann eine noch bessere Leistung erzielt werden, als durch deren Planung auf separaten physischen Kernen, wenn sie in einem beliebigen Frame nicht mehr als 50 % der Zeit benötigen.Locking two threads to separate CPU sets that share a cache and a physical core may provide even better performance than scheduling them on separate physical cores if they do not require more than 50% of the time in any given frame.

In diesem Codebeispiel wird veranschaulicht, wie Sie ermitteln, ob Threads, die häufig kommunizieren, einen Cache der letzten Ebene teilen können.This code example shows how to determine whether threads that communicate frequently can share a last level cache.

unsigned long retsize = 0;
(void)GetSystemCpuSetInformation(nullptr, 0, &retsize,
    GetCurrentProcess(), 0);
 
std::unique_ptr<uint8_t[]> data(new uint8_t[retsize]);
if (!GetSystemCpuSetInformation(
    reinterpret_cast<PSYSTEM_CPU_SET_INFORMATION>(data.get()),
    retsize, &retsize, GetCurrentProcess(), 0))
{
    // Error!
}
 
unsigned long count = retsize / sizeof(SYSTEM_CPU_SET_INFORMATION);
bool sharedcache = false;
 
std::map<unsigned char, std::vector<SYSTEM_CPU_SET_INFORMATION>> cachemap;
for (size_t i = 0; i < count; ++i)
{
    auto cpuset = reinterpret_cast<PSYSTEM_CPU_SET_INFORMATION>(data.get())[i];
    if (cpuset.Type == CPU_SET_INFORMATION_TYPE::CpuSetInformation)
    {
        if (cachemap.find(cpuset.CpuSet.LastLevelCacheIndex) == cachemap.end())
        {
            std::pair<unsigned char, std::vector<SYSTEM_CPU_SET_INFORMATION>> newvalue;
            newvalue.first = cpuset.CpuSet.LastLevelCacheIndex;
            newvalue.second.push_back(cpuset);
            cachemap.insert(newvalue);
        }
        else
        {
            sharedcache = true;
            cachemap[cpuset.CpuSet.LastLevelCacheIndex].push_back(cpuset);
        }
    }
}

Das in Abbildung 1 dargestellte Cache-Layout ist ein Beispiel für die Art von Layout, die Sie möglicherweise bei einem System sehen.The cache layout illustrated in Figure 1 is an example of the type of layout you might see from a system. In dieser Abbildung sehen Sie eine Darstellung der Caches in einem Microsoft Lumia 950.This figure is an illustration of the caches found in a Microsoft Lumia 950. Threadübergreifende Kommunikation zwischen CPU 256 und CPU 260 würde erheblichen Overhead verursachen, da das System seine L2-Caches kohärent halten müsste.Inter-thread communication occurring between CPU 256 and CPU 260 would incur significant overhead because it would require the system to keep their L2 caches coherent.

Abbildung 1. Die Cache Architektur wurde auf einem Microsoft Lumia 950-Gerät gefunden.Figure 1. Cache architecture found on a Microsoft Lumia 950 device.

Lumia 950-Cache

ZusammenfassungSummary

Die für UWP-Entwicklung verfügbare CPUSets-API bietet eine beträchtliche Menge an Informationen und Kontrolle über Ihre Multithreading-Optionen.The CPUSets API available for UWP development provides a considerable amount of information and control over your multithreading options. Der zusätzliche Komplexität im Vergleich zu früheren Multithread-APIs für die Windows-Entwicklung ist mit einer Lernkurve verbunden. Die gestiegene Flexibilität ermöglicht aber letztendlich eine bessere Leistung auf unterschiedlichen Verbraucher-PCs und anderen Hardwarezielen.The added complexities compared to previous multithreaded APIs for Windows development has some learning curve, but the increased flexibility ultimately allows for better performance across a range of consumer PCs and other hardware targets.

Zusätzliche RessourcenAdditional resources