Thread (21 messages) 21 messages, 3 authors, 2021-05-24

Re: [PATCH 4/6] mm/page_alloc: Scale the number of pages that are batch freed

From: Mel Gorman <hidden>
Date: 2021-05-24 09:12:26
Also in: lkml

On Fri, May 21, 2021 at 03:36:05PM -0700, Dave Hansen wrote:
...
quoted
+static int nr_pcp_free(struct per_cpu_pages *pcp, int high, int batch)
+{
+	int min_nr_free, max_nr_free;
+
+	/* Check for PCP disabled or boot pageset */
+	if (unlikely(high < batch))
+		return 1;
+
+	min_nr_free = batch;
+	max_nr_free = high - batch;
I puzzled over this for a minute.  I *think* it means to say: "Leave at
least one batch worth of pages in the pcp at all times so that the next
allocation can still be satisfied from this pcp."
Yes, I added a comment.
quoted
+	batch <<= pcp->free_factor;
+	if (batch < max_nr_free)
+		pcp->free_factor++;
+	batch = clamp(batch, min_nr_free, max_nr_free);
+
+	return batch;
+}
+
 static void free_unref_page_commit(struct page *page, unsigned long pfn,
 				   int migratetype)
 {
 	struct zone *zone = page_zone(page);
 	struct per_cpu_pages *pcp;
+	int high;
 
 	__count_vm_event(PGFREE);
 	pcp = this_cpu_ptr(zone->per_cpu_pageset);
 	list_add(&page->lru, &pcp->lists[migratetype]);
 	pcp->count++;
-	if (pcp->count >= READ_ONCE(pcp->high))
-		free_pcppages_bulk(zone, READ_ONCE(pcp->batch), pcp);
+	high = READ_ONCE(pcp->high);
+	if (pcp->count >= high) {
+		int batch = READ_ONCE(pcp->batch);
+
+		free_pcppages_bulk(zone, nr_pcp_free(pcp, high, batch), pcp);
+	}
 }
 
 /*
@@ -3531,6 +3555,7 @@ static struct page *rmqueue_pcplist(struct zone *preferred_zone,
 
 	local_lock_irqsave(&pagesets.lock, flags);
 	pcp = this_cpu_ptr(zone->per_cpu_pageset);
+	pcp->free_factor >>= 1;
 	list = &pcp->lists[migratetype];
 	page = __rmqueue_pcplist(zone,  migratetype, alloc_flags, pcp, list);
 	local_unlock_irqrestore(&pagesets.lock, flags);
A high-level description of the algorithm in the changelog would also be
nice.  I *think* it's basically:

After hitting the high pcp mark, free one pcp->batch at a time.  But, as
subsequent pcp free operations occur, keep doubling the size of the
freed batches.  Cap them so that they always leave at least one
pcp->batch worth of pages.  Scale the size back down by half whenever an
allocation that consumes a page from the pcp occurs.

While I'd appreciate another comment or two, I do think this is worth
doing, and the approach seems sound:

Acked-by: Dave Hansen <dave.hansen@linux.intel.com>
Thanks, I added a few additional comments.

-- 
Mel Gorman
SUSE Labs
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help