OverviewFilesCommitsIssuesDocsReleasesPeers

opencog-matrix / opencog / matrix / progress.scm

122 lines · scm ref:
;
; progress.scm
;
; Timing and progress report utilities.
;
; Copyright (c) 2013, 2014, 2017, 2018, 2021 Linas Vepstas
;
; ---------------------------------------------------------------------
;
(use-modules (srfi srfi-1))
(use-modules (ice-9 atomic))
(use-modules (ice-9 optargs))

; ---------------------------------------------------------------------

(define-public (atomic-inc ctr)
"
  atomic-inc CTR - increment the atomic-box CTR by one.

  This is the atomic version of (set! CTR (+ 1 CTR)).
  This returns the new, incremented value.

  Example usage:
     (define cnt (make-atomic-box 0))
     (atomic-inc cnt)
     (atomic-inc cnt)
     (format #t \"Its ~A\n\" (atomic-box-ref cnt))
"
	(define old (atomic-box-ref ctr))
	(define new (+ 1 old))
	(define swp (atomic-box-compare-and-swap! ctr old new))
	(if (= old swp) new (atomic-inc ctr))
)

; ---------------------------------------------------------------------

;; XXX TODO define a new version of this, where TOTAL is an optional
;; argument. Also WHEN could be optional, too. (i.e. WHEN=1 if not
;; given. And if WHEN=0, then print only if HYST.) Maybe make these
;; named arguments ???
(define*-public (make-progress-rpt FUNC WHEN TOTAL MSG #:optional HYST)
"
  make-progress-rpt FUNC WHEN TOTAL MSG [HYST] - print progress report.

  This returns a wrapper around FUNC, so that it calls FUNC whenever
  it is called.

  Whenever the number of calls is a multiple of WHEN, a progress
  report is printed, as given by MSG. If the optional argument HYST
  is provided, then the progress report is printed only if at least
  HYST seconds have elapsed.

  FUNC should be the function to be called, taking one argument.
  MSG should be a string of the form
     \"Did ~A of ~A in ~A seconds (~A items/sec)\n\"
     or
     \"Did ~A in ~A seconds (~A items/sec)\n\"
     The first argument is the message; the second is the TOTAL,
     the third is the elapsed time in seconds, the fourth is the
     rate, in calls per second. If TOTAL is #f, then this argument
     is not passed.
  WHEN should be the number of times that this function is called,
     between printing of progress reports. It is used to take the
     modulo of the of the call count.
  TOTAL should be the total number of items to process; it becomes
     the second argument to the MSG. If TOTAL is #f, then it is not
     passed to the MSG for printing.
"
	(let ((cnt (make-atomic-box 0))
			(start-time 0)
			(done 0))
		(lambda (item)
			; back-date to avoid divide-by-zero
			(if (eqv? 0 (atomic-box-ref cnt))
				(set! start-time (- (current-time) 0.00001)))
			(FUNC item)
			(if (eqv? 0 (modulo (atomic-inc cnt) WHEN))
				(let* ((now (current-time))
						(elapsed (- now start-time))
						(ilapsed (inexact->exact (round elapsed)))
						(icnt (atomic-box-ref cnt))
						(rate (if (< 0 elapsed)
							(/ (exact->inexact (- icnt done)) elapsed) 0))
						(irate (if (< 100 rate) ; If rate is large, round to integer
							(inexact->exact (round rate)) rate))
					)
					(when (or (not HYST) (<= HYST ilapsed))
						(if TOTAL
							(format #t MSG icnt TOTAL ilapsed irate)
							(format #t MSG icnt ilapsed irate))
						(set! start-time now)
						(set! done icnt))))))
)

; ---------------------------------------------------------------------

(define*-public (make-elapsed-secs #:optional hysteresis)
"
  make-elapsed-secs [hysteresis]

  Create a timer. The timer returns the number of elapsed seconds
  since the last call to it. If the optional `hysteresis` argument
  is given, then the timer is not reset until at least that many
  seconds have passed.

  Example usage:
  (define elapsed-secs (make-elapsed-secs))
  (sleep 2)
  (format #t \"Seconds since start: ~A\n\" (elapsed-secs))
"
	(define start-time (current-time))
	(lambda ()
		(define now (current-time))
		(define diff (- now start-time))
		; Reset only if the minimum has elapsed.
		(if (or (not hysteresis) (<= hysteresis diff))
			(set! start-time now))
		diff)
)

; ---------------------------------------------------------------------