From 60635fb0e76cbcefc2872b8dd9b4c32dc2489bd6 Mon Sep 17 00:00:00 2001 From: Nick Robinson Date: Wed, 14 Dec 2022 14:42:02 +0000 Subject: [PATCH 01/10] Test `TimeZone` has minimal allocations - Should not allocate for cached FixedTimeZone - Should allocate only once for cached VariableTimeZone --- test/helpers.jl | 12 ++++++++++++ test/types/timezone.jl | 10 ++++++++++ 2 files changed, 22 insertions(+) diff --git a/test/helpers.jl b/test/helpers.jl index 8071876d9..c497a8b49 100644 --- a/test/helpers.jl +++ b/test/helpers.jl @@ -1,5 +1,17 @@ # Utility functions for testing +if VERSION < v"1.9.0-" # https://github.com/JuliaLang/julia/pull/47367 + macro allocations(ex) + quote + Base.Experimental.@force_compile + local stats = Base.gc_num() + $(esc(ex)) + local diff = Base.GC_Diff(Base.gc_num(), stats) + Base.gc_alloc_count(diff) + end + end +end + function ignore_output(body::Function; stdout::Bool=true, stderr::Bool=true) out_old = Base.stdout err_old = Base.stderr diff --git a/test/types/timezone.jl b/test/types/timezone.jl index 0ca6db54c..890ea91c3 100644 --- a/test/types/timezone.jl +++ b/test/types/timezone.jl @@ -1,5 +1,15 @@ using TimeZones: Class +@testset "TimeZone allocations" begin + tz = TimeZone("UTC") # run once for compilation and to populate cache + @assert tz isa FixedTimeZone + @test 0 == @allocations(TimeZone("UTC")) + + tz = TimeZone("America/Winnipeg") # populate cache + @assert tz isa VariableTimeZone + @test 1 == @allocations(TimeZone("America/Winnipeg")) +end + @testset "istimezone" begin @test istimezone("Europe/Warsaw") @test istimezone("UTC+02") From e57e3b2cbb0eb7a4c06684204877c1e129d9b78f Mon Sep 17 00:00:00 2001 From: Nick Robinson Date: Wed, 21 Dec 2022 15:56:43 +0000 Subject: [PATCH 02/10] Avoid using `@force_compile` --- test/helpers.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/helpers.jl b/test/helpers.jl index c497a8b49..601a3ea38 100644 --- a/test/helpers.jl +++ b/test/helpers.jl @@ -3,7 +3,7 @@ if VERSION < v"1.9.0-" # https://github.com/JuliaLang/julia/pull/47367 macro allocations(ex) quote - Base.Experimental.@force_compile + while false; end # want to force compilation, but v1.6 doesn't have `@force_compile` local stats = Base.gc_num() $(esc(ex)) local diff = Base.GC_Diff(Base.gc_num(), stats) From dcac298b2489a5c5911c709f1ec67ae3d8f85ced Mon Sep 17 00:00:00 2001 From: Tom Gillam Date: Thu, 30 Nov 2023 17:02:02 +0000 Subject: [PATCH 03/10] Implement type-specific caches --- src/TimeZones.jl | 2 +- src/types/timezone.jl | 32 +++++++++++++++++++++++--------- test/helpers.jl | 21 ++++++++++++++++++--- 3 files changed, 42 insertions(+), 13 deletions(-) diff --git a/src/TimeZones.jl b/src/TimeZones.jl index 4b704d840..124378cc8 100644 --- a/src/TimeZones.jl +++ b/src/TimeZones.jl @@ -70,9 +70,9 @@ include("indexable_generator.jl") include("class.jl") include("utcoffset.jl") -include(joinpath("types", "timezone.jl")) include(joinpath("types", "fixedtimezone.jl")) include(joinpath("types", "variabletimezone.jl")) +include(joinpath("types", "timezone.jl")) include(joinpath("types", "zoneddatetime.jl")) include(joinpath("tzfile", "TZFile.jl")) include(joinpath("tzjfile", "TZJFile.jl")) diff --git a/src/types/timezone.jl b/src/types/timezone.jl index b6f9cba87..8dbeb3932 100644 --- a/src/types/timezone.jl +++ b/src/types/timezone.jl @@ -1,15 +1,17 @@ # Retains the compiled tzdata in memory. Read-only access is thread-safe and any changes # to this structure can result in inconsistent behaviour. -const _TZ_CACHE = Dict{String,Tuple{TimeZone,Class}}() +const _FTZ_CACHE = Dict{String,Tuple{FixedTimeZone,Class}}() +const _VTZ_CACHE = Dict{String,Tuple{VariableTimeZone,Class}}() function _reload_cache(compiled_dir::AbstractString) - _reload_cache!(_TZ_CACHE, compiled_dir) - !isempty(_TZ_CACHE) || error("Cache remains empty after loading") + _reload_cache!(_FTZ_CACHE, _VTZ_CACHE, compiled_dir) + !isempty(_FTZ_CACHE) && !isempty(_VTZ_CACHE) || error("Cache remains empty after loading") return nothing end -function _reload_cache!(cache::AbstractDict, compiled_dir::AbstractString) - empty!(cache) +function _reload_cache!(ftz_cache::AbstractDict, vtz_cache::AbstractDict, compiled_dir::AbstractString) + empty!(ftz_cache) + empty!(vtz_cache) check = Tuple{String,String}[(compiled_dir, "")] for (dir, partial) in check @@ -22,12 +24,24 @@ function _reload_cache!(cache::AbstractDict, compiled_dir::AbstractString) if isdir(path) push!(check, (path, name)) else - cache[name] = open(TZJFile.read, path, "r")(name) + tz, class = open(TZJFile.read, path, "r")(name) + if isa(tz, FixedTimeZone) + ftz_cache[name] = (tz, class) + elseif isa(tz, VariableTimeZone) + vtz_cache[name] = (tz, class) + end end end end + return nothing +end - return cache +function _get_from_cache(f_default::Function, name::AbstractString) + return get(_FTZ_CACHE, name) do + get(_VTZ_CACHE, name) do + return f_default() + end + end end """ @@ -71,7 +85,7 @@ US/Pacific (UTC-8/UTC-7) TimeZone(::AbstractString, ::Class) function TimeZone(str::AbstractString, mask::Class=Class(:DEFAULT)) - tz, class = get(_TZ_CACHE, str) do + tz, class = _get_from_cache(str) do if occursin(FIXED_TIME_ZONE_REGEX, str) FixedTimeZone(str), Class(:FIXED) else @@ -116,7 +130,7 @@ function istimezone(str::AbstractString, mask::Class=Class(:DEFAULT)) end # Checks against pre-compiled time zones - tz, class = get(_TZ_CACHE, str) do + tz, class = _get_from_cache(str) do nothing, Class(:NONE) end diff --git a/test/helpers.jl b/test/helpers.jl index 601a3ea38..df013000d 100644 --- a/test/helpers.jl +++ b/test/helpers.jl @@ -67,12 +67,27 @@ function add!(cache::Dict, tz::FixedTimeZone) end function with_tz_cache(f, cache::Dict{String,Tuple{TimeZone,TimeZones.Class}}) - old_cache = deepcopy(TimeZones._TZ_CACHE) - copy!(TimeZones._TZ_CACHE, cache) + old_ftz_cache = deepcopy(TimeZones._FTZ_CACHE) + old_vtz_cache = deepcopy(TimeZones._VTZ_CACHE) + + # Split the contents of `cache` between the fixed and variable caches + # as appropriate. + empty!(TimeZones._FTZ_CACHE) + empty!(TimeZones._VTZ_CACHE) + foreach(items(cache)) do (k, v) + setindex!( + isa(v, FixedTimeZone) ? TimeZones._FTZ_CACHE : TimeZones._VTZ_CACHE, + k, + v, + ) + end + copy!(TimeZones._FTZ_CACHE, cache) + copy!(TimeZones._VTZ_CACHE, cache) try return f() finally - copy!(TimeZones._TZ_CACHE, old_cache) + copy!(TimeZones._FTZ_CACHE, old_ftz_cache) + copy!(TimeZones._VTZ_CACHE, old_vtz_cache) end end From 14afcfefa7821db8fe1b5383dda6da34afc51ac0 Mon Sep 17 00:00:00 2001 From: Tom Gillam Date: Thu, 30 Nov 2023 17:11:12 +0000 Subject: [PATCH 04/10] Reinstate comment from original PR --- src/types/timezone.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/types/timezone.jl b/src/types/timezone.jl index 8dbeb3932..a754aeaf2 100644 --- a/src/types/timezone.jl +++ b/src/types/timezone.jl @@ -1,5 +1,8 @@ # Retains the compiled tzdata in memory. Read-only access is thread-safe and any changes # to this structure can result in inconsistent behaviour. +# +# Use a separate cache for FixedTimeZone (which is `isbits`) so the container is concretely +# typed and we avoid allocating a FixedTimeZone every time we get one from the cache. const _FTZ_CACHE = Dict{String,Tuple{FixedTimeZone,Class}}() const _VTZ_CACHE = Dict{String,Tuple{VariableTimeZone,Class}}() From b297bac512e78ef0305d8acbe1ed579e4278f1e5 Mon Sep 17 00:00:00 2001 From: Tom Gillam Date: Thu, 30 Nov 2023 17:42:47 +0000 Subject: [PATCH 05/10] Fix bug --- test/helpers.jl | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/test/helpers.jl b/test/helpers.jl index df013000d..1b868af01 100644 --- a/test/helpers.jl +++ b/test/helpers.jl @@ -74,15 +74,13 @@ function with_tz_cache(f, cache::Dict{String,Tuple{TimeZone,TimeZones.Class}}) # as appropriate. empty!(TimeZones._FTZ_CACHE) empty!(TimeZones._VTZ_CACHE) - foreach(items(cache)) do (k, v) + foreach(cache) do (k, v) setindex!( - isa(v, FixedTimeZone) ? TimeZones._FTZ_CACHE : TimeZones._VTZ_CACHE, - k, + isa(first(v), FixedTimeZone) ? TimeZones._FTZ_CACHE : TimeZones._VTZ_CACHE, v, + k, ) end - copy!(TimeZones._FTZ_CACHE, cache) - copy!(TimeZones._VTZ_CACHE, cache) try return f() From 7c0e07f72b16773d399f887f974b5f5f1f954c86 Mon Sep 17 00:00:00 2001 From: Tom Gillam Date: Thu, 30 Nov 2023 17:42:56 +0000 Subject: [PATCH 06/10] Remove trailing space --- src/types/timezone.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/timezone.jl b/src/types/timezone.jl index a754aeaf2..c68cad54a 100644 --- a/src/types/timezone.jl +++ b/src/types/timezone.jl @@ -30,7 +30,7 @@ function _reload_cache!(ftz_cache::AbstractDict, vtz_cache::AbstractDict, compil tz, class = open(TZJFile.read, path, "r")(name) if isa(tz, FixedTimeZone) ftz_cache[name] = (tz, class) - elseif isa(tz, VariableTimeZone) + elseif isa(tz, VariableTimeZone) vtz_cache[name] = (tz, class) end end From 3efcb48ee58c952c66f776cb5c33f72bcff016eb Mon Sep 17 00:00:00 2001 From: Tom Gillam Date: Thu, 30 Nov 2023 17:43:12 +0000 Subject: [PATCH 07/10] Can't get VariableTimeZone retrieval below 2 allocs --- test/types/timezone.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/types/timezone.jl b/test/types/timezone.jl index 890ea91c3..37dfc4153 100644 --- a/test/types/timezone.jl +++ b/test/types/timezone.jl @@ -7,7 +7,7 @@ using TimeZones: Class tz = TimeZone("America/Winnipeg") # populate cache @assert tz isa VariableTimeZone - @test 1 == @allocations(TimeZone("America/Winnipeg")) + @test 2 == @allocations(TimeZone("America/Winnipeg")) end @testset "istimezone" begin From 2b0b76e1e9e6ac28f605566caaf496e20383f022 Mon Sep 17 00:00:00 2001 From: Tom Gillam Date: Thu, 30 Nov 2023 21:22:56 +0000 Subject: [PATCH 08/10] Apply suggestions from code review Co-authored-by: Curtis Vogt --- src/types/timezone.jl | 2 ++ test/helpers.jl | 10 ++++------ test/types/timezone.jl | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/types/timezone.jl b/src/types/timezone.jl index c68cad54a..c547a40c9 100644 --- a/src/types/timezone.jl +++ b/src/types/timezone.jl @@ -32,6 +32,8 @@ function _reload_cache!(ftz_cache::AbstractDict, vtz_cache::AbstractDict, compil ftz_cache[name] = (tz, class) elseif isa(tz, VariableTimeZone) vtz_cache[name] = (tz, class) + else + error("Unhandled TimeZone class encountered: $(typeof(tz))") end end end diff --git a/test/helpers.jl b/test/helpers.jl index 1b868af01..d045638d2 100644 --- a/test/helpers.jl +++ b/test/helpers.jl @@ -1,6 +1,6 @@ # Utility functions for testing -if VERSION < v"1.9.0-" # https://github.com/JuliaLang/julia/pull/47367 +if VERSION < v"1.9.0-DEV.1744" # https://github.com/JuliaLang/julia/pull/47367 macro allocations(ex) quote while false; end # want to force compilation, but v1.6 doesn't have `@force_compile` @@ -75,11 +75,9 @@ function with_tz_cache(f, cache::Dict{String,Tuple{TimeZone,TimeZones.Class}}) empty!(TimeZones._FTZ_CACHE) empty!(TimeZones._VTZ_CACHE) foreach(cache) do (k, v) - setindex!( - isa(first(v), FixedTimeZone) ? TimeZones._FTZ_CACHE : TimeZones._VTZ_CACHE, - v, - k, - ) + tz = first(v) + cache = tz isa FixedTimeZone ? TimeZones._FTZ_CACHE : TimeZones._VTZ_CACHE + setindex!(cache, v, k) end try diff --git a/test/types/timezone.jl b/test/types/timezone.jl index 37dfc4153..3c37bd13b 100644 --- a/test/types/timezone.jl +++ b/test/types/timezone.jl @@ -3,11 +3,11 @@ using TimeZones: Class @testset "TimeZone allocations" begin tz = TimeZone("UTC") # run once for compilation and to populate cache @assert tz isa FixedTimeZone - @test 0 == @allocations(TimeZone("UTC")) + @test @allocations(TimeZone("UTC")) == 0 tz = TimeZone("America/Winnipeg") # populate cache @assert tz isa VariableTimeZone - @test 2 == @allocations(TimeZone("America/Winnipeg")) + @test @allocations(TimeZone("America/Winnipeg")) == 2 end @testset "istimezone" begin From 67f2c3f3798759bacc4858a89d644f9a4a9e9dcf Mon Sep 17 00:00:00 2001 From: Curtis Vogt Date: Wed, 22 May 2024 23:12:56 -0500 Subject: [PATCH 09/10] Create TimeZoneCache struct --- src/types/timezone.jl | 93 ++++++++++++++++++++++++------------------- test/helpers.jl | 36 +++++++---------- test/io.jl | 3 +- 3 files changed, 69 insertions(+), 63 deletions(-) diff --git a/src/types/timezone.jl b/src/types/timezone.jl index cb2273baa..b0e1f6249 100644 --- a/src/types/timezone.jl +++ b/src/types/timezone.jl @@ -1,37 +1,29 @@ -# Retains the compiled tzdata in memory. Read-only access to the cache is thread-safe and -# any changes to this structure can result in inconsistent behaviour. Do not access this -# object directly, instead use `_get_tz_cache_entry()` to access the cache content. -# # Use a separate cache for FixedTimeZone (which is `isbits`) so the container is concretely # typed and we avoid allocating a FixedTimeZone every time we get one from the cache. -const _FTZ_CACHE = Dict{String,Tuple{FixedTimeZone,Class}}() -const _VTZ_CACHE = Dict{String,Tuple{VariableTimeZone,Class}}() -const _TZ_CACHE_LOCK = ReentrantLock() -const _TZ_CACHE_INITIALIZED = Threads.Atomic{Bool}(false) - -function _init_tz_cache() - # Write out our compiled tzdata representations into a scratchspace - desired_version = TZData.tzdata_version() - - _COMPILED_DIR[] = if desired_version == TZJData.TZDATA_VERSION - TZJData.ARTIFACT_DIR - else - TZData.build(desired_version, _scratch_dir()) - end - - # Load the pre-computed TZData into memory. - return _reload_tz_cache(_COMPILED_DIR[]) +struct TimeZoneCache + ftz::Dict{String,Tuple{FixedTimeZone,Class}} + vtz::Dict{String,Tuple{VariableTimeZone,Class}} + lock::ReentrantLock + initialized::Threads.Atomic{Bool} end -function _reload_tz_cache(compiled_dir::AbstractString) - _reload_tz_cache!(_FTZ_CACHE, _VTZ_CACHE, compiled_dir) - !isempty(_FTZ_CACHE) && !isempty(_VTZ_CACHE) || error("Cache remains empty after loading") - return nothing +TimeZoneCache() = TimeZoneCache(Dict(), Dict(), ReentrantLock(), Threads.Atomic{Bool}(false)) + +# Retains the compiled tzdata in memory. Read-only access to the cache is thread-safe and +# any changes to this structure can result in inconsistent behaviour. Do not access this +# object directly, instead use `get` to access the cache content. +const _TZ_CACHE = TimeZoneCache() + +function Base.copy!(dst::TimeZoneCache, src::TimeZoneCache) + copy!(dst.ftz, src.ftz) + copy!(dst.vtz, src.vtz) + dst.initialized[] = src.initialized[] + return dst end -function _reload_tz_cache!(ftz_cache::AbstractDict, vtz_cache::AbstractDict, compiled_dir::AbstractString) - empty!(ftz_cache) - empty!(vtz_cache) +function reload!(cache::TimeZoneCache, compiled_dir::AbstractString=_COMPILED_DIR[]) + empty!(cache.ftz) + empty!(cache.vtz) check = Tuple{String,String}[(compiled_dir, "")] for (dir, partial) in check @@ -47,35 +39,54 @@ function _reload_tz_cache!(ftz_cache::AbstractDict, vtz_cache::AbstractDict, com tz, class = open(TZJFile.read, path, "r")(name) if tz isa FixedTimeZone - ftz_cache[name] = (tz, class) + cache.ftz[name] = (tz, class) elseif tz isa VariableTimeZone - vtz_cache[name] = (tz, class) + cache.vtz[name] = (tz, class) else error("Unhandled TimeZone class encountered: $(typeof(tz))") end end end end - return nothing + + !isempty(cache.ftz) && !isempty(cache.vtz) || error("Cache remains empty after loading") + + return cache end -function _get_tz_cache_entry(body::Function, name::AbstractString) - if !_TZ_CACHE_INITIALIZED[] - lock(_TZ_CACHE_LOCK) do - if !_TZ_CACHE_INITIALIZED[] - _init_tz_cache() - _TZ_CACHE_INITIALIZED[] = true +function Base.get(body::Function, cache::TimeZoneCache, name::AbstractString) + if !cache.initialized[] + lock(cache.lock) do + if !cache.initialized[] + _initialize() + reload!(cache) + cache.initialized[] = true end end end - return get(_FTZ_CACHE, name) do - get(_VTZ_CACHE, name) do + return get(cache.ftz, name) do + get(cache.vtz, name) do body() end end end +function _initialize() + # Write out our compiled tzdata representations into a scratchspace + desired_version = TZData.tzdata_version() + + _COMPILED_DIR[] = if desired_version == TZJData.TZDATA_VERSION + TZJData.ARTIFACT_DIR + else + TZData.build(desired_version, _scratch_dir()) + end + + return nothing +end + +_reload_tz_cache(compiled_dir::AbstractString) = reload!(_TZ_CACHE, compiled_dir) + """ TimeZone(str::AbstractString) -> TimeZone @@ -117,7 +128,7 @@ US/Pacific (UTC-8/UTC-7) TimeZone(::AbstractString, ::Class) function TimeZone(str::AbstractString, mask::Class=Class(:DEFAULT)) - tz, class = _get_tz_cache_entry(str) do + tz, class = get(_TZ_CACHE, str) do if occursin(FIXED_TIME_ZONE_REGEX, str) FixedTimeZone(str), Class(:FIXED) else @@ -162,6 +173,6 @@ function istimezone(str::AbstractString, mask::Class=Class(:DEFAULT)) end # Checks against pre-compiled time zones - class = _get_tz_cache_entry(() -> (UTC_ZERO, Class(:NONE)), str)[2] + class = get(() -> (UTC_ZERO, Class(:NONE)), _TZ_CACHE, str)[2] return mask & class != Class(:NONE) end diff --git a/test/helpers.jl b/test/helpers.jl index d045638d2..0bd0b079f 100644 --- a/test/helpers.jl +++ b/test/helpers.jl @@ -47,43 +47,37 @@ show_compact = (io, args...) -> show(IOContext(io, :compact => true), args...) # Modified the internal TimeZones cache. Should only be used as part of testing and only is # needed when the data between the test tzdata version and the built tzdata versions differ. -function add!(cache::Dict, t::Tuple{TimeZone,TimeZones.Class}) +function add!(dict::Dict, t::Tuple{TimeZone,TimeZones.Class}) tz, class = t name = TimeZones.name(tz) - push!(cache, name => t) + push!(dict, name => t) return tz end -function add!(cache::Dict, tz::VariableTimeZone) +function add!(cache::TimeZones.TimeZoneCache, t::Tuple{T,TimeZones.Class}) where {T<:TimeZone} + dict = T == FixedTimeZone ? cache.ftz : cache.vtz + return add!(dict, t) +end + +function add!(cache::TimeZones.TimeZoneCache, tz::VariableTimeZone) # Not all `VariableTimeZone`s are the STANDARD class. However, for testing purposes # the class doesn't need to be precise. class = TimeZones.Class(:STANDARD) - return add!(cache, (tz, class)) + return add!(cache.vtz, (tz, class)) end -function add!(cache::Dict, tz::FixedTimeZone) +function add!(cache::TimeZones.TimeZoneCache, tz::FixedTimeZone) class = TimeZones.Class(:FIXED) - return add!(cache, (tz, class)) + return add!(cache.ftz, (tz, class)) end -function with_tz_cache(f, cache::Dict{String,Tuple{TimeZone,TimeZones.Class}}) - old_ftz_cache = deepcopy(TimeZones._FTZ_CACHE) - old_vtz_cache = deepcopy(TimeZones._VTZ_CACHE) - - # Split the contents of `cache` between the fixed and variable caches - # as appropriate. - empty!(TimeZones._FTZ_CACHE) - empty!(TimeZones._VTZ_CACHE) - foreach(cache) do (k, v) - tz = first(v) - cache = tz isa FixedTimeZone ? TimeZones._FTZ_CACHE : TimeZones._VTZ_CACHE - setindex!(cache, v, k) - end +function with_tz_cache(f, cache::TimeZones.TimeZoneCache) + old_cache = deepcopy(TimeZones._TZ_CACHE) + copy!(TimeZones._TZ_CACHE, cache) try return f() finally - copy!(TimeZones._FTZ_CACHE, old_ftz_cache) - copy!(TimeZones._VTZ_CACHE, old_vtz_cache) + copy!(TimeZones._TZ_CACHE, old_cache) end end diff --git a/test/io.jl b/test/io.jl index 5141551dd..701225f2a 100644 --- a/test/io.jl +++ b/test/io.jl @@ -1,7 +1,8 @@ using TimeZones.TZData: parse_components using TimeZones: Transition -cache = Dict{String,Tuple{TimeZone,TimeZones.Class}}() +cache = TimeZones.TimeZoneCache() +cache.initialized[] = true dt = DateTime(1942,12,25,1,23,45) custom_dt = DateTime(1800,1,1) From 123717388d5ad2b65e9890ef477f8bda505d2585 Mon Sep 17 00:00:00 2001 From: Curtis Vogt Date: Thu, 23 May 2024 08:24:20 -0500 Subject: [PATCH 10/10] Refactor allocation tests --- test/types/timezone.jl | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/test/types/timezone.jl b/test/types/timezone.jl index 3c37bd13b..d7a45b27c 100644 --- a/test/types/timezone.jl +++ b/test/types/timezone.jl @@ -1,15 +1,5 @@ using TimeZones: Class -@testset "TimeZone allocations" begin - tz = TimeZone("UTC") # run once for compilation and to populate cache - @assert tz isa FixedTimeZone - @test @allocations(TimeZone("UTC")) == 0 - - tz = TimeZone("America/Winnipeg") # populate cache - @assert tz isa VariableTimeZone - @test @allocations(TimeZone("America/Winnipeg")) == 2 -end - @testset "istimezone" begin @test istimezone("Europe/Warsaw") @test istimezone("UTC+02") @@ -35,3 +25,15 @@ end @test TimeZone("Etc/GMT+12", Class(:LEGACY)) == FixedTimeZone("Etc/GMT+12", -12 * 3600) @test TimeZone("Etc/GMT-14", Class(:LEGACY)) == FixedTimeZone("Etc/GMT-14", 14 * 3600) end + +@testset "allocations" begin + tz = TimeZone("UTC") # Trigger compilation and ensure the cache is populated + @test tz isa FixedTimeZone + @test @allocations(TimeZone("UTC")) == 0 + @test @allocations(istimezone("UTC")) == 0 + + tz = TimeZone("America/Winnipeg") # Trigger compilation and ensure the cache is populated + @test tz isa VariableTimeZone + @test @allocations(TimeZone("America/Winnipeg")) == 2 + @test @allocations(istimezone("America/Winnipeg")) == 1 +end