From: <do...@co...> - 2000-01-27 19:18:35
|
So who's on this list so far? I can't seem to find out. (Authentication fails?) I see one undigested member of clocc-list. I suggest maintaining one readme file in which the entire contents of the archive are listed. You should be able to download that and then search for what you want, rather than having to download many different subdirectories. I notice a good many empty subdirectories under src. Is there some organizational plan? A comment on one of the requirements for code in this repository: Self-contained, i.e. does not require packages not in this repository, I suggest that even reliance on this repository be minimized. I like the others, but is there such a thing as totally unlicensed code? Do you have to put something on the top in order to make it qualify as that? What's "public domain"? I'm open to suggestions. A few other suggestions: - Each piece of code, as much as possible should do one thing, so you can take what you need without having to get a lot of extra stuff. - Each piece (meant to be used as part of a larger system) should be in its own package (which most of my code violates so far, but which I'll try to fix before I send it in) with documented external interfaces. - Each piece should minimize its impact on the rest of the system. Acceptable impact is adding a new package, adding a new element to *modules*. It's real bad to change the meaning/value of anything in the standard environment (like changing *features*, *print-pretty*, or the standard readtables) unless the package is only meant to do that one thing. Even then, e.g., if you provide a new readmacro, it's best to provide a function that will install it if/when/where the user wants. Perhaps we can try to agree on some standards and post them somewhere. I look forward to hearing additional suggestions. Now finally to get around to answering the original message: Tell us about your intended code contributions. I guess I should look around and find out. I should also look at the things I find in order to make sure they're in shape for the library. Below is the first (and smallest) installment for your consideration and reading pleasure. It's meant for very low level optimization, where you want to find out how long some tiny piece of code takes to run and look at its disassembly. It measures the time by running the code in a loop, doing it more and more times looking for a stable result. I think in this special case it's reasonable to leave the code in the user package cause this is not meant to be called by other programs or to be saved as part of a larger application. Please send me your opinions/suggestions/complaints/... ================ ;;; -*- Mode: Common-Lisp; Package: USER; -*- (in-package :user) #| Measure-usec returns the time it takes to do something in microseconds, e.g., (measure-usec '(length *features*)) will do (length *features*) enough times (compiled) to estimate with reasonable accuracy how long it takes. The bindings argument allows you to time things that use local variables: (measure-usec '(+ x y) :bindings '((x 1) (y 2))) The precision argument describes the desired accuracy, e.g., .1 means within 10%. Of course, a much smaller value, e.g., .01, may never converge. (However the max-time argument will override that.) Other keyword arguments are a maximum time (seconds) allowed to do the measurement, a minimal number of times to run the code, and the compiler optimization settings, e.g., ((speed 3) (debug 0)) It's worth mentioning that compilers can sometimes optimize out more than you want for such a test. For instance, in the example above they may realize that x and y never change during the computation, so the + really computes a constant. Even worse, they might recognize that the loop is really useless. Obviously there's overhead in measurement. For very fast operations the actual results should not be taken too seriously. However the difference between the results for similar forms does seem pretty reliable. Note, however, that the time for accessing variables may depend on where they're bound and how. So it's really only fair to compare forms that access the same variables in the same way the same number of times. The return values are: - the number of microseconds per iteration - the number of iterations used to get this average - the time (get-internal-run-time) that many iterations took |# (provide :measure-usec) (defvar *PRODUCTION-COMPILER-OPTIONS* '(:speed 3 :safety 1 :space 1 :debug 1)) (defun measure-usec (code &key &allow-other-keys (precision .05) bindings (max-time 10) (min-n 0) optimize) (funcall (compile nil `(lambda (&aux (time1 0) time2 (n 1) ,.bindings) (declare (optimize ,.optimize)) (labels ((rtime (&aux (tmp (get-internal-run-time))) (run n) (- (get-internal-run-time) tmp)) (run (n) (dotimes (i n) ,code))) (setf time2 (rtime)) (loop until (or (> time2 ,(* (/ max-time 4) internal-time-units-per-second)) ;; if that iteration took > .25 max, all earlier ;; ones might have taken > .25 max, and the next ;; will take > .5 max giving a total > max (and (> n ,min-n) (> time2 ,(/ 1.0 precision)) (< (* time1 ,(* 2.0 (- 1.0 precision))) time2 (* time1 ,(* 2.0 (+ 1.0 precision))))) ;; e.g., consider it to have converged within 10% ;; if new time within 10% of double previous time ;; first few times should take care of paging etc. ) do (setf n (+ n n) time1 time2 time2 (rtime)))) (values (* 1000000.0 (/ time2 n internal-time-units-per-second)) n time2))))) ;; show disassembly of code (defun show-asm (code &key bindings optimize) (disassemble (compile nil `(lambda () (declare (optimize ,.optimize)) (let ,bindings ,code))))) ================ The next piece (I'll try to get it in shape by tomorrow) is something I have called at various times record-calls and monitor-calls. It's a monitoring package somewhat similar to the one in the repository now, but instead of the traditional overall summary statistics (which show you how much various functions cost in total and on average), this records the individual calls. It's meant for finding out WHICH calls are taking a long time, and is also useful for debugging (you see a history of calls with their inputs and outputs). |