random-state.net

Nikodemus Siivola

<< next | top | previous >>

DEFGLOBAL in SBCL #
hacking, May 22nd 2009

I recently added support for global variables in SBCL: they cannot be rebound or made unbound, which are occasionally useful semantic properties.

More importantly, however, they are an efficiency measure for those cases when a threaded application is using a special as global variable — never rebinding it: on threaded builds special variable lookup has a fair bit of overhead: in addition to normal boundness checking the system also needs to check for the thread-local binding. Using a global instead allows just grabbing the value slot of the symbol:

(defparameter *foo* 0)
(defparameter *foo2* 0)

(defun foo (n)
  (declare (fixnum n))
  (dotimes (i n)
    (setf *foo* *foo2*)
    (setf *foo2* *foo*)))

(defglobal **bar** 0)
(defglobal **bar2** 0)

(defun bar (n)
  (declare (fixnum n))
  (dotimes (i n)
    (setf **bar** **bar2**)
    (setf **bar2** **bar**)))

(time (foo 100000000))
(time (bar 100000000))

FOO takes 0.55 seconds of run time, and BAR 0.37 — about 30% difference in favor of global variables.

It needs to be taken into account, however, that this is an extremely artificial benchmark. Eg. doing bignum arithmetic in the loop loses the difference between specials and globals into noise, so gains for real applications are likely to be much smaller — and almost certainly nonexistent for a large class of applications.

Secondary effects due to reduced code size are possible, however. This is what assignment from *FOO2* to *FOO* (both special variables) looks like:

;      1E2: L0:   8B05A8419E11     MOV EAX, [#x119E41A8]      ; '*FOO2*
;      1E8:       8B5011           MOV EDX, [EAX+17]
;      1EB:       64               FS-SEGMENT-PREFIX
;      1EC:       8B12             MOV EDX, [EDX]
;      1EE:       83FA5A           CMP EDX, 90
;      1F1:       7503             JNE L1
;      1F3:       8B50FD           MOV EDX, [EAX-3]
;      1F6: L1:   83FA4A           CMP EDX, 74
;      1F9:       7464             JEQ L8
;      1FB:       8B35AC419E11     MOV ESI, [#x119E41AC]      ; '*FOO*
;      201:       8B4611           MOV EAX, [ESI+17]
;      204:       64               FS-SEGMENT-PREFIX
;      205:       83385A           CMP DWORD PTR [EAX], 90
;      208:       7405             JEQ L2
;      20A:       64               FS-SEGMENT-PREFIX
;      20B:       8910             MOV [EAX], EDX
;      20D:       EB03             JMP L3
;      20F: L2:   8956FD           MOV [ESI-3], EDX

Contrast and compare with assigment from **BAR2** to **BAR** (both globals):

;      A18: L0:   8B15CC69A211     MOV EDX, [#x11A269CC]      ; '**BAR2**
;      A1E:       8B52FD           MOV EDX, [EDX-3]
;      A21:       8B1DC869A211     MOV EBX, [#x11A269C8]      ; '**BAR**
;      A27:       8953FD           MOV [EBX-3], EDX

Hopefully there are users out there who find this of use! To me at least they seems like a natural match for locks, for example.