Here's a simple program to trigger the issue with /proc/<pid>/maps.

Thanks,
Calvin

/* Simple program to reproduce O(N^2) behavior reading /proc/<pid>/maps
 *
 * Example on a random server:
 *
 *      $ ./map_repro 0
 *      Spawning 0 threads
 *      Reading /proc/self/maps... read 2189 bytes in 1 syscalls in 33us!
 *      $ ./map_repro 10
 *      Spawning 10 threads
 *      Reading /proc/self/maps... read 3539 bytes in 1 syscalls in 55us!
 *      $ ./map_repro 100
 *      Spawning 100 threads
 *      Reading /proc/self/maps... read 15689 bytes in 4 syscalls in 373us!
 *      $ ./map_repro 1000
 *      Spawning 1000 threads
 *      Reading /proc/self/maps... read 137189 bytes in 34 syscalls in 32376us!
 *      $ ./map_repro 2000
 *      Spawning 2000 threads
 *      Reading /proc/self/maps... read 272189 bytes in 68 syscalls in 119980us!
 *      $ ./map_repro 4000
 *      Spawning 4000 threads
 *      Reading /proc/self/maps... read 544912 bytes in 134 syscalls in 
712200us!
 *      $ ./map_repro 8000
 *      Spawning 8000 threads
 *      Reading /proc/self/maps... read 1090189 bytes in 268 syscalls in 
3650718us!
 *      $ ./map_repro 16000
 *      Spawning 16000 threads
 *      Reading /proc/self/maps... read 2178189 bytes in 534 syscalls in 
42701311us!
 */

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <limits.h>
#include <pthread.h>
#include <unistd.h>
#include <time.h>
#include <fcntl.h>

static char buf[65536] = {0};
static void time_maps_read(void)
{
        struct timespec then, now;
        long usec_elapsed;
        int ret, fd;
        int count = 0;
        int rd = 0;

        fd = open("/proc/self/maps", O_RDONLY);
        if (fd == -1) {
                printf("Couldn't open /proc/self/maps, bailing...\n");
                return;
        }

        printf("Reading /proc/self/maps... ");
        ret = clock_gettime(CLOCK_MONOTONIC, &then);

        while (1) {
                ret = read(fd, &buf, 65536);
                if (!ret || ret == -1)
                        break;
                rd += ret;
                count++;
        }

        ret = clock_gettime(CLOCK_MONOTONIC, &now); 
        usec_elapsed = (now.tv_sec - then.tv_sec) * 1000000L;
        usec_elapsed += (now.tv_nsec - then.tv_nsec) / 1000L;

        printf("read %d bytes in %d syscalls in %ldus!\n", rd, count, 
usec_elapsed);
        close(fd);
}

static void *do_nothing_forever(void *unused)
{
        while (1)
                sleep(60);

        return NULL;
}

int main(int args, char **argv)
{
        int i, ret, threads_to_spawn = 0;       
        pthread_t tmp;

        if (args != 1) {
                threads_to_spawn = atoi(argv[1]);
                printf("Spawning %d threads\n", threads_to_spawn);
        }

        for (i = 0; i < threads_to_spawn; i++) {
                ret = pthread_create(&tmp, NULL, do_nothing_forever, NULL);
                if (ret)
                        printf("Thread %d failed to spawn?\n", i);
        }

        time_maps_read();
        return 0;
}
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to