From 2743ff5af4d489ed32bf994771a988cf6470119a Mon Sep 17 00:00:00 2001 From: Lyndon White Date: Thu, 11 Jan 2018 21:22:51 +0800 Subject: [PATCH 1/5] =gut the dictionary operations --- src/corefunctionality.jl | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/corefunctionality.jl b/src/corefunctionality.jl index dfab8cb..10e9c47 100644 --- a/src/corefunctionality.jl +++ b/src/corefunctionality.jl @@ -1,21 +1,23 @@ const pool = WeakKeyDict{String, Void}() -function intern!(wkd::WeakKeyDict{K}, key)::K where K + +function intern!(wkd::WeakKeyDict{K}, key::K)::K where K kk = convert(K, key) kwr = WeakRef(kk) - lock(wkd) do - found_key = getkey(wkd.ht, kwr, Base.secret_table_token) - found = !(found_key === Base.secret_table_token) - if found - return found_key.value + lock(wkd) do + index = Base.ht_keyindex2(wkd.ht, kwr) # returns index if present, or -index if not + if index > 0 + # found it + @inbounds found_key = wkd.ht.keys[index] + return found_key.value # a strong ref else # Not found, so add it, # and mark it as a reference we track to delete! - finalizer(kk, wkd.finalizer) - wkd.ht[kwr]=nothing - return kk + finalizer(kk, wkd.finalizer) # finalizer is set on the strong ref + @inbounds Base._setindex!(wkd.ht, nothing, kwr, -index) + return kk # Return the strong ref end end end From 0aa5381fb961f4492fde5c4270eedfa251c1cd9e Mon Sep 17 00:00:00 2001 From: Lyndon White Date: Thu, 11 Jan 2018 21:56:56 +0800 Subject: [PATCH 2/5] move locking inline, and avoid constructing weakrefs if not used --- src/corefunctionality.jl | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/src/corefunctionality.jl b/src/corefunctionality.jl index 10e9c47..07b4c3f 100644 --- a/src/corefunctionality.jl +++ b/src/corefunctionality.jl @@ -2,23 +2,26 @@ const pool = WeakKeyDict{String, Void}() -function intern!(wkd::WeakKeyDict{K}, key::K)::K where K - kk = convert(K, key) - kwr = WeakRef(kk) - - lock(wkd) do - index = Base.ht_keyindex2(wkd.ht, kwr) # returns index if present, or -index if not - if index > 0 - # found it - @inbounds found_key = wkd.ht.keys[index] - return found_key.value # a strong ref - else - # Not found, so add it, - # and mark it as a reference we track to delete! - finalizer(kk, wkd.finalizer) # finalizer is set on the strong ref - @inbounds Base._setindex!(wkd.ht, nothing, kwr, -index) - return kk # Return the strong ref - end + +@inline function intern!(wkd::WeakKeyDict{K}, key::K) ::K where K + kk::K = convert(K, key) + + lock(wkd.lock) + index = Base.ht_keyindex2(wkd.ht, kk) # returns index if present, or -index if not + # note hash of weakref is equal to the hash of value, so avoid constructing it if not required + if index > 0 + # found it + @inbounds found_key = wkd.ht.keys[index] + unlock(wkd.lock) + + return found_key.value # a strong ref + else + # Not found, so add it, + # and mark it as a reference we track to delete! + finalizer(kk, wkd.finalizer) # finalizer is set on the strong ref + @inbounds Base._setindex!(wkd.ht, nothing, WeakRef(kk), -index) + unlock(wkd.lock) + return kk # Return the strong ref end end From cc3bb6706bd3c3986f5dc2f7e103355536a573a9 Mon Sep 17 00:00:00 2001 From: Lyndon White Date: Thu, 11 Jan 2018 22:45:57 +0800 Subject: [PATCH 3/5] add reminder to make type-stable --- src/corefunctionality.jl | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/corefunctionality.jl b/src/corefunctionality.jl index 07b4c3f..87a134d 100644 --- a/src/corefunctionality.jl +++ b/src/corefunctionality.jl @@ -2,8 +2,7 @@ const pool = WeakKeyDict{String, Void}() - -@inline function intern!(wkd::WeakKeyDict{K}, key::K) ::K where K +@inline function intern!(wkd::WeakKeyDict{K}, key)::K where K kk::K = convert(K, key) lock(wkd.lock) @@ -14,7 +13,7 @@ const pool = WeakKeyDict{String, Void}() @inbounds found_key = wkd.ht.keys[index] unlock(wkd.lock) - return found_key.value # a strong ref + return found_key.value # a strong ref #TODO workout away to make this type stable else # Not found, so add it, # and mark it as a reference we track to delete! From 32115336c73eb34fade19204a182ebb334752e6b Mon Sep 17 00:00:00 2001 From: Lyndon White Date: Fri, 12 Jan 2018 00:55:34 +0800 Subject: [PATCH 4/5] =type inference --- src/corefunctionality.jl | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/corefunctionality.jl b/src/corefunctionality.jl index 87a134d..79b7ce5 100644 --- a/src/corefunctionality.jl +++ b/src/corefunctionality.jl @@ -1,19 +1,20 @@ - const pool = WeakKeyDict{String, Void}() +# This forces the type to be inferred (I don't know that the @noinline is reqired or even good) +@noinline getvalue(::Type{K}, wk) where K = wk.value::K @inline function intern!(wkd::WeakKeyDict{K}, key)::K where K kk::K = convert(K, key) lock(wkd.lock) + # hand positioning the locks and unlocks (rather than do block or try finally, seems to be faster) index = Base.ht_keyindex2(wkd.ht, kk) # returns index if present, or -index if not # note hash of weakref is equal to the hash of value, so avoid constructing it if not required if index > 0 # found it @inbounds found_key = wkd.ht.keys[index] unlock(wkd.lock) - - return found_key.value # a strong ref #TODO workout away to make this type stable + return getvalue(K, found_key) # return the strong ref else # Not found, so add it, # and mark it as a reference we track to delete! From 95b391609e38ef51c13167db22262d1881e1faca Mon Sep 17 00:00:00 2001 From: Lyndon White Date: Fri, 12 Jan 2018 10:25:34 +0800 Subject: [PATCH 5/5] Update corefunctionality.jl --- src/corefunctionality.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/corefunctionality.jl b/src/corefunctionality.jl index 79b7ce5..8327ad1 100644 --- a/src/corefunctionality.jl +++ b/src/corefunctionality.jl @@ -3,6 +3,8 @@ const pool = WeakKeyDict{String, Void}() # This forces the type to be inferred (I don't know that the @noinline is reqired or even good) @noinline getvalue(::Type{K}, wk) where K = wk.value::K + +# NOTE: This code is carefully optimised. Do not tweak it (for readability or otherwise) without benchmarking @inline function intern!(wkd::WeakKeyDict{K}, key)::K where K kk::K = convert(K, key)