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

Closed
@valyala

Description

@valyala

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    compiler/runtimeIssues related to the Go compiler and/or runtime.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions