[PATCH V3 2/3] perf,tools: store cpu socket_id and core_id in perf.date

From: Kan Liang
Date: Mon Aug 31 2015 - 14:37:25 EST


From: Kan Liang <kan.liang@xxxxxxxxx>

This patch stores cpu socket_id and core_id in perf.date, and read them
to perf_env in header process.
Although the changes modify the CPU_TOPOLOGY feature, the old perf still
can correctly read new perf.data. Because the new codes are added at the
end of the cpu_topology section. The old perf can ignore the extra data.
For reading old perf.data, new perf will error out and leave message in
debug mode. So the user can upgrade the perf accordingly.

Signed-off-by: Kan Liang <kan.liang@xxxxxxxxx>
---

Changes since V1:
- Store core_id and socket_id in perf.date

Changes since V2:
- Use funcitons in cpumap.c to get core_id and socket_id
- Modify changelog

tools/perf/util/header.c | 72 ++++++++++++++++++++++++++++++++++++++++++++---
tools/perf/util/header.h | 6 ++++
tools/perf/util/session.c | 1 +
3 files changed, 75 insertions(+), 4 deletions(-)

diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 4181454..a1451f3 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -441,10 +441,13 @@ static int write_cmdline(int fd, struct perf_header *h __maybe_unused,
"/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list"

struct cpu_topo {
+ u32 cpu_nr;
u32 core_sib;
u32 thread_sib;
char **core_siblings;
char **thread_siblings;
+ int *core_id;
+ int *phy_pkg_id;
};

static int build_cpu_topo(struct cpu_topo *tp, int cpu)
@@ -507,6 +510,9 @@ try_threads:
}
ret = 0;
done:
+ tp->core_id[cpu] = cpu_map__get_core_id(cpu);
+ tp->phy_pkg_id[cpu] = cpu_map__get_socket_id(cpu);
+
if(fp)
fclose(fp);
free(buf);
@@ -534,7 +540,7 @@ static struct cpu_topo *build_cpu_topology(void)
struct cpu_topo *tp;
void *addr;
u32 nr, i;
- size_t sz;
+ size_t sz, sz_id;
long ncpus;
int ret = -1;

@@ -545,17 +551,22 @@ static struct cpu_topo *build_cpu_topology(void)
nr = (u32)(ncpus & UINT_MAX);

sz = nr * sizeof(char *);
+ sz_id = nr * sizeof(int);

- addr = calloc(1, sizeof(*tp) + 2 * sz);
+ addr = calloc(1, sizeof(*tp) + 2 * sz + 2 * sz_id);
if (!addr)
return NULL;

tp = addr;
-
+ tp->cpu_nr = nr;
addr += sizeof(*tp);
tp->core_siblings = addr;
addr += sz;
tp->thread_siblings = addr;
+ addr += sz;
+ tp->core_id = addr;
+ addr += sz_id;
+ tp->phy_pkg_id = addr;

for (i = 0; i < nr; i++) {
ret = build_cpu_topo(tp, i);
@@ -598,6 +609,15 @@ static int write_cpu_topology(int fd, struct perf_header *h __maybe_unused,
if (ret < 0)
break;
}
+
+ for (i = 0; i < tp->cpu_nr; i++) {
+ ret = do_write(fd, &tp->core_id[i], sizeof(int));
+ if (ret < 0)
+ return ret;
+ ret = do_write(fd, &tp->phy_pkg_id[i], sizeof(int));
+ if (ret < 0)
+ return ret;
+ }
done:
free_cpu_topo(tp);
return ret;
@@ -938,6 +958,7 @@ static void print_cpu_topology(struct perf_header *ph, int fd __maybe_unused,
{
int nr, i;
char *str;
+ int cpu_nr = ph->env.nr_cpus_online;

nr = ph->env.nr_sibling_cores;
str = ph->env.sibling_cores;
@@ -954,6 +975,10 @@ static void print_cpu_topology(struct perf_header *ph, int fd __maybe_unused,
fprintf(fp, "# sibling threads : %s\n", str);
str += strlen(str) + 1;
}
+
+ for (i = 0; i < cpu_nr; i++)
+ fprintf(fp, "# CPU %d: Core ID %d, Socket ID %d\n", i,
+ ph->env.cpu[i].core_id, ph->env.cpu[i].socket_id);
}

static void free_event_desc(struct perf_evsel *events)
@@ -1590,10 +1615,15 @@ static int process_cpu_topology(struct perf_file_section *section __maybe_unused
u32 nr, i;
char *str;
struct strbuf sb;
+ int cpu_nr = ph->env.nr_cpus_online;
+
+ ph->env.cpu = calloc(cpu_nr, sizeof(*ph->env.cpu));
+ if (!ph->env.cpu)
+ return -1;

ret = readn(fd, &nr, sizeof(nr));
if (ret != sizeof(nr))
- return -1;
+ goto free_cpu;

if (ph->needs_swap)
nr = bswap_32(nr);
@@ -1631,10 +1661,44 @@ static int process_cpu_topology(struct perf_file_section *section __maybe_unused
free(str);
}
ph->env.sibling_threads = strbuf_detach(&sb, NULL);
+
+ for (i = 0; i < (u32)cpu_nr; i++) {
+ ret = readn(fd, &nr, sizeof(nr));
+ if (ret != sizeof(nr))
+ goto free_cpu;
+
+ if (ph->needs_swap)
+ nr = bswap_32(nr);
+
+ if (nr > (u32)cpu_nr) {
+ pr_debug("core_id number is too big."
+ "You may need to upgrade the perf tool.\n");
+ goto free_cpu;
+ }
+ ph->env.cpu[i].core_id = nr;
+
+ ret = readn(fd, &nr, sizeof(nr));
+ if (ret != sizeof(nr))
+ goto free_cpu;
+
+ if (ph->needs_swap)
+ nr = bswap_32(nr);
+
+ if (nr > (u32)cpu_nr) {
+ pr_debug("socket_id number is too big."
+ "You may need to upgrade the perf tool.\n");
+ goto free_cpu;
+ }
+
+ ph->env.cpu[i].socket_id = nr;
+ }
+
return 0;

error:
strbuf_release(&sb);
+free_cpu:
+ free(ph->env.cpu);
return -1;
}

diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 396e496..975d803 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -66,6 +66,11 @@ struct perf_header;
int perf_file_header__read(struct perf_file_header *header,
struct perf_header *ph, int fd);

+struct cpu_topology_map {
+ int socket_id;
+ int core_id;
+};
+
struct perf_env {
char *hostname;
char *os_release;
@@ -89,6 +94,7 @@ struct perf_env {
char *sibling_threads;
char *numa_nodes;
char *pmu_mappings;
+ struct cpu_topology_map *cpu;
};

struct perf_header {
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 8a4537e..61669be 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -185,6 +185,7 @@ static void perf_session_env__exit(struct perf_env *env)
zfree(&env->sibling_threads);
zfree(&env->numa_nodes);
zfree(&env->pmu_mappings);
+ zfree(&env->cpu);
}

void perf_session__delete(struct perf_session *session)
--
1.8.3.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/