{Begin Chapter Performance Issues} {Title Performance Issues} {Text {index *PRIMARY* Performance analysis} This chapter describes a number of areas that often contribute to performance problems in Interlisp-D programs. Many performance problems can be improved by optimizing the use of storage, since allocating and reclaiming large amounts of storage is expensive. Another tactic that can sometimes yield performance improvements is to change the use of variable bindings on the stack to reduce variable lookup time. There are a number of tools that can be used to determine which parts of a computation cause performance bottlenecks. {Include GarbageCollection} {Include VariableBindings} {Include Measuring} {Include GainSpace} {Begin SubSec Using Data Types Instead of Records} {Title Using Data Types Instead of Records} {Text {index Data types} If a program uses large numbers of large data structures, there are several advantages to representing them as user data types rather than as list structures. The primary advantage is increased speed: accessing and setting the fields of a data type can be significantly faster than walking through a list with repeated {lisp CAR}s and {lisp CDR}s. Also, compiled code for referencing data types is usually smaller. Finally, by reducing the number of objects created (one object against many list cells), this can reduce the expense of garbage collection. User data types are declared by using the {lisp DATATYPE} record type ({PageRef (Record Type) DATATYPE}). If a list structure has been defined using the {lisp RECORD} record type ({PageRef (Record Type) RECORD}), and all accessing operations are written using the record package's {lisp fetch}, {lisp replace}, and {lisp create} operations, changing from {lisp RECORD}s to {lisp DATATYPE}s only requires editing the record declaration (using {fn EDITREC}, {PageRef Fn EDITREC}) to replace declaration type {lisp RECORD} by {lisp DATATYPE}, and recompiling. Note: There are some minor disadvantages with allocating new data types: First, there is an upper limit on the number of data types which can exist. Also, space for data types is allocated a page at a time, so each data type has at least one page assigned to it, which may be wasteful of space if there are only a few examples of a given data type. These problems should not effect most applications programs. }{End SubSec Using Data Types Instead of Records} {Begin SubSec Using Incomplete File Names} {Title Using Incomplete File Names} {Text {index File names} {index Incomplete File Names} Currently, Interlisp allows you to specify an open file by giving the file name. If the file name is incomplete (it doesn't have the device/host, directory, name, extension, and version number all supplied), the system converts it to a complete file name, by supplying defaults and searching through directories (which may be on remote file servers), and then searches the open streams for one corresponding to that file name. This file name-completion process happens whenever any I/O function is given an incomplete file name, which can cause a serious performance problem if I/O operations are done repeatedly. In general, it is much faster to convert an incomplete file name to a stream once, and use the stream from then on. For example, suppose a file is opened with {lisp (SETQ STRM (OPENSTREAM 'MYNAME 'INPUT))}. After doing this, {lisp (READC 'MYNAME)} and {lisp (READC STRM)} would both work, but {lisp (READC 'MYNAME)} would take longer (sometimes orders of magnitude longer). This could seriously effect the performance if a program which is doing many I/O operations. Note: At some point in the future, when multiple streams are supported to a single file, the feature of mapping file names to streams will be removed. This is yet another reason why programs should use streams as handles to open files, instead of file names. For more information on efficiency considerations when using files, see {PageRef Tag StreamFileNames}. }{End SubSec Using Incomplete File Names} {Begin SubSec Using "Fast" and "Destructive" Functions} {Title Using "Fast" and "Destructive" Functions} {Text Among the functions used for manipulating objects of various data types, there are a number of functions which have "fast" and "destructive" versions. The user should be aware of what these functions do, and when they should be used. {index Fast functions} "Fast" functions: By convention, a function named by prefixing an existing function name with {lisp F} indicates that the new function is a "fast" version of the old. These usually have the same definitions as the slower versions, but they compile open and run without any "safety" error checks. For example, {fn FNTH} runs faster than {fn NTH}, however, it does not make as many checks (for lists ending with anything but {lisp NIL}, etc). If these functions are given arguments that are not in the form that they expect, their behavior is unpredictable; they may run forever, or cause a system error. In general, the user should only use "fast" functions in code that has already been completely debugged, to speed it up. {index *PRIMARY* Destructive functions} "Destructive" functions: By convention, a function named by prefixing an existing function with {lisp D} indicates the new function is a "destructive" version of the old one, which does not make any new structure but cannibalizes its argument(s). For example, {fn REMOVE} returns a copy of a list with a particular element removed, but {fn DREMOVE} actually changes the list structure of the list. (Unfortunately, not all destructive functions follow this naming convention: the destructive version of {fn APPEND} is {fn NCONC}.) The user should be careful when using destructive functions that they do not inadvertantly change data structures. }{End SubSec Using "Fast" and "Destructive" Functions} {Begin Note} add info about: (WITHOUT-INTERRUPTS ---)? Date: 6-Oct-82 17:08:37 PDT (Wednesday) From: Masinter.PA I think WITHOUT-INTERRUPTS should just get strong warnings: do SAVEVM before timing anything because if it doesn't work, the only way out is to boot. Date: 6-Oct-82 16:12:16 PDT (Wednesday) From: vanMelle.PA WITHOUT-INTERRUPTS in its current state is far too dangerous to document. (WITHOUT-INTERRUPTS FORM) [NLAMBDA function] WITHOUT-INTERRUPTS is a special form for running real-time critical sections of code, or for doing benchmarks, since it filters out extraneous computations. It evaluates FORM with the display refresh, keyboard sampling, ethernet process, etc. all turned off. [Note: There is no way of recovering from an error underneath WITHOUT-INTERRUPTS except by booting!] {End Note} }{End Chapter Performance Issues} ?1(DEFAULTFONT 1 (GACHA 10) (GACHA 8) (TERMINAL 8)) ?1(DEFAULTFONT 1 (GACHA 10) (GACHA 8) (TERMINAL 8)) z