#include "evsel.h"
 #include "ui/browsers/hists.h"
 #include "thread.h"
+#include "mem2node.h"
 
 struct c2c_hists {
        struct hists            hists;
        struct c2c_hists        *hists;
        struct c2c_stats         stats;
        unsigned long           *cpuset;
+       unsigned long           *nodeset;
        struct c2c_stats        *node_stats;
        unsigned int             cacheline_idx;
 
         * because of its callchain dynamic entry
         */
        struct hist_entry       he;
+
+       unsigned long            paddr;
+       unsigned long            paddr_cnt;
+       bool                     paddr_zero;
+       char                    *nodestr;
 };
 
 static char const *coalesce_default = "pid,iaddr";
 struct perf_c2c {
        struct perf_tool        tool;
        struct c2c_hists        hists;
+       struct mem2node         mem2node;
 
        unsigned long           **nodes;
        int                      nodes_cnt;
        if (!c2c_he->cpuset)
                return NULL;
 
+       c2c_he->nodeset = bitmap_alloc(c2c.nodes_cnt);
+       if (!c2c_he->nodeset)
+               return NULL;
+
        c2c_he->node_stats = zalloc(c2c.nodes_cnt * sizeof(*c2c_he->node_stats));
        if (!c2c_he->node_stats)
                return NULL;
        }
 
        free(c2c_he->cpuset);
+       free(c2c_he->nodeset);
+       free(c2c_he->nodestr);
        free(c2c_he->node_stats);
        free(c2c_he);
 }
        set_bit(sample->cpu, c2c_he->cpuset);
 }
 
+static void c2c_he__set_node(struct c2c_hist_entry *c2c_he,
+                            struct perf_sample *sample)
+{
+       int node;
+
+       if (!sample->phys_addr) {
+               c2c_he->paddr_zero = true;
+               return;
+       }
+
+       node = mem2node__node(&c2c.mem2node, sample->phys_addr);
+       if (WARN_ONCE(node < 0, "WARNING: failed to find node\n"))
+               return;
+
+       set_bit(node, c2c_he->nodeset);
+
+       if (c2c_he->paddr != sample->phys_addr) {
+               c2c_he->paddr_cnt++;
+               c2c_he->paddr = sample->phys_addr;
+       }
+}
+
 static void compute_stats(struct c2c_hist_entry *c2c_he,
                          struct c2c_stats *stats,
                          u64 weight)
        c2c_add_stats(&c2c_hists->stats, &stats);
 
        c2c_he__set_cpu(c2c_he, sample);
+       c2c_he__set_node(c2c_he, sample);
 
        hists__inc_nr_samples(&c2c_hists->hists, he->filtered);
        ret = hist_entry__append_callchain(he, sample);
                compute_stats(c2c_he, &stats, sample->weight);
 
                c2c_he__set_cpu(c2c_he, sample);
+               c2c_he__set_node(c2c_he, sample);
 
                hists__inc_nr_samples(&c2c_hists->hists, he->filtered);
                ret = hist_entry__append_callchain(he, sample);
        return scnprintf(hpp->buf, hpp->size, "%*s", width, HEX_STR(buf, addr));
 }
 
+static int
+dcacheline_node_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
+                     struct hist_entry *he)
+{
+       struct c2c_hist_entry *c2c_he;
+       int width = c2c_width(fmt, hpp, he->hists);
+
+       c2c_he = container_of(he, struct c2c_hist_entry, he);
+       if (WARN_ON_ONCE(!c2c_he->nodestr))
+               return 0;
+
+       return scnprintf(hpp->buf, hpp->size, "%*s", width, c2c_he->nodestr);
+}
+
 static int offset_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
                        struct hist_entry *he)
 {
        .width          = 18,
 };
 
+static struct c2c_dimension dim_dcacheline_node = {
+       .header         = HEADER_LOW("Node"),
+       .name           = "dcacheline_node",
+       .cmp            = empty_cmp,
+       .entry          = dcacheline_node_entry,
+       .width          = 4,
+};
+
 static struct c2c_header header_offset_tui = HEADER_LOW("Off");
 
 static struct c2c_dimension dim_offset = {
        .width          = 18,
 };
 
+static struct c2c_dimension dim_offset_node = {
+       .header         = HEADER_LOW("Node"),
+       .name           = "offset_node",
+       .cmp            = empty_cmp,
+       .entry          = dcacheline_node_entry,
+       .width          = 4,
+};
+
 static struct c2c_dimension dim_iaddr = {
        .header         = HEADER_LOW("Code address"),
        .name           = "iaddr",
 
 static struct c2c_dimension *dimensions[] = {
        &dim_dcacheline,
+       &dim_dcacheline_node,
        &dim_offset,
+       &dim_offset_node,
        &dim_iaddr,
        &dim_tot_hitm,
        &dim_lcl_hitm,
        return has_hitm || c2c_he->stats.store;
 }
 
+static void set_node_width(struct c2c_hist_entry *c2c_he, int len)
+{
+       struct c2c_dimension *dim;
+
+       dim = &c2c.hists == c2c_he->hists ?
+             &dim_dcacheline_node : &dim_offset_node;
+
+       if (len > dim->width)
+               dim->width = len;
+}
+
+static int set_nodestr(struct c2c_hist_entry *c2c_he)
+{
+       char buf[30];
+       int len;
+
+       if (c2c_he->nodestr)
+               return 0;
+
+       if (bitmap_weight(c2c_he->nodeset, c2c.nodes_cnt)) {
+               len = bitmap_scnprintf(c2c_he->nodeset, c2c.nodes_cnt,
+                                     buf, sizeof(buf));
+       } else {
+               len = scnprintf(buf, sizeof(buf), "N/A");
+       }
+
+       set_node_width(c2c_he, len);
+       c2c_he->nodestr = strdup(buf);
+       return c2c_he->nodestr ? 0 : -ENOMEM;
+}
+
 static void calc_width(struct c2c_hist_entry *c2c_he)
 {
        struct c2c_hists *c2c_hists;
 
        c2c_hists = container_of(c2c_he->he.hists, struct c2c_hists, hists);
        hists__calc_col_len(&c2c_hists->hists, &c2c_he->he);
+       set_nodestr(c2c_he);
 }
 
 static int filter_cb(struct hist_entry *he)
                "percent_lcl_hitm,"
                "percent_stores_l1hit,"
                "percent_stores_l1miss,"
-               "offset,",
+               "offset,offset_node,",
                add_pid   ? "pid," : "",
                add_tid   ? "tid," : "",
                add_iaddr ? "iaddr," : "",
                goto out;
        }
 
-       err = setup_callchain(session->evlist);
+       err = mem2node__init(&c2c.mem2node, &session->header.env);
        if (err)
                goto out_session;
 
+       err = setup_callchain(session->evlist);
+       if (err)
+               goto out_mem2node;
+
        if (symbol__init(&session->header.env) < 0)
-               goto out_session;
+               goto out_mem2node;
 
        /* No pipe support at the moment. */
        if (perf_data__is_pipe(session->data)) {
                pr_debug("No pipe support at the moment.\n");
-               goto out_session;
+               goto out_mem2node;
        }
 
        if (c2c.use_stdio)
        err = perf_session__process_events(session);
        if (err) {
                pr_err("failed to process sample\n");
-               goto out_session;
+               goto out_mem2node;
        }
 
        c2c_hists__reinit(&c2c.hists,
                        "cl_idx,"
                        "dcacheline,"
+                       "dcacheline_node,"
                        "tot_recs,"
                        "percent_hitm,"
                        "tot_hitm,lcl_hitm,rmt_hitm,"
 
        perf_c2c_display(session);
 
+out_mem2node:
+       mem2node__exit(&c2c.mem2node);
 out_session:
        perf_session__delete(session);
 out: