lkml.org 
[lkml]   [2007]   [Apr]   [5]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    /
    Date
    From
    SubjectRe: missing madvise functionality
    On Wed, 4 Apr 2007 06:09:18 -0700 William Lee Irwin III <wli@holomorphy.com> wrote:
    >> Oh dear.

    On Wed, Apr 04, 2007 at 11:51:05AM -0700, Andrew Morton wrote:
    > what's all this about?

    I rewrote Jakub's testcase and included it as a MIME attachment.
    Current working version inline below. Also at

    http://holomorphy.com/~wli/jakub.c

    The basic idea was that I wanted a few more niceties, such as specifying
    the number of iterations and other things of that nature on the cmdline.
    I threw in a little code reorganization and error checking, too.


    -- wli


    #include <pthread.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <unistd.h>
    #include <errno.h>
    #include <stdint.h>
    #include <sys/mman.h>
    #include <sys/time.h>
    #include <sys/resource.h>

    enum thread_return {
    tr_success = 0,
    tr_mmap_init = -1,
    tr_mmap_free = -2,
    tr_mprotect = -3,
    tr_madvise = -4,
    tr_unknown = -5,
    tr_munmap = -6,
    };

    enum release_method {
    release_by_mmap = 0,
    release_by_madvise = 1,
    release_by_max = 2,
    };

    struct thread_argument {
    size_t page_size;
    int iterations, pages_per_thread, nr_threads;
    enum release_method method;
    };

    static enum thread_return mmap_release(void *p, size_t n)
    {
    void *q;

    q = mmap(p, n, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, -1, 0);
    if (p != q) {
    perror("thread_function: mmap release failed");
    return tr_mmap_free;
    }
    if (mprotect(p, n, PROT_READ | PROT_WRITE)) {
    perror("thread_function: mprotect failed");
    return tr_mprotect;
    }
    return tr_success;
    }

    static enum thread_return madvise_release(void *p, size_t n)
    {
    if (madvise(p, n, MADV_DONTNEED)) {
    perror("thread_function: madvise failed");
    return tr_madvise;
    }
    return tr_success;
    }

    static enum thread_return (*release_methods[])(void *, size_t) = {
    mmap_release,
    madvise_release,
    };

    static void *thread_function(void *__arg)
    {
    char *p;
    int i;
    struct thread_argument *arg = __arg;
    size_t arena_size = arg->pages_per_thread * arg->page_size;

    p = (char *)mmap(NULL, arena_size,
    PROT_READ | PROT_WRITE,
    MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    if (p == MAP_FAILED) {
    perror("thread_function: arena allocation failed");
    return (void *)tr_mmap_init;
    }
    for (i = 0; i < arg->iterations; i++) {
    size_t s;
    char *q, *r;
    enum thread_return ret;

    /* Pretend to use the buffer. */
    r = p + arena_size;
    for (q = p; q < r; q += arg->page_size)
    *q = 1;
    for (s = 0, q = p; q < r; q += arg->page_size)
    s += *q;
    if (arg->method >= release_by_max) {
    perror("thread_function: "
    "unknown freeing method specified");
    return (void *)tr_unknown;
    }
    ret = (*release_methods[arg->method])(p, arena_size);
    if (ret != tr_success)
    return (void *)ret;
    }
    if (munmap(p, arena_size)) {
    perror("thread_function: munmap() failed");
    return (void *)tr_munmap;
    }
    return (void *)tr_success;
    }

    static int configure(struct thread_argument *arg, int argc, char *argv[])
    {
    char optstring[] = "t:m:i:p:";
    int c, tmp, ret = 0;
    long n;

    n = sysconf(_SC_PAGE_SIZE);
    if (n < 0) {
    perror("configure: sysconf(_SC_PAGE_SIZE) failed");
    ret = -1;
    }
    arg->nr_threads = 32,
    arg->page_size = (size_t)n;
    arg->method = release_by_mmap;
    arg->iterations = 100000;
    arg->pages_per_thread = 128;

    while ((c = getopt(argc, argv, optstring)) != -1) {
    switch (c) {
    case 't':
    if (sscanf(optarg, "%d", &tmp) == 1)
    arg->nr_threads = tmp;
    else {
    perror("configure: non-numeric thread count");
    ret = -1;
    }
    break;
    case 'm':
    if (!strcmp(optarg, "mmap"))
    arg->method = release_by_mmap;
    else if (!strcmp(optarg, "madvise"))
    arg->method = release_by_madvise;
    else {
    perror("configure: unrecognised release method");
    ret = -1;
    }
    break;
    case 'i':
    if (sscanf(optarg, "%d", &tmp) == 1)
    arg->iterations = tmp;
    else {
    perror("configure: non-numeric iteration count");
    ret = -1;
    }
    break;
    case 'p':
    if (sscanf(optarg, "%d", &tmp) == 1)
    arg->pages_per_thread = tmp;
    else {
    perror("configure: non-numeric pages per thread count");
    ret = -1;
    }
    break;
    default:
    perror("unrecognignized argument");
    ret = -1;
    }
    }
    if (arg->nr_threads <= 0) {
    perror("configure: zero or negative thread count");
    ret = -1;
    }
    if (arg->iterations < 0) {
    perror("configure: negative iteration count");
    ret = -1;
    }
    if (arg->pages_per_thread <= 0) {
    perror("configure: zero or negative arena size");
    ret = -1;
    }
    if (SIZE_MAX/arg->page_size < (size_t)arg->pages_per_thread) {
    perror("configure: arena size overflow");
    ret = -1;
    }
    return ret;
    }

    static unsigned long long timeval_to_usec(struct timeval *tv)
    {
    return 1000000*tv->tv_sec + tv->tv_usec;
    }

    static unsigned long long elapsed_usec(struct timeval *tv1, struct timeval *tv2)
    {
    return timeval_to_usec(tv2) - timeval_to_usec(tv1);
    }

    #define user_usec(ru) timeval_to_usec(&(ru)->ru_utime)
    #define sys_usec(ru) timeval_to_usec(&(ru)->ru_stime)
    #define user_sec(ru) ((user_usec(ru) % 60000000ULL)/1000000.0)
    #define sys_sec(ru) ((sys_usec(ru) % 60000000ULL)/1000000.0)
    #define elapsed_sec(tv1, tv2) \
    ((elapsed_usec(tv1, tv2) % 60000000ULL)/1000000.0)

    #define user_min(ru) ((unsigned long)((user_usec(ru)/60000000ULL) % 60))
    #define sys_min(ru) ((unsigned long)((sys_usec(ru)/60000000ULL) % 60))
    #define elapsed_min(tv1, tv2) \
    ((unsigned long)((elapsed_usec(tv1, tv2)/60000000ULL) % 60))

    #define user_hrs(ru) ((unsigned long)(user_usec(ru)/3600000000ULL))
    #define sys_hrs(ru) ((unsigned long)(user_usec(ru)/3600000000ULL))
    #define elapsed_hrs(tv1, tv2) \
    ((unsigned long)(elapsed_usec(tv1, tv2)/3600000000ULL))

    int main(int argc, char *argv[])
    {
    int i, ret = EXIT_SUCCESS;
    struct thread_argument arg;
    struct rusage ru;
    struct timeval start, finish;
    pthread_t *th;

    if (gettimeofday(&start, NULL)) {
    perror("main: initial gettimeofday failed");
    return EXIT_FAILURE;
    }
    if (configure(&arg, argc, argv))
    return EXIT_FAILURE;
    th = calloc(arg.nr_threads, sizeof(pthread_t));
    if (!th) {
    perror("main: calloc of thread array failed");
    return EXIT_FAILURE;
    }
    for (i = 0; i < arg.nr_threads; i++) {
    if (pthread_create(&th[i], NULL, thread_function, &arg)) {
    perror("main: pthread_create failed");
    break;
    }
    }
    for (--i; i >= 0; --i) {
    void *status;

    if (pthread_join(th[i], &status)) {
    perror("main: pthread_join failed");
    ret = EXIT_FAILURE;
    } else if (status != (void *)tr_success)
    ret = EXIT_FAILURE;
    }
    free(th);
    getrusage(RUSAGE_SELF, &ru);
    if (gettimeofday(&finish, NULL)) {
    perror("final gettimeofday failed");
    ret = EXIT_FAILURE;
    }
    if (printf("%lu:%.2lu:%05.2lf elapsed time\n"
    "%lu:%.2lu:%05.2lf user time\n"
    "%lu:%.2lu:%05.2lf system time\n"
    "%ld major faults\n"
    "%ld minor faults\n"
    "%ld voluntary context switches\n"
    "%ld involuntary context switches\n",
    elapsed_hrs(&start, &finish),
    elapsed_min(&start, &finish),
    elapsed_sec(&start, &finish),
    user_hrs(&ru), user_min(&ru), user_sec(&ru),
    sys_hrs(&ru), sys_min(&ru), sys_sec(&ru),
    ru.ru_majflt,
    ru.ru_minflt,
    ru.ru_nvcsw,
    ru.ru_nivcsw) < 0)
    ret = EXIT_FAILURE;
    return ret;
    }
    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

    \
     
     \ /
      Last update: 2007-04-05 06:17    [W:0.040 / U:60.276 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site