[comp.windows.x] X Performance problems....

engtech@GTE.COM (Abe Lockman) (11/28/90)

HI   I am having performance problems on X11R3.
It is running on a Sun4/180 on SunOS 4.0.1.
The sun has 32 Meg of RAM.

X is just a dog on this.  Now we are upgrading to
SunOS 4.0.3, X11R4..  But what else can we do to tune
for performance.  This s****r could kill a saint, so there
must be something else wrong in the configuration.

Any hints greatly appreciated.

jimf@SABER.COM (11/28/90)

|HI   I am having performance problems on X11R3.
|It is running on a Sun4/180 on SunOS 4.0.1.
|The sun has 32 Meg of RAM.
|
|X is just a dog on this.  Now we are upgrading to
|SunOS 4.0.3, X11R4..  But what else can we do to tune
|for performance.  This s****r could kill a saint, so there
|must be something else wrong in the configuration.

It's probably not the problem, but one problem on lower-end Suns is a
thrashing problem known as pmegs thrashing.  If you have large enough
processes or quite a bit of core, circumstances can arise where there
aren't enough pmegs to go around and a thrashing condition results.

This problem is obvious on loaded Sparcstation 1 and 1+'s (4/60 and
4/65s).  I'm told it can happen on Sparcstation 330s as well although
it takes a lot more effort.  We saw the problem on SS1's running 20Mb+
processes, although most people saw the problem running SS1's with a
lot of core (generally 32Mb or more).

There are patches available for SunOS 4.0.3c and 4.1, and the problem
is fixed in SunOS 4.1.1.

The following program can be used to determine if you have the problem
under 4.0.3c.  If the last number output (pmegs stolen from address
space with context) is nonzero for any length of time it's a problem.
I heard a lot of people talking about numbers around the 200 range,
but here we saw them in 60,000 - 70,000 range.

I have a Sunspots report with many more details for those who are
interested.

jim frost
saber software
jimf@saber.com

-- cut here --
/*
 * hatstat -- Get pmeg usage information from the kernel
 *
 * Copyright 1990 by Sun Microsystems, Inc.
 */

#define MMU_3LEVEL      /* Support 3-level MMU operations */

#include <sys/types.h>
#include <stdio.h>
#include <sys/file.h>
#include <nlist.h>
#include <sys/time.h>
#include <signal.h>
#include <sun/vm_hat.h>

#define void    char

#define MON_MEMNAME     "/dev/kmem"
#define MON_NLNAME      "/vmunix"

extern  char    *optarg;
extern  int     optind;

int     on_exit();

struct nlist nl[] = {
#define N_HATCNT        0
	{ "_hatcnt" },
#define N_PMGRPFREE     1
	{ "_pmgrpfree" },
#define N_SMGRPFREE     2
	{ "_smgrpfree" },
	"",
};

struct hatcnt {
	int     hc_ctxalloc;    /* number of context allocations */
	int     hc_ctxstolen;   /* number of contexts stolen from other
	as's */
	int     hc_pmghave;     /* number of pmg_allocs that already
	have pmg */
	int     hc_pmgalloc;    /* number of pmg allocations */
	int     hc_pmgstolennoctx; /* pmgs stolen from as's with no ctx
	*/
	int     hc_pmgstolenctx; /* pmgs stolen from other as's with a
	ctx */
	int     hc_smghave;     /* number of smg_allocs that already
	have smg */
	int     hc_smgalloc;    /* number of smg allocations */
	int     hc_smgstolennoctx; /* smgs stolen from procs with no
	ctx */
	int     hc_smgstolenctx; /* smgs stolen from other procs with a
	ctx */
	int     hc_ctxpmgs;     /* number of pmgs found on as at
	ctxalloc */
} hatcnt;

struct hatcnt   old_hatcnt, diff_hatcnt;
int             detail = 0;
int             no_smegs = 0;
int             do_tod = 0;
int             mem;

