Remove path caching.

The path cache was originally a moderate benefit, but over time a couple of things have conspired against it:

- Only paths with BlockedByActor.None are cached. Originally all paths regardless of blocking were cached but this was deemed unacceptable due to potentially returning outdated paths as actors move about. Paths with BlockedByActor.None are only invalidated if terrain conditions change, which are rarer.
- Move will try and find a path 4 times, trying with a different BlockedByActor check each time. BlockedByActor.None is the last check and only reached if the other searches fail. This is a rare scenario.

Overall, this means the hit rate for the cache is almost non-existent. Given the constraints on path validity it seems unlikely that the hit rate could be improved significantly, therefore it seems reasonable to remove the cache entirely to remove the overhead of cache management.
This commit is contained in:
RoosterDragon
2021-11-28 18:24:27 +00:00
committed by reaperrr
parent 31bd32e7ef
commit 137d384304
4 changed files with 1 additions and 186 deletions

View File

@@ -1,20 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2021 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version. For more
* information, see COPYING.
*/
#endregion
namespace OpenRA
{
public interface ICacheStorage<T>
{
void Remove(string key);
void Store(string key, T data);
T Retrieve(string key);
}
}

View File

@@ -1,74 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2021 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version. For more
* information, see COPYING.
*/
#endregion
using System.Collections.Generic;
using System.Linq;
namespace OpenRA.Mods.Common.Pathfinder
{
public class PathCacheStorage : ICacheStorage<List<CPos>>
{
class CachedPath
{
public List<CPos> Result;
public int Tick;
}
const int MaxPathAge = 50;
readonly World world;
Dictionary<string, CachedPath> cachedPaths = new Dictionary<string, CachedPath>(100);
public PathCacheStorage(World world)
{
this.world = world;
}
public void Remove(string key)
{
cachedPaths.Remove(key);
}
public void Store(string key, List<CPos> data)
{
// Eventually clean up the cachedPaths dictionary
if (cachedPaths.Count >= 100)
foreach (var cachedPath in cachedPaths.Where(p => IsExpired(p.Value)).ToList())
cachedPaths.Remove(cachedPath.Key);
cachedPaths.Add(key, new CachedPath
{
Tick = world.WorldTick,
Result = data
});
}
public List<CPos> Retrieve(string key)
{
if (cachedPaths.TryGetValue(key, out var cached))
{
if (IsExpired(cached))
{
cachedPaths.Remove(key);
return null;
}
return cached.Result;
}
return null;
}
bool IsExpired(CachedPath path)
{
return world.WorldTick - path.Tick > MaxPathAge;
}
}
}

View File

@@ -1,91 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2021 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version. For more
* information, see COPYING.
*/
#endregion
using System.Collections.Generic;
using OpenRA.Mods.Common.Traits;
using OpenRA.Support;
using OpenRA.Traits;
namespace OpenRA.Mods.Common.Pathfinder
{
/// <summary>
/// A decorator used to cache FindUnitPath and FindUnitPathToRange (Decorator design pattern)
/// </summary>
public class PathFinderUnitPathCacheDecorator : IPathFinder
{
readonly IPathFinder pathFinder;
readonly ICacheStorage<List<CPos>> cacheStorage;
public PathFinderUnitPathCacheDecorator(IPathFinder pathFinder, ICacheStorage<List<CPos>> cacheStorage)
{
this.pathFinder = pathFinder;
this.cacheStorage = cacheStorage;
}
public List<CPos> FindUnitPath(CPos source, CPos target, Actor self, Actor ignoreActor, BlockedByActor check)
{
using (new PerfSample("Pathfinder"))
{
var key = "FindUnitPath" + self.ActorID + source.X + source.Y + target.X + target.Y;
// Only cache path when transient actors are ignored, otherwise there is no guarantee that the path
// is still valid at the next check.
if (check == BlockedByActor.None)
{
var cachedPath = cacheStorage.Retrieve(key);
if (cachedPath != null)
return cachedPath;
}
var pb = pathFinder.FindUnitPath(source, target, self, ignoreActor, check);
if (check == BlockedByActor.None)
cacheStorage.Store(key, pb);
return pb;
}
}
public List<CPos> FindUnitPathToRange(CPos source, SubCell srcSub, WPos target, WDist range, Actor self, BlockedByActor check)
{
using (new PerfSample("Pathfinder"))
{
var key = "FindUnitPathToRange" + self.ActorID + source.X + source.Y + target.X + target.Y;
if (check == BlockedByActor.None)
{
var cachedPath = cacheStorage.Retrieve(key);
if (cachedPath != null)
return cachedPath;
}
var pb = pathFinder.FindUnitPathToRange(source, srcSub, target, range, self, check);
if (check == BlockedByActor.None)
cacheStorage.Store(key, pb);
return pb;
}
}
public List<CPos> FindPath(IPathSearch search)
{
using (new PerfSample("Pathfinder"))
return pathFinder.FindPath(search);
}
public List<CPos> FindBidiPath(IPathSearch fromSrc, IPathSearch fromDest)
{
using (new PerfSample("Pathfinder"))
return pathFinder.FindBidiPath(fromSrc, fromDest);
}
}
}

View File

@@ -22,7 +22,7 @@ namespace OpenRA.Mods.Common.Traits
{
public override object Create(ActorInitializer init)
{
return new PathFinderUnitPathCacheDecorator(new PathFinder(init.World), new PathCacheStorage(init.World));
return new PathFinder(init.World);
}
}