Skip to content

Commit

Permalink
Minor attribute cleanups for C# module (#1753)
Browse files Browse the repository at this point in the history
  • Loading branch information
RReverser authored Sep 27, 2024
1 parent ccd7e84 commit 6ba91bb
Show file tree
Hide file tree
Showing 7 changed files with 141 additions and 97 deletions.
7 changes: 4 additions & 3 deletions crates/bindings-csharp/BSATN.Codegen/Utils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -182,9 +182,10 @@ IEnumerable<T> values
_ => constant.Value,
};

public static T ParseAs<T>(this AttributeData attrData)
public static T ParseAs<T>(this AttributeData attrData, System.Type? type = null)
where T : Attribute
{
type ??= typeof(T);
var ctorArgs = attrData.ConstructorArguments.Select(ResolveConstant).ToArray();
// For now only support attributes with a single constructor.
//
Expand All @@ -193,10 +194,10 @@ public static T ParseAs<T>(this AttributeData attrData)
// which prevent APIs like `Activator.CreateInstance` from finding the constructor.
//
// Expand logic in the future if it ever becomes actually necessary.
var attr = (T)typeof(T).GetConstructors().Single().Invoke(ctorArgs);
var attr = (T)type.GetConstructors().Single().Invoke(ctorArgs);
foreach (var arg in attrData.NamedArguments)
{
typeof(T).GetProperty(arg.Key).SetValue(attr, ResolveConstant(arg.Value));
type.GetProperty(arg.Key).SetValue(attr, ResolveConstant(arg.Value));
}
return attr;
}
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

75 changes: 45 additions & 30 deletions crates/bindings-csharp/Codegen/Module.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,37 @@ namespace SpacetimeDB.Codegen;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using SpacetimeDB.Internal;
using static Utils;

readonly record struct ColumnAttr(ColumnAttrs Mask, string? Table = null)
{
private static readonly ImmutableDictionary<string, System.Type> AttrTypes = ImmutableArray
.Create(
typeof(AutoIncAttribute),
typeof(PrimaryKeyAttribute),
typeof(UniqueAttribute),
typeof(IndexedAttribute)
)
.ToImmutableDictionary(t => t.FullName);

public static ColumnAttr Parse(AttributeData attrData)
{
if (
attrData.AttributeClass is not { } attrClass
|| !AttrTypes.TryGetValue(attrClass.ToString(), out var attrType)
)
{
return default;
}
var attr = attrData.ParseAs<ColumnAttribute>(attrType);
return new(attr.Mask, attr.Table);
}
}

record ColumnDeclaration : MemberDeclaration
{
public readonly EquatableArray<(string? table, ColumnAttrs mask)> Attrs;
public readonly EquatableArray<ColumnAttr> Attrs;
public readonly bool IsEquatable;
public readonly string FullTableName;

Expand All @@ -22,11 +48,16 @@ bool isEquatable
)
: base(name, type, typeInfo)
{
Attrs = new(ImmutableArray.Create((default(string), attrs)));
Attrs = new(ImmutableArray.Create(new ColumnAttr(attrs)));
IsEquatable = isEquatable;
FullTableName = tableName;
}

// A helper to combine multiple column attributes into a single mask.
// Note: it doesn't check the table names, this is left up to the caller.
private static ColumnAttrs CombineColumnAttrs(IEnumerable<ColumnAttr> attrs) =>
attrs.Aggregate(ColumnAttrs.UnSet, (mask, attr) => mask | attr.Mask);

