Skip to content

Hoist access to volatile variables out of loop in ConcurrentDictionary #34198

Closed

Description

@kunalspathak

There are few places in ConcurrentDictionary where we call AcquireAllLocks but still access the volatile variables like _tables._countPerLock, _tables._buckets and _tables._locks inside loop.

E.g. CopyTo, GetCountInternal, CopyTo, GetKeys and GetValues.

Is there a reason for doing it or can we cache those variables outside the loop and use it inside? Currently, for ARM64, JIT generates expensive memory barrier instructions for accessing volatile variables. With volatile variables getting accessed inside the loop, we are executing these instructions inside the loop. Caching them would optimize the performance of these APIs on ARM64.

Below is an example of machine code we generate before/after caching the volatile variable outside loop for GetCountInternal method.
Before:
before

After: I made following change and see this generated code. This gave approx. 30% win in Dictionary.Count benchmark.

private int GetCountInternal()
{
    int count = 0;
    int[] countPerLocks = _tables._countPerLock;

    // Compute the count, we allow overflow
    for (int i = 0; i < countPerLocks.Length; i++)
    {
        count += countPerLocks[i];
    }

    return count;
}

after

Activity

  1. kunalspathak commented on Mar 27, 2020

    @kunalspathak
    ContributorAuthor

    // @danmosemsft , @BruceForstall

  2. danmoseley commented on Mar 27, 2020

    @danmoseley
    Contributor
  3. stephentoub commented on Mar 27, 2020

    @stephentoub
    Member

    I'd need to look in more depth to be sure, but if memory serves, as long as all the locks are held, it should be fine to do the reads once (even as non-volatile).

  4. kunalspathak commented on Mar 27, 2020

    @kunalspathak
    ContributorAuthor

    Thanks @stephentoub . I will send out the PR to address this. Let me know if your findings don't allow it.

  5. removed
    untriagedNew issue has not been triaged by the area owner
    on Jul 7, 2020
  6. ghost locked as resolved and limited conversation to collaborators on Dec 10, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions