Sign in with Google to keep private notes

Performance Profiling 101

Performance Measurement Counter Events

MPKI: Misses per kilo instruction

STLB:L Second Translation Lookaside Buffer

Notes:

STLB metric being speculative refers to attempting to use the TLB before for an instruction that isn't guaranteed to retired

Metric Name Description Formula
L1MPKI L1 cache true misses per kilo instruction For retired demand loads 1000 * MEM_LOAD_RETIRED.L1_MISS_PS / INST_RETIRED.ANY
L2MPKI L2 cache true misses per kilo instruction For retired demand loads 1000 * MEM_LOAD_RETIRED.L2_MISS_PS / INST_RETIRED.ANY
L3MPKI L3 cache true misses per kilo instruction For retired demand loads 1000 * MEM_LOAD_RETIRED.L3_MISS_PS / INST_RETIRED.ANY
Branch Mispr. Ratio Ratio of all branches which mispredict — BR_MISP_RETIRED.ALL_BRANCHES / BR_INST_RETIRED.ALL_BRANCHES
STLB MPKI 2nd Level TLB code speculative misses per kilo instruction Misses of any page size that complete the page walk<br>STLB MPKI = STLB MPKI Load + STLB MPKI Store 1000 * ITLB_MISSES.WALK_COMPLETED / INST_RETIRED.ANY
STLB MPKI Load 2nd Level TLB data load speculative misses per kilo instruction — 1000 * DTLB_LD_MISSES.WALK_COMPLETED / INST_RETIRED.ANY
STLB MPKI Store STLB data store speculative misses per kilo instruction — 1000 * DTLB_ST_MISSES.WALK_COMPLETED / INST_RETIRED.ANY
Load Miss Real Latency* Average latency for L1 D-cache miss demand load operations In core cycles L1D_PEND_MISS.PENDING / MEM_LD_COMPLETED.L1_MISS_ANY
ILP Instruction-level parallelism per core Average number of µops executed when there is execution UOPS_EXECUTED.THREAD / UOPS_EXECUTED.CORE_CYCLES_GE1<br>Divide by 2 if SMT is enabled
MLP Memory-level parallelism per thread MLP = Total cycles with ≥1 outstanding miss (weighted by count) / Total cycles with ≥1 outstanding mis.<br><br>In laymans terms, average number of outstanding L2/LLC misses per cycle, sampled over intervals where at least one miss is pending. L1D_PEND_MISS.PENDING / L1D_PEND_MISS.PENDING_CYCLES
DRAM BW Use GB/sec* Average external memory bandwidth use For reads and writes. (64 * (UNC_M_CAS_COUNT.RD + UNC_M_CAS_COUNT.WR) / 1GB) / Time
IpCall Instructions per near call This just refers to the average number of instructions before a call is made. So its a instruction per call frequency. INST_RETIRED.ANY / BR_INST_RETIRED.NEAR_CALL
IpBranch Instructions per branch See above. INST_RETIRED.ANY / BR_INST_RETIRED.ALL_BRANCHES
IpLoad Instructions per load See above. INST_RETIRED.ANY / MEM_INST_RETIRED.ALL_LOADS_PS
IpStore Instructions per store See above. INST_RETIRED.ANY / MEM_INST_RETIRED.ALL_STORES_PS
IpMispredict Instructions per non-speculative branch misprediction See above. INST_RETIRED.ANY / BR_MISP_RETIRED.ALL_BRANCHES
IpFLOP Instructions per FP operation Lol<br>FLOP is floating point operation but unless you live under a rock you probably have heard of this horrifying term
IpArith Instructions per FP arithmetic instruction <br>IpArith (all FP arithmetic instructions)<br>├── Scalar<br>│ ├── IpArith Scalar SP<br>│ └── IpArith Scalar DP<br>└── Vector (SIMD/packed)<br>├── AVX128 (128-bit vectors, AVX-encoded: e.g., VADDPS/VADDPD with xmm registers)<br>├── AVX256 (256-bit vectors, AVX-encoded: e.g., VADDPS/VADDPD with ymm registers)<br>└── (on AVX-512-capable systems) AVX512 (512-bit vectors, zmm registers)<br>
IpArith Scalar SP Instructions per FP arithmetic scalar single-precision instruction — INST_RETIRED.ANY / FP_ARITH_INST.SCALAR_SINGLE
IpArith Scalar DP Instructions per FP arithmetic scalar double-precision instruction — INST_RETIRED.ANY / FP_ARITH_INST.SCALAR_DOUBLE
Ip Arith AVX128 Instructions per arithmetic AVX/SSE 128-bit instruction AVX stands for advanced vector selections. INST_RETIRED.ANY / (FP_ARITH_INST.128B_PACKED_DOUBLE + FP_ARITH_INST.128B_PACKED_SINGLE)
Ip Arith AVX256 Instructions per arithmetic AVX 256-bit instruction — INST_RETIRED.ANY / (FP_ARITH_INST.256B_PACKED_DOUBLE + FP_ARITH_INST.256B_PACKED_SINGLE)
Ip SWPF Instructions per software prefetch instruction Of any type<br>Apparently too much software prefetch is actually a bad thing. INST_RETIRED.ANY / SW_PREFETCH_ACCESS.T0:u0xF

Caveats

  1. ILP and MLP metrics do not represent theoretical maximums for an application; rather they measure the actual ILP and MLP of an application on a given machine. On an ideal machine with infinite resources, these numbers would be higher.
  2. All metrics besides “DRAM BW Use” and “Load Miss Real Latency” are fractions; we can apply fairly straightforward reasoning to each of them to tell whether a specific metric is high or low. But to make sense of “DRAM BW Use” and “Load Miss Real Latency” metrics, we need to put them in context. For the former, we would like to know if a program saturates the memory bandwidth or not. The latter gives you an idea of the average cost of a cache miss, which is useless by itself unless you know the latencies of each component in the cache hierarchy.

MLC

$ sudo ./mlc --idle_latency -c0 -L -b10m
Intel(R) Memory Latency Checker - v3.10
Command line parameters: --idle_latency -c0 -L -b10m
Using buffer size of 10.000MiB
Each iteration took 31.1 base frequency clocks ( 12.5 ns)

idle-latency for idle simulation, load-latency to simulate there being other hungry processes, c0 to pin the measurement process to logical core 0. if you read the manual for this system, this is actually a Performance Core

$ sudo ./mlc --max_bandwidth -k0-15 -Y -L -u -b18m
Measuring Maximum Memory Bandwidths for the system
Bandwidths are in MB/sec (1 MB/sec = 1,000,000 Bytes/sec)
Using all the threads from each core if Hyper-threading is enabled
Using traffic with the following read-write ratios
ALL Reads
:
349670.42

On most Intel chips (the ones MLC targets), the L3 cache is inclusive of L1 and L2. That means: whatever is sitting in L1 or L2 is also required to have a copy sitting in L3 at the same time. L3 isn't a separate 18 MB pool that's short-changed by however much lives "up" in L1/L2 — it's a superset. If a cache line is in L1, it's guaranteed to also be in L3.

So wehn you choose -b18m since L3 capacity is 18mb then you'd effectively be measuring the L3 cache latency

(-u ensured when you're saying all threads in total use 18mb. if excluded, you'd measure 18mb * 8)

Practice

Here's what i identified as abnormal

Here's what I should have identified as well, highlighted in green

Also take care to note that these readings are actually averages that may change over the course of the program's lifecycle. E.g. imagine IPC is shown to be 2, which is actually the average of 2 different average performance modes where in one you have 1 IPC and in the other 3 IPC.

Cool stuff

If you go with a P/E core design, you can have the P cores L2 cache be in-core and E cores L2 cache be shared between multiple cores.

 

 

Articles to read next