From: torvalds@klaava.Helsinki.FI (Linus Torvalds)
Subject: Re: A simple xload program using proc fs
Keywords: xload
Organization: University of Helsinki
Date: Tue, 12 Jan 1993 17:55:21 GMT

This isn't really a comment on the xload program, but just a general
warning about performance, as I've seen a couple of mails/postings
saying that the /proc thing is slower than a kmem based 'ps' etc. 

While the /proc interface may not be the fastest possible, you can
probably get much better perfomance by readin things in bigger chunks
and only once.  I wrote the routines in such a way that they should work
fine even if you do several small reads, but the whole buffer is always
calculated for each read, so using stdio routines is generally not the
best way to handle it (at the very least, stdio needs to do two reads:
the second one will just return EOF). 

In the xload case this isn't really something you need to care about, as
the buffer is both small and fast to calculate, and xload doesn't need
to read it very often anyway, but this is also an easy way to show the
"preferred" way of handling the /proc directory, so I'll use it as an
example. 

In article <1993Jan12.125403.14817@olymp.informatik.uni-bonn.de> lederer@informatik.uni-bonn.de writes:
>
>void get_value(Widget w, XtPointer client_data, XtPointer chart_value)
>{
>	FILE *loadavg;
>	
>	if( (loadavg=fopen(LOADAVG,"r"))==NULL)
>		{
>			fprintf(stderr,"couldn't open %s",LOADAVG);
>			exit(1);	
>		}
>	fscanf(loadavg,"%lf", (double *) chart_value);
>	fclose(loadavg);
>}

The optimal way to do this is probably:

void get_value(Widget w, XtPointer client_data, XtPointer chart_value)
{
	static int fd = -1;
	static char buf[4097];
	int i;

	*(double *) chart_value = 0.0;
	if (fd < 0) {
		fd = open(LOADAVG,O_RDONLY);
		if (fd < 0) {
			fprintf(stderr,"couldn't open %s\n",LOADAVG);
			exit(1);
		}
	}
	i = read(fd,buf,4096);
	if (i > 0) {
		buf[i] = '\0';
		sscanf(buf,"%lf", (double *) chart_value);
	}
}

A couple of points:

 - do the open only once if at all possible, as you'll otherwise have to
   look up the name every time.  If you have to open several different
   /proc files, and not much else, the fastest way is to do a "chdir()"
   to the /proc directory, and then use relative filenames.  This way
   you avoid looking up the inodes etc from disk, and can do name lookup
   entirely in the procfs (this probably only pays off with 'ps', and
   maybe not even there..).

 - read all the statistics files (/proc/loadavg, /proc/meminfo,
   /proc/<pid>/stat etc) with just one read, with a buffer of 4096
   bytes.  Also note that the strings are usually not '\0'-terminated,
   so you have to do that yourself with the value returned by the read
   if you are going to use them as strings.  This means that the buffer
   actually has to be 1 byte longer than a page for safety (but note the
   special meaning of '\0' in /proc/xxx/environ and /proc/xxx/cmdline)

 - these points are meaningless unless you really care about
   performance: all the /proc files have been designed so that you can
   use shell scripts, perl or whatever to read and parse them.  So use
   perl/shell scripts (or stdio) when appropriate, and try to optimize
   only when there is any reason for it. 

		Linus
Newsgroups: comp.os.linux