[comp.os.minix] vi under minix, ALSO profiling

kirkenda@psueea.uucp (Steve Kirkendall) (07/19/89)

At the end of this article is a profiler for Minix-ST.  But first...

In article <2892@ast.cs.vu.nl> ast@cs.vu.nl (Andy Tanenbaum) writes:
>In article <1385@bruce.OZ> mark@bruce.OZ (Mark Goodwin) writes:
>>Has anyone ported vi to Minix? 
>I have stevie running on MINIX.  It is pretty vi like, but keeps the file
>being edited in core, which limits it to files of around 50K.  It really
>is not well polished.  If you are really a vi addict, you could
>volunteer to finish it off :-)  The source is 56 files and 375K bytes C text.
>That shouldn't deter a real vi addict.  Emacs is 10 times that.  I
>think the source should be in the archives.  I am not wild about sending
>375K to Australia, but will do it if you can't find it elsewhere.

I've been working on a vi clone that uses temp files, like the real vi.
I can even recover files in case of a crash!  (Crashes are pretty common
at this stage in development.)

So far, I have most EX commands implemented and many of the VI movement
commands, but almost none of the VI editing commands.  My greatest concern
at this time is *speed* -- on my ST, it has a hard time keeping up with
auto-repeating keys.  (Zips along pleasantly on a 20MHz '386 running Xenix,
though; it can even keep up with auto-repeat of the <PgDn> key!)

Last night I had an inspiration which may allow me to speed things up.
I was fixing a bug, and thought, "Ugh! Why would I have done something
like that?  Oh, I see, it's simpler, faster, more compact, and less
error-prone. Hmmm..."

Size: About 50K text + 60K data.  That's on an ST; an 8086 would have smaller
text.  I don't expect the data size to grow much, but text will probably grow
by about 20K more.  In short: It *might* run under MINIX-PC.  The source is
perhaps 100K at this time; it will probably peak at about 125k.

 <<<----------------------------------------------------------------------->>>
 <<< VAPORWARE ALERT:  I work on this as I find time.  Lately I have found >>>
 <<< plenty of time, and have made good progress, but I can't *promise* a  >>>
 <<< delivery date.  Also, don't expect an exact clone; I'm writing this   >>>
 <<< precisely because there are a few things about VI that I don't like.  >>>
 <<<----------------------------------------------------------------------->>>

Having said that, I can tell you that I *hope* to have something worthwhile
in about two months.  Most differences concern the way text is displayed;
keystrokes won't differ much.

===============================================================================

Change of subject:

In working to speed up VI, I have been doing a lot of profiling.  The ACK
compiler supports profiling via the "-p" flag, but the library lacks the
necessary support functions.  So I wrote my own.

This code was developed for Minix-ST.  It should be compiled WITHOUT the
"-p" flag and added to /usr/lib/libc.a.  You should then compile your
program WITH "-p" and it will link in this code.  This code collects statistics
and then, when you return from main(), it writes the statistics to a file
called profile.out.  Note that you must *return* from main(); if you call
exit(), then profile.out will not be created.

This code also prints a stack trace in the event of a deadly signal.

------ cut here ---------- cut here ---------- cut here --------
cat >/usr/src/lib/profile.c
/* profile.c */

/* This file contains functions which implement profiling.  It depends on the
 * compiler to generate calls to procentry("funcname") at the start of every
 * function and procexit("funcname") at the end of each function.  Also,
 * these functions dump a stack trace in the event of a deadly signal.
 */

#include <sys/types.h>
#include <sys/times.h>
#include <stdio.h>
#include <signal.h>

static struct
{
	char	*name;	/* name of a function */
	long	time;	/* accumulates time */
	short	cnt;	/* number of calls */
}
		f[200];		/* tracks individual functions */
static struct
{
	char	*name;	/* name of the function */
	long	time;	/* records start time, used to calc elapsed time */
	long	xtime;	/* time spent in sub functions */
}
		stack[30];	/* tracks nested active functions */
static	int	ns, nf;

/* This function prints a stack trace */
static trace(signo)
	int		signo;
{
	static char	*signames[] = {
		"", "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", "SIGTRAP",
		"SIGIOT", "SIGEMT", "SIGFPE", "SIGKILL", "SIGBUS", "SIGSEGV",
		"SIGSYS", "SIGPIPE", "SIGALRM", "SIGTERM"
	};

	fprintf(stderr, "\r\n%s", signames[signo]);
	do
	{
		ns--;
		fprintf(stderr, "\t%s()\r\n", stack[ns].name);
	} while (ns > 0);
	exit(signo);
}

/* This function dumps the profiling info out to a file */
static pdump()
{
	int	i;
	FILE	*fp;

	fp = fopen("profile.out", "w");
	if (!fp)
		return;
	fprintf(fp, "    time  cnt name\n");
	for (i = 0; i < nf; i++)
	{
		fprintf(fp, "%8ld%5d %s\n", f[i].time, f[i].cnt, f[i].name);
	}
	fclose(fp);
}
/* This function is called at the start of every user function.  It records
 * the functions name (for stack tracing) and start time (for computation
 * of elapsed time).  The first time, it also arranges for trace() to be
 * run when a deadly signal happens.
 */
procentry(name)
	char	*name;
{
	struct tms	tbuf;

	/* initialize tracing? */
	if (ns == 0)
	{
		signal(SIGQUIT, trace);	/* ctrl-backslash */
		signal(SIGILL, 	trace);	/* illegal instruction */
		signal(SIGFPE, 	trace);	/* floating point exception */
		signal(SIGBUS, 	trace);	/* bus error */
		signal(SIGSEGV, trace);	/* segmentation violation */
	}

	/* record this function call */
	stack[ns].name = name;
	times(&tbuf);
	stack[ns].time = tbuf.tms_utime + tbuf.tms_stime;
	stack[ns].xtime = 0L;
	ns++;
}

/* This function is called at the end of each user function.  It updates the
 * function's time & cnt accumulators, and, if we're returning from main(),
 * it calls dump() to write the profile info to a file
 */
procexit(name)
	char	*name;
{
	struct tms	tbuf;
	int		i;

	times(&tbuf);

	/* find the function's slot */
	for (i = 0; i < nf && f[i].name != name; i++)
	{
	}
	if (i == nf)
	f[nf++].name = name;

	/* update it */
	ns--;
	stack[ns].time = tbuf.tms_utime + tbuf.tms_stime
				 - stack[ns].time - stack[ns].xtime;
	f[i].time += stack[ns].time;
	f[i].cnt++;

	/* if exiting main(), write the report */
	if (ns == 0)
	{
		pdump();
	}
	else
	{
		/* don't count the time as part of caller's time */
		stack[ns - 1].xtime += stack[ns].time + stack[ns].xtime;
	}
}
------ cut here ---------- cut here ---------- cut here --------
	-- Steve Kirkendall
	   ...uunet!tektronix!psu-cs!kirkenda