main (argc, argv)

	int     argc;
	char    **argv;

{
	struct nlist    *np;
	char            *nlfile;
	int             interval = 5;
	int             have_interval = 0;
	int             count = 1;
	int             have_count = 0;
	int             i;

/*
 * Parse arguments
 */
	while ((i = getopt (argc, argv, "dTi:c:")) != -1) {
		switch (i) {
		    case 'd':
			detail++;
			break;
		    case 'T':
			do_tod++;
			break;
		    case 'i':
			interval = atoi (optarg);
			have_interval++;
			break;
		    case 'c':
			count = atoi (optarg);
			have_count++;
			break;
		    case '?':
		    default:
usage:
			printf ("Usage: hatstat [-d] [-T] [-i interval] [-c count] [namelist]\n");
			exit (1);
		}
	}
/*
 * Optional argument is namelist file
 */
	if (optind < argc)
		nlfile = argv[optind++];
	else
		nlfile = "/vmunix";
	if (optind != argc)
		goto usage;

	if (have_interval && !have_count)
		count = 0x7fffffff;
/*
 * Open input file
 */
	if ((mem = open ("/dev/kmem", O_RDONLY)) == -1) {
		perror ("/dev/kmem");
		exit (1);
	}
/*
 * Get namelist file and addresses of relevant data
 */
	nlist (nlfile, nl);
	for (np = nl; *np->n_name; np++) {
		if (np->n_type == 0) {
			if (np == &nl[N_SMGRPFREE])
				no_smegs++;
			else {
				fprintf (stderr, "'%s' missing from name list.\n",
					 np->n_name);
				exit (1);
			}
		}
	}

/*
 * Read kernel data
 */
	getkval ((void *)&hatcnt, mem, nl[N_HATCNT].n_value,
		 sizeof (struct hatcnt));
/*
 * If not iterating, display data in detail
 */
	if (count == 1 || detail)
		print_cumulative (&hatcnt);
	if (count == 1)
		exit (0);

	signal (SIGINT, on_exit);
/*
 * Iterate
 */

	for (i = 0; i < count; i++) {
		if ((i % 20) == 0) {
			if (do_tod) {
				time_t  tod;

				time(&tod);
				printf ("%s", ctime(&tod));
			}

			printf ("Pmegs   Contexts  Pmegs ---------Pmegs---------");
			if (!no_smegs)
				printf (" Smegs ---------Smegs---------");
			printf ("\n free alloc stoln reatt reusd alloc stlnc stlcx");
			if (!no_smegs)
				printf ("  free reusd alloc stlnc stlcx\n");
			else
				printf ("\n");
		}
		old_hatcnt = hatcnt;
		sleep (interval);
		getkval ((void *)&hatcnt, mem, nl[N_HATCNT].n_value,
			 sizeof (struct hatcnt));
		compute_diff (&hatcnt, &old_hatcnt, &diff_hatcnt);
		printf ("%5d%6d%6d%6d%6d%6d%6d%6d%",
			count_free_pmgs(),
			diff_hatcnt.hc_ctxalloc,
			diff_hatcnt.hc_ctxstolen,
			diff_hatcnt.hc_ctxpmgs, diff_hatcnt.hc_pmghave,
			diff_hatcnt.hc_pmgalloc,
			diff_hatcnt.hc_pmgstolennoctx,
			diff_hatcnt.hc_pmgstolenctx);
		if (no_smegs)
			printf ("\n");
		else {
			printf ("%6d%6d%6d%6d%6d\n", count_free_smgs(),
			diff_hatcnt.hc_smghave,
			diff_hatcnt.hc_smgalloc,
			diff_hatcnt.hc_smgstolennoctx,
			diff_hatcnt.hc_smgstolenctx);
		}
	}
}

/*
 * getkval -- Read requested value (of requested size) from kernel
 memory.
 */
getkval (val, fd, addr, size)

	void    *val;
	int     fd;
	off_t   addr;
	int     size;

{
	if (lseek (fd, addr, L_SET) == -1) {
		perror ("lseek (/dev/kmem)");
		exit (1);
	}
	if (read (fd, (char *)val, size) == -1) {
		perror ("read (/dev/kmem)");
		exit (1);
	}
}

compute_diff (new, old, diff)

	struct hatcnt   *new, *old, *diff;
{

	diff->hc_ctxalloc = new->hc_ctxalloc - old->hc_ctxalloc;
	diff->hc_ctxstolen = new->hc_ctxstolen - old->hc_ctxstolen;
	diff->hc_pmghave = new->hc_pmghave - old->hc_pmghave;
	diff->hc_pmgalloc = new->hc_pmgalloc - old->hc_pmgalloc;
	diff->hc_pmgstolennoctx = new->hc_pmgstolennoctx -
	old->hc_pmgstolennoctx;
	diff->hc_pmgstolenctx = new->hc_pmgstolenctx -
	old->hc_pmgstolenctx;
	diff->hc_smghave = new->hc_smghave - old->hc_smghave;
	diff->hc_smgalloc = new->hc_smgalloc - old->hc_smgalloc;
	diff->hc_smgstolennoctx = new->hc_smgstolennoctx -
	old->hc_smgstolennoctx;
	diff->hc_smgstolenctx = new->hc_smgstolenctx -
	old->hc_smgstolenctx;
	diff->hc_ctxpmgs = new->hc_ctxpmgs - old->hc_ctxpmgs;

}

print_cumulative (cum)

struct hatcnt *cum;

{
	printf ("%10d Pmegs free\n", count_free_pmgs());
	printf ("%10d Contexts allocated\n", cum->hc_ctxalloc);
	printf ("%10d Contexts stolen\n", cum->hc_ctxstolen);
	printf ("%10d Pmegs reattached at context allocation\n",
	cum->hc_ctxpmgs);
	printf ("%10d Pmegs reused\n", cum->hc_pmghave);
	printf ("%10d Pmegs allocated\n", cum->hc_pmgalloc);
	printf ("%10d Pmegs stolen from address space with no context\n",
		cum->hc_pmgstolennoctx);
	printf ("%10d Pmegs stolen from address space with context\n",
		cum->hc_pmgstolenctx);
	if (!no_smegs) {
		printf ("%10d Smegs free\n", count_free_smgs());
		printf ("%10d Smegs reused\n", cum->hc_smghave);
		printf ("%10d Smegs allocated\n", cum->hc_smgalloc);
		printf ("%10d Smegs stolen from address space with no context\n",
			cum->hc_smgstolennoctx);
		printf ("%10d Smegs stolen from address space with context\n",
			cum->hc_smgstolenctx);
	}

}

count_free_pmgs()

{
	struct pmgrp    pmg;
	struct pmgrp    *pp;
	int             free_pmgs;

	getkval ((void *)&pp, mem, nl[N_PMGRPFREE].n_value, sizeof
	(pp));

	for (free_pmgs = 0; pp != NULL; free_pmgs++) {
		getkval ((void *)&pmg, mem, (off_t)pp, sizeof (struct
		pmgrp));
		pp = pmg.pmg_next;
	}

	return (free_pmgs);
}

count_free_smgs()

{
	struct smgrp    smg;
	struct smgrp    *sp;
	int             free_smgs;

	getkval ((void *)&sp, mem, nl[N_SMGRPFREE].n_value, sizeof
	(sp));

	for (free_smgs = 0; sp != NULL; free_smgs++) {
		getkval ((void *)&smg, mem, (off_t)sp, sizeof (struct
		smgrp));
		sp = smg.smg_next;
	}

	return (free_smgs);
}

on_exit ()
{

	if (detail)
		print_cumulative (&hatcnt);

	exit (0);
}