home *** CD-ROM | disk | FTP | other *** search
- Path: sparky!uunet!know!cass.ma02.bull.com!think.com!ames!agate!doc.ic.ac.uk!syma!ianr
- From: ianr@syma.sussex.ac.uk (Ian Rogers)
- Newsgroups: comp.lang.pop
- Subject: Re: Clarity VS Efficiency in POP11
- Message-ID: <1992Nov22.131443.11011@syma.sussex.ac.uk>
- Date: 22 Nov 92 13:14:43 GMT
- References: <TMR.92Nov21122734@emotsun.bham.ac.uk>
- Organization: University of Sussex at Brighton
- Lines: 160
-
- tmr@cs.bham.ac.uk (Tim Read) writes:
- > It is my feeling as a competent beginner in POP11, that putting too many
- > efficiency hacks into your code tends to lose the inherent clarity that
- > POP11 provides.
-
- Efficiency *hacks* are bad, sure (Pop11 buys you clarity, a Good
- Thing IMHO)
-
- > My conclusion is that (bearing in mind I am using an 86 MIP workstation), I
- > will not worry about efficiency until I notice that my program is running
- > slowly.
- > ....
- > Until I notice that it takes longer for the program to run than it does for
- > the data to be output, I'll lose no sleep over it....
-
- But it's this sort of attitude that's brought us dogs like
- OpenWindows (I now need a SuperZoom Mega BitBlitter graphics card
- with dual carbs, turbo charger and nitrous' laser injection paint
- whacker before my xterm can come up within a week :-(
-
- > An example of what I mean is using a temporary closure within a
- > loop, which looks nice and neat, but will cause extra garbage collections,
- > as opposed to using an lblock (As Aaron pointed out).
-
- So make a new data type (even notionally) and optimise the code,
- *after* you've finished development, by free-listing instances.
-
- A case in point:
-
- Last week I was developing a graphics package to draw links between
- graph nodes. The data structure for the lines are shortvecs of
- between 8 and 12 elements. These were being thrown around willy
- nilly, but that's ok 'cos I've got a garbage collector.
-
- So I set up an animation to demonstrate the links and I keep getting
- 1 second pauses. Hmm, garbage collector, bad news in direct
- manipulation user interfaces.
-
- So I write a free-listing utility:
-
- lconstant
- pvh_len = 12,
- pv_hold = initv(pvh_len),
- ;
-
- define free_pointvec(v);
- lvars v, i = length(v),
- ;
- returnif(i fi_> pvh_len);
- /***
- we need the second -fast_subscrv- to "persuade" the
- shortvec to act as a full vector
- ***/
- fast_subscrv(i, pv_hold) -> fast_subscrv(1, v);
- v -> fast_subscrv(i, pv_hold);
- enddefine;
-
- define make_pointvec(n);
- lvars n, v,
- ;
- if n fi_> pvh_len or (fast_subscrv(n, pv_hold) ->> v) == 0 then
- consshortvec(n)
- else
- fast_subscrv(1, v) -> fast_subscrv(n, pv_hold);
- () -> explode(v);
- v
- endif
- enddefine;
-
- constant old_pop_after_gc = pop_after_gc;
-
- /***
- The free-list table will be completely corrupted after a GC
- so we'd better clear it out :-)
- ***/
- define clear_pv_hold;
- set_subvector(0, 1, pv_hold, pvh_len);
- old_pop_after_gc();
- enddefine;
-
- define vars procedure pop_after_gc =
- clear_pv_hold;
- enddefine;
-
- Then I change all relevant calls to -consshortvec- with
- -make_pointvec-. Easy peasy, and the semantics and the look of the
- main body of the code hasn't changed one jot.
-
- The optimistations then come in carefully selecting where to place
- calls to -free_pointvec-. Purely by coincidence, I'm programming in
- the OOP paradigm so no other piece of code gets a look in on these
- data structures. There's only one place where the vectors are being
- trashed before making a new one. So:
-
- if link.pvec then
- free_pointvec(link.pvec);
- false -> link.pvec; ;;; just to make sure I don't try to use
- ;;; it later
- endif;
-
- This has now completely changed the store usage of my link objects.
- In the worst case, a link object will generate one of each size of
- vector and then cycle them through the free list.
-
- No more pauses in my user interface, Yipeee!! :->
-
- I've just realised I haven't answered your implied question. Hmm...
-
- In your case you can free-list the closures, either in a simple list
- if you're only making closures of a single procedure, or in a
- property that matches against the pdpart. I'll tackle the difficult
- case (if the weather wasn't so bad I'd be out walking on the South
- Downs :( )
-
- define lconstant pdr_table =
- newproperty([], 8, [], "tmpboth")
- enddefine;
-
- define make_closure(n) -> clos;
- lvars n, i, args, free, clos, pdr,
- ;
- conslist(n) -> args; ;;; get the rest of the stuff
- () -> pdr; ;;; from the stack
- pdr_table(pdr) -> free;
- if free == [] then
- ;;; just like before
- partapply(pdr, args) -> clos;
- else
- destpair(free) -> pdr_table(pdr) -> clos;
- 1 -> n;
- for i in args do
- i -> frozval(n, clos);
- n + 1 -> n;
- endfor;
- endif;
- sys_grbg_list(args);
- enddefine;
-
- define free_closure(clos);
- lvars clos, pdr = pdpart(clos),
- ;
- clos :: pdr_table(pdr) -> pdr_table(pdr);
- enddefine;
-
- vars a = identfn(% "a", "b" %);
- frozval(1, a) =>
- ** a
-
- vars b = make_closure(identfn, #| "a", "b" |#);
- frozval(1, b) =>
- ** a
-
- free_closure(a);
- vars c = make_closure(identfn, #| "c", "b" |#);
- frozval(1, c) =>
- ** c
-
- Ian.
- "Deep in the fundamental heart of mind and Universe,"
- said Slartibartfast, "there is a reason" - Douglas Adams
-