The various filters must be specified as a comma separated list: --branch-filter any_ret,u,k
 Note that this feature may not be available on all processors.
 
+-W::
+--weight::
+Enable weightened sampling. An additional weight is recorded per sample and can be
+displayed with the weight and local_weight sort keys.  This currently works for TSX
+abort events and some memory events in precise mode on modern Intel CPUs.
+
 SEE ALSO
 --------
 linkperf:perf-stat[1], linkperf:perf-list[1]
 
 --sort=::
        Sort histogram entries by given key(s) - multiple keys can be specified
        in CSV format.  Following sort keys are available:
-       pid, comm, dso, symbol, parent, cpu, srcline.
+       pid, comm, dso, symbol, parent, cpu, srcline, weight, local_weight.
 
        Each key has following meaning:
 
 
 
 -s::
 --sort::
-       Sort by key(s): pid, comm, dso, symbol, parent, srcline.
+       Sort by key(s): pid, comm, dso, symbol, parent, srcline, weight, local_weight.
 
 -n::
 --show-nr-samples::
 
                return 0;
        }
 
-       he = __hists__add_entry(&evsel->hists, al, NULL, 1);
+       he = __hists__add_entry(&evsel->hists, al, NULL, 1, 1);
        if (he == NULL)
                return -ENOMEM;
 
 
 }
 
 static int hists__add_entry(struct hists *self,
-                           struct addr_location *al, u64 period)
+                           struct addr_location *al, u64 period,
+                           u64 weight)
 {
-       if (__hists__add_entry(self, al, NULL, period) != NULL)
+       if (__hists__add_entry(self, al, NULL, period, weight) != NULL)
                return 0;
        return -ENOMEM;
 }
        if (al.filtered)
                return 0;
 
-       if (hists__add_entry(&evsel->hists, &al, sample->period)) {
+       if (hists__add_entry(&evsel->hists, &al, sample->period, sample->weight)) {
                pr_warning("problem incrementing symbol period, skipping event\n");
                return -1;
        }
 
        OPT_CALLBACK('j', "branch-filter", &record.opts.branch_stack,
                     "branch filter mask", "branch stack filter modes",
                     parse_branch_stack),
+       OPT_BOOLEAN('W', "weight", &record.opts.sample_weight,
+                   "sample by weight (on special events only)"),
        OPT_END()
 };
 
 
                 * and not events sampled. Thus we use a pseudo period of 1.
                 */
                he = __hists__add_branch_entry(&evsel->hists, al, parent,
-                               &bi[i], 1);
+                               &bi[i], 1, 1);
                if (he) {
                        struct annotation *notes;
                        err = -ENOMEM;
                        return err;
        }
 
-       he = __hists__add_entry(&evsel->hists, al, parent, sample->period);
+       he = __hists__add_entry(&evsel->hists, al, parent, sample->period,
+                                       sample->weight);
        if (he == NULL)
                return -ENOMEM;
 
                    "Use the stdio interface"),
        OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
                   "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline,"
-                  " dso_to, dso_from, symbol_to, symbol_from, mispredict"),
+                  " dso_to, dso_from, symbol_to, symbol_from, mispredict,"
+                  " weight, local_weight"),
        OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,
                    "Show sample percentage for different cpu modes"),
        OPT_STRING('p', "parent", &parent_pattern, "regex",
 
 {
        struct hist_entry *he;
 
-       he = __hists__add_entry(&evsel->hists, al, NULL, sample->period);
+       he = __hists__add_entry(&evsel->hists, al, NULL, sample->period,
+                               sample->weight);
        if (he == NULL)
                return NULL;
 
        OPT_INCR('v', "verbose", &verbose,
                    "be more verbose (show counter open errors, etc)"),
        OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
-                  "sort by key(s): pid, comm, dso, symbol, parent"),
+                  "sort by key(s): pid, comm, dso, symbol, parent, weight, local_weight"),
        OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
                    "Show a column with the number of samples"),
        OPT_CALLBACK_DEFAULT('G', "call-graph", &top.record_opts,
 
        bool         pipe_output;
        bool         raw_samples;
        bool         sample_address;
+       bool         sample_weight;
        bool         sample_time;
        bool         period;
        unsigned int freq;
 
                                                          &sample, 0) < 0)
                                goto out;
 
