diff --git a/drivers/android/Kconfig b/drivers/android/Kconfig index 53b22e26266c3ea2eca4be14447b97d89de46c21..18f636e6d30e314215fe5fa1907df5d825093b94 100644 --- a/drivers/android/Kconfig +++ b/drivers/android/Kconfig @@ -54,6 +54,13 @@ config ANDROID_BINDER_IPC_SELFTEST exhaustively with combinations of various buffer sizes and alignments. +config BINDER_TRANSACTION_PROC_BRIEF + bool "Brief debug info for binder transaction and proc" + depends on ANDROID_BINDER_IPC + default n + help + + Enable binder optimization endif # if ANDROID endmenu diff --git a/drivers/android/binder.c b/drivers/android/binder.c index bb8b072f3451b4d4838fe50cfac2dbe695f952b3..db4bdb65be9f282b8951158f2ccd5134cae3d40a 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -66,6 +66,9 @@ #include #include #include +#ifdef CONFIG_BINDER_TRANSACTION_PROC_BRIEF +#include +#endif #include #include @@ -93,6 +96,11 @@ static atomic_t binder_last_id; static int proc_show(struct seq_file *m, void *unused); DEFINE_SHOW_ATTRIBUTE(proc); +#ifdef CONFIG_BINDER_TRANSACTION_PROC_BRIEF +static int binder_transaction_proc_show(struct seq_file *m, void *unused); +DEFINE_SHOW_ATTRIBUTE(binder_transaction_proc); +#endif + #define FORBIDDEN_MMAP_FLAGS (VM_WRITE) #ifdef CONFIG_ACCESS_TOKENID @@ -585,6 +593,11 @@ struct binder_transaction { int debug_id; struct binder_work work; struct binder_thread *from; +#ifdef CONFIG_BINDER_TRANSACTION_PROC_BRIEF + int async_from_pid; + int async_from_tid; + u64 timestamp; +#endif struct binder_transaction *from_parent; struct binder_proc *to_proc; struct binder_thread *to_thread; @@ -911,6 +924,16 @@ static void binder_free_thread(struct binder_thread *thread); static void binder_free_proc(struct binder_proc *proc); static void binder_inc_node_tmpref_ilocked(struct binder_node *node); +#ifdef CONFIG_BINDER_TRANSACTION_PROC_BRIEF +static inline u64 binder_clock(void) +{ +#ifdef CONFIG_TRACE_CLOCK + return trace_clock_local(); +#endif + return 0; +} +#endif + static bool binder_has_work_ilocked(struct binder_thread *thread, bool do_proc_work) { @@ -3103,10 +3126,19 @@ static void binder_transaction(struct binder_proc *proc, (u64)tr->data_size, (u64)tr->offsets_size, (u64)extra_buffers_size); - if (!reply && !(tr->flags & TF_ONE_WAY)) + if (!reply && !(tr->flags & TF_ONE_WAY)) { t->from = thread; - else +#ifdef CONFIG_BINDER_TRANSACTION_PROC_BRIEF + t->async_from_pid = -1; + t->async_from_tid = -1; +#endif + } else { t->from = NULL; +#ifdef CONFIG_BINDER_TRANSACTION_PROC_BRIEF + t->async_from_pid = thread->proc->pid; + t->async_from_tid = thread->pid; +#endif +} t->sender_euid = task_euid(proc->tsk); #ifdef CONFIG_ACCESS_TOKENID t->sender_tokenid = current->token; @@ -3440,6 +3472,9 @@ static void binder_transaction(struct binder_proc *proc, goto err_dead_proc_or_thread; } BUG_ON(t->buffer->async_transaction != 0); +#ifdef CONFIG_BINDER_TRANSACTION_PROC_BRIEF + t->timestamp = in_reply_to->timestamp; +#endif binder_pop_transaction_ilocked(target_thread, in_reply_to); binder_enqueue_thread_work_ilocked(target_thread, &t->work); binder_inner_proc_unlock(target_proc); @@ -3459,6 +3494,9 @@ static void binder_transaction(struct binder_proc *proc, t->need_reply = 1; t->from_parent = thread->transaction_stack; thread->transaction_stack = t; +#ifdef CONFIG_BINDER_TRANSACTION_PROC_BRIEF + t->timestamp = binder_clock(); +#endif binder_inner_proc_unlock(proc); if (!binder_proc_transaction(t, target_proc, target_thread)) { binder_inner_proc_lock(proc); @@ -3470,6 +3508,9 @@ static void binder_transaction(struct binder_proc *proc, BUG_ON(target_node == NULL); BUG_ON(t->buffer->async_transaction != 1); binder_enqueue_thread_work(thread, tcomplete); +#ifdef CONFIG_BINDER_TRANSACTION_PROC_BRIEF + t->timestamp = binder_clock(); +#endif if (!binder_proc_transaction(t, target_proc, NULL)) goto err_dead_proc_or_thread; } @@ -4797,6 +4838,10 @@ static int binder_thread_release(struct binder_proc *proc, t = t->to_parent; } else if (t->from == thread) { t->from = NULL; +#ifdef CONFIG_BINDER_TRANSACTION_PROC_BRIEF + t->async_from_pid = -1; + t->async_from_tid = -1; +#endif t = t->from_parent; } else BUG(); @@ -6134,6 +6179,149 @@ const struct file_operations binder_fops = { .release = binder_release, }; +#ifdef CONFIG_BINDER_TRANSACTION_PROC_BRIEF +static void print_binder_transaction_brief_ilocked( + struct seq_file *m, + const char *prefix, struct binder_transaction *t, + u64 timestamp) +{ + struct binder_proc *to_proc = NULL; + int from_pid = 0; + int from_tid = 0; + int to_pid = 0; + + spin_lock(&t->lock); + to_proc = t->to_proc; + from_pid = t->from ? (t->from->proc ? t->from->proc->pid : 0) : t->async_from_pid; + from_tid = t->from ? t->from->pid : t->async_from_tid; + to_pid = to_proc ? to_proc->pid : 0; + + seq_printf(m, + "%s%d:%d to %d:%d code %x wait:%lld.%lld s\n", + prefix, + from_pid, from_tid, + to_pid, t->to_thread ? t->to_thread->pid : 0, + t->code, + timestamp > t->timestamp ? (timestamp - t->timestamp) / 1000000000 : 0, + timestamp > t->timestamp ? (timestamp - t->timestamp) % 1000000000 : 0); + spin_unlock(&t->lock); +} + +static void print_binder_work_transaction_nilocked(struct seq_file *m, + const char *prefix, struct binder_work *w, + u64 timestamp) +{ + struct binder_transaction *t = NULL; + + switch (w->type) { + case BINDER_WORK_TRANSACTION: + t = container_of(w, struct binder_transaction, work); + print_binder_transaction_brief_ilocked(m, prefix, t, timestamp); + break; + + default: + break; + } +} + +static void print_binder_transaction_brief(struct seq_file *m, + struct binder_proc *proc, + u64 timestamp) +{ + struct binder_work *w = NULL; + struct rb_node *n = NULL; + struct binder_node *last_node = NULL; + size_t start_pos = m->count; + size_t header_pos = m->count; + + /* sync binder / not one way */ + binder_inner_proc_lock(proc); + for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n)) { + struct binder_thread *thread = rb_entry(n, struct binder_thread, rb_node); + struct binder_transaction *t = thread->transaction_stack; + while (t) { + if (t->from == thread) { + print_binder_transaction_brief_ilocked(m, "\t", t, timestamp); + t = t->from_parent; + } else if (t->to_thread == thread) { + t = t->to_parent; + } else { + t = NULL; + } + } + } + + /* async binder / one way */ + for (n = rb_first(&proc->nodes); n != NULL; n = rb_next(n)) { + struct binder_node *node = rb_entry(n, struct binder_node, rb_node); + /* + * take a temporary reference on the node so it + * survives and isn't removed from the tree + * while we print it. + */ + binder_inc_node_tmpref_ilocked(node); + /* Need to drop inner lock to take node lock */ + binder_inner_proc_unlock(proc); + if (last_node) + binder_put_node(last_node); + binder_node_inner_lock(node); + list_for_each_entry(w, &node->async_todo, entry) + print_binder_work_transaction_nilocked(m, "async\t", w, timestamp); + binder_node_inner_unlock(node); + last_node = node; + binder_inner_proc_lock(proc); + } + binder_inner_proc_unlock(proc); + + if (last_node) + binder_put_node(last_node); + + if (m->count == header_pos) + m->count = start_pos; +} + +static void print_binder_proc_brief(struct seq_file *m, + struct binder_proc *proc) +{ + struct binder_thread *thread = NULL; + int ready_threads = 0; + size_t free_async_space = binder_alloc_get_free_async_space(&proc->alloc); + + seq_printf(m, "%d\t", proc->pid); + seq_printf(m, "%s\t", proc->context->name); + + binder_inner_proc_lock(proc); + list_for_each_entry(thread, &proc->waiting_threads, waiting_thread_node) + ready_threads++; + + seq_printf(m, "%d\t%d\t%d\t%d" + "\t%zd\n", proc->requested_threads, + proc->requested_threads_started, proc->max_threads, + ready_threads, + free_async_space); + binder_inner_proc_unlock(proc); +} + +static int binder_transaction_proc_show(struct seq_file *m, void *unused) +{ + struct binder_proc *proc = NULL; + u64 now = 0; + + mutex_lock(&binder_procs_lock); + now = binder_clock(); + hlist_for_each_entry(proc, &binder_procs, proc_node) + print_binder_transaction_brief(m, proc, now); + + seq_printf(m, "\npid\tcontext\t\trequest\tstarted\tmax\tready\tfree_async_space\n"); + hlist_for_each_entry(proc, &binder_procs, proc_node) + print_binder_proc_brief(m, proc); + mutex_unlock(&binder_procs_lock); + + return 0; +} + +#endif + static int __init init_binder_device(const char *name) { int ret; @@ -6209,6 +6397,13 @@ static int __init binder_init(void) binder_debugfs_dir_entry_root, &binder_transaction_log_failed, &binder_transaction_log_fops); +#ifdef CONFIG_BINDER_TRANSACTION_PROC_BRIEF + debugfs_create_file("transaction_proc", + S_IRUGO, + binder_debugfs_dir_entry_root, + NULL, + &binder_transaction_proc_fops); +#endif } if (!IS_ENABLED(CONFIG_ANDROID_BINDERFS) &&