Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf stat: Remove topdown event special handling

Now the events are computed from json metrics, the hard coded logic
can be removed.

Signed-off-by: Ian Rogers <irogers@google.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Alexandre Torgue <alexandre.torgue@foss.st.com>
Cc: Andrii Nakryiko <andrii@kernel.org>
Cc: Athira Rajeev <atrajeev@linux.vnet.ibm.com>
Cc: Caleb Biggers <caleb.biggers@intel.com>
Cc: Eduard Zingerman <eddyz87@gmail.com>
Cc: Florian Fischer <florian.fischer@muhq.space>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@arm.com>
Cc: Jing Zhang <renyu.zj@linux.alibaba.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: John Garry <john.g.garry@oracle.com>
Cc: Kajol Jain <kjain@linux.ibm.com>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Leo Yan <leo.yan@linaro.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Maxime Coquelin <mcoquelin.stm32@gmail.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Perry Taylor <perry.taylor@intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Ravi Bangoria <ravi.bangoria@amd.com>
Cc: Sandipan Das <sandipan.das@amd.com>
Cc: Sean Christopherson <seanjc@google.com>
Cc: Stephane Eranian <eranian@google.com>
Cc: Suzuki Poulouse <suzuki.poulose@arm.com>
Cc: Xing Zhengjun <zhengjun.xing@linux.intel.com>
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-stm32@st-md-mailman.stormreply.com
Link: https://lore.kernel.org/r/20230219092848.639226-42-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Ian Rogers and committed by
Arnaldo Carvalho de Melo
7b86475f 1647cd5b

