What was done to make this release faster

Stack redesign to remove the names of variable from the stack.  This reduces the function call time overhead by 60%(?).

Opcode redesign and microcode support for some of the common operations.  CONS is now in microcode.

Several functions were reimplemented to improve performance, e.g. READ, (anyone know any others?).

Anything else???

 

WAYS OF DETERMINING WHAT IS GOING ON INSIDE YOUR PROGRAMS

TIMEALL

(TIMEALL FORM NREPS) EVALuates FORM and gives time and storage use for all types of storage for FORM.

BREAKDOWN

BREAKDOWN (described in chapter 21 of the Interlisp Manual) provides a breakdown of computation time on a function by function basis.  It works best on larger chunks of program.

Stats

Provides an accurate, low level measure of where time is being spent on a function by function basis as well as giving dynamic calling information.  Requires loading two files (APS.DCOM and PCALLSTATS.DCOM).  See the memo on using statistics.

Control-T

An interrupt character that gives the function being executed and the percentages of time spent in disk, keyboard, network, garbage collection and cpu (assumed to be everything else).  The percentage are since the last control-T so that typing a multiple control-t's will give a good indication of current usage. 

Control-C

An interrupt character that calls RAID.  From RAID, the entire stack can be examined (using the L command - see Interlisp-D User-s's Guide) to determine what function are being executed.  This is occasionally a good way to determine what functions are using storage.

WAYS OF MAKING THINGS MORE EFFICIENT

Method of variable binding

A major difference between Interlisp-10 and Interlisp-D is the method of accessing free variables.  Interlisp-10 uses what is called "shallow" binding.   Interlisp-D uses what is called "deep" binding.  

The binding of variables occurs when a function or a PROG is entered.  For example, if the function FOO has the definition (LAMBDA (A B) body), the variable A and B are bound so that any reference to A or B from "body" or any function called from "body" will refer to the arguments to the function FOO and not to the value of A or B from a higher level function.  All variable names (ATOMs) have a top level value cell which is used if the variable is used before it has been bound.   In discussions of variable access, it is useful to distinquish between three types of variable access: local, special and global.  Local variable access is the use of a variable that is bound within the function from which it is used.  Special variables access is the use of a variable that is bound by another function.  Global variable access is the use of a variable that has not been bound.  We will often refer to a variable all of whose accesses are local as a "local variable."  Similarly, a variable all of whose accesses are global we call a "global variable."    

In a "deep" bound system, A variable is bound by saving on the stack the variable's name together with a value cell which contains that variable's new value.  When a variable is accessed, its value is found by searching the stack for the most recent binding (occurrence) and retrieving the value stored there.

In a "shallow" bound system, a variable is bound by saving on the stack the variable name and the variables old value and putting the new value in the variable's top level value cell.  When a variable is accessed, its value is always found in its top level value cell.

The deep binding scheme has one disadvantage: the amount of cpu time required to fetch the value of a variable depends on the stack distance between its use and its binding.  The compiler can determine local variable accesses and compiles them as fetches directly from the stack.  Thus this computation cost only arises in the use of variable not bound in the frame (called "free" variables).  The process of finding the value of a free variable is called free variable lookup.

In a shallow bound system, the amount of cpu time required to fetch the value of a variable is constant regardless of whether the variable is local, special or global.  The disadvantages of this scheme are that the actual binding of a variable takes longer (thus slowing down function call), the cells that contain the current in use values are spread through out the space of all atom value cells (thus increasing the working set size of functions) and that context switching between processes requires unwinding and rewinding the stack (thus effectively prohibiting the use of context switching for many applications).

A deep binding scheme was choosen for Interlisp-D because of the working set considerations and the speed of context switching which we expected to use heavily when processes were added.  The free variable look up routine was microcoded, thus greatly reducing the search time.  In the benchmarks we performed, the largest percentage of free variable look up time was 20 percent of the total ellapsed time and the more normal time between 5 and 10 percent.

The ramification of deep binding for users is that they can, in some cases, signifigently improve performance by declaring global variables.  If a global variable is declared global, the compiler will compile an access to that variable as a retrieve of its top level value.  This should be done only for variables that are never bound such as variables used for databases or flags.

Declarations can be done in two ways.  One way is to include the file package command GLOBALVARS on the coms of a file.  Its form is (GLOBALVARS  var1 var2 ... varN).  The other way is to include a declaration in the functions that access the variables.  This is done by including the form (DECLARE (GLOBALVARS var1 var2 ... varN)) following the argument list in the definition of the function.  It declares var1 thru varN global within the body of this function.

Declare (LOCALVARS . T)
Makes free variable look up faster.  Makes function entry faster. Enables optomizations in the compiler.

METHODS OF REPRESENTING DATA

Use datatypes instead of records

For data structures that are large (more than 8 fields) and used alot, DATATYPEs have several advantages over RECORDs.  For code that has been written using the record package's fetch, replace and create operations, changing to datatypes requires only editting the record declaration (using EDITREC) to replace declaration type RECORD by DATATYPE, and recompiling.

Saves on time to access and set.  Makes the compiled code which uses them smaller.  Reduces the interactions with the garbage collector.

Dangers: Finite number of datatypes.  Datatypes are allocated on a page basis so each type has at least one page.

Comments: file package command ULGYVARS

Save and reuse resources.

Avoid certain functions in inner loops: PACK, CONCAT

The small number ranges (the range of integers that can be represented without additional storage) is greater in Interlisp-D than in Interlisp-10 but the time lost by falling outside those ranges is greater.  The small number range is from -2↑16 to 2↑16-1.

REASONS WHY THINGS MAY BE TAKING LONGER

Compiler

The Interlisp-D compiler performs many optimizations whereas the Interlisp-10 compiler performs almost none.  (See Masinter and Deustch, Compiler design in Papers on Interlisp-D.)  These optimizations take time during the compilation but produces faster and/or smaller code which results in faster execution time.  For special applications in which fast object code is unimportant, there is a fast compiler (FCOMPILE).

Disk and Network I/O

During files operations such as loading, making a file or compiling a file, a significant amount of time can be spent in disk or network I/O, particularly when performing I/O to a busy file server.

Swapping

When changing working sets or when operating in a sysout that has become fragmented, or when running very large working set programs, a significant amount of time can be spent swapping.  This is signaled in the cursor.  The top line is flashed on while doing a page read.  The bottom line is flashed on while doing a page write.  It is possible to get an indication of the amount of time that is being spent in I/O and swapping by typing control-T which will print out the percentage of time spent in various modes of I/O since the last control-T.

The new system has a facility that writes out dirty pages under tty I/O wait.  This feature will also try to keep a consistent virtual memory image to increase the changes of recovery after a system crash.

File maps

When moving files that are created by Interlisp-10 to dolphins with FTP,  if the transfer is not done in "transparent" mode, the carriage-return-linefeed sequences are translated into carriage returns.  Part of an Interlisp file (called the filemap) contains byte pointers to the functions in the file.  Translating the CR/LFs invalidates these pointers because is changes the number of characters on the file.  Interlisp recognizes when this has occurred and recalculates the filemap (a lengthy operation).

Garbage Collector

Interlisp-D uses a modified reference counting scheme of garbage collection.  This places more of the time burden of storage use on the allocation and setting of cells than does the "mark and sweep" collector of Interlisp-10.  The advantage of the reference counting scheme is that the time to do a garbage collection is proportional to the amount of garbage collected, NOT to the amount of address space in use.  This means that garbage collections take much less time in Interlisp-D than in Interlisp-10 but that each storage allocation requires slightly longer than it might.