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.