public ColumnDeclaration(string tableName, IFieldSymbol field)
: base(field)
{
Expand All @@ -35,21 +66,12 @@ public ColumnDeclaration(string tableName, IFieldSymbol field)
Attrs = new(
field
.GetAttributes()
.Select(a =>
(
table: a.NamedArguments.FirstOrDefault(a => a.Key == "Table").Value.Value
as string,
attr: a.AttributeClass?.ToString() switch
{
"SpacetimeDB.AutoIncAttribute" => ColumnAttrs.AutoInc,
"SpacetimeDB.PrimaryKeyAttribute" => ColumnAttrs.PrimaryKey,
"SpacetimeDB.UniqueAttribute" => ColumnAttrs.Unique,
"SpacetimeDB.IndexedAttribute" => ColumnAttrs.Indexed,
_ => ColumnAttrs.UnSet,
}
)
.Select(ColumnAttr.Parse)
.Where(a => a.Mask != ColumnAttrs.UnSet)
.GroupBy(
a => a.Table,
(key, group) => new ColumnAttr(CombineColumnAttrs(group), key)
)
.Where(a => a.attr != ColumnAttrs.UnSet)
.ToImmutableArray()
);

Expand All @@ -75,7 +97,7 @@ or SpecialType.System_Int64
_ => false,
};

var attrs = Attrs.Aggregate(ColumnAttrs.UnSet, (xs, x) => xs | x.mask);
var attrs = CombineColumnAttrs(Attrs);

if (attrs.HasFlag(ColumnAttrs.AutoInc) && !isInteger)
{
Expand Down Expand Up @@ -107,9 +129,7 @@ or SpecialType.System_Int64
}

public ColumnAttrs GetAttrs(string tableName) =>
Attrs
.Where(x => x.table == null || x.table == tableName)
.Aggregate(ColumnAttrs.UnSet, (xs, x) => xs | x.mask);
CombineColumnAttrs(Attrs.Where(x => x.Table == null || x.Table == tableName));

// For the `TableDesc` constructor.
public string GenerateColumnDef() =>
Expand All @@ -128,16 +148,11 @@ record TableView

public TableView(TableDeclaration table, AttributeData data)
{
Name =
data.NamedArguments.FirstOrDefault(x => x.Key == "Name").Value.Value as string
?? table.ShortName;

IsPublic = data.NamedArguments.Any(pair => pair is { Key: "Public", Value.Value: true });
var attr = data.ParseAs<TableAttribute>();

Scheduled = data
.NamedArguments.Where(pair => pair.Key == "Scheduled")
.Select(pair => (string?)pair.Value.Value)
.SingleOrDefault();
Name = attr.Name ?? table.ShortName;
IsPublic = attr.Public;
Scheduled = attr.Scheduled;
}
}

