perf/core improvements and refactorings:
Infrastructure: - Reference count the cpu_map and thread_map classes. (Jiri Olsa) - Set evsel->{cpus,threads} from the evlist, if not set, allowing the generalization of some 'perf stat' functions that previously were accessing private static evlist variable. (Jiri Olsa) - Delete an unnecessary check before the calling free_event_desc() (Markus Elfring) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJVjG3ZAAoJENZQFvNTUqpA4GAP/2BY9VIQM4d83V5tzZ9NFe3w vhUTQxRRTl4y2oYKsbYdI+EfbiVlH+vjNzbqzfUfsqCYzj4mLh+2Qpny+O71up2c ybIrm3vexc/yn4i/DpJeE1Vn/KtXCsv7LNNvEJWv8GR+dMRASYb8EFNO5zhyBNjA su2kskJ2/a9cmW6IOJKjkyjU025ZMWM73vX+IrvTknEYfQNMt9RzoC7GYjYgho/6 Dc+IyZW00vHR9FOezg0DKf0T4eSR4NWixnDnSiTEL+y+CUylO5peVzSgoobPlyIR uec6RH/PpRZg4tkUOSROMGjNskpzh8RcoYSz7A1VkVjWBM8XIFrW1w4Jwm/XQry1 A/xVC1XXPMGqQgdfsBvIIa81YXwVR/eqWDq3exuoCQKtvOR4PVVZ6FEgs6TCsnGY ZDNva6DfXPCxtlln/AWUffwwv2bNEumrM/p/ZYKXsb8skGvW0E5V+oU/lx9m854G kVOYHf12W2VYZFor8ZIpxyEiCswswVXgivDAxYI0tHODh9N2ZoON26WB1zzSAdmp KY2wswOOCa/LeuvENSn98WA+6jAUKrgyCGZMGVRuAotKjvKav4ThcHsKkgbxxXXV 1W26BYV0lILdcGxesNr0Lih52ifln0DqzH6q3zLwIUdZb/TZ2fS95mmWVdJ1KRHs dd2bKoBn9NhtRjLGw/eE =ztqK -----END PGP SIGNATURE----- Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/urgent Pull perf/core improvements and refactorings from Arnaldo Carvalho de Melo: Infrastructure changes: - Reference count the cpu_map and thread_map classes. (Jiri Olsa) - Set evsel->{cpus,threads} from the evlist, if not set, allowing the generalization of some 'perf stat' functions that previously were accessing private static evlist variable. (Jiri Olsa) - Delete an unnecessary check before the calling free_event_desc() (Markus Elfring) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
commit
6eedf41642
|
@ -141,16 +141,6 @@ static inline void diff_timespec(struct timespec *r, struct timespec *a,
|
|||
}
|
||||
}
|
||||
|
||||
static inline struct cpu_map *perf_evsel__cpus(struct perf_evsel *evsel)
|
||||
{
|
||||
return (evsel->cpus && !target.cpu_list) ? evsel->cpus : evsel_list->cpus;
|
||||
}
|
||||
|
||||
static inline int perf_evsel__nr_cpus(struct perf_evsel *evsel)
|
||||
{
|
||||
return perf_evsel__cpus(evsel)->nr;
|
||||
}
|
||||
|
||||
static void perf_evsel__reset_stat_priv(struct perf_evsel *evsel)
|
||||
{
|
||||
int i;
|
||||
|
|
|
@ -545,8 +545,8 @@ out_err:
|
|||
if (evlist) {
|
||||
perf_evlist__delete(evlist);
|
||||
} else {
|
||||
cpu_map__delete(cpus);
|
||||
thread_map__delete(threads);
|
||||
cpu_map__put(cpus);
|
||||
thread_map__put(threads);
|
||||
}
|
||||
machines__destroy_kernel_maps(&machines);
|
||||
machine__delete_threads(machine);
|
||||
|
|
|
@ -144,8 +144,8 @@ out_err:
|
|||
perf_evlist__disable(evlist);
|
||||
perf_evlist__delete(evlist);
|
||||
} else {
|
||||
cpu_map__delete(cpus);
|
||||
thread_map__delete(threads);
|
||||
cpu_map__put(cpus);
|
||||
thread_map__put(threads);
|
||||
}
|
||||
|
||||
return err;
|
||||
|
|
|
@ -140,8 +140,8 @@ out_delete_evlist:
|
|||
cpus = NULL;
|
||||
threads = NULL;
|
||||
out_free_cpus:
|
||||
cpu_map__delete(cpus);
|
||||
cpu_map__put(cpus);
|
||||
out_free_threads:
|
||||
thread_map__delete(threads);
|
||||
thread_map__put(threads);
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -143,7 +143,7 @@ static int synth_process(struct machine *machine)
|
|||
perf_event__process,
|
||||
machine, 0, 500);
|
||||
|
||||
thread_map__delete(map);
|
||||
thread_map__put(map);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
@ -111,6 +111,6 @@ out_close_fd:
|
|||
out_evsel_delete:
|
||||
perf_evsel__delete(evsel);
|
||||
out_thread_map_delete:
|
||||
thread_map__delete(threads);
|
||||
thread_map__put(threads);
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -56,6 +56,6 @@ out_close_fd:
|
|||
out_evsel_delete:
|
||||
perf_evsel__delete(evsel);
|
||||
out_thread_map_delete:
|
||||
thread_map__delete(threads);
|
||||
thread_map__put(threads);
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -560,8 +560,8 @@ out:
|
|||
perf_evlist__disable(evlist);
|
||||
perf_evlist__delete(evlist);
|
||||
} else {
|
||||
cpu_map__delete(cpus);
|
||||
thread_map__delete(threads);
|
||||
cpu_map__put(cpus);
|
||||
thread_map__put(threads);
|
||||
}
|
||||
|
||||
return err;
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "asm/bug.h"
|
||||
|
||||
static struct cpu_map *cpu_map__default_new(void)
|
||||
{
|
||||
|
@ -22,6 +23,7 @@ static struct cpu_map *cpu_map__default_new(void)
|
|||
cpus->map[i] = i;
|
||||
|
||||
cpus->nr = nr_cpus;
|
||||
atomic_set(&cpus->refcnt, 1);
|
||||
}
|
||||
|
||||
return cpus;
|
||||
|
@ -35,6 +37,7 @@ static struct cpu_map *cpu_map__trim_new(int nr_cpus, int *tmp_cpus)
|
|||
if (cpus != NULL) {
|
||||
cpus->nr = nr_cpus;
|
||||
memcpy(cpus->map, tmp_cpus, payload_size);
|
||||
atomic_set(&cpus->refcnt, 1);
|
||||
}
|
||||
|
||||
return cpus;
|
||||
|
@ -194,14 +197,32 @@ struct cpu_map *cpu_map__dummy_new(void)
|
|||
if (cpus != NULL) {
|
||||
cpus->nr = 1;
|
||||
cpus->map[0] = -1;
|
||||
atomic_set(&cpus->refcnt, 1);
|
||||
}
|
||||
|
||||
return cpus;
|
||||
}
|
||||
|
||||
void cpu_map__delete(struct cpu_map *map)
|
||||
static void cpu_map__delete(struct cpu_map *map)
|
||||
{
|
||||
free(map);
|
||||
if (map) {
|
||||
WARN_ONCE(atomic_read(&map->refcnt) != 0,
|
||||
"cpu_map refcnt unbalanced\n");
|
||||
free(map);
|
||||
}
|
||||
}
|
||||
|
||||
struct cpu_map *cpu_map__get(struct cpu_map *map)
|
||||
{
|
||||
if (map)
|
||||
atomic_inc(&map->refcnt);
|
||||
return map;
|
||||
}
|
||||
|
||||
void cpu_map__put(struct cpu_map *map)
|
||||
{
|
||||
if (map && atomic_dec_and_test(&map->refcnt))
|
||||
cpu_map__delete(map);
|
||||
}
|
||||
|
||||
int cpu_map__get_socket(struct cpu_map *map, int idx)
|
||||
|
@ -263,6 +284,7 @@ static int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res,
|
|||
/* ensure we process id in increasing order */
|
||||
qsort(c->map, c->nr, sizeof(int), cmp_ids);
|
||||
|
||||
atomic_set(&cpus->refcnt, 1);
|
||||
*res = c;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -3,18 +3,19 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <linux/atomic.h>
|
||||
|
||||
#include "perf.h"
|
||||
#include "util/debug.h"
|
||||
|
||||
struct cpu_map {
|
||||
atomic_t refcnt;
|
||||
int nr;
|
||||
int map[];
|
||||
};
|
||||
|
||||
struct cpu_map *cpu_map__new(const char *cpu_list);
|
||||
struct cpu_map *cpu_map__dummy_new(void);
|
||||
void cpu_map__delete(struct cpu_map *map);
|
||||
struct cpu_map *cpu_map__read(FILE *file);
|
||||
size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp);
|
||||
int cpu_map__get_socket(struct cpu_map *map, int idx);
|
||||
|
@ -22,6 +23,9 @@ int cpu_map__get_core(struct cpu_map *map, int idx);
|
|||
int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp);
|
||||
int cpu_map__build_core_map(struct cpu_map *cpus, struct cpu_map **corep);
|
||||
|
||||
struct cpu_map *cpu_map__get(struct cpu_map *map);
|
||||
void cpu_map__put(struct cpu_map *map);
|
||||
|
||||
static inline int cpu_map__socket(struct cpu_map *sock, int s)
|
||||
{
|
||||
if (!sock || s > sock->nr || s < 0)
|
||||
|
|
|
@ -114,8 +114,8 @@ void perf_evlist__delete(struct perf_evlist *evlist)
|
|||
{
|
||||
perf_evlist__munmap(evlist);
|
||||
perf_evlist__close(evlist);
|
||||
cpu_map__delete(evlist->cpus);
|
||||
thread_map__delete(evlist->threads);
|
||||
cpu_map__put(evlist->cpus);
|
||||
thread_map__put(evlist->threads);
|
||||
evlist->cpus = NULL;
|
||||
evlist->threads = NULL;
|
||||
perf_evlist__purge(evlist);
|
||||
|
@ -1101,6 +1101,31 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
|
|||
return perf_evlist__mmap_ex(evlist, pages, overwrite, 0, false);
|
||||
}
|
||||
|
||||
static int perf_evlist__propagate_maps(struct perf_evlist *evlist,
|
||||
struct target *target)
|
||||
{
|
||||
struct perf_evsel *evsel;
|
||||
|
||||
evlist__for_each(evlist, evsel) {
|
||||
/*
|
||||
* We already have cpus for evsel (via PMU sysfs) so
|
||||
* keep it, if there's no target cpu list defined.
|
||||
*/
|
||||
if (evsel->cpus && target->cpu_list)
|
||||
cpu_map__put(evsel->cpus);
|
||||
|
||||
if (!evsel->cpus || target->cpu_list)
|
||||
evsel->cpus = cpu_map__get(evlist->cpus);
|
||||
|
||||
evsel->threads = thread_map__get(evlist->threads);
|
||||
|
||||
if (!evsel->cpus || !evsel->threads)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target)
|
||||
{
|
||||
evlist->threads = thread_map__new_str(target->pid, target->tid,
|
||||
|
@ -1117,10 +1142,10 @@ int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target)
|
|||
if (evlist->cpus == NULL)
|
||||
goto out_delete_threads;
|
||||
|
||||
return 0;
|
||||
return perf_evlist__propagate_maps(evlist, target);
|
||||
|
||||
out_delete_threads:
|
||||
thread_map__delete(evlist->threads);
|
||||
thread_map__put(evlist->threads);
|
||||
evlist->threads = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
@ -1353,7 +1378,7 @@ static int perf_evlist__create_syswide_maps(struct perf_evlist *evlist)
|
|||
out:
|
||||
return err;
|
||||
out_free_cpus:
|
||||
cpu_map__delete(evlist->cpus);
|
||||
cpu_map__put(evlist->cpus);
|
||||
evlist->cpus = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
|
|
@ -885,6 +885,8 @@ void perf_evsel__exit(struct perf_evsel *evsel)
|
|||
perf_evsel__free_fd(evsel);
|
||||
perf_evsel__free_id(evsel);
|
||||
close_cgroup(evsel->cgrp);
|
||||
cpu_map__put(evsel->cpus);
|
||||
thread_map__put(evsel->threads);
|
||||
zfree(&evsel->group_name);
|
||||
zfree(&evsel->name);
|
||||
perf_evsel__object.fini(evsel);
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <linux/types.h>
|
||||
#include "xyarray.h"
|
||||
#include "symbol.h"
|
||||
#include "cpumap.h"
|
||||
|
||||
struct perf_counts_values {
|
||||
union {
|
||||
|
@ -82,6 +83,7 @@ struct perf_evsel {
|
|||
struct cgroup_sel *cgrp;
|
||||
void *handler;
|
||||
struct cpu_map *cpus;
|
||||
struct thread_map *threads;
|
||||
unsigned int sample_size;
|
||||
int id_pos;
|
||||
int is_pos;
|
||||
|
@ -113,6 +115,16 @@ struct thread_map;
|
|||
struct perf_evlist;
|
||||
struct record_opts;
|
||||
|
||||
static inline struct cpu_map *perf_evsel__cpus(struct perf_evsel *evsel)
|
||||
{
|
||||
return evsel->cpus;
|
||||
}
|
||||
|
||||
static inline int perf_evsel__nr_cpus(struct perf_evsel *evsel)
|
||||
{
|
||||
return perf_evsel__cpus(evsel)->nr;
|
||||
}
|
||||
|
||||
void perf_counts_values__scale(struct perf_counts_values *count,
|
||||
bool scale, s8 *pscaled);
|
||||
|
||||
|
|
|
@ -1063,8 +1063,7 @@ out:
|
|||
free(buf);
|
||||
return events;
|
||||
error:
|
||||
if (events)
|
||||
free_event_desc(events);
|
||||
free_event_desc(events);
|
||||
events = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "parse-events-flex.h"
|
||||
#include "pmu.h"
|
||||
#include "thread_map.h"
|
||||
#include "cpumap.h"
|
||||
#include "asm/bug.h"
|
||||
|
||||
#define MAX_NAME_LEN 100
|
||||
|
@ -285,7 +286,9 @@ __add_event(struct list_head *list, int *idx,
|
|||
if (!evsel)
|
||||
return NULL;
|
||||
|
||||
evsel->cpus = cpus;
|
||||
if (cpus)
|
||||
evsel->cpus = cpu_map__get(cpus);
|
||||
|
||||
if (name)
|
||||
evsel->name = strdup(name);
|
||||
list_add_tail(&evsel->node, list);
|
||||
|
|
|
@ -384,7 +384,7 @@ static int pyrf_cpu_map__init(struct pyrf_cpu_map *pcpus,
|
|||
|
||||
static void pyrf_cpu_map__delete(struct pyrf_cpu_map *pcpus)
|
||||
{
|
||||
cpu_map__delete(pcpus->cpus);
|
||||
cpu_map__put(pcpus->cpus);
|
||||
pcpus->ob_type->tp_free((PyObject*)pcpus);
|
||||
}
|
||||
|
||||
|
@ -453,7 +453,7 @@ static int pyrf_thread_map__init(struct pyrf_thread_map *pthreads,
|
|||
|
||||
static void pyrf_thread_map__delete(struct pyrf_thread_map *pthreads)
|
||||
{
|
||||
thread_map__delete(pthreads->threads);
|
||||
thread_map__put(pthreads->threads);
|
||||
pthreads->ob_type->tp_free((PyObject*)pthreads);
|
||||
}
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ static bool perf_probe_api(setup_probe_fn_t fn)
|
|||
if (!cpus)
|
||||
return false;
|
||||
cpu = cpus->map[0];
|
||||
cpu_map__delete(cpus);
|
||||
cpu_map__put(cpus);
|
||||
|
||||
do {
|
||||
ret = perf_do_probe_api(fn, cpu, try[i++]);
|
||||
|
@ -226,7 +226,7 @@ bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str)
|
|||
struct cpu_map *cpus = cpu_map__new(NULL);
|
||||
|
||||
cpu = cpus ? cpus->map[0] : 0;
|
||||
cpu_map__delete(cpus);
|
||||
cpu_map__put(cpus);
|
||||
} else {
|
||||
cpu = evlist->cpus->map[0];
|
||||
}
|
||||
|
|
|
@ -1895,7 +1895,7 @@ int perf_session__cpu_bitmap(struct perf_session *session,
|
|||
err = 0;
|
||||
|
||||
out_delete_map:
|
||||
cpu_map__delete(map);
|
||||
cpu_map__put(map);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
@ -748,7 +748,7 @@ static int str_to_bitmap(char *s, cpumask_t *b)
|
|||
set_bit(c, cpumask_bits(b));
|
||||
}
|
||||
|
||||
cpu_map__delete(m);
|
||||
cpu_map__put(m);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <unistd.h>
|
||||
#include "strlist.h"
|
||||
#include <string.h>
|
||||
#include "asm/bug.h"
|
||||
#include "thread_map.h"
|
||||
#include "util.h"
|
||||
|
||||
|
@ -22,7 +23,7 @@ static int filter(const struct dirent *dir)
|
|||
|
||||
static struct thread_map *thread_map__realloc(struct thread_map *map, int nr)
|
||||
{
|
||||
size_t size = sizeof(*map) + sizeof(pid_t) * nr;
|
||||
size_t size = sizeof(*map) + sizeof(map->map[0]) * nr;
|
||||
|
||||
return realloc(map, size);
|
||||
}
|
||||
|
@ -47,6 +48,7 @@ struct thread_map *thread_map__new_by_pid(pid_t pid)
|
|||
for (i = 0; i < items; i++)
|
||||
thread_map__set_pid(threads, i, atoi(namelist[i]->d_name));
|
||||
threads->nr = items;
|
||||
atomic_set(&threads->refcnt, 1);
|
||||
}
|
||||
|
||||
for (i=0; i<items; i++)
|
||||
|
@ -63,6 +65,7 @@ struct thread_map *thread_map__new_by_tid(pid_t tid)
|
|||
if (threads != NULL) {
|
||||
thread_map__set_pid(threads, 0, tid);
|
||||
threads->nr = 1;
|
||||
atomic_set(&threads->refcnt, 1);
|
||||
}
|
||||
|
||||
return threads;
|
||||
|
@ -84,6 +87,7 @@ struct thread_map *thread_map__new_by_uid(uid_t uid)
|
|||
goto out_free_threads;
|
||||
|
||||
threads->nr = 0;
|
||||
atomic_set(&threads->refcnt, 1);
|
||||
|
||||
while (!readdir_r(proc, &dirent, &next) && next) {
|
||||
char *end;
|
||||
|
@ -212,6 +216,8 @@ static struct thread_map *thread_map__new_by_pid_str(const char *pid_str)
|
|||
|
||||
out:
|
||||
strlist__delete(slist);
|
||||
if (threads)
|
||||
atomic_set(&threads->refcnt, 1);
|
||||
return threads;
|
||||
|
||||
out_free_namelist:
|
||||
|
@ -231,6 +237,7 @@ struct thread_map *thread_map__new_dummy(void)
|
|||
if (threads != NULL) {
|
||||
thread_map__set_pid(threads, 0, -1);
|
||||
threads->nr = 1;
|
||||
atomic_set(&threads->refcnt, 1);
|
||||
}
|
||||
return threads;
|
||||
}
|
||||
|
@ -273,6 +280,8 @@ static struct thread_map *thread_map__new_by_tid_str(const char *tid_str)
|
|||
threads->nr = ntasks;
|
||||
}
|
||||
out:
|
||||
if (threads)
|
||||
atomic_set(&threads->refcnt, 1);
|
||||
return threads;
|
||||
|
||||
out_free_threads:
|
||||
|
@ -292,9 +301,26 @@ struct thread_map *thread_map__new_str(const char *pid, const char *tid,
|
|||
return thread_map__new_by_tid_str(tid);
|
||||
}
|
||||
|
||||
void thread_map__delete(struct thread_map *threads)
|
||||
static void thread_map__delete(struct thread_map *threads)
|
||||
{
|
||||
free(threads);
|
||||
if (threads) {
|
||||
WARN_ONCE(atomic_read(&threads->refcnt) != 0,
|
||||
"thread map refcnt unbalanced\n");
|
||||
free(threads);
|
||||
}
|
||||
}
|
||||
|
||||
struct thread_map *thread_map__get(struct thread_map *map)
|
||||
{
|
||||
if (map)
|
||||
atomic_inc(&map->refcnt);
|
||||
return map;
|
||||
}
|
||||
|
||||
void thread_map__put(struct thread_map *map)
|
||||
{
|
||||
if (map && atomic_dec_and_test(&map->refcnt))
|
||||
thread_map__delete(map);
|
||||
}
|
||||
|
||||
size_t thread_map__fprintf(struct thread_map *threads, FILE *fp)
|
||||
|
|
|
@ -3,12 +3,14 @@
|
|||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <linux/atomic.h>
|
||||
|
||||
struct thread_map_data {
|
||||
pid_t pid;
|
||||
};
|
||||
|
||||
struct thread_map {
|
||||
atomic_t refcnt;
|
||||
int nr;
|
||||
struct thread_map_data map[];
|
||||
};
|
||||
|
@ -19,11 +21,12 @@ struct thread_map *thread_map__new_by_tid(pid_t tid);
|
|||
struct thread_map *thread_map__new_by_uid(uid_t uid);
|
||||
struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid);
|
||||
|
||||
struct thread_map *thread_map__get(struct thread_map *map);
|
||||
void thread_map__put(struct thread_map *map);
|
||||
|
||||
struct thread_map *thread_map__new_str(const char *pid,
|
||||
const char *tid, uid_t uid);
|
||||
|
||||
void thread_map__delete(struct thread_map *threads);
|
||||
|
||||
size_t thread_map__fprintf(struct thread_map *threads, FILE *fp);
|
||||
|
||||
static inline int thread_map__nr(struct thread_map *threads)
|
||||
|
|
Loading…
Reference in New Issue