[comp.sys.hp] X on 9000/318's

mahesh@shark.cs.fau.edu (Mahesh Neelakanta) (11/02/90)

Greetings,
  We have about 7 hp 9000/318 which used to be faculty workstations
before we got some 345's. The 318's have 4 Megs are are now diskless
student machines. The problem: X11 barely runs on these things. It is
*real* slow and unresponsive. My questions is: Is there a way of running
the X11 Server on one of our more powerful hp's and run a small program
on the diskless which just draws to the screen. This way, the apps could
still run on the diskless but the server would be on a big server. Is
this possible/impossible/stupid?

Mahesh

Mahesh Neelakanta                               Internet: mahesh@cs.fau.edu
CS Student                                                mahesh@acc.fau.edu
(407) 367-3981                                  Bitnet:   mahesh@fauvax

            Autobots, transform and roll out! - Optimis Prime

tml@tik.vtt.fi (Tor Lillqvist) (11/03/90)

In article <MAHESH.90Nov1234750@shark.cs.fau.edu> mahesh@shark.cs.fau.edu (Mahesh Neelakanta) writes:

   Greetings,
     We have about 7 hp 9000/318 which used to be faculty workstations
   before we got some 345's. The 318's have 4 Megs are are now diskless
   student machines. The problem: X11 barely runs on these things. It is
   *real* slow and unresponsive. My questions is: Is there a way of running
   the X11 Server on one of our more powerful hp's and run a small program
   on the diskless which just draws to the screen. 

No you cannot run the X server remotely.  But something like this is
possible.  Basically you generate a really minimal kernel (tune down
nproc, ntext, npty, nbuf etc), and put in /etc/inittab:

is:2:initdefault:
st::sysinit:stty 9600 clocal icanon echo opost onlcr ienqak ixon icrnl ignpar < /dev/systty
bc::bootwait:/etc/brc 1>/dev/syscon 2>&1 #bootrun command
cr::bootwait:/bin/cat /etc/copyright >/dev/syscon
rc::wait:/etc/rc.x-terminal </dev/syscon >/dev/syscon 2>&1 #run com
co:023456:respawn:/usr/bin/X11/X -query host.running.xdm >/dev/console 2>&1

and /etc/rc.x-terminal is:

#!/bin/sh
set -- `getcontext` && cnodename=$1
hostname ...
ifconfig lan0 `hostname` up
/etc/xlockserver

