Make refcnt to use a hash table to reduce search overhead on refcnt_root. This hash is based on passed object address.
Signed-off-by: Masami Hiramatsu <masami.hiramatsu...@hitachi.com> --- tools/perf/util/refcnt.c | 71 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 49 insertions(+), 22 deletions(-) diff --git a/tools/perf/util/refcnt.c b/tools/perf/util/refcnt.c index 9bd36b2b..9748dba 100644 --- a/tools/perf/util/refcnt.c +++ b/tools/perf/util/refcnt.c @@ -9,9 +9,21 @@ #include "debug.h" #include "util.h" #include "refcnt.h" +#include "linux/hash.h" -/* A root of backtrace */ -static LIST_HEAD(refcnt_root); /* List head of refcnt object */ +#define REFCNT_HASHBITS 7 +#define REFCNT_HASHSZ (1 << REFCNT_HASHBITS) + +/* A root of backtraces (a hash table of the list of refcnt_object)*/ +static struct list_head refcnt_root[REFCNT_HASHSZ]; + +static void __attribute__((constructor)) refcnt__init_root(void) +{ + int h; + + for (h = 0; h < REFCNT_HASHSZ; h++) + INIT_LIST_HEAD(&refcnt_root[h]); +} static void refcnt_object__delete(struct refcnt_object *ref) { @@ -29,9 +41,9 @@ static void refcnt_object__delete(struct refcnt_object *ref) static struct refcnt_object *refcnt_object__find(void *obj) { struct refcnt_object *ref; + int h = (int)hash_ptr(obj, REFCNT_HASHBITS); - /* TODO: use hash list */ - list_for_each_entry(ref, &refcnt_root, list) + list_for_each_entry(ref, &refcnt_root[h], list) if (ref->obj == obj) return ref; @@ -67,6 +79,7 @@ static void refcnt_object__record(struct refcnt_object *ref, int count) static struct refcnt_object *refcnt_object__new(void *obj, const char *name) { struct refcnt_object *ref = malloc(sizeof(*ref)); + int h = (int)hash_ptr(obj, REFCNT_HASHBITS); if (!ref) { pr_debug("REFCNT: Out of memory for %p (%s)\n", @@ -77,7 +90,7 @@ static struct refcnt_object *refcnt_object__new(void *obj, const char *name) INIT_LIST_HEAD(&ref->head); ref->name = name; ref->obj = obj; - list_add_tail(&ref->list, &refcnt_root); + list_add_tail(&ref->list, &refcnt_root[h]); return ref; } @@ -110,6 +123,11 @@ static void pr_refcnt_buffer(struct refcnt_buffer *buf) if (!buf) return; + + pr_debug("Refcount %s => %d at\n", + buf->count >= 0 ? "+1" : "-1", + buf->count >= 0 ? buf->count : -buf->count - 1); + symbuf = backtrace_symbols(buf->buf, buf->nr); /* Skip the first one because it is always btrace__record */ for (i = 1; i < buf->nr; i++) { @@ -121,29 +139,38 @@ static void pr_refcnt_buffer(struct refcnt_buffer *buf) free(symbuf); } -static void __attribute__((destructor)) refcnt__dump_unreclaimed(void) +static void pr_refcnt_object(struct refcnt_object *ref) { - struct refcnt_object *ref, *n; struct refcnt_buffer *buf; - int i = 0; - if (list_empty(&refcnt_root)) - return; + pr_debug("Unreclaimed %s@%p\n", + ref->name ? ref->name : "(object)", ref->obj); + + list_for_each_entry(buf, &ref->head, list) + pr_refcnt_buffer(buf); +} +static void __attribute__((destructor)) refcnt__dump_unreclaimed(void) +{ + struct refcnt_object *ref, *n; + int h, i = 0; + + for (h = 0; h < REFCNT_HASHSZ; h++) + if (!list_empty(&refcnt_root[h])) + goto found; + return; +found: pr_warning("REFCNT: BUG: Unreclaimed objects found.\n"); - list_for_each_entry_safe(ref, n, &refcnt_root, list) { - pr_debug("==== [%d] ====\nUnreclaimed %s@%p\n", i, - ref->name ? ref->name : "(object)", ref->obj); - list_for_each_entry(buf, &ref->head, list) { - pr_debug("Refcount %s => %d at\n", - buf->count >= 0 ? "+1" : "-1", - buf->count >= 0 ? buf->count : - -buf->count - 1); - pr_refcnt_buffer(buf); + for ( ; h < REFCNT_HASHSZ; h++) + list_for_each_entry_safe(ref, n, &refcnt_root[h], list) { + if (verbose) { + pr_debug("==== [%d] ====\n", i); + pr_refcnt_object(ref); + } + refcnt_object__delete(ref); + i++; } - refcnt_object__delete(ref); - i++; - } + pr_warning("REFCNT: Total %d objects are not reclaimed.\n", i); if (!verbose) pr_warning(" To see all backtraces, rerun with -v option\n"); -- To unsubscribe from this list: send the line "unsubscribe linux-perf-users" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html