chore: Removes benchmarks. (#985)
This commit is contained in:
parent
fdcd6c80a8
commit
4d1ee21568
24 changed files with 0 additions and 3977 deletions
|
|
@ -10,8 +10,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Server.Tests", "Projects\Se
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UOContent.Tests", "Projects\UOContent.Tests\UOContent.Tests.csproj", "{3C4797F9-603E-44EF-8E8C-9275CC9EA74B}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Benchmarks", "Projects\Benchmarks\Benchmarks.csproj", "{38B7E4A1-FDDD-486C-98EE-BA7B13712528}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Analyze|x64 = Analyze|x64
|
||||
|
|
@ -43,12 +41,6 @@ Global
|
|||
{3C4797F9-603E-44EF-8E8C-9275CC9EA74B}.Debug|x64.Build.0 = Debug|x64
|
||||
{3C4797F9-603E-44EF-8E8C-9275CC9EA74B}.Release|x64.ActiveCfg = Release|x64
|
||||
{3C4797F9-603E-44EF-8E8C-9275CC9EA74B}.Release|x64.Build.0 = Release|x64
|
||||
{38B7E4A1-FDDD-486C-98EE-BA7B13712528}.Analyze|x64.ActiveCfg = Release|x64
|
||||
{38B7E4A1-FDDD-486C-98EE-BA7B13712528}.Analyze|x64.Build.0 = Release|x64
|
||||
{38B7E4A1-FDDD-486C-98EE-BA7B13712528}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{38B7E4A1-FDDD-486C-98EE-BA7B13712528}.Debug|x64.Build.0 = Debug|x64
|
||||
{38B7E4A1-FDDD-486C-98EE-BA7B13712528}.Release|x64.ActiveCfg = Release|x64
|
||||
{38B7E4A1-FDDD-486C-98EE-BA7B13712528}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Platforms>x64</Platforms>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<LangVersion>9</LangVersion>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<SkipLocalsInitiAttribute>true</SkipLocalsInitiAttribute>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BenchmarkDotNet" Version="0.13.1" />
|
||||
<PackageReference Include="NetFabric.Hyperlinq" Version="3.0.0-beta48" />
|
||||
<PackageReference Include="StructLinq" Version="0.27.1" />
|
||||
<ProjectReference Include="..\Server\Server.csproj" />
|
||||
<ProjectReference Include="..\UOContent\UOContent.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
@ -1,130 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using Server.Collections;
|
||||
|
||||
namespace Benchmarks
|
||||
{
|
||||
[MemoryDiagnoser]
|
||||
[SimpleJob(RuntimeMoniker.Net60)]
|
||||
public class BenchmarkOrderedHashSet
|
||||
{
|
||||
private readonly string[] _iterations = new string[16];
|
||||
|
||||
[IterationSetup]
|
||||
public void IterationSetup()
|
||||
{
|
||||
for (var i = 0; i < _iterations.Length; i++)
|
||||
{
|
||||
_iterations[i] = i.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public int UsingList()
|
||||
{
|
||||
var list = new List<string>();
|
||||
for (int i = 0; i < _iterations.Length / 2; i++)
|
||||
{
|
||||
AddIfNotPresent(list, _iterations[i]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < _iterations.Length; i++)
|
||||
{
|
||||
AddIfNotPresent(list, _iterations[i]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
{
|
||||
list[i].ToString();
|
||||
}
|
||||
|
||||
return list.Count;
|
||||
}
|
||||
|
||||
private static int AddIfNotPresent<T>(List<T> list, T item)
|
||||
{
|
||||
var index = list.IndexOf(item);
|
||||
if (index > -1)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
list.Add(item);
|
||||
return list.Count - 1;
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public int UsingOrderedHashSet()
|
||||
{
|
||||
var ordered = new OrderedHashSet<string>();
|
||||
for (int i = 0; i < _iterations.Length / 2; i++)
|
||||
{
|
||||
ordered.GetOrAdd(_iterations[i]).ToString();
|
||||
}
|
||||
|
||||
for (int i = 0; i < _iterations.Length; i++)
|
||||
{
|
||||
ordered.GetOrAdd(_iterations[i]).ToString();
|
||||
}
|
||||
|
||||
foreach (var str in ordered)
|
||||
{
|
||||
str.ToString();
|
||||
}
|
||||
|
||||
return ordered.Count;
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public int UsingPooledOrderedHashSet()
|
||||
{
|
||||
var ordered = new PooledOrderedHashSet<string>();
|
||||
for (int i = 0; i < _iterations.Length / 2; i++)
|
||||
{
|
||||
ordered.GetOrAdd(_iterations[i]).ToString();
|
||||
}
|
||||
|
||||
for (int i = 0; i < _iterations.Length; i++)
|
||||
{
|
||||
ordered.GetOrAdd(_iterations[i]).ToString();
|
||||
}
|
||||
|
||||
foreach (var str in ordered)
|
||||
{
|
||||
str.ToString();
|
||||
}
|
||||
|
||||
return ordered.Count;
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public int UsingHashSet()
|
||||
{
|
||||
var hashSet = new HashSet<(string, int)>(new OrderedStringComparer());
|
||||
for (int i = 0; i < _iterations.Length / 2; i++)
|
||||
{
|
||||
hashSet.Add((_iterations[i], i));
|
||||
}
|
||||
|
||||
for (int i = 0; i < _iterations.Length; i++)
|
||||
{
|
||||
hashSet.Add((_iterations[i], i));
|
||||
}
|
||||
|
||||
foreach (var str in hashSet)
|
||||
{
|
||||
str.ToString();
|
||||
}
|
||||
|
||||
return hashSet.Count;
|
||||
}
|
||||
|
||||
private class OrderedStringComparer : EqualityComparer<(string, int)>
|
||||
{
|
||||
public override bool Equals((string, int) x, (string, int) y) => x.Item1.Equals(y.Item1, System.StringComparison.Ordinal);
|
||||
|
||||
public override int GetHashCode((string, int) obj) => obj.Item1.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,95 +0,0 @@
|
|||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using Server.Buffers;
|
||||
using Server.Collections;
|
||||
|
||||
namespace Benchmarks
|
||||
{
|
||||
[MemoryDiagnoser]
|
||||
[SimpleJob(RuntimeMoniker.Net60)]
|
||||
public class BenchmarkPooledRefQueue
|
||||
{
|
||||
[GlobalSetup]
|
||||
public void Setup()
|
||||
{
|
||||
// Allocate
|
||||
var arrays = new long[16][];
|
||||
for (var i = 0; i < 16; i++)
|
||||
{
|
||||
arrays[i] = ArrayPool<long>.Shared.Rent(64);
|
||||
}
|
||||
|
||||
var stArrays = new long[16][];
|
||||
for (var i = 0; i < 16; i++)
|
||||
{
|
||||
stArrays[i] = STArrayPool<long>.Shared.Rent(64);
|
||||
}
|
||||
|
||||
for (var i = 0; i < 16; i++)
|
||||
{
|
||||
ArrayPool<long>.Shared.Return(arrays[i]);
|
||||
}
|
||||
|
||||
for (var i = 0; i < 16; i++)
|
||||
{
|
||||
STArrayPool<long>.Shared.Return(stArrays[i]);
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void UseQueue()
|
||||
{
|
||||
for (var i = 0; i < 8; i++)
|
||||
{
|
||||
var queue = new Queue<long>();
|
||||
for (var j = 0; j < 32; j++)
|
||||
{
|
||||
queue.Enqueue(j);
|
||||
}
|
||||
|
||||
for (var j = 0; j < 32; j++)
|
||||
{
|
||||
var num = queue.Dequeue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void UsePooledRefQueue()
|
||||
{
|
||||
for (var i = 0; i < 8; i++)
|
||||
{
|
||||
using var queue = PooledRefQueue<long>.Create();
|
||||
for (var j = 0; j < 32; j++)
|
||||
{
|
||||
queue.Enqueue(j);
|
||||
}
|
||||
|
||||
for (var j = 0; j < 32; j++)
|
||||
{
|
||||
var num = queue.Dequeue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void UsePooledRefQueueMT()
|
||||
{
|
||||
for (var i = 0; i < 8; i++)
|
||||
{
|
||||
using var queue = PooledRefQueue<long>.CreateMT();
|
||||
for (var j = 0; j < 32; j++)
|
||||
{
|
||||
queue.Enqueue(j);
|
||||
}
|
||||
|
||||
for (var j = 0; j < 32; j++)
|
||||
{
|
||||
var num = queue.Dequeue();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using Server.Buffers;
|
||||
|
||||
namespace Benchmarks
|
||||
{
|
||||
[MemoryDiagnoser]
|
||||
[SimpleJob(RuntimeMoniker.Net60)]
|
||||
public class BenchmarkSTArray
|
||||
{
|
||||
private static long[][] arrays = new long[16][];
|
||||
private static long[][] stArrays = new long[16][];
|
||||
private static long[][] newArrays = new long[16][];
|
||||
private static Queue<long>[] newQueue = new Queue<long>[16];
|
||||
|
||||
[GlobalSetup]
|
||||
public void Setup()
|
||||
{
|
||||
// Allocate
|
||||
arrays = new long[16][];
|
||||
for (var i = 0; i < 16; i++)
|
||||
{
|
||||
arrays[i] = ArrayPool<long>.Shared.Rent(64);
|
||||
}
|
||||
|
||||
stArrays = new long[16][];
|
||||
for (var i = 0; i < 16; i++)
|
||||
{
|
||||
stArrays[i] = STArrayPool<long>.Shared.Rent(64);
|
||||
}
|
||||
|
||||
for (var i = 0; i < 16; i++)
|
||||
{
|
||||
ArrayPool<long>.Shared.Return(arrays[i]);
|
||||
}
|
||||
|
||||
for (var i = 0; i < 16; i++)
|
||||
{
|
||||
STArrayPool<long>.Shared.Return(stArrays[i]);
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void ArrayPool()
|
||||
{
|
||||
for (var i = 0; i < 8; i++)
|
||||
{
|
||||
arrays[i] = ArrayPool<long>.Shared.Rent(64);
|
||||
}
|
||||
|
||||
for (var i = 0; i < 8; i++)
|
||||
{
|
||||
ArrayPool<long>.Shared.Return(arrays[i], true);
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void STArrayPool()
|
||||
{
|
||||
for (var i = 0; i < 8; i++)
|
||||
{
|
||||
arrays[i] = STArrayPool<long>.Shared.Rent(64);
|
||||
}
|
||||
|
||||
for (var i = 0; i < 8; i++)
|
||||
{
|
||||
STArrayPool<long>.Shared.Return(arrays[i], true);
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void NewArray()
|
||||
{
|
||||
for (var i = 0; i < 8; i++)
|
||||
{
|
||||
newArrays[i] = new long[64];
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void NewQueue()
|
||||
{
|
||||
for (var i = 0; i < 8; i++)
|
||||
{
|
||||
newQueue[i] = new Queue<long>();
|
||||
newQueue[i].EnsureCapacity(64);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
using System;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using Serilog;
|
||||
using Serilog.Core;
|
||||
|
||||
namespace Benchmarks
|
||||
{
|
||||
[SimpleJob(RuntimeMoniker.Net60)]
|
||||
public class BenchmarkConsoleLogging
|
||||
{
|
||||
private const string text = "Sample message";
|
||||
|
||||
private Logger logger;
|
||||
private Logger asyncLogger;
|
||||
|
||||
[GlobalSetup]
|
||||
public void GlobalSetup()
|
||||
{
|
||||
logger = new LoggerConfiguration()
|
||||
.WriteTo.Console()
|
||||
.CreateLogger();
|
||||
|
||||
asyncLogger = new LoggerConfiguration()
|
||||
.WriteTo.Async(a => a.Console())
|
||||
.CreateLogger();
|
||||
}
|
||||
|
||||
[GlobalCleanup]
|
||||
public void GlobalCleanup()
|
||||
{
|
||||
logger = null;
|
||||
asyncLogger = null;
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void TestConsoleWriteLine()
|
||||
{
|
||||
for (int i = 0; i < 10000; i++)
|
||||
{
|
||||
Console.WriteLine(text);
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void TestSerilogConsoleSink()
|
||||
{
|
||||
for (int i = 0; i < 10000; i++)
|
||||
{
|
||||
logger.Information(text);
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void TestSerilogAsyncConsoleSink()
|
||||
{
|
||||
for (int i = 0; i < 10000; i++)
|
||||
{
|
||||
asyncLogger.Information(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,545 +0,0 @@
|
|||
using BenchmarkDotNet.Attributes;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using NetFabric.Hyperlinq;
|
||||
using Server;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using static NetFabric.Hyperlinq.ArrayExtensions;
|
||||
|
||||
namespace Benchmarks.EntitiesSelectors
|
||||
{
|
||||
[SimpleJob(RuntimeMoniker.Net60)]
|
||||
[MemoryDiagnoser]
|
||||
public class MapEntitiesSelectors
|
||||
{
|
||||
private static readonly Sector sector = new();
|
||||
private static readonly Point3D[] locations = { new Point3D(0, 0, 0), new Point3D(50, 50, 0) };
|
||||
|
||||
public static Rectangle2D[] BoundsArray() => new[]
|
||||
{
|
||||
new Rectangle2D(70, 70, 100, 100),
|
||||
new Rectangle2D(30, 30, 100, 100),
|
||||
new Rectangle2D(0, 0, 100, 100),
|
||||
};
|
||||
|
||||
[GlobalSetup]
|
||||
public static void Init()
|
||||
{
|
||||
for (int j = 0; j < locations.Length; j++)
|
||||
{
|
||||
Point3D loc = locations[j];
|
||||
|
||||
for (int i = 0; i < 500; ++i)
|
||||
{
|
||||
sector.BItems.Add(new BItem(loc));
|
||||
}
|
||||
|
||||
for (int i = 0; i < 25; ++i)
|
||||
{
|
||||
sector.Mobiles.Add(new Mobile(loc));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[ParamsSource(nameof(BoundsArray))]
|
||||
public Rectangle2D bounds;
|
||||
|
||||
[Benchmark(Baseline = true)]
|
||||
public IEntity SelectEntitiesFor()
|
||||
{
|
||||
IEntity toRet = null;
|
||||
for (int i = sector.Mobiles.Count - 1; i >= 0; --i)
|
||||
{
|
||||
Mobile mob = sector.Mobiles[i];
|
||||
if (mob is { Deleted: false } tMob && bounds.Contains(mob.Location))
|
||||
{
|
||||
toRet = tMob;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = sector.BItems.Count - 1; i >= 0; --i)
|
||||
{
|
||||
BItem item = sector.BItems[i];
|
||||
if (item is { Deleted: false, Parent: null } tItem && bounds.Contains(item.Location))
|
||||
{
|
||||
toRet = tItem;
|
||||
}
|
||||
}
|
||||
|
||||
return toRet;
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public IEntity SelectEntitiesNew()
|
||||
{
|
||||
IEntity toRet = null;
|
||||
foreach (IEntity e in SelectEntitiesNew(sector, bounds))
|
||||
{
|
||||
toRet = e;
|
||||
}
|
||||
|
||||
return toRet;
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public IEntity SelectEntitiesLinq()
|
||||
{
|
||||
IEntity toRet = null;
|
||||
foreach (IEntity e in SelectEntitiesLinq(sector, bounds))
|
||||
{
|
||||
toRet = e;
|
||||
}
|
||||
|
||||
return toRet;
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public IEntity SelectMobilesHyperLinq()
|
||||
{
|
||||
IEntity toRet = null;
|
||||
foreach (IEntity e in SelectEntitiesHyperlinq(sector, bounds))
|
||||
{
|
||||
toRet = e;
|
||||
}
|
||||
|
||||
return toRet;
|
||||
}
|
||||
|
||||
|
||||
public IEnumerable<IEntity> SelectEntitiesLinq(Sector s, Rectangle2D bounds)
|
||||
{
|
||||
return Enumerable.Empty<IEntity>()
|
||||
.Union(s.Mobiles.Where(o => o is { Deleted: false } && bounds.Contains(o.Location)))
|
||||
.Union(s.BItems.Where(o => o is { Deleted: false, Parent: null } && bounds.Contains(o.Location)));
|
||||
}
|
||||
|
||||
private readonly List<IEntity> entities = new(10);
|
||||
|
||||
public IEnumerable<IEntity> SelectEntitiesNew(Sector s, Rectangle2D bounds)
|
||||
{
|
||||
entities.Clear();
|
||||
entities.EnsureCapacity(s.Mobiles.Count + s.BItems.Count);
|
||||
|
||||
for (int i = s.Mobiles.Count - 1, j = s.BItems.Count - 1; i >= 0 || j >= 0; --i, --j)
|
||||
{
|
||||
if (j >= 0)
|
||||
{
|
||||
BItem BItem = s.BItems[j];
|
||||
if (BItem is { Deleted: false, Parent: null } && bounds.Contains(BItem.Location))
|
||||
{
|
||||
entities.Add(BItem);
|
||||
}
|
||||
}
|
||||
if (i >= 0)
|
||||
{
|
||||
Mobile mob = s.Mobiles[i];
|
||||
if (mob is { Deleted: false } && bounds.Contains(mob.Location))
|
||||
{
|
||||
entities.Add(mob);
|
||||
}
|
||||
}
|
||||
}
|
||||
return entities;
|
||||
}
|
||||
|
||||
public IEnumerable<IEntity> SelectEntitiesHyperlinq(Sector s, Rectangle2D bounds)
|
||||
{
|
||||
ArraySegmentWhereSelectEnumerable<Mobile, IEntity, MobileWhereHyper, SelectHyper<Mobile, IEntity>> mobiles =
|
||||
s.Mobiles.AsValueEnumerable().Where(new MobileWhereHyper(bounds)).Select<IEntity, SelectHyper<Mobile, IEntity>>();
|
||||
|
||||
ArraySegmentWhereSelectEnumerable<BItem, IEntity, BItemWhereHyper, SelectHyper<BItem, IEntity>> items =
|
||||
s.BItems.AsValueEnumerable().Where(new BItemWhereHyper(bounds)).Select<IEntity, SelectHyper<BItem, IEntity>>();
|
||||
|
||||
return mobiles.Concat(items);
|
||||
}
|
||||
}
|
||||
|
||||
public class BItem : IPoint3D, IEntity
|
||||
{
|
||||
public object Parent { get; set; } = null;
|
||||
|
||||
public bool Deleted { get; set; } = false;
|
||||
|
||||
public int Z { get; set; } = 1;
|
||||
|
||||
public int X { get; set; } = 1;
|
||||
|
||||
public int Y { get; set; } = 1;
|
||||
|
||||
public Serial Serial => throw new NotImplementedException();
|
||||
|
||||
public Point3D Location { get; }
|
||||
public Map Map { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
|
||||
public Region Region => throw new NotImplementedException();
|
||||
|
||||
public string Name { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
public int Hue { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
public Direction Direction { get => throw new System.NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
public DateTime Created { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
|
||||
public int TypeRef => throw new NotImplementedException();
|
||||
|
||||
Point3D IEntity.Location => Location;
|
||||
|
||||
Map IEntity.Map => throw new NotImplementedException();
|
||||
|
||||
int IPoint3D.Z => throw new NotImplementedException();
|
||||
|
||||
int IPoint2D.X => throw new NotImplementedException();
|
||||
|
||||
int IPoint2D.Y => throw new NotImplementedException();
|
||||
|
||||
DateTime ISerializable.Created { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
DateTime ISerializable.LastSerialized { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
long ISerializable.SavePosition { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
BufferWriter ISerializable.SaveBuffer { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
|
||||
int ISerializable.TypeRef => throw new NotImplementedException();
|
||||
|
||||
Serial ISerializable.Serial => throw new NotImplementedException();
|
||||
|
||||
bool ISerializable.Deleted => throw new NotImplementedException();
|
||||
|
||||
public BItem(Point3D location)
|
||||
{
|
||||
Location = location;
|
||||
}
|
||||
|
||||
public void Delete()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void ProcessDelta()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void OnStatsQuery(Server.Mobile m)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void InvalidateProperties()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public int CompareTo(object obj)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public int CompareTo(IEntity other)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void MoveToWorld(Point3D location, Map map)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool InRange(Point2D p, int range)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool InRange(Point3D p, int range)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void RemoveBItem(BItem BItem)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void BeforeSerialize()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Deserialize(IGenericReader reader)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Serialize(IGenericWriter writer)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void SetTypeRef(Type type)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
void IEntity.MoveToWorld(Point3D location, Map map)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
void IEntity.ProcessDelta()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
bool IEntity.InRange(Point2D p, int range)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
bool IEntity.InRange(Point3D p, int range)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
void ISerializable.BeforeSerialize()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
void ISerializable.Deserialize(IGenericReader reader)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
void ISerializable.Serialize(IGenericWriter writer)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
void ISerializable.Delete()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
void ISerializable.SetTypeRef(Type type)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void RemoveItem(Item item)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public class Mobile : IPoint3D, IEntity
|
||||
{
|
||||
public bool Deleted { get; set; } = false;
|
||||
|
||||
public int Z { get; set; } = 1;
|
||||
|
||||
public int X { get; set; } = 1;
|
||||
|
||||
public int Y { get; set; } = 1;
|
||||
|
||||
public Serial Serial => throw new NotImplementedException();
|
||||
|
||||
public Point3D Location { get; }
|
||||
public Map Map { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
|
||||
public Region Region => throw new NotImplementedException();
|
||||
|
||||
public string Name { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
public int Hue { get => throw new System.NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
public Direction Direction { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
public DateTime Created { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
|
||||
public int TypeRef => throw new NotImplementedException();
|
||||
|
||||
Point3D IEntity.Location => Location;
|
||||
|
||||
Map IEntity.Map => throw new NotImplementedException();
|
||||
|
||||
int IPoint3D.Z => throw new NotImplementedException();
|
||||
|
||||
int IPoint2D.X => throw new NotImplementedException();
|
||||
|
||||
int IPoint2D.Y => throw new NotImplementedException();
|
||||
|
||||
DateTime ISerializable.Created { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
DateTime ISerializable.LastSerialized { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
long ISerializable.SavePosition { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
BufferWriter ISerializable.SaveBuffer { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
|
||||
int ISerializable.TypeRef => throw new NotImplementedException();
|
||||
|
||||
Serial ISerializable.Serial => throw new NotImplementedException();
|
||||
|
||||
bool ISerializable.Deleted => throw new NotImplementedException();
|
||||
|
||||
public Mobile(Point3D location)
|
||||
{
|
||||
Location = location;
|
||||
}
|
||||
|
||||
public void Delete()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void ProcessDelta()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void OnStatsQuery(Server.Mobile m)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void InvalidateProperties()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public int CompareTo(object obj)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public int CompareTo(IEntity other)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void MoveToWorld(Point3D location, Map map)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool InRange(Point2D p, int range)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool InRange(Point3D p, int range)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void RemoveBItem(BItem BItem)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void BeforeSerialize()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Deserialize(IGenericReader reader)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Serialize(IGenericWriter writer)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void SetTypeRef(Type type)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
void IEntity.MoveToWorld(Point3D location, Map map)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
void IEntity.ProcessDelta()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
bool IEntity.InRange(Point2D p, int range)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
bool IEntity.InRange(Point3D p, int range)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
void ISerializable.BeforeSerialize()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
void ISerializable.Deserialize(IGenericReader reader)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
void ISerializable.Serialize(IGenericWriter writer)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
void ISerializable.Delete()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
void ISerializable.SetTypeRef(Type type)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void RemoveItem(Item item)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public class Sector
|
||||
{
|
||||
public List<BItem> BItems { get; set; } = new();
|
||||
public List<Mobile> Mobiles { get; set; } = new();
|
||||
}
|
||||
|
||||
public struct BItemWhereHyper : NetFabric.Hyperlinq.IFunction<BItem, bool>
|
||||
{
|
||||
private readonly Rectangle2D bounds;
|
||||
|
||||
public BItemWhereHyper(Rectangle2D bounds)
|
||||
{
|
||||
this.bounds = bounds;
|
||||
}
|
||||
|
||||
public bool Invoke(BItem element)
|
||||
{
|
||||
return element is { Deleted: false, Parent: null } && bounds.Contains(element.Location);
|
||||
}
|
||||
}
|
||||
|
||||
public struct MobileWhereHyper : NetFabric.Hyperlinq.IFunction<Mobile, bool>
|
||||
{
|
||||
private readonly Rectangle2D bounds;
|
||||
|
||||
public MobileWhereHyper(Rectangle2D bounds)
|
||||
{
|
||||
this.bounds = bounds;
|
||||
}
|
||||
|
||||
public bool Invoke(Mobile element)
|
||||
{
|
||||
return element is { Deleted: false } && bounds.Contains(element.Location);
|
||||
}
|
||||
}
|
||||
|
||||
public struct SelectHyper<TSource, TDest> : NetFabric.Hyperlinq.IFunction<TSource, TDest> where TSource : TDest
|
||||
{
|
||||
public TDest Invoke(TSource arg)
|
||||
{
|
||||
return arg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,403 +0,0 @@
|
|||
using BenchmarkDotNet.Attributes;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using NetFabric.Hyperlinq;
|
||||
using Server;
|
||||
using StructLinq;
|
||||
using StructLinq.Array;
|
||||
using StructLinq.List;
|
||||
using StructLinq.Select;
|
||||
using StructLinq.Where;
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using static NetFabric.Hyperlinq.ArrayExtensions;
|
||||
|
||||
namespace Benchmarks.ItemSelectors
|
||||
{
|
||||
[SimpleJob(RuntimeMoniker.Net60)]
|
||||
[MemoryDiagnoser]
|
||||
public class MapItemSelectors
|
||||
{
|
||||
private static readonly Sector sector = new();
|
||||
private static readonly Point3D[] locations = { new Point3D(0, 0, 0), new Point3D(50, 50, 0) };
|
||||
|
||||
public static Rectangle2D[] BoundsArray() => new[]
|
||||
{
|
||||
new Rectangle2D(70, 70, 100, 100),
|
||||
new Rectangle2D(30, 30, 100, 100),
|
||||
new Rectangle2D(0, 0, 100, 100),
|
||||
};
|
||||
|
||||
[GlobalSetup]
|
||||
public static void Init()
|
||||
{
|
||||
for (int j = 0; j < locations.Length; j++)
|
||||
{
|
||||
Point3D loc = locations[j];
|
||||
|
||||
for (int i = 0; i < 500; ++i)
|
||||
{
|
||||
sector.BItems.Add(new BItemDerived(loc));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[ParamsSource(nameof(BoundsArray))]
|
||||
public Rectangle2D bounds;
|
||||
|
||||
[Benchmark(Baseline = true)]
|
||||
public BItemDerived SelectBItemsFor()
|
||||
{
|
||||
BItemDerived toRet = null;
|
||||
for (int i = sector.BItems.Count - 1; i >= 0; --i)
|
||||
{
|
||||
BItem BItem = sector.BItems[i];
|
||||
if (BItem is BItemDerived { Deleted: false, Parent: null } tItem && bounds.Contains(BItem.Location))
|
||||
{
|
||||
toRet = tItem;
|
||||
}
|
||||
}
|
||||
|
||||
return toRet;
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public BItemDerived SelectBItemsNew()
|
||||
{
|
||||
BItemDerived toRet = null;
|
||||
foreach (BItemDerived i in SelectBItems<BItemDerived>(sector, bounds))
|
||||
{
|
||||
toRet = i;
|
||||
}
|
||||
|
||||
return toRet;
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public BItemDerived SelectBItemsLinq()
|
||||
{
|
||||
BItemDerived toRet = null;
|
||||
foreach (BItemDerived i in SelectBItemsLinq<BItemDerived>(sector, bounds))
|
||||
{
|
||||
toRet = i;
|
||||
}
|
||||
|
||||
return toRet;
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public BItemDerived SelectBItemsLinqStruct()
|
||||
{
|
||||
BItemDerived toRet = null;
|
||||
foreach (BItemDerived i in SelectBItemsLinqStruct<BItemDerived>(sector, bounds))
|
||||
{
|
||||
toRet = i;
|
||||
}
|
||||
|
||||
return toRet;
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public BItemDerived SelectBItemsLinqStructInterface()
|
||||
{
|
||||
BItemDerived toRet = null;
|
||||
IEnumerable<BItemDerived> enumerable = SelectBItemsLinqStruct<BItemDerived>(sector, bounds).ToEnumerable();
|
||||
|
||||
foreach (BItemDerived i in enumerable)
|
||||
{
|
||||
toRet = i;
|
||||
}
|
||||
|
||||
return toRet;
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public BItemDerived SelectBItemsHyperLinq()
|
||||
{
|
||||
BItemDerived toRet = null;
|
||||
foreach (BItemDerived i in SelectBItemsHyperlinq<BItemDerived>(sector, bounds))
|
||||
{
|
||||
toRet = i;
|
||||
}
|
||||
|
||||
return toRet;
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public BItemDerived SelectBItemsHyperLinqInterface()
|
||||
{
|
||||
BItemDerived toRet = null;
|
||||
IEnumerable<BItemDerived> enumerable = SelectBItemsHyperlinq<BItemDerived>(sector, bounds);
|
||||
|
||||
foreach (BItemDerived i in enumerable)
|
||||
{
|
||||
toRet = i;
|
||||
}
|
||||
|
||||
return toRet;
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public BItemDerived SelectBItemsHyperLinqArrayPool()
|
||||
{
|
||||
BItemDerived toRet = null;
|
||||
using Lease<BItemDerived> lease = SelectBItemsHyperlinq<BItemDerived>(sector, bounds).ToArray(ArrayPool<BItemDerived>.Shared);
|
||||
|
||||
foreach (BItemDerived i in lease)
|
||||
{
|
||||
toRet = i;
|
||||
}
|
||||
|
||||
return toRet;
|
||||
}
|
||||
|
||||
public IEnumerable<T> SelectBItemsLinq<T>(Sector s, Rectangle2D bounds) where T : BItem
|
||||
{
|
||||
return s.BItems.OfType<T>().Where(o => o is { Deleted: false, Parent: null } && bounds.Contains(o.Location));
|
||||
}
|
||||
|
||||
public IEnumerable<T> SelectBItems<T>(Sector s, Rectangle2D bounds) where T : BItem
|
||||
{
|
||||
List<BItem> items = s.BItems;
|
||||
List<T> entities = new(items.Count);
|
||||
|
||||
for (int i = items.Count - 1; i >= 0; --i)
|
||||
{
|
||||
if (items[i] is T { Deleted: false, Parent: null } tItem && bounds.Contains(tItem.Location))
|
||||
{
|
||||
entities.Add(tItem);
|
||||
}
|
||||
}
|
||||
return entities;
|
||||
}
|
||||
|
||||
public SelectEnumerable<BItem, T, WhereEnumerable<BItem, ListEnumerable<BItem>, ArrayStructEnumerator<BItem>, BItemWhere<T>>,
|
||||
WhereEnumerator<BItem, ArrayStructEnumerator<BItem>, BItemWhere<T>>, BItemSelect<T>>
|
||||
SelectBItemsLinqStruct<T>(Sector s, Rectangle2D bounds) where T : BItem
|
||||
{
|
||||
BItemWhere<T> bitemWhere = new(bounds);
|
||||
BItemSelect<T> bitemSelect = new();
|
||||
|
||||
return s.BItems.ToStructEnumerable()
|
||||
.Where(ref bitemWhere, x => x)
|
||||
.Select(ref bitemSelect, x => x, x => x);
|
||||
}
|
||||
|
||||
public ArraySegmentWhereSelectEnumerable<BItem, T, BItemWhereHyper<T>, SelectHyper<BItem, T>>
|
||||
SelectBItemsHyperlinq<T>(Sector s, Rectangle2D bounds) where T : BItem
|
||||
{
|
||||
return s.BItems.AsValueEnumerable()
|
||||
.Where(new BItemWhereHyper<T>(bounds))
|
||||
.Select<T, SelectHyper<BItem, T>>();
|
||||
}
|
||||
}
|
||||
|
||||
public class BItem : IPoint3D, IEntity
|
||||
{
|
||||
public object Parent { get; set; } = null;
|
||||
|
||||
public bool Deleted { get; set; } = false;
|
||||
|
||||
public int Z { get; set; } = 1;
|
||||
|
||||
public int X { get; set; } = 1;
|
||||
|
||||
public int Y { get; set; } = 1;
|
||||
|
||||
public Serial Serial => throw new NotImplementedException();
|
||||
|
||||
public Point3D Location { get; }
|
||||
|
||||
public Map Map { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
|
||||
public Region Region => throw new NotImplementedException();
|
||||
|
||||
public string Name { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
public int Hue { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
public Direction Direction { get => throw new System.NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
public DateTime Created { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
|
||||
public int TypeRef => throw new NotImplementedException();
|
||||
|
||||
Point3D IEntity.Location => Location;
|
||||
|
||||
int IPoint3D.Z => throw new NotImplementedException();
|
||||
|
||||
int IPoint2D.X => throw new NotImplementedException();
|
||||
|
||||
int IPoint2D.Y => throw new NotImplementedException();
|
||||
|
||||
DateTime ISerializable.Created { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
DateTime ISerializable.LastSerialized { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
long ISerializable.SavePosition { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
BufferWriter ISerializable.SaveBuffer { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
|
||||
int ISerializable.TypeRef => throw new NotImplementedException();
|
||||
|
||||
Serial ISerializable.Serial => throw new NotImplementedException();
|
||||
|
||||
bool ISerializable.Deleted => throw new NotImplementedException();
|
||||
|
||||
public BItem(Point3D location)
|
||||
{
|
||||
Location = location;
|
||||
}
|
||||
|
||||
public void Delete()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void ProcessDelta()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void OnStatsQuery(Server.Mobile m)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void InvalidateProperties()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public int CompareTo(object obj)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public int CompareTo(IEntity other)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void MoveToWorld(Point3D location, Map map)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool InRange(Point2D p, int range)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool InRange(Point3D p, int range)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void RemoveBItem(BItem BItem)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void BeforeSerialize()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Deserialize(IGenericReader reader)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Serialize(IGenericWriter writer)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void SetTypeRef(Type type)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
void ISerializable.BeforeSerialize()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
void ISerializable.Deserialize(IGenericReader reader)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
void ISerializable.Serialize(IGenericWriter writer)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
void ISerializable.Delete()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
void ISerializable.SetTypeRef(Type type)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void RemoveItem(Item item)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public class BItemDerived : BItem
|
||||
{
|
||||
public BItemDerived(Point3D location) : base(location) { }
|
||||
}
|
||||
|
||||
public class Sector
|
||||
{
|
||||
public List<BItem> BItems { get; set; } = new();
|
||||
}
|
||||
|
||||
public struct BItemWhere<T> : StructLinq.IFunction<BItem, bool> where T : BItem
|
||||
{
|
||||
private readonly Rectangle2D bounds;
|
||||
|
||||
public BItemWhere(Rectangle2D bounds)
|
||||
{
|
||||
this.bounds = bounds;
|
||||
}
|
||||
|
||||
public bool Eval(BItem element)
|
||||
{
|
||||
return element is T { Deleted: false, Parent: null } && bounds.Contains(element.Location);
|
||||
}
|
||||
}
|
||||
|
||||
public struct BItemSelect<T> : StructLinq.IFunction<BItem, T> where T : BItem
|
||||
{
|
||||
public T Eval(BItem element)
|
||||
{
|
||||
return (T)element;
|
||||
}
|
||||
}
|
||||
|
||||
public struct BItemWhereHyper<T> : NetFabric.Hyperlinq.IFunction<BItem, bool> where T : BItem
|
||||
{
|
||||
private readonly Rectangle2D bounds;
|
||||
|
||||
public BItemWhereHyper(Rectangle2D bounds)
|
||||
{
|
||||
this.bounds = bounds;
|
||||
}
|
||||
|
||||
public bool Invoke(BItem element)
|
||||
{
|
||||
return element is T { Deleted: false, Parent: null } && bounds.Contains(element.Location);
|
||||
}
|
||||
}
|
||||
|
||||
public struct SelectHyper<TSource, TDest> : NetFabric.Hyperlinq.IFunction<TSource, TDest> where TDest : TSource
|
||||
{
|
||||
public TDest Invoke(TSource arg)
|
||||
{
|
||||
return (TDest)arg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,254 +0,0 @@
|
|||
using BenchmarkDotNet.Attributes;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using NetFabric.Hyperlinq;
|
||||
using Server;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using static NetFabric.Hyperlinq.ArrayExtensions;
|
||||
|
||||
namespace Benchmarks.MobileSelectors
|
||||
{
|
||||
[SimpleJob(RuntimeMoniker.Net60)]
|
||||
[MemoryDiagnoser]
|
||||
public class MapMobileSelectors
|
||||
{
|
||||
private static readonly Sector sector = new();
|
||||
private static readonly Point3D[] locations = { new Point3D(0, 0, 0), new Point3D(50, 50, 0) };
|
||||
|
||||
public static Rectangle2D[] BoundsArray() => new[]
|
||||
{
|
||||
new Rectangle2D(70, 70, 100, 100),
|
||||
new Rectangle2D(30, 30, 100, 100),
|
||||
new Rectangle2D(0, 0, 100, 100),
|
||||
};
|
||||
|
||||
[GlobalSetup]
|
||||
public static void Init()
|
||||
{
|
||||
for (int j = 0; j < locations.Length; j++)
|
||||
{
|
||||
Point3D loc = locations[j];
|
||||
|
||||
for (int i = 0; i < 500; ++i)
|
||||
{
|
||||
sector.Mobiles.Add(new MobileDerived(loc));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[ParamsSource(nameof(BoundsArray))]
|
||||
public Rectangle2D bounds;
|
||||
|
||||
[Benchmark(Baseline = true)]
|
||||
public MobileDerived SelectMobilesFor()
|
||||
{
|
||||
MobileDerived toRet = null;
|
||||
for (int i = sector.Mobiles.Count - 1; i >= 0; --i)
|
||||
{
|
||||
Mobile mob = sector.Mobiles[i];
|
||||
if (mob is MobileDerived { Deleted: false } tMob && bounds.Contains(mob.Location))
|
||||
{
|
||||
toRet = tMob;
|
||||
}
|
||||
}
|
||||
|
||||
return toRet;
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public MobileDerived SelectMobilesNew()
|
||||
{
|
||||
MobileDerived toRet = null;
|
||||
foreach (MobileDerived m in SelectMobiles<MobileDerived>(sector, bounds))
|
||||
{
|
||||
toRet = m;
|
||||
}
|
||||
|
||||
return toRet;
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public MobileDerived SelectMobilesLinq()
|
||||
{
|
||||
MobileDerived toRet = null;
|
||||
foreach (MobileDerived m in SelectMobilesLinq<MobileDerived>(sector, bounds))
|
||||
{
|
||||
toRet = m;
|
||||
}
|
||||
|
||||
return toRet;
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public MobileDerived SelectMobilesHyperLinq()
|
||||
{
|
||||
MobileDerived toRet = null;
|
||||
foreach (MobileDerived m in SelectMobilesHyperlinq<MobileDerived>(sector, bounds))
|
||||
{
|
||||
toRet = m;
|
||||
}
|
||||
|
||||
return toRet;
|
||||
}
|
||||
|
||||
public IEnumerable<T> SelectMobilesLinq<T>(Sector s, Rectangle2D bounds) where T : Mobile
|
||||
{
|
||||
return s.Mobiles.OfType<T>().Where(o => o is { Deleted: false } && bounds.Contains(o.Location));
|
||||
}
|
||||
|
||||
public IEnumerable<T> SelectMobiles<T>(Sector s, Rectangle2D bounds) where T : Mobile
|
||||
{
|
||||
List<Mobile> mobiles = s.Mobiles;
|
||||
List<T> entities = new(mobiles.Count);
|
||||
|
||||
for (int i = mobiles.Count - 1; i >= 0; --i)
|
||||
{
|
||||
if (mobiles[i] is T { Deleted: false } tMob && bounds.Contains(tMob.Location))
|
||||
{
|
||||
entities.Add(tMob);
|
||||
}
|
||||
}
|
||||
return entities;
|
||||
}
|
||||
|
||||
public ArraySegmentWhereSelectEnumerable<Mobile, T, MobileWhereHyper<T>, SelectHyper<Mobile, T>>
|
||||
SelectMobilesHyperlinq<T>(Sector s, Rectangle2D bounds) where T : Mobile
|
||||
{
|
||||
return s.Mobiles.AsValueEnumerable()
|
||||
.Where(new MobileWhereHyper<T>(bounds))
|
||||
.Select<T, SelectHyper<Mobile, T>>();
|
||||
}
|
||||
}
|
||||
|
||||
public class Mobile : IPoint3D, IEntity
|
||||
{
|
||||
public bool Deleted { get; set; } = false;
|
||||
|
||||
public int Z { get; set; } = 1;
|
||||
|
||||
public int X { get; set; } = 1;
|
||||
|
||||
public int Y { get; set; } = 1;
|
||||
|
||||
public Serial Serial => throw new NotImplementedException();
|
||||
|
||||
public Point3D Location { get; }
|
||||
|
||||
public Map Map { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
|
||||
public Region Region => throw new NotImplementedException();
|
||||
|
||||
public string Name { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
public int Hue { get => throw new System.NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
public Direction Direction { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
public DateTime Created { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
|
||||
public int TypeRef => throw new NotImplementedException();
|
||||
|
||||
int IPoint3D.Z => throw new NotImplementedException();
|
||||
|
||||
int IPoint2D.X => throw new NotImplementedException();
|
||||
|
||||
int IPoint2D.Y => throw new NotImplementedException();
|
||||
|
||||
DateTime ISerializable.Created { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
DateTime ISerializable.LastSerialized { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
long ISerializable.SavePosition { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
BufferWriter ISerializable.SaveBuffer { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
|
||||
int ISerializable.TypeRef => throw new NotImplementedException();
|
||||
|
||||
Serial ISerializable.Serial => throw new NotImplementedException();
|
||||
|
||||
bool ISerializable.Deleted => throw new NotImplementedException();
|
||||
|
||||
public Mobile(Point3D location)
|
||||
{
|
||||
Location = location;
|
||||
}
|
||||
|
||||
public void MoveToWorld(Point3D location, Map map)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void ProcessDelta()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool InRange(Point2D p, int range)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool InRange(Point3D p, int range)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void RemoveItem(Item item)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void BeforeSerialize()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Deserialize(IGenericReader reader)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Serialize(IGenericWriter writer)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Delete()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void SetTypeRef(Type type)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public class MobileDerived : Mobile
|
||||
{
|
||||
public MobileDerived(Point3D location) : base(location) { }
|
||||
}
|
||||
|
||||
public class Sector
|
||||
{
|
||||
public List<Mobile> Mobiles { get; set; } = new();
|
||||
}
|
||||
|
||||
public struct MobileWhereHyper<T> : NetFabric.Hyperlinq.IFunction<Mobile, bool> where T : Mobile
|
||||
{
|
||||
private readonly Rectangle2D bounds;
|
||||
|
||||
public MobileWhereHyper(Rectangle2D bounds)
|
||||
{
|
||||
this.bounds = bounds;
|
||||
}
|
||||
|
||||
public bool Invoke(Mobile element)
|
||||
{
|
||||
return element is T { Deleted: false } && bounds.Contains(element.Location);
|
||||
}
|
||||
}
|
||||
|
||||
public struct SelectHyper<TSource, TDest> : NetFabric.Hyperlinq.IFunction<TSource, TDest> where TDest : TSource
|
||||
{
|
||||
public TDest Invoke(TSource arg)
|
||||
{
|
||||
return (TDest)arg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,310 +0,0 @@
|
|||
using BenchmarkDotNet.Attributes;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using NetFabric.Hyperlinq;
|
||||
using Server;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using static NetFabric.Hyperlinq.ArrayExtensions;
|
||||
|
||||
namespace Benchmarks.MultiSelectors
|
||||
{
|
||||
[SimpleJob(RuntimeMoniker.Net60)]
|
||||
[MemoryDiagnoser]
|
||||
public class MapMultiSelectors
|
||||
{
|
||||
private static readonly Sector sector = new();
|
||||
private static readonly Point3D[] locations = { new Point3D(0, 0, 0), new Point3D(50, 50, 0) };
|
||||
|
||||
public static Rectangle2D[] BoundsArray() => new[]
|
||||
{
|
||||
new Rectangle2D(70, 70, 100, 100),
|
||||
new Rectangle2D(30, 30, 100, 100),
|
||||
new Rectangle2D(0, 0, 100, 100),
|
||||
};
|
||||
|
||||
[GlobalSetup]
|
||||
public static void Init()
|
||||
{
|
||||
for (int j = 0; j < locations.Length; j++)
|
||||
{
|
||||
Point3D loc = locations[j];
|
||||
|
||||
for (int i = 0; i < 25; ++i)
|
||||
{
|
||||
sector.Multis.Add(new BaseMulti(loc));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[ParamsSource(nameof(BoundsArray))]
|
||||
public Rectangle2D bounds;
|
||||
|
||||
[Benchmark(Baseline = true)]
|
||||
public BaseMulti SelectMultiFor()
|
||||
{
|
||||
BaseMulti toRet = null;
|
||||
for (int i = sector.Multis.Count - 1; i >= 0; --i)
|
||||
{
|
||||
BaseMulti multi = sector.Multis[i];
|
||||
if (multi is { Deleted: false } tMulti && bounds.Contains(multi.Location))
|
||||
{
|
||||
toRet = tMulti;
|
||||
}
|
||||
}
|
||||
|
||||
return toRet;
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public BaseMulti SelectMultiNew()
|
||||
{
|
||||
BaseMulti toRet = null;
|
||||
foreach (BaseMulti m in SelectMultiNew(sector, bounds))
|
||||
{
|
||||
toRet = m;
|
||||
}
|
||||
|
||||
return toRet;
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public BaseMulti SelectMultiLinq()
|
||||
{
|
||||
BaseMulti toRet = null;
|
||||
foreach (BaseMulti m in SelectMultiLinq(sector, bounds))
|
||||
{
|
||||
toRet = m;
|
||||
}
|
||||
|
||||
return toRet;
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public BaseMulti SelectMultiHyperLinq()
|
||||
{
|
||||
BaseMulti toRet = null;
|
||||
foreach (BaseMulti m in SelectMultiHyperlinq(sector, bounds))
|
||||
{
|
||||
toRet = m;
|
||||
}
|
||||
|
||||
return toRet;
|
||||
}
|
||||
|
||||
public IEnumerable<BaseMulti> SelectMultiLinq(Sector s, Rectangle2D bounds)
|
||||
{
|
||||
return s.Multis.Where(o => o is { Deleted: false } && bounds.Contains(o.Location));
|
||||
}
|
||||
|
||||
public IEnumerable<BaseMulti> SelectMultiNew(Sector s, Rectangle2D bounds)
|
||||
{
|
||||
List<BaseMulti> entities = new(s.Multis.Count);
|
||||
|
||||
for (int i = s.Multis.Count - 1; i >= 0; --i)
|
||||
{
|
||||
BaseMulti multiItem = s.Multis[i];
|
||||
if (multiItem is { Deleted: false } && bounds.Contains(multiItem.Location))
|
||||
{
|
||||
entities.Add(multiItem);
|
||||
}
|
||||
}
|
||||
return entities;
|
||||
}
|
||||
|
||||
public ArraySegmentWhereEnumerable<BaseMulti, MultiWhereHyper>
|
||||
SelectMultiHyperlinq(Sector s, Rectangle2D bounds)
|
||||
{
|
||||
return s.Multis.AsValueEnumerable().Where(new MultiWhereHyper(bounds));
|
||||
}
|
||||
}
|
||||
|
||||
public class BItem : IPoint3D, IEntity
|
||||
{
|
||||
public object Parent { get; set; } = null;
|
||||
|
||||
public bool Deleted { get; set; } = false;
|
||||
|
||||
public int Z { get; set; } = 1;
|
||||
|
||||
public int X { get; set; } = 1;
|
||||
|
||||
public int Y { get; set; } = 1;
|
||||
|
||||
public Serial Serial => throw new NotImplementedException();
|
||||
|
||||
public Point3D Location { get; }
|
||||
|
||||
public Map Map { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
|
||||
public Region Region => throw new NotImplementedException();
|
||||
|
||||
public string Name { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
public int Hue { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
public Direction Direction { get => throw new System.NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
public DateTime Created { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
|
||||
public int TypeRef => throw new NotImplementedException();
|
||||
|
||||
int IPoint3D.Z => throw new NotImplementedException();
|
||||
|
||||
int IPoint2D.X => throw new NotImplementedException();
|
||||
|
||||
int IPoint2D.Y => throw new NotImplementedException();
|
||||
|
||||
DateTime ISerializable.Created { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
DateTime ISerializable.LastSerialized { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
long ISerializable.SavePosition { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
BufferWriter ISerializable.SaveBuffer { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
|
||||
int ISerializable.TypeRef => throw new NotImplementedException();
|
||||
|
||||
Serial ISerializable.Serial => throw new NotImplementedException();
|
||||
|
||||
bool ISerializable.Deleted => throw new NotImplementedException();
|
||||
|
||||
public BItem(Point3D location)
|
||||
{
|
||||
Location = location;
|
||||
}
|
||||
|
||||
public void Delete()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void ProcessDelta()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void OnStatsQuery(Server.Mobile m)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void InvalidateProperties()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public int CompareTo(object obj)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public int CompareTo(IEntity other)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void MoveToWorld(Point3D location, Map map)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool InRange(Point2D p, int range)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool InRange(Point3D p, int range)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void RemoveBItem(BItem BItem)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void BeforeSerialize()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Deserialize(IGenericReader reader)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Serialize(IGenericWriter writer)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void SetTypeRef(Type type)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
void ISerializable.BeforeSerialize()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
void ISerializable.Deserialize(IGenericReader reader)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
void ISerializable.Serialize(IGenericWriter writer)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
void ISerializable.Delete()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
void ISerializable.SetTypeRef(Type type)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void RemoveItem(Item item)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public class BaseMulti : BItem
|
||||
{
|
||||
public MultiComponentList Components = MultiComponentList.Empty;
|
||||
|
||||
public BaseMulti(Point3D location) : base(location)
|
||||
{
|
||||
for (int i = 0; i < 20; ++i)
|
||||
{
|
||||
for (int j = 0; j < 20; ++j)
|
||||
{
|
||||
for (int z = 0; z < 20; ++z)
|
||||
{
|
||||
Components.Add(123, i, j, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class Sector
|
||||
{
|
||||
public List<BaseMulti> Multis { get; set; } = new();
|
||||
}
|
||||
|
||||
public struct MultiWhereHyper : IFunction<BaseMulti, bool>
|
||||
{
|
||||
private readonly Rectangle2D bounds;
|
||||
|
||||
public MultiWhereHyper(Rectangle2D bounds)
|
||||
{
|
||||
this.bounds = bounds;
|
||||
}
|
||||
|
||||
public bool Invoke(BaseMulti element)
|
||||
{
|
||||
return element is { Deleted: false } && bounds.Contains(element.Location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,350 +0,0 @@
|
|||
using BenchmarkDotNet.Attributes;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using Server;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Benchmarks.MultiTilesSelectors
|
||||
{
|
||||
[SimpleJob(RuntimeMoniker.Net60)]
|
||||
[MemoryDiagnoser]
|
||||
public class MapMultiTilesSelectors
|
||||
{
|
||||
private static readonly Sector sector = new();
|
||||
private static readonly Point3D[] locations = { new Point3D(0, 0, 0), new Point3D(50, 50, 0) };
|
||||
|
||||
public static Rectangle2D[] BoundsArray() => new[]
|
||||
{
|
||||
new Rectangle2D(70, 70, 100, 100),
|
||||
new Rectangle2D(30, 30, 100, 100),
|
||||
new Rectangle2D(0, 0, 100, 100),
|
||||
};
|
||||
|
||||
[GlobalSetup]
|
||||
public static void Init()
|
||||
{
|
||||
for (int j = 0; j < locations.Length; j++)
|
||||
{
|
||||
Point3D loc = locations[j];
|
||||
|
||||
for (int i = 0; i < 25; ++i)
|
||||
{
|
||||
sector.Multis.Add(new BaseMulti(loc));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[ParamsSource(nameof(BoundsArray))]
|
||||
public Rectangle2D bounds;
|
||||
|
||||
[Benchmark]
|
||||
public int SelectMultiTilesNew()
|
||||
{
|
||||
int toRet = 0;
|
||||
|
||||
foreach (StaticTile[] tiles in SelectMultiTilesNew(sector, bounds))
|
||||
{
|
||||
for (int i = 0; i < tiles.Length; ++i)
|
||||
{
|
||||
toRet = tiles[i].ID;
|
||||
}
|
||||
}
|
||||
|
||||
return toRet;
|
||||
}
|
||||
|
||||
[Benchmark(Baseline = true)]
|
||||
public int SelectMultiTilesLinq()
|
||||
{
|
||||
int toRet = 0;
|
||||
|
||||
foreach (StaticTile[] tiles in SelectMultiTilesLinq(sector, bounds))
|
||||
{
|
||||
for (int i = 0; i < tiles.Length; ++i)
|
||||
{
|
||||
toRet = tiles[i].ID;
|
||||
}
|
||||
}
|
||||
|
||||
return toRet;
|
||||
}
|
||||
|
||||
public IEnumerable<StaticTile[]> SelectMultiTilesLinq(Sector s, Rectangle2D bounds)
|
||||
{
|
||||
foreach (var o in s.Multis.Where(o => o != null && !o.Deleted))
|
||||
{
|
||||
var c = o.Components;
|
||||
|
||||
int x, y, xo, yo;
|
||||
StaticTile[] t, r;
|
||||
|
||||
for (x = bounds.Start.X; x < bounds.End.X; x++)
|
||||
{
|
||||
xo = x - (o.X + c.Min.X);
|
||||
|
||||
if (xo < 0 || xo >= c.Width)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (y = bounds.Start.Y; y < bounds.End.Y; y++)
|
||||
{
|
||||
yo = y - (o.Y + c.Min.Y);
|
||||
|
||||
if (yo < 0 || yo >= c.Height)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
t = c.Tiles[xo][yo];
|
||||
|
||||
if (t.Length <= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
r = new StaticTile[t.Length];
|
||||
|
||||
for (var i = 0; i < t.Length; i++)
|
||||
{
|
||||
r[i] = t[i];
|
||||
r[i].Z += o.Z;
|
||||
}
|
||||
|
||||
yield return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<StaticTile[]> SelectMultiTilesNew(Sector s, Rectangle2D bounds)
|
||||
{
|
||||
List<BaseMulti> multis = s.Multis;
|
||||
|
||||
for (int l = multis.Count - 1; l >= 0; --l)
|
||||
{
|
||||
if (multis[l] is not { Deleted: false } o)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
MultiComponentList c = o.Components;
|
||||
|
||||
int x, y, xo, yo;
|
||||
StaticTile[] t, r;
|
||||
|
||||
for (x = bounds.Start.X; x < bounds.End.X; x++)
|
||||
{
|
||||
xo = x - (o.X + c.Min.X);
|
||||
|
||||
if (xo < 0 || xo >= c.Width)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (y = bounds.Start.Y; y < bounds.End.Y; y++)
|
||||
{
|
||||
yo = y - (o.Y + c.Min.Y);
|
||||
|
||||
if (yo < 0 || yo >= c.Height)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
t = c.Tiles[xo][yo];
|
||||
|
||||
if (t.Length <= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
r = new StaticTile[t.Length];
|
||||
|
||||
for (var i = 0; i < t.Length; i++)
|
||||
{
|
||||
r[i] = t[i];
|
||||
r[i].Z += o.Z;
|
||||
}
|
||||
|
||||
yield return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class BItem : IPoint3D, IEntity
|
||||
{
|
||||
public object Parent { get; set; } = null;
|
||||
|
||||
public bool Deleted { get; set; } = false;
|
||||
|
||||
public int Z { get; set; } = 1;
|
||||
|
||||
public int X { get; set; } = 1;
|
||||
|
||||
public int Y { get; set; } = 1;
|
||||
|
||||
public Serial Serial => throw new NotImplementedException();
|
||||
|
||||
public Point3D Location { get; }
|
||||
|
||||
public Map Map { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
|
||||
public Region Region => throw new NotImplementedException();
|
||||
|
||||
public string Name { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
public int Hue { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
public Direction Direction { get => throw new System.NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
public DateTime Created { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
|
||||
public int TypeRef => throw new NotImplementedException();
|
||||
|
||||
int IPoint3D.Z => throw new NotImplementedException();
|
||||
|
||||
int IPoint2D.X => throw new NotImplementedException();
|
||||
|
||||
int IPoint2D.Y => throw new NotImplementedException();
|
||||
|
||||
DateTime ISerializable.Created { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
DateTime ISerializable.LastSerialized { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
long ISerializable.SavePosition { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
BufferWriter ISerializable.SaveBuffer { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
|
||||
int ISerializable.TypeRef => throw new NotImplementedException();
|
||||
|
||||
Serial ISerializable.Serial => throw new NotImplementedException();
|
||||
|
||||
bool ISerializable.Deleted => throw new NotImplementedException();
|
||||
|
||||
public BItem(Point3D location)
|
||||
{
|
||||
Location = location;
|
||||
}
|
||||
|
||||
public void Delete()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void ProcessDelta()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void OnStatsQuery(Server.Mobile m)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void InvalidateProperties()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public int CompareTo(object obj)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public int CompareTo(IEntity other)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void MoveToWorld(Point3D location, Map map)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool InRange(Point2D p, int range)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool InRange(Point3D p, int range)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void RemoveBItem(BItem BItem)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void BeforeSerialize()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Deserialize(IGenericReader reader)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Serialize(IGenericWriter writer)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void SetTypeRef(Type type)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
void ISerializable.BeforeSerialize()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
void ISerializable.Deserialize(IGenericReader reader)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
void ISerializable.Serialize(IGenericWriter writer)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
void ISerializable.Delete()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
void ISerializable.SetTypeRef(Type type)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void RemoveItem(Item item)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public class BaseMulti : BItem
|
||||
{
|
||||
public MultiComponentList Components = MultiComponentList.Empty;
|
||||
|
||||
public BaseMulti(Point3D location) : base(location)
|
||||
{
|
||||
for (int i = 0; i < 20; ++i)
|
||||
{
|
||||
for (int j = 0; j < 20; ++j)
|
||||
{
|
||||
for (int z = 0; z < 20; ++z)
|
||||
{
|
||||
Components.Add(123, i, j, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class Sector
|
||||
{
|
||||
public List<BaseMulti> Multis { get; set; } = new();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,174 +0,0 @@
|
|||
using System;
|
||||
using System.Buffers;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using Server;
|
||||
using Server.Network;
|
||||
|
||||
namespace Benchmarks
|
||||
{
|
||||
[SimpleJob(RuntimeMoniker.Net60)]
|
||||
public class BenchmarkPacketBroadcast
|
||||
{
|
||||
public static int SendUnicodeMessage(
|
||||
ArraySegment<byte>[] buffer,
|
||||
Serial serial, int graphic, MessageType type, int hue, int font, string lang, string name, string text
|
||||
)
|
||||
{
|
||||
name = name?.Trim() ?? "";
|
||||
text = text?.Trim() ?? "";
|
||||
lang = lang?.Trim() ?? "ENU";
|
||||
|
||||
if (hue == 0)
|
||||
{
|
||||
hue = 0x3B2;
|
||||
}
|
||||
|
||||
var writer = new CircularBufferWriter(buffer);
|
||||
writer.Write((byte)0xAE);
|
||||
writer.Write((ushort)(50 + text.Length * 2));
|
||||
writer.Write(serial.Value);
|
||||
writer.Write((short)graphic);
|
||||
writer.Write((byte)type);
|
||||
writer.Write((short)hue);
|
||||
writer.Write((short)font);
|
||||
writer.WriteAscii(lang, 4);
|
||||
writer.WriteAscii(name, 30);
|
||||
writer.WriteBigUniNull(text);
|
||||
|
||||
return writer.Position;
|
||||
}
|
||||
|
||||
public static int CreateUnicodeMessage(
|
||||
Span<byte> buffer,
|
||||
Serial serial, int graphic, MessageType type, int hue, int font, string lang, string name, string text
|
||||
)
|
||||
{
|
||||
name = name?.Trim() ?? "";
|
||||
text = text?.Trim() ?? "";
|
||||
lang = lang?.Trim() ?? "ENU";
|
||||
|
||||
if (hue == 0)
|
||||
{
|
||||
hue = 0x3B2;
|
||||
}
|
||||
|
||||
var writer = new SpanWriter(buffer);
|
||||
writer.Write((byte)0xAE);
|
||||
writer.Write((ushort)(50 + text.Length * 2));
|
||||
writer.Write(serial);
|
||||
writer.Write((short)graphic);
|
||||
writer.Write((byte)type);
|
||||
writer.Write((short)hue);
|
||||
writer.Write((short)font);
|
||||
writer.WriteAscii(lang, 4);
|
||||
writer.WriteAscii(name, 30);
|
||||
writer.WriteBigUniNull(text);
|
||||
|
||||
return writer.Position;
|
||||
}
|
||||
|
||||
private Pipe<byte>[] _pipes = new Pipe<byte>[25000];
|
||||
|
||||
[IterationSetup]
|
||||
public void SetUp()
|
||||
{
|
||||
for (var i = 0; i < _pipes.Length; i++)
|
||||
{
|
||||
_pipes[i] = new Pipe<byte>(new byte[4096]);
|
||||
}
|
||||
}
|
||||
|
||||
[IterationCleanup]
|
||||
public void CleanUp()
|
||||
{
|
||||
for (var i = 0; i < _pipes.Length; i++)
|
||||
{
|
||||
_pipes[i] = null;
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public int TestCircularBuffer()
|
||||
{
|
||||
var text = "This is some really long text that we want to handle. It should take a little bit to encode this.";
|
||||
foreach (var pipe in _pipes)
|
||||
{
|
||||
var result = pipe.Writer.TryGetMemory();
|
||||
var length = SendUnicodeMessage(
|
||||
result.Buffer,
|
||||
Serial.MinusOne, -1, MessageType.Regular, 0x3B2, 3, "ENU", "System", text
|
||||
);
|
||||
pipe.Writer.Advance((uint)length);
|
||||
}
|
||||
|
||||
return _pipes.Length;
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public int TestSpanWriterFromBuffer()
|
||||
{
|
||||
var text = "This is some really long text that we want to handle. It should take a little bit to encode this.";
|
||||
foreach (var pipe in _pipes)
|
||||
{
|
||||
var result = pipe.Writer.TryGetMemory();
|
||||
|
||||
Span<byte> buffer = result.Buffer[0];
|
||||
|
||||
var length = CreateUnicodeMessage(
|
||||
buffer, Serial.MinusOne, -1, MessageType.Regular, 0x3B2, 3, "ENU", "System", text
|
||||
);
|
||||
pipe.Writer.Advance((uint)length);
|
||||
}
|
||||
|
||||
return _pipes.Length;
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public int TestSpanWriter()
|
||||
{
|
||||
var text = "This is some really long text that we want to handle. It should take a little bit to encode this.";
|
||||
Span<byte> buffer = stackalloc byte[OutgoingMessagePackets.GetMaxMessageLength(text)];
|
||||
var length = CreateUnicodeMessage(
|
||||
buffer, Serial.MinusOne, -1, MessageType.Regular, 0x3B2, 3, "ENU", "System", text
|
||||
);
|
||||
|
||||
buffer = buffer[..length];
|
||||
|
||||
foreach (var pipe in _pipes)
|
||||
{
|
||||
var result = pipe.Writer.TryGetMemory();
|
||||
result.CopyFrom(buffer);
|
||||
pipe.Writer.Advance((uint)buffer.Length);
|
||||
}
|
||||
|
||||
return _pipes.Length;
|
||||
}
|
||||
|
||||
private static void SendUnicodeMessageWithSpan(Pipe<byte> pipe, string text)
|
||||
{
|
||||
Span<byte> buffer = stackalloc byte[OutgoingMessagePackets.GetMaxMessageLength(text)];
|
||||
var length = CreateUnicodeMessage(
|
||||
buffer, Serial.MinusOne, -1, MessageType.Regular, 0x3B2, 3, "ENU", "System", text
|
||||
);
|
||||
|
||||
buffer = buffer[..length];
|
||||
var result = pipe.Writer.TryGetMemory();
|
||||
result.CopyFrom(buffer);
|
||||
pipe.Writer.Advance((uint)buffer.Length);
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public int TestSpanWriterLooped()
|
||||
{
|
||||
var text = "This is some really long text that we want to handle. It should take a little bit to encode this.";
|
||||
|
||||
foreach (var pipe in _pipes)
|
||||
{
|
||||
SendUnicodeMessageWithSpan(pipe, text);
|
||||
}
|
||||
|
||||
return _pipes.Length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,265 +0,0 @@
|
|||
using System;
|
||||
using System.Buffers;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using Server.Diagnostics;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public abstract class Packet
|
||||
{
|
||||
private const int CompressorBufferSize = 0x10000;
|
||||
|
||||
private readonly int m_Length;
|
||||
|
||||
private byte[] m_CompiledBuffer;
|
||||
private int m_CompiledLength;
|
||||
private State m_State;
|
||||
|
||||
protected Packet(int packetID)
|
||||
{
|
||||
PacketID = packetID;
|
||||
|
||||
if (Core.Profiling)
|
||||
{
|
||||
var prof = PacketSendProfile.Acquire(PacketID);
|
||||
prof.Increment();
|
||||
}
|
||||
}
|
||||
|
||||
protected Packet(int packetID, int length)
|
||||
{
|
||||
PacketID = packetID;
|
||||
m_Length = length;
|
||||
|
||||
Stream = PacketWriter.CreateInstance(length); // new PacketWriter( length );
|
||||
Stream.Write((byte)packetID);
|
||||
|
||||
if (Core.Profiling)
|
||||
{
|
||||
var prof = PacketSendProfile.Acquire(PacketID);
|
||||
prof.Increment();
|
||||
}
|
||||
}
|
||||
|
||||
public int PacketID { get; }
|
||||
|
||||
public PacketWriter Stream { get; protected set; }
|
||||
|
||||
public void EnsureCapacity(int length)
|
||||
{
|
||||
Stream = PacketWriter.CreateInstance(length); // new PacketWriter( length );
|
||||
Stream.Write((byte)PacketID);
|
||||
Stream.Write((short)0);
|
||||
}
|
||||
|
||||
public static Packet SetStatic(Packet p)
|
||||
{
|
||||
p.SetStatic();
|
||||
return p;
|
||||
}
|
||||
|
||||
public static Packet Acquire(Packet p)
|
||||
{
|
||||
p.Acquire();
|
||||
return p;
|
||||
}
|
||||
|
||||
public static void Release(ref Packet p)
|
||||
{
|
||||
p?.Release();
|
||||
p = null;
|
||||
}
|
||||
|
||||
public static void Release(Packet p)
|
||||
{
|
||||
p?.Release();
|
||||
}
|
||||
|
||||
public void SetStatic()
|
||||
{
|
||||
m_State |= State.Static | State.Acquired;
|
||||
}
|
||||
|
||||
public void Acquire()
|
||||
{
|
||||
m_State |= State.Acquired;
|
||||
}
|
||||
|
||||
public void OnSend()
|
||||
{
|
||||
if ((m_State & (State.Acquired | State.Static)) == 0)
|
||||
{
|
||||
Free();
|
||||
}
|
||||
}
|
||||
|
||||
private void Free()
|
||||
{
|
||||
if (m_CompiledBuffer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ((m_State & State.Buffered) != 0)
|
||||
{
|
||||
ArrayPool<byte>.Shared.Return(m_CompiledBuffer);
|
||||
}
|
||||
|
||||
m_State &= ~(State.Static | State.Acquired | State.Buffered);
|
||||
|
||||
m_CompiledBuffer = null;
|
||||
}
|
||||
|
||||
public void Release()
|
||||
{
|
||||
if ((m_State & State.Acquired) != 0)
|
||||
{
|
||||
Free();
|
||||
}
|
||||
}
|
||||
|
||||
private readonly object _object = new();
|
||||
|
||||
public byte[] Compile(bool compress, out int length)
|
||||
{
|
||||
lock (_object)
|
||||
{
|
||||
if (m_CompiledBuffer == null)
|
||||
{
|
||||
if ((m_State & State.Accessed) == 0)
|
||||
{
|
||||
m_State |= State.Accessed;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((m_State & State.Warned) == 0)
|
||||
{
|
||||
m_State |= State.Warned;
|
||||
|
||||
try
|
||||
{
|
||||
using var op = new StreamWriter("net_opt.log", true);
|
||||
op.WriteLine("Redundant compile for packet {0}, use Acquire() and Release()", GetType());
|
||||
op.WriteLine(new StackTrace());
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
m_CompiledBuffer = Array.Empty<byte>();
|
||||
m_CompiledLength = 0;
|
||||
|
||||
length = m_CompiledLength;
|
||||
return m_CompiledBuffer;
|
||||
}
|
||||
|
||||
InternalCompile(compress);
|
||||
}
|
||||
|
||||
length = m_CompiledLength;
|
||||
return m_CompiledBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
private void InternalCompile(bool compress)
|
||||
{
|
||||
if (m_Length == 0)
|
||||
{
|
||||
var streamLen = Stream.Length;
|
||||
|
||||
Stream.Seek(1, SeekOrigin.Begin);
|
||||
Stream.Write((ushort)streamLen);
|
||||
}
|
||||
else if (Stream.Length != m_Length)
|
||||
{
|
||||
var diff = (int)Stream.Length - m_Length;
|
||||
|
||||
Console.WriteLine(
|
||||
"Packet: 0x{0:X2}: Bad packet length! ({1}{2} bytes)",
|
||||
PacketID,
|
||||
diff >= 0 ? "+" : "",
|
||||
diff
|
||||
);
|
||||
}
|
||||
|
||||
var ms = Stream.UnderlyingStream;
|
||||
|
||||
m_CompiledBuffer = ms.GetBuffer();
|
||||
var length = (int)ms.Length;
|
||||
|
||||
if (compress)
|
||||
{
|
||||
var compressorBuffer = new byte[CompressorBufferSize];
|
||||
var compressedLength = NetworkCompression.Compress(m_CompiledBuffer.AsSpan(0, length), compressorBuffer);
|
||||
|
||||
if (length <= 0)
|
||||
{
|
||||
Console.WriteLine(
|
||||
"Warning: Compression buffer overflowed on packet 0x{0:X2} ('{1}') (length={2})",
|
||||
PacketID,
|
||||
GetType().Name,
|
||||
length
|
||||
);
|
||||
using var op = new StreamWriter("compression_overflow.log", true);
|
||||
op.WriteLine(
|
||||
"{0} Warning: Compression buffer overflowed on packet 0x{1:X2} ('{2}') (length={3})",
|
||||
Core.Now,
|
||||
PacketID,
|
||||
GetType().Name,
|
||||
length
|
||||
);
|
||||
op.WriteLine(new StackTrace());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_CompiledBuffer = compressorBuffer;
|
||||
m_CompiledLength = compressedLength;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_CompiledLength = length;
|
||||
}
|
||||
|
||||
if (m_CompiledLength > 0)
|
||||
{
|
||||
var old = m_CompiledBuffer;
|
||||
|
||||
if ((m_State & State.Static) != 0)
|
||||
{
|
||||
m_CompiledBuffer = new byte[m_CompiledLength];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Release it later using Release()
|
||||
m_CompiledBuffer = ArrayPool<byte>.Shared.Rent(m_CompiledLength);
|
||||
m_State |= State.Buffered;
|
||||
}
|
||||
|
||||
Buffer.BlockCopy(old, 0, m_CompiledBuffer, 0, m_CompiledLength);
|
||||
|
||||
if (compress)
|
||||
{
|
||||
ArrayPool<byte>.Shared.Return(old);
|
||||
}
|
||||
}
|
||||
|
||||
PacketWriter.ReleaseInstance(Stream);
|
||||
Stream = null;
|
||||
}
|
||||
|
||||
[Flags]
|
||||
private enum State
|
||||
{
|
||||
Inactive = 0x00,
|
||||
Static = 0x01,
|
||||
Acquired = 0x02,
|
||||
Accessed = 0x04,
|
||||
Buffered = 0x08,
|
||||
Warned = 0x10
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
using System;
|
||||
using System.Buffers.Binary;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Server;
|
||||
using Server.Network;
|
||||
|
||||
namespace Benchmarks
|
||||
{
|
||||
public static class PacketTestUtilities
|
||||
{
|
||||
public static Span<byte> Compile(this Packet p) =>
|
||||
p.Compile(false, out var length).AsSpan(0, length);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Write(this Span<byte> data, ref int pos, Serial serial)
|
||||
{
|
||||
BinaryPrimitives.WriteUInt32BigEndian(data.Slice(pos, 4), serial.Value);
|
||||
pos += 4;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Write(this Span<byte> data, ref int pos, ushort value)
|
||||
{
|
||||
BinaryPrimitives.WriteUInt16BigEndian(data.Slice(pos, 2), value);
|
||||
pos += 2;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Write(this Span<byte> data, ref int pos, byte value) => data[pos++] = value;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,354 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides functionality for writing primitive binary data.
|
||||
/// </summary>
|
||||
public class PacketWriter
|
||||
{
|
||||
private static readonly ConcurrentQueue<PacketWriter> m_Pool = new();
|
||||
|
||||
/// <summary>
|
||||
/// Internal format buffer.
|
||||
/// </summary>
|
||||
private readonly byte[] m_Buffer = new byte[4];
|
||||
|
||||
private int m_Capacity;
|
||||
|
||||
/// <summary>
|
||||
/// Instantiates a new PacketWriter instance with a given capacity.
|
||||
/// </summary>
|
||||
/// <param name="capacity">Initial capacity for the internal stream.</param>
|
||||
public PacketWriter(int capacity = 32)
|
||||
{
|
||||
UnderlyingStream = new MemoryStream(capacity);
|
||||
m_Capacity = capacity;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the total stream length.
|
||||
/// </summary>
|
||||
public long Length => UnderlyingStream.Length;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the current stream position.
|
||||
/// </summary>
|
||||
public long Position
|
||||
{
|
||||
get => UnderlyingStream.Position;
|
||||
set => UnderlyingStream.Position = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The internal stream used by this PacketWriter instance.
|
||||
/// </summary>
|
||||
public MemoryStream UnderlyingStream { get; }
|
||||
|
||||
public static PacketWriter CreateInstance(int capacity = 32)
|
||||
{
|
||||
if (m_Pool.TryDequeue(out var pw))
|
||||
{
|
||||
pw.m_Capacity = capacity;
|
||||
pw.UnderlyingStream.SetLength(0);
|
||||
return pw;
|
||||
}
|
||||
|
||||
return new PacketWriter(capacity);
|
||||
}
|
||||
|
||||
public static void ReleaseInstance(PacketWriter pw)
|
||||
{
|
||||
m_Pool.Enqueue(pw);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a 1-byte boolean value to the underlying stream. False is represented by 0, true by 1.
|
||||
/// </summary>
|
||||
public void Write(bool value)
|
||||
{
|
||||
UnderlyingStream.WriteByte((byte)(value ? 1 : 0));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a 1-byte unsigned integer value to the underlying stream.
|
||||
/// </summary>
|
||||
public void Write(byte value)
|
||||
{
|
||||
UnderlyingStream.WriteByte(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a 1-byte signed integer value to the underlying stream.
|
||||
/// </summary>
|
||||
public void Write(sbyte value)
|
||||
{
|
||||
UnderlyingStream.WriteByte((byte)value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a 2-byte signed integer value to the underlying stream.
|
||||
/// </summary>
|
||||
public void Write(short value)
|
||||
{
|
||||
m_Buffer[0] = (byte)(value >> 8);
|
||||
m_Buffer[1] = (byte)value;
|
||||
|
||||
UnderlyingStream.Write(m_Buffer, 0, 2);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a 2-byte unsigned integer value to the underlying stream.
|
||||
/// </summary>
|
||||
public void Write(ushort value)
|
||||
{
|
||||
m_Buffer[0] = (byte)(value >> 8);
|
||||
m_Buffer[1] = (byte)value;
|
||||
|
||||
UnderlyingStream.Write(m_Buffer, 0, 2);
|
||||
}
|
||||
|
||||
public void Write(Serial serial) => Write(serial.Value);
|
||||
|
||||
/// <summary>
|
||||
/// Writes a 4-byte signed integer value to the underlying stream.
|
||||
/// </summary>
|
||||
public void Write(int value)
|
||||
{
|
||||
m_Buffer[0] = (byte)(value >> 24);
|
||||
m_Buffer[1] = (byte)(value >> 16);
|
||||
m_Buffer[2] = (byte)(value >> 8);
|
||||
m_Buffer[3] = (byte)value;
|
||||
|
||||
UnderlyingStream.Write(m_Buffer, 0, 4);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a 4-byte unsigned integer value to the underlying stream.
|
||||
/// </summary>
|
||||
public void Write(uint value)
|
||||
{
|
||||
m_Buffer[0] = (byte)(value >> 24);
|
||||
m_Buffer[1] = (byte)(value >> 16);
|
||||
m_Buffer[2] = (byte)(value >> 8);
|
||||
m_Buffer[3] = (byte)value;
|
||||
|
||||
UnderlyingStream.Write(m_Buffer, 0, 4);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a sequence of bytes to the underlying stream
|
||||
/// </summary>
|
||||
public void Write(byte[] buffer, int offset, int size)
|
||||
{
|
||||
UnderlyingStream.Write(buffer, offset, size);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a fixed-length ASCII-encoded string value to the underlying stream. To fit (size), the string content is either
|
||||
/// truncated or padded with null characters.
|
||||
/// </summary>
|
||||
public void WriteAsciiFixed(string value, int size)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
Console.WriteLine("Network: Attempted to WriteAsciiFixed() with null value");
|
||||
value = string.Empty;
|
||||
}
|
||||
|
||||
var length = value.Length;
|
||||
|
||||
UnderlyingStream.SetLength(UnderlyingStream.Length + size);
|
||||
|
||||
if (length >= size)
|
||||
{
|
||||
UnderlyingStream.Position +=
|
||||
Encoding.ASCII.GetBytes(value, 0, size, UnderlyingStream.GetBuffer(), (int)UnderlyingStream.Position);
|
||||
}
|
||||
else
|
||||
{
|
||||
Encoding.ASCII.GetBytes(value, 0, length, UnderlyingStream.GetBuffer(), (int)UnderlyingStream.Position);
|
||||
UnderlyingStream.Position += size;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a dynamic-length ASCII-encoded string value to the underlying stream, followed by a 1-byte null character.
|
||||
/// </summary>
|
||||
public void WriteAsciiNull(string value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
Console.WriteLine("Network: Attempted to WriteAsciiNull() with null value");
|
||||
value = string.Empty;
|
||||
}
|
||||
|
||||
var length = value.Length;
|
||||
|
||||
UnderlyingStream.SetLength(UnderlyingStream.Length + length + 1);
|
||||
|
||||
Encoding.ASCII.GetBytes(value, 0, length, UnderlyingStream.GetBuffer(), (int)UnderlyingStream.Position);
|
||||
UnderlyingStream.Position += length + 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a dynamic-length little-endian unicode string value to the underlying stream, followed by a 2-byte null
|
||||
/// character.
|
||||
/// </summary>
|
||||
public void WriteLittleUniNull(string value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
Console.WriteLine("Network: Attempted to WriteLittleUniNull() with null value");
|
||||
value = string.Empty;
|
||||
}
|
||||
|
||||
var length = value.Length;
|
||||
|
||||
UnderlyingStream.SetLength(UnderlyingStream.Length + (length + 1) * 2);
|
||||
|
||||
UnderlyingStream.Position +=
|
||||
Encoding.Unicode.GetBytes(value, 0, length, UnderlyingStream.GetBuffer(), (int)UnderlyingStream.Position);
|
||||
UnderlyingStream.Position += 2;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a fixed-length little-endian unicode string value to the underlying stream. To fit (size), the string content is
|
||||
/// either truncated or padded with null characters.
|
||||
/// </summary>
|
||||
public void WriteLittleUniFixed(string value, int size)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
Console.WriteLine("Network: Attempted to WriteLittleUniFixed() with null value");
|
||||
value = string.Empty;
|
||||
}
|
||||
|
||||
var length = value.Length;
|
||||
size *= 2;
|
||||
|
||||
UnderlyingStream.SetLength(UnderlyingStream.Length + size);
|
||||
|
||||
if (length * 2 >= size)
|
||||
{
|
||||
UnderlyingStream.Position +=
|
||||
Encoding.Unicode.GetBytes(
|
||||
value,
|
||||
0,
|
||||
size / 2,
|
||||
UnderlyingStream.GetBuffer(),
|
||||
(int)UnderlyingStream.Position
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
Encoding.Unicode.GetBytes(value, 0, length, UnderlyingStream.GetBuffer(), (int)UnderlyingStream.Position);
|
||||
UnderlyingStream.Position += size;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a dynamic-length big-endian unicode string value to the underlying stream, followed by a 2-byte null character.
|
||||
/// </summary>
|
||||
public void WriteBigUniNull(string value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
Console.WriteLine("Network: Attempted to WriteBigUniNull() with null value");
|
||||
value = string.Empty;
|
||||
}
|
||||
|
||||
var length = value.Length;
|
||||
|
||||
UnderlyingStream.SetLength(UnderlyingStream.Length + (length + 1) * 2);
|
||||
|
||||
UnderlyingStream.Position +=
|
||||
Encoding.BigEndianUnicode.GetBytes(
|
||||
value,
|
||||
0,
|
||||
length,
|
||||
UnderlyingStream.GetBuffer(),
|
||||
(int)UnderlyingStream.Position
|
||||
);
|
||||
UnderlyingStream.Position += 2;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a fixed-length big-endian unicode string value to the underlying stream. To fit (size), the string content is
|
||||
/// either truncated or padded with null characters.
|
||||
/// </summary>
|
||||
public void WriteBigUniFixed(string value, int size)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
Console.WriteLine("Network: Attempted to WriteBigUniFixed() with null value");
|
||||
value = string.Empty;
|
||||
}
|
||||
|
||||
var length = value.Length;
|
||||
size *= 2;
|
||||
|
||||
UnderlyingStream.SetLength(UnderlyingStream.Length + size);
|
||||
|
||||
if (length * 2 >= size)
|
||||
{
|
||||
UnderlyingStream.Position +=
|
||||
Encoding.BigEndianUnicode.GetBytes(
|
||||
value,
|
||||
0,
|
||||
size / 2,
|
||||
UnderlyingStream.GetBuffer(),
|
||||
(int)UnderlyingStream.Position
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
Encoding.BigEndianUnicode.GetBytes(
|
||||
value,
|
||||
0,
|
||||
length,
|
||||
UnderlyingStream.GetBuffer(),
|
||||
(int)UnderlyingStream.Position
|
||||
);
|
||||
UnderlyingStream.Position += size;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fills the stream from the current position up to (capacity) with 0x00's
|
||||
/// </summary>
|
||||
public void Fill()
|
||||
{
|
||||
Fill(m_Capacity - UnderlyingStream.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a number of 0x00 byte values to the underlying stream.
|
||||
/// </summary>
|
||||
public void Fill(long length)
|
||||
{
|
||||
if (UnderlyingStream.Position == UnderlyingStream.Length)
|
||||
{
|
||||
UnderlyingStream.SetLength(UnderlyingStream.Length + length);
|
||||
UnderlyingStream.Seek(0, SeekOrigin.End);
|
||||
}
|
||||
else
|
||||
{
|
||||
UnderlyingStream.Write(new byte[length], 0, (int)length);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Offsets the current position from an origin.
|
||||
/// </summary>
|
||||
public long Seek(long offset, SeekOrigin origin) => UnderlyingStream.Seek(offset, origin);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the entire stream content as a byte array.
|
||||
/// </summary>
|
||||
public byte[] ToArray() => UnderlyingStream.ToArray();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
using BenchmarkDotNet.Attributes;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using Server.Random;
|
||||
|
||||
namespace Benchmarks.Benchmarks.Rng
|
||||
{
|
||||
[MemoryDiagnoser]
|
||||
[SimpleJob(RuntimeMoniker.Net60)]
|
||||
public class BenchmarkDoubleVsFixed
|
||||
{
|
||||
private Xoshiro256PlusPlus _xoshiro256PlusPlus;
|
||||
|
||||
[GlobalSetup]
|
||||
public void Setup()
|
||||
{
|
||||
_xoshiro256PlusPlus = new Xoshiro256PlusPlus();
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public bool NextDouble() => 50.1 < _xoshiro256PlusPlus.NextDouble() * 100;
|
||||
|
||||
[Benchmark]
|
||||
public bool NextFixedInt() => 501 < _xoshiro256PlusPlus.Next(1000);
|
||||
|
||||
[Benchmark]
|
||||
public bool NextHighResDouble() => 50.1 < _xoshiro256PlusPlus.NextDoubleHighRes() * 100;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
using System;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using Server.Random;
|
||||
|
||||
namespace Benchmarks.Benchmarks.Rng
|
||||
{
|
||||
[MemoryDiagnoser]
|
||||
[SimpleJob(RuntimeMoniker.Net60)]
|
||||
public class BenchmarkXoshiro
|
||||
{
|
||||
private Random _random;
|
||||
private Xoshiro256PlusPlus _xoshiro256PlusPlus;
|
||||
|
||||
[GlobalSetup]
|
||||
public void Setup()
|
||||
{
|
||||
_xoshiro256PlusPlus = new Xoshiro256PlusPlus();
|
||||
_random = new Random();
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public int SystemRandomULong() => _random.Next(10000);
|
||||
|
||||
[Benchmark]
|
||||
public int XoshiroRandomULong() => _xoshiro256PlusPlus.Next(10000);
|
||||
|
||||
[Benchmark]
|
||||
public double SystemRandomDouble() => _random.NextDouble();
|
||||
|
||||
[Benchmark]
|
||||
public double XoshiroRandomDouble() => _xoshiro256PlusPlus.NextDouble();
|
||||
|
||||
[Benchmark]
|
||||
public int SystemRandomMinMax() => _random.Next(5000, 85000);
|
||||
|
||||
[Benchmark]
|
||||
public int XoshiroRandomMinMax()
|
||||
{
|
||||
const int min = 5000;
|
||||
const int max = 85000;
|
||||
|
||||
return min + (int)_xoshiro256PlusPlus.Next((uint)(max - min + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
using BenchmarkDotNet.Attributes;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using Server.Text;
|
||||
|
||||
namespace Benchmarks.BenchmarkText
|
||||
{
|
||||
[MemoryDiagnoser]
|
||||
[SimpleJob(RuntimeMoniker.Net60)]
|
||||
public class BenchmarkTextEncoding
|
||||
{
|
||||
private const string text =
|
||||
"This is supposed to be a really long text Ƞă¼ÖƄŭȘú😅¥♓ǵDƤĂ😋ġǁ⚕😐'ƿī😪_l" +
|
||||
"This is supposed to be a really long text Ƞă¼ÖƄŭȘú😅¥♓ǵDƤĂ😋ġǁ⚕😐'ƿī😪_l" +
|
||||
"This is supposed to be a really long text Ƞă¼ÖƄŭȘú😅¥♓ǵDƤĂ😋ġǁ⚕😐'ƿī😪_l" +
|
||||
"This is supposed to be a really long text Ƞă¼ÖƄŭȘú😅¥♓ǵDƤĂ😋ġǁ⚕😐'ƿī😪_l" +
|
||||
"This is supposed to be a really long text Ƞă¼ÖƄŭȘú😅¥♓ǵDƤĂ😋ġǁ⚕😐'ƿī😪_l";
|
||||
|
||||
[Benchmark]
|
||||
public byte[] TestEncodingOldReturnBytes()
|
||||
{
|
||||
var bytes = TextEncoding.UTF8.GetBytes(text);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public byte[] TestEncodingNewReturnBytes()
|
||||
{
|
||||
var bytes = text.GetBytesUtf8();
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,96 +0,0 @@
|
|||
using System;
|
||||
using System.Threading;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
[MemoryDiagnoser]
|
||||
[SimpleJob(RuntimeMoniker.Net60, warmupCount: 20, targetCount: 20)]
|
||||
public class BenchmarkTimerExecutions
|
||||
{
|
||||
private const int timerCount = 1000;
|
||||
private CancellationTokenSource _cancellationTokenSource;
|
||||
private static SemaphoreSlim _slim;
|
||||
|
||||
[GlobalSetup]
|
||||
public void Setup()
|
||||
{
|
||||
Core.Profiling = false;
|
||||
Timer.Init(0);
|
||||
|
||||
RUOTimer.TimerThread ttObj = new RUOTimer.TimerThread();
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
var timerThread = new Thread(() => ttObj.TimerMain(_cancellationTokenSource.Token))
|
||||
{
|
||||
Name = "Timer Thread"
|
||||
};
|
||||
|
||||
timerThread.Start();
|
||||
}
|
||||
|
||||
[GlobalCleanup]
|
||||
public void Cleanup()
|
||||
{
|
||||
RUOTimer.TimerThread.Set();
|
||||
_cancellationTokenSource.Cancel();
|
||||
RUOTimer.TimerThread.CleanupForTesting();
|
||||
Timer.ClearAllTimers(0);
|
||||
GC.Collect();
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void RUOTimerExecutions()
|
||||
{
|
||||
_slim = new SemaphoreSlim(1);
|
||||
|
||||
for (var i = 0; i < timerCount; i++)
|
||||
{
|
||||
new TestRUOTimer(TimeSpan.FromMilliseconds(1), i).Start();
|
||||
}
|
||||
|
||||
RUOTimer.TimerThread.m_TickCount += 8;
|
||||
RUOTimer.TimerThread.Set();
|
||||
_slim.Wait();
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void MUOTimerExecutions()
|
||||
{
|
||||
for (var i = 0; i < timerCount; i++)
|
||||
{
|
||||
new TestMUOTimer(TimeSpan.FromMilliseconds(1), i).Start();
|
||||
}
|
||||
|
||||
Timer.Slice(8);
|
||||
}
|
||||
|
||||
public class TestRUOTimer : RUOTimer
|
||||
{
|
||||
private int _amount;
|
||||
|
||||
public TestRUOTimer(TimeSpan delay, int amount) : base(delay) => _amount = amount;
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
var b = 6 * _amount;
|
||||
if (_amount == timerCount - 1)
|
||||
{
|
||||
_slim.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class TestMUOTimer : Timer
|
||||
{
|
||||
private int _amount;
|
||||
|
||||
public TestMUOTimer(TimeSpan delay, int amount) : base(delay) => _amount = amount;
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
var b = 6 * _amount;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
using System;
|
||||
using System.Threading;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
[MemoryDiagnoser]
|
||||
[SimpleJob(RuntimeMoniker.Net60, warmupCount: 20, targetCount: 20)]
|
||||
public class BenchmarkTimerInserts
|
||||
{
|
||||
private const int timerCount = 1000;
|
||||
private CancellationTokenSource _cancellationTokenSource;
|
||||
|
||||
[GlobalSetup]
|
||||
public void Setup()
|
||||
{
|
||||
Core.Profiling = false;
|
||||
Timer.Init(0);
|
||||
|
||||
RUOTimer.TimerThread ttObj = new RUOTimer.TimerThread();
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
var timerThread = new Thread(() => ttObj.TimerMain(_cancellationTokenSource.Token))
|
||||
{
|
||||
Name = "Timer Thread"
|
||||
};
|
||||
|
||||
timerThread.Start();
|
||||
}
|
||||
|
||||
[GlobalCleanup]
|
||||
public void Cleanup()
|
||||
{
|
||||
_cancellationTokenSource.Cancel();
|
||||
RUOTimer.TimerThread.Set();
|
||||
RUOTimer.TimerThread.CleanupForTesting();
|
||||
Timer.ClearAllTimers(0);
|
||||
GC.Collect();
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void RUOTimerInserts()
|
||||
{
|
||||
for (var i = 0; i < timerCount; i++)
|
||||
{
|
||||
new RUOTimer(TimeSpan.Zero).Start();
|
||||
}
|
||||
RUOTimer.TimerThread.Set();
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void MUOTimerInserts()
|
||||
{
|
||||
for (var i = 0; i < timerCount; i++)
|
||||
{
|
||||
new Timer(TimeSpan.Zero).Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,495 +0,0 @@
|
|||
/***************************************************************************
|
||||
* Timer.cs
|
||||
* -------------------
|
||||
* begin : May 1, 2002
|
||||
* copyright : (C) The RunUO Software Team
|
||||
* email : info@runuo.com
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using Server.Diagnostics;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public enum TimerPriority
|
||||
{
|
||||
EveryTick,
|
||||
TenMS,
|
||||
TwentyFiveMS,
|
||||
FiftyMS,
|
||||
TwoFiftyMS,
|
||||
OneSecond,
|
||||
FiveSeconds,
|
||||
OneMinute
|
||||
}
|
||||
|
||||
public class RUOTimer
|
||||
{
|
||||
private long m_Next;
|
||||
private long m_Delay;
|
||||
private long m_Interval;
|
||||
private bool m_Running;
|
||||
private int m_Index, m_Count;
|
||||
private TimerPriority m_Priority;
|
||||
private List<RUOTimer> m_List;
|
||||
private bool m_PrioritySet;
|
||||
|
||||
private static string FormatDelegate( Delegate callback )
|
||||
{
|
||||
if ( callback == null )
|
||||
{
|
||||
return "null";
|
||||
}
|
||||
|
||||
return String.Format( "{0}.{1}", callback.Method.DeclaringType.FullName, callback.Method.Name );
|
||||
}
|
||||
|
||||
public TimerPriority Priority
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Priority;
|
||||
}
|
||||
set
|
||||
{
|
||||
if ( !m_PrioritySet )
|
||||
{
|
||||
m_PrioritySet = true;
|
||||
}
|
||||
|
||||
if ( m_Priority != value )
|
||||
{
|
||||
m_Priority = value;
|
||||
|
||||
if ( m_Running )
|
||||
{
|
||||
TimerThread.PriorityChange( this, (int)m_Priority );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public DateTime Next
|
||||
{
|
||||
// Obnoxious
|
||||
get { return DateTime.UtcNow + TimeSpan.FromMilliseconds(m_Next-TimerThread.m_TickCount); }
|
||||
}
|
||||
|
||||
public TimeSpan Delay
|
||||
{
|
||||
get { return TimeSpan.FromMilliseconds(m_Delay); }
|
||||
set { m_Delay = (long)value.TotalMilliseconds; }
|
||||
}
|
||||
|
||||
public TimeSpan Interval
|
||||
{
|
||||
get { return TimeSpan.FromMilliseconds(m_Interval); }
|
||||
set { m_Interval = (long)value.TotalMilliseconds; }
|
||||
}
|
||||
|
||||
public bool Running
|
||||
{
|
||||
get { return m_Running; }
|
||||
set {
|
||||
if ( value ) {
|
||||
Start();
|
||||
} else {
|
||||
Stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public TimerProfile GetProfile()
|
||||
{
|
||||
if ( !Core.Profiling ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
string name = ToString();
|
||||
|
||||
if ( name == null ) {
|
||||
name = "null";
|
||||
}
|
||||
|
||||
return TimerProfile.Acquire( name );
|
||||
}
|
||||
|
||||
public class TimerThread
|
||||
{
|
||||
public static long m_TickCount; // Mimics core tick count for testing
|
||||
|
||||
private static Dictionary<RUOTimer,TimerChangeEntry> m_Changed = new Dictionary<RUOTimer,TimerChangeEntry>();
|
||||
|
||||
private static long[] m_NextPriorities = new long[8];
|
||||
private static long[] m_PriorityDelays = new long[8]
|
||||
{
|
||||
0,
|
||||
10,
|
||||
25,
|
||||
50,
|
||||
250,
|
||||
1000,
|
||||
5000,
|
||||
60000
|
||||
};
|
||||
|
||||
private static List<RUOTimer>[] m_Timers = new List<RUOTimer>[8]
|
||||
{
|
||||
new List<RUOTimer>(),
|
||||
new List<RUOTimer>(),
|
||||
new List<RUOTimer>(),
|
||||
new List<RUOTimer>(),
|
||||
new List<RUOTimer>(),
|
||||
new List<RUOTimer>(),
|
||||
new List<RUOTimer>(),
|
||||
new List<RUOTimer>(),
|
||||
};
|
||||
|
||||
private class TimerChangeEntry
|
||||
{
|
||||
public RUOTimer MRuoTimer;
|
||||
public int m_NewIndex;
|
||||
public bool m_IsAdd;
|
||||
|
||||
private TimerChangeEntry( RUOTimer t, int newIndex, bool isAdd )
|
||||
{
|
||||
MRuoTimer = t;
|
||||
m_NewIndex = newIndex;
|
||||
m_IsAdd = isAdd;
|
||||
}
|
||||
|
||||
public void Free()
|
||||
{
|
||||
lock (m_InstancePool) {
|
||||
if (m_InstancePool.Count < 200) // Arbitrary
|
||||
{
|
||||
m_InstancePool.Enqueue( this );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Queue<TimerChangeEntry> m_InstancePool = new Queue<TimerChangeEntry>();
|
||||
|
||||
public static TimerChangeEntry GetInstance( RUOTimer t, int newIndex, bool isAdd )
|
||||
{
|
||||
TimerChangeEntry e = null;
|
||||
|
||||
lock (m_InstancePool) {
|
||||
if ( m_InstancePool.Count > 0 ) {
|
||||
e = m_InstancePool.Dequeue();
|
||||
}
|
||||
}
|
||||
|
||||
if (e != null) {
|
||||
e.MRuoTimer = t;
|
||||
e.m_NewIndex = newIndex;
|
||||
e.m_IsAdd = isAdd;
|
||||
} else {
|
||||
e = new TimerChangeEntry( t, newIndex, isAdd );
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
public TimerThread()
|
||||
{
|
||||
}
|
||||
|
||||
public static void Change( RUOTimer t, int newIndex, bool isAdd )
|
||||
{
|
||||
lock (m_Changed)
|
||||
{
|
||||
m_Changed[t] = TimerChangeEntry.GetInstance(t, newIndex, isAdd);
|
||||
}
|
||||
|
||||
m_Signal.Set();
|
||||
}
|
||||
|
||||
public static void AddTimer( RUOTimer t )
|
||||
{
|
||||
Change( t, (int)t.Priority, true );
|
||||
}
|
||||
|
||||
public static void PriorityChange( RUOTimer t, int newPrio )
|
||||
{
|
||||
Change( t, newPrio, false );
|
||||
}
|
||||
|
||||
public static void RemoveTimer( RUOTimer t )
|
||||
{
|
||||
Change( t, -1, false );
|
||||
}
|
||||
|
||||
private static void ProcessChanged()
|
||||
{
|
||||
lock (m_Changed) {
|
||||
long curTicks = m_TickCount;
|
||||
|
||||
foreach (TimerChangeEntry tce in m_Changed.Values) {
|
||||
RUOTimer ruoTimer = tce.MRuoTimer;
|
||||
int newIndex = tce.m_NewIndex;
|
||||
|
||||
if (ruoTimer.m_List != null)
|
||||
{
|
||||
ruoTimer.m_List.Remove(ruoTimer);
|
||||
}
|
||||
|
||||
if (tce.m_IsAdd) {
|
||||
ruoTimer.m_Next = curTicks + ruoTimer.m_Delay;
|
||||
ruoTimer.m_Index = 0;
|
||||
}
|
||||
|
||||
if (newIndex >= 0) {
|
||||
ruoTimer.m_List = m_Timers[newIndex];
|
||||
ruoTimer.m_List.Add(ruoTimer);
|
||||
} else {
|
||||
ruoTimer.m_List = null;
|
||||
}
|
||||
|
||||
tce.Free();
|
||||
}
|
||||
|
||||
m_Changed.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public static void CleanupForTesting()
|
||||
{
|
||||
lock (m_Changed)
|
||||
{
|
||||
m_Changed.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
private static AutoResetEvent m_Signal = new AutoResetEvent( false );
|
||||
public static void Set() { m_Signal.Set(); }
|
||||
|
||||
public void TimerMain(CancellationToken cancellationToken)
|
||||
{
|
||||
long now;
|
||||
int i, j;
|
||||
bool loaded;
|
||||
|
||||
while ( !cancellationToken.IsCancellationRequested )
|
||||
{
|
||||
ProcessChanged();
|
||||
|
||||
loaded = false;
|
||||
|
||||
for ( i = 0; i < m_Timers.Length; i++)
|
||||
{
|
||||
now = m_TickCount;
|
||||
if ( now < m_NextPriorities[i] )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
m_NextPriorities[i] = now + m_PriorityDelays[i];
|
||||
|
||||
for ( j = 0; j < m_Timers[i].Count; j++)
|
||||
{
|
||||
RUOTimer t = m_Timers[i][j];
|
||||
|
||||
if ( !t.m_Queued && now > t.m_Next )
|
||||
{
|
||||
t.m_Queued = true;
|
||||
|
||||
lock ( m_Queue )
|
||||
{
|
||||
m_Queue.Enqueue( t );
|
||||
}
|
||||
|
||||
loaded = true;
|
||||
|
||||
if ( t.m_Count != 0 && (++t.m_Index >= t.m_Count) )
|
||||
{
|
||||
t.Stop();
|
||||
}
|
||||
else
|
||||
{
|
||||
t.m_Next = now + t.m_Interval;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( loaded )
|
||||
{
|
||||
// Core.Set();
|
||||
}
|
||||
|
||||
m_Signal.WaitOne(-1, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Queue<RUOTimer> m_Queue = new Queue<RUOTimer>();
|
||||
private static int m_BreakCount = 20000;
|
||||
|
||||
public static int BreakCount{ get{ return m_BreakCount; } set{ m_BreakCount = value; } }
|
||||
|
||||
private static int m_QueueCountAtSlice;
|
||||
|
||||
private bool m_Queued;
|
||||
|
||||
public static void Slice()
|
||||
{
|
||||
lock ( m_Queue )
|
||||
{
|
||||
m_QueueCountAtSlice = m_Queue.Count;
|
||||
|
||||
int index = 0;
|
||||
|
||||
while ( index < m_BreakCount && m_Queue.Count != 0 )
|
||||
{
|
||||
RUOTimer t = m_Queue.Dequeue();
|
||||
TimerProfile prof = t.GetProfile();
|
||||
|
||||
if ( prof != null ) {
|
||||
prof.Start();
|
||||
}
|
||||
|
||||
t.OnTick();
|
||||
t.m_Queued = false;
|
||||
++index;
|
||||
|
||||
if ( prof != null ) {
|
||||
prof.Finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public RUOTimer( TimeSpan delay ) : this( delay, TimeSpan.Zero, 1 )
|
||||
{
|
||||
}
|
||||
|
||||
public RUOTimer( TimeSpan delay, TimeSpan interval ) : this( delay, interval, 0 )
|
||||
{
|
||||
}
|
||||
|
||||
public virtual bool DefRegCreation
|
||||
{
|
||||
get{ return true; }
|
||||
}
|
||||
|
||||
public void RegCreation()
|
||||
{
|
||||
TimerProfile prof = GetProfile();
|
||||
|
||||
if ( prof != null ) {
|
||||
prof.Created++;
|
||||
}
|
||||
}
|
||||
|
||||
public RUOTimer( TimeSpan delay, TimeSpan interval, int count )
|
||||
{
|
||||
m_Delay = (long)delay.TotalMilliseconds;
|
||||
m_Interval = (long)interval.TotalMilliseconds;
|
||||
m_Count = count;
|
||||
|
||||
if ( !m_PrioritySet ) {
|
||||
if ( count == 1 ) {
|
||||
m_Priority = ComputePriority( delay );
|
||||
} else {
|
||||
m_Priority = ComputePriority( interval );
|
||||
}
|
||||
m_PrioritySet = true;
|
||||
}
|
||||
|
||||
if ( DefRegCreation )
|
||||
{
|
||||
RegCreation();
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return GetType().FullName;
|
||||
}
|
||||
|
||||
public static TimerPriority ComputePriority( TimeSpan ts )
|
||||
{
|
||||
if ( ts >= TimeSpan.FromMinutes( 1.0 ) )
|
||||
{
|
||||
return TimerPriority.FiveSeconds;
|
||||
}
|
||||
|
||||
if ( ts >= TimeSpan.FromSeconds( 10.0 ) )
|
||||
{
|
||||
return TimerPriority.OneSecond;
|
||||
}
|
||||
|
||||
if ( ts >= TimeSpan.FromSeconds( 5.0 ) )
|
||||
{
|
||||
return TimerPriority.TwoFiftyMS;
|
||||
}
|
||||
|
||||
if ( ts >= TimeSpan.FromSeconds( 2.5 ) )
|
||||
{
|
||||
return TimerPriority.FiftyMS;
|
||||
}
|
||||
|
||||
if ( ts >= TimeSpan.FromSeconds( 1.0 ) )
|
||||
{
|
||||
return TimerPriority.TwentyFiveMS;
|
||||
}
|
||||
|
||||
if ( ts >= TimeSpan.FromSeconds( 0.5 ) )
|
||||
{
|
||||
return TimerPriority.TenMS;
|
||||
}
|
||||
|
||||
return TimerPriority.EveryTick;
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
if ( !m_Running )
|
||||
{
|
||||
m_Running = true;
|
||||
TimerThread.AddTimer( this );
|
||||
|
||||
TimerProfile prof = GetProfile();
|
||||
|
||||
if ( prof != null ) {
|
||||
prof.Started++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
if ( m_Running )
|
||||
{
|
||||
m_Running = false;
|
||||
TimerThread.RemoveTimer( this );
|
||||
|
||||
TimerProfile prof = GetProfile();
|
||||
|
||||
if ( prof != null ) {
|
||||
prof.Stopped++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnTick()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,87 +0,0 @@
|
|||
using System.Buffers;
|
||||
using System.Text;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using Server.Buffers;
|
||||
|
||||
namespace Benchmarks.BenchmarkUtilities
|
||||
{
|
||||
[MemoryDiagnoser]
|
||||
[SimpleJob(RuntimeMoniker.Net60)]
|
||||
public class BenchmarkStringHelpers
|
||||
{
|
||||
private readonly string[] names =
|
||||
{
|
||||
"Kamron", "Owyn", "Luthius", "Jaedan", "Vorspire", "other people",
|
||||
"Kamron-2", "Owyn-2", "Luthius-2", "Jaedan-2", "Vorspire-2", "other people too"
|
||||
};
|
||||
|
||||
private int length;
|
||||
|
||||
[GlobalSetup]
|
||||
public void Setup()
|
||||
{
|
||||
var chrs = ArrayPool<char>.Shared.Rent(65535);
|
||||
ArrayPool<char>.Shared.Return(chrs);
|
||||
length = 0;
|
||||
|
||||
for (int i = 0; i < names.Length; i++)
|
||||
{
|
||||
length += names.Length;
|
||||
}
|
||||
|
||||
length += 2 * (names.Length - 1) + 3;
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public string BenchmarkStringBuilder()
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
for (var i = 0; i < names.Length; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
sb.Append(i == names.Length - 1 ? ", and" : ", ");
|
||||
}
|
||||
|
||||
sb.Append(names[i]);
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public string BenchmarkValueStringBuilderWithStack()
|
||||
{
|
||||
using var sb = new ValueStringBuilder(stackalloc char[length]);
|
||||
for (var i = 0; i < names.Length; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
sb.Append(i == names.Length - 1 ? ", and" : ", ");
|
||||
}
|
||||
|
||||
sb.Append(names[i]);
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public string BenchmarkValueStringBuilderWithRentedBuffer()
|
||||
{
|
||||
using var sb = new ValueStringBuilder(stackalloc char[32]);
|
||||
for (var i = 0; i < names.Length; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
sb.Append(i == names.Length - 1 ? ", and" : ", ");
|
||||
}
|
||||
|
||||
sb.Append(names[i]);
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
<Project>
|
||||
<!-- Only here so that the default Directory.Build.props will not be used. -->
|
||||
</Project>
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
using BenchmarkDotNet.Running;
|
||||
using Benchmarks.EntitiesSelectors;
|
||||
using Benchmarks.ItemSelectors;
|
||||
using Benchmarks.MobileSelectors;
|
||||
using Benchmarks.MultiSelectors;
|
||||
using Benchmarks.MultiTilesSelectors;
|
||||
using Server;
|
||||
|
||||
namespace Benchmarks
|
||||
{
|
||||
public static class Program
|
||||
{
|
||||
private static void Main(string[] args)
|
||||
{
|
||||
// var featureFlags = BenchmarkRunner.Run<BenchmarkFeatureFlags>();
|
||||
// var packetConstruction = BenchmarkRunner.Run<BenchmarkPacketConstruction>();
|
||||
// var broadcast = BenchmarkRunner.Run<BenchmarkPacketBroadcast>();
|
||||
// var stringHelpers = BenchmarkRunner.Run<BenchmarkStringHelpers>();
|
||||
// var indexList = BenchmarkRunner.Run<BenchmarkOrderedHashSet>();
|
||||
// var textEncoding = BenchmarkRunner.Run<BenchmarkTextEncoding>();
|
||||
// var logging = BenchmarkRunner.Run<BenchmarkConsoleLogging>();
|
||||
// var gumpPacket = BenchmarkRunner.Run<OutgoingGumpPacketBenchmarks>();
|
||||
// var rngTest = BenchmarkRunner.Run<BenchmarkXoshiro>();
|
||||
//var doubleRngText = BenchmarkRunner.Run<BenchmarkDoubleVsFixed>();
|
||||
|
||||
//var mapEntitiesSelectors = BenchmarkRunner.Run<MapEntitiesSelectors>();
|
||||
//var mapMobilesSelectors = BenchmarkRunner.Run<MapMobileSelectors>();
|
||||
//var mapMultiTilesSelectors = BenchmarkRunner.Run<MapMultiTilesSelectors>();
|
||||
//var mapMultiSelectors = BenchmarkRunner.Run<MapMultiSelectors>();
|
||||
// var mapItemsSelectors = BenchmarkRunner.Run<MapItemSelectors>();
|
||||
// var stArray = BenchmarkRunner.Run<BenchmarkSTArray>();
|
||||
// var pooledRefQueue = BenchmarkRunner.Run<BenchmarkPooledRefQueue>();
|
||||
|
||||
var timerInsertionTest = BenchmarkRunner.Run<BenchmarkTimerInserts>();
|
||||
// var timerExecutionTest = BenchmarkRunner.Run<BenchmarkTimerExecutions>();
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue