Merge branch 'perf/hw_breakpoints' into perf/core
authorIngo Molnar <mingo@kernel.org>
Wed, 28 Jan 2015 14:48:59 +0000 (15:48 +0100)
committerIngo Molnar <mingo@kernel.org>
Wed, 28 Jan 2015 14:48:59 +0000 (15:48 +0100)
The new hw_breakpoint bits are now ready for v3.20, merge them
into the main branch, to avoid conflicts.

Conflicts:
tools/perf/Documentation/perf-record.txt

Signed-off-by: Ingo Molnar <mingo@kernel.org>
1  2 
arch/x86/include/asm/cpufeature.h
arch/x86/include/uapi/asm/msr-index.h
arch/x86/kernel/cpu/amd.c
tools/perf/Documentation/perf-record.txt
tools/perf/tests/parse-events.c
tools/perf/util/parse-events.c
tools/perf/util/parse-events.h

  #define X86_FEATURE_TOPOEXT   ( 6*32+22) /* topology extensions CPUID leafs */
  #define X86_FEATURE_PERFCTR_CORE ( 6*32+23) /* core performance counter extensions */
  #define X86_FEATURE_PERFCTR_NB  ( 6*32+24) /* NB performance counter extensions */
+ #define X86_FEATURE_BPEXT     (6*32+26) /* data breakpoint extension */
  #define X86_FEATURE_PERFCTR_L2        ( 6*32+28) /* L2 performance counter extensions */
  
  /*
  #define X86_FEATURE_DTHERM    ( 7*32+ 7) /* Digital Thermal Sensor */
  #define X86_FEATURE_HW_PSTATE ( 7*32+ 8) /* AMD HW-PState */
  #define X86_FEATURE_PROC_FEEDBACK ( 7*32+ 9) /* AMD ProcFeedbackInterface */
 +#define X86_FEATURE_HWP               ( 7*32+ 10) /* "hwp" Intel HWP */
 +#define X86_FEATURE_HWP_NOITFY        ( 7*32+ 11) /* Intel HWP_NOTIFY */
 +#define X86_FEATURE_HWP_ACT_WINDOW ( 7*32+ 12) /* Intel HWP_ACT_WINDOW */
 +#define X86_FEATURE_HWP_EPP   ( 7*32+13) /* Intel HWP_EPP */
 +#define X86_FEATURE_HWP_PKG_REQ ( 7*32+14) /* Intel HWP_PKG_REQ */
  
  /* Virtualization flags: Linux defined, word 8 */
  #define X86_FEATURE_TPR_SHADOW  ( 8*32+ 0) /* Intel TPR Shadow */
@@@ -388,6 -384,7 +389,7 @@@ extern const char * const x86_bug_flags
  #define cpu_has_cx16          boot_cpu_has(X86_FEATURE_CX16)
  #define cpu_has_eager_fpu     boot_cpu_has(X86_FEATURE_EAGER_FPU)
  #define cpu_has_topoext               boot_cpu_has(X86_FEATURE_TOPOEXT)
+ #define cpu_has_bpext         boot_cpu_has(X86_FEATURE_BPEXT)
  
  #if __GNUC__ >= 4
  extern void warn_pre_alternatives(void);
  #define MSR_CC6_DEMOTION_POLICY_CONFIG        0x00000668
  #define MSR_MC6_DEMOTION_POLICY_CONFIG        0x00000669
  
 +/* Hardware P state interface */
 +#define MSR_PPERF                     0x0000064e
 +#define MSR_PERF_LIMIT_REASONS                0x0000064f
 +#define MSR_PM_ENABLE                 0x00000770
 +#define MSR_HWP_CAPABILITIES          0x00000771
 +#define MSR_HWP_REQUEST_PKG           0x00000772
 +#define MSR_HWP_INTERRUPT             0x00000773
 +#define MSR_HWP_REQUEST               0x00000774
 +#define MSR_HWP_STATUS                        0x00000777
 +
 +/* CPUID.6.EAX */
 +#define HWP_BASE_BIT                  (1<<7)
 +#define HWP_NOTIFICATIONS_BIT         (1<<8)
 +#define HWP_ACTIVITY_WINDOW_BIT               (1<<9)
 +#define HWP_ENERGY_PERF_PREFERENCE_BIT        (1<<10)
 +#define HWP_PACKAGE_LEVEL_REQUEST_BIT (1<<11)
 +
 +/* IA32_HWP_CAPABILITIES */
 +#define HWP_HIGHEST_PERF(x)           (x & 0xff)
 +#define HWP_GUARANTEED_PERF(x)                ((x & (0xff << 8)) >>8)
 +#define HWP_MOSTEFFICIENT_PERF(x)     ((x & (0xff << 16)) >>16)
 +#define HWP_LOWEST_PERF(x)            ((x & (0xff << 24)) >>24)
 +
 +/* IA32_HWP_REQUEST */
 +#define HWP_MIN_PERF(x)               (x & 0xff)
 +#define HWP_MAX_PERF(x)               ((x & 0xff) << 8)
 +#define HWP_DESIRED_PERF(x)           ((x & 0xff) << 16)
 +#define HWP_ENERGY_PERF_PREFERENCE(x) ((x & 0xff) << 24)
 +#define HWP_ACTIVITY_WINDOW(x)                ((x & 0xff3) << 32)
 +#define HWP_PACKAGE_CONTROL(x)                ((x & 0x1) << 42)
 +
 +/* IA32_HWP_STATUS */
 +#define HWP_GUARANTEED_CHANGE(x)      (x & 0x1)
 +#define HWP_EXCURSION_TO_MINIMUM(x)   (x & 0x4)
 +
 +/* IA32_HWP_INTERRUPT */
 +#define HWP_CHANGE_TO_GUARANTEED_INT(x)       (x & 0x1)
 +#define HWP_EXCURSION_TO_MINIMUM_INT(x)       (x & 0x2)
 +
  #define MSR_AMD64_MC0_MASK            0xc0010044
  
  #define MSR_IA32_MCx_CTL(x)           (MSR_IA32_MC0_CTL + 4*(x))
  /* Fam 16h MSRs */
  #define MSR_F16H_L2I_PERF_CTL         0xc0010230
  #define MSR_F16H_L2I_PERF_CTR         0xc0010231
+ #define MSR_F16H_DR1_ADDR_MASK                0xc0011019
+ #define MSR_F16H_DR2_ADDR_MASK                0xc001101a
+ #define MSR_F16H_DR3_ADDR_MASK                0xc001101b
+ #define MSR_F16H_DR0_ADDR_MASK                0xc0011027
  
  /* Fam 15h MSRs */
  #define MSR_F15H_PERF_CTL             0xc0010200
  
  #define MSR_IA32_TEMPERATURE_TARGET   0x000001a2
  
 +#define MSR_MISC_PWR_MGMT             0x000001aa
 +
  #define MSR_IA32_ENERGY_PERF_BIAS     0x000001b0
  #define ENERGY_PERF_BIAS_PERFORMANCE  0
  #define ENERGY_PERF_BIAS_NORMAL               6
@@@ -566,17 -566,6 +566,17 @@@ static void init_amd_k8(struct cpuinfo_
  
        if (!c->x86_model_id[0])
                strcpy(c->x86_model_id, "Hammer");
 +
 +#ifdef CONFIG_SMP
 +      /*
 +       * Disable TLB flush filter by setting HWCR.FFDIS on K8
 +       * bit 6 of msr C001_0015
 +       *
 +       * Errata 63 for SH-B3 steppings
 +       * Errata 122 for all steppings (F+ have it disabled by default)
 +       */
 +      msr_set_bit(MSR_K7_HWCR, 6);
 +#endif
  }
  
  static void init_amd_gh(struct cpuinfo_x86 *c)
@@@ -647,6 -636,18 +647,6 @@@ static void init_amd(struct cpuinfo_x8
  {
        u32 dummy;
  
 -#ifdef CONFIG_SMP
 -      /*
 -       * Disable TLB flush filter by setting HWCR.FFDIS on K8
 -       * bit 6 of msr C001_0015
 -       *
 -       * Errata 63 for SH-B3 steppings
 -       * Errata 122 for all steppings (F+ have it disabled by default)
 -       */
 -      if (c->x86 == 0xf)
 -              msr_set_bit(MSR_K7_HWCR, 6);
 -#endif
 -
        early_init_amd(c);
  
        /*
@@@ -869,3 -870,22 +869,22 @@@ static bool cpu_has_amd_erratum(struct 
  
        return false;
  }
+ void set_dr_addr_mask(unsigned long mask, int dr)
+ {
+       if (!cpu_has_bpext)
+               return;
+       switch (dr) {
+       case 0:
+               wrmsr(MSR_F16H_DR0_ADDR_MASK, mask, 0);
+               break;
+       case 1:
+       case 2:
+       case 3:
+               wrmsr(MSR_F16H_DR1_ADDR_MASK - 1 + dr, mask, 0);
+               break;
+       default:
+               break;
+       }
+ }
@@@ -33,24 -33,15 +33,27 @@@ OPTION
          - a raw PMU event (eventsel+umask) in the form of rNNN where NNN is a
          hexadecimal event descriptor.
  
-         - a hardware breakpoint event in the form of '\mem:addr[:access]'
 +      - a symbolically formed PMU event like 'pmu/param1=0x3,param2/' where
 +        'param1', 'param2', etc are defined as formats for the PMU in
 +        /sys/bus/event_sources/devices/<pmu>/format/*.
 +
 +      - a symbolically formed event like 'pmu/config=M,config1=N,config3=K/'
 +
 +          where M, N, K are numbers (in decimal, hex, octal format). Acceptable
 +          values for each of 'config', 'config1' and 'config2' are defined by
 +          corresponding entries in /sys/bus/event_sources/devices/<pmu>/format/*
 +          param1 and param2 are defined as formats for the PMU in:
 +          /sys/bus/event_sources/devices/<pmu>/format/*
 +
+         - a hardware breakpoint event in the form of '\mem:addr[/len][:access]'
            where addr is the address in memory you want to break in.
            Access is the memory access type (read, write, execute) it can
-           be passed as follows: '\mem:addr[:[r][w][x]]'.
+           be passed as follows: '\mem:addr[:[r][w][x]]'. len is the range,
+           number of bytes from specified addr, which the breakpoint will cover.
            If you want to profile read-write accesses in 0x1000, just set
            'mem:0x1000:rw'.
+           If you want to profile write accesses in [0x1000~1008), just set
+           'mem:0x1000/8:w'.
  
  --filter=<filter>::
          Event filter.
@@@ -1145,6 -1145,49 +1145,49 @@@ static int test__pinned_group(struct pe
        return 0;
  }
  
+ static int test__checkevent_breakpoint_len(struct perf_evlist *evlist)
+ {
+       struct perf_evsel *evsel = perf_evlist__first(evlist);
+       TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+       TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type);
+       TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
+       TEST_ASSERT_VAL("wrong bp_type", (HW_BREAKPOINT_R | HW_BREAKPOINT_W) ==
+                                        evsel->attr.bp_type);
+       TEST_ASSERT_VAL("wrong bp_len", HW_BREAKPOINT_LEN_1 ==
+                                       evsel->attr.bp_len);
+       return 0;
+ }
+ static int test__checkevent_breakpoint_len_w(struct perf_evlist *evlist)
+ {
+       struct perf_evsel *evsel = perf_evlist__first(evlist);
+       TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+       TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type);
+       TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
+       TEST_ASSERT_VAL("wrong bp_type", HW_BREAKPOINT_W ==
+                                        evsel->attr.bp_type);
+       TEST_ASSERT_VAL("wrong bp_len", HW_BREAKPOINT_LEN_2 ==
+                                       evsel->attr.bp_len);
+       return 0;
+ }
+ static int
+ test__checkevent_breakpoint_len_rw_modifier(struct perf_evlist *evlist)
+ {
+       struct perf_evsel *evsel = perf_evlist__first(evlist);
+       TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+       TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
+       TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+       TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+       return test__checkevent_breakpoint_rw(evlist);
+ }
  static int count_tracepoints(void)
  {
        char events_path[PATH_MAX];
@@@ -1420,6 -1463,21 +1463,21 @@@ static struct evlist_test test__events[
                .check = test__pinned_group,
                .id    = 41,
        },
+       {
+               .name  = "mem:0/1",
+               .check = test__checkevent_breakpoint_len,
+               .id    = 42,
+       },
+       {
+               .name  = "mem:0/2:w",
+               .check = test__checkevent_breakpoint_len_w,
+               .id    = 43,
+       },
+       {
+               .name  = "mem:0/4:rw:u",
+               .check = test__checkevent_breakpoint_len_rw_modifier,
+               .id    = 44
+       },
  #if defined(__s390x__)
        {
                .name  = "kvm-s390:kvm_s390_create_vm",
@@@ -1471,7 -1529,7 +1529,7 @@@ static int test_event(struct evlist_tes
        } else {
                ret = e->check(evlist);
        }
 -      
 +
        perf_evlist__delete(evlist);
  
        return ret;
@@@ -526,7 -526,7 +526,7 @@@ do {                                       
  }
  
  int parse_events_add_breakpoint(struct list_head *list, int *idx,
-                               void *ptr, char *type)
+                               void *ptr, char *type, u64 len)
  {
        struct perf_event_attr attr;
  
        if (parse_breakpoint_type(type, &attr))
                return -EINVAL;
  
-       /*
-        * We should find a nice way to override the access length
-        * Provide some defaults for now
-        */
-       if (attr.bp_type == HW_BREAKPOINT_X)
-               attr.bp_len = sizeof(long);
-       else
-               attr.bp_len = HW_BREAKPOINT_LEN_4;
+       /* Provide some defaults if len is not specified */
+       if (!len) {
+               if (attr.bp_type == HW_BREAKPOINT_X)
+                       len = sizeof(long);
+               else
+                       len = HW_BREAKPOINT_LEN_4;
+       }
+       attr.bp_len = len;
  
        attr.type = PERF_TYPE_BREAKPOINT;
        attr.sample_period = 1;
@@@ -681,8 -682,6 +682,8 @@@ int parse_events_add_pmu(struct list_he
        if (evsel) {
                evsel->unit = info.unit;
                evsel->scale = info.scale;
 +              evsel->per_pkg = info.per_pkg;
 +              evsel->snapshot = info.snapshot;
        }
  
        return evsel ? 0 : -ENOMEM;
@@@ -1121,7 -1120,7 +1122,7 @@@ void print_tracepoint_events(const cha
                return;
  
        for_each_subsystem(sys_dir, sys_dirent, sys_next) {
 -              if (subsys_glob != NULL && 
 +              if (subsys_glob != NULL &&
                    !strglobmatch(sys_dirent.d_name, subsys_glob))
                        continue;
  
                        continue;
  
                for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) {
 -                      if (event_glob != NULL && 
 +                      if (event_glob != NULL &&
                            !strglobmatch(evt_dirent.d_name, event_glob))
                                continue;
  
@@@ -1305,7 -1304,7 +1306,7 @@@ static void print_symbol_events(const c
  
        for (i = 0; i < max; i++, syms++) {
  
 -              if (event_glob != NULL && 
 +              if (event_glob != NULL &&
                    !(strglobmatch(syms->symbol, event_glob) ||
                      (syms->alias && strglobmatch(syms->alias, event_glob))))
                        continue;
@@@ -1366,7 -1365,7 +1367,7 @@@ void print_events(const char *event_glo
                printf("\n");
  
                printf("  %-50s [%s]\n",
-                      "mem:<addr>[:access]",
+                      "mem:<addr>[/len][:access]",
                        event_type_descriptors[PERF_TYPE_BREAKPOINT]);
                printf("\n");
        }
@@@ -71,7 -71,6 +71,7 @@@ struct parse_events_term 
        int type_val;
        int type_term;
        struct list_head list;
 +      bool used;
  };
  
  struct parse_events_evlist {
@@@ -105,7 -104,7 +105,7 @@@ int parse_events_add_numeric(struct lis
  int parse_events_add_cache(struct list_head *list, int *idx,
                           char *type, char *op_result1, char *op_result2);
  int parse_events_add_breakpoint(struct list_head *list, int *idx,
-                               void *ptr, char *type);
+                               void *ptr, char *type, u64 len);
  int parse_events_add_pmu(struct list_head *list, int *idx,
                         char *pmu , struct list_head *head_config);
  enum perf_pmu_event_symbol_type