• Jiri Pirko's avatar
    Make ->ru_maxrss value in struct rusage filled accordingly to rss hiwater · 86610bb4
    Jiri Pirko authored
    mark.  This struct is filled as a parameter to getrusage syscall. 
    ->ru_maxrss value is set to KBs which is the way it is done in BSD
    systems.  /usr/bin/time (gnu time) application converts ->ru_maxrss to KBs
    which seems to be incorrect behavior.  Maintainer of this util was
    notified by me with the patch which corrects it and cc'ed.
    
    To make this happen we extend struct signal_struct by two fields.  The
    first one is ->maxrss which we use to store rss hiwater of the task.  The
    second one is ->cmaxrss which we use to store highest rss hiwater of all
    task childs.  These values are used in k_getrusage() to actually fill
    ->ru_maxrss.  k_getrusage() uses current rss hiwater value directly if mm
    struct exists.
    
    Note:
    exec() clear mm->hiwater_rss, but doesn't clear sig->maxrss.
    it is intetionally behavior. *BSD getrusage have exec() inheriting.
    
    Test progmam and test case
    ===========================
    
    getrusage.c
    ====
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/time.h>
    #include <sys/resource.h>
    #include <sys/types.h>
    #include <sys/wait.h>
    #include <unistd.h>
    #include <signal.h>
    
    static void consume(int mega)
    {
    	size_t sz = mega * 1024 * 1024;
    	void *ptr;
    
    	ptr = malloc(sz);
    	memset(ptr, 0, sz);
    	usleep(1);  /* BSD rusage statics need to sleep 1 tick */
    }
    
    static void show_rusage(char *prefix)
    {
    	int err, err2;
    	struct rusage rusage_self;
    	struct rusage rusage_children;
    
    	printf("%s: ", prefix);
    	err = getrusage(RUSAGE_SELF, &rusage_self);
    	if (!err)
    		printf("self %ld ", rusage_self.ru_maxrss);
    	err2 = getrusage(RUSAGE_CHILDREN, &rusage_children);
    	if (!err2)
    		printf("children %ld ", rusage_children.ru_maxrss);
    
    	printf("\n");
    }
    
    int main(int argc, char** argv)
    {
    	int status;
    	int c;
    	int need_sleep_before_wait = 0;
    	int consume_large_memory_at_first = 0;
    	int create_child_at_first = 0;
    	int sigign = 0;
    	int create_child_before_exec = 0;
    	int after_fork_test = 0;
    
    	while ((c = getopt(argc, argv, "ceflsz")) != -1) {
    		switch (c) {
    		case 'c':
    			create_child_at_first = 1;
    			break;
    		case 'e':
    			create_child_before_exec = 1;
    			break;
    		case 'f':
    			after_fork_test = 1;
    			break;
    		case 'l':
    			consume_large_memory_at_first = 1;
    			break;
    		case 's':
    			sigign = 1;
    			break;
    		case 'z':
    			need_sleep_before_wait = 1;
    			break;
    		default:
    			break;
    		}
    	}
    
    	if (consume_large_memory_at_first)
    		consume(100);
    
    	if (create_child_at_first)
    		system("./child -q");
    
    	if (sigign)
    		signal(SIGCHLD, SIG_IGN);
    
    	if (fork()) {
    		usleep(1);
    		if (need_sleep_before_wait)
    			sleep(3); /* children become zombie */
    		show_rusage("pre_wait");
    		wait(&status);
    		show_rusage("post_wait");
    	} else {
    		usleep(1);
    		show_rusage("fork");
    
    		if (after_fork_test) {
    			consume(30);
    			show_rusage("fork2");
    		}
    		if (create_child_before_exec) {
    			system("./child -lq");
    			usleep(1);
    			show_rusage("fork3");
    		}
    
    		execl("./child", "child", 0);
    		exit(0);
    	}
    
    	return 0;
    }
    
    child.c
    ====
    #include <sys/types.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/wait.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/time.h>
    #include <sys/resource.h>
    
    static void consume(int mega)
    {
    	size_t sz = mega * 1024 * 1024;
    	void *ptr;
    
    	ptr = malloc(sz);
    	memset(ptr, 0, sz);
    	usleep(1);  /* BSD rusage statics need to sleep 1 tick */
    }
    
    static void show_rusage(char *prefix)
    {
    	int err, err2;
    	struct rusage rusage_self;
    	struct rusage rusage_children;
    
    	printf("%s: ", prefix);
    	err = getrusage(RUSAGE_SELF, &rusage_self);
    	if (!err)
    		printf("self %ld ", rusage_self.ru_maxrss);
    	err2 = getrusage(RUSAGE_CHILDREN, &rusage_children);
    	if (!err2)
    		printf("children %ld ", rusage_children.ru_maxrss);
    
    	printf("\n");
    
    }
    
    int main(int argc, char** argv)
    {
    	int status;
    	int c;
    	int silent = 0;
    	int light_weight = 0;
    
    	while ((c = getopt(argc, argv, "lq")) != -1) {
    		switch (c) {
    		case 'l':
    			light_weight = 1;
    			break;
    		case 'q':
    			silent = 1;
    			break;
    		default:
    			break;
    		}
    	}
    
    	if (!silent)
    		show_rusage("exec");
    
    	if (fork()) {
    		if (light_weight)
    			consume(400);
    		else
    			consume(700);
    		wait(&status);
    	} else {
    		if (light_weight)
    			consume(600);
    		else
    			consume(900);
    
    		exit(0);
    	}
    
    	return 0;
    }
    
    testcase
    ========
    
    1. inherit fork?
    
       test way:
       	% ./getrusage -lc
    
       bsd result:
       	fork line is "fork: self 0 children 0".
    
       	-> rusage sholdn't be inherit by fork.
    	   (both RUSAGE_SELF and RUSAGE_CHILDREN)
    
    2. inherit exec?
    
       test way:
       	% ./getrusage -lce
    
       bsd result:
       	fork3: self 103204 children 60000
    	exec: self 103204 children 60000
    
       	fork3 and exec line are the same.
    
       	-> rusage shold be inherit by exec.
    	   (both RUSAGE_SELF and RUSAGE_CHILDREN)
    
    3. getrusage(RUSAGE_CHILDREN) collect grandchild statics?
    
       test way:
       	% ./getrusage
    
       bsd result:
       	post_wait line is about "post_wait: self 0 children 90000".
    
    	-> RUSAGE_CHILDREN can collect grandchild.
    
    4. zombie, but not waited children collect or not?
    
       test way:
       	% ./getrusage -z
    
       bsd result:
       	pre_wait line is "pre_wait: self 0 children 0".
    
    	-> zombie child process (not waited-for child process)
    	   isn't accounted.
    
    5. SIG_IGN collect or not
    
       test way:
       	% ./getrusage -s
    
       bsd result:
       	post_wait line is "post_wait: self 0 children 0".
    
    	-> if SIGCHLD is ignored, children isn't accounted.
    
    6. fork and malloc
       test way:
       	% ./getrusage -lcf
    
       bsd result:
       	fork line is "fork: self 0 children 0".
       	fork2 line is about "fork: self 130000 children 0".
    
       	-> rusage sholdn't be inherit by fork.
    	   (both RUSAGE_SELF and RUSAGE_CHILDREN)
    	   but additional memory cunsumption cause right
    	   maxrss calculation.
    Signed-off-by: default avatarJiri Pirko <jpirko@redhat.com>
    Signed-off-by: default avatarKOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
    Cc: Oleg Nesterov <oleg@redhat.com>
    Cc: Hugh Dickins <hugh.dickins@tiscali.co.uk>
    Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
    86610bb4
fork.c 42 KB