This patch use kmem_cache to allocate/free binder objects.

It will have better memory efficiency. And we can also get
object usage details in /sys/kernel/slab/* for futher analysis.

Signed-off-by: Ganesh Mahendran <[email protected]>
---
 drivers/android/binder.c | 127 ++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 104 insertions(+), 23 deletions(-)

diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index 3c71b98..f1f8362 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -54,6 +54,14 @@
 static HLIST_HEAD(binder_deferred_list);
 static HLIST_HEAD(binder_dead_nodes);
 
+static struct kmem_cache *binder_proc_cachep;
+static struct kmem_cache *binder_thread_cachep;
+static struct kmem_cache *binder_node_cachep;
+static struct kmem_cache *binder_ref_cachep;
+static struct kmem_cache *binder_transaction_cachep;
+static struct kmem_cache *binder_work_cachep;
+static struct kmem_cache *binder_ref_death_cachep;
+
 static struct dentry *binder_debugfs_dir_entry_root;
 static struct dentry *binder_debugfs_dir_entry_proc;
 static struct binder_node *binder_context_mgr_node;
@@ -902,7 +910,7 @@ static struct binder_node *binder_new_node(struct 
binder_proc *proc,
                        return NULL;
        }
 
-       node = kzalloc(sizeof(*node), GFP_KERNEL);
+       node = kmem_cache_zalloc(binder_node_cachep, GFP_KERNEL);
        if (node == NULL)
                return NULL;
        binder_stats_created(BINDER_STAT_NODE);
@@ -992,7 +1000,7 @@ static int binder_dec_node(struct binder_node *node, int 
strong, int internal)
                                             "dead node %d deleted\n",
                                             node->debug_id);
                        }
-                       kfree(node);
+                       kmem_cache_free(binder_node_cachep, node);
                        binder_stats_deleted(BINDER_STAT_NODE);
                }
        }
@@ -1043,7 +1051,7 @@ static struct binder_ref *binder_get_ref_for_node(struct 
binder_proc *proc,
                else
                        return ref;
        }
-       new_ref = kzalloc(sizeof(*ref), GFP_KERNEL);
+       new_ref = kmem_cache_zalloc(binder_ref_cachep, GFP_KERNEL);
        if (new_ref == NULL)
                return NULL;
        binder_stats_created(BINDER_STAT_REF);
@@ -1108,10 +1116,10 @@ static void binder_delete_ref(struct binder_ref *ref)
                             "%d delete ref %d desc %d has death 
notification\n",
                              ref->proc->pid, ref->debug_id, ref->desc);
                list_del(&ref->death->work.entry);
-               kfree(ref->death);
+               kmem_cache_free(binder_ref_death_cachep, ref->death);
                binder_stats_deleted(BINDER_STAT_DEATH);
        }
-       kfree(ref);
+       kmem_cache_free(binder_ref_cachep, ref);
        binder_stats_deleted(BINDER_STAT_REF);
 }
 
@@ -1183,7 +1191,7 @@ static void binder_pop_transaction(struct binder_thread 
*target_thread,
        t->need_reply = 0;
        if (t->buffer)
                t->buffer->transaction = NULL;
-       kfree(t);
+       kmem_cache_free(binder_transaction_cachep, t);
        binder_stats_deleted(BINDER_STAT_TRANSACTION);
 }
 
@@ -1444,14 +1452,14 @@ static void binder_transaction(struct binder_proc *proc,
        e->to_proc = target_proc->pid;
 
        /* TODO: reuse incoming transaction for reply */
-       t = kzalloc(sizeof(*t), GFP_KERNEL);
+       t = kmem_cache_zalloc(binder_transaction_cachep, GFP_KERNEL);
        if (t == NULL) {
                return_error = BR_FAILED_REPLY;
                goto err_alloc_t_failed;
        }
        binder_stats_created(BINDER_STAT_TRANSACTION);
 
-       tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL);
+       tcomplete = kmem_cache_zalloc(binder_work_cachep, GFP_KERNEL);
        if (tcomplete == NULL) {
                return_error = BR_FAILED_REPLY;
                goto err_alloc_tcomplete_failed;
@@ -1742,10 +1750,10 @@ static void binder_transaction(struct binder_proc *proc,
        t->buffer->transaction = NULL;
        binder_free_buf(target_proc, t->buffer);
 err_binder_alloc_buf_failed:
-       kfree(tcomplete);
+       kmem_cache_free(binder_work_cachep, tcomplete);
        binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE);
 err_alloc_tcomplete_failed:
-       kfree(t);
+       kmem_cache_free(binder_transaction_cachep, t);
        binder_stats_deleted(BINDER_STAT_TRANSACTION);
 err_alloc_t_failed:
 err_bad_call_stack:
@@ -2039,7 +2047,7 @@ static int binder_thread_write(struct binder_proc *proc,
                                                proc->pid, thread->pid);
                                        break;
                                }
