Skip to content

Commit

Permalink
Add some small performance tests for path access and slightly improve…
Browse files Browse the repository at this point in the history
… the "GetValue" call when the root path doesn't exist
  • Loading branch information
kennyvv committed Oct 23, 2023
1 parent a49025e commit 0b08914
Show file tree
Hide file tree
Showing 2 changed files with 157 additions and 16 deletions.
117 changes: 117 additions & 0 deletions src/MolangSharp.Tests/PerformanceTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
using System.Diagnostics;
using ConcreteMC.MolangSharp.Parser;
using ConcreteMC.MolangSharp.Runtime;
using ConcreteMC.MolangSharp.Runtime.Exceptions;
using ConcreteMC.MolangSharp.Runtime.Value;
using ConcreteMC.MolangSharp.Utils;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace ConcreteMC.MolangSharp.Tests;

[TestClass]
public class PerformanceTest
{
private Stopwatch _sw;
private MoLangEnvironment _environment;
private MoLangRuntime _runtime;

[TestInitialize]
public void Init()
{
_sw = new Stopwatch();
_environment = new MoLangEnvironment();
_runtime = new MoLangRuntime(_environment);

_environment.SetValue(new MoPath("variable.test"), DoubleValue.One);

MoLangRuntimeConfiguration.UseDummyValuesInsteadOfExceptions = false;
MoLangRuntimeConfiguration.UseMoLangStackTrace = true;
}

[TestMethod]
public void TestVariableReadingMath()
{
const int iterations = 5000000;
long total = 0;

var expression = MoLangParser.Parse("return variable.test * 20");
for (int i = 0; i < iterations; i++)
{
_sw.Restart();
var a = _runtime.Execute(expression);
total += _sw.ElapsedMilliseconds;
Assert.AreEqual(20, a.AsDouble());
}

Debug.WriteLine($"Average: {((double)total / iterations):N10}ms");
}

[TestMethod]
public void TestVariableReading()
{
const int iterations = 5000000;
long total = 0;

var expression = MoLangParser.Parse("return variable.test");
for (int i = 0; i < iterations; i++)
{
_sw.Restart();
var a = _runtime.Execute(expression);
total += _sw.ElapsedMilliseconds;
Assert.AreEqual(1, a.AsDouble());
}

Debug.WriteLine($"Average: {((double)total / iterations):N10}ms");
}

[TestMethod]
public void TestVariableWriting()
{
const int iterations = 5000000;
long total = 0;

var expression = MoLangParser.Parse("variable.test = 20");
for (int i = 0; i < iterations; i++)
{
_sw.Restart();
_runtime.Execute(expression);
total += _sw.ElapsedMilliseconds;
}

Debug.WriteLine($"Average: {((double)total / iterations):N10}ms");
}

[TestMethod]
public void TestInvalidPathPerformance()
{
const int iterations = 50000;
long total = 0;

var expression = MoLangParser.Parse("return fr.test");
for (int i = 0; i < iterations; i++)
{
_sw.Restart();

try
{
_runtime.Execute(expression);
}
catch
{

}
total += _sw.ElapsedMilliseconds;
}

Debug.WriteLine($"Average: {((double)total / iterations):N10}ms");
}

[TestMethod]
public void TestDummyValuesConfiguration()
{
var expression = MoLangParser.Parse("return fr.test");
MoLangRuntimeConfiguration.UseDummyValuesInsteadOfExceptions = true;
var result = _runtime.Execute(expression);
Assert.AreEqual(0d, result.AsDouble());
}
}
56 changes: 40 additions & 16 deletions src/MolangSharp/Runtime/MoLangEnvironment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,17 @@ public class MoLangEnvironment : IMoValue
/// <inheritdoc />
public object Value => Structs;

/// <summary>
/// The available root paths
/// </summary>
/// <remarks>
/// Contains the following root structs by default: <br/>
/// math.<br/>
/// temp.<br/>
/// variable. <br/>
/// array.<br/>
/// context.
/// </remarks>
public Dictionary<string, IMoStruct> Structs { get; } =
new Dictionary<string, IMoStruct>(StringComparer.OrdinalIgnoreCase);

Expand All @@ -39,41 +50,54 @@ public MoLangEnvironment()
Structs.TryAdd("context", new ContextStruct());
}

public IMoValue GetValue(MoPath name)
/// <summary>
/// Get a MoLang variable by it's path
/// </summary>
/// <param name="path">The path to access</param>
/// <returns>The variable at specified path</returns>
public IMoValue GetValue(MoPath path)
{
return GetValue(name, MoParams.Empty);
return GetValue(path, MoParams.Empty);
}

public IMoValue GetValue(MoPath name, MoParams param)
/// <summary>
/// Get a MoLang variable by it's path and specified parameters
/// </summary>
/// <param name="path">The path to access</param>
/// <returns>The variable at specified path</returns>
public IMoValue GetValue(MoPath path, MoParams param)
{
try
if (!Structs.TryGetValue(path.Value, out var v))
{
return Structs[name.Value].Get(name.Next, param);
}
catch (Exception ex)
{
// Experimental
if (MoLangRuntimeConfiguration.UseDummyValuesInsteadOfExceptions)
return DoubleValue.Zero;

throw new MoLangRuntimeException($"Cannot retrieve struct: {name}", ex);
throw new MoLangRuntimeException($"Invalid path: {path.Path}");
}

return v.Get(path.Next, param);
}

public void SetValue(MoPath name, IMoValue value)
/// <summary>
/// Set a MoLang variable by its path
/// </summary>
/// <param name="path"></param>
/// <param name="value"></param>
/// <exception cref="MoLangRuntimeException"></exception>
public void SetValue(MoPath path, IMoValue value)
{
if (!Structs.TryGetValue(name.Value, out var v))
if (!Structs.TryGetValue(path.Value, out var v))
{
throw new MoLangRuntimeException($"Invalid path: {name.Path}", null);
throw new MoLangRuntimeException($"Invalid path: {path.Path}", null);
}

try
{
v.Set(name.Next, value);
v.Set(path.Next, value);
}
catch (Exception ex)
{
throw new MoLangRuntimeException($"Cannot set value on struct: {name}", ex);
throw new MoLangRuntimeException($"Cannot set value on struct: {path}", ex);
}
}

Expand Down

0 comments on commit 0b08914

Please sign in to comment.