|
@@ -367,10 +367,17 @@ static int probe_cache__open(struct probe_cache *pcache, const char *target)
|
|
|
{
|
|
|
char cpath[PATH_MAX];
|
|
|
char sbuildid[SBUILD_ID_SIZE];
|
|
|
- char *dir_name;
|
|
|
+ char *dir_name = NULL;
|
|
|
bool is_kallsyms = !target;
|
|
|
int ret, fd;
|
|
|
|
|
|
+ if (target && build_id_cache__cached(target)) {
|
|
|
+ /* This is a cached buildid */
|
|
|
+ strncpy(sbuildid, target, SBUILD_ID_SIZE);
|
|
|
+ dir_name = build_id_cache__linkname(sbuildid, NULL, 0);
|
|
|
+ goto found;
|
|
|
+ }
|
|
|
+
|
|
|
if (target)
|
|
|
ret = filename__sprintf_build_id(target, sbuildid);
|
|
|
else {
|
|
@@ -394,8 +401,11 @@ static int probe_cache__open(struct probe_cache *pcache, const char *target)
|
|
|
|
|
|
dir_name = build_id_cache__cachedir(sbuildid, target, is_kallsyms,
|
|
|
false);
|
|
|
- if (!dir_name)
|
|
|
+found:
|
|
|
+ if (!dir_name) {
|
|
|
+ pr_debug("Failed to get cache from %s\n", target);
|
|
|
return -ENOMEM;
|
|
|
+ }
|
|
|
|
|
|
snprintf(cpath, PATH_MAX, "%s/probes", dir_name);
|
|
|
fd = open(cpath, O_CREAT | O_RDWR, 0644);
|
|
@@ -424,12 +434,15 @@ static int probe_cache__load(struct probe_cache *pcache)
|
|
|
p = strchr(buf, '\n');
|
|
|
if (p)
|
|
|
*p = '\0';
|
|
|
- if (buf[0] == '#') { /* #perf_probe_event */
|
|
|
+ /* #perf_probe_event or %sdt_event */
|
|
|
+ if (buf[0] == '#' || buf[0] == '%') {
|
|
|
entry = probe_cache_entry__new(NULL);
|
|
|
if (!entry) {
|
|
|
ret = -ENOMEM;
|
|
|
goto out;
|
|
|
}
|
|
|
+ if (buf[0] == '%')
|
|
|
+ entry->sdt = true;
|
|
|
entry->spev = strdup(buf + 1);
|
|
|
if (entry->spev)
|
|
|
ret = parse_perf_probe_command(buf + 1,
|
|
@@ -524,7 +537,7 @@ static bool streql(const char *a, const char *b)
|
|
|
return !strcmp(a, b);
|
|
|
}
|
|
|
|
|
|
-static struct probe_cache_entry *
|
|
|
+struct probe_cache_entry *
|
|
|
probe_cache__find(struct probe_cache *pcache, struct perf_probe_event *pev)
|
|
|
{
|
|
|
struct probe_cache_entry *entry = NULL;
|
|
@@ -548,6 +561,24 @@ found:
|
|
|
return entry;
|
|
|
}
|
|
|
|
|
|
+struct probe_cache_entry *
|
|
|
+probe_cache__find_by_name(struct probe_cache *pcache,
|
|
|
+ const char *group, const char *event)
|
|
|
+{
|
|
|
+ struct probe_cache_entry *entry = NULL;
|
|
|
+
|
|
|
+ list_for_each_entry(entry, &pcache->entries, node) {
|
|
|
+ /* Hit if same event name or same command-string */
|
|
|
+ if (streql(entry->pev.group, group) &&
|
|
|
+ streql(entry->pev.event, event))
|
|
|
+ goto found;
|
|
|
+ }
|
|
|
+ entry = NULL;
|
|
|
+
|
|
|
+found:
|
|
|
+ return entry;
|
|
|
+}
|
|
|
+
|
|
|
int probe_cache__add_entry(struct probe_cache *pcache,
|
|
|
struct perf_probe_event *pev,
|
|
|
struct probe_trace_event *tevs, int ntevs)
|
|
@@ -593,19 +624,79 @@ out_err:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+static unsigned long long sdt_note__get_addr(struct sdt_note *note)
|
|
|
+{
|
|
|
+ return note->bit32 ? (unsigned long long)note->addr.a32[0]
|
|
|
+ : (unsigned long long)note->addr.a64[0];
|
|
|
+}
|
|
|
+
|
|
|
+int probe_cache__scan_sdt(struct probe_cache *pcache, const char *pathname)
|
|
|
+{
|
|
|
+ struct probe_cache_entry *entry = NULL;
|
|
|
+ struct list_head sdtlist;
|
|
|
+ struct sdt_note *note;
|
|
|
+ char *buf;
|
|
|
+ char sdtgrp[64];
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ INIT_LIST_HEAD(&sdtlist);
|
|
|
+ ret = get_sdt_note_list(&sdtlist, pathname);
|
|
|
+ if (ret < 0) {
|
|
|
+ pr_debug("Failed to get sdt note: %d\n", ret);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+ list_for_each_entry(note, &sdtlist, note_list) {
|
|
|
+ ret = snprintf(sdtgrp, 64, "sdt_%s", note->provider);
|
|
|
+ if (ret < 0)
|
|
|
+ break;
|
|
|
+ /* Try to find same-name entry */
|
|
|
+ entry = probe_cache__find_by_name(pcache, sdtgrp, note->name);
|
|
|
+ if (!entry) {
|
|
|
+ entry = probe_cache_entry__new(NULL);
|
|
|
+ if (!entry) {
|
|
|
+ ret = -ENOMEM;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ entry->sdt = true;
|
|
|
+ ret = asprintf(&entry->spev, "%s:%s=%s", sdtgrp,
|
|
|
+ note->name, note->name);
|
|
|
+ if (ret < 0)
|
|
|
+ break;
|
|
|
+ entry->pev.event = strdup(note->name);
|
|
|
+ entry->pev.group = strdup(sdtgrp);
|
|
|
+ list_add_tail(&entry->node, &pcache->entries);
|
|
|
+ }
|
|
|
+ ret = asprintf(&buf, "p:%s/%s %s:0x%llx",
|
|
|
+ sdtgrp, note->name, pathname,
|
|
|
+ sdt_note__get_addr(note));
|
|
|
+ if (ret < 0)
|
|
|
+ break;
|
|
|
+ strlist__add(entry->tevlist, buf);
|
|
|
+ free(buf);
|
|
|
+ entry = NULL;
|
|
|
+ }
|
|
|
+ if (entry) {
|
|
|
+ list_del_init(&entry->node);
|
|
|
+ probe_cache_entry__delete(entry);
|
|
|
+ }
|
|
|
+ cleanup_sdt_note_list(&sdtlist);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
static int probe_cache_entry__write(struct probe_cache_entry *entry, int fd)
|
|
|
{
|
|
|
struct str_node *snode;
|
|
|
struct stat st;
|
|
|
struct iovec iov[3];
|
|
|
+ const char *prefix = entry->sdt ? "%" : "#";
|
|
|
int ret;
|
|
|
/* Save stat for rollback */
|
|
|
ret = fstat(fd, &st);
|
|
|
if (ret < 0)
|
|
|
return ret;
|
|
|
|
|
|
- pr_debug("Writing cache: #%s\n", entry->spev);
|
|
|
- iov[0].iov_base = (void *)"#"; iov[0].iov_len = 1;
|
|
|
+ pr_debug("Writing cache: %s%s\n", prefix, entry->spev);
|
|
|
+ iov[0].iov_base = (void *)prefix; iov[0].iov_len = 1;
|
|
|
iov[1].iov_base = entry->spev; iov[1].iov_len = strlen(entry->spev);
|
|
|
iov[2].iov_base = (void *)"\n"; iov[2].iov_len = 1;
|
|
|
ret = writev(fd, iov, 3);
|
|
@@ -655,3 +746,75 @@ int probe_cache__commit(struct probe_cache *pcache)
|
|
|
out:
|
|
|
return ret;
|
|
|
}
|
|
|
+
|
|
|
+static bool probe_cache_entry__compare(struct probe_cache_entry *entry,
|
|
|
+ struct strfilter *filter)
|
|
|
+{
|
|
|
+ char buf[128], *ptr = entry->spev;
|
|
|
+
|
|
|
+ if (entry->pev.event) {
|
|
|
+ snprintf(buf, 128, "%s:%s", entry->pev.group, entry->pev.event);
|
|
|
+ ptr = buf;
|
|
|
+ }
|
|
|
+ return strfilter__compare(filter, ptr);
|
|
|
+}
|
|
|
+
|
|
|
+int probe_cache__filter_purge(struct probe_cache *pcache,
|
|
|
+ struct strfilter *filter)
|
|
|
+{
|
|
|
+ struct probe_cache_entry *entry, *tmp;
|
|
|
+
|
|
|
+ list_for_each_entry_safe(entry, tmp, &pcache->entries, node) {
|
|
|
+ if (probe_cache_entry__compare(entry, filter)) {
|
|
|
+ pr_info("Removed cached event: %s\n", entry->spev);
|
|
|
+ list_del_init(&entry->node);
|
|
|
+ probe_cache_entry__delete(entry);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int probe_cache__show_entries(struct probe_cache *pcache,
|
|
|
+ struct strfilter *filter)
|
|
|
+{
|
|
|
+ struct probe_cache_entry *entry;
|
|
|
+
|
|
|
+ list_for_each_entry(entry, &pcache->entries, node) {
|
|
|
+ if (probe_cache_entry__compare(entry, filter))
|
|
|
+ printf("%s\n", entry->spev);
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/* Show all cached probes */
|
|
|
+int probe_cache__show_all_caches(struct strfilter *filter)
|
|
|
+{
|
|
|
+ struct probe_cache *pcache;
|
|
|
+ struct strlist *bidlist;
|
|
|
+ struct str_node *nd;
|
|
|
+ char *buf = strfilter__string(filter);
|
|
|
+
|
|
|
+ pr_debug("list cache with filter: %s\n", buf);
|
|
|
+ free(buf);
|
|
|
+
|
|
|
+ bidlist = build_id_cache__list_all();
|
|
|
+ if (!bidlist) {
|
|
|
+ pr_debug("Failed to get buildids: %d\n", errno);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ strlist__for_each_entry(nd, bidlist) {
|
|
|
+ pcache = probe_cache__new(nd->s);
|
|
|
+ if (!pcache)
|
|
|
+ continue;
|
|
|
+ if (!list_empty(&pcache->entries)) {
|
|
|
+ buf = build_id_cache__origname(nd->s);
|
|
|
+ printf("%s (%s):\n", buf, nd->s);
|
|
|
+ free(buf);
|
|
|
+ probe_cache__show_entries(pcache, filter);
|
|
|
+ }
|
|
|
+ probe_cache__delete(pcache);
|
|
|
+ }
|
|
|
+ strlist__delete(bidlist);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|