The following topics are discussed in this section.
The Xbox One console contains two processor modules, each of which has four processor cores. The cores on a processor module share L2 cache memory and bandwidth to main memory, and L1 and local L2 cache hits have substantially lower latency than L2 cache hits on the other processor module, or cache misses that result in a fetch from main memory. The System partition reserves one processor core for shared apps and system functionality such as NUI processing. The app running in the Exclusive partition is allocated the other seven cores for its use. Of the seven Exclusive partition cores, cores 0-3 occupy an entire processor module, and cores 4, 5, and 6 share a processor module with the cores allocated to the System partition. Cores 4, 5, and 6 are subject to contention for L2 cache space and main memory bandwidth with the system core, which can affect performance on those three cores. You should not allocate memory-intensive threads to cores 4, 5, or 6 for this reason.
Input/output-intensive threads, and threads that copy large amounts of data originating from shared apps or the system should be allocated to cores 4, 5, and 6. Game logic and memory-intensive worker threads that do not share data with shared apps or the system, should be allocated to cores 0-3.
| Exclusive core identifier | Shares processor module with System |
|---|---|
| 0 | No |
| 1 | No |
| 2 | No |
| 3 | No |
| 4 | Yes |
| 5 | Yes |
| 6 | Yes |
A thread is assigned to a core as soon as the thread becomes ready to run. The thread is assigned to an idle core if one is available. If multiple idle cores are available, the scheduler tries to avoid moving threads between cores and CPU modules. If there are no idle cores available, the thread is assigned to a core chosen by the operating system at thread creation time.
To lock a thread to a particular subset of cores, use the core identifiers listed above to set thread processor affinity using SetThreadAffinityMask.
Note It is currently not possible to specify which core a lambda will run on.
This section introduces performance monitoring counters (PMCs), events, and thread affinitization.
Each CPU core in the Xbox One contains four hardware PMCs. These counters can be configured to count one of a number of events relating to the core and its execution. In this way, the core can potentially monitor many different events, but only any four of these events at any one time.
Prior to the August 2013 XDK, these event counts were only shown by the PIX System Monitor — this display switches the events being counted on each core and generates averaged data on a per second basis. For micro-optimization of specific pieces of code, per second aggregated views are less useful; for this situation, from the August 2013 XDK onwards, game titles can configure and read the per-core PMCs.
Title code can map hardware events to each of the PMCs using this call:
HRESULT ConfigurePMCs(unsigned int eventIndex0, unsigned int eventIndex1, unsigned int eventIndex2, unsigned int eventIndex3);
The parameters to this call are indexes to a table of hardware events. The first event index is assigned to the first PMC. For example, this call configures PMC 0 to count retired instructions, PMC 1 will count L1 data cache misses, PMC 2 will count mispredicted branches, and PMC 3 will count data TLB misses.
HRESULT result = ConfigurePMCs(14,3,16,6);
The PMCs on all available cores are configured to count the same events. See the section about cores and affinitization below to understand the implications.
When title code calls ConfigurePMCs , it takes ownership of the counters from PIX. PIX System Monitor will no longer be able to configure the counters and display per-second counts for the whole set of counters. It is assumed the title code configuring the counters takes precedence over PIX. In a later XDK, a mechanism to hand ownership back to PIX will be provided.
PMCs hold an unsigned 64-bit total of the event they are configured to count. Title code can read that value like this:
UINT64 count;
GetPMCValue(0,&count);
The first parameter is the index of the PMC to be read. The valid range is 0 to 3 — there are only four PMCs on the core. This value is not the event index — remember the core can only count four of the possible events at any one time.
Code calling GetPMCValue before ConfigurePMCs will be returned zero values.
ConfigurePMCs sets the PMCs on all cores to count the same events. However, each core has separate PMCs; this means differencing or comparing event counts from different cores is meaningless.
Threads that are not hard affinitized to a single core using SetThreadAffinityMask can be migrated between cores by the OS scheduler. If you have a thread reading PMC values that is not hard affinitized, it will get discontinuous or incorrect values across the period it migrates cores.
For example, imagine configuring PMC 0 to count L1 data cache misses. If core 1 runs threads that cause many data cache misses, and core 4 runs threads causing very few misses, the event totals will be completely different on the two cores. If a thread reads PMC 0 on core 1 then is moved to core 4 by the OS, then reads PMC 0 on core 4 and differences the values, even though both PMCs are counting data cache misses, an incorrect picture of data cache misses will result.
When a title is set to PLM constrained state, CPU cores 4, 5, and 6 are reclaimed by the system; title threads running on those cores are forcibly migrated to cores 2 and 3. In the same way as the example above, reading PMCs across this change will result in a false picture as those threads may read PMCs from different cores.
Be aware PMC values can give a false picture in these two scenarios.
The event index provided to ConfigurePMCs should be taken from the table below. ConfigurePMCs will return E_INVALID_ARG if the index is out of range.
| Index | Name | Description |
|---|---|---|
| 0 | Reserved | Reserved |
| 1 | RetiredSseAvx | The number of SSE/AVX operations retired |
| 2 | DCacheAccesses | The number of accesses to the L1 data cache for load and store references |
| 3 | DCacheMisses | The number of L1 data cache references which miss the data cache |
| 4 | DCacheRefills | The number of L1 data cache refills satisfied from the L2 cache (and/or the northbridge) |
| 5 | L1DTLBMissL2DTLBHit | The number of L1 data cache accesses that miss in the L1 DTLB and hit in the L2 DTLB |
| 6 | DtlbMiss | The number of L1 data cache accesses that miss in both the L1 and L2 DTLBs |
| 7 | L1DtlbHit | The number of L1 data cache accesses that hit in the L1 DTLB |
| 8 | L1ITLBMissL2ITLBHit | The number of instruction fetches that miss in the L1 ITLB but hit in the L2 ITLB |
| 9 | ItlbMiss | The number of instruction fetches that miss in the 4K ITLB and 2M ITLB |
| 10 | ItlbInstructionFetchHits | The number of instruction fetches that hit in the 4K ITLB and 2M ITLB |
| 11 | MisalignedAccess | The number of L1 data cache accesses that are misaligned. Misaligned accesses incur at least an extra cache access and an extra cycle of latency on reads |
| 12 | IneffectiveSWPrefetches | The number of software prefetches that do not cause an actual L1 data cache refill |
| 13 | CpuClkNotHalted | The number of clocks that the CPU is not in a halted state |
| 14 | RetiredInstructions | The number of instructions retired (execution completed and architectural state updated). This count includes exceptions and interrupts. |
| 15 | BranchInstructions | The number of branch instructions retired. This includes all types of architectural control flow changes, including exceptions and interrupts. |
| 16 | MispredictedBranch | The number of branch instructions retired, of any type, that were not correctly predicted in either target or direction. |
| 17 | RetiredTakenBranch | The number of taken branches that were retired. This includes all types of architectural control flow changes, including exceptions and interrupts, and excludes resyncs. |
| 18 | RetiredFarSyscall | The number of far syscalls retired |
| 19 | RetiredNearReturns | The number of near return instructions retired |
| 20 | RetiredReturnsMispredicted | A near return instruction was retired that mispredicted in either target or direction |
| 21 | MispredictedTakenBranch | A taken branch instruction was retired that mispredicted in target address (but not in direction) |
| 22 | MmxFPInstructions | A floating point (x87, MMX, or SSE) instruction was retired |
| 23 | RetiredFPInstructions | The number of SSE/AVX operations retired |
| 24 | RetiredMmxInstructions | The number of MMX operations retired |
| 25 | RetiredSseInstructions | The number of SSE operations retired |
| 26 | InstructionFetchStalls | The number cycles that the instruction fetch engine is stalled |
| 27 | DataCachePrefetches | L1 data cache prefetches |
| 28 | DataCacheReadSize | The number of L1 data cache reads |
| 29 | DataCacheWriteSize | The number of L1 data cache writes |
| 30 | ITLBReloadStalls | The number of cycles when the fetch engine is stalled for an ITLB reload |