linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Rasmus Villemoes <linux@rasmusvillemoes.dk>
To: Tejun Heo <tj@kernel.org>, Andrew Morton <akpm@linux-foundation.org>
Cc: linux-kernel@vger.kernel.org,
	Lai Jiangshan <jiangshanlai@gmail.com>,
	Jens Axboe <axboe@kernel.dk>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	Rasmus Villemoes <linux@rasmusvillemoes.dk>
Subject: [RFC 04/10] lib/tida.c: a very simple integer id allocator
Date: Thu,  8 Dec 2016 02:22:59 +0100	[thread overview]
Message-ID: <1481160187-9652-5-git-send-email-linux@rasmusvillemoes.dk> (raw)
In-Reply-To: <1481160187-9652-1-git-send-email-linux@rasmusvillemoes.dk>

The idr-based id allocator ida has a rather large memory footprint
(despite claims to the contrary). For example, on my laptop, each of
the six idas associated to the workqueues uses more than 16 KB of
memory (most of which sits unused in the embedded idr structure), even
though _combined_ they have only handed out a little over 100 ids in
their lifetime. That's about 1KB of overhead per id, which is rather
far from "each id only occupies a bit".

This introduces tida (t for tiny, trivial, whatever). Initially we
only support allocating the smallest available id, but this can
already replace many uses of ida throughout the tree.

It shouldn't be that hard to implement e.g. tida_get_min() or
tida_get_exact() which might make this capable of replacing more ida
instances.

Signed-off-by: Rasmus Villemoes <linux@rasmusvillemoes.dk>
---
 include/linux/tida.h |  26 +++++++++++++
 lib/Makefile         |   2 +-
 lib/tida.c           | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 130 insertions(+), 1 deletion(-)
 create mode 100644 include/linux/tida.h
 create mode 100644 lib/tida.c

diff --git a/include/linux/tida.h b/include/linux/tida.h
new file mode 100644
index 000000000000..9aa3ad96a632
--- /dev/null
+++ b/include/linux/tida.h
@@ -0,0 +1,26 @@
+#ifndef __LINUX_TIDA_H__
+#define __LINUX_TIDA_H__
+
+#include <linux/types.h>
+#include <linux/spinlock.h>
+
+struct tida {
+	unsigned long	*bits;
+	unsigned long	alloc;
+	spinlock_t	lock;
+	int		hint;
+};
+
+#define TIDA_INIT(name)				\
+	{ .lock = __SPIN_LOCK_UNLOCKED(name.lock), }
+
+#define DEFINE_TIDA(name) struct tida name = TIDA_INIT(name)
+
+void tida_init(struct tida *tida);
+void tida_destroy(struct tida *tida);
+
+int tida_get(struct tida *tida, gfp_t gfp);
+void tida_put(struct tida *tida, int id);
+
+
+#endif /* __LINUX_TIDA_H__ */
diff --git a/lib/Makefile b/lib/Makefile
index 50144a3aeebd..e6f5b9896bbd 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -18,7 +18,7 @@ KCOV_INSTRUMENT_dynamic_debug.o := n
 
 lib-y := ctype.o string.o vsprintf.o cmdline.o \
 	 rbtree.o radix-tree.o dump_stack.o timerqueue.o\
-	 idr.o int_sqrt.o extable.o \
+	 idr.o int_sqrt.o extable.o tida.o \
 	 sha1.o chacha20.o md5.o irq_regs.o argv_split.o \
 	 flex_proportions.o ratelimit.o show_mem.o \
 	 is_single_threaded.o plist.o decompress.o kobject_uevent.o \
diff --git a/lib/tida.c b/lib/tida.c
new file mode 100644
index 000000000000..1ea0deb6fa64
--- /dev/null
+++ b/lib/tida.c
@@ -0,0 +1,103 @@
+#include <linux/bitmap.h>
+#include <linux/bitops.h>
+#include <linux/export.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/tida.h>
+
+/*
+ * An extremely simple integer id allocator with small memory
+ * footprint, mostly useful for cases where up to a few hundred ids
+ * get allocated.
+ *
+ * Note that the backing bitmap is never shrunk.
+ */
+
+/*
+ * Invariant:
+ *
+ *   0 <= tida->hint
+ *     <= find_next_zero_bit(tida->bits, tida->alloc, 0)
+ *     <= tida->alloc.
+ */
+
+static int
+tida_expand(struct tida *tida, gfp_t gfp, unsigned long *flags)
+	__releases(tida->lock)
+	__acquires(tida->lock)
+{
+	unsigned long newalloc, oldalloc = tida->alloc;
+	unsigned long *bits;
+
+	newalloc = oldalloc ? 2 * oldalloc : BITS_PER_LONG;
+
+	spin_unlock_irqrestore(&tida->lock, *flags);
+	bits = kcalloc(BITS_TO_LONGS(newalloc), sizeof(*bits), gfp);
+	spin_lock_irqsave(&tida->lock, *flags);
+
+	if (!bits)
+		return -ENOMEM;
+
+	if (tida->alloc < newalloc) {
+		memcpy(bits, tida->bits, tida->alloc/8);
+		tida->alloc = newalloc;
+		swap(tida->bits, bits);
+	}
+	kfree(bits);
+
+	return 0;
+}
+
+int
+tida_get(struct tida *tida, gfp_t gfp)
+{
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&tida->lock, flags);
+	while (1) {
+		/* find_next_zero_bit is fine with a NULL bitmap as long as size is 0 */
+		ret = find_next_zero_bit(tida->bits, tida->alloc, tida->hint);
+		if (ret < tida->alloc)
+			break;
+		ret = tida_expand(tida, gfp, &flags);
+		if (ret < 0)
+			goto out;
+	}
+
+	__set_bit(ret, tida->bits);
+	tida->hint = ret+1;
+out:
+	spin_unlock_irqrestore(&tida->lock, flags);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(tida_get);
+
+void
+tida_put(struct tida *tida, int id)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&tida->lock, flags);
+	__clear_bit(id, tida->bits);
+	if (id < tida->hint)
+		tida->hint = id;
+	spin_unlock_irqrestore(&tida->lock, flags);
+}
+EXPORT_SYMBOL_GPL(tida_put);
+
+void
+tida_init(struct tida *tida)
+{
+	memset(tida, 0, sizeof(*tida));
+	spin_lock_init(&tida->lock);
+}
+EXPORT_SYMBOL_GPL(tida_init);
+
+void
+tida_destroy(struct tida *tida)
+{
+	kfree(tida->bits);
+}
+EXPORT_SYMBOL_GPL(tida_destroy);
-- 
2.1.4

  parent reply	other threads:[~2016-12-08  1:24 UTC|newest]

Thread overview: 25+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-12-08  1:22 [RFC 00/10] implement alternative and much simpler id allocator Rasmus Villemoes
2016-12-08  1:22 ` [RFC 01/10] lib/idr.c: reused free bitmaps are already clear Rasmus Villemoes
2016-12-08  1:22 ` [RFC 02/10] lib/idr.c: delete useless condition Rasmus Villemoes
2016-12-08  1:22 ` [RFC 03/10] lib/idr.c: only fill ida->idr when needed Rasmus Villemoes
2016-12-08  1:22 ` Rasmus Villemoes [this message]
2016-12-08  1:23 ` [RFC 05/10] kernel/workqueue.c: replace id allocator ida with tida Rasmus Villemoes
2016-12-08  1:23 ` [RFC 06/10] block: use tida as small id allocator Rasmus Villemoes
2016-12-08  3:56   ` Jens Axboe
2016-12-08 11:02     ` Greg Kroah-Hartman
2016-12-08  1:23 ` [RFC 07/10] drivers/base/platform.c: use simpler " Rasmus Villemoes
2016-12-08  1:23 ` [RFC 08/10] lib/tida.c: introduce tida_get_above Rasmus Villemoes
2016-12-08  1:23 ` [RFC 09/10] drm: use simpler id allocator Rasmus Villemoes
2016-12-08  1:23 ` [RFC 10/10] fs/devpts: use tida for id allocation Rasmus Villemoes
2016-12-09 13:49 ` [RFC 00/10] implement alternative and much simpler id allocator Tejun Heo
2016-12-09 22:01 ` Andrew Morton
2016-12-12 17:09   ` Tejun Heo
2016-12-12 17:35     ` Matthew Wilcox
2016-12-12 18:05       ` Tejun Heo
2016-12-16 19:14   ` Matthew Wilcox
2016-12-16 20:32     ` Rasmus Villemoes
2016-12-16 21:09       ` Matthew Wilcox
2016-12-17 13:28       ` Matthew Wilcox
2016-12-22 23:46         ` Rasmus Villemoes
2016-12-23 17:03           ` Matthew Wilcox
2016-12-18  2:42       ` Matthew Wilcox

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1481160187-9652-5-git-send-email-linux@rasmusvillemoes.dk \
    --to=linux@rasmusvillemoes.dk \
    --cc=akpm@linux-foundation.org \
    --cc=axboe@kernel.dk \
    --cc=gregkh@linuxfoundation.org \
    --cc=jiangshanlai@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=tj@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).