Skip to content

Use typed Channels for allcells, allleaves, allparents to fix type instability#46

Open
cserteGT3 wants to merge 2 commits intoJuliaGeometry:masterfrom
cserteGT3:cst-fix-channels
Open

Use typed Channels for allcells, allleaves, allparents to fix type instability#46
cserteGT3 wants to merge 2 commits intoJuliaGeometry:masterfrom
cserteGT3:cst-fix-channels

Conversation

@cserteGT3
Copy link

@cserteGT3 cserteGT3 commented Nov 24, 2025

Closes #43
Fixed the type instability by adding types to Channels in allcells, allleaves, allparents. Basically applied the change suggested in #43. It comes with a little bit of performance improvement, but nothing groundbreaking. You can find my test code and results below:

Test code

using RegionTrees
using StaticArrays: SVector
using BenchmarkTools

root = RegionTrees.Cell(SVector(0., 0), SVector(1., 1))
split!(root)
split!(root[1,1])

# adaptive sampling
using RegionTrees
import RegionTrees: AbstractRefinery, needs_refinement, refine_data

struct MyRefinery <: AbstractRefinery
    tolerance::Float64
end

function needs_refinement(r::MyRefinery, cell)
    maximum(cell.boundary.widths) > r.tolerance
end

function refine_data(r::MyRefinery, cell::Cell, indices)
    boundary = child_boundary(cell, indices)
    "child with widths: $(boundary.widths)"
end

r = MyRefinery(0.1)
root = Cell(SVector(0., 0), SVector(1., 1), "root")
adaptivesampling!(root, r)

Results on master

julia> @benchmark allleaves(root)
BenchmarkTools.Trial: 10000 samples with 3 evaluations per sample.
 Range (min  max):   7.833 μs   11.930 ms  ┊ GC (min  max):  0.00%  99.66%
 Time  (median):     11.100 μs               ┊ GC (median):     0.00%
 Time  (mean ± σ):   17.645 μs ± 133.990 μs  ┊ GC (mean ± σ):  10.09% ±  1.40%

  ▂██▇▃▃▂▃▃▃▃▂▁▁▁▂▃▃▂▂▂▁▁▁▁                                    ▂
  ████████████████████████████████▇█▇▆▆▆▆▆▄▄▅▃▆▅▅▃▁▅▅▄▅▄▅▄▄▃▅▄ █
  7.83 μs       Histogram: log(frequency) by time      77.5 μs <

 Memory estimate: 2.41 KiB, allocs estimate: 46.

julia> @benchmark collect(allleaves(root))
BenchmarkTools.Trial: 5845 samples with 1 evaluation per sample.
 Range (min  max):  692.600 μs    5.000 ms  ┊ GC (min  max): 0.00%  0.00%
 Time  (median):     762.900 μs               ┊ GC (median):    0.00%
 Time  (mean ± σ):   849.657 μs ± 225.039 μs  ┊ GC (mean ± σ):  0.00% ± 0.00%

  ▄▇█▇▅▄▅▅▆▄▄▃▃▃▂▂▂▁▁  ▁                                        ▂
  ████████████████████████████▇▇█▇█▆▇▇▇▆▇▇▇▇▇▇▆▅▅▅▁▅▅▅▆▇▅▅▅▅▅▅▅ █
  693 μs        Histogram: log(frequency) by time       1.85 ms <

 Memory estimate: 17.66 KiB, allocs estimate: 648.

julia> @code_warntype allleaves(root)
MethodInstance for allleaves(::Cell{String, 2, Float64, 4})
  from allleaves(cell::Cell) @ RegionTrees C:\Users\csert\.julia\dev\RegionTrees\src\cell.jl:110
Arguments
  #self#::Core.Const(RegionTrees.allleaves)
  cell::Cell{String, 2, Float64, 4}
Locals
  #44::RegionTrees.var"#allleaves##0#allleaves##1"{Cell{String, 2, Float64, 4}}