-                       he = __hists__add_entry(&evsel->hists, &al, NULL, 1);
+                       he = __hists__add_entry(&evsel->hists, &al, NULL, 1, 1);
                        if (he == NULL)
                                goto out;
 
                                                          &sample, 0) < 0)
                                goto out;
 
-                       he = __hists__add_entry(&evsel->hists, &al, NULL, 1);
+                       he = __hists__add_entry(&evsel->hists, &al, NULL, 1, 1);
                        if (he == NULL)
                                goto out;
 
 
        u64 id;
        u64 stream_id;
        u64 period;
+       u64 weight;
        u32 cpu;
        u32 raw_size;
        void *raw_data;
 
                attr->branch_sample_type = opts->branch_stack;
        }
 
+       if (opts->sample_weight)
+               attr->sample_type       |= PERF_SAMPLE_WEIGHT;
+
        attr->mmap = track;
        attr->comm = track;
 
        data->cpu = data->pid = data->tid = -1;
        data->stream_id = data->id = data->time = -1ULL;
        data->period = 1;
+       data->weight = 0;
 
        if (event->header.type != PERF_RECORD_SAMPLE) {
                if (!evsel->attr.sample_id_all)
                }
        }
 
+       data->weight = 0;
+       if (type & PERF_SAMPLE_WEIGHT) {
+               data->weight = *array;
+               array++;
+       }
+
        return 0;
 }
 
 
        }
 }
 
-static void he_stat__add_period(struct he_stat *he_stat, u64 period)
+static void he_stat__add_period(struct he_stat *he_stat, u64 period,
+                               u64 weight)
 {
        he_stat->period         += period;
+       he_stat->weight         += weight;
        he_stat->nr_events      += 1;
 }
 
        dest->period_guest_sys  += src->period_guest_sys;
        dest->period_guest_us   += src->period_guest_us;
        dest->nr_events         += src->nr_events;
+       dest->weight            += src->weight;
 }
 
 static void hist_entry__decay(struct hist_entry *he)
 {
        he->stat.period = (he->stat.period * 7) / 8;
        he->stat.nr_events = (he->stat.nr_events * 7) / 8;
+       /* XXX need decay for weight too? */
 }
 
 static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
 static struct hist_entry *add_hist_entry(struct hists *hists,
                                      struct hist_entry *entry,
                                      struct addr_location *al,
-                                     u64 period)
+                                     u64 period,
+                                     u64 weight)
 {
        struct rb_node **p;
        struct rb_node *parent = NULL;
                cmp = hist_entry__cmp(he, entry);
 
                if (!cmp) {
-                       he_stat__add_period(&he->stat, period);
+                       he_stat__add_period(&he->stat, period, weight);
 
                        /* If the map of an existing hist_entry has
                         * become out-of-date due to an exec() or
                                             struct addr_location *al,
                                             struct symbol *sym_parent,
                                             struct branch_info *bi,
-                                            u64 period)
+                                            u64 period,
+                                            u64 weight)
 {
        struct hist_entry entry = {
                .thread = al->thread,
                .stat = {
                        .period = period,
                        .nr_events = 1,
+                       .weight = weight,
                },
                .parent = sym_parent,
                .filtered = symbol__parent_filter(sym_parent),
                .hists  = self,
        };
 
-       return add_hist_entry(self, &entry, al, period);
+       return add_hist_entry(self, &entry, al, period, weight);
 }
 
 struct hist_entry *__hists__add_entry(struct hists *self,
                                      struct addr_location *al,
-                                     struct symbol *sym_parent, u64 period)
+                                     struct symbol *sym_parent, u64 period,
+                                     u64 weight)
 {
        struct hist_entry entry = {
                .thread = al->thread,
                .stat = {
                        .period = period,
                        .nr_events = 1,
+                       .weight = weight,
                },
                .parent = sym_parent,
                .filtered = symbol__parent_filter(sym_parent),
                .hists  = self,
        };
 
-       return add_hist_entry(self, &entry, al, period);
+       return add_hist_entry(self, &entry, al, period, weight);
 }
 
 int64_t
 
        HISTC_DSO_FROM,
        HISTC_DSO_TO,
        HISTC_SRCLINE,
+       HISTC_LOCAL_WEIGHT,
+       HISTC_GLOBAL_WEIGHT,
        HISTC_NR_COLS, /* Last entry */
 };
 
 
 struct hist_entry *__hists__add_entry(struct hists *self,
                                      struct addr_location *al,
-                                     struct symbol *parent, u64 period);
+                                     struct symbol *parent, u64 period,
+                                     u64 weight);
 int64_t hist_entry__cmp(struct hist_entry *left, struct hist_entry *right);
 int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right);
 int hist_entry__sort_snprintf(struct hist_entry *self, char *bf, size_t size,
                                             struct addr_location *al,
                                             struct symbol *sym_parent,
                                             struct branch_info *bi,
-                                            u64 period);
+                                            u64 period,
+                                            u64 weight);
 
 void hists__output_resort(struct hists *self);
 void hists__output_resort_threaded(struct hists *hists);
 
 
        if (sample_type & PERF_SAMPLE_STACK_USER)
                stack_user__printf(&sample->user_stack);
