On Mon, 2008-11-10 at 11:55 +0000, Mel Gorman wrote:
> In the situation a caller allocates multiple buffers with
> get_hugepage_region(), all the buffers will align to the start of the
> hugepage. This means the buffers are almost certainly using the same
> cachelines and operations like copying between the arrays will be mysteriously
> slow in comparison to buffers allocated from malloc(). In STREAM, allocating
> the three arrays using get_huge_pages() was approximately 40% the throughput
> of malloc().
>
> When requested, this patch uses bytes that would normally be wasted to
> offset the buffer by some random cacheline. Effort is made to select a
> random cache-line to give good average performance.
>
> Signed-off-by: Mel Gorman <[EMAIL PROTECTED]>
Acked-by: Adam Litke <[EMAIL PROTECTED]>
> ---
> alloc.c | 49 +++++++++++++++++++++++++++++++++++++++++++-
> hugetlbfs.h | 8 +++++-
> man/get_hugepage_region.3 | 9 +++++++-
> 3 files changed, 61 insertions(+), 5 deletions(-)
>
> diff --git a/alloc.c b/alloc.c
> index 74bb5a4..4de75b5 100644
> --- a/alloc.c
> +++ b/alloc.c
> @@ -24,6 +24,7 @@
> #include <stdlib.h>
> #include <string.h>
> #include <unistd.h>
> +#include <time.h>
> #include <sys/mman.h>
> #include <sys/types.h>
>
> @@ -179,6 +180,41 @@ void free_huge_pages(void *ptr)
> fclose(fd);
> }
>
> +/*
> + * Offset the buffer using bytes wasted due to alignment to avoid using the
> + * same cache lines for the start of every buffer returned by
> + * get_huge_pages(). A small effort is made to select a random cacheline
> + * rather than sequential lines to give decent behaviour on average.
> + */
> +void *cachecolor(void *buf, size_t len, size_t color_bytes)
> +{
> + static long cacheline_size = 0;
> + static int linemod = 0;
> + char *bytebuf = (char *)buf;
> + int numlines;
> + int line = 0;
> +
> + /* Lookup our cacheline size once */
> + if (cacheline_size == 0) {
> + cacheline_size = sysconf(_SC_LEVEL2_CACHE_LINESIZE);
> + linemod = time(NULL);
> + }
> +
> + numlines = color_bytes / cacheline_size;
> + DEBUG("%d lines of cacheline size %ld due to %zd wastage\n",
> + numlines, cacheline_size, color_bytes);
> + if (numlines) {
> + line = linemod % numlines;
> + bytebuf += cacheline_size * line;
> +
> + /* Pseudo-ish random line selection */
> + linemod += len % numlines;
> + }
> + DEBUG("Using line offset %d from start\n", line);
> +
> + return bytebuf;
> +}
> +
> /**
> * get_hugepage_region - Allocate an amount of memory backed by huge pages
> *
> @@ -208,12 +244,16 @@ void *get_hugepage_region(size_t len, ghr_t flags)
> buf = fallback_base_pages(len, flags);
> }
>
> - /* Calculate wastage */
> + /* Calculate wastage for coloring */
> wastage = aligned_len - len;
> - if (wastage != 0)
> + if (wastage != 0 && !(flags & GHR_COLOR))
> DEBUG("get_hugepage_region: Wasted %zd bytes due to
> alignment\n",
> wastage);
>
> + /* Only colour if requested */
> + if (flags & GHR_COLOR)
> + buf = cachecolor(buf, len, wastage);
> +
> return buf;
> }
>
> @@ -228,5 +268,10 @@ void *get_hugepage_region(size_t len, ghr_t flags)
> */
> void free_hugepage_region(void *ptr)
> {
> + /* Buffers may be offset for cache line coloring */
> + DEBUG("free_hugepage_region(%p) unaligned\n", ptr);
> + ptr = (void *)ALIGN_DOWN((unsigned long)ptr, gethugepagesize());
> + DEBUG("free_hugepage_region(%p) aligned\n", ptr);
> +
> free_huge_pages(ptr);
> }
> diff --git a/hugetlbfs.h b/hugetlbfs.h
> index ebb676c..ecd178b 100644
> --- a/hugetlbfs.h
> +++ b/hugetlbfs.h
> @@ -60,13 +60,17 @@ void free_huge_pages(void *ptr);
> * GHR_FALLBACK - Use the default hugepage size if possible but fallback to
> * smaller pages if necessary
> * GHR_STRICT - Use hugepages of some size or return NULL
> + * GHP_COLOR - Use bytes wasted due to alignment to offset the buffer
> + * by a random cache line. This gives better average
> + * performance with many buffers
> */
> typedef unsigned long ghr_t;
> #define GHR_STRICT ((ghr_t)0x10000000U)
> #define GHR_FALLBACK ((ghr_t)0x20000000U)
> -#define GHR_DEFAULT GHR_FALLBACK
> +#define GHR_COLOR ((ghr_t)0x40000000U)
> +#define GHR_DEFAULT (GHR_FALLBACK|GHR_COLOR)
>
> -#define GHR_MASK (GHR_FALLBACK|GHR_STRICT)
> +#define GHR_MASK (GHR_FALLBACK|GHR_STRICT|GHR_COLOR)
>
> /* Allocation functions for regions backed by hugepages */
> void *get_hugepage_region(size_t len, ghr_t flags);
> diff --git a/man/get_hugepage_region.3 b/man/get_hugepage_region.3
> index ce0b018..88fd940 100644
> --- a/man/get_hugepage_region.3
> +++ b/man/get_hugepage_region.3
> @@ -47,11 +47,18 @@ Use base pages if there are an insufficient number of
> huge pages.
> .B GHR_STRICT
> Use hugepages or return NULL.
>
> +.B GHR_COLOR
> +When specified, bytes that would be wasted due to alignment are used to
> +color the buffer by offsetting it by a random cacheline within the hugepage.
> +This avoids a performance problem whereby multiple buffers use the same
> +cache lines at the same offsets. If it is not important that the start of the
> +buffer be page-aligned, specify this flag.
> +
> .B GHR_DEFAULT
>
> The library chooses a sensible combination of flags for allocating a region
> of
> memory. The current default is:
> - GHR_FALLBACK
> + GHR_FALLBACK | GHR_COLOR
>
> .PP
>
--
Adam Litke - (agl at us.ibm.com)
IBM Linux Technology Center
-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
Libhugetlbfs-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/libhugetlbfs-devel