Skip to content

adding GetChild benchmark - #5239

Merged
Aaronontheweb merged 4 commits into
akkadotnet:devfrom
Aaronontheweb:perf/GetChild-performance
Sep 1, 2021
Merged

Aaronontheweb merged 4 commits into
akkadotnet:devfrom
Aaronontheweb:perf/GetChild-performance

Conversation

@Aaronontheweb

Copy link
Copy Markdown
Member

Working on cleaning up the read-side resolve pipeline inside Akka.Cluster.Sharding and Akka.Remote. This seemed like a good place to start.

@to11mtm

to11mtm commented Aug 31, 2021

Copy link
Copy Markdown
Member

How many layers deep do the children get here? Is there a way we can somehow measure difference in perf based on how deep the path is?

@Aaronontheweb

Copy link
Copy Markdown
Member Author

Data so far:

BenchmarkDotNet=v0.13.1, OS=Windows 10.0.19041.1165 (2004/May2020Update/20H1)
AMD Ryzen 7 1700, 1 CPU, 16 logical and 8 physical cores
.NET SDK=5.0.302
  [Host]     : .NET Core 3.1.17 (CoreCLR 4.700.21.31506, CoreFX 4.700.21.31502), X64 RyuJIT
  DefaultJob : .NET Core 3.1.17 (CoreCLR 4.700.21.31506, CoreFX 4.700.21.31502), X64 RyuJIT

Method Mean Error StdDev Allocated
ResolveChild 62.07 ns 0.971 ns 0.811 ns -

@Aaronontheweb

Copy link
Copy Markdown
Member Author

How many layers deep do the children get here? Is there a way we can somehow measure difference in perf based on how deep the path is?

I can add a method to traverse the graph a few layers deeper, yes

@Aaronontheweb

Copy link
Copy Markdown
Member Author

Ideally, this is the path we want to optimize read-side in Akka.Remote:

internal IInternalActorRef ResolveActorRef(IInternalActorRef actorRef, IReadOnlyCollection<string> pathElements)
{
if (pathElements.Count == 0)
{
_log.Debug("Resolve of empty path sequence fails (per definition)");
return _deadLetters;
}
var child = actorRef.GetChild(pathElements);
if (child.IsNobody())
{
_log.Debug("Resolve of path sequence [/{0}] failed", ActorPath.FormatPathElements(pathElements));
return new EmptyLocalActorRef(_system.Provider, actorRef.Path / pathElements, _eventStream);
}
return (IInternalActorRef)child;
}

It gets called twice per-read and doesn't appear to be cached at all.

@Aaronontheweb

Copy link
Copy Markdown
Member Author

Ah, I take that back - looks like we do cache inside RARP here:

/// <summary>
        /// Resolves a deserialized path into an <see cref="IActorRef"/>
        /// </summary>
        /// <param name="path">The path of the actor we are attempting to resolve.</param>
        /// <returns>A local <see cref="IActorRef"/> if it exists, <see cref="ActorRefs.Nobody"/> otherwise.</returns>
        public IActorRef ResolveActorRef(string path)
        {
            if (IgnoreActorRef.IsIgnoreRefPath(path))
                return IgnoreRef;

            // using thread local LRU cache, which will call InternalResolveActorRef
            // if the value is not cached
            if (_actorRefResolveThreadLocalCache == null)
            {
                return InternalResolveActorRef(path); // cache not initialized yet
            }
            return _actorRefResolveThreadLocalCache.Cache.GetOrCompute(path);
        }

@Aaronontheweb

Copy link
Copy Markdown
Member Author

Actually, funnily enough no - that doesn't get used at all inside the AkkaPduCodec

@Aaronontheweb

Copy link
Copy Markdown
Member Author

Done, expanded the benchmark to include some more scenarios.

BenchmarkDotNet=v0.13.1, OS=Windows 10.0.19041.1165 (2004/May2020Update/20H1)
AMD Ryzen 7 1700, 1 CPU, 16 logical and 8 physical cores
.NET SDK=5.0.302
  [Host]     : .NET Core 3.1.17 (CoreCLR 4.700.21.31506, CoreFX 4.700.21.31502), X64 RyuJIT
  DefaultJob : .NET Core 3.1.17 (CoreCLR 4.700.21.31506, CoreFX 4.700.21.31502), X64 RyuJIT

Method Mean Error StdDev Gen 0 Allocated
ResolveChild 64.69 ns 0.145 ns 0.129 ns - -
Resolve3DeepChildRepointableActorRef 652.15 ns 9.237 ns 8.641 ns 0.0839 352 B
Resolve3DeepChildLocalActorRef 311.74 ns 4.924 ns 4.605 ns 0.0629 264 B

@Aaronontheweb
Aaronontheweb enabled auto-merge (squash) September 1, 2021 19:30
@Aaronontheweb
Aaronontheweb merged commit 682ca13 into akkadotnet:dev Sep 1, 2021
@Aaronontheweb
Aaronontheweb deleted the perf/GetChild-performance branch September 1, 2021 19:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants