Skip to content

Commit 4aad09c

Browse files
authored
Opti: disk cache allocs (#6523)
1 parent c80dc48 commit 4aad09c

File tree

5 files changed

+113
-24
lines changed

5 files changed

+113
-24
lines changed

Explorer/Assets/DCL/Infrastructure/ECS/StreamableLoading/Cache/Disk/CleanUp/LRUDiskCleanUp.cs

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,14 @@ namespace ECS.StreamableLoading.Cache.Disk.CleanUp
99
{
1010
public class LRUDiskCleanUp : IDiskCleanUp
1111
{
12+
private static readonly EnumerationOptions options =
13+
new EnumerationOptions
14+
{
15+
IgnoreInaccessible = true,
16+
RecurseSubdirectories = false,
17+
AttributesToSkip = FileAttributes.Hidden | FileAttributes.System
18+
};
19+
1220
private readonly CacheDirectory cacheDirectory;
1321
private readonly FilesLock filesLock;
1422
private readonly long maxCacheSizeBytes;
@@ -17,6 +25,7 @@ public class LRUDiskCleanUp : IDiskCleanUp
1725
/// Use file system enumerable because default DirectoryInfo API allocates a lot of memory per each call
1826
/// </summary>
1927
private readonly FileSystemEnumerable<CacheFileInfo> files;
28+
private readonly FileSystemEnumerable<long> fileSizes;
2029

2130
public LRUDiskCleanUp(CacheDirectory cacheDirectory, FilesLock filesLock, long maxCacheSizeBytes = 1024 * 1024 * 1024) //1GB
2231
{
@@ -27,25 +36,31 @@ public LRUDiskCleanUp(CacheDirectory cacheDirectory, FilesLock filesLock, long m
2736
files = new FileSystemEnumerable<CacheFileInfo>(
2837
cacheDirectory.Path,
2938
(ref FileSystemEntry entry) => CacheFileInfo.FromFileSystemEntry(ref entry),
30-
new EnumerationOptions
31-
{
32-
IgnoreInaccessible = true,
33-
RecurseSubdirectories = false,
34-
AttributesToSkip = FileAttributes.Hidden | FileAttributes.System
35-
}
39+
options
3640
)
3741
{
38-
ShouldIncludePredicate = (ref FileSystemEntry entry) => entry.IsDirectory == false,
42+
ShouldIncludePredicate = Predicate,
3943
};
44+
45+
fileSizes = new FileSystemEnumerable<long>(
46+
cacheDirectory.Path,
47+
(ref FileSystemEntry entry) => entry.Length,
48+
options
49+
)
50+
{
51+
ShouldIncludePredicate = Predicate,
52+
};
53+
54+
static bool Predicate(ref FileSystemEntry entry) => entry.IsDirectory == false;
4055
}
4156

4257
public void CleanUpIfNeeded()
4358
{
44-
using var _ = CachedFiles(out var cachedFiles);
45-
long directorySize = DirectorySize(cachedFiles);
59+
long directorySize = DirectorySize(fileSizes);
4660

4761
if (directorySize > maxCacheSizeBytes)
4862
{
63+
using var _ = CachedFiles(out var cachedFiles);
4964
cachedFiles.Sort(LRUComparer.INSTANCE);
5065

5166
for (int i = 0; i < cachedFiles.Count; i++)
@@ -68,10 +83,10 @@ public void NotifyUsed(string fileName)
6883
File.SetLastAccessTimeUtc(Path.Combine(cacheDirectory.Path, fileName), DateTime.UtcNow);
6984
}
7085

71-
private static long DirectorySize(IReadOnlyCollection<CacheFileInfo> files)
86+
private static long DirectorySize(FileSystemEnumerable<long> fileSizes)
7287
{
7388
long size = 0;
74-
foreach (CacheFileInfo fi in files) size += fi.Size;
89+
foreach (long fi in fileSizes) size += fi;
7590
return size;
7691
}
7792

Explorer/Assets/DCL/Infrastructure/ECS/StreamableLoading/Cache/Disk/Playgrounds/DiskCachePlayground.cs

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,33 @@ public class DiskCachePlayground : MonoBehaviour
1212
{
1313
[SerializeField] private string cacheDirectory = string.Empty;
1414
[SerializeField] private string testFile = string.Empty;
15+
[SerializeField] private bool useCleanUp = true;
16+
1517

1618
private void Start()
1719
{
1820
StartAsync().Forget();
1921
}
22+
23+
private void Update()
24+
{
25+
CleanUp();
26+
}
2027

21-
private IDiskCache NewDiskCache() =>
22-
new DiskCache(CacheDirectory.New(cacheDirectory), new FilesLock(), IDiskCleanUp.None.INSTANCE);
28+
private IDiskCache NewDiskCache(out IDiskCleanUp cleanUp)
29+
{
30+
var directory = CacheDirectory.New(cacheDirectory);
31+
var filesLock = new FilesLock();
32+
cleanUp = useCleanUp ? new LRUDiskCleanUp(directory, filesLock) : IDiskCleanUp.None.INSTANCE;
33+
return new DiskCache(directory, filesLock, cleanUp);
34+
}
2335

2436
private async UniTaskVoid StartAsync()
2537
{
2638
byte[] testData = await File.ReadAllBytesAsync(testFile, destroyCancellationToken)!;
2739
string testExtension = Path.GetExtension(testFile);
2840

29-
IDiskCache diskCache = NewDiskCache();
41+
IDiskCache diskCache = NewDiskCache(out _);
3042
using HashKey hashKey = HashKey.FromString(testFile);
3143

3244
using SingleMemoryIterator iterator = new SingleMemoryIterator(testData);
@@ -43,10 +55,17 @@ private async UniTaskVoid StartAsync()
4355
[ContextMenu(nameof(RemoveAsync))]
4456
public async UniTaskVoid RemoveAsync()
4557
{
46-
IDiskCache diskCache = NewDiskCache();
58+
IDiskCache diskCache = NewDiskCache(out _);
4759
using HashKey hashKey = HashKey.FromString(testFile);
4860
var result = await diskCache.RemoveAsync(hashKey, Path.GetExtension(testFile), destroyCancellationToken);
4961
print($"Remove result: success {result.Success} and error {result.Error?.Message}");
5062
}
63+
64+
[ContextMenu(nameof(CleanUp))]
65+
public void CleanUp()
66+
{
67+
var _ = NewDiskCache(out var cache);
68+
cache.CleanUpIfNeeded();
69+
}
5170
}
5271
}

Explorer/Assets/DCL/Infrastructure/ECS/StreamableLoading/Cache/Disk/Playgrounds/DiskCachePlayground.unity

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -248,14 +248,14 @@ MonoBehaviour:
248248
m_ScreenCoordScaleBias: {x: 0, y: 0, z: 0, w: 0}
249249
m_RequiresDepthTexture: 0
250250
m_RequiresColorTexture: 0
251-
m_Version: 2
252251
m_TaaSettings:
253252
m_Quality: 3
254253
m_FrameInfluence: 0.1
255254
m_JitterScale: 1
256255
m_MipBias: 0
257256
m_VarianceClampScale: 0.9
258257
m_ContrastAdaptiveSharpening: 0
258+
m_Version: 2
259259
--- !u!1 &672635447
260260
GameObject:
261261
m_ObjectHideFlags: 0
@@ -300,7 +300,7 @@ MonoBehaviour:
300300
m_Script: {fileID: 11500000, guid: 1aafb2f1e4aa48c6a63ccc21dc766405, type: 3}
301301
m_Name:
302302
m_EditorClassIdentifier:
303-
cacheDirectory: Assets/DCL/Caches/Playgrounds/CacheTest
303+
cacheDirectory: /Users/nickkhalow/Library/Application Support/Decentraland/Explorer/DiskCacheV3
304304
testFile: Assets/DCL/MapRenderer/MapLayers/Atlas/SatelliteAtlasFallbackImages/0,0.jpg
305305
--- !u!1 &937544251
306306
GameObject:
@@ -328,14 +328,14 @@ Light:
328328
m_PrefabAsset: {fileID: 0}
329329
m_GameObject: {fileID: 937544251}
330330
m_Enabled: 1
331-
serializedVersion: 11
331+
serializedVersion: 12
332332
m_Type: 1
333333
m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1}
334334
m_Intensity: 1
335335
m_Range: 10
336336
m_SpotAngle: 30
337337
m_InnerSpotAngle: 21.80208
338-
m_CookieSize: 10
338+
m_CookieSize2D: {x: 10, y: 10}
339339
m_Shadows:
340340
m_Type: 2
341341
m_Resolution: -1
@@ -412,17 +412,23 @@ MonoBehaviour:
412412
m_Script: {fileID: 11500000, guid: 474bcb49853aa07438625e644c072ee6, type: 3}
413413
m_Name:
414414
m_EditorClassIdentifier:
415-
m_Version: 3
416415
m_UsePipelineSettings: 1
417416
m_AdditionalLightsShadowResolutionTier: 2
418-
m_LightLayerMask: 1
419-
m_RenderingLayers: 1
420417
m_CustomShadowLayers: 0
421-
m_ShadowLayerMask: 1
422-
m_ShadowRenderingLayers: 1
423418
m_LightCookieSize: {x: 1, y: 1}
424419
m_LightCookieOffset: {x: 0, y: 0}
425420
m_SoftShadowQuality: 0
421+
m_RenderingLayersMask:
422+
serializedVersion: 0
423+
m_Bits: 1
424+
m_ShadowRenderingLayersMask:
425+
serializedVersion: 0
426+
m_Bits: 1
427+
m_Version: 4
428+
m_LightLayerMask: 1
429+
m_ShadowLayerMask: 1
430+
m_RenderingLayers: 1
431+
m_ShadowRenderingLayers: 1
426432
--- !u!1660057539 &9223372036854775807
427433
SceneRoots:
428434
m_ObjectHideFlags: 0
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
using DCL.Diagnostics;
2+
using DCL.Optimization.PerformanceBudgeting;
3+
using ECS.StreamableLoading.Common.Components;
4+
using NSubstitute;
5+
using NUnit.Framework;
6+
using System;
7+
using System.Collections.Generic;
8+
using System.Threading;
9+
using UnityEngine;
10+
using Unity.Profiling;
11+
using Unity.PerformanceTesting;
12+
using ECS.StreamableLoading.Cache.Disk;
13+
using ECS.StreamableLoading.Cache.Disk.CleanUp;
14+
using ECS.StreamableLoading.Cache.Disk.Lock;
15+
16+
namespace DCL.Tests.PlayMode.PerformanceTests
17+
{
18+
public class LRUCacheCleanUpPerformanceTest
19+
{
20+
private LRUDiskCleanUp cache;
21+
22+
[SetUp]
23+
public void Setup()
24+
{
25+
CacheDirectory directory = CacheDirectory.NewDefault();
26+
FilesLock filesLock = new FilesLock();
27+
cache = new LRUDiskCleanUp(directory, filesLock);
28+
}
29+
30+
[Test]
31+
[Performance]
32+
public void CleanUpIfNeeded()
33+
{
34+
ProfilerRecorder gcAlloc =
35+
ProfilerRecorder.StartNew(ProfilerCategory.Memory, "GC.Alloc");
36+
37+
Measure
38+
.Method(cache.CleanUpIfNeeded)
39+
.WarmupCount(10)
40+
.MeasurementCount(10)
41+
.GC()
42+
.Run();
43+
44+
Debug.Log($"GC Alloc: {gcAlloc.LastValue} bytes");
45+
}
46+
}
47+
}

Explorer/Assets/DCL/Tests/PlayMode/PerformanceTests/LRUCacheCleanUpPerformanceTest.cs.meta

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)