• KAMEZAWA Hiroyuki's avatar
    memcg: use generic percpu instead of private implementation · c62b1a3b
    KAMEZAWA Hiroyuki authored
    When per-cpu counter for memcg was implemneted, dynamic percpu allocator
    was not very good.  But now, we have good one and useful macros.  This
    patch replaces memcg's private percpu counter implementation with generic
    dynamic percpu allocator.
    
    The benefits are
    	- We can remove private implementation.
    	- The counters will be NUMA-aware. (Current one is not...)
    	- This patch makes sizeof struct mem_cgroup smaller. Then,
    	  struct mem_cgroup may be fit in page size on small config.
            - About basic performance aspects, see below.
    
     [Before]
     # size mm/memcontrol.o
       text    data     bss     dec     hex filename
      24373    2528    4132   31033    7939 mm/memcontrol.o
    
     [page-fault-throuput test on 8cpu/SMP in root cgroup]
     # /root/bin/perf stat -a -e page-faults,cache-misses --repeat 5 ./multi-fault-fork 8
    
     Performance counter stats for './multi-fault-fork 8' (5 runs):
    
           45878618  page-faults                ( +-   0.110% )
          602635826  cache-misses               ( +-   0.105% )
    
       61.005373262  seconds time elapsed   ( +-   0.004% )
    
     Then cache-miss/page fault = 13.14
    
     [After]
     #size mm/memcontrol.o
       text    data     bss     dec     hex filename
      23913    2528    4132   30573    776d mm/memcontrol.o
     # /root/bin/perf stat -a -e page-faults,cache-misses --repeat 5 ./multi-fault-fork 8
    
     Performance counter stats for './multi-fault-fork 8' (5 runs):
    
           48179400  page-faults                ( +-   0.271% )
          588628407  cache-misses               ( +-   0.136% )
    
       61.004615021  seconds time elapsed   ( +-   0.004% )
    
      Then cache-miss/page fault = 12.22
    
     Text size is reduced.
     This performance improvement is not big and will be invisible in real world
     applications. But this result shows this patch has some good effect even
     on (small) SMP.
    
    Here is a test program I used.
    
     1. fork() processes on each cpus.
     2. do page fault repeatedly on each process.
     3. after 60secs, kill all childredn and exit.
    
    (3 is necessary for getting stable data, this is improvement from previous one.)
    
    #define _GNU_SOURCE
    #include <stdio.h>
    #include <sched.h>
    #include <sys/mman.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <signal.h>
    #include <stdlib.h>
    
    /*
     * For avoiding contention in page table lock, FAULT area is
     * sparse. If FAULT_LENGTH is too large for your cpus, decrease it.
     */
    #define FAULT_LENGTH	(2 * 1024 * 1024)
    #define PAGE_SIZE	4096
    #define MAXNUM		(128)
    
    void alarm_handler(int sig)
    {
    }
    
    void *worker(int cpu, int ppid)
    {
    	void *start, *end;
    	char *c;
    	cpu_set_t set;
    	int i;
    
    	CPU_ZERO(&set);
    	CPU_SET(cpu, &set);
    	sched_setaffinity(0, sizeof(set), &set);
    
    	start = mmap(NULL, FAULT_LENGTH, PROT_READ|PROT_WRITE,
    			MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
    	if (start == MAP_FAILED) {
    		perror("mmap");
    		exit(1);
    	}
    	end = start + FAULT_LENGTH;
    
    	pause();
    	//fprintf(stderr, "run%d", cpu);
    	while (1) {
    		for (c = (char*)start; (void *)c < end; c += PAGE_SIZE)
    			*c = 0;
    		madvise(start, FAULT_LENGTH, MADV_DONTNEED);
    	}
    	return NULL;
    }
    
    int main(int argc, char *argv[])
    {
    	int num, i, ret, pid, status;
    	int pids[MAXNUM];
    
    	if (argc < 2)
    		return 0;
    
    	setpgid(0, 0);
    	signal(SIGALRM, alarm_handler);
    	num = atoi(argv[1]);
    	pid = getpid();
    
    	for (i = 0; i < num; ++i) {
    		ret = fork();
    		if (!ret) {
    			worker(i, pid);
    			exit(0);
    		}
    		pids[i] = ret;
    	}
    	sleep(1);
    	kill(-pid, SIGALRM);
    	sleep(60);
    	for (i = 0; i < num; i++)
    		kill(pids[i], SIGKILL);
    	for (i = 0; i < num; i++)
    		waitpid(pids[i], &status, 0);
    	return 0;
    }
    Signed-off-by: default avatarKAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
    Cc: Daisuke Nishimura <nishimura@mxp.nes.nec.co.jp>
    Cc: Balbir Singh <balbir@in.ibm.com>
    Cc: Pavel Emelyanov <xemul@openvz.org>
    Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
    Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
    c62b1a3b
memcontrol.c 108 KB