All of lore.kernel.org
 help / color / mirror / Atom feed
From: Pauli Nieminen <suokkos@gmail.com>
To: dri-devel@lists.sourceforge.net
Subject: [PATCH 5/7] drm/ttm: Dynamically scale the allocation sizes of pools.
Date: Wed, 17 Mar 2010 22:50:04 +0200	[thread overview]
Message-ID: <1268859006-18707-6-git-send-email-suokkos@gmail.com> (raw)
In-Reply-To: <1268859006-18707-5-git-send-email-suokkos@gmail.com>

If we need large number of pages allocations in short time frame allocating
large number of pages in single operation performs better than many small
operations. If there is less allocation operations allocating large number of
pages in a fill operation would waste memory and performance.

The allocation sizes of pools is doubled everytime refill is done more than
once between shrink calls. While the size is halfed happens if there is no
refills for manager->shrink_alloc_interval seconds.

Signed-off-by: Pauli Nieminen <suokkos@gmail.com>
---
 drivers/gpu/drm/ttm/ttm_page_alloc.c |  105 ++++++++++++++++++++++++++--------
 1 files changed, 81 insertions(+), 24 deletions(-)

diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc.c b/drivers/gpu/drm/ttm/ttm_page_alloc.c
index 206bee9..af91994 100644
--- a/drivers/gpu/drm/ttm/ttm_page_alloc.c
+++ b/drivers/gpu/drm/ttm/ttm_page_alloc.c
@@ -47,8 +47,9 @@
 
 
 #define NUM_PAGES_TO_ALLOC		256
-#define SMALL_ALLOCATION		64
+#define SMALL_ALLOCATION		16
 #define FREE_ALL_PAGES			1
+#define SHRINK_ALLOC_INTERVAL		8
 /* times are in msecs */
 #define PAGE_FREE_INTERVAL		1000
 
@@ -63,7 +64,10 @@
  * @gfp_flags: Flags to pass for alloc_page.
  * @npages: Number of pages in pool
  * @nlowpages: Minimum nubmer of pages in pool since previous shrink
+ * @freed_pages: Number of pages freed in this shrinker run.
  * @alloc_size: Allocation sizes of this pool.
+ * @last_refill: Number of shrink calls (with more than alloc_size pages free)
+ * since last refill call.
  * operation.
  */
 struct ttm_page_pool {
@@ -73,7 +77,9 @@ struct ttm_page_pool {
 	int			gfp_flags;
 	unsigned		npages;
 	unsigned		nlowpages;
+	unsigned		freed_pages;
 	unsigned		alloc_size;
+	unsigned		last_refill;
 	char			*name;
 	unsigned long		nfrees;
 	unsigned long		nrefills;
@@ -101,6 +107,7 @@ struct ttm_pool_manager {
 	atomic_t		page_alloc_inited;
 	struct delayed_work	work;
 	unsigned		small_allocation;
+	unsigned		shrink_alloc_interval;
 
 	union {
 		struct ttm_page_pool	pools[NUM_POOLS];
@@ -199,17 +206,33 @@ static void ttm_pages_put(struct page *pages[], unsigned npages)
  **/
 static bool ttm_reset_pools(struct ttm_pool_manager *manager)
 {
+	struct ttm_page_pool *pool;
 	unsigned long irq_flags;
-	bool pages_in_pool = false;
+	bool more_delayed_work = false;
 	unsigned i;
 	for (i = 0; i < NUM_POOLS; ++i) {
-		spin_lock_irqsave(&manager->pools[i].lock, irq_flags);
-		manager->pools[i].nlowpages = manager->pools[i].npages;
-		pages_in_pool = pages_in_pool
-			|| manager->pools[i].npages > manager->pools[i].alloc_size;
-		spin_unlock_irqrestore(&manager->pools[i].lock, irq_flags);
+		pool = &manager->pools[i];
+		spin_lock_irqsave(&pool->lock, irq_flags);
+		/**
+		 * Check if pool has shrink work in a second.
+		 **/
+		if (pool->alloc_size > manager->small_allocation) {
+			/* Reduce pool sizes if there is no refills for
+			 * manager->shrink_alloc_interval seconds. */
+			if (++pool->last_refill % manager->shrink_alloc_interval == 0)
+				pool->alloc_size /= 2;
+
+			more_delayed_work = true;
+		} else
+			more_delayed_work = more_delayed_work
+				|| pool->npages > pool->alloc_size;
+
+		pool->nlowpages = pool->npages;
+		pool->freed_pages = 0;
+
+		spin_unlock_irqrestore(&pool->lock, irq_flags);
 	}
-	return pages_in_pool;
+	return more_delayed_work;
 }
 
 /**
@@ -220,16 +243,19 @@ static bool ttm_reset_pools(struct ttm_pool_manager *manager)
 static unsigned ttm_page_pool_get_npages_to_free_locked(struct ttm_page_pool *pool)
 {
 	unsigned r;
+	unsigned low = pool->nlowpages - pool->freed_pages;
+	if (pool->nlowpages < pool->freed_pages)
+		low = 0;
 	/* If less than alloc sizes was the lowest number of pages we don't
 	 * free any */
-	if (pool->nlowpages < pool->alloc_size)
+	if (low < pool->alloc_size)
 		return 0;
 	/* leave half of unused pages to pool */
-	r = (pool->nlowpages - pool->alloc_size)/2;
+	r = (low - pool->alloc_size)/2;
 	if (r)
 		return r;
 	/* make sure we remove all pages even when there is rounding down */
-	if (pool->nlowpages)
+	if (low)
 		return 1;
 	return 0;
 }
@@ -251,12 +277,12 @@ static bool ttm_page_pool_free_pages_locked(struct ttm_page_pool *pool,
 	 */
 	tmp = 2*freed_pages;
 	/* protect against rounding errors */
-	if (tmp < pool->nlowpages) {
-		pool->nlowpages -= tmp;
+	if (tmp < pool->nlowpages - pool->freed_pages) {
+		pool->freed_pages += tmp;
 		return true;
 	}
 
-	pool->nlowpages = 0;
+	pool->freed_pages = pool->nlowpages;
 	return false;
 }
 
@@ -329,7 +355,7 @@ restart:
 	/* set nlowpages to zero to prevent extra freeing in thsi patch.
 	 * nlowpages is reseted later after all work has been finnished.
 	 **/
-	pool->nlowpages = 0;
+	pool->freed_pages = pool->nlowpages;
 
 	/* remove range of pages from the pool */
 	if (freed_pages)
@@ -516,6 +542,8 @@ static void ttm_page_pool_fill_locked(struct ttm_page_pool *pool,
 	struct page *p, *tmp;
 	int r;
 	unsigned cpages = 0;
+	unsigned alloc_size;
+	bool queue_shrink = false;
 	/**
 	 * Only allow one pool fill operation at a time.
 	 * If pool doesn't have enough pages for the allocation new pages are
@@ -528,6 +556,24 @@ static void ttm_page_pool_fill_locked(struct ttm_page_pool *pool,
 
 	if (count < _manager.small_allocation
 		&& count > pool->npages) {
+		/* Increase allocation sizes if we are refilling pool multiple
+		 * times between shrink calls. Clamp alloc size of the pool
+		 * to NUM_PAGES_TO_ALLOC * 2. */
+		if (pool->last_refill == 0
+			&& pool->alloc_size < NUM_PAGES_TO_ALLOC * 2) {
+			pool->alloc_size *= 2;
+			queue_shrink = true;
+		}
+
+		pool->last_refill = 0;
+		alloc_size = pool->alloc_size;
+
+		/* clamp size to NUM_PAGES_TO_ALLOC because it is maximum
+		 * number of pages in a single caching change.
+		 */
+		if (alloc_size > NUM_PAGES_TO_ALLOC)
+			alloc_size = NUM_PAGES_TO_ALLOC;
+
 		/* If allocation request is small and there is not enough
 		 * pages in pool we fill the pool first */
 		INIT_LIST_HEAD(&new_pages);
@@ -538,16 +584,20 @@ static void ttm_page_pool_fill_locked(struct ttm_page_pool *pool,
 		 */
 		spin_unlock_irqrestore(&pool->lock, irq_flags);
 		r = ttm_alloc_new_pages(&new_pages, pool->gfp_flags, ttm_flags,
-				cstate,	pool->alloc_size);
+				cstate,	alloc_size);
+		if (queue_shrink)
+			(void)queue_delayed_work(_manager.glob->swap_queue,
+					&_manager.work,
+					round_jiffies(_manager.free_interval));
 		spin_lock_irqsave(&pool->lock, irq_flags);
 
 		if (!r) {
 			list_splice(&new_pages, &pool->list);
 			++pool->nrefills;
-			pool->npages += pool->alloc_size;
+			pool->npages += alloc_size;
 			/* Have to remmber to update the low number of pages
 			 * too */
-			pool->nlowpages += pool->alloc_size;
+			pool->nlowpages += alloc_size;
 		} else {
 			printk(KERN_ERR "[ttm] Failed to fill pool (%p).", pool);
 			/* If we have any pages left put them to the pool. */
@@ -738,7 +788,9 @@ static void ttm_page_pool_init_locked(struct ttm_page_pool *pool, int flags,
 	pool->fill_lock = false;
 	INIT_LIST_HEAD(&pool->list);
 	pool->npages = pool->nlowpages = pool->nfrees = 0;
-	pool->alloc_size = NUM_PAGES_TO_ALLOC;
+	pool->last_refill = 0;
+	pool->freed_pages = 0;
+	pool->alloc_size = SMALL_ALLOCATION;
 	pool->gfp_flags = flags;
 	pool->name = name;
 }
@@ -762,10 +814,14 @@ int ttm_page_alloc_init(struct ttm_mem_global *glob)
 
 	_manager.free_interval = msecs_to_jiffies(PAGE_FREE_INTERVAL);
 	_manager.small_allocation = SMALL_ALLOCATION;
+	_manager.shrink_alloc_interval = SHRINK_ALLOC_INTERVAL;
 	_manager.glob = glob;
 
 	INIT_DELAYED_WORK(&_manager.work, ttm_pool_shrink);
 
+	(void)queue_delayed_work(_manager.glob->swap_queue,
+			&_manager.work,
+			round_jiffies(_manager.free_interval));
 	return 0;
 }
 
@@ -789,20 +845,21 @@ int ttm_page_alloc_debugfs(struct seq_file *m, void *data)
 {
 	struct ttm_page_pool *p;
 	unsigned i;
-	char *h[] = {"pool", "refills", "pages freed", "size", "min size"};
+	char *h[] = {"pool", "refills", "pages freed", "size", "min size",
+		"alloc size"};
 	if (atomic_read(&_manager.page_alloc_inited) == 0) {
 		seq_printf(m, "No pool allocator running.\n");
 		return 0;
 	}
-	seq_printf(m, "%6s %12s %13s %8s %8s\n",
-			h[0], h[1], h[2], h[3], h[4]);
+	seq_printf(m, "%6s %12s %13s %8s %8s %8s\n",
+			h[0], h[1], h[2], h[3], h[4], h[5]);
 	for (i = 0; i < NUM_POOLS; ++i) {
 		p = &_manager.pools[i];
 
-		seq_printf(m, "%6s %12ld %13ld %8d %8d\n",
+		seq_printf(m, "%6s %12ld %13ld %8d %8d %8d\n",
 				p->name, p->nrefills,
 				p->nfrees, p->npages,
-				p->nlowpages);
+				p->nlowpages, p->alloc_size);
 	}
 	return 0;
 }
-- 
1.6.3.3


------------------------------------------------------------------------------
Download Intel&#174; Parallel Studio Eval
Try the new software tools for yourself. Speed compiling, find bugs
proactively, and fine-tune applications for parallel performance.
See why Intel Parallel Studio got high marks during beta.
http://p.sf.net/sfu/intel-sw-dev
--

  reply	other threads:[~2010-03-17 20:50 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-03-17 20:49 [PATCH 0/7] drm/ttm: Pool allocator Pauli Nieminen
2010-03-17 20:50 ` [PATCH 1/7] drm/ttm: add pool wc/uc page allocator Pauli Nieminen
2010-03-17 20:50   ` [PATCH 2/7] drm/ttm: Add debugfs output entry to pool allocator Pauli Nieminen
2010-03-17 20:50     ` [PATCH 3/7] drm/radeon/kms: Add ttm page pool debugfs file Pauli Nieminen
2010-03-17 20:50       ` [PATCH 4/7] drm/nouveau: " Pauli Nieminen
2010-03-17 20:50         ` Pauli Nieminen [this message]
2010-03-17 20:50           ` [PATCH 6/7] arch/x86: Add array variants for setting memory to wc caching Pauli Nieminen
2010-03-17 20:50             ` [PATCH 7/7] drm/ttm: Use set_pages_array_wc instead of set_memory_wc Pauli Nieminen
2010-03-17 23:52             ` [PATCH 6/7] arch/x86: Add array variants for setting memory to wc caching Dave Airlie
2010-03-18  9:41               ` Pauli Nieminen
2010-03-18 19:29                 ` Suresh Siddha
2010-03-18 19:18                   ` Pauli Nieminen
     [not found] ` <4BA36207.1070501@shipmail.org>
2010-03-19 12:41   ` [PATCH 0/7] drm/ttm: Pool allocator Pauli Nieminen
2010-03-19 19:51     ` Thomas Hellström

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=1268859006-18707-6-git-send-email-suokkos@gmail.com \
    --to=suokkos@gmail.com \
    --cc=dri-devel@lists.sourceforge.net \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.