Body::Channel{Any}
1%1 = RegionTrees.Channel::Core.Const(Channel)
│   %2 = RegionTrees.:(var"#allleaves##0#allleaves##1")::Core.Const(RegionTrees.var"#allleaves##0#allleaves##1")
│   %3 = Core._typeof_captured_variable(cell)::Core.Const(Cell{String, 2, Float64, 4})
│   %4 = Core.apply_type(%2, %3)::Core.Const(RegionTrees.var"#allleaves##0#allleaves##1"{Cell{String, 2, Float64, 4}})
│        (#44 = %new(%4, cell))%6 = #44::RegionTrees.var"#allleaves##0#allleaves##1"{Cell{String, 2, Float64, 4}}%7 = (%1)(%6)::Channel{Any}
└──      return %7

julia> @code_warntype collect(allleaves(root))
MethodInstance for collect(::Channel{Any})
  from collect(itr) @ Base array.jl:728
Arguments
  #self#::Core.Const(collect)
  itr::Channel{Any}
Body::Vector{Any}
1%1 = Base._collect::Core.Const(Base._collect)
│   %2 = Base.:(:)::Core.Const(Colon())
│   %3 = (%2)(1, 1)::Core.Const(1:1)
│   %4 = Base.IteratorEltype::Core.Const(Base.IteratorEltype)
│   %5 = (%4)(itr)::Core.Const(Base.HasEltype())
│   %6 = Base.IteratorSize::Core.Const(Base.IteratorSize)
│   %7 = (%6)(itr)::Core.Const(Base.SizeUnknown())
│   %8 = (%1)(%3, itr, %5, %7)::Vector{Any}
└──      return %8

Results on PR branch

julia> @benchmark allleaves(root)
BenchmarkTools.Trial: 10000 samples with 4 evaluations per sample.
 Range (min  max):   7.050 μs    9.418 ms  ┊ GC (min  max):  0.00%  99.70%
 Time  (median):     10.475 μs               ┊ GC (median):     0.00%
 Time  (mean ± σ):   17.647 μs ± 125.818 μs  ┊ GC (mean ± σ):  11.56% ±  1.71%

  ▁██▇▄▃▃▄▃▄▃▃▃▄▃▂▂▂▁▁  ▁                                      ▂
  ████████████████████████▇██▇█▇▇▇▇▇▆▆▇▆▆▆▇▅▆▄▅▆▃▆▅▅▄▅▄▄▅▄▄▄▄▄ █
  7.05 μs       Histogram: log(frequency) by time      74.4 μs <

 Memory estimate: 2.39 KiB, allocs estimate: 45.
 
 julia> @benchmark collect(allleaves(root))
BenchmarkTools.Trial: 6504 samples with 1 evaluation per sample.
 Range (min  max):  634.800 μs    7.777 ms  ┊ GC (min  max): 0.00%  90.92%
 Time  (median):     675.900 μs               ┊ GC (median):    0.00%
 Time  (mean ± σ):   762.953 μs ± 225.599 μs  ┊ GC (mean ± σ):  0.14% ±  1.13%

  ▆█▆▄▃▃▅▅▄▃▂▂▁ ▁                                               ▁
  ████████████████████▇▇█▆▇▇▇▇▇██▇▇▇▆▆▆▆▇▇▇▆▆▆▆▅▅▆▅▆▅▅▄▅▅▄▄▄▄▄▅ █
  635 μs        Histogram: log(frequency) by time       1.69 ms <

 Memory estimate: 17.65 KiB, allocs estimate: 647.

 julia> @code_warntype allleaves(root)
MethodInstance for allleaves(::Cell{String, 2, Float64, 4})
  from allleaves(cell::Cell{Data, N, T, L}) where {Data, N, T, L} @ RegionTrees C:\Users\csert\.julia\dev\RegionTrees\src\cell.jl:110
Static Parameters
  Data = String
  N = 2
  T = Float64
  L = 4
Arguments
  #self#::Core.Const(RegionTrees.allleaves)
  cell::Cell{String, 2, Float64, 4}
Locals
  #44::RegionTrees.var"#allleaves##0#allleaves##1"{Cell{String, 2, Float64, 4}}
Body::Channel{Cell{String, 2, Float64, 4}}
1%1  = RegionTrees.Channel::Core.Const(Channel)
│   %2  = RegionTrees.Cell::Core.Const(Cell)
│   %3  = $(Expr(:static_parameter, 1))::Core.Const(String)
│   %4  = $(Expr(:static_parameter, 2))::Core.Const(2)
│   %5  = $(Expr(:static_parameter, 3))::Core.Const(Float64)
│   %6  = $(Expr(:static_parameter, 4))::Core.Const(4)
│   %7  = Core.apply_type(%2, %3, %4, %5, %6)::Core.Const(Cell{String, 2, Float64, 4})
│   %8  = Core.apply_type(%1, %7)::Core.Const(Channel{Cell{String, 2, Float64, 4}})
│   %9  = RegionTrees.:(var"#allleaves##0#allleaves##1")::Core.Const(RegionTrees.var"#allleaves##0#allleaves##1")
│   %10 = Core._typeof_captured_variable(cell)::Core.Const(Cell{String, 2, Float64, 4})
│   %11 = Core.apply_type(%9, %10)::Core.Const(RegionTrees.var"#allleaves##0#allleaves##1"{Cell{String, 2, Float64, 4}})
│         (#44 = %new(%11, cell))%13 = #44::RegionTrees.var"#allleaves##0#allleaves##1"{Cell{String, 2, Float64, 4}}%14 = (%8)(%13)::Channel{Cell{String, 2, Float64, 4}}
└──       return %14

julia> @code_warntype collect(allleaves(root))
MethodInstance for collect(::Channel{Cell{String, 2, Float64, 4}})
  from collect(itr) @ Base array.jl:728
Arguments
  #self#::Core.Const(collect)
  itr::Channel{Cell{String, 2, Float64, 4}}
Body::Vector{Cell{String, 2, Float64, 4}}
1%1 = Base._collect::Core.Const(Base._collect)
│   %2 = Base.:(:)::Core.Const(Colon())
│   %3 = (%2)(1, 1)::Core.Const(1:1)
│   %4 = Base.IteratorEltype::Core.Const(Base.IteratorEltype)
│   %5 = (%4)(itr)::Core.Const(Base.HasEltype())
│   %6 = Base.IteratorSize::Core.Const(Base.IteratorSize)
│   %7 = (%6)(itr)::Core.Const(Base.SizeUnknown())
│   %8 = (%1)(%3, itr, %5, %7)::Vector{Cell{String, 2, Float64, 4}}
└──      return %8

@cserteGT3
Copy link
Author

CI needs 6eeb3c5 from #45 to run.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Type unstable allchildren()

1 participant