-385
-346
tools/perf/util/stat-shadow.c
··· 241 241 update_runtime_stat(st, STAT_TRANSACTION, map_idx, count, &rsd); 242 242 else if (perf_stat_evsel__is(counter, ELISION_START)) 243 243 update_runtime_stat(st, STAT_ELISION, map_idx, count, &rsd); 244 - else if (perf_stat_evsel__is(counter, TOPDOWN_TOTAL_SLOTS)) 245 - update_runtime_stat(st, STAT_TOPDOWN_TOTAL_SLOTS, 246 - map_idx, count, &rsd); 247 - else if (perf_stat_evsel__is(counter, TOPDOWN_SLOTS_ISSUED)) 248 - update_runtime_stat(st, STAT_TOPDOWN_SLOTS_ISSUED, 249 - map_idx, count, &rsd); 250 - else if (perf_stat_evsel__is(counter, TOPDOWN_SLOTS_RETIRED)) 251 - update_runtime_stat(st, STAT_TOPDOWN_SLOTS_RETIRED, 252 - map_idx, count, &rsd); 253 - else if (perf_stat_evsel__is(counter, TOPDOWN_FETCH_BUBBLES)) 254 - update_runtime_stat(st, STAT_TOPDOWN_FETCH_BUBBLES, 255 - map_idx, count, &rsd); 256 - else if (perf_stat_evsel__is(counter, TOPDOWN_RECOVERY_BUBBLES)) 257 - update_runtime_stat(st, STAT_TOPDOWN_RECOVERY_BUBBLES, 258 - map_idx, count, &rsd); 259 - else if (perf_stat_evsel__is(counter, TOPDOWN_RETIRING)) 260 - update_runtime_stat(st, STAT_TOPDOWN_RETIRING, 261 - map_idx, count, &rsd); 262 - else if (perf_stat_evsel__is(counter, TOPDOWN_BAD_SPEC)) 263 - update_runtime_stat(st, STAT_TOPDOWN_BAD_SPEC, 264 - map_idx, count, &rsd); 265 - else if (perf_stat_evsel__is(counter, TOPDOWN_FE_BOUND)) 266 - update_runtime_stat(st, STAT_TOPDOWN_FE_BOUND, 267 - map_idx, count, &rsd); 268 - else if (perf_stat_evsel__is(counter, TOPDOWN_BE_BOUND)) 269 - update_runtime_stat(st, STAT_TOPDOWN_BE_BOUND, 270 - map_idx, count, &rsd); 271 - else if (perf_stat_evsel__is(counter, TOPDOWN_HEAVY_OPS)) 272 - update_runtime_stat(st, STAT_TOPDOWN_HEAVY_OPS, 273 - map_idx, count, &rsd); 274 - else if (perf_stat_evsel__is(counter, TOPDOWN_BR_MISPREDICT)) 275 - update_runtime_stat(st, STAT_TOPDOWN_BR_MISPREDICT, 276 - map_idx, count, &rsd); 277 - else if (perf_stat_evsel__is(counter, TOPDOWN_FETCH_LAT)) 278 - update_runtime_stat(st, STAT_TOPDOWN_FETCH_LAT, 279 - map_idx, count, &rsd); 280 - else if (perf_stat_evsel__is(counter, TOPDOWN_MEM_BOUND)) 281 - update_runtime_stat(st, STAT_TOPDOWN_MEM_BOUND, 282 - map_idx, count, &rsd); 283 244 else if (evsel__match(counter, HARDWARE, HW_STALLED_CYCLES_FRONTEND)) 284 245 update_runtime_stat(st, STAT_STALLED_CYCLES_FRONT, 285 246 map_idx, count, &rsd); ··· 485 524 out->print_metric(config, out->ctx, color, "%7.2f%%", "of all LL-cache accesses", ratio); 486 525 } 487 526 488 - /* 489 - * High level "TopDown" CPU core pipe line bottleneck break down. 490 - * 491 - * Basic concept following 492 - * Yasin, A Top Down Method for Performance analysis and Counter architecture 493 - * ISPASS14 494 - * 495 - * The CPU pipeline is divided into 4 areas that can be bottlenecks: 496 - * 497 - * Frontend -> Backend -> Retiring 498 - * BadSpeculation in addition means out of order execution that is thrown away 499 - * (for example branch mispredictions) 500 - * Frontend is instruction decoding. 501 - * Backend is execution, like computation and accessing data in memory 502 - * Retiring is good execution that is not directly bottlenecked 503 - * 504 - * The formulas are computed in slots. 505 - * A slot is an entry in the pipeline each for the pipeline width 506 - * (for example a 4-wide pipeline has 4 slots for each cycle) 507 - * 508 - * Formulas: 509 - * BadSpeculation = ((SlotsIssued - SlotsRetired) + RecoveryBubbles) / 510 - * TotalSlots 511 - * Retiring = SlotsRetired / TotalSlots 512 - * FrontendBound = FetchBubbles / TotalSlots 513 - * BackendBound = 1.0 - BadSpeculation - Retiring - FrontendBound 514 - * 515 - * The kernel provides the mapping to the low level CPU events and any scaling 516 - * needed for the CPU pipeline width, for example: 517 - * 518 - * TotalSlots = Cycles * 4 519 - * 520 - * The scaling factor is communicated in the sysfs unit. 521 - * 522 - * In some cases the CPU may not be able to measure all the formulas due to 523 - * missing events. In this case multiple formulas are combined, as possible. 524 - * 525 - * Full TopDown supports more levels to sub-divide each area: for example 526 - * BackendBound into computing bound and memory bound. For now we only 527 - * support Level 1 TopDown. 528 - */ 529 - 530 - static double sanitize_val(double x) 531 - { 532 - if (x < 0 && x >= -0.02) 533 - return 0.0; 534 - return x; 535 - } 536 - 537 - static double td_total_slots(int map_idx, struct runtime_stat *st, 538 - struct runtime_stat_data *rsd) 539 - { 540 - return runtime_stat_avg(st, STAT_TOPDOWN_TOTAL_SLOTS, map_idx, rsd); 541 - } 542 - 543 - static double td_bad_spec(int map_idx, struct runtime_stat *st, 544 - struct runtime_stat_data *rsd) 545 - { 546 - double bad_spec = 0; 547 - double total_slots; 548 - double total; 549 - 550 - total = runtime_stat_avg(st, STAT_TOPDOWN_SLOTS_ISSUED, map_idx, rsd) - 551 - runtime_stat_avg(st, STAT_TOPDOWN_SLOTS_RETIRED, map_idx, rsd) + 552 - runtime_stat_avg(st, STAT_TOPDOWN_RECOVERY_BUBBLES, map_idx, rsd); 553 - 554 - total_slots = td_total_slots(map_idx, st, rsd); 555 - if (total_slots) 556 - bad_spec = total / total_slots; 557 - return sanitize_val(bad_spec); 558 - } 559 - 560 - static double td_retiring(int map_idx, struct runtime_stat *st, 561 - struct runtime_stat_data *rsd) 562 - { 563 - double retiring = 0; 564 - double total_slots = td_total_slots(map_idx, st, rsd); 565 - double ret_slots = runtime_stat_avg(st, STAT_TOPDOWN_SLOTS_RETIRED, 566 - map_idx, rsd); 567 - 568 - if (total_slots) 569 - retiring = ret_slots / total_slots; 570 - return retiring; 571 - } 572 - 573 - static double td_fe_bound(int map_idx, struct runtime_stat *st, 574 - struct runtime_stat_data *rsd) 575 - { 576 - double fe_bound = 0; 577 - double total_slots = td_total_slots(map_idx, st, rsd); 578 - double fetch_bub = runtime_stat_avg(st, STAT_TOPDOWN_FETCH_BUBBLES, 579 - map_idx, rsd); 580 - 581 - if (total_slots) 582 - fe_bound = fetch_bub / total_slots; 583 - return fe_bound; 584 - } 585 - 586 - static double td_be_bound(int map_idx, struct runtime_stat *st, 587 - struct runtime_stat_data *rsd) 588 - { 589 - double sum = (td_fe_bound(map_idx, st, rsd) + 590 - td_bad_spec(map_idx, st, rsd) + 591 - td_retiring(map_idx, st, rsd)); 592 - if (sum == 0) 593 - return 0; 594 - return sanitize_val(1.0 - sum); 595 - } 596 - 597 - /* 598 - * Kernel reports metrics multiplied with slots. To get back 599 - * the ratios we need to recreate the sum. 600 - */ 601 - 602 - static double td_metric_ratio(int map_idx, enum stat_type type, 603 - struct runtime_stat *stat, 604 - struct runtime_stat_data *rsd) 605 - { 606 - double sum = runtime_stat_avg(stat, STAT_TOPDOWN_RETIRING, map_idx, rsd) + 607 - runtime_stat_avg(stat, STAT_TOPDOWN_FE_BOUND, map_idx, rsd) + 608 - runtime_stat_avg(stat, STAT_TOPDOWN_BE_BOUND, map_idx, rsd) + 609 - runtime_stat_avg(stat, STAT_TOPDOWN_BAD_SPEC, map_idx, rsd); 610 - double d = runtime_stat_avg(stat, type, map_idx, rsd); 611 - 612 - if (sum) 613 - return d / sum; 614 - return 0; 615 - } 616 - 617 - /* 618 - * ... but only if most of the values are actually available. 619 - * We allow two missing. 620 - */ 621 - 622 - static bool full_td(int map_idx, struct runtime_stat *stat, 623 - struct runtime_stat_data *rsd) 624 - { 625 - int c = 0; 626 - 627 - if (runtime_stat_avg(stat, STAT_TOPDOWN_RETIRING, map_idx, rsd) > 0) 628 - c++; 629 - if (runtime_stat_avg(stat, STAT_TOPDOWN_BE_BOUND, map_idx, rsd) > 0) 630 - c++; 631 - if (runtime_stat_avg(stat, STAT_TOPDOWN_FE_BOUND, map_idx, rsd) > 0) 632 - c++; 633 - if (runtime_stat_avg(stat, STAT_TOPDOWN_BAD_SPEC, map_idx, rsd) > 0) 634 - c++; 635 - return c >= 2; 636 - } 637 - 638 527 static void print_smi_cost(struct perf_stat_config *config, int map_idx, 639 528 struct perf_stat_output_ctx *out, 640 529 struct runtime_stat *st, ··· 696 885 void *ctxp = out->ctx; 697 886 print_metric_t print_metric = out->print_metric; 698 887 double total, ratio = 0.0, total2; 699 - const char *color = NULL; 700 888 struct runtime_stat_data rsd = { 701 889 .ctx = evsel_context(evsel), 702 890 .cgrp = evsel->cgrp, ··· 854 1044 avg / (ratio * evsel->scale)); 855 1045 else 856 1046 print_metric(config, ctxp, NULL, NULL, "CPUs utilized", 0); 857 - } else if (perf_stat_evsel__is(evsel, TOPDOWN_FETCH_BUBBLES)) { 858 - double fe_bound = td_fe_bound(map_idx, st, &rsd); 859 - 860 - if (fe_bound > 0.2) 861 - color = PERF_COLOR_RED; 862 - print_metric(config, ctxp, color, "%8.1f%%", "frontend bound", 863 - fe_bound * 100.); 864 - } else if (perf_stat_evsel__is(evsel, TOPDOWN_SLOTS_RETIRED)) { 865 - double retiring = td_retiring(map_idx, st, &rsd); 866 - 867 - if (retiring > 0.7) 868 - color = PERF_COLOR_GREEN; 869 - print_metric(config, ctxp, color, "%8.1f%%", "retiring", 870 - retiring * 100.); 871 - } else if (perf_stat_evsel__is(evsel, TOPDOWN_RECOVERY_BUBBLES)) { 872 - double bad_spec = td_bad_spec(map_idx, st, &rsd); 873 - 874 - if (bad_spec > 0.1) 875 - color = PERF_COLOR_RED; 876 - print_metric(config, ctxp, color, "%8.1f%%", "bad speculation", 877 - bad_spec * 100.); 878 - } else if (perf_stat_evsel__is(evsel, TOPDOWN_SLOTS_ISSUED)) { 879 - double be_bound = td_be_bound(map_idx, st, &rsd); 880 - const char *name = "backend bound"; 881 - static int have_recovery_bubbles = -1; 882 - 883 - /* In case the CPU does not support topdown-recovery-bubbles */ 884 - if (have_recovery_bubbles < 0) 885 - have_recovery_bubbles = pmu_have_event("cpu", 886 - "topdown-recovery-bubbles"); 887 - if (!have_recovery_bubbles) 888 - name = "backend bound/bad spec"; 889 - 890 - if (be_bound > 0.2) 891 - color = PERF_COLOR_RED; 892 - if (td_total_slots(map_idx, st, &rsd) > 0) 893 - print_metric(config, ctxp, color, "%8.1f%%", name, 894 - be_bound * 100.); 895 - else 896 - print_metric(config, ctxp, NULL, NULL, name, 0); 897 - } else if (perf_stat_evsel__is(evsel, TOPDOWN_RETIRING) && 898 - full_td(map_idx, st, &rsd)) { 899 - double retiring = td_metric_ratio(map_idx, 900 - STAT_TOPDOWN_RETIRING, st, 901 - &rsd); 902 - if (retiring > 0.7) 903 - color = PERF_COLOR_GREEN; 904 - print_metric(config, ctxp, color, "%8.1f%%", "Retiring", 905 - retiring * 100.); 906 - } else if (perf_stat_evsel__is(evsel, TOPDOWN_FE_BOUND) && 907 - full_td(map_idx, st, &rsd)) { 908 - double fe_bound = td_metric_ratio(map_idx, 909 - STAT_TOPDOWN_FE_BOUND, st, 910 - &rsd); 911 - if (fe_bound > 0.2) 912 - color = PERF_COLOR_RED; 913 - print_metric(config, ctxp, color, "%8.1f%%", "Frontend Bound", 914 - fe_bound * 100.); 915 - } else if (perf_stat_evsel__is(evsel, TOPDOWN_BE_BOUND) && 916 - full_td(map_idx, st, &rsd)) { 917 - double be_bound = td_metric_ratio(map_idx, 918 - STAT_TOPDOWN_BE_BOUND, st, 919 - &rsd); 920 - if (be_bound > 0.2) 921 - color = PERF_COLOR_RED; 922 - print_metric(config, ctxp, color, "%8.1f%%", "Backend Bound", 923 - be_bound * 100.); 924 - } else if (perf_stat_evsel__is(evsel, TOPDOWN_BAD_SPEC) && 925 - full_td(map_idx, st, &rsd)) { 926 - double bad_spec = td_metric_ratio(map_idx, 927 - STAT_TOPDOWN_BAD_SPEC, st, 928 - &rsd); 929 - if (bad_spec > 0.1) 930 - color = PERF_COLOR_RED; 931 - print_metric(config, ctxp, color, "%8.1f%%", "Bad Speculation", 932 - bad_spec * 100.); 933 - } else if (perf_stat_evsel__is(evsel, TOPDOWN_HEAVY_OPS) && 934 - full_td(map_idx, st, &rsd) && (config->topdown_level > 1)) { 935 - double retiring = td_metric_ratio(map_idx, 936 - STAT_TOPDOWN_RETIRING, st, 937 - &rsd); 938 - double heavy_ops = td_metric_ratio(map_idx, 939 - STAT_TOPDOWN_HEAVY_OPS, st, 940 - &rsd); 941 - double light_ops = retiring - heavy_ops; 942 - 943 - if (retiring > 0.7 && heavy_ops > 0.1) 944 - color = PERF_COLOR_GREEN; 945 - print_metric(config, ctxp, color, "%8.1f%%", "Heavy Operations", 946 - heavy_ops * 100.); 947 - if (retiring > 0.7 && light_ops > 0.6) 948 - color = PERF_COLOR_GREEN; 949 - else 950 - color = NULL; 951 - print_metric(config, ctxp, color, "%8.1f%%", "Light Operations", 952 - light_ops * 100.); 953 - } else if (perf_stat_evsel__is(evsel, TOPDOWN_BR_MISPREDICT) && 954 - full_td(map_idx, st, &rsd) && (config->topdown_level > 1)) { 955 - double bad_spec = td_metric_ratio(map_idx, 956 - STAT_TOPDOWN_BAD_SPEC, st, 957 - &rsd); 958 - double br_mis = td_metric_ratio(map_idx, 959 - STAT_TOPDOWN_BR_MISPREDICT, st, 960 - &rsd); 961 - double m_clears = bad_spec - br_mis; 962 - 963 - if (bad_spec > 0.1 && br_mis > 0.05) 964 - color = PERF_COLOR_RED; 965 - print_metric(config, ctxp, color, "%8.1f%%", "Branch Mispredict", 966 - br_mis * 100.); 967 - if (bad_spec > 0.1 && m_clears > 0.05) 968 - color = PERF_COLOR_RED; 969 - else 970 - color = NULL; 971 - print_metric(config, ctxp, color, "%8.1f%%", "Machine Clears", 972 - m_clears * 100.); 973 - } else if (perf_stat_evsel__is(evsel, TOPDOWN_FETCH_LAT) && 974 - full_td(map_idx, st, &rsd) && (config->topdown_level > 1)) { 975 - double fe_bound = td_metric_ratio(map_idx, 976 - STAT_TOPDOWN_FE_BOUND, st, 977 - &rsd); 978 - double fetch_lat = td_metric_ratio(map_idx, 979 - STAT_TOPDOWN_FETCH_LAT, st, 980 - &rsd); 981 - double fetch_bw = fe_bound - fetch_lat; 982 - 983 - if (fe_bound > 0.2 && fetch_lat > 0.15) 984 - color = PERF_COLOR_RED; 985 - print_metric(config, ctxp, color, "%8.1f%%", "Fetch Latency", 986 - fetch_lat * 100.); 987 - if (fe_bound > 0.2 && fetch_bw > 0.1) 988 - color = PERF_COLOR_RED; 989 - else 990 - color = NULL; 991 - print_metric(config, ctxp, color, "%8.1f%%", "Fetch Bandwidth", 992 - fetch_bw * 100.); 993 - } else if (perf_stat_evsel__is(evsel, TOPDOWN_MEM_BOUND) && 994 - full_td(map_idx, st, &rsd) && (config->topdown_level > 1)) { 995 - double be_bound = td_metric_ratio(map_idx, 996 - STAT_TOPDOWN_BE_BOUND, st, 997 - &rsd); 998 - double mem_bound = td_metric_ratio(map_idx, 999 - STAT_TOPDOWN_MEM_BOUND, st, 1000 - &rsd); 1001 - double core_bound = be_bound - mem_bound; 1002 - 1003 - if (be_bound > 0.2 && mem_bound > 0.2) 1004 - color = PERF_COLOR_RED; 1005 - print_metric(config, ctxp, color, "%8.1f%%", "Memory Bound", 1006 - mem_bound * 100.); 1007 - if (be_bound > 0.2 && core_bound > 0.1) 1008 - color = PERF_COLOR_RED; 1009 - else 1010 - color = NULL; 1011 - print_metric(config, ctxp, color, "%8.1f%%", "Core Bound", 1012 - core_bound * 100.); 1013 1047 } else if (runtime_stat_n(st, STAT_NSECS, map_idx, &rsd) != 0) { 1014 1048 char unit = ' '; 1015 1049 char unit_buf[10] = "/sec";
-13
tools/perf/util/stat.c
··· 91 91 ID(TRANSACTION_START, cpu/tx-start/), 92 92 ID(ELISION_START, cpu/el-start/), 93 93 ID(CYCLES_IN_TX_CP, cpu/cycles-ct/), 94 - ID(TOPDOWN_TOTAL_SLOTS, topdown-total-slots), 95 - ID(TOPDOWN_SLOTS_ISSUED, topdown-slots-issued), 96 - ID(TOPDOWN_SLOTS_RETIRED, topdown-slots-retired), 97 - ID(TOPDOWN_FETCH_BUBBLES, topdown-fetch-bubbles), 98 - ID(TOPDOWN_RECOVERY_BUBBLES, topdown-recovery-bubbles), 99 - ID(TOPDOWN_RETIRING, topdown-retiring), 100 - ID(TOPDOWN_BAD_SPEC, topdown-bad-spec), 101 - ID(TOPDOWN_FE_BOUND, topdown-fe-bound), 102 - ID(TOPDOWN_BE_BOUND, topdown-be-bound), 103 - ID(TOPDOWN_HEAVY_OPS, topdown-heavy-ops), 104 - ID(TOPDOWN_BR_MISPREDICT, topdown-br-mispredict), 105 - ID(TOPDOWN_FETCH_LAT, topdown-fetch-lat), 106 - ID(TOPDOWN_MEM_BOUND, topdown-mem-bound), 107 94 ID(SMI_NUM, msr/smi/), 108 95 ID(APERF, msr/aperf/), 109 96 };
-26
tools/perf/util/stat.h
··· 25 25 PERF_STAT_EVSEL_ID__TRANSACTION_START, 26 26 PERF_STAT_EVSEL_ID__ELISION_START, 27 27 PERF_STAT_EVSEL_ID__CYCLES_IN_TX_CP, 28 - PERF_STAT_EVSEL_ID__TOPDOWN_TOTAL_SLOTS, 29 - PERF_STAT_EVSEL_ID__TOPDOWN_SLOTS_ISSUED, 30 - PERF_STAT_EVSEL_ID__TOPDOWN_SLOTS_RETIRED, 31 - PERF_STAT_EVSEL_ID__TOPDOWN_FETCH_BUBBLES, 32 - PERF_STAT_EVSEL_ID__TOPDOWN_RECOVERY_BUBBLES, 33 - PERF_STAT_EVSEL_ID__TOPDOWN_RETIRING, 34 - PERF_STAT_EVSEL_ID__TOPDOWN_BAD_SPEC, 35 - PERF_STAT_EVSEL_ID__TOPDOWN_FE_BOUND, 36 - PERF_STAT_EVSEL_ID__TOPDOWN_BE_BOUND, 37 - PERF_STAT_EVSEL_ID__TOPDOWN_HEAVY_OPS, 38 - PERF_STAT_EVSEL_ID__TOPDOWN_BR_MISPREDICT, 39 - PERF_STAT_EVSEL_ID__TOPDOWN_FETCH_LAT, 40 - PERF_STAT_EVSEL_ID__TOPDOWN_MEM_BOUND, 41 28 PERF_STAT_EVSEL_ID__SMI_NUM, 42 29 PERF_STAT_EVSEL_ID__APERF, 43 30 PERF_STAT_EVSEL_ID__MAX, ··· 95 108 STAT_CYCLES_IN_TX, 96 109 STAT_TRANSACTION, 97 110 STAT_ELISION, 98 - STAT_TOPDOWN_TOTAL_SLOTS, 99 - STAT_TOPDOWN_SLOTS_ISSUED, 100 - STAT_TOPDOWN_SLOTS_RETIRED, 101 - STAT_TOPDOWN_FETCH_BUBBLES, 102 - STAT_TOPDOWN_RECOVERY_BUBBLES, 103 - STAT_TOPDOWN_RETIRING, 104 - STAT_TOPDOWN_BAD_SPEC, 105 - STAT_TOPDOWN_FE_BOUND, 106 - STAT_TOPDOWN_BE_BOUND, 107 - STAT_TOPDOWN_HEAVY_OPS, 108 - STAT_TOPDOWN_BR_MISPREDICT, 109 - STAT_TOPDOWN_FETCH_LAT, 110 - STAT_TOPDOWN_MEM_BOUND, 111 111 STAT_SMI_NUM, 112 112 STAT_APERF, 113 113 STAT_MAX