aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/machine.c
diff options
context:
space:
mode:
authorKan Liang <kan.liang@intel.com>2017-09-10 22:23:14 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2017-09-18 08:40:19 -0400
commit91e467bc568f15da2eac688e131010601e889184 (patch)
treed6e2441af518536d534eacde9a4e549ffeb8ec42 /tools/perf/util/machine.c
parent56de5b63ffaff859f75c19aff057ee10f20c6c07 (diff)
perf machine: Use hashtable for machine threads
To process any events, it needs to find the thread in the machine first. The machine maintains a rb tree to store all threads. The rb tree is protected by a rw lock. It is not a problem for current perf which serially processing events. However, it will have scalability performance issue to process events in parallel, especially on a heavy load system which have many threads. Introduce a hashtable to divide the big rb tree into many samll rb tree for threads. The index is thread id % hashtable size. It can reduce the lock contention. Committer notes: Renamed some variables and function names to reduce semantic confusion: 'struct threads' pointers: thread -> threads threads hastable index: tid -> hash_bucket struct threads *machine__thread() -> machine__threads() Cast tid to (unsigned int) to handle -1 in machine__threads() (Kan Liang) Signed-off-by: Kan Liang <kan.liang@intel.com> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Adrian Hunter <adrian.hunter@intel.com> Cc: Andi Kleen <ak@linux.intel.com> Cc: Jiri Olsa <jolsa@kernel.org> Cc: Lukasz Odzioba <lukasz.odzioba@intel.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Link: http://lkml.kernel.org/r/1505096603-215017-2-git-send-email-kan.liang@intel.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/util/machine.c')
-rw-r--r--tools/perf/util/machine.c136
1 files changed, 85 insertions, 51 deletions
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index df709363ef69..f4f926753209 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -33,6 +33,20 @@ static void dsos__init(struct dsos *dsos)
33 pthread_rwlock_init(&dsos->lock, NULL); 33 pthread_rwlock_init(&dsos->lock, NULL);
34} 34}
35 35
36static void machine__threads_init(struct machine *machine)
37{
38 int i;
39
40 for (i = 0; i < THREADS__TABLE_SIZE; i++) {
41 struct threads *threads = &machine->threads[i];
42 threads->entries = RB_ROOT;
43 pthread_rwlock_init(&threads->lock, NULL);
44 threads->nr = 0;
45 INIT_LIST_HEAD(&threads->dead);
46 threads->last_match = NULL;
47 }
48}
49
36int machine__init(struct machine *machine, const char *root_dir, pid_t pid) 50int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
37{ 51{
38 memset(machine, 0, sizeof(*machine)); 52 memset(machine, 0, sizeof(*machine));
@@ -40,11 +54,7 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
40 RB_CLEAR_NODE(&machine->rb_node); 54 RB_CLEAR_NODE(&machine->rb_node);
41 dsos__init(&machine->dsos); 55 dsos__init(&machine->dsos);
42 56
43 machine->threads = RB_ROOT; 57 machine__threads_init(machine);
44 pthread_rwlock_init(&machine->threads_lock, NULL);
45 machine->nr_threads = 0;
46 INIT_LIST_HEAD(&machine->dead_threads);
47 machine->last_match = NULL;
48 58
49 machine->vdso_info = NULL; 59 machine->vdso_info = NULL;
50 machine->env = NULL; 60 machine->env = NULL;
@@ -141,27 +151,37 @@ static void dsos__exit(struct dsos *dsos)
141void machine__delete_threads(struct machine *machine) 151void machine__delete_threads(struct machine *machine)
142{ 152{
143 struct rb_node *nd; 153 struct rb_node *nd;
154 int i;
144 155
145 pthread_rwlock_wrlock(&machine->threads_lock); 156 for (i = 0; i < THREADS__TABLE_SIZE; i++) {
146 nd = rb_first(&machine->threads); 157 struct threads *threads = &machine->threads[i];
147 while (nd) { 158 pthread_rwlock_wrlock(&threads->lock);
148 struct thread *t = rb_entry(nd, struct thread, rb_node); 159 nd = rb_first(&threads->entries);
160 while (nd) {
161 struct thread *t = rb_entry(nd, struct thread, rb_node);
149 162
150 nd = rb_next(nd); 163 nd = rb_next(nd);
151 __machine__remove_thread(machine, t, false); 164 __machine__remove_thread(machine, t, false);
165 }
166 pthread_rwlock_unlock(&threads->lock);
152 } 167 }
153 pthread_rwlock_unlock(&machine->threads_lock);
154} 168}
155 169
156void machine__exit(struct machine *machine) 170void machine__exit(struct machine *machine)
157{ 171{
172 int i;
173
158 machine__destroy_kernel_maps(machine); 174 machine__destroy_kernel_maps(machine);
159 map_groups__exit(&machine->kmaps); 175 map_groups__exit(&machine->kmaps);
160 dsos__exit(&machine->dsos); 176 dsos__exit(&machine->dsos);
161 machine__exit_vdso(machine); 177 machine__exit_vdso(machine);
162 zfree(&machine->root_dir); 178 zfree(&machine->root_dir);
163 zfree(&machine->current_tid); 179 zfree(&machine->current_tid);
164 pthread_rwlock_destroy(&machine->threads_lock); 180
181 for (i = 0; i < THREADS__TABLE_SIZE; i++) {
182 struct threads *threads = &machine->threads[i];
183 pthread_rwlock_destroy(&threads->lock);
184 }
165} 185}
166 186
167void machine__delete(struct machine *machine) 187void machine__delete(struct machine *machine)
@@ -382,7 +402,8 @@ static struct thread *____machine__findnew_thread(struct machine *machine,
382 pid_t pid, pid_t tid, 402 pid_t pid, pid_t tid,
383 bool create) 403 bool create)
384{ 404{
385 struct rb_node **p = &machine->threads.rb_node; 405 struct threads *threads = machine__threads(machine, tid);
406 struct rb_node **p = &threads->entries.rb_node;
386 struct rb_node *parent = NULL; 407 struct rb_node *parent = NULL;
387 struct thread *th; 408 struct thread *th;
388 409
@@ -391,14 +412,14 @@ static struct thread *____machine__findnew_thread(struct machine *machine,
391 * so most of the time we dont have to look up 412 * so most of the time we dont have to look up
392 * the full rbtree: 413 * the full rbtree:
393 */ 414 */
394 th = machine->last_match; 415 th = threads->last_match;
395 if (th != NULL) { 416 if (th != NULL) {
396 if (th->tid == tid) { 417 if (th->tid == tid) {
397 machine__update_thread_pid(machine, th, pid); 418 machine__update_thread_pid(machine, th, pid);
398 return thread__get(th); 419 return thread__get(th);
399 } 420 }
400 421
401 machine->last_match = NULL; 422 threads->last_match = NULL;
402 } 423 }
403 424
404 while (*p != NULL) { 425 while (*p != NULL) {
@@ -406,7 +427,7 @@ static struct thread *____machine__findnew_thread(struct machine *machine,
406 th = rb_entry(parent, struct thread, rb_node); 427 th = rb_entry(parent, struct thread, rb_node);
407 428
408 if (th->tid == tid) { 429 if (th->tid == tid) {
409 machine->last_match = th; 430 threads->last_match = th;
410 machine__update_thread_pid(machine, th, pid); 431 machine__update_thread_pid(machine, th, pid);
411 return thread__get(th); 432 return thread__get(th);
412 } 433 }
@@ -423,7 +444,7 @@ static struct thread *____machine__findnew_thread(struct machine *machine,
423 th = thread__new(pid, tid); 444 th = thread__new(pid, tid);
424 if (th != NULL) { 445 if (th != NULL) {
425 rb_link_node(&th->rb_node, parent, p); 446 rb_link_node(&th->rb_node, parent, p);
426 rb_insert_color(&th->rb_node, &machine->threads); 447 rb_insert_color(&th->rb_node, &threads->entries);
427 448
428 /* 449 /*
429 * We have to initialize map_groups separately 450 * We have to initialize map_groups separately
@@ -434,7 +455,7 @@ static struct thread *____machine__findnew_thread(struct machine *machine,
434 * leader and that would screwed the rb tree. 455 * leader and that would screwed the rb tree.
435 */ 456 */
436 if (thread__init_map_groups(th, machine)) { 457 if (thread__init_map_groups(th, machine)) {
437 rb_erase_init(&th->rb_node, &machine->threads); 458 rb_erase_init(&th->rb_node, &threads->entries);
438 RB_CLEAR_NODE(&th->rb_node); 459 RB_CLEAR_NODE(&th->rb_node);
439 thread__put(th); 460 thread__put(th);
440 return NULL; 461 return NULL;
@@ -443,8 +464,8 @@ static struct thread *____machine__findnew_thread(struct machine *machine,
443 * It is now in the rbtree, get a ref 464 * It is now in the rbtree, get a ref
444 */ 465 */
445 thread__get(th); 466 thread__get(th);
446 machine->last_match = th; 467 threads->last_match = th;
447 ++machine->nr_threads; 468 ++threads->nr;
448 } 469 }
449 470
450 return th; 471 return th;
@@ -458,21 +479,24 @@ struct thread *__machine__findnew_thread(struct machine *machine, pid_t pid, pid
458struct thread *machine__findnew_thread(struct machine *machine, pid_t pid, 479struct thread *machine__findnew_thread(struct machine *machine, pid_t pid,
459 pid_t tid) 480 pid_t tid)
460{ 481{
482 struct threads *threads = machine__threads(machine, tid);
461 struct thread *th; 483 struct thread *th;
462 484
463 pthread_rwlock_wrlock(&machine->threads_lock); 485 pthread_rwlock_wrlock(&threads->lock);
464 th = __machine__findnew_thread(machine, pid, tid); 486 th = __machine__findnew_thread(machine, pid, tid);
465 pthread_rwlock_unlock(&machine->threads_lock); 487 pthread_rwlock_unlock(&threads->lock);
466 return th; 488 return th;
467} 489}
468 490
469struct thread *machine__find_thread(struct machine *machine, pid_t pid, 491struct thread *machine__find_thread(struct machine *machine, pid_t pid,
470 pid_t tid) 492 pid_t tid)
471{ 493{
494 struct threads *threads = machine__threads(machine, tid);
472 struct thread *th; 495 struct thread *th;
473 pthread_rwlock_rdlock(&machine->threads_lock); 496
497 pthread_rwlock_rdlock(&threads->lock);
474 th = ____machine__findnew_thread(machine, pid, tid, false); 498 th = ____machine__findnew_thread(machine, pid, tid, false);
475 pthread_rwlock_unlock(&machine->threads_lock); 499 pthread_rwlock_unlock(&threads->lock);
476 return th; 500 return th;
477} 501}
478 502
@@ -719,21 +743,24 @@ size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp)
719 743
720size_t machine__fprintf(struct machine *machine, FILE *fp) 744size_t machine__fprintf(struct machine *machine, FILE *fp)
721{ 745{
722 size_t ret;
723 struct rb_node *nd; 746 struct rb_node *nd;
747 size_t ret;
748 int i;
724 749
725 pthread_rwlock_rdlock(&machine->threads_lock); 750 for (i = 0; i < THREADS__TABLE_SIZE; i++) {
726 751 struct threads *threads = &machine->threads[i];
727 ret = fprintf(fp, "Threads: %u\n", machine->nr_threads); 752 pthread_rwlock_rdlock(&threads->lock);
728 753
729 for (nd = rb_first(&machine->threads); nd; nd = rb_next(nd)) { 754 ret = fprintf(fp, "Threads: %u\n", threads->nr);
730 struct thread *pos = rb_entry(nd, struct thread, rb_node);
731 755
732 ret += thread__fprintf(pos, fp); 756 for (nd = rb_first(&threads->entries); nd; nd = rb_next(nd)) {
733 } 757 struct thread *pos = rb_entry(nd, struct thread, rb_node);
734 758
735 pthread_rwlock_unlock(&machine->threads_lock); 759 ret += thread__fprintf(pos, fp);
760 }
736 761
762 pthread_rwlock_unlock(&threads->lock);
763 }
737 return ret; 764 return ret;
738} 765}
739 766
@@ -1479,23 +1506,25 @@ out_problem:
1479 1506
1480static void __machine__remove_thread(struct machine *machine, struct thread *th, bool lock) 1507static void __machine__remove_thread(struct machine *machine, struct thread *th, bool lock)
1481{ 1508{
1482 if (machine->last_match == th) 1509 struct threads *threads = machine__threads(machine, th->tid);
1483 machine->last_match = NULL; 1510
1511 if (threads->last_match == th)
1512 threads->last_match = NULL;
1484 1513
1485 BUG_ON(refcount_read(&th->refcnt) == 0); 1514 BUG_ON(refcount_read(&th->refcnt) == 0);
1486 if (lock) 1515 if (lock)
1487 pthread_rwlock_wrlock(&machine->threads_lock); 1516 pthread_rwlock_wrlock(&threads->lock);
1488 rb_erase_init(&th->rb_node, &machine->threads); 1517 rb_erase_init(&th->rb_node, &threads->entries);
1489 RB_CLEAR_NODE(&th->rb_node); 1518 RB_CLEAR_NODE(&th->rb_node);
1490 --machine->nr_threads; 1519 --threads->nr;
1491 /* 1520 /*
1492 * Move it first to the dead_threads list, then drop the reference, 1521 * Move it first to the dead_threads list, then drop the reference,
1493 * if this is the last reference, then the thread__delete destructor 1522 * if this is the last reference, then the thread__delete destructor
1494 * will be called and we will remove it from the dead_threads list. 1523 * will be called and we will remove it from the dead_threads list.
1495 */ 1524 */
1496 list_add_tail(&th->node, &machine->dead_threads); 1525 list_add_tail(&th->node, &threads->dead);
1497 if (lock) 1526 if (lock)
1498 pthread_rwlock_unlock(&machine->threads_lock); 1527 pthread_rwlock_unlock(&threads->lock);
1499 thread__put(th); 1528 thread__put(th);
1500} 1529}
1501 1530
@@ -2140,21 +2169,26 @@ int machine__for_each_thread(struct machine *machine,
2140 int (*fn)(struct thread *thread, void *p), 2169 int (*fn)(struct thread *thread, void *p),
2141 void *priv) 2170 void *priv)
2142{ 2171{
2172 struct threads *threads;
2143 struct rb_node *nd; 2173 struct rb_node *nd;
2144 struct thread *thread; 2174 struct thread *thread;
2145 int rc = 0; 2175 int rc = 0;
2176 int i;
2146 2177
2147 for (nd = rb_first(&machine->threads); nd; nd = rb_next(nd)) { 2178 for (i = 0; i < THREADS__TABLE_SIZE; i++) {
2148 thread = rb_entry(nd, struct thread, rb_node); 2179 threads = &machine->threads[i];
2149 rc = fn(thread, priv); 2180 for (nd = rb_first(&threads->entries); nd; nd = rb_next(nd)) {
2150 if (rc != 0) 2181 thread = rb_entry(nd, struct thread, rb_node);
2151 return rc; 2182 rc = fn(thread, priv);
2152 } 2183 if (rc != 0)
2184 return rc;
2185 }
2153 2186
2154 list_for_each_entry(thread, &machine->dead_threads, node) { 2187 list_for_each_entry(thread, &threads->dead, node) {
2155 rc = fn(thread, priv); 2188 rc = fn(thread, priv);
2156 if (rc != 0) 2189 if (rc != 0)
2157 return rc; 2190 return rc;
2191 }
2158 } 2192 }
2159 return rc; 2193 return rc;
2160} 2194}