The function random is a bit slow, can it be optimized?

Bug #2078520 reported by xizang
6
This bug affects 1 person
Affects Status Importance Assigned to Milestone
SBCL
Invalid
Undecided
Unassigned

Bug Description

Hi,
Random numbers are frequently used in machine learning algorithms, but the random function of sbcl is a bit slow. Can it be optimized?

(time (dotimes (i 1000000)
        (random 1.0 (make-random-state t))))
Evaluation took:
  135.454 seconds of real time
  135.443309 seconds of total run time (19.848173 user, 115.595136 system)
  [ Real times consist of 0.095 seconds GC time, and 135.359 seconds non-GC time. ]
  [ Run times consist of 0.093 seconds GC time, and 135.351 seconds non-GC time. ]
  99.99% CPU
  393,361,050,731 processor cycles
  3,423,087,968 bytes consed

In src/code/target-random.lisp

#-win32
(defun os-random-seed ()
  (or
   ;; On unices, we try to read from /dev/urandom and pass the results
   ;; to our (simple-array (unsigned-byte 32) (*)) processor below.
   ;; More than 256 bits would provide a false sense of security.
   ;; If you need more bits than that, you probably also need
   ;; a better algorithm too.
   (ignore-errors
    (with-open-file (r "/dev/urandom" :element-type '(unsigned-byte 32)
                                      :direction :input :if-does-not-exist :error)
      (let ((a (make-array '(8) :element-type '(unsigned-byte 32))))
        (aver (= 8 (read-sequence a r)))
        a)))
   (fallback-random-seed)
   ))

(defun fallback-random-seed ()
  ;; When /dev/urandom is not available, we make do with time and pid
  ;; Thread ID and/or address of a CONS cell would be even better, but...
  ;; [ADDRESS-BASED-COUNTER-VAL in 'target-sxhash' could be used here]
  (/show0 "No /dev/urandom, using randomness from time and pid")
  (+ (get-internal-real-time)
     (ash (sb-unix:unix-getpid) 32)))

Can these two functions be improved like this?
#-win32
(defun os-random-seed ()
  (or
   ;; On unices, we try to read from /dev/urandom and pass the results
   ;; to our (simple-array (unsigned-byte 32) (*)) processor below.
   ;; More than 256 bits would provide a false sense of security.
   ;; If you need more bits than that, you probably also need
   ;; a better algorithm too.
   (fallback-random-seed) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; change this
   (ignore-errors
    (with-open-file (r "/dev/urandom" :element-type '(unsigned-byte 32)
                                      :direction :input :if-does-not-exist :error)
      (let ((a (make-array '(8) :element-type '(unsigned-byte 32))))
        (aver (= 8 (read-sequence a r)))
        a)))
   ))

(defun fallback-random-seed ()
  ;; When /dev/urandom is not available, we make do with time and pid
  ;; Thread ID and/or address of a CONS cell would be even better, but...
  ;; [ADDRESS-BASED-COUNTER-VAL in 'target-sxhash' could be used here]
  (/show0 "No /dev/urandom, using randomness from time and pid")
  (multiple-value-bind (sec usec)
      (get-time-of-day)
    (+ sec (ash usec 8))))

Now,

 (time (dotimes (i 1000000)
        (random 1.0 (make-random-state t))))
Evaluation took:
  3.991 seconds of real time
  3.993465 seconds of total run time (3.980038 user, 0.013427 system)
  [ Real times consist of 0.070 seconds GC time, and 3.921 seconds non-GC time. ]
  [ Run times consist of 0.069 seconds GC time, and 3.925 seconds non-GC time. ]
  100.05% CPU
  11,592,835,590 processor cycles
  2,543,946,064 bytes consed

Best regards!

Revision history for this message
Stas Boukarev (stassats) wrote :

Don't do (make-random-state t) on each iteration.

Changed in sbcl:
status: New → Invalid
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.