chris%umcp-cs.csnet@csnet-relay.arpa (02/28/84)
From: Chris Torek <chris%umcp-cs.csnet@csnet-relay.arpa> Here is a set of modifications for Emacs (#264), to speed up startup. It makes a noticeable difference -- in fact, if I run an "emacs -q -eexit-emacs" in "/", Emacs now finishes in less time than Vi! (Of course, most startups will be slower: the "-q" option is our "quick Emacs" mod; it bypasses the .emacs_pro file.) All changes are contained within the file "macros.c". Rather than including a "diff" listing, I'll just describe what to do, and supply some new routines. *** Note *** *** For #85, you would have to change the code that defines the *** "nothing" procedure. Instead of putting a 0 in directly, *** you should introduce the "nothing" function earlier, and *** then set *** MacBodies[FindMac ("nothing")] = 0; *** I think that will work. Also, you can't use the DefMac *** routine as given here. The only part I changed was the code *** that adds a new macro; the rest should probably remain the *** same. *** *** etoN ------------ Instructions ------------ .5 SAVE THE OLD macros.c FILE!!! 1. Add '#include <ctype.h>' after '#include "buffer.h"' 2. Delete the "static MacrosAreSorted;" 3. In FindMac 3a. delete the unused "int cmp;" 3b. Delete the line referencing MacrosAreSorted (macros will always be sorted) 4. Replace the old DefMac function with the one below 5. Delete the SortMacros function 6. Replace the old ScanMap function with the one below 7. In InitMacros 7a. Between the last defproc() and the first ScanMap() call, add the lines NMacs = NewNames - MacBodies; QSortA (MacBodies, &MacBodies[NMacs - 1]); 7b. Between the last ScanMap() and the for (i) loop, add the line QSortN (MacBodies, &MacBodies[NMacs - 1]); 7c. Delete the call to SortMacros ---------------------------- New or replacement functions ---------------------------- /* define the named macro to have the given body (or mlisp proc) This procedure occupies a lot of time when loading mlisp packages and/or .emacs_pro's, so it's been tweaked. */ DefMac (s, body, IsMLisp) union { struct keymap *b_keymap; char *b_string; } body; char *s; { register int i; register struct BoundName *p; if ((i = FindMac (s)) < 0) { register struct BoundName **bp; register char **np; register struct BoundName **be; if (NMacs >= maxmacs) { error ("Too many macro definitions."); return; } np = &MacNames[NMacs]; bp = &MacBodies[NMacs++]; be = &MacBodies[-i - 1]; np[1] = 0; /* sneaky! */ while (bp > be) { np[0] = np[-1]; bp[0] = bp[-1]; --np, --bp; } p = *bp = (struct BoundName *) malloc (sizeof (struct BoundName)); p -> b_name = *np = savestr (s); p -> b_StepThrough = 0; } else { if ((p = MacBodies[i]) -> b_binding == ProcBound) { error ("%s is already bound to a wired procedure!", s); return; } if (IsMLisp == -1 /* Its an autoload definition of an already defined function, ignore it. */ && (p -> b_binding != MLispBound || p -> b_bound.b.b_start) && p -> b_binding != AutoLoadBound) return; if (p -> b_binding == KeyBound) { register struct buffer *b; for (b = buffers; b; b = b -> b_next) if (b -> b_mode.md_keys == p -> b_bound.b_keymap) b -> b_mode.md_keys = 0; if (CurrentGlobalMap == p -> b_bound.b_keymap) CurrentGlobalMap == &GlobalMap; if (bf_mode.md_keys == p -> b_bound.b_keymap) bf_mode.md_keys == 0; NextLocalKeymap = NextGlobalKeymap = 0; free (p -> b_bound.b_keymap); } else if (p -> b_binding == AutoLoadBound || p -> b_binding == MacroBound) free (p -> b_bound.b_body); } if (IsMLisp == -1) { p -> b_binding = AutoLoadBound; p -> b_bound.b_body = savestr (body.b_string); } else if (IsMLisp == -2) { p -> b_binding = KeyBound; p -> b_bound.b_keymap = body.b_keymap; } else if (IsMLisp) { p -> b_binding = MLispBound; p -> b_bound.b.b_start = body.b_string; } else { p -> b_binding = MacroBound; p -> b_bound.b_body = savestr (body.b_string); } } static ScanMap (map) register struct keymap *map; { register struct BoundName *p; register c; for (c = 0; c < 0200; c++) if (p = map -> k_binding[c]) { int lo = 0, hi = NMacs - 1; register struct BoundName **m; while (lo <= hi) { register mid = (lo + hi) >> 1; m = &MacBodies[mid]; if (*m == p) goto SkipIt; if (*m > p) hi = mid - 1; else lo = mid + 1; } m = &MacBodies[lo]; { register struct BoundName **j = NewNames++; while (j > m) { j[0] = j[-1]; j--; } } *m = p; NMacs++; SkipIt: if (islower (c)) map -> k_binding[toupper (c)] = p; } } static QSortN (l, h) struct BoundName **l; register struct BoundName **h; { register struct BoundName **i, **j; register char *s1, *s2; if ((i = l) >= h) return; j = h; partition: /* while (strcmp ((*i) -> b_name, (*h) -> b_name) < 0) i++; */ for (;;) { s1 = (*i) -> b_name; s2 = (*h) -> b_name; while (*s1 == *s2++) if (*s1++ == 0) goto out1; if (*s1 > *--s2) break; i++; } out1: /* while (--j > i && strcmp ((*j) -> b_name, (*h) -> b_name) > 0); */ while (--j > i) { s1 = (*j) -> b_name; s2 = (*h) -> b_name; while (*s1 == *s2++) if (*s1++ == 0) goto out2; if (*s1 < *--s2) break; } out2: if (i < j) { register struct BoundName *t; t = *i, *i = *j, *j = t; goto partition; } if (i < h) { register struct BoundName *t; t = *i, *i = *h, *h = t; QSortN (i + 1, h); } QSortN (l, i - 1); } static QSortA (l, h) struct BoundName **l; register struct BoundName **h; { register struct BoundName **i, **j; if ((i = l) >= h) return; j = h; partition: while (*i < *h) i++; while (--j > i && *j > *h); if (i < j) { register struct BoundName *t; t = *i, *i = *j, *j = t; goto partition; } if (i < h) { register struct BoundName *t; t = *i, *i = *h, *h = t; QSortA (i + 1, h); } QSortA (l, i - 1); } ----------------------------------------------------------- That's it! The heart of the speedup is really in ScanMap, where some 200 or so trips around the outer loop can use as an inner loop a binary -- rather than linear -- search, which more often than not actually locates something. A further possible speedup could be gained by modifying simplecoms.c and emacs.c such that self-insert is not bound to anything until after the keymaps have been scanned. But according to the last profile I made, much more could be gained by optimizing the read() and stat() system calls.... -- In-Real-Life: Chris Torek, Univ of MD Comp Sci UUCP: {seismo,allegra,brl-bmd}!umcp-cs!chris CSNet: chris@umcp-cs ARPA: chris.umcp-cs@CSNet-Relay