chore: Removes benchmarks. (#985)

This commit is contained in:
Kamron Batman 2022-03-31 10:37:33 -07:00 committed by GitHub
parent fdcd6c80a8
commit 4d1ee21568
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 0 additions and 3977 deletions

View file

@ -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

View file

@ -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>

View file

@ -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();
}
}
}

View file

@ -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();
}
}
}
}
}

View file

@ -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);
}
}
}
}

View file

@ -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);
}
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -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);
}
}
}

View file

@ -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();
}
}

View file

@ -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;
}
}
}

View file

@ -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
}
}
}

View file

@ -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;
}
}

View file

@ -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();
}
}

View file

@ -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;
}
}

View file

@ -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));
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}
}

View file

@ -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();
}
}
}
}

View file

@ -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()
{
}
}
}

View file

@ -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();
}
}
}

View file

@ -1,3 +0,0 @@
<Project>
<!-- Only here so that the default Directory.Build.props will not be used. -->
</Project>

View file

@ -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>();
}
}
}