mirror of
https://gitee.com/bianbu-linux/linux-6.6
synced 2025-04-24 14:07:52 -04:00
When a pagevec is initialised on the stack, it is generally used multiple times over a range of pages, looking up entries and then releasing them. On each pagevec_release, the per-cpu deferred LRU pagevecs are drained on the grounds the page being released may be on those queues and the pages may be cache hot. In many cases only the first drain is necessary as it's unlikely that the range of pages being walked is racing against LRU addition. Even if there is such a race, the impact is marginal where as constantly redraining the lru pagevecs costs. This patch ensures that pagevec is only drained once in a given lifecycle without increasing the cache footprint of the pagevec structure. Only sparsetruncate tiny is shown here as large files have many exceptional entries and calls pagecache_release less frequently. sparsetruncate (tiny) 4.14.0-rc4 4.14.0-rc4 batchshadow-v1r1 onedrain-v1r1 Min Time 141.00 ( 0.00%) 141.00 ( 0.00%) 1st-qrtle Time 142.00 ( 0.00%) 142.00 ( 0.00%) 2nd-qrtle Time 142.00 ( 0.00%) 142.00 ( 0.00%) 3rd-qrtle Time 143.00 ( 0.00%) 143.00 ( 0.00%) Max-90% Time 144.00 ( 0.00%) 144.00 ( 0.00%) Max-95% Time 146.00 ( 0.00%) 145.00 ( 0.68%) Max-99% Time 198.00 ( 0.00%) 194.00 ( 2.02%) Max Time 254.00 ( 0.00%) 208.00 ( 18.11%) Amean Time 145.12 ( 0.00%) 144.30 ( 0.56%) Stddev Time 12.74 ( 0.00%) 9.62 ( 24.49%) Coeff Time 8.78 ( 0.00%) 6.67 ( 24.06%) Best99%Amean Time 144.29 ( 0.00%) 143.82 ( 0.32%) Best95%Amean Time 142.68 ( 0.00%) 142.31 ( 0.26%) Best90%Amean Time 142.52 ( 0.00%) 142.19 ( 0.24%) Best75%Amean Time 142.26 ( 0.00%) 141.98 ( 0.20%) Best50%Amean Time 141.90 ( 0.00%) 141.71 ( 0.13%) Best25%Amean Time 141.80 ( 0.00%) 141.43 ( 0.26%) The impact on bonnie is marginal and within the noise because a significant percentage of the file being truncated has been reclaimed and consists of shadow entries which reduce the hotness of the pagevec_release path. Link: http://lkml.kernel.org/r/20171018075952.10627-5-mgorman@techsingularity.net Signed-off-by: Mel Gorman <mgorman@techsingularity.net> Cc: Andi Kleen <ak@linux.intel.com> Cc: Dave Chinner <david@fromorbit.com> Cc: Dave Hansen <dave.hansen@intel.com> Cc: Jan Kara <jack@suse.cz> Cc: Johannes Weiner <hannes@cmpxchg.org> Cc: Vlastimil Babka <vbabka@suse.cz> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
91 lines
2.3 KiB
C
91 lines
2.3 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/*
|
|
* include/linux/pagevec.h
|
|
*
|
|
* In many places it is efficient to batch an operation up against multiple
|
|
* pages. A pagevec is a multipage container which is used for that.
|
|
*/
|
|
|
|
#ifndef _LINUX_PAGEVEC_H
|
|
#define _LINUX_PAGEVEC_H
|
|
|
|
/* 14 pointers + two long's align the pagevec structure to a power of two */
|
|
#define PAGEVEC_SIZE 14
|
|
|
|
struct page;
|
|
struct address_space;
|
|
|
|
struct pagevec {
|
|
unsigned long nr;
|
|
bool cold;
|
|
bool drained;
|
|
struct page *pages[PAGEVEC_SIZE];
|
|
};
|
|
|
|
void __pagevec_release(struct pagevec *pvec);
|
|
void __pagevec_lru_add(struct pagevec *pvec);
|
|
unsigned pagevec_lookup_entries(struct pagevec *pvec,
|
|
struct address_space *mapping,
|
|
pgoff_t start, unsigned nr_entries,
|
|
pgoff_t *indices);
|
|
void pagevec_remove_exceptionals(struct pagevec *pvec);
|
|
unsigned pagevec_lookup_range(struct pagevec *pvec,
|
|
struct address_space *mapping,
|
|
pgoff_t *start, pgoff_t end);
|
|
static inline unsigned pagevec_lookup(struct pagevec *pvec,
|
|
struct address_space *mapping,
|
|
pgoff_t *start)
|
|
{
|
|
return pagevec_lookup_range(pvec, mapping, start, (pgoff_t)-1);
|
|
}
|
|
|
|
unsigned pagevec_lookup_range_tag(struct pagevec *pvec,
|
|
struct address_space *mapping, pgoff_t *index, pgoff_t end,
|
|
int tag);
|
|
unsigned pagevec_lookup_range_nr_tag(struct pagevec *pvec,
|
|
struct address_space *mapping, pgoff_t *index, pgoff_t end,
|
|
int tag, unsigned max_pages);
|
|
static inline unsigned pagevec_lookup_tag(struct pagevec *pvec,
|
|
struct address_space *mapping, pgoff_t *index, int tag)
|
|
{
|
|
return pagevec_lookup_range_tag(pvec, mapping, index, (pgoff_t)-1, tag);
|
|
}
|
|
|
|
static inline void pagevec_init(struct pagevec *pvec, int cold)
|
|
{
|
|
pvec->nr = 0;
|
|
pvec->cold = cold;
|
|
pvec->drained = false;
|
|
}
|
|
|
|
static inline void pagevec_reinit(struct pagevec *pvec)
|
|
{
|
|
pvec->nr = 0;
|
|
}
|
|
|
|
static inline unsigned pagevec_count(struct pagevec *pvec)
|
|
{
|
|
return pvec->nr;
|
|
}
|
|
|
|
static inline unsigned pagevec_space(struct pagevec *pvec)
|
|
{
|
|
return PAGEVEC_SIZE - pvec->nr;
|
|
}
|
|
|
|
/*
|
|
* Add a page to a pagevec. Returns the number of slots still available.
|
|
*/
|
|
static inline unsigned pagevec_add(struct pagevec *pvec, struct page *page)
|
|
{
|
|
pvec->pages[pvec->nr++] = page;
|
|
return pagevec_space(pvec);
|
|
}
|
|
|
|
static inline void pagevec_release(struct pagevec *pvec)
|
|
{
|
|
if (pagevec_count(pvec))
|
|
__pagevec_release(pvec);
|
|
}
|
|
|
|
#endif /* _LINUX_PAGEVEC_H */
|