Expand Down Expand Up @@ -347,7 +362,7 @@ public override Scope.Extensions ToExtensions()
nameof({{ShortName}}),
{{tuple.pos}},
nameof({{tuple.col.Name}}),
(SpacetimeDB.ColumnAttrs){{(int)tuple.attr}}
SpacetimeDB.Internal.ColumnAttrs.{{tuple.attr}}
)
"""
)
Expand Down
130 changes: 72 additions & 58 deletions crates/bindings-csharp/Runtime/Attrs.cs
Original file line number Diff line number Diff line change
@@ -1,73 +1,87 @@
namespace SpacetimeDB;

[Flags]
public enum ColumnAttrs : byte
namespace SpacetimeDB
{
UnSet = 0b0000,
Indexed = 0b0001,
AutoInc = 0b0010,
Unique = Indexed | 0b0100,
Identity = Unique | AutoInc,
PrimaryKey = Unique | 0b1000,
PrimaryKeyAuto = PrimaryKey | AutoInc,
namespace Internal
{
[Flags]
public enum ColumnAttrs : byte
{
UnSet = 0b0000,
Indexed = 0b0001,
AutoInc = 0b0010,
Unique = Indexed | 0b0100,
Identity = Unique | AutoInc,
PrimaryKey = Unique | 0b1000,
PrimaryKeyAuto = PrimaryKey | AutoInc,
}

// A legacy alias, originally defined as `PrimaryKey | Identity` which is numerically same as above.
PrimaryKeyIdentity = PrimaryKeyAuto,
}
[AttributeUsage(AttributeTargets.Field)]
public abstract class ColumnAttribute : Attribute
{
public string? Table { get; init; }
internal abstract ColumnAttrs Mask { get; }
}
}

/// <summary>
/// Registers a type as the row structure of a SpacetimeDB table, enabling codegen for it.
///
/// <para>
/// Multiple [Table] attributes per type are supported. This is useful to reuse row types.
/// Each attribute instance must have a unique name and will create a SpacetimeDB table.
/// </para>
/// </summary>
[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class, AllowMultiple = true)]
public sealed class TableAttribute : Attribute
{
/// <summary>
/// This identifier is used to name the SpacetimeDB table on the host as well as the
/// table handle structures generated to access the table from within a reducer call.
/// Registers a type as the row structure of a SpacetimeDB table, enabling codegen for it.
///
/// <para>Defaults to the <c>nameof</c> of the target type.</para>
/// <para>
/// Multiple [Table] attributes per type are supported. This is useful to reuse row types.
/// Each attribute instance must have a unique name and will create a SpacetimeDB table.
/// </para>
/// </summary>
public string? Name { get; init; }
[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class, AllowMultiple = true)]
public sealed class TableAttribute : Attribute
{
/// <summary>
/// This identifier is used to name the SpacetimeDB table on the host as well as the
/// table handle structures generated to access the table from within a reducer call.
///
/// <para>Defaults to the <c>nameof</c> of the target type.</para>
/// </summary>
public string? Name { get; init; }

/// <summary>
/// Set to <c>true</c> to make the table visible to everyone.
///
/// <para>Defaults to the table only being visible to its owner.</para>
/// </summary>
public bool Public { get; init; } = false;
/// <summary>
/// Set to <c>true</c> to make the table visible to everyone.
///
/// <para>Defaults to the table only being visible to its owner.</para>
/// </summary>
public bool Public { get; init; } = false;

public string? Scheduled { get; init; }
}
public string? Scheduled { get; init; }
}

[AttributeUsage(AttributeTargets.Field)]
public abstract class ColumnAttribute : Attribute
{
public string? Table { get; init; }
}

public sealed class AutoIncAttribute : ColumnAttribute { }
public sealed class AutoIncAttribute : Internal.ColumnAttribute
{
internal override Internal.ColumnAttrs Mask => Internal.ColumnAttrs.AutoInc;
}

public sealed class PrimaryKeyAttribute : ColumnAttribute { }
public sealed class PrimaryKeyAttribute : Internal.ColumnAttribute
{
internal override Internal.ColumnAttrs Mask => Internal.ColumnAttrs.PrimaryKey;
}

public sealed class UniqueAttribute : ColumnAttribute { }
public sealed class UniqueAttribute : Internal.ColumnAttribute
{
internal override Internal.ColumnAttrs Mask => Internal.ColumnAttrs.Unique;
}

public sealed class IndexedAttribute : ColumnAttribute { }
public sealed class IndexedAttribute : Internal.ColumnAttribute
{
internal override Internal.ColumnAttrs Mask => Internal.ColumnAttrs.Indexed;
}

public static class ReducerKind
{
public const string Init = "__init__";
public const string Update = "__update__";
public const string Connect = "__identity_connected__";
public const string Disconnect = "__identity_disconnected__";
}
public static class ReducerKind
{
public const string Init = "__init__";
public const string Update = "__update__";
public const string Connect = "__identity_connected__";
public const string Disconnect = "__identity_disconnected__";
}

[AttributeUsage(AttributeTargets.Method, Inherited = false)]
public sealed class ReducerAttribute(string? name = null) : Attribute
{
public string? Name => name;
[AttributeUsage(AttributeTargets.Method, Inherited = false)]
public sealed class ReducerAttribute(string? name = null) : Attribute
{
public string? Name => name;
}
}
12 changes: 8 additions & 4 deletions crates/bindings-csharp/SpacetimeSharpSATS.sln
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spacetimedb-quickstart-serv
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "sdk-test-multi-cs", "..\..\modules\sdk-test-multi-cs\sdk-test-multi-cs.csproj", "{960384A9-D78F-4C07-986A-1D1F3846AEBE}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "sdk-tests", "sdk-tests", "{D39E8203-6C3C-4C4B-9C7D-7911AA19D7CC}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -53,25 +55,27 @@ Global
{2C282EBD-8E37-4F4C-8EE1-E91E21E75FEE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2C282EBD-8E37-4F4C-8EE1-E91E21E75FEE}.Release|Any CPU.Build.0 = Release|Any CPU
{5393711C-44B0-4752-B8D0-852C73D6866F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5393711C-44B0-4752-B8D0-852C73D6866F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5393711C-44B0-4752-B8D0-852C73D6866F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5393711C-44B0-4752-B8D0-852C73D6866F}.Release|Any CPU.Build.0 = Release|Any CPU
{40F1C615-EDD9-463F-A012-B232F6710FA5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{40F1C615-EDD9-463F-A012-B232F6710FA5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{40F1C615-EDD9-463F-A012-B232F6710FA5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{40F1C615-EDD9-463F-A012-B232F6710FA5}.Release|Any CPU.Build.0 = Release|Any CPU
{FDACD960-168E-44F9-B036-2E29EA391BE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FDACD960-168E-44F9-B036-2E29EA391BE7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FDACD960-168E-44F9-B036-2E29EA391BE7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FDACD960-168E-44F9-B036-2E29EA391BE7}.Release|Any CPU.Build.0 = Release|Any CPU
{960384A9-D78F-4C07-986A-1D1F3846AEBE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{960384A9-D78F-4C07-986A-1D1F3846AEBE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{960384A9-D78F-4C07-986A-1D1F3846AEBE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{960384A9-D78F-4C07-986A-1D1F3846AEBE}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{5393711C-44B0-4752-B8D0-852C73D6866F} = {D39E8203-6C3C-4C4B-9C7D-7911AA19D7CC}
{40F1C615-EDD9-463F-A012-B232F6710FA5} = {D39E8203-6C3C-4C4B-9C7D-7911AA19D7CC}
{FDACD960-168E-44F9-B036-2E29EA391BE7} = {D39E8203-6C3C-4C4B-9C7D-7911AA19D7CC}
{960384A9-D78F-4C07-986A-1D1F3846AEBE} = {D39E8203-6C3C-4C4B-9C7D-7911AA19D7CC}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {8A5DE392-1C9D-4806-B6C7-EDD4D33C5D1E}
EndGlobalSection
Expand Down
5 changes: 5 additions & 0 deletions modules/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- Only needed when referencing local dependencies as projects. For published packages, these are imported automatically. -->
<Import Project="../crates/bindings-csharp/Runtime/build/SpacetimeDB.Runtime.props" />

<!-- Prevent test projects from being picked up by `dotnet pack`. -->
<PropertyGroup>
<IsPackable>false</IsPackable>
</PropertyGroup>
</Project>

2 comments on commit 6ba91bb

@github-actions
Copy link

@github-actions github-actions bot commented on 6ba91bb Sep 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Criterion benchmark results

Criterion benchmark report

YOU SHOULD PROBABLY IGNORE THESE RESULTS.

Criterion is a wall time based benchmarking system that is extremely noisy when run on CI. We collect these results for longitudinal analysis, but they are not reliable for comparing individual PRs.

Go look at the callgrind report instead.

empty

db on disk new latency old latency new throughput old throughput
sqlite 💿 410.6±2.82ns 408.0±3.04ns - -
sqlite 🧠 402.9±3.23ns 403.2±5.42ns - -
stdb_raw 💿 625.6±1.67ns 625.5±0.54ns - -
stdb_raw 🧠 625.0±1.28ns 626.6±0.70ns - -

insert_1

db on disk schema indices preload new latency old latency new throughput old throughput

insert_bulk

db on disk schema indices preload count new latency old latency new throughput old throughput
sqlite 💿 u32_u64_str btree_each_column 2048 256 579.9±1.38µs 581.7±0.51µs 1724 tx/sec 1719 tx/sec
sqlite 💿 u32_u64_str unique_0 2048 256 149.1±1.12µs 148.3±0.40µs 6.6 Ktx/sec 6.6 Ktx/sec
sqlite 💿 u32_u64_u64 btree_each_column 2048 256 463.8±0.74µs 470.3±0.68µs 2.1 Ktx/sec 2.1 Ktx/sec
sqlite 💿 u32_u64_u64 unique_0 2048 256 134.7±1.05µs 134.5±0.23µs 7.2 Ktx/sec 7.3 Ktx/sec
sqlite 🧠 u32_u64_str btree_each_column 2048 256 444.5±0.43µs 443.6±0.98µs 2.2 Ktx/sec 2.2 Ktx/sec
sqlite 🧠 u32_u64_str unique_0 2048 256 119.3±0.70µs 120.6±0.71µs 8.2 Ktx/sec 8.1 Ktx/sec
sqlite 🧠 u32_u64_u64 btree_each_column 2048 256 364.5±0.71µs 364.8±0.46µs 2.7 Ktx/sec 2.7 Ktx/sec
sqlite 🧠 u32_u64_u64 unique_0 2048 256 106.1±0.36µs 103.9±0.52µs 9.2 Ktx/sec 9.4 Ktx/sec
stdb_raw 💿 u32_u64_str btree_each_column 2048 256 599.2±16.99µs 586.7±18.36µs 1668 tx/sec 1704 tx/sec
stdb_raw 💿 u32_u64_str unique_0 2048 256 414.7±17.03µs 424.8±15.18µs 2.4 Ktx/sec 2.3 Ktx/sec
stdb_raw 💿 u32_u64_u64 btree_each_column 2048 256 379.7±6.88µs 381.0±4.95µs 2.6 Ktx/sec 2.6 Ktx/sec
stdb_raw 💿 u32_u64_u64 unique_0 2048 256 351.8±7.40µs 352.4±9.75µs 2.8 Ktx/sec 2.8 Ktx/sec
stdb_raw 🧠 u32_u64_str btree_each_column 2048 256 306.0±0.29µs 306.7±0.31µs 3.2 Ktx/sec 3.2 Ktx/sec
stdb_raw 🧠 u32_u64_str unique_0 2048 256 239.3±0.30µs 241.1±0.15µs 4.1 Ktx/sec 4.1 Ktx/sec
stdb_raw 🧠 u32_u64_u64 btree_each_column 2048 256 244.5±0.13µs 245.6±0.25µs 4.0 Ktx/sec 4.0 Ktx/sec
stdb_raw 🧠 u32_u64_u64 unique_0 2048 256 220.2±0.10µs 219.8±0.26µs 4.4 Ktx/sec 4.4 Ktx/sec

iterate

db on disk schema indices new latency old latency new throughput old throughput
sqlite 💿 u32_u64_str unique_0 20.8±0.08µs 23.0±0.10µs 46.9 Ktx/sec 42.5 Ktx/sec
sqlite 💿 u32_u64_u64 unique_0 19.9±0.12µs 21.2±0.06µs 49.2 Ktx/sec 46.0 Ktx/sec
sqlite 🧠 u32_u64_str unique_0 18.8±0.16µs 20.0±0.24µs 51.8 Ktx/sec 48.9 Ktx/sec
sqlite 🧠 u32_u64_u64 unique_0 17.3±0.10µs 18.4±0.09µs 56.5 Ktx/sec 53.2 Ktx/sec
stdb_raw 💿 u32_u64_str unique_0 4.7±0.00µs 4.7±0.00µs 206.3 Ktx/sec 206.1 Ktx/sec
stdb_raw 💿 u32_u64_u64 unique_0 4.6±0.00µs 4.6±0.00µs 211.1 Ktx/sec 211.2 Ktx/sec
stdb_raw 🧠 u32_u64_str unique_0 4.7±0.00µs 4.7±0.00µs 206.3 Ktx/sec 206.2 Ktx/sec
stdb_raw 🧠 u32_u64_u64 unique_0 4.6±0.00µs 4.6±0.00µs 211.1 Ktx/sec 211.0 Ktx/sec

find_unique

db on disk key type preload new latency old latency new throughput old throughput

filter

db on disk key type index strategy load count new latency old latency new throughput old throughput
sqlite 💿 string index 2048 256 68.3±0.15µs 69.2±0.13µs 14.3 Ktx/sec 14.1 Ktx/sec
sqlite 💿 u64 index 2048 256 64.2±0.03µs 65.0±0.16µs 15.2 Ktx/sec 15.0 Ktx/sec
sqlite 🧠 string index 2048 256 64.1±0.13µs 65.4±0.32µs 15.2 Ktx/sec 14.9 Ktx/sec
sqlite 🧠 u64 index 2048 256 59.3±0.04µs 59.9±0.06µs 16.5 Ktx/sec 16.3 Ktx/sec
stdb_raw 💿 string index 2048 256 4.8±0.00µs 4.8±0.00µs 202.0 Ktx/sec 201.9 Ktx/sec
stdb_raw 💿 u64 index 2048 256 4.8±0.00µs 4.8±0.00µs 201.8 Ktx/sec 201.5 Ktx/sec
stdb_raw 🧠 string index 2048 256 4.8±0.00µs 4.8±0.00µs 202.0 Ktx/sec 201.8 Ktx/sec
stdb_raw 🧠 u64 index 2048 256 4.8±0.00µs 4.8±0.00µs 201.6 Ktx/sec 201.7 Ktx/sec

serialize

schema format count new latency old latency new throughput old throughput
u32_u64_str bflatn_to_bsatn_fast_path 100 3.3±0.01µs 3.3±0.01µs 29.1 Mtx/sec 29.3 Mtx/sec
u32_u64_str bflatn_to_bsatn_slow_path 100 3.4±0.00µs 3.4±0.00µs 28.3 Mtx/sec 28.3 Mtx/sec
u32_u64_str bsatn 100 2.4±0.06µs 2.4±0.00µs 39.4 Mtx/sec 39.8 Mtx/sec
u32_u64_str bsatn 100 40.2±0.17ns 40.3±0.19ns 2.3 Gtx/sec 2.3 Gtx/sec
u32_u64_str json 100 4.6±0.05µs 4.8±0.05µs 20.6 Mtx/sec 20.0 Mtx/sec
u32_u64_str json 100 7.5±0.08µs 7.5±0.05µs 12.7 Mtx/sec 12.7 Mtx/sec
u32_u64_str product_value 100 1015.6±0.70ns 1019.5±0.70ns 93.9 Mtx/sec 93.5 Mtx/sec
u32_u64_u64 bflatn_to_bsatn_fast_path 100 1127.7±15.38ns 1104.9±17.84ns 84.6 Mtx/sec 86.3 Mtx/sec
u32_u64_u64 bflatn_to_bsatn_slow_path 100 2.8±0.00µs 2.8±0.00µs 34.3 Mtx/sec 34.3 Mtx/sec
u32_u64_u64 bsatn 100 1703.4±32.61ns 1710.4±34.66ns 56.0 Mtx/sec 55.8 Mtx/sec
u32_u64_u64 bsatn 100 39.4±0.06ns 39.3±0.12ns 2.4 Gtx/sec 2.4 Gtx/sec
u32_u64_u64 json 100 3.0±0.01µs 3.2±0.03µs 31.4 Mtx/sec 29.4 Mtx/sec
u32_u64_u64 json 100 5.2±0.05µs 5.3±0.08µs 18.4 Mtx/sec 18.1 Mtx/sec
u32_u64_u64 product_value 100 1013.2±1.72ns 1015.8±1.70ns 94.1 Mtx/sec 93.9 Mtx/sec
u64_u64_u32 bflatn_to_bsatn_fast_path 100 904.2±0.85ns 891.5±1.27ns 105.5 Mtx/sec 107.0 Mtx/sec
u64_u64_u32 bflatn_to_bsatn_slow_path 100 2.8±0.00µs 2.8±0.00µs 34.2 Mtx/sec 34.2 Mtx/sec
u64_u64_u32 bsatn 100 1705.7±34.20ns 1697.4±32.92ns 55.9 Mtx/sec 56.2 Mtx/sec
u64_u64_u32 bsatn 100 756.4±0.42ns 753.1±0.53ns 126.1 Mtx/sec 126.6 Mtx/sec
u64_u64_u32 json 100 3.3±0.06µs 3.2±0.03µs 28.7 Mtx/sec 30.0 Mtx/sec
u64_u64_u32 json 100 5.1±0.02µs 5.1±0.04µs 18.9 Mtx/sec 18.8 Mtx/sec
u64_u64_u32 product_value 100 1018.0±0.58ns 1017.5±0.72ns 93.7 Mtx/sec 93.7 Mtx/sec

stdb_module_large_arguments

arg size new latency old latency new throughput old throughput
64KiB 101.1±9.61µs 113.2±5.17µs - -

stdb_module_print_bulk

line count new latency old latency new throughput old throughput
1 55.7±5.10µs 52.9±6.65µs - -
100 601.4±7.39µs 597.7±7.06µs - -
1000 4.8±0.69ms 3.9±0.77ms - -

remaining

name new latency old latency new throughput old throughput
special/db_game/circles/load=10 283.1±2.55µs 284.5±2.59µs - -
special/db_game/circles/load=100 285.2±2.29µs 286.2±2.90µs - -
special/db_game/ia_loop/load=10 0.0±0.00ns 0.0±0.00ns - -
special/db_game/ia_loop/load=100 0.0±0.00ns 0.0±0.00ns - -
sqlite/💿/update_bulk/u32_u64_str/unique_0/load=2048/count=256 52.1±0.27µs 54.9±0.20µs 18.7 Ktx/sec 17.8 Ktx/sec
sqlite/💿/update_bulk/u32_u64_u64/unique_0/load=2048/count=256 44.5±0.09µs 46.5±0.09µs 21.9 Ktx/sec 21.0 Ktx/sec
sqlite/🧠/update_bulk/u32_u64_str/unique_0/load=2048/count=256 37.6±0.14µs 39.9±0.31µs 26.0 Ktx/sec 24.5 Ktx/sec
sqlite/🧠/update_bulk/u32_u64_u64/unique_0/load=2048/count=256 33.6±0.08µs 35.4±0.07µs 29.1 Ktx/sec 27.6 Ktx/sec
stdb_module/💿/update_bulk/u32_u64_str/unique_0/load=2048/count=256 1229.5±8.91µs 1263.4±19.06µs 813 tx/sec 791 tx/sec
stdb_module/💿/update_bulk/u32_u64_u64/unique_0/load=2048/count=256 972.8±13.78µs 980.8±10.50µs 1027 tx/sec 1019 tx/sec
stdb_raw/💿/update_bulk/u32_u64_str/unique_0/load=2048/count=256 650.5±21.84µs 648.9±36.08µs 1537 tx/sec 1541 tx/sec
stdb_raw/💿/update_bulk/u32_u64_u64/unique_0/load=2048/count=256 495.6±6.60µs 493.1±7.46µs 2017 tx/sec 2028 tx/sec
stdb_raw/🧠/update_bulk/u32_u64_str/unique_0/load=2048/count=256 383.0±0.70µs 381.5±0.54µs 2.5 Ktx/sec 2.6 Ktx/sec
stdb_raw/🧠/update_bulk/u32_u64_u64/unique_0/load=2048/count=256 345.3±0.39µs 345.4±0.76µs 2.8 Ktx/sec 2.8 Ktx/sec

@github-actions
Copy link

@github-actions github-actions bot commented on 6ba91bb Sep 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Callgrind benchmark results

Callgrind Benchmark Report

These benchmarks were run using callgrind,
an instruction-level profiler. They allow comparisons between sqlite (sqlite), SpacetimeDB running through a module (stdb_module), and the underlying SpacetimeDB data storage engine (stdb_raw). Callgrind emulates a CPU to collect the below estimates.

Measurement changes larger than five percent are in bold.

In-memory benchmarks

callgrind: empty transaction

db total reads + writes old total reads + writes Δrw estimated cycles old estimated cycles Δcycles
stdb_raw 5411 5411 0.00% 5453 5453 0.00%
sqlite 5555 5555 0.00% 5965 5965 0.00%

callgrind: filter

db schema indices count preload _column data_type total reads + writes old total reads + writes Δrw estimated cycles old estimated cycles Δcycles
stdb_raw u32_u64_str no_index 64 128 2 string 117813 117813 0.00% 118289 118289 0.00%
stdb_raw u32_u64_str no_index 64 128 1 u64 75401 75401 0.00% 75849 75849 0.00%
stdb_raw u32_u64_str btree_each_column 64 128 2 string 24085 24069 0.07% 24505 24485 0.08%
stdb_raw u32_u64_str btree_each_column 64 128 1 u64 23036 23036 0.00% 23376 23376 0.00%
sqlite u32_u64_str no_index 64 128 2 string 144678 144678 0.00% 146144 146144 0.00%
sqlite u32_u64_str no_index 64 128 1 u64 124027 124027 0.00% 125245 125249 -0.00%
sqlite u32_u64_str btree_each_column 64 128 2 string 134477 134477 0.00% 136207 136203 0.00%
sqlite u32_u64_str btree_each_column 64 128 1 u64 131344 131344 0.00% 132910 132914 -0.00%

callgrind: insert bulk

db schema indices count preload total reads + writes old total reads + writes Δrw estimated cycles old estimated cycles Δcycles
stdb_raw u32_u64_str unique_0 64 128 904885 905308 -0.05% 957803 958258 -0.05%
stdb_raw u32_u64_str btree_each_column 64 128 1057705 1054689 0.29% 1097457 1125033 -2.45%
sqlite u32_u64_str unique_0 64 128 398292 398292 0.00% 417280 417288 -0.00%
sqlite u32_u64_str btree_each_column 64 128 983609 983609 0.00% 1021793 1021809 -0.00%

callgrind: iterate

db schema indices count total reads + writes old total reads + writes Δrw estimated cycles old estimated cycles Δcycles
stdb_raw u32_u64_str unique_0 1024 152697 152697 0.00% 152735 152735 0.00%
stdb_raw u32_u64_str unique_0 64 15722 15722 0.00% 15756 15756 0.00%
sqlite u32_u64_str unique_0 1024 1068223 1068223 0.00% 1071495 1071495 0.00%
sqlite u32_u64_str unique_0 64 76227 76209 0.02% 77281 77263 0.02%

callgrind: serialize_product_value

count format total reads + writes old total reads + writes Δrw estimated cycles old estimated cycles Δcycles
64 json 47118 47118 0.00% 49770 49770 0.00%
64 bsatn 25716 25716 0.00% 27994 27994 0.00%
16 json 12062 12062 0.00% 13966 13966 0.00%
16 bsatn 8117 8117 0.00% 9477 9477 0.00%

callgrind: update bulk

db schema indices count preload total reads + writes old total reads + writes Δrw estimated cycles old estimated cycles Δcycles
stdb_raw u32_u64_str unique_0 1024 1024 20753546 20715351 0.18% 21401276 21316081 0.40%
stdb_raw u32_u64_str unique_0 64 128 1310716 1308206 0.19% 1384260 1381042 0.23%
sqlite u32_u64_str unique_0 1024 1024 1801983 1801983 0.00% 1811077 1811077 0.00%
sqlite u32_u64_str unique_0 64 128 128329 128329 0.00% 131247 131247 0.00%
On-disk benchmarks

callgrind: empty transaction

db total reads + writes old total reads + writes Δrw estimated cycles old estimated cycles Δcycles
stdb_raw 5421 5421 0.00% 5467 5467 0.00%
sqlite 5597 5597 0.00% 6071 6071 0.00%

callgrind: filter

db schema indices count preload _column data_type total reads + writes old total reads + writes Δrw estimated cycles old estimated cycles Δcycles
stdb_raw u32_u64_str no_index 64 128 2 string 118933 118933 0.00% 119425 119425 0.00%
stdb_raw u32_u64_str no_index 64 128 1 u64 75411 75411 0.00% 75855 75855 0.00%
stdb_raw u32_u64_str btree_each_column 64 128 2 string 24084 24079 0.02% 24500 24495 0.02%
stdb_raw u32_u64_str btree_each_column 64 128 1 u64 23046 23046 0.00% 23378 23378 0.00%
sqlite u32_u64_str no_index 64 128 2 string 146650 146599 0.03% 148436 148385 0.03%
sqlite u32_u64_str no_index 64 128 1 u64 125948 125948 0.00% 127534 127534 0.00%
sqlite u32_u64_str btree_each_column 64 128 2 string 136599 136599 0.00% 138835 138835 0.00%
sqlite u32_u64_str btree_each_column 64 128 1 u64 133440 133440 0.00% 135488 135488 0.00%

callgrind: insert bulk

db schema indices count preload total reads + writes old total reads + writes Δrw estimated cycles old estimated cycles Δcycles
stdb_raw u32_u64_str unique_0 64 128 854628 855024 -0.05% 906864 907340 -0.05%
stdb_raw u32_u64_str btree_each_column 64 128 1004200 1007022 -0.28% 1074732 1077736 -0.28%
sqlite u32_u64_str unique_0 64 128 415829 415829 0.00% 434073 434073 0.00%
sqlite u32_u64_str btree_each_column 64 128 1021870 1021870 0.00% 1059668 1059672 -0.00%

callgrind: iterate

db schema indices count total reads + writes old total reads + writes Δrw estimated cycles old estimated cycles Δcycles
stdb_raw u32_u64_str unique_0 1024 152707 152707 0.00% 152741 152741 0.00%
stdb_raw u32_u64_str unique_0 64 15732 15732 0.00% 15766 15766 0.00%
sqlite u32_u64_str unique_0 1024 1071291 1071291 0.00% 1074861 1074861 0.00%
sqlite u32_u64_str unique_0 64 77981 77981 0.00% 79247 79247 0.00%

callgrind: serialize_product_value

count format total reads + writes old total reads + writes Δrw estimated cycles old estimated cycles Δcycles
64 json 47118 47118 0.00% 49770 49770 0.00%
64 bsatn 25716 25716 0.00% 27994 27994 0.00%
16 json 12062 12062 0.00% 13966 13966 0.00%
16 bsatn 8117 8117 0.00% 9477 9477 0.00%

callgrind: update bulk

db schema indices count preload total reads + writes old total reads + writes Δrw estimated cycles old estimated cycles Δcycles
stdb_raw u32_u64_str unique_0 1024 1024 19460355 19458524 0.01% 20131697 20128178 0.02%
stdb_raw u32_u64_str unique_0 64 128 1262492 1262220 0.02% 1334880 1334530 0.03%
sqlite u32_u64_str unique_0 1024 1024 1809538 1809556 -0.00% 1818266 1818292 -0.00%
sqlite u32_u64_str unique_0 64 128 132449 132449 0.00% 135457 135457 0.00%

Please sign in to comment.