Apply this to all benchmarks.

(Message inbox:1659)
To: lm@sgi.com
Subject: current status
Date: Mon, 02 Jun 1997 11:14:05 -0700
From: Carl Staelin <staelin@hplchs.hpl.hp.com>

Larry,

I am home sick (I think I must have caught your cold), but I 
have made some progress on lmbench.  I have enclosed copies
of bench.h and lat_sig.c which have the new timing loop
macro LOOP and examples of its use.

Carl


# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by Carl Staelin <staelin@hplchs> on Mon Jun  2 11:13:46 1997
#
# This archive contains:
#	bench.h		lat_sig.c	
#

LANG=""; export LANG
PATH=/bin:/usr/bin:/usr/sbin:/usr/ccs/bin:$PATH; export PATH

echo x - bench.h
cat >bench.h <<'@EOF'
/*
 * $Id: bench.h,v 1.14 1997/05/27 23:03:14 lm Exp staelin $
 */
#ifndef _BENCH_H
#define _BENCH_H

#include        <stdio.h>
#include        <unistd.h>
#include        <stdlib.h>
#include        <sys/types.h>
#include        <signal.h>
#include        <errno.h>
#include	"config.h"

#ifdef	NO_PORTMAPPER	/* not recently tested */
#define	TCP_XACT	-3962
#define	TCP_CONTROL	-3963
#define	TCP_DATA	-3964
#define	TCP_CONNECT	-3965
#else
#define	TCP_XACT	(u_long)404039	/* XXX - unregistered */
#define	TCP_CONTROL	(u_long)404040	/* XXX - unregistered */
#define	TCP_DATA	(u_long)404041	/* XXX - unregistered */
#define	TCP_CONNECT	(u_long)404042	/* XXX - unregistered */
#define	UDP_XACT 	(u_long)404032	/* XXX - unregistered */
#define	UDP_DATA 	(u_long)404033	/* XXX - unregistered */
#define	VERS		(u_long)1
#endif

#define	UNIX_CONTROL	"/tmp/lmbench.ctl"
#define	UNIX_DATA	"/tmp/lmbench.data"
#define	UNIX_LAT	"/tmp/lmbench.lat"

/*
 * socket send/recv buffer optimizations
 */
#define	SOCKOPT_READ	0x0001
#define	SOCKOPT_WRITE	0x0002
#define	SOCKOPT_RDWR	0x0003
#define	SOCKOPT_PID	0x0004
#define	SOCKOPT_REUSE	0x0008
#define	SOCKOPT_NONE	0

#ifndef SOCKBUF
#define	SOCKBUF		(1024*1024)
#endif

#ifndef	XFERSIZE
#define	XFERSIZE	(64*1024)	/* all bandwidth I/O should use this */
#endif

#ifdef SYS5
#define	bzero(b, len)	memset(b, 0, len)
#define	bcopy(s, d, l)	memcpy(d, s, l)
#define	rindex(s, c)	strrchr(s, c)
#endif
#define	ulong	unsigned long

#define	TIME_OPEN2CLOSE

#define	GO_AWAY	signal(SIGALRM, exit); alarm(60 * 60);
#define	SHORT	 1000000
#define	MEDIUM	 5000000
#define	LONGER	10000000	/* for networking, etc */
#define	ENOUGH	SHORT

#define LOOP(loop_body, loop_size, result, N, usecs, enough, t_overhead, 
l_overhead)		\
{									\
	static int	_N = 1;						\
timit:	loop_body;	/* warm the instruction cache */		\
	start(0);							\
	for ((N) = _N; (N) > 0; --(N)) {				\
		loop_body;						\
	}								\
	usecs = stop(0,0);						\
	/*  \
	   fprintf(stderr, "\tN=%d u=%lu", _N, (unsigned long)usecs);	\
	   fflush(stderr);\
	   fprintf(stderr, " c=%.2f\tr=%.2f\n", (double)usecs/_N,	\
		((double)usecs - t_overhead - _N * l_overhead)		\
		/ (double)(_N * (loop_size)));  			\
	*/ \
	result  = (double)usecs;					\
	result -= t_overhead + _N * l_overhead;				\
	result /= (double)(_N * loop_size);				\
	if ((double)usecs < 0.99 * (double)enough			\
	    || (double)usecs > 1.2 * (double)enough) {			\
		if (usecs > 150)					\
			_N = (int)(1.1 * (double)(_N * enough) / 	\
					(double)usecs) + 1; 		\
		else							\
			_N *= 10;					\
	}								\
	if ((double)usecs < 0.95 * (double)enough) 			\
		goto timit;						\
	N = _N;								\
}

/*
 * Standard timing loop.  Usage:
 *
 *	LOOP_FIRST(N, usecs, time)
 *	<code that you want timed>
 *	LOOP_LAST(N, usecs, time)
 *
 * time is how long you think it should run to be accurate.
 * "N" is a variable that will be set to the number of times it 
 * took to get "usecs" duration.  You then use N & usecs to print
 * out your results.
 * 
 * Notes: 
 *
 * Adjust the amount of time proportional to how
 * far we need to go.  We want time/usecs to be ~1.
 *
 * For systems with low resolution clocks, usecs can
 * be 0 or very close to 0.  We don't know how 
 * much time we spent, it could be anywhere from
 * 1 to 9999 usecs.  We pretend it was 1000 usecs.
 * The 129 value is because some systems bump the
 * timeval each time you call gettimeofday().
 */
#define	LOOP_FIRST(N, usecs, time)			\
	N = 0;						\
	do {						\
		if (!N) {				\
			N = 1;				\
		} else {				\
			double	adj;			\
			int	n;			\
			if (usecs <= 129) {		\
				usecs = 1000;		\
			}				\
			adj = (int)((time * 1.5)/usecs + .9);	\
			n = N * adj;			\
			/*printf("\tN=%.2f u=%.2f a=%.2f n=%d\n", \
			    (double)N, (double)usecs, adj, n);  \
			*/ \
			N = n <= N ? N+1 : n;		\
		}					\
timit:		usecs = N;				\
		start(0);				\
		while (usecs--) {

#define	LOOP_LAST(N, usecs, time)			\
		}					\
		usecs = stop(0,0);			\
	} while (usecs < time);				



/*
 * Generated from msg.x which is included here:

	program XACT_PROG {
	    version XACT_VERS {
		char
		RPC_XACT(char) = 1;
    	} = 1;
	} = 3970;

 * Please do not edit this file.
 * It was generated using rpcgen.
 */

#include <rpc/types.h>

#define XACT_PROG ((u_long)3970)
#define XACT_VERS ((u_long)1)
#define RPC_XACT ((u_long)1)
#define RPC_EXIT ((u_long)2)
extern char *rpc_xact_1();
extern char *client_rpc_xact_1();

#endif /* _BENCH_H */
@EOF

chmod 644 bench.h

echo x - lat_sig.c
cat >lat_sig.c <<'@EOF'
/*
 * lat_sig.c - signal handler test
 *
 * XXX - this benchmark requires the POSIX sigaction interface.  The reason
 * for that is that the signal handler stays installed with that interface.
 * The more portable signal() interface may or may not stay installed and
 * reinstalling it each time is expensive.
 *
 * XXX - should really do a two process version.
 *
 * Copyright (c) 1994 Larry McVoy.  Distributed under the FSF GPL with
 * additional restriction that results may published only if
 * (1) the benchmark is unmodified, and
 * (2) the version in the sccsid below is included in the report.
 */
char	*id = "$Id: lat_sig.c,v 1.10 1997/05/27 23:02:49 lm Exp staelin $\n";

#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/signal.h>
#include <fcntl.h>
#include "timing.h"
#include "bench.h"
#include "stats.h"

#define TRIES 49


uint64	enough;
double	t_overhead;
double	l_overhead;
double	kill_overhead;

void	handler() { }
void	prot() {
	static int	n = 1, caught = 0, tries = 0;
	static double	results[TRIES];
	if (++caught == n) {
		uint64	usecs;
		usecs = stop(0,0);
		results[tries] = (double)usecs;
		results[tries] -= t_overhead + n * l_overhead;
		results[tries] /= (double)n;
		if ((double)usecs < 0.99 * (double)enough
		    || (double)usecs > 1.2 * (double)enough) {
			if (usecs > 150)
				n = (int)((double)(1.1 * n * enough) /
					  (double)usecs) + 1;
			else
				n *= 10;
		}
		if ((double)usecs >= 0.95 * (double)enough) tries++;
		if (tries >= TRIES) {
			fprintf(stderr, 
				"Protection fault: %.3f microseconds\n", 
				double_min(results, TRIES));
			exit(0);
		}
		/* reset the timing for the next try */
		caught = 0;
		start(0);
	}
}

double
overhead()
{
	int	me = getpid(), N, usecs, i;
	double	results[TRIES];

	/*
	 * OS cost of sending a signal without actually sending one
	 */
	for (i = 0; i < TRIES; ++i) 
		LOOP(kill(me, 0), 1, results[i], N, usecs, enough, t_overhead, l_overhead);
	return double_min(results, TRIES);
}

void
siginstall()
{
	struct	sigaction sa, old;
	sa.sa_handler = handler;
	sigemptyset(&sa.sa_mask);	
	sa.sa_flags = 0;
	sigaction(SIGUSR1, &sa, &old);
}

void
do_install()
{
	int	N, usecs, i;
	double	results[TRIES];

	/*
	 * Installation cost
	 */
	for (i = 0; i < TRIES; ++i)
		LOOP(siginstall(), 1, results[i], N, usecs, enough, t_overhead, l_overhead);

	fprintf(stderr, "Signal handler installation: %.3f microseconds\n", 
		double_min(results, TRIES));
}

void
do_catch(int report)
{
	int	me = getpid(), N, usecs, i;
	struct	sigaction sa, old;
	double	results[TRIES];

	kill_overhead = overhead();

	/*
	 * Cost of catching the signal less the cost of sending it
	 */
	sa.sa_handler = handler;
	sigemptyset(&sa.sa_mask);	
	sa.sa_flags = 0;
	sigaction(SIGUSR1, &sa, &old);

	if (!report) return;

	for (i = 0; i < TRIES; ++i) 
		LOOP(kill(me, SIGUSR1), 1, results[i], N, usecs, enough, t_overhead, 
l_overhead);
	fprintf(stderr, "Signal handler overhead: %.3f microseconds [total = %.3f, 
overhead = %.3f]\n",
		double_min(results, TRIES) - kill_overhead,
		double_min(results, TRIES), kill_overhead);
}

void
do_prot(int ac, char **av)
{
	int	fd;
	struct	sigaction sa;
	char	*where;

	if (ac != 3) {
		fprintf(stderr, "usage: %s prot file\n", av[0]);          
		exit(1);
	}
	fd = open(av[2], 0);
	where = mmap(0, 4096, PROT_READ, MAP_SHARED, fd, 0);
	if ((int)where == -1) {
		perror("mmap");
		exit(1);
	}
	/*
	 * Catch protection faults.
	 * Assume that they will cost the same as a normal catch.
	 */
	do_catch(0);
	sa.sa_handler = prot;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = 0;
	sigaction(SIGSEGV, &sa, 0);
	sigaction(SIGBUS, &sa, 0);
	start(0);
	*where = 1;
}

int
main(int ac, char **av)
{
	if (ac < 2) goto usage;

	initialize_timing();

	if (!strcmp("install", av[1])) {
		do_install();
	} else if (!strcmp("catch", av[1])) {
		do_catch(1);
	} else if (!strcmp("prot", av[1])) {
		do_prot(ac, av);
	} else {
usage:		printf("Usage: %s install|catch|prot file\n", av[0]);
	}
	exit(0);
}
@EOF

chmod 644 lat_sig.c

exit 0

-- 
-------------------------------------------------------------------------------
Carl Staelin				
  email:	staelin@hpl.hp.com		Hewlett-Packard Laboratories
  voice:	(415)857-6823			1501 Page Mill Road, M/S 3L-9
  FAX:		(415)852-2986			P.O. Box 10490
  http://www.hpl.hp.com/personal/Carl_Staelin	Palo Alto, CA 94303-0969
-------------------------------------------------------------------------------

[61;1H[K
