Re: Why are intepreters so slow today

(davis@pacific.mps.ohio-state.edu)
Tue, 19 Apr 1994 19:42:08 GMT

In article <nagleCoACH4.25p@netcom.com> nagle@netcom.com (John Nagle) writes:
> Lately, I've been looking at interpreters suitable for use as
> extension languages in a control application. I need something that
> can do computation reasonably fast, say no worse than 1/10 of the
> speed of compiled C code. Interpreters have been written in that speed
> range quite often in the past. But when I try a few of the interpreters
> available on the Mac, performance is terrible.
>
> My basic test is to run something equivalent to
>
> int i; double x = 0.0;
> for (i = 0; i < 1000000; i++) x = x + 1.0;
>
> The Smalltalk and Python versions are slower than the C version by factors
> of greater than 1000. This is excessive. LISP interpreters do a bit
> better, but still don't reach 1/10 of C. What interpreters do a decent
> job on computation?

I think that you are being *far* too optimistic about the speed of an
interpreter. Interpreters implement all sorts of run time type checking and
range checking that compilers do not. In addition, a good interpreter will
implement some form of garbage collection so that one does not have to worry
about memory allocation. All of this takes up tremendous overhead.

To get some idea of what I am talking about, consider your loop coded in the
following form:

#include <stdio.h>

/* #define INTERP */
#ifdef INTERP
int LT (int a, int b, int c) { if (c) return a < b; return 0; }
int IADD (int a, int b, int c) { if (c) return a + b; return 0;}
double FADD (double a, double b, int c) { if (c) return a + b; return 0.0;}
void IASSIGN(int *a, int b, int c) { if (c) *a = b;}
void FASSIGN(double *a, double b, int c) { if (c) *a = b;}
int IVALUE (int a, int c) { if (c) return a; return 0;}
double FVALUE (double a, int c) { if (c) return a; return 0.0;}

#else
# define LT(a,b,c) ((a) < (b))
# define IADD(a,b,c) ((a) + (b))
# define IASSIGN(a, b, c) *(a) = (b)
# define IVALUE(x, c) (x)
# define FADD(a,b, c) ((a) + (b))
# define FASSIGN(a, b, c) *(a) = (b)
# define FVALUE(x, c) (x)
#endif

int main ()
{
double x;
int i;

FASSIGN(&x, FVALUE(0.0, 1), 1);

for (IASSIGN(&i, IVALUE(0, 1), 1);
LT(IVALUE(i, 1), IVALUE(1000000, 1), 1);
IASSIGN(&i, IADD(IVALUE(i, 1), IVALUE(1, 1), 1), 1))
{
FASSIGN(&x, FADD(FVALUE(x, 1), FVALUE(1.1, 1), 1), 1);
}
fprintf (stdout, "%f\n", FVALUE(x, 1));
return 0;
}

Without INTERP defined, this will preprocess into basically your loop. If
INTERP is defined, it compiles into something more analogous to what an
inerpreter would do. Although the function calls mimic some of the overhead
of an interpreter, an interpreter still has far more overhead. The above
program with what I consider minimal overhead runs 10 times slower.

Finally, given the rule of thumb that a program spends 90% of its time
executing 10% of the code, an embedded interpreter such as S-Lang will
probably meet your needs. Since S-Lang is trivial to embed into a C program,
I would say that by choosing the right intrinsics, embedding S-Lang would
produce an interpreted program that is asymptotically as fast as a C program.

--
     _____________
#___/John E. Davis\_________________________________________________________
#
# internet: davis@amy.tch.harvard.edu
#   bitnet: davis@ohstpy
#   office: 617-735-6746
#