-                               death = kzalloc(sizeof(*death), GFP_KERNEL);
+                               death = 
kmem_cache_zalloc(binder_ref_death_cachep, GFP_KERNEL);
                                if (death == NULL) {
                                        thread->return_error = BR_ERROR;
                                        
binder_debug(BINDER_DEBUG_FAILED_TRANSACTION,
@@ -2282,7 +2290,7 @@ static int binder_thread_read(struct binder_proc *proc,
                                     proc->pid, thread->pid);
 
                        list_del(&w->entry);
-                       kfree(w);
+                       kmem_cache_free(binder_work_cachep, w);
                        binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE);
                } break;
                case BINDER_WORK_NODE: {
@@ -2342,7 +2350,7 @@ static int binder_thread_read(struct binder_proc *proc,
                                                     (u64)node->ptr,
                                                     (u64)node->cookie);
                                        rb_erase(&node->rb_node, &proc->nodes);
-                                       kfree(node);
+                                       kmem_cache_free(binder_node_cachep, 
node);
                                        binder_stats_deleted(BINDER_STAT_NODE);
                                } else {
                                        binder_debug(BINDER_DEBUG_INTERNAL_REFS,
@@ -2383,7 +2391,7 @@ static int binder_thread_read(struct binder_proc *proc,
 
                        if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION) {
                                list_del(&w->entry);
-                               kfree(death);
+                               kmem_cache_free(binder_ref_death_cachep, death);
                                binder_stats_deleted(BINDER_STAT_DEATH);
                        } else
                                list_move(&w->entry, &proc->delivered_death);
@@ -2463,7 +2471,7 @@ static int binder_thread_read(struct binder_proc *proc,
                        thread->transaction_stack = t;
                } else {
                        t->buffer->transaction = NULL;
-                       kfree(t);
+                       kmem_cache_free(binder_transaction_cachep, t);
                        binder_stats_deleted(BINDER_STAT_TRANSACTION);
                }
                break;
@@ -2508,14 +2516,14 @@ static void binder_release_work(struct list_head *list)
                                        "undelivered transaction %d\n",
                                        t->debug_id);
                                t->buffer->transaction = NULL;
-                               kfree(t);
+                               kmem_cache_free(binder_transaction_cachep, t);
                                binder_stats_deleted(BINDER_STAT_TRANSACTION);
                        }
                } break;
                case BINDER_WORK_TRANSACTION_COMPLETE: {
                        binder_debug(BINDER_DEBUG_DEAD_TRANSACTION,
                                "undelivered TRANSACTION_COMPLETE\n");
-                       kfree(w);
+                       kmem_cache_free(binder_work_cachep, w);
                        binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE);
                } break;
                case BINDER_WORK_DEAD_BINDER_AND_CLEAR:
@@ -2526,7 +2534,7 @@ static void binder_release_work(struct list_head *list)
                        binder_debug(BINDER_DEBUG_DEAD_TRANSACTION,
                                "undelivered death notification, %016llx\n",
                                (u64)death->cookie);
-                       kfree(death);
+                       kmem_cache_free(binder_ref_death_cachep, death);
                        binder_stats_deleted(BINDER_STAT_DEATH);
                } break;
                default:
@@ -2556,7 +2564,7 @@ static struct binder_thread *binder_get_thread(struct 
binder_proc *proc)
                        break;
        }
        if (*p == NULL) {
-               thread = kzalloc(sizeof(*thread), GFP_KERNEL);
+               thread = kmem_cache_zalloc(binder_thread_cachep, GFP_KERNEL);
                if (thread == NULL)
                        return NULL;
                binder_stats_created(BINDER_STAT_THREAD);
@@ -2609,7 +2617,7 @@ static int binder_free_thread(struct binder_proc *proc,
        if (send_reply)
                binder_send_failed_reply(send_reply, BR_DEAD_REPLY);
        binder_release_work(&thread->todo);
-       kfree(thread);
+       kmem_cache_free(binder_thread_cachep, thread);
        binder_stats_deleted(BINDER_STAT_THREAD);
        return active_transactions;
 }
@@ -2973,7 +2981,7 @@ static int binder_open(struct inode *nodp, struct file 
*filp)
        binder_debug(BINDER_DEBUG_OPEN_CLOSE, "binder_open: %d:%d\n",
                     current->group_leader->pid, current->pid);
 
-       proc = kzalloc(sizeof(*proc), GFP_KERNEL);
+       proc = kmem_cache_zalloc(binder_proc_cachep, GFP_KERNEL);
        if (proc == NULL)
                return -ENOMEM;
        get_task_struct(current);
@@ -3053,7 +3061,7 @@ static int binder_node_release(struct binder_node *node, 
int refs)
        binder_release_work(&node->async_todo);
 
        if (hlist_empty(&node->refs)) {
-               kfree(node);
+               kmem_cache_free(binder_node_cachep, node);
                binder_stats_deleted(BINDER_STAT_NODE);
 
                return refs;
@@ -3190,7 +3198,7 @@ static void binder_deferred_release(struct binder_proc 
*proc)
                     __func__, proc->pid, threads, nodes, incoming_refs,
                     outgoing_refs, active_transactions, buffers, page_count);
 
-       kfree(proc);
+       kmem_cache_free(binder_proc_cachep, proc);
 }
 
 static void binder_deferred_func(struct work_struct *work)
@@ -3691,10 +3699,83 @@ static int binder_transaction_log_show(struct seq_file 
*m, void *unused)
 BINDER_DEBUG_ENTRY(transactions);
 BINDER_DEBUG_ENTRY(transaction_log);
 
+static void binder_destroy_cache(void)
+{
+       if (binder_proc_cachep)
+               kmem_cache_destroy(binder_proc_cachep);
+
+       if (binder_thread_cachep)
+               kmem_cache_destroy(binder_thread_cachep);
+
+       if (binder_node_cachep)
+               kmem_cache_destroy(binder_node_cachep);
+
+       if (binder_ref_cachep)
+               kmem_cache_destroy(binder_ref_cachep);
+
+       if (binder_transaction_cachep)
+               kmem_cache_destroy(binder_transaction_cachep);
+
+       if (binder_work_cachep)
+               kmem_cache_destroy(binder_work_cachep);
+
+       if (binder_ref_death_cachep)
+               kmem_cache_destroy(binder_ref_death_cachep);
+}
+
+static int __init binder_create_cache(void)
+{
+       binder_proc_cachep = kmem_cache_create("binder_proc",
+                                       sizeof(struct binder_proc), 0, 0, NULL);
+       if (!binder_proc_cachep)
+               goto fail;
+
+       binder_thread_cachep = kmem_cache_create("binder_thread",
+                                       sizeof(struct binder_thread), 0, 0, 
NULL);
+       if (!binder_thread_cachep)
+               goto fail;
+
+       binder_node_cachep = kmem_cache_create("binder_node",
+                                       sizeof(struct binder_node), 0, 0, NULL);
+       if (!binder_node_cachep)
+               goto fail;
+
+       binder_ref_cachep = kmem_cache_create("binder_ref",
+                                       sizeof(struct binder_ref), 0, 0, NULL);
+       if (!binder_ref_cachep)
+               goto fail;
+
+       binder_transaction_cachep = kmem_cache_create("binder_transaction",
+                                       sizeof(struct binder_transaction), 0, 
0, NULL);
+       if (!binder_transaction_cachep)
+               goto fail;
+
+       binder_work_cachep = kmem_cache_create("binder_work",
+                                       sizeof(struct binder_work), 0, 0, NULL);
+       if (!binder_work_cachep)
+               goto fail;
+
+       binder_ref_death_cachep = kmem_cache_create("binder_ref_death",
+                                       sizeof(struct binder_ref_death), 0, 0, 
NULL);
+       if (!binder_ref_death_cachep)
+               goto fail;
+
+       return 0;
+
+fail:
+       binder_destroy_cache();
+       return -ENOMEM;
+}
+
 static int __init binder_init(void)
 {
        int ret;
 
+       if (binder_create_cache()) {
+               pr_err("binder cache creation failed\n");
+               return -ENOMEM;
+       }
+
        binder_debugfs_dir_entry_root = debugfs_create_dir("binder", NULL);
        if (binder_debugfs_dir_entry_root)
                binder_debugfs_dir_entry_proc = debugfs_create_dir("proc",
-- 
1.9.1

Reply via email to