Changeset 724

Show
Ignore:
Timestamp:
02/25/08 16:56:45 (6 months ago)
Author:
dormando
Message:

Enable use of large memory pages (Trond Norbye) <Trond.Norbye@Sun.COM>

Initial support for solaris.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/server/configure.ac

    r703 r724  
    200200 
    201201AC_CHECK_FUNCS(mlockall) 
     202AC_CHECK_FUNCS(getpagesizes) 
     203AC_CHECK_FUNCS(memcntl) 
    202204 
    203205AC_CONFIG_FILES(Makefile doc/Makefile) 
  • trunk/server/doc/memory_management.txt

    r120 r724  
     1Date: Tue, 20 Feb 2008 
     2From: Trond Norbye <trond.norbye@sun.com> 
     3 
     4When started with -L memcached will try to enable large memory 
     5pages, and preallocate all memory up front. By using large memory 
     6pages memcached could reduce the number of TLB misses (depending 
     7on the access pattern), and hence improve performance.  
     8 
     9See http://en.wikipedia.org/wiki/Translation_lookaside_buffer for 
     10a description of TLB. 
     11 
    112Date: Fri, 5 Sep 2003 20:31:03 +0300 
    213From: Anatoly Vorobey <mellon@pobox.com> 
     
    4556that's at all possible) common sizes of objects that the clients 
    4657of this particular installation of memcached are likely to store. 
    47 For example, if your installation is going to store hundreds of                                                                  thousands of objects of the size exactly 120 bytes, you'd be much better 
     58For example, if your installation is going to store hundreds of 
     59thousands of objects of the size exactly 120 bytes, you'd be much better 
    4860off changing, in the "naive" list of sizes outlined above, the class 
    4961of 128 bytes to something a bit higher (because the overhead of  
  • trunk/server/memcached.c

    r712 r724  
    26942694           "-P <file>     save PID in <file>, only used with -d option\n" 
    26952695           "-f <factor>   chunk size growth factor, default 1.25\n" 
    2696            "-n <bytes>    minimum space allocated for key+value+flags, default 48\n"); 
     2696           "-n <bytes>    minimum space allocated for key+value+flags, default 48\n" 
     2697 
     2698#if defined(HAVE_GETPAGESIZES) && defined(HAVE_MEMCNTL) 
     2699           "-L            Try to use large memory pages (if available). Increasing\n" 
     2700           "              the memory page size could reduce the number of TLB misses\n" 
     2701           "              and improve the performance. In order to get large pages\n" 
     2702           "              from the OS, memcached will allocate the total item-cache\n" 
     2703           "              in one large chunk.\n" 
     2704#endif 
     2705           ); 
     2706 
    26972707#ifdef USE_THREADS 
    26982708    printf("-t <num>      number of threads to use, default 4\n"); 
     
    28052815} 
    28062816 
     2817#if defined(HAVE_GETPAGESIZES) && defined(HAVE_MEMCNTL) 
     2818/* 
     2819 * On systems that supports multiple page sizes we may reduce the 
     2820 * number of TLB-misses by using the biggest available page size 
     2821 */ 
     2822int enable_large_pages(void) { 
     2823    int ret = -1; 
     2824    size_t sizes[32]; 
     2825    int avail = getpagesizes(sizes, 32); 
     2826    if (avail != -1) { 
     2827        size_t max = sizes[0]; 
     2828        struct memcntl_mha arg = {0}; 
     2829        int ii; 
     2830 
     2831        for (ii = 1; ii < avail; ++ii) { 
     2832            if (max < sizes[ii]) { 
     2833                max = sizes[ii]; 
     2834            } 
     2835        } 
     2836 
     2837        arg.mha_flags   = 0; 
     2838        arg.mha_pagesize = max; 
     2839        arg.mha_cmd = MHA_MAPSIZE_BSSBRK; 
     2840 
     2841        if (memcntl(0, 0, MC_HAT_ADVISE, (caddr_t)&arg, 0, 0) == -1) { 
     2842            fprintf(stderr, "Failed to set large pages: %s\n", 
     2843                    strerror(errno)); 
     2844            fprintf(stderr, "Will use default page size\n"); 
     2845        } else { 
     2846            ret = 0; 
     2847        } 
     2848    } else { 
     2849        fprintf(stderr, "Failed to get supported pagesizes: %s\n", 
     2850                strerror(errno)); 
     2851        fprintf(stderr, "Will use default page size\n"); 
     2852    } 
     2853 
     2854    return ret; 
     2855} 
     2856#endif 
     2857 
    28072858int main (int argc, char **argv) { 
    28082859    int c; 
     
    28102861    bool lock_memory = false; 
    28112862    bool daemonize = false; 
     2863    bool preallocate = false; 
    28122864    int maxcore = 0; 
    28132865    char *username = NULL; 
     
    28342886 
    28352887    /* process arguments */ 
    2836     while ((c = getopt(argc, argv, "a:bp:s:U:m:Mc:khirvdl:u:P:f:s:n:t:D:")) != -1) { 
     2888    while ((c = getopt(argc, argv, "a:bp:s:U:m:Mc:khirvdl:u:P:f:s:n:t:D:L")) != -1) { 
    28372889        switch (c) { 
    28382890        case 'a': 
     
    29182970            settings.detail_enabled = 1; 
    29192971            break; 
     2972#if defined(HAVE_GETPAGESIZES) && defined(HAVE_MEMCNTL) 
     2973        case 'L' : 
     2974            if (enable_large_pages() == 0) { 
     2975                preallocate = true; 
     2976            } 
     2977            break; 
     2978#endif 
    29202979        default: 
    29212980            fprintf(stderr, "Illegal argument \"%c\"\n", c); 
     
    30573116    /* Hacky suffix buffers. */ 
    30583117    suffix_init(); 
    3059     slabs_init(settings.maxbytes, settings.factor); 
     3118    slabs_init(settings.maxbytes, settings.factor, preallocate); 
    30603119 
    30613120    /* managed instance? alloc and zero a bucket array */ 
  • trunk/server/slabs.c

    r696 r724  
    5555static int power_largest; 
    5656 
     57static void *mem_base = NULL; 
     58static void *mem_current = NULL; 
     59static size_t mem_avail = 0; 
     60 
    5761/* 
    5862 * Forward Declarations 
    5963 */ 
    6064static int do_slabs_newslab(const unsigned int id); 
     65static void *memory_allocate(size_t size); 
    6166 
    6267#ifndef DONT_PREALLOC_SLABS 
     
    9398 * accordingly. 
    9499 */ 
    95 void slabs_init(const size_t limit, const double factor) { 
     100void slabs_init(const size_t limit, const double factor, const bool prealloc) { 
    96101    int i = POWER_SMALLEST - 1; 
    97102    unsigned int size = sizeof(item) + settings.chunk_size; 
     
    102107 
    103108    mem_limit = limit; 
     109 
     110    if (prealloc) { 
     111        /* Allocate everything in a big chunk with malloc */ 
     112        mem_base = malloc(mem_limit); 
     113        if (mem_base != NULL) { 
     114            mem_current = mem_base; 
     115            mem_avail = mem_limit; 
     116        } else { 
     117            fprintf(stderr, "Warning: Failed to allocate requested memory in" 
     118                    " one large chunk.\nWill allocate in smaller chunks\n"); 
     119        } 
     120    } 
     121 
    104122    memset(slabclass, 0, sizeof(slabclass)); 
    105123 
     
    188206    if (grow_slab_list(id) == 0) return 0; 
    189207 
    190     ptr = malloc((size_t)len); 
     208    ptr = memory_allocate((size_t)len); 
    191209    if (ptr == 0) return 0; 
    192210 
     
    375393} 
    376394#endif 
     395 
     396static void *memory_allocate(size_t size) { 
     397    void *ret; 
     398 
     399    if (mem_base == NULL) { 
     400        /* We are not using a preallocated large memory chunk */ 
     401        ret = malloc(size); 
     402    } else { 
     403        ret = mem_current; 
     404 
     405        if (size > mem_avail) { 
     406            return NULL; 
     407        } 
     408 
     409        /* mem_current pointer _must_ be aligned!!! */ 
     410        if (size % CHUNK_ALIGN_BYTES) { 
     411            size += CHUNK_ALIGN_BYTES - (size % CHUNK_ALIGN_BYTES); 
     412        } 
     413 
     414        mem_current += size; 
     415        if (size < mem_avail) { 
     416            mem_avail -= size; 
     417        } else { 
     418            mem_avail = 0; 
     419        } 
     420    } 
     421 
     422    return ret; 
     423} 
  • trunk/server/slabs.h

    r596 r724  
    33/** Init the subsystem. 1st argument is the limit on no. of bytes to allocate, 
    44    0 if no limit. 2nd argument is the growth factor; each slab will use a chunk 
    5     size equal to the previous slab's chunk size times this factor. */ 
    6 void slabs_init(const size_t limit, const double factor); 
     5    size equal to the previous slab's chunk size times this factor. 
     6    3rd argument specifies if the slab allocator should allocate all memory 
     7    up front (if true), or allocate memory in chunks as it is needed (if false) 
     8*/ 
     9void slabs_init(const size_t limit, const double factor, const bool prealloc); 
    710 
    811