0001
0002
0003 #include "util/debug.h"
0004 #include "util/evlist.h"
0005 #include "util/evsel.h"
0006 #include "util/mmap.h"
0007 #include "util/perf_api_probe.h"
0008 #include <perf/mmap.h>
0009 #include <linux/perf_event.h>
0010 #include <limits.h>
0011 #include <pthread.h>
0012 #include <sched.h>
0013 #include <stdbool.h>
0014
0015 int evlist__add_sb_event(struct evlist *evlist, struct perf_event_attr *attr,
0016 evsel__sb_cb_t cb, void *data)
0017 {
0018 struct evsel *evsel;
0019
0020 if (!attr->sample_id_all) {
0021 pr_warning("enabling sample_id_all for all side band events\n");
0022 attr->sample_id_all = 1;
0023 }
0024
0025 evsel = evsel__new_idx(attr, evlist->core.nr_entries);
0026 if (!evsel)
0027 return -1;
0028
0029 evsel->side_band.cb = cb;
0030 evsel->side_band.data = data;
0031 evlist__add(evlist, evsel);
0032 return 0;
0033 }
0034
0035 static void *perf_evlist__poll_thread(void *arg)
0036 {
0037 struct evlist *evlist = arg;
0038 bool draining = false;
0039 int i, done = 0;
0040
0041
0042
0043
0044
0045
0046
0047 unshare(CLONE_FS);
0048
0049 while (!done) {
0050 bool got_data = false;
0051
0052 if (evlist->thread.done)
0053 draining = true;
0054
0055 if (!draining)
0056 evlist__poll(evlist, 1000);
0057
0058 for (i = 0; i < evlist->core.nr_mmaps; i++) {
0059 struct mmap *map = &evlist->mmap[i];
0060 union perf_event *event;
0061
0062 if (perf_mmap__read_init(&map->core))
0063 continue;
0064 while ((event = perf_mmap__read_event(&map->core)) != NULL) {
0065 struct evsel *evsel = evlist__event2evsel(evlist, event);
0066
0067 if (evsel && evsel->side_band.cb)
0068 evsel->side_band.cb(event, evsel->side_band.data);
0069 else
0070 pr_warning("cannot locate proper evsel for the side band event\n");
0071
0072 perf_mmap__consume(&map->core);
0073 got_data = true;
0074 }
0075 perf_mmap__read_done(&map->core);
0076 }
0077
0078 if (draining && !got_data)
0079 break;
0080 }
0081 return NULL;
0082 }
0083
0084 void evlist__set_cb(struct evlist *evlist, evsel__sb_cb_t cb, void *data)
0085 {
0086 struct evsel *evsel;
0087
0088 evlist__for_each_entry(evlist, evsel) {
0089 evsel->core.attr.sample_id_all = 1;
0090 evsel->core.attr.watermark = 1;
0091 evsel->core.attr.wakeup_watermark = 1;
0092 evsel->side_band.cb = cb;
0093 evsel->side_band.data = data;
0094 }
0095 }
0096
0097 int evlist__start_sb_thread(struct evlist *evlist, struct target *target)
0098 {
0099 struct evsel *counter;
0100
0101 if (!evlist)
0102 return 0;
0103
0104 if (evlist__create_maps(evlist, target))
0105 goto out_delete_evlist;
0106
0107 if (evlist->core.nr_entries > 1) {
0108 bool can_sample_identifier = perf_can_sample_identifier();
0109
0110 evlist__for_each_entry(evlist, counter)
0111 evsel__set_sample_id(counter, can_sample_identifier);
0112
0113 evlist__set_id_pos(evlist);
0114 }
0115
0116 evlist__for_each_entry(evlist, counter) {
0117 if (evsel__open(counter, evlist->core.user_requested_cpus,
0118 evlist->core.threads) < 0)
0119 goto out_delete_evlist;
0120 }
0121
0122 if (evlist__mmap(evlist, UINT_MAX))
0123 goto out_delete_evlist;
0124
0125 evlist__for_each_entry(evlist, counter) {
0126 if (evsel__enable(counter))
0127 goto out_delete_evlist;
0128 }
0129
0130 evlist->thread.done = 0;
0131 if (pthread_create(&evlist->thread.th, NULL, perf_evlist__poll_thread, evlist))
0132 goto out_delete_evlist;
0133
0134 return 0;
0135
0136 out_delete_evlist:
0137 evlist__delete(evlist);
0138 evlist = NULL;
0139 return -1;
0140 }
0141
0142 void evlist__stop_sb_thread(struct evlist *evlist)
0143 {
0144 if (!evlist)
0145 return;
0146 evlist->thread.done = 1;
0147 pthread_join(evlist->thread.th, NULL);
0148 evlist__delete(evlist);
0149 }