NULL,
 };
 
+static const char *topdown_metric_L2_attrs[] = {
+       "slots",
+       "topdown-retiring",
+       "topdown-bad-spec",
+       "topdown-fe-bound",
+       "topdown-be-bound",
+       "topdown-heavy-ops",
+       "topdown-br-mispredict",
+       "topdown-fetch-lat",
+       "topdown-mem-bound",
+       NULL,
+};
+
 static const char *smi_cost_attrs = {
        "{"
        "msr/aperf/,"
        OPT_BOOLEAN(0, "metric-no-merge", &stat_config.metric_no_merge,
                       "don't try to share events between metrics in a group"),
        OPT_BOOLEAN(0, "topdown", &topdown_run,
-                       "measure topdown level 1 statistics"),
+                       "measure top-down statistics"),
+       OPT_UINTEGER(0, "td-level", &stat_config.topdown_level,
+                       "Set the metrics level for the top-down statistics (0: max level)"),
        OPT_BOOLEAN(0, "smi-cost", &smi_cost,
                        "measure SMI cost"),
        OPT_CALLBACK('M', "metrics", &evsel_list, "metric/metric group list",
        }
 
        if (topdown_run) {
+               const char **metric_attrs = topdown_metric_attrs;
+               unsigned int max_level = 1;
                char *str = NULL;
                bool warn = false;
 
                if (!force_metric_only)
                        stat_config.metric_only = true;
 
-               if (topdown_filter_events(topdown_metric_attrs, &str, 1) < 0) {
+               if (pmu_have_event("cpu", topdown_metric_L2_attrs[5])) {
+                       metric_attrs = topdown_metric_L2_attrs;
+                       max_level = 2;
+               }
+
+               if (stat_config.topdown_level > max_level) {
+                       pr_err("Invalid top-down metrics level. The max level is %u.\n", max_level);
+                       return -1;
+               } else if (!stat_config.topdown_level)
+                       stat_config.topdown_level = max_level;
+
+               if (topdown_filter_events(metric_attrs, &str, 1) < 0) {
                        pr_err("Out of memory\n");
                        return -1;
                }
-               if (topdown_metric_attrs[0] && str) {
+               if (metric_attrs[0] && str) {
                        if (!stat_config.interval && !stat_config.metric_only) {
                                fprintf(stat_config.output,
                                        "Topdown accuracy may decrease when measuring long periods.\n"
 
        else if (perf_stat_evsel__is(counter, TOPDOWN_BE_BOUND))
                update_runtime_stat(st, STAT_TOPDOWN_BE_BOUND,
                                    cpu, count, &rsd);
+       else if (perf_stat_evsel__is(counter, TOPDOWN_HEAVY_OPS))
+               update_runtime_stat(st, STAT_TOPDOWN_HEAVY_OPS,
+                                   cpu, count, &rsd);
+       else if (perf_stat_evsel__is(counter, TOPDOWN_BR_MISPREDICT))
+               update_runtime_stat(st, STAT_TOPDOWN_BR_MISPREDICT,
+                                   cpu, count, &rsd);
+       else if (perf_stat_evsel__is(counter, TOPDOWN_FETCH_LAT))
+               update_runtime_stat(st, STAT_TOPDOWN_FETCH_LAT,
+                                   cpu, count, &rsd);
+       else if (perf_stat_evsel__is(counter, TOPDOWN_MEM_BOUND))
+               update_runtime_stat(st, STAT_TOPDOWN_MEM_BOUND,
+                                   cpu, count, &rsd);
        else if (evsel__match(counter, HARDWARE, HW_STALLED_CYCLES_FRONTEND))
                update_runtime_stat(st, STAT_STALLED_CYCLES_FRONT,
                                    cpu, count, &rsd);
                        color = PERF_COLOR_RED;
                print_metric(config, ctxp, color, "%8.1f%%", "bad speculation",
                                bad_spec * 100.);
+       } else if (perf_stat_evsel__is(evsel, TOPDOWN_HEAVY_OPS) &&
+                       full_td(cpu, st, &rsd) && (config->topdown_level > 1)) {
+               double retiring = td_metric_ratio(cpu,
+                                                 STAT_TOPDOWN_RETIRING, st,
+                                                 &rsd);
+               double heavy_ops = td_metric_ratio(cpu,
+                                                  STAT_TOPDOWN_HEAVY_OPS, st,
+                                                  &rsd);
+               double light_ops = retiring - heavy_ops;
+
+               if (retiring > 0.7 && heavy_ops > 0.1)
+                       color = PERF_COLOR_GREEN;
+               print_metric(config, ctxp, color, "%8.1f%%", "heavy operations",
+                               heavy_ops * 100.);
+               if (retiring > 0.7 && light_ops > 0.6)
+                       color = PERF_COLOR_GREEN;
+               else
+                       color = NULL;
+               print_metric(config, ctxp, color, "%8.1f%%", "light operations",
+                               light_ops * 100.);
+       } else if (perf_stat_evsel__is(evsel, TOPDOWN_BR_MISPREDICT) &&
+                       full_td(cpu, st, &rsd) && (config->topdown_level > 1)) {
+               double bad_spec = td_metric_ratio(cpu,
+                                                 STAT_TOPDOWN_BAD_SPEC, st,
+                                                 &rsd);
+               double br_mis = td_metric_ratio(cpu,
+                                               STAT_TOPDOWN_BR_MISPREDICT, st,
+                                               &rsd);
+               double m_clears = bad_spec - br_mis;
+
+               if (bad_spec > 0.1 && br_mis > 0.05)
+                       color = PERF_COLOR_RED;
+               print_metric(config, ctxp, color, "%8.1f%%", "branch mispredict",
+                               br_mis * 100.);
+               if (bad_spec > 0.1 && m_clears > 0.05)
+                       color = PERF_COLOR_RED;
+               else
+                       color = NULL;
+               print_metric(config, ctxp, color, "%8.1f%%", "machine clears",
+                               m_clears * 100.);
+       } else if (perf_stat_evsel__is(evsel, TOPDOWN_FETCH_LAT) &&
+                       full_td(cpu, st, &rsd) && (config->topdown_level > 1)) {
+               double fe_bound = td_metric_ratio(cpu,
+                                                 STAT_TOPDOWN_FE_BOUND, st,
+                                                 &rsd);
+               double fetch_lat = td_metric_ratio(cpu,
+                                                  STAT_TOPDOWN_FETCH_LAT, st,
+                                                  &rsd);
+               double fetch_bw = fe_bound - fetch_lat;
+
+               if (fe_bound > 0.2 && fetch_lat > 0.15)
+                       color = PERF_COLOR_RED;
+               print_metric(config, ctxp, color, "%8.1f%%", "fetch latency",
+                               fetch_lat * 100.);
+               if (fe_bound > 0.2 && fetch_bw > 0.1)
+                       color = PERF_COLOR_RED;
+               else
+                       color = NULL;
+               print_metric(config, ctxp, color, "%8.1f%%", "fetch bandwidth",
+                               fetch_bw * 100.);
+       } else if (perf_stat_evsel__is(evsel, TOPDOWN_MEM_BOUND) &&
+                       full_td(cpu, st, &rsd) && (config->topdown_level > 1)) {
+               double be_bound = td_metric_ratio(cpu,
+                                                 STAT_TOPDOWN_BE_BOUND, st,
+                                                 &rsd);
+               double mem_bound = td_metric_ratio(cpu,
+                                                  STAT_TOPDOWN_MEM_BOUND, st,
+                                                  &rsd);
+               double core_bound = be_bound - mem_bound;
+
+               if (be_bound > 0.2 && mem_bound > 0.2)
+                       color = PERF_COLOR_RED;
+               print_metric(config, ctxp, color, "%8.1f%%", "memory bound",
+                               mem_bound * 100.);
+               if (be_bound > 0.2 && core_bound > 0.1)
+                       color = PERF_COLOR_RED;
+               else
+                       color = NULL;
+               print_metric(config, ctxp, color, "%8.1f%%", "Core bound",
+                               core_bound * 100.);
        } else if (evsel->metric_expr) {
                generic_metric(config, evsel->metric_expr, evsel->metric_events, NULL,
                                evsel->name, evsel->metric_name, NULL, 1, cpu, out, st);