+
+       if (sample_type & PERF_SAMPLE_WEIGHT)
+               printf("... weight: %" PRIu64 "\n", sample->weight);
 }
 
 static struct machine *
 
        .se_width_idx   = HISTC_MISPREDICT,
 };
 
+static u64 he_weight(struct hist_entry *he)
+{
+       return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0;
+}
+
+static int64_t
+sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right)
+{
+       return he_weight(left) - he_weight(right);
+}
+
+static int hist_entry__local_weight_snprintf(struct hist_entry *self, char *bf,
+                                   size_t size, unsigned int width)
+{
+       return repsep_snprintf(bf, size, "%-*llu", width, he_weight(self));
+}
+
+struct sort_entry sort_local_weight = {
+       .se_header      = "Local Weight",
+       .se_cmp         = sort__local_weight_cmp,
+       .se_snprintf    = hist_entry__local_weight_snprintf,
+       .se_width_idx   = HISTC_LOCAL_WEIGHT,
+};
+
+static int64_t
+sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right)
+{
+       return left->stat.weight - right->stat.weight;
+}
+
+static int hist_entry__global_weight_snprintf(struct hist_entry *self, char *bf,
+                                             size_t size, unsigned int width)
+{
+       return repsep_snprintf(bf, size, "%-*llu", width, self->stat.weight);
+}
+
+struct sort_entry sort_global_weight = {
+       .se_header      = "Weight",
+       .se_cmp         = sort__global_weight_cmp,
+       .se_snprintf    = hist_entry__global_weight_snprintf,
+       .se_width_idx   = HISTC_GLOBAL_WEIGHT,
+};
+
 struct sort_dimension {
        const char              *name;
        struct sort_entry       *entry;
        DIM(SORT_PARENT, "parent", sort_parent),
        DIM(SORT_CPU, "cpu", sort_cpu),
        DIM(SORT_SRCLINE, "srcline", sort_srcline),
+       DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
+       DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
 };
 
 #undef DIM
 
        u64                     period_us;
        u64                     period_guest_sys;
        u64                     period_guest_us;
+       u64                     weight;
        u32                     nr_events;
 };
 
        SORT_PARENT,
        SORT_CPU,
        SORT_SRCLINE,
+       SORT_LOCAL_WEIGHT,
+       SORT_GLOBAL_WEIGHT,
 
        /* branch stack specific sort keys */
        __SORT_BRANCH_STACK,