Skip to content

Commit

Permalink
[Add] 132 use stackalloc or the new params collection + getalternatel…
Browse files Browse the repository at this point in the history
…ookup to avoid array allocations in propertiesextensions (#146)

* Reduce number of array allocations

* Use C# params collections + collection expression feature

---------

Co-authored-by: Apollo3zehn <[email protected]>
  • Loading branch information
Apollo3zehn and Apollo3zehn authored Aug 8, 2024
1 parent 0b49363 commit 8c75990
Show file tree
Hide file tree
Showing 10 changed files with 33 additions and 35 deletions.
2 changes: 1 addition & 1 deletion src/Nexus/API/CatalogsController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ public async Task<ActionResult<string?>>
if (license is null)
{
var catalogInfo = await catalogContainer.GetLazyCatalogInfoAsync(cancellationToken);
license = catalogInfo.Catalog.Properties?.GetStringValue([DataModelExtensions.LicenseKey]);
license = catalogInfo.Catalog.Properties?.GetStringValue(DataModelExtensions.LicenseKey);
}

return license;
Expand Down
7 changes: 5 additions & 2 deletions src/Nexus/Extensibility/DataSource/DataSourceController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ internal class DataSourceController(
DataOptions dataOptions,
ILogger<DataSourceController> logger) : IDataSourceController
{
private static readonly string[] _pipelinePositionPath = [DataModelExtensions.NEXUS_KEY, DataModelExtensions.PIPELINE_POSITION_KEY];

internal readonly IReadOnlyDictionary<string, JsonElement>? _requestConfiguration = requestConfiguration;

Expand Down Expand Up @@ -422,7 +421,11 @@ private async Task ReadOriginalAsync(
var currentReadRequests = readRequests
.Where(request =>
request.CatalogItem.Resource.Properties is null ||
request.CatalogItem.Resource.Properties.GetIntValue(_pipelinePositionPath) == pipelinePosition
request.CatalogItem.Resource.Properties
.GetIntValue(
DataModelExtensions.NEXUS_KEY,
DataModelExtensions.PIPELINE_POSITION_KEY
) == pipelinePosition
)
.ToArray();

Expand Down
4 changes: 2 additions & 2 deletions src/Nexus/Extensions/Sources/Sample.cs
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,8 @@ public async Task ReadAsync(
// check credentials
if (catalog.Id == RemoteCatalogId)
{
var user = Context.RequestConfiguration?.GetStringValue([typeof(Sample).FullName!, "user"]);
var password = Context.RequestConfiguration?.GetStringValue([typeof(Sample).FullName!, "password"]);
var user = Context.RequestConfiguration?.GetStringValue(typeof(Sample).FullName!, "user");
var password = Context.RequestConfiguration?.GetStringValue(typeof(Sample).FullName!, "password");

if (user != RemoteUsername || password != RemotePassword)
throw new Exception("The provided credentials are invalid.");
Expand Down
10 changes: 4 additions & 6 deletions src/Nexus/Extensions/Writers/Csv.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@ namespace Nexus.Writers;
"https://github.com/nexus-main/nexus/blob/master/src/Nexus/Extensions/Writers/Csv.cs")]
internal class Csv : IDataWriter, IDisposable
{
private static readonly string[] _unitPath = [DataModelExtensions.UnitKey];

private const string DESCRIPTION = """
{
"label":"CSV + Schema (*.csv)",
Expand Down Expand Up @@ -114,7 +112,7 @@ public async Task OpenAsync(

if (!_resourceMap.TryGetValue(resourceFilePath, out var resource))
{
var rowIndexFormat = Context.RequestConfiguration?.GetStringValue(["row-index-format"]) ?? "index";
var rowIndexFormat = Context.RequestConfiguration?.GetStringValue("row-index-format") ?? "index";
var constraints = new Constraints(Required: true);

var timestampField = rowIndexFormat switch
Expand Down Expand Up @@ -211,9 +209,9 @@ public async Task WriteAsync(TimeSpan fileOffset, WriteRequest[] requests, IProg
.GroupBy(request => request.CatalogItem.Catalog.Id)
.ToList();

var rowIndexFormat = Context.RequestConfiguration?.GetStringValue(["row-index-format"]) ?? "index";
var rowIndexFormat = Context.RequestConfiguration?.GetStringValue("row-index-format") ?? "index";

var significantFigures = int.Parse(Context.RequestConfiguration?.GetStringValue(["significant-figures"]) ?? "4");
var significantFigures = int.Parse(Context.RequestConfiguration?.GetStringValue("significant-figures") ?? "4");
significantFigures = Math.Clamp(significantFigures, 0, 30);

var groupIndex = 0;
Expand Down Expand Up @@ -307,7 +305,7 @@ private static void AppendWindowsNewLine(StringBuilder stringBuilder)
private static string GetFieldName(CatalogItem catalogItem)
{
var unit = catalogItem.Resource.Properties?
.GetStringValue(_unitPath);
.GetStringValue(DataModelExtensions.UnitKey);

var fieldName = $"{catalogItem.Resource.Id}_{catalogItem.Representation.Id}{DataModelUtilities.GetRepresentationParameterString(catalogItem.Parameters)}";

Expand Down
2 changes: 1 addition & 1 deletion src/Nexus/Services/AppStateManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ private void LoadDataWriters()
}

var additionalInformation = attribute.Description;
var label = (additionalInformation?.GetStringValue([UI.Core.Constants.DATA_WRITER_LABEL_KEY])) ?? throw new Exception($"The description of data writer {fullName} has no label property");
var label = (additionalInformation?.GetStringValue(UI.Core.Constants.DATA_WRITER_LABEL_KEY)) ?? throw new Exception($"The description of data writer {fullName} has no label property");
var version = dataWriterType.Assembly
.GetCustomAttribute<AssemblyInformationalVersionAttribute>()!
.InformationalVersion;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,18 +230,19 @@ IDataSource[] dataSources
var isModified = false;
var newResources = new List<Resource>();

string[] originalNamePath = [OriginalNameKey];
string[] pipelinePositionPath = [NEXUS_KEY, PIPELINE_POSITION_KEY];
string[] groupsPath = [GroupsKey];

foreach (var resource in catalog.Resources)
{
var resourceProperties = resource.Properties;
var newResource = resource;

var originalName = resourceProperties?.GetStringValue(originalNamePath);
var currentPipelinePosition = resourceProperties?.GetIntValue(pipelinePositionPath);
var groups = resourceProperties?.GetStringArray(groupsPath);
var originalName = resourceProperties?
.GetStringValue(OriginalNameKey);

var currentPipelinePosition = resourceProperties?
.GetIntValue(NEXUS_KEY, PIPELINE_POSITION_KEY);

var groups = resourceProperties?
.GetStringArray(GroupsKey);

var distinctGroups = groups is null
? default
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,8 @@ public static class PropertiesExtensions
/// <param name="properties">The properties.</param>
/// <param name="pathSegments">The propery path segments.</param>
/// <returns></returns>
public static string? GetStringValue(this IReadOnlyDictionary<string, JsonElement> properties, Span<string> pathSegments)
public static string? GetStringValue(this IReadOnlyDictionary<string, JsonElement> properties, params ReadOnlySpan<string> pathSegments)
{
// TODO Maybe use params collection (Span) in future? https://github.com/dotnet/csharplang/issues/7700

if (properties.TryGetValue(pathSegments[0], out var element))
{
pathSegments = pathSegments[1..];
Expand All @@ -44,7 +42,7 @@ public static class PropertiesExtensions
/// <param name="properties">The properties.</param>
/// <param name="pathSegments">The propery path segments.</param>
/// <returns></returns>
public static string? GetStringValue(this JsonElement properties, Span<string> pathSegments)
public static string? GetStringValue(this JsonElement properties, params ReadOnlySpan<string> pathSegments)
{
var root = properties.GetJsonObjectFromPath(pathSegments[0..^1]);
var propertyName = pathSegments[^1];
Expand All @@ -66,7 +64,7 @@ public static class PropertiesExtensions
/// <param name="properties">The properties.</param>
/// <param name="pathSegments">The property path segments.</param>
/// <returns></returns>
public static string?[]? GetStringArray(this IReadOnlyDictionary<string, JsonElement> properties, Span<string> pathSegments)
public static string?[]? GetStringArray(this IReadOnlyDictionary<string, JsonElement> properties, params ReadOnlySpan<string> pathSegments)
{
if (properties.TryGetValue(pathSegments[0], out var element))
{
Expand Down Expand Up @@ -96,7 +94,7 @@ public static class PropertiesExtensions
/// <param name="properties">The properties.</param>
/// <param name="pathSegments">The property path segments.</param>
/// <returns></returns>
public static string?[]? GetStringArray(this JsonElement properties, Span<string> pathSegments)
public static string?[]? GetStringArray(this JsonElement properties, params ReadOnlySpan<string> pathSegments)
{
var root = properties.GetJsonObjectFromPath(pathSegments[0..^1]);
var propertyName = pathSegments[^1];
Expand All @@ -116,7 +114,7 @@ public static class PropertiesExtensions
return default;
}

internal static int? GetIntValue(this IReadOnlyDictionary<string, JsonElement> properties, Span<string> pathSegments)
internal static int? GetIntValue(this IReadOnlyDictionary<string, JsonElement> properties, params ReadOnlySpan<string> pathSegments)
{
if (properties.TryGetValue(pathSegments[0], out var element))
{
Expand All @@ -132,7 +130,7 @@ public static class PropertiesExtensions
return default;
}

internal static int? GetIntValue(this JsonElement properties, Span<string> pathSegments)
internal static int? GetIntValue(this JsonElement properties, params ReadOnlySpan<string> pathSegments)
{
var root = properties.GetJsonObjectFromPath(pathSegments[0..^1]);
var propertyName = pathSegments[^1];
Expand All @@ -148,7 +146,7 @@ public static class PropertiesExtensions
return default;
}

private static JsonElement GetJsonObjectFromPath(this JsonElement root, Span<string> pathSegements)
private static JsonElement GetJsonObjectFromPath(this JsonElement root, ReadOnlySpan<string> pathSegements)
{
if (pathSegements.Length == 0)
return root;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,6 @@ internal bool TryFind(ResourcePathParseResult parseResult, [NotNullWhen(true)] o
}
}

string[] typePath = ["type"];

var parametersAreOK =

(representation.Parameters is null && parameters is null) ||
Expand All @@ -163,8 +161,8 @@ internal bool TryFind(ResourcePathParseResult parseResult, [NotNullWhen(true)] o

parameters.ContainsKey(current.Key) &&

(current.Value.GetStringValue(typePath) == "input-integer" && long.TryParse(parameters[current.Key], out var _) ||
current.Value.GetStringValue(typePath) == "select" /* no validation here */)));
(current.Value.GetStringValue("type") == "input-integer" && long.TryParse(parameters[current.Key], out var _) ||
current.Value.GetStringValue("type") == "select" /* no validation here */)));

if (!parametersAreOK)
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ internal class ReadRequestManager : IDisposable
public ReadRequestManager(CatalogItem catalogItem, int elementCount)
{
var byteCount = elementCount * catalogItem.Representation.ElementSize;
var originalResourceName = catalogItem.Resource.Properties!.GetStringValue([DataModelExtensions.OriginalNameKey])!;
var originalResourceName = catalogItem.Resource.Properties!.GetStringValue(DataModelExtensions.OriginalNameKey)!;

/* data memory */
var dataOwner = MemoryPool<byte>.Shared.Rent(byteCount);
Expand Down
4 changes: 2 additions & 2 deletions tests/Nexus.Tests/DataSource/SampleDataSourceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ public async Task ProvidesCatalog()

// assert
var actualIds = actual.Resources!.Select(resource => resource.Id).ToList();
var actualUnits = actual.Resources!.Select(resource => resource.Properties?.GetStringValue(["unit"])).ToList();
var actualGroups = actual.Resources!.SelectMany(resource => resource.Properties?.GetStringArray(["groups"]) ?? []);
var actualUnits = actual.Resources!.Select(resource => resource.Properties?.GetStringValue(DataModelExtensions.UnitKey)).ToList();
var actualGroups = actual.Resources!.SelectMany(resource => resource.Properties?.GetStringArray(DataModelExtensions.GroupsKey) ?? []);
var actualDataTypes = actual.Resources!.SelectMany(resource => resource.Representations!.Select(representation => representation.DataType)).ToList();

var expectedIds = new List<string>() { "T1", "V1", "unix_time1", "unix_time2" };
Expand Down

0 comments on commit 8c75990

Please sign in to comment.