From 9edb5a3677951072bc8e5178010493aea31558a9 Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Fri, 28 Feb 2014 15:32:06 -0500 Subject: [PATCH] attempt to lower idle CPU usage when reading list/blist --- kernel-module/xt_MEDIAPROXY.c | 267 +++++++++++++++++++++++----------- 1 file changed, 186 insertions(+), 81 deletions(-) diff --git a/kernel-module/xt_MEDIAPROXY.c b/kernel-module/xt_MEDIAPROXY.c index e3671fb82..a3c6df8b8 100644 --- a/kernel-module/xt_MEDIAPROXY.c +++ b/kernel-module/xt_MEDIAPROXY.c @@ -153,6 +153,16 @@ struct mediaproxy_target { struct mp_crypto_context encrypt; }; +struct mp_bitfield { + unsigned long b[256 / (sizeof(unsigned long) * 8)]; + unsigned int used; +}; + +struct mp_bucket { + struct mp_bitfield targets; + struct mediaproxy_target *target[256]; +}; + struct mediaproxy_table { atomic_t refcnt; rwlock_t target_lock; @@ -165,9 +175,9 @@ struct mediaproxy_table { struct proc_dir_entry *list; struct proc_dir_entry *blist; - struct mediaproxy_target **target[256]; + struct mp_bitfield buckets; + struct mp_bucket *bucket[256]; - unsigned int buckets; unsigned int targets; }; @@ -481,6 +491,7 @@ static void clear_proc(struct proc_dir_entry **e) { static void table_push(struct mediaproxy_table *t) { int i, j; + struct mp_bucket *b; if (!t) return; @@ -491,19 +502,20 @@ static void table_push(struct mediaproxy_table *t) { DBG("Freeing table\n"); for (i = 0; i < 256; i++) { - if (!t->target[i]) + b = t->bucket[i]; + if (!b) continue; for (j = 0; j < 256; j++) { - if (!t->target[i][j]) + if (!b->target[j]) continue; - t->target[i][j]->table = -1; - target_push(t->target[i][j]); - t->target[i][j] = NULL; + b->target[j]->table = -1; + target_push(b->target[j]); + b->target[j] = NULL; } - kfree(t->target[i]); - t->target[i] = NULL; + kfree(b); + t->bucket[i] = NULL; } clear_proc(&t->status); @@ -599,7 +611,7 @@ static ssize_t proc_status(struct file *f, char __user *b, size_t l, loff_t *o) len += sprintf(buf + len, "Refcount: %u\n", atomic_read(&t->refcnt) - 1); len += sprintf(buf + len, "Control PID: %u\n", t->pid); len += sprintf(buf + len, "Targets: %u\n", t->targets); - len += sprintf(buf + len, "Buckets: %u\n", t->buckets); + len += sprintf(buf + len, "Buckets: %u\n", t->buckets.used); read_unlock_irqrestore(&t->target_lock, flags); table_push(t); @@ -664,6 +676,105 @@ static int proc_main_list_show(struct seq_file *f, void *v) { +static inline unsigned char bitfield_next_slot(unsigned int slot) { + unsigned char c; + c = slot * (sizeof(unsigned long) * 8); + c += sizeof(unsigned long) * 8; + return c; +} +static inline unsigned int bitfield_slot(unsigned char i) { + return i / (sizeof(unsigned long) * 8); +} +static inline unsigned int bitfield_bit(unsigned char i) { + return i % (sizeof(unsigned long) * 8); +} +static inline void bitfield_set(struct mp_bitfield *bf, unsigned char i) { + unsigned int b, m; + unsigned long k; + + b = bitfield_slot(i); + m = bitfield_bit(i); + k = 1 << m; + if ((bf->b[b] & k)) + return; + bf->b[b] |= k; + bf->used++; +} +static inline void bitfield_clear(struct mp_bitfield *bf, unsigned char i) { + unsigned int b, m; + unsigned long k; + + b = bitfield_slot(i); + m = bitfield_bit(i); + k = 1 << m; + if (!(bf->b[b] & k)) + return; + bf->b[b] &= ~k; + bf->used--; +} +static inline struct mediaproxy_target *find_next_target(struct mediaproxy_table *t, int *port) { + unsigned long flags; + struct mp_bucket *b; + unsigned char hi, lo; + unsigned int hi_b, lo_b; + struct mediaproxy_target *g; + + if (*port < 0 || *port > 0xffff) + return NULL; + + hi = (*port & 0xff00) >> 8; + lo = *port & 0xff; + + read_lock_irqsave(&t->target_lock, flags); + + for (;;) { + hi_b = bitfield_slot(hi); + if (!t->buckets.b[hi_b]) { + hi = bitfield_next_slot(hi_b); + lo = 0; + goto next; + } + + b = t->bucket[hi]; + if (!b) { + hi++; + lo = 0; + goto next; + } + + lo_b = bitfield_slot(lo); + if (!b->targets.b[lo_b]) { + lo = bitfield_next_slot(lo_b); + goto next_lo; + } + + g = b->target[lo]; + if (!g) { + lo++; + goto next_lo; + } + + target_hold(g); + break; + +next_lo: + if (!lo) + hi++; +next: + if (!hi && !lo) + break; + } + + read_unlock_irqrestore(&t->target_lock, flags); + + *port = (hi << 8) | lo; + (*port)++; + + return g; +} + + + static int proc_blist_open(struct inode *i, struct file *f) { u_int32_t id; struct mediaproxy_table *t; @@ -700,6 +811,7 @@ static ssize_t proc_blist_read(struct file *f, char __user *b, size_t l, loff_t int err; struct mediaproxy_target *g; unsigned long flags; + int port; if (l != sizeof(op)) return -EINVAL; @@ -712,15 +824,12 @@ static ssize_t proc_blist_read(struct file *f, char __user *b, size_t l, loff_t if (!t) return -ENOENT; - for (;;) { - err = 0; - if (*o > 0xffff) - goto err; - - g = get_target(t, (*o)++); - if (g) - break; - } + port = (int) *o; + g = find_next_target(t, &port); + *o = port; + err = 0; + if (!g) + goto err; memset(&op, 0, sizeof(op)); memcpy(&op.target, &g->target, sizeof(op.target)); @@ -789,46 +898,19 @@ static void proc_list_stop(struct seq_file *f, void *v) { static void *proc_list_next(struct seq_file *f, void *v, loff_t *o) { /* v is invalid */ u_int32_t id = (u_int32_t) (unsigned long) f->private; - struct mediaproxy_target *g = NULL; struct mediaproxy_table *t; - u_int16_t port; - unsigned char hi, lo; - unsigned long flags; + struct mediaproxy_target *g; + int port; - if (*o < 0 || *o > 0xffff) - return NULL; - port = (u_int16_t) *o; + port = (int) *o; t = get_table(id); if (!t) return NULL; - hi = (port & 0xff00) >> 8; - lo = port & 0xff; - - read_lock_irqsave(&t->target_lock, flags); - for (;;) { - lo++; /* will make the iteration start from 1 */ - if (lo == 0) { - hi++; - if (hi == 0) - break; - } - if (!t->target[hi]) { - lo = 0xff; - continue; - } - - g = t->target[hi][lo]; - if (!g) - continue; - - target_hold(g); - break; - } - read_unlock_irqrestore(&t->target_lock, flags); + g = find_next_target(t, &port); - *o = (hi << 8) | lo; + *o = port; table_push(t); return g; @@ -902,7 +984,8 @@ static int proc_list_show(struct seq_file *f, void *v) { static int table_del_target(struct mediaproxy_table *t, u_int16_t port) { unsigned char hi, lo; - struct mediaproxy_target *g; + struct mp_bucket *b; + struct mediaproxy_target *g = NULL; unsigned long flags; if (!port) @@ -912,15 +995,30 @@ static int table_del_target(struct mediaproxy_table *t, u_int16_t port) { lo = port & 0xff; write_lock_irqsave(&t->target_lock, flags); - g = t->target[hi] ? t->target[hi][lo] : NULL; - if (g) { - t->target[hi][lo] = NULL; - t->targets--; + b = t->bucket[hi]; + if (!b) + goto out; + g = b->target[lo]; + if (!g) + goto out; + + b->target[lo] = NULL; + bitfield_clear(&b->targets, lo); + t->targets--; + if (!b->targets.used) { + t->bucket[hi] = NULL; + bitfield_clear(&t->buckets, hi); } + else + b = NULL; + +out: write_unlock_irqrestore(&t->target_lock, flags); if (!g) return -ENOENT; + if (b) + kfree(b); target_push(g); @@ -1247,6 +1345,7 @@ error: + static void crypto_context_init(struct mp_crypto_context *c, struct mediaproxy_srtp *s) { c->cipher = &mp_ciphers[s->cipher]; c->hmac = &mp_hmacs[s->hmac]; @@ -1255,7 +1354,7 @@ static void crypto_context_init(struct mp_crypto_context *c, struct mediaproxy_s static int table_new_target(struct mediaproxy_table *t, struct mediaproxy_target_info *i, int update) { unsigned char hi, lo; struct mediaproxy_target *g; - struct mediaproxy_target **gp; + struct mp_bucket *b, *ba = NULL; struct mediaproxy_target *og = NULL; int err; unsigned long flags; @@ -1302,31 +1401,37 @@ static int table_new_target(struct mediaproxy_table *t, struct mediaproxy_target if (err) goto fail2; - err = -ENOMEM; - if (update) - gp = NULL; - else { - gp = kmalloc(sizeof(void *) * 256, GFP_KERNEL); - if (!gp) - goto fail2; - memset(gp, 0, sizeof(void *) * 256); - } - hi = (i->target_port & 0xff00) >> 8; lo = i->target_port & 0xff; write_lock_irqsave(&t->target_lock, flags); - if (!t->target[hi]) { + if (!(b = t->bucket[hi])) { err = -ENOENT; if (update) goto fail4; - t->target[hi] = gp; - gp = NULL; - t->buckets++; + + write_unlock_irqrestore(&t->target_lock, flags); + + b = kmalloc(sizeof(*b), GFP_KERNEL); + err = -ENOMEM; + if (!b) + goto fail2; + memset(b, 0, sizeof(*b)); + + write_lock_irqsave(&t->target_lock, flags); + + if (!t->bucket[hi]) { + t->bucket[hi] = b; + bitfield_set(&t->buckets, hi); + } + else { + ba = b; + b = t->bucket[hi]; + } } if (update) { err = -ENOENT; - og = t->target[hi][lo]; + og = b->target[lo]; if (!og) goto fail4; @@ -1336,18 +1441,18 @@ static int table_new_target(struct mediaproxy_table *t, struct mediaproxy_target } else { err = -EEXIST; - if (t->target[hi][lo]) + if (b->target[lo]) goto fail4; + bitfield_set(&b->targets, lo); + t->targets++; } - t->target[hi][lo] = g; + b->target[lo] = g; g = NULL; - if (!update) - t->targets++; write_unlock_irqrestore(&t->target_lock, flags); - if (gp) - kfree(gp); + if (ba) + kfree(ba); if (og) target_push(og); @@ -1355,8 +1460,8 @@ static int table_new_target(struct mediaproxy_table *t, struct mediaproxy_target fail4: write_unlock_irqrestore(&t->target_lock, flags); - if (gp) - kfree(gp); + if (ba) + kfree(ba); fail2: kfree(g); fail1: @@ -1381,7 +1486,7 @@ static struct mediaproxy_target *get_target(struct mediaproxy_table *t, u_int16_ lo = port & 0xff; read_lock_irqsave(&t->target_lock, flags); - r = t->target[hi] ? t->target[hi][lo] : NULL; + r = t->bucket[hi] ? t->bucket[hi]->target[lo] : NULL; if (r) target_hold(r); read_unlock_irqrestore(&t->target_lock, flags);