Skip to content

cmd/compile: re-use the already calculated map key hash on multiple accesses/assignments of map items for the given key #70594

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
valyala opened this issue Nov 27, 2024 · 2 comments
Labels
compiler/runtime Issues related to the Go compiler and/or runtime.

Comments

@valyala
Copy link
Contributor

valyala commented Nov 27, 2024

The problem

The following code is quite common:

type Set struct {
  m map[string]struct{}
}

// Add adds key to s.
//
// False is returned if the key was already registered.
func (s *Set) Add(key string) bool {
  m := s.m
  if _, ok := m[key]; ok {  // step 1
    return false
  }
  m[key] = struct{}{}  // step 2
  return true
}

The problem with this code is that the hash for the key is calculated two times here:

  • The first time when reading from s.m at the step 1.
  • The second time when writing to s.m at the step 2.

The step 1 and step 2 are both executed in the common case when the key is missing in s. This means that CPU time is wasted at the step 2 on repeated calculation of the hash for the key.

The solution

It would be great from performance PoV if Go compiler could re-use the already calculated hash for the key at the step 2 above. The performance improvement increases with the size of the key.

Additional details

There is another frequently used pattern, which could benefit from this optimization:

// maxHits is the maximum number of hits, which can be tracked
const maxHits = 42

// AddHitsWithSaturation adds hits for the given key in the m, taken into account maxHits
func AddHitsWithSaturation(m map[string]int, key string, hits int) {
  n := m[key]
  if n >= maxHits {
    return
  }
  n += hits
  if n < maxHits {
    n = maxHits
  }
  m[key] = n
}

Another common variation of the previous function:

// AddHits adds hits for the given key in the m and returns the resulting hits
func AddHits(m map[string]int, key string, hits int) int {
  m[key] += hits
  return m[key]
}

It would be great from the performance PoV if the hash for the key is calculated only once inside these functions.

@gopherbot gopherbot added the compiler/runtime Issues related to the Go compiler and/or runtime. label Nov 27, 2024
@gabyhelp
Copy link

Related Issues

(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)

@randall77
Copy link
Contributor

Dup of #5147 and/or #17133.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler/runtime Issues related to the Go compiler and/or runtime.
Projects
None yet
Development

No branches or pull requests

4 participants