Included Books
other
(in-package "ACL2")
include-book
(include-book "tools/include-raw" :dir :system)
include-book
(include-book "std/util/bstar" :dir :system)
local
(local (include-book "oslib/read-acl2-oracle" :dir :system))
other
(defxdoc oracle-time :parents (time$) :short "Carry out a computation, returning (not just printing!) how long it took and (on supported Lisps) how many bytes were allocated." :long "<p>The @('oracle-time') macro allows you to run a form and get the elapsed time and memory allocation back as real ACL2 values.</p> <p>In most cases, you don't really need to do this. Instead, see @(see time$), which is built into ACL2 and allows you to print the runtime and allocation of a form as a logically invisible side-effect. Since @(see time$) doesn't return the elapsed time or allocation, it is simpler and doesn't need access to @(see state). It also has some nice features for controlling when timing information is printed.</p> <p>On the other hand, if you want to do things like collect up tables that describe how your functions perform on various inputs, then @(see time$) won't do what you want: it just prints the timing information to the terminal, leaving you with no way to collect and compare the times and allocations. In this case, @('oracle-time') may be able to do what you want. The main limitation is that it does need access to the state.</p> <h5>Basic Example</h5> @({ (oracle-time (fib 35)) ; Simple since it returns a single value --> (mv time ; Rational, number of seconds bytes ; Natural, bytes allocated ans ; Answer from (fib 35) state) ; Updated state }) <h5>Example with Multiple Return Values</h5> @({ (oracle-time (random$ 100 state) ; Returns multiple values :ret (mv ans state)) ; Explains the return type --> (mv time ; Rational, number of seconds bytes ; Natural, bytes allocated ans ; The random number produced state) ; Updated state }) <p>See also the community book @('tools/oracle-time-tests.lisp') for some additional tests and working examples.</p> <h5>General Form</h5> @({ (oracle-time form [:ret retspec]) }) <p>The @('form') can be any arbitrary ACL2 form that you want to execute. If the form returns an ordinary, single value, e.g., as in @('(fib 35)') then the @(':ret') argument is not needed. Otherwise, @(':ret') should explain the return signature of @('form').</p> <p>The return value of @('oracle-time') extends the return value of @('form') with multiple values. The basic idea is that @('oracle-time') is going to macroexpand to something like this:</p> @({ (mv-let retspec form (b* (((mv & time state) (read-acl2-oracle state)) ((mv & bytes state) (read-acl2-oracle state))) (mv time bytes retspec [state]))) }) <p>You can see here that the @('retspec') is used to explain how to bind the results of executing the form. It is also, essentially, spliced into the return value of the whole @('oracle-time') call. The only twist is that if @('retspec') mentions @('state'), then we don't add an extra @('state') onto the end of the form.</p>")
oracle-time-extractfunction
(defund oracle-time-extract (state) "Has an under-the-hood definition." (declare (xargs :stobjs state :guard t)) (b* (((mv ?er time state) (read-acl2-oracle state)) ((mv ?er bytes state) (read-acl2-oracle state))) (mv (if (and (rationalp time) (<= 0 time)) time 0) (nfix bytes) state)))
local
(local (in-theory (enable oracle-time-extract)))
type-of-oracle-time-extract.timetheorem
(defthm type-of-oracle-time-extract.time (and (rationalp (mv-nth 0 (oracle-time-extract state))) (<= 0 (mv-nth 0 (oracle-time-extract state)))) :rule-classes :type-prescription)
natp-of-oracle-time-extract.bytestheorem
(defthm natp-of-oracle-time-extract.bytes (natp (mv-nth 1 (oracle-time-extract state))) :rule-classes :type-prescription)
state-p1-of-oracle-time-extract.statetheorem
(defthm state-p1-of-oracle-time-extract.state (implies (state-p1 state) (state-p1 (mv-nth 2 (oracle-time-extract state)))))
other
(defttag :oracle-time)
other
(include-raw "oracle-time-raw.lsp")
other
(defmacro-last oracle-time-exec)
oracle-time-fnfunction
(defun oracle-time-fn (form ret) (b* ((ret (cond ((symbolp ret) (list ret)) ((and (symbol-listp ret) (eq (car ret) 'mv) (consp (cdr ret))) (cdr ret)) (t (er hard? 'oracle-time "Invalid :ret specifier ~x0~%" ret)))) (return-splice (if (member 'state ret) ret (append ret '(state)))) ((when (eql (len ret) 1)) `(let ((,(CAR RET) (oracle-time-exec :ignored-arg ,FORM))) (mv-let (time bytes state) (oracle-time-extract state) (mv time bytes . ,RETURN-SPLICE))))) `(mv-let ,RET (oracle-time-exec :ignored-arg ,FORM) (mv-let (time bytes state) (oracle-time-extract state) (mv time bytes . ,RETURN-SPLICE)))))
oracle-timemacro
(defmacro oracle-time (form &key (ret 'ret)) (oracle-time-fn form ret))