Skip to content

Instantly share code, notes, and snippets.

@GiuseppeChillemi
Last active February 8, 2025 13:34
Show Gist options
  • Save GiuseppeChillemi/8bd833ba511af556ae135474088dda06 to your computer and use it in GitHub Desktop.
Save GiuseppeChillemi/8bd833ba511af556ae135474088dda06 to your computer and use it in GitHub Desktop.
Context reuse speed test
Red [
Title: "Speed comparison with context keeping"
Description: {
This test compares the same function with and without the
initialization phase
The purpose of this the is to test context reusing:
A function has ofen an check and init phase. In stict loops
many of these checks and inits could be bypassed after the first
one if part of the function context could be passed again
at each run.
APPLY could do this if modified but also
Rebol3 has the ability to use accept external context for
the called function
Lets see the difference: I have created an extract-keys
and extract-keys-fast fuctions. The latter one uses pre
calculated values in the system context.
Later, I have tested multiple optimization,
adding each optimization benchmarks
At the end you can find the results
}
]
contains?: func [
target [block!]
data [block!]
] [
either empty? exclude data target [true] [false]
]
extract-keys: func [
data [map! object!]
keys [block!]
datatype [datatype!]
/couples "keys are couples"
/into "Extract inside a target"
target [map! block!]
/local
keys-to-pick
keys-to-write
data-keys
target-keys
go-on?
err
out-data
] [
err: "Keys not valid"
go-on?: case [
datatype = object! [parse keys [any [word!]]]
datatype = map! [parse keys [any [any-word! | any-string! | any-block!]]]
]
;--- Settings the keys to request and to write
if go-on? [
either couples [
keys-to-pick: extract keys 2
keys-to-write: extract/index keys 2 2
] [
keys-to-pick: keys-to-write: keys
]
;--- Creating the target container or using the one provided by /INTO
either into [
out-data: target
] [
out-data: copy []
forall keys-to-write [
append out-data reduce [
either datatype = object! [to-set-word :keys-to-write/1][:keys-to-write/1]
none
]
]
err: "Error creating datatype"
either attempt [out-data: make datatype out-data] [go-on?: true] [go-on?: false]
]
]
;Intead of the previous code, an empty container should used
if go-on? [
target-keys: words-of out-data
data-keys: words-of data
go-on?: contains? data-keys keys-to-pick
]
;--- The CORE of the code
;
if go-on? [
forall keys-to-pick [
out-data/(pick keys-to-write index? keys-to-pick): :data/(:keys-to-pick/1)
]
]
either go-on? [out-data] [do make error! err]
]
map-types: make typeset! [any-word! any-string! any-block!]
extract-key-typeset: func [
data [map! object!]
keys [block!]
datatype [datatype!]
/couples "keys are couples"
/into "Extract inside a target"
target [map! block!]
/local
keys-to-pick
keys-to-write
data-keys
target-keys
go-on?
err
out-data
] [
err: "Keys not valid"
go-on?: case [
datatype = object! [parse keys [any [word!]]]
datatype = map! [forall keys [find map-types :keys/1]]
]
;--- Settings the keys to request and to write
if go-on? [
either couples [
keys-to-pick: extract keys 2
keys-to-write: extract/index keys 2 2
] [
keys-to-pick: keys-to-write: keys
]
;--- Creating the target container or using the one provided by /INTO
either into [
out-data: target
] [
out-data: copy []
forall keys-to-write [
append out-data reduce [
either datatype = object! [to-set-word :keys-to-write/1][:keys-to-write/1]
none
]
]
err: "Error creating datatype"
either attempt [out-data: make datatype out-data] [go-on?: true] [go-on?: false]
]
]
;Intead of the previous code, an empty container should used
if go-on? [
target-keys: words-of out-data
data-keys: words-of data
go-on?: contains? data-keys keys-to-pick
]
;--- The CORE of the code
;
if go-on? [
forall keys-to-pick [
out-data/(pick keys-to-write index? keys-to-pick): :data/(:keys-to-pick/1)
]
]
either go-on? [out-data] [do make error! err]
]
extract-key-typeset-type-forall: func [
data [map! object!]
keys [block!]
datatype [datatype!]
/couples "keys are couples"
/into "Extract inside a target"
target [map! block!]
/local
keys-to-pick
keys-to-write
data-keys
target-keys
go-on?
err
out-data
] [
err: "Keys not valid"
go-on?: case [
datatype = object! [forall keys [type? :keys/1 = word!]]
datatype = map! [forall keys [find map-types :keys/1]]
]
;--- Settings the keys to request and to write
if go-on? [
either couples [
keys-to-pick: extract keys 2
keys-to-write: extract/index keys 2 2
] [
keys-to-pick: keys-to-write: keys
]
;--- Creating the target container or using the one provided by /INTO
either into [
out-data: target
] [
out-data: copy []
forall keys-to-write [
append out-data reduce [
either datatype = object! [to-set-word :keys-to-write/1][:keys-to-write/1]
none
]
]
err: "Error creating datatype"
either attempt [out-data: make datatype out-data] [go-on?: true] [go-on?: false]
]
]
;Intead of the previous code, an empty container should used
if go-on? [
target-keys: words-of out-data
data-keys: words-of data
go-on?: contains? data-keys keys-to-pick
]
;--- The CORE of the code
;
if go-on? [
forall keys-to-pick [
out-data/(pick keys-to-write index? keys-to-pick): :data/(:keys-to-pick/1)
]
]
either go-on? [out-data] [do make error! err]
]
recycle/off
extract-keys-fast: func [
data [map! object!]
keys [block!]
datatype [datatype!]
/couples "keys are couples"
/into "Extract inside a target"
target [map! block!]
/local
] [
forall keys-to-pick [
out-data/(pick keys-to-write index? keys-to-pick): :data/(:keys-to-pick/1)
]
out-data
]
extract-keys-passed-keys: func [
data [map! object!]
keys [block!]
datatype [datatype!]
keys-to-pick
keys-to-write
/couples "keys are couples"
/into "Extract inside a target"
target [map! block!]
/local
data-keys
target-keys
go-on?
err
out-data
] [
err: "Keys not valid"
go-on?: case [
datatype = object! [parse keys [any [word!]]]
datatype = map! [parse keys [any [any-word! | any-string! | any-block!]]]
]
;--- Settings the keys to request and to write
if go-on? [
;--- Creating the target container or using the one provided by /INTO
either into [
out-data: target
] [
out-data: copy []
forall keys-to-write [
append out-data reduce [
either datatype = object! [to-set-word :keys-to-write/1][:keys-to-write/1]
none
]
]
err: "Error creating datatype"
either attempt [out-data: make datatype out-data] [go-on?: true] [go-on?: false]
]
]
;Intead of the previous code, an empty container should used
if go-on? [
target-keys: words-of out-data
data-keys: words-of data
go-on?: contains? data-keys keys-to-pick
]
;--- The CORE of the code
;
if go-on? [
forall keys-to-pick [
out-data/(pick keys-to-write index? keys-to-pick): :data/(:keys-to-pick/1)
]
]
either go-on? [out-data] [do make error! err]
]
extract-keys-external-out-data-container: func [
data [map! object!]
keys [block!]
datatype [datatype!]
out-data
/couples "keys are couples"
/into "Extract inside a target"
target [map! block!]
/local
keys-to-pick
keys-to-write
data-keys
target-keys
go-on?
err
] [
err: "Keys not valid"
go-on?: case [
datatype = object! [parse keys [any [word!]]]
datatype = map! [parse keys [any [any-word! | any-string! | any-block!]]]
]
;--- Settings the keys to request and to write
if go-on? [
either couples [
keys-to-pick: extract keys 2
keys-to-write: extract/index keys 2 2
] [
keys-to-pick: keys-to-write: keys
]
;--- Creating the target container or using the one provided by /INTO
either into [
out-data: target
] [
]
]
;Intead of the previous code, an empty container should used
if go-on? [
target-keys: words-of out-data
data-keys: words-of data
go-on?: contains? data-keys keys-to-pick
]
;--- The CORE of the code
;
if go-on? [
forall keys-to-pick [
out-data/(pick keys-to-write index? keys-to-pick): :data/(:keys-to-pick/1)
]
]
either go-on? [out-data] [do make error! err]
]
extract-keys-no-contains: func [
data [map! object!]
keys [block!]
datatype [datatype!]
/couples "keys are couples"
/into "Extract inside a target"
target [map! block!]
/local
keys-to-pick
keys-to-write
data-keys
target-keys
go-on?
err
out-data
] [
err: "Keys not valid"
go-on?: case [
datatype = object! [parse keys [any [word!]]]
datatype = map! [parse keys [any [any-word! | any-string! | any-block!]]]
]
;--- Settings the keys to request and to write
if go-on? [
either couples [
keys-to-pick: extract keys 2
keys-to-write: extract/index keys 2 2
] [
keys-to-pick: keys-to-write: keys
]
;--- Creating the target container or using the one provided by /INTO
either into [
out-data: target
] [
out-data: copy []
forall keys-to-write [
append out-data reduce [
either datatype = object! [to-set-word :keys-to-write/1][:keys-to-write/1]
none
]
]
err: "Error creating datatype"
either attempt [out-data: make datatype out-data] [go-on?: true] [go-on?: false]
]
]
;Intead of the previous code, an empty container should used
; if go-on? [
; target-keys: words-of out-data
; data-keys: words-of data
;
; go-on?: contains? data-keys keys-to-pick
; ]
;--- The CORE of the code
;
if go-on? [
forall keys-to-pick [
out-data/(pick keys-to-write index? keys-to-pick): :data/(:keys-to-pick/1)
]
]
either go-on? [out-data] [do make error! err]
]
;--- Repetitions for the test
times: 100000
;--- Data to keep values from
m: #[a: 11 b: 22 c: 22]
;--- Running test with init inside
prin "Full: " probe dt [loop times [extract-keys m [a b] object!]]
;---- extract-key-typeset
prin "Typeset: " probe dt [loop times [extract-key-typeset m [a b] object!]]
;---- extract-key-typeset
prin "Typeset-type-forall: " probe dt [loop times [extract-key-typeset-type-forall m [a b] object!]]
;--- Passed keys
;either couples [
; keys-to-pick: extract keys 2
; keys-to-write: extract/index keys 2 2
;] [
; keys-to-pick: keys-to-write: keys
;]
prin "Typeset-type-passed-keys: " probe dt [loop times [extract-keys-passed-keys m [a b] object! [a b] [a b]]]
;---- extract-key-typeset
datatype: object!
out-data: copy []
keys-to-write: [a b]
forall keys-to-write [
append out-data reduce [
either datatype = object! [to-set-word :keys-to-write/1][:keys-to-write/1]
none
]
]
either attempt [out-data: make datatype out-data] [go-on?: true] [go-on?: false]
prin "Typeset-type-external-out-data-container: " probe dt [loop times [copy extract-keys-external-out-data-container m [a b] object! out-data]]
;------
prin "extract-keys-no-contains: " probe dt [loop times [extract-keys-no-contains m [a b] object!]]
;--- Running test without init but reusing containers
keys-to-pick: keys-to-write: [a b]
out-data: make object! [a: none b: none]
Prin "Fast: " probe dt [loop times [extract-keys-fast m [a b] object!]]
;--- Results (Note, they are not cumulative, the reference is the FULL version and not the previous one)
;Full: 0:00:01.37004 ;The base function
;Typeset: 0:00:01.34702 ;Changed parse of multiple datatypes with forall
;Typeset-type-forall: 0:00:01.276 ; As before + change of parse of for WORD! keys with a forall [word? key]
;Typeset-type-passed-keys: 0:00:01.28894 ;The keys are passed and not extracted
;Typeset-type-external-out-data-container: 0:00:01.04831 ;The target container is created externally and reused. On exit you copy it
;extract-keys-no-contains: 0:00:01.00221 ;No check if keys exists
;Fast: 0:00:00.174525 ;Just the loop and everything external
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment