Skip to content

OrderedDict: improve performance for non-concrete values and keys#166

Merged
KristofferC merged 1 commit into
JuliaCollections:masterfrom
KristofferC:kc/non_concrete
Jun 1, 2026
Merged

OrderedDict: improve performance for non-concrete values and keys#166
KristofferC merged 1 commit into
JuliaCollections:masterfrom
KristofferC:kc/non_concrete

Conversation

@KristofferC
Copy link
Copy Markdown
Collaborator

Using the following benchmark

  using OrderedCollections
  using BenchmarkTools

  const N = 1000
  pairs = [i => (iseven(i) ? i : Float64(i)) for i in 1:N]

  d_base = Dict{Int,Number}(pairs)
  d_ord  = OrderedDict{Int,Number}(pairs)

  function sumvals(d)
      s = 0.0
      for (k, v) in d
          s += v
      end
      return s
  end

  println(Base.return_types(iterate, (Dict{Int,Number},))[1])
  println(Base.return_types(iterate, (OrderedDict{Int,Number},))[1])

  @btime sumvals($d_base)
  @btime sumvals($d_ord)

I get:

  # Base:
  #  16.441 μs (1000 allocations: 15.62 KiB)
  # Ordered Before PR
  # 179.508 μs (6214 allocations: 143.97 KiB)
  # Ordered After PR:
  # 9.180 μs (1000 allocations: 15.62 KiB)

This mirrors how Base does it https://github.com/JuliaLang/julia/blob/3e1bf51ccd6f5cb8a547ca99d0fd33de24ac85e8/base/dict.jl#L701

@KristofferC KristofferC changed the title improve performance for non-concrete values and keys OrderedDict: improve performance for non-concrete values and keys Jun 1, 2026
Copy link
Copy Markdown
Member

@timholy timholy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sad to see more rather than fewer @inbounds annotations but the performance gain is compelling.

One optional tweak. Good to go once you decide how you want to proceed.

Comment thread src/ordered_dict.jl
function iterate(t::OrderedDict{K,V}) where {K,V}
t.ndel > 0 && rehash!(t)
length(t.keys) < 1 && return nothing
return (Pair(t.keys[1], t.vals[1]), 2)
Copy link
Copy Markdown
Member

@timholy timholy Jun 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know you're just copying what was already there, but I wonder about switching to first and similarly checkbounds(Bool, t.keys, i) for the i-generic one; those are more precisely aligned to what's actually being tested. It's the same thing for Vector, of course. Up to you, I'd merge this without that change.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather minimize the diff in this PR to focus on the specifics that changed the behavior.

@KristofferC
Copy link
Copy Markdown
Collaborator Author

Sad to see more rather than fewer @inbounds annotations but the performance gain is compelling.

Most (pretty much all) perf comes from the type of the Pair but there is already a lot of inbounds in here that asserts the same things and Base uses it as well.

@KristofferC KristofferC merged commit 6af78d8 into JuliaCollections:master Jun 1, 2026
14 checks passed
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.

2 participants