Then you run some X Display Manager program on another host, and it
manages the 318 like an X Terminal.  Unfortunately xdm as supplied by
MIT doesn't work too well on HP-UX (some confusion about signal
semantics etc).  But if you have VUE, I think vuesession is xdm in
disguise.  I did try this once when we still had 318s, but it didn't
work too well (we didn't have VUE then), and I didn't have time to
look into it more deeply.  And the people with 318s were not too
dissatisfied after all...  If you cannot get the xdm/vuesession
approach working, you could keep getty and let people log in normally,
but have /etc/profile start the X server and remsh a hpterm/xterm on a
remote host.  Etc.

The xlockserver mentioned above is a really small program:

xxxxxxxxxxxxxxxx cut here xxxxxxxxxxxxxxxx
/*
 * S E R V . U D P
 * 
 * This is an example program that demonstrates the use of datagram sockets as
 * an IPC mechanism.  This contains the server, and is intended to operate in
 * conjunction with the client program found in client.udp.  Together, these
 * two programs demonstrate many of the features of sockets, as well as good
 * conventions for using these features.
 * 
 * This program provides a service called "xlock".  It starts the xlock program.
 * In order for it to function, an entry for it needs to exist in the
 * /etc/services file.  The port address for this service can be any port
 * number that is likely to be unused, such as 22375, for example. The host
 * on which the client will be running must also have the same entry (same
 * port number) in its /etc/services file.
 * 
 */

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <netdb.h>
#include <pwd.h>

int             s;		/* socket descriptor */

#define BUFFERSIZE	17	/* maximum size of packets to be received */
int             cc;		/* contains the number of bytes read */
char            buffer[BUFFERSIZE];	/* buffer for packets to be read into */

struct servent *sp;		/* pointer to service information */

struct sockaddr_in myaddr_in;	/* for local socket address */
struct sockaddr_in clientaddr_in;	/* for client's socket address */

/*
 * M A I N
 * 
 * This routine starts the server.  It forks, leaving the child to do all the
 * work, so it does not have to be run in the background.  It sets up the
 * socket, and for each incoming request, it starts xlock.  The request 
 * contains the name of the user.
 * 
 */
main(argc, argv)
	int             argc;
	char           *argv[];
{
	int             addrlen;
	struct passwd  *pwd;

	/* clear out address structures */
	memset((char *) &myaddr_in, 0, sizeof(struct sockaddr_in));
	memset((char *) &clientaddr_in, 0, sizeof(struct sockaddr_in));

	/* Set up address structure for the socket. */
	myaddr_in.sin_family = AF_INET;
	/*
	 * The server should receive on the wildcard address, rather than its
	 * own internet address.  This is generally good practice for
	 * servers, because on systems which are connected to more than one
	 * network at once will be able to have one server listening on all
	 * networks at once.  Even when the host is connected to only one
	 * network, this is good practice, because it makes the server
	 * program more portable.
	 */
	myaddr_in.sin_addr.s_addr = INADDR_ANY;
	/*
	 * Find the information for the "xlock" server in order to get the
	 * needed port number.
	 */
	sp = getservbyname("xlock", "udp");
	if (sp == NULL) {
		fprintf(stderr, "%s: xlock not found in /etc/services\n",
			argv[0]);
		exit(1);
	}
	myaddr_in.sin_port = sp->s_port;

	/* Create the socket. */
	s = socket(AF_INET, SOCK_DGRAM, 0);
	if (s == -1) {
		perror(argv[0]);
		fprintf(stderr, "%s: unable to create socket\n", argv[0]);
		exit(1);
	}
	/* Bind the server's address to the socket. */
	if (bind(s, &myaddr_in, sizeof(struct sockaddr_in)) == -1) {
		perror(argv[0]);
		fprintf(stderr, "%s: unable to bind address\n", argv[0]);
		exit(1);
	}
	/*
	 * Now, all the initialization of the server is complete, and any
	 * user errors will have already been detected.  Now we can fork the
	 * daemon and return to the user.  We need to do a setpgrp so that
	 * the daemon will no longer be associated with the user's control
	 * terminal.  This is done before the fork, so that the child will
	 * not be a process group leader.  Otherwise, if the child were to
	 * open a terminal, it would become associated with that terminal as
	 * its control terminal.  It is always best for the parent to do the
	 * setpgrp.
	 */
	setpgrp();

	switch (fork()) {
	case -1:		/* Unable to fork, for some reason. */
		perror(argv[0]);
		fprintf(stderr, "%s: unable to fork daemon\n", argv[0]);
		exit(1);

	case 0:		/* The child process (daemon) comes here. */
		for (;;) {
			/*
			 * Note that addrlen is passed as a pointer so that
			 * the recvfrom call can return the size of the
			 * returned address.
			 */
			addrlen = sizeof(struct sockaddr_in);
			/*
			 * This call will block until a new request arrives.
			 * Then, it will return the address of the client,
			 * and a buffer containing its request. BUFFERSIZE -
			 * 1 bytes are read so that room is left at the end
			 * of the buffer for a null character.
			 */
			cc = recvfrom(s, buffer, BUFFERSIZE - 1, 0,
				      &clientaddr_in, &addrlen);
			if (cc == -1) {
				perror(argv[0]);
				exit(1);
			}
			buffer[cc] = '\0';
			if ((pwd = getpwnam(buffer)) == NULL) {
				fprintf(stderr, "%s: unknown user %s\n");
				exit(1);
			}
			/* Fork and exec xlock */
			switch (fork()) {
			case -1:
				perror(argv[0]);
				fprintf(stderr, "%s: unable to fork xlock\n", argv[0]);
				break;
			case 0:
				setgid(pwd->pw_gid);
				setuid(pwd->pw_uid);
				execl("/usr/bin/X11/xlock", "xlock", (char *) NULL);
			default:
				wait((int *) NULL);
			}

		}

	default:		/* Parent process comes here. */
		exit(0);
	}
}
xxxxxxxxxxxxxxxx cut here xxxxxxxxxxxxxxxx

and you run the corresponding client on the remote host:

xxxxxxxxxxxxxxxx cut here xxxxxxxxxxxxxxxx
/*
 * C L I E N T . U D P
 * 
 * This is an example program that demonstrates the use of datagram sockets as
 * an IPC mechanism.  This contains the client, and is intended to operate in
 * conjunction with the server program found in serv.udp.  Together, these
 * two programs demonstrate many of the features of sockets, as well as good
 * conventions for using these features.
 * 
 * This program requests a service called "xlock".  In order for it to function,
 * an entry for it needs to exist in the /etc/services file.  The port
 * address for this service can be any port number that is likely to be
 * unused, such as 22375, for example.  The host on which the server will be
 * running must also have the same entry (same port number) in its
 * /etc/services file.
 * 
 * The "xlock" service is starts the xlock program on an "X terminal mode"
 * workstation, i.e. a workstation that has only the X server and the xlock
 * server running, so that the user has no way to start xlock (normally
 * started from the window manager).
 * 
 */

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/errno.h>
#include <netinet/in.h>
#include <stdio.h>
#include <netdb.h>

extern int      errno;

int             s;		/* socket descriptor */

struct hostent *hp;		/* pointer to host info for nameserver host */

struct servent *sp;		/* pointer to service information */

struct sockaddr_in myaddr_in;	/* for local socket address */
struct sockaddr_in servaddr_in;	/* for server socket address */

#define RETRIES	5		/* number of times to retry before givin up */

/*
 * M A I N
 * 
 * This routine is the client which requests service from the remote "xlock
 * server".
 */
main(argc, argv)
	int             argc;
	char           *argv[];
{
	int             i;
	int             retry = RETRIES;	/* holds the retry count */
	char           *display, *colon, *logname;
	char           *inet_ntoa();

	/* clear out address structures */
	memset((char *) &myaddr_in, 0, sizeof(struct sockaddr_in));
	memset((char *) &servaddr_in, 0, sizeof(struct sockaddr_in));

	/* Set up the server address. */
	servaddr_in.sin_family = AF_INET;
	/*
	 * Get the host information for the server's hostname that the user
	 * passed in.
	 */

	if ((display = getenv("DISPLAY")) == NULL) {
		fprintf(stderr, "No $DISPLAY.\n");
		exit(1);
	}
	colon = strchr(display, ':');
	if (colon == NULL) {
		fprintf(stderr, "Malformed $DISPLAY\n");
		exit(1);
	}
	*colon = 0;

	hp = gethostbyname(display);
	if (hp == NULL) {
		fprintf(stderr, "%s: unknown host %s\n",
			argv[0], display);
		exit(1);
	}
	logname = getenv("LOGNAME");

	servaddr_in.sin_addr.s_addr = ((struct in_addr *) (hp->h_addr))->s_addr;
	/*
	 * Find the information for the "xlock" server in order to get the
	 * needed port number.
	 */
	sp = getservbyname("xlock", "udp");
	if (sp == NULL) {
		fprintf(stderr, "%s: xlock not found in /etc/services\n",
			argv[0]);
		exit(1);
	}
	servaddr_in.sin_port = sp->s_port;

	/* Create the socket. */
	s = socket(AF_INET, SOCK_DGRAM, 0);
	if (s == -1) {
		perror(argv[0]);
		fprintf(stderr, "%s: unable to create socket\n", argv[0]);
		exit(1);
	}
	/* Send the request. */
	if (sendto(s, logname, strlen(logname), 0, &servaddr_in,
		   sizeof(struct sockaddr_in)) == -1) {
		perror(argv[0]);
		fprintf(stderr, "%s: unable to send request\n", argv[0]);
		exit(1);
	}
	exit(0);
}
xxxxxxxxxxxxxxxx cut here xxxxxxxxxxxxxxxx
--
Tor Lillqvist,
working, but not speaking, for the Technical Research Centre of Finland

munir@hpfcmgw.HP.COM (Munir Mallal) (11/03/90)

  >We have about 7 hp 9000/318 which used to be faculty workstations
>before we got some 345's. The 318's have 4 Megs are are now diskless
>student machines. The problem: X11 barely runs on these things. It is
>*real* slow and unresponsive. My questions is: Is there a way of running
>the X11 Server on one of our more powerful hp's and run a small program
>on the diskless which just draws to the screen. This way, the apps could
>still run on the diskless but the server would be on a big server. Is
>this possible/impossible/stupid?

What you might be able to do to improve the performance is to tune the kernel 
on the diskless nodes to increase the amount of RAM available to X.  A good 
start is to reduce nbuf since once X is started, there will be little
filesystem activity.  Also make sure that only essential processes are 
running on the 318s.

Munir Mallal

Disclaimer:  Tuning only improves inefficiently used resources, you will 
             never get more performance than your machine has to offer.
             My opinions are my own, HP has a support process which will
             probably yeild better results.

hardy@golem.ps.uci.edu (Meinhard E. Mayer (Hardy)) (11/03/90)

HP supplies a version of xdm with its Xterminal (700-something)
distribution. Ask your HP-person for it.

----****----
Professor Meinhard E. Mayer
Department of Physics
University of California
Irvine, CA, 92717
USA

alan@km4ba.UUCP (Alan Barrow) (11/04/90)

I am using X on a 318. It is very slow, mainly because 
hp-ux & X need more than 4 MB. You are continually swapping.

You can try to reuce your memory requirements, but it will still
be slow.

One of the 3rd pty memory manufacturers will add 4 MB to your
318. It is prob. not supported by HP, and might void your service
contract.

But, it remains that the 318 has a 330 cpu board in it, and their
mod involves a new backplane/connector board that allows you to
plus in thier memory expansion card. It was around $2k.

to answer your original question, I do not know of a way to do that.

Good Luck!

Alan Barrow km4ba

..!gatech!kd4nc!km4ba!alan

scotta@hpcuhd.HP.COM (Scott Anderson) (11/06/90)

    When I used to have a 318, my solution was to tune the kernel
(previously mentioned), glean daemons that I didn't need (e.g.
rfadaemon, vtdaemon, etc.) from the system by modifying the startup
scripts and finally, have my .x11start do a remsh to run a script on a
350 that started all my clients on that machine.  The end result was
that only the X server was running on the 318 and all the X clients were
running on the 350.  By doing this, I ended up with better performance
than 330's fully loaded with memory that had both the server and clients
running on them.  BTW, you'll want to make sure that your "power box"
(the 350 in my case) has enough memory/CPU in order to accommodate the
extra load.

    Scott Anderson
    An RTEsian and proud of it...		Hewlett-Packard
						Data Systems Operation
    scotta@cup.hp.com				11000 Wolfe Rd.  MS 42UN
    408-447-5219				Cupertino, CA  95014

alan@km4ba.UUCP (Alan Barrow) (11/26/90)

FYI, I have seen 3rd party memory people in the mags that
claim to provide a 4Mb upgrade for 318's. 

I have no idea how good they are, and they will prob. 
void any warantee you have, but if you need more memory,
they claim to do it.

Check the HP focused magazines, that is where I saw them.

Good luck!

Alan Barrow

..!gatech!kd4nc!km4ba!alan