diff options
author | Dirk Herrmann <dirk@dirk-herrmanns-seiten.de> | 2002-07-20 01:21:36 +0000 |
---|---|---|
committer | Dirk Herrmann <dirk@dirk-herrmanns-seiten.de> | 2002-07-20 01:21:36 +0000 |
commit | 0237895653e013fa727e08c877a39ce99350c5e5 (patch) | |
tree | 70a270e36f6745e859660ed90ea0facf141f36dd | |
parent | bb59ff52aff9af97dbfad423465051df2c367fa9 (diff) |
* COPYING, README, Makefile.am, lib.scm, guile-benchmark: Copied
from the test-suite directory, renamed and adapted for use with
benchmarks.
* benchmarks/logand.bm, benchmarks/continuations.bm,
benchmarks/if.bm: Added as initial fairly stupid examples for
benchmarks.
-rw-r--r-- | benchmark-suite/COPYING | 340 | ||||
-rw-r--r-- | benchmark-suite/ChangeLog | 13 | ||||
-rw-r--r-- | benchmark-suite/Makefile.am | 15 | ||||
-rw-r--r-- | benchmark-suite/README | 18 | ||||
-rw-r--r-- | benchmark-suite/benchmarks/continuations.bm | 5 | ||||
-rw-r--r-- | benchmark-suite/benchmarks/if.bm | 51 | ||||
-rw-r--r-- | benchmark-suite/benchmarks/logand.bm | 6 | ||||
-rwxr-xr-x | benchmark-suite/guile-benchmark | 220 | ||||
-rw-r--r-- | benchmark-suite/lib.scm | 268 |
9 files changed, 936 insertions, 0 deletions
diff --git a/benchmark-suite/COPYING b/benchmark-suite/COPYING new file mode 100644 index 000000000..eeb586b39 --- /dev/null +++ b/benchmark-suite/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/benchmark-suite/ChangeLog b/benchmark-suite/ChangeLog new file mode 100644 index 000000000..0f9f90638 --- /dev/null +++ b/benchmark-suite/ChangeLog @@ -0,0 +1,13 @@ +2002-07-20 Dirk Herrmann <D.Herrmann@tu-bs.de> + + * COPYING, README, Makefile.am, lib.scm, guile-benchmark: Copied + from the test-suite directory, renamed and adapted for use with + benchmarks. + + * benchmarks/logand.bm, benchmarks/continuations.bm, + benchmarks/if.bm: Added as initial fairly stupid examples for + benchmarks. + +2002-07-20 Dirk Herrmann <D.Herrmann@tu-bs.de> + + * Log begins. diff --git a/benchmark-suite/Makefile.am b/benchmark-suite/Makefile.am new file mode 100644 index 000000000..4bb81e49e --- /dev/null +++ b/benchmark-suite/Makefile.am @@ -0,0 +1,15 @@ +SCM_BENCHMARKS = benchmarks/foo.bm \ + benchmarks/bar.bm + +## SCM_BENCHMARKS_DIRS = benchmarks/dirfoo \ +## benchmarks/dirbar + +EXTRA_DIST = guile-benchmark lib.scm $(SCM_BENCHMARKS) + +## Automake should be able to handle the distribution of benchmarks/dirfoo +## etc without any help, but not all version can handle 'deep' +## directories. So we do it on our own. +dist-hook: + for d in $(SCM_BENCHMARKS_DIRS); do \ + cp -pR $(srcdir)/$$d $(distdir)/$$d; \ + done diff --git a/benchmark-suite/README b/benchmark-suite/README new file mode 100644 index 000000000..186a74351 --- /dev/null +++ b/benchmark-suite/README @@ -0,0 +1,18 @@ +This directory contains some benchmarks for Guile, and some generic +benchmarking support code. + +To run these benchmarks, you will need a version of Guile more recent +than 15 Feb 1999 --- the benchmarks use the (ice-9 and-let*) and +(ice-9 getopt-long) modules, which were added to Guile around then. + +For information about how to run the benchmark suite, read the usage +instructions in the comments at the top of the guile-benchmark script. + +You can reference the file `lib.scm' from your own code as the module +(benchmark-suite lib); it also has comments at the top and before each +function explaining what's going on. + +Please write more Guile benchmarks, and send them to bug-guile@gnu.org. +We'll merge them into the distribution. All benchmark suites must be +licensed for our use under the GPL, but I don't think we're going to +collect assignment papers for them. diff --git a/benchmark-suite/benchmarks/continuations.bm b/benchmark-suite/benchmarks/continuations.bm new file mode 100644 index 000000000..7c44300f7 --- /dev/null +++ b/benchmark-suite/benchmarks/continuations.bm @@ -0,0 +1,5 @@ +(define (callee continuation) + (continuation #t)) + +(benchmark "call/cc" 300 + (call-with-current-continuation callee)) diff --git a/benchmark-suite/benchmarks/if.bm b/benchmark-suite/benchmarks/if.bm new file mode 100644 index 000000000..30c22c9c3 --- /dev/null +++ b/benchmark-suite/benchmarks/if.bm @@ -0,0 +1,51 @@ +(with-benchmark-prefix "if-<expr>-then-else" + + (benchmark "executing then" 330000 + (if (quote #t) #t #f)) + + (benchmark "executing else" 330000 + (if (quote #f) #t #f))) + +(with-benchmark-prefix "if-<expr>-then" + + (benchmark "executing then" 330000 + (if (quote #t) #t)) + + (benchmark "executing else" 330000 + (if (quote #f) #t))) + +(with-benchmark-prefix "if-<iloc>-then-else" + + (let ((x #t)) + (benchmark "executing then" 330000 + (if x #t #f))) + + (let ((x #f)) + (benchmark "executing else" 330000 + (if x #t #f)))) + +(with-benchmark-prefix "if-<iloc>-then" + + (let ((x #t)) + (benchmark "executing then" 330000 + (if x #t))) + + (let ((x #f)) + (benchmark "executing else" 330000 + (if x #t)))) + +(with-benchmark-prefix "if-<bool>-then-else" + + (benchmark "executing then" 330000 + (if #t #t #f)) + + (benchmark "executing else" 330000 + (if #f #t #f))) + +(with-benchmark-prefix "if-<bool>-then" + + (benchmark "executing then" 330000 + (if #t #t)) + + (benchmark "executing else" 330000 + (if #f #t))) diff --git a/benchmark-suite/benchmarks/logand.bm b/benchmark-suite/benchmarks/logand.bm new file mode 100644 index 000000000..cdb05e88d --- /dev/null +++ b/benchmark-suite/benchmarks/logand.bm @@ -0,0 +1,6 @@ +(define bignum (1- (expt 2 128))) + +(let* ((i 0)) + (benchmark "bignum" 130000 + (logand i bignum) + (set! i (+ i 1)))) diff --git a/benchmark-suite/guile-benchmark b/benchmark-suite/guile-benchmark new file mode 100755 index 000000000..58f061749 --- /dev/null +++ b/benchmark-suite/guile-benchmark @@ -0,0 +1,220 @@ +#!../libguile/guile \ +-e main -s +!# + +;;;; guile-benchmark --- run the Guile benchmark suite +;;;; Adapted from code by Jim Blandy <jimb@red-bean.com> --- May 1999 +;;;; +;;;; Copyright (C) 2002 Free Software Foundation, Inc. +;;;; +;;;; This program is free software; you can redistribute it and/or modify +;;;; it under the terms of the GNU General Public License as published by +;;;; the Free Software Foundation; either version 2, or (at your option) +;;;; any later version. +;;;; +;;;; This program is distributed in the hope that it will be useful, +;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;;; GNU General Public License for more details. +;;;; +;;;; You should have received a copy of the GNU General Public License +;;;; along with this software; see the file COPYING. If not, write to +;;;; the Free Software Foundation, Inc., 59 Temple Place, Suite 330, +;;;; Boston, MA 02111-1307 USA + + +;;;; Usage: [guile -e main -s] guile-benchmark [OPTIONS] [BENCHMARK ...] +;;;; +;;;; Run benchmarks from the Guile benchmark suite. Report timing +;;;; results to the standard output, along with a summary of all +;;;; the results. Record each reported benchmark outcome in the log +;;;; file, `benchmarks.log'. +;;;; +;;;; Normally, guile-benchmark scans the benchmark directory, and +;;;; executes all files whose names end in `.bm'. (It assumes they contain +;;;; Scheme code.) However, you can have it execute specific benchmarks by +;;;; listing their filenames on the command line. +;;;; +;;;; The option `--benchmark-suite' can be given to specify the benchmark +;;;; directory. If no such option is given, the benchmark directory is +;;;; taken from the environment variable BENCHMARK_SUITE_DIR (if defined), +;;;; otherwise a default directory that is hardcoded in this file is +;;;; used (see "Installation" below). +;;;; +;;;; If present, the `--iteration-factor FACTOR' option tells +;;;; `guile-benchmark' to multiply the number of iterations given with +;;;; each single benchmark by the value of FACTOR. This allows to +;;;; reduce or increase the total time for benchmarking. +;;;; +;;;; If present, the `--log-file LOG' option tells `guile-benchmark' to put +;;;; the log output in a file named LOG. +;;;; +;;;; If present, the `--debug' option will enable a debugging mode. +;;;; +;;;; +;;;; Installation: +;;;; +;;;; If you change the #! line at the top of this script to point at +;;;; the Guile interpreter you want to run, you can call this script +;;;; as an executable instead of having to pass it as a parameter to +;;;; guile via "guile -e main -s guile-benchmark". Further, you can edit +;;;; the definition of default-benchmark-suite to point to the parent +;;;; directory of the `benchmarks' tree, which makes it unnecessary to set +;;;; the environment variable `BENCHMARK_SUITE_DIR'. +;;;; +;;;; +;;;; Shortcomings: +;;;; +;;;; At the moment, due to a simple-minded implementation, benchmark files +;;;; must live in the benchmark directory, and you must specify their names +;;;; relative to the top of the benchmark directory. If you want to send +;;;; me a patch that fixes this, but still leaves sane benchmark names in +;;;; the log file, that would be great. At the moment, all the benchmarks +;;;; I care about are in the benchmark directory, though. +;;;; +;;;; It would be nice if you could specify the Guile interpreter you +;;;; want to benchmark on the command line. As it stands, if you want to +;;;; change which Guile interpreter you're benchmarking, you need to edit +;;;; the #! line at the top of this file, which is stupid. + + +;;; User configurable settings: +(define default-benchmark-suite + (string-append (getenv "HOME") "/bogus-path/benchmark-suite")) + + +(use-modules (benchmark-suite lib) + (ice-9 getopt-long) + (ice-9 and-let-star) + (ice-9 rdelim)) + + +;;; Variables that will receive their actual values later. +(define benchmark-suite default-benchmark-suite) + +(define tmp-dir #f) + + +;;; General utilities, that probably should be in a library somewhere. + +;;; Enable debugging +(define (enable-debug-mode) + (write-line %load-path) + (set! %load-verbosely #t) + (debug-enable 'backtrace 'debug)) + +;;; Traverse the directory tree at ROOT, applying F to the name of +;;; each file in the tree, including ROOT itself. For a subdirectory +;;; SUB, if (F SUB) is true, we recurse into SUB. Do not follow +;;; symlinks. +(define (for-each-file f root) + + ;; A "hard directory" is a path that denotes a directory and is not a + ;; symlink. + (define (file-is-hard-directory? filename) + (eq? (stat:type (lstat filename)) 'directory)) + + (let visit ((root root)) + (let ((should-recur (f root))) + (if (and should-recur (file-is-hard-directory? root)) + (let ((dir (opendir root))) + (let loop () + (let ((entry (readdir dir))) + (cond + ((eof-object? entry) #f) + ((or (string=? entry ".") + (string=? entry "..") + (string=? entry "CVS") + (string=? entry "RCS")) + (loop)) + (else + (visit (string-append root "/" entry)) + (loop)))))))))) + + +;;; The benchmark driver. + + +;;; Localizing benchmark files and temporary data files. + +(define (data-file-name filename) + (in-vicinity tmp-dir filename)) + +(define (benchmark-file-name benchmark) + (in-vicinity benchmark-suite benchmark)) + +;;; Return a list of all the benchmark files in the benchmark tree. +(define (enumerate-benchmarks benchmark-dir) + (let ((root-len (+ 1 (string-length benchmark-dir))) + (benchmarks '())) + (for-each-file (lambda (file) + (if (has-suffix? file ".bm") + (let ((short-name + (substring file root-len))) + (set! benchmarks (cons short-name benchmarks)))) + #t) + benchmark-dir) + + ;; for-each-file presents the files in whatever order it finds + ;; them in the directory. We sort them here, so they'll always + ;; appear in the same order. This makes it easier to compare benchmark + ;; log files mechanically. + (sort benchmarks string<?))) + +(define (main args) + (let ((options (getopt-long args + `((benchmark-suite + (single-char #\t) + (value #t)) + (iteration-factor + (single-char #\t) + (value #t)) + (log-file + (single-char #\l) + (value #t)) + (debug + (single-char #\d)))))) + (define (opt tag default) + (let ((pair (assq tag options))) + (if pair (cdr pair) default))) + + (if (opt 'debug #f) + (enable-debug-mode)) + + (set! benchmark-suite + (or (opt 'benchmark-suite #f) + (getenv "BENCHMARK_SUITE_DIR") + default-benchmark-suite)) + + (set! iteration-factor + (string->number (opt 'iteration-factor "1"))) + + ;; directory where temporary files are created. + (set! tmp-dir (getcwd)) + + (let* ((benchmarks + (let ((foo (opt '() '()))) + (if (null? foo) + (enumerate-benchmarks benchmark-suite) + foo))) + (log-file + (opt 'log-file "benchmarks.log"))) + + ;; Open the log file. + (let ((log-port (open-output-file log-file))) + + ;; Register some reporters. + (register-reporter (make-log-reporter log-port)) + (register-reporter user-reporter) + + ;; Run the benchmarks. + (for-each (lambda (benchmark) + (with-benchmark-prefix benchmark + (load (benchmark-file-name benchmark)))) + benchmarks) + (close-port log-port))))) + + +;;; Local Variables: +;;; mode: scheme +;;; End: diff --git a/benchmark-suite/lib.scm b/benchmark-suite/lib.scm new file mode 100644 index 000000000..2eb858228 --- /dev/null +++ b/benchmark-suite/lib.scm @@ -0,0 +1,268 @@ +;;;; benchmark-suite/lib.scm --- generic support for benchmarking +;;;; Copyright (C) 2002 Free Software Foundation, Inc. +;;;; +;;;; This program is free software; you can redistribute it and/or modify +;;;; it under the terms of the GNU General Public License as published by +;;;; the Free Software Foundation; either version 2, or (at your option) +;;;; any later version. +;;;; +;;;; This program is distributed in the hope that it will be useful, +;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;;; GNU General Public License for more details. +;;;; +;;;; You should have received a copy of the GNU General Public License +;;;; along with this software; see the file COPYING. If not, write to +;;;; the Free Software Foundation, Inc., 59 Temple Place, Suite 330, +;;;; Boston, MA 02111-1307 USA + +(define-module (benchmark-suite lib) + :export ( + + ;; Controlling the execution. + iteration-factor + scale-iterations + + ;; Running benchmarks. + run-benchmark + benchmark + + ;; Naming groups of benchmarks in a regular fashion. + with-benchmark-prefix with-benchmark-prefix* current-benchmark-prefix + format-benchmark-name + + ;; Reporting results in various ways. + register-reporter unregister-reporter reporter-registered? + make-log-reporter + full-reporter + user-reporter)) + +;;;; MISCELLANEOUS +;;;; + +;;; Scale the number of iterations according to the given scaling factor. +(define iteration-factor 1) +(define (scale-iterations iterations) + (let* ((i (inexact->exact (round (* iterations iteration-factor))))) + (if (< i 1) 1 i))) + +;;;; CORE FUNCTIONS +;;;; + +;;; The central routine for executing benchmarks. +;;; The idea is taken from Greg, the GNUstep regression test environment. +(define run-benchmark #f) +(let ((benchmark-running #f)) + (define (local-run-benchmark name iterations thunk) + (if benchmark-running + (error "Nested calls to run-benchmark are not permitted.") + (let ((benchmark-name (full-name name)) + (iterations (scale-iterations iterations))) + (set! benchmark-running #t) + (let ((before #f) (after #f) (gc-time #f)) + (gc) + (set! gc-time (gc-run-time)) + (set! before (times)) + (do ((i 0 (+ i 1))) + ((= i iterations)) + (thunk)) + (set! after (times)) + (set! gc-time (- (gc-run-time) gc-time)) + (report benchmark-name iterations before after gc-time)) + (set! benchmark-running #f)))) + (set! run-benchmark local-run-benchmark)) + +;;; A short form for benchmarks. +(defmacro benchmark (name iterations body . rest) + `(,run-benchmark ,name ,iterations (lambda () ,body ,@rest))) + + +;;;; BENCHMARK NAMES +;;;; + +;;;; Turn a benchmark name into a nice human-readable string. +(define (format-benchmark-name name) + (call-with-output-string + (lambda (port) + (let loop ((name name) + (separator "")) + (if (pair? name) + (begin + (display separator port) + (display (car name) port) + (loop (cdr name) ": "))))))) + +;;;; For a given benchmark-name, deliver the full name including all prefixes. +(define (full-name name) + (append (current-benchmark-prefix) (list name))) + +;;; A fluid containing the current benchmark prefix, as a list. +(define prefix-fluid (make-fluid)) +(fluid-set! prefix-fluid '()) +(define (current-benchmark-prefix) + (fluid-ref prefix-fluid)) + +;;; Postpend PREFIX to the current name prefix while evaluting THUNK. +;;; The name prefix is only changed within the dynamic scope of the +;;; call to with-benchmark-prefix*. Return the value returned by THUNK. +(define (with-benchmark-prefix* prefix thunk) + (with-fluids ((prefix-fluid + (append (fluid-ref prefix-fluid) (list prefix)))) + (thunk))) + +;;; (with-benchmark-prefix PREFIX BODY ...) +;;; Postpend PREFIX to the current name prefix while evaluating BODY ... +;;; The name prefix is only changed within the dynamic scope of the +;;; with-benchmark-prefix expression. Return the value returned by the last +;;; BODY expression. +(defmacro with-benchmark-prefix (prefix . body) + `(with-benchmark-prefix* ,prefix (lambda () ,@body))) + + +;;;; TIME CALCULATION +;;;; + +(define time-base + internal-time-units-per-second) + +(define frame-time/iteration + "<will be set during initialization>") + +(define (total-time before after) + (- (tms:clock after) (tms:clock before))) + +(define (user-time before after) + (- (tms:utime after) (tms:utime before))) + +(define (system-time before after) + (- (tms:stime after) (tms:stime before))) + +(define (frame-time iterations) + (* iterations frame-time/iteration)) + +(define (benchmark-time iterations before after) + (- (user-time before after) (frame-time iterations))) + +(define (user-time\interpreter before after gc-time) + (- (user-time before after) gc-time)) + +(define (benchmark-time\interpreter iterations before after gc-time) + (- (benchmark-time iterations before after) gc-time)) + + +;;;; REPORTERS +;;;; + +;;; The global list of reporters. +(define reporters '()) + +;;; The default reporter, to be used only if no others exist. +(define default-reporter #f) + +;;; Add the procedure REPORTER to the current set of reporter functions. +;;; Signal an error if that reporter procedure object is already registered. +(define (register-reporter reporter) + (if (memq reporter reporters) + (error "register-reporter: reporter already registered: " reporter)) + (set! reporters (cons reporter reporters))) + +;;; Remove the procedure REPORTER from the current set of reporter +;;; functions. Signal an error if REPORTER is not currently registered. +(define (unregister-reporter reporter) + (if (memq reporter reporters) + (set! reporters (delq! reporter reporters)) + (error "unregister-reporter: reporter not registered: " reporter))) + +;;; Return true iff REPORTER is in the current set of reporter functions. +(define (reporter-registered? reporter) + (if (memq reporter reporters) #t #f)) + +;;; Send RESULT to all currently registered reporter functions. +(define (report . args) + (if (pair? reporters) + (for-each (lambda (reporter) (apply reporter args)) + reporters) + (apply default-reporter args))) + + +;;;; Some useful standard reporters: +;;;; Log reporters write all test results to a given log file. +;;;; Full reporters write all benchmark results to the standard output. +;;;; User reporters write some interesting results to the standard output. + +;;; Display a single benchmark result to the given port +(define (print-result port name iterations before after gc-time) + (let* ((name (format-benchmark-name name)) + (total-time (total-time before after)) + (user-time (user-time before after)) + (system-time (system-time before after)) + (frame-time (frame-time iterations)) + (benchmark-time (benchmark-time iterations before after)) + (user-time\interpreter (user-time\interpreter before after gc-time)) + (benchmark-time\interpreter + (benchmark-time\interpreter iterations before after gc-time))) + (write (list name iterations + "total:" (/ total-time time-base) + "user:" (/ user-time time-base) + "system:" (/ system-time time-base) + "frame:" (/ frame-time time-base) + "benchmark:" (/ benchmark-time time-base) + "user/interp:" (/ user-time\interpreter time-base) + "bench/interp:" (/ benchmark-time\interpreter time-base) + "gc:" (/ gc-time time-base)) + port) + (newline port))) + +;;; Return a reporter procedure which prints all results to the file +;;; FILE, in human-readable form. FILE may be a filename, or a port. +(define (make-log-reporter file) + (let ((port (if (output-port? file) file + (open-output-file file)))) + (lambda args + (apply print-result port args) + (force-output port)))) + +;;; A reporter that reports all results to the user. +(define (full-reporter . args) + (apply print-result (current-output-port) args)) + +;;; Display interesting results of a single benchmark to the given port +(define (print-user-result port name iterations before after gc-time) + (let* ((name (format-benchmark-name name)) + (user-time (user-time before after)) + (benchmark-time (benchmark-time iterations before after)) + (benchmark-time\interpreter + (benchmark-time\interpreter iterations before after gc-time))) + (write (list name iterations + "user:" (/ user-time time-base) + "benchmark:" (/ benchmark-time time-base) + "bench/interp:" (/ benchmark-time\interpreter time-base) + "gc:" (/ gc-time time-base)) + port) + (newline port))) + +;;; A reporter that reports interesting results to the user. +(define (user-reporter . args) + (apply print-user-result (current-output-port) args)) + + +;;;; Initialize the benchmarking system: +;;;; + +;;; First, make sure the benchmarking routines are compiled. +(define (null-reporter . args) #t) +(set! default-reporter null-reporter) +(benchmark "empty initialization benchmark" 2 #t) + +;;; Second, initialize the system constants +(define (initialization-reporter name iterations before after gc-time) + (let* ((frame-time (- (tms:utime after) (tms:utime before) gc-time 3))) + (set! frame-time/iteration (/ frame-time iterations)) + (display ";; frame time per iteration: " (current-output-port)) + (display (/ frame-time/iteration time-base) (current-output-port)) + (newline (current-output-port)))) +(set! default-reporter initialization-reporter) +(benchmark "empty initialization benchmark" 524288 #t) + +;;; Finally, set the default reporter +(set! default-reporter user-reporter) |