Skip to content

Commit

Permalink
Stopwatch and reducer rng (#1681)
Browse files Browse the repository at this point in the history
Signed-off-by: Ingvar Stepanyan <me@rreverser.com>
Co-authored-by: Steve Boytsun <steve@clockwokrlabs.io>
Co-authored-by: Ingvar Stepanyan <me@rreverser.com>
  • Loading branch information
3 people authored Sep 18, 2024
1 parent f6bc6dc commit 14e5098
Show file tree
Hide file tree
Showing 11 changed files with 100 additions and 22 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ __pycache__/
cs-src/
crates/bench/spacetime.svg
crates/bench/sqlite.svg
.vs/

# benchmark files
out.json
Expand Down
5 changes: 5 additions & 0 deletions crates/bindings-csharp/Runtime/Exceptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ public class NoSuchIterException : StdbException
public override string Message => "The provided row iterator does not exist";
}

public class NoSuchLogStopwatch : StdbException
{
public override string Message => "The provided stopwatch does not exist";
}

public class NoSuchBytesException : StdbException
{
public override string Message => "The provided bytes source or sink does not exist";
Expand Down
33 changes: 33 additions & 0 deletions crates/bindings-csharp/Runtime/Internal/FFI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public enum Errno : short
BSATN_DECODE_ERROR = 3,
NO_SUCH_TABLE = 4,
NO_SUCH_ITER = 6,
NO_SUCH_CONSOLE_TIMER = 7,
NO_SUCH_BYTES = 8,
NO_SPACE = 9,
BUFFER_TOO_SMALL = 11,
Expand Down Expand Up @@ -75,6 +76,7 @@ public static CheckedStatus ConvertToManaged(Errno status)
Errno.BSATN_DECODE_ERROR => new BsatnDecodeException(),
Errno.NO_SUCH_TABLE => new NoSuchTableException(),
Errno.NO_SUCH_ITER => new NoSuchIterException(),
Errno.NO_SUCH_CONSOLE_TIMER => new NoSuchLogStopwatch(),
Errno.NO_SUCH_BYTES => new NoSuchBytesException(),
Errno.NO_SPACE => new NoSpaceException(),
Errno.BUFFER_TOO_SMALL => new BufferTooSmallException(),
Expand Down Expand Up @@ -221,4 +223,35 @@ public static partial CheckedStatus _bytes_sink_write(
ReadOnlySpan<byte> buffer,
ref uint buffer_len
);

[NativeMarshalling(typeof(ConsoleTimerIdMarshaller))]
[StructLayout(LayoutKind.Sequential)]
public readonly struct ConsoleTimerId
{
private readonly uint timer_id;

private ConsoleTimerId(uint id)
{
timer_id = id;
}

//LayoutKind.Sequential is apparently not enough for this struct to be returnable in PInvoke, so we need a custom marshaller unfortunately
[CustomMarshaller(
typeof(ConsoleTimerId),
MarshalMode.Default,
typeof(ConsoleTimerIdMarshaller)
)]
internal static class ConsoleTimerIdMarshaller
{
public static ConsoleTimerId ConvertToManaged(uint id) => new ConsoleTimerId(id);

public static uint ConvertToUnmanaged(ConsoleTimerId id) => id.timer_id;
}
}

[LibraryImport(StdbNamespace)]
public static partial ConsoleTimerId _console_timer_start([In] byte[] name, uint name_len);

[LibraryImport(StdbNamespace)]
public static partial CheckedStatus _console_timer_end(ConsoleTimerId stopwatch_id);
}
5 changes: 2 additions & 3 deletions crates/bindings-csharp/Runtime/Internal/Module.cs
Original file line number Diff line number Diff line change
Expand Up @@ -192,11 +192,10 @@ BytesSink error

try
{
Runtime.Random = new((int)timestamp.MicrosecondsSinceEpoch);

using var stream = new MemoryStream(args.Consume());
using var reader = new BinaryReader(stream);
reducers[(int)id].Invoke(reader, new(sender, address, timestamp.ToStd()));
var context = new ReducerContext(sender, address, timestamp);
reducers[(int)id].Invoke(reader, context);
if (stream.Position != stream.Length)
{
throw new Exception("Unrecognised extra bytes in the reducer arguments");
Expand Down
30 changes: 30 additions & 0 deletions crates/bindings-csharp/Runtime/LogStopwatch.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System.Text;
using SpacetimeDB.Internal;

namespace SpacetimeDB;

public sealed class LogStopwatch : IDisposable
{
private readonly FFI.ConsoleTimerId StopwatchId;
private bool WasStopped;

public LogStopwatch(string name)
{
var name_bytes = Encoding.UTF8.GetBytes(name);
StopwatchId = FFI._console_timer_start(name_bytes, (uint)name_bytes.Length);
}

void IDisposable.Dispose()
{
if (!WasStopped)
{
End();
}
}

public void End()
{
FFI._console_timer_end(StopwatchId);
WasStopped = true;
}
}
13 changes: 8 additions & 5 deletions crates/bindings-csharp/Runtime/Runtime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,21 @@ public class ReducerContext
public readonly DateTimeOffset Time;
public readonly Address? Address;

/// <summary>
/// A reducer-specific instance of `System.Random` that is seeded by current reducer's timestamp. This object is unchanged throught the entire reducer call
/// </summary>
public readonly Random Rng;

internal ReducerContext(
Identity senderIdentity,
Address? senderAddress,
DateTimeOffset timestamp
DateTimeOffsetRepr timestamp
)
{
Sender = senderIdentity;
Address = senderAddress;
Time = timestamp;
Time = timestamp.ToStd();
Rng = new Random((int)timestamp.MicrosecondsSinceEpoch);
}
}

Expand Down Expand Up @@ -112,7 +118,4 @@ public static void Log(
(uint)text_bytes.Length
);
}

// An instance of `System.Random` that is reseeded by each reducer's timestamp.
public static Random Random { get; internal set; } = new();
}
7 changes: 7 additions & 0 deletions crates/bindings-csharp/Runtime/bindings.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ OPAQUE_TYPEDEF(LogLevel, uint8_t);
OPAQUE_TYPEDEF(BytesSink, uint32_t);
OPAQUE_TYPEDEF(BytesSource, uint32_t);
OPAQUE_TYPEDEF(RowIter, uint32_t);
OPAQUE_TYPEDEF(ConsoleTimerId, uint32_t);

#define CSTR(s) (uint8_t*)s, sizeof(s) - 1

Expand Down Expand Up @@ -79,6 +80,12 @@ IMPORT(int16_t, _bytes_source_read, (BytesSource source, uint8_t* buffer_ptr, si
(source, buffer_ptr, buffer_len_ptr));
IMPORT(uint16_t, _bytes_sink_write, (BytesSink sink, const uint8_t* buffer_ptr, size_t* buffer_len_ptr),
(sink, buffer_ptr, buffer_len_ptr));
IMPORT(ConsoleTimerId, _console_timer_start,
(const uint8_t* name, size_t name_len),
(name, name_len));
IMPORT(Status, _console_timer_end,
(ConsoleTimerId stopwatch_id),
(stopwatch_id));

#ifndef EXPERIMENTAL_WASM_AOT
static MonoClass* ffi_class;
Expand Down
2 changes: 1 addition & 1 deletion crates/bindings/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
#[macro_use]
mod io;
mod impls;
pub mod log_stopwatch;
mod logger;
#[cfg(feature = "rand")]
mod rng;
#[doc(hidden)]
pub mod rt;
pub mod time_span;
mod timestamp;

use spacetimedb_lib::buffer::{BufReader, BufWriter, Cursor, DecodeError};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
pub struct Span {
span_id: u32,
pub struct LogStopwatch {
stopwatch_id: u32,
}

impl Span {
pub fn start(name: &str) -> Self {
impl LogStopwatch {
pub fn new(name: &str) -> Self {
let name = name.as_bytes();
let id = unsafe { spacetimedb_bindings_sys::raw::_console_timer_start(name.as_ptr(), name.len()) };
Self { span_id: id }
Self { stopwatch_id: id }
}

pub fn end(self) {
// just drop self
}
}

impl std::ops::Drop for Span {
impl std::ops::Drop for LogStopwatch {
fn drop(&mut self) {
unsafe {
spacetimedb_bindings_sys::raw::_console_timer_end(self.span_id);
spacetimedb_bindings_sys::raw::_console_timer_end(self.stopwatch_id);
}
}
}
2 changes: 1 addition & 1 deletion crates/primitives/src/errno.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ macro_rules! errnos {
NO_SUCH_TABLE(4, "No such table"),
NO_SUCH_INDEX(5, "No such index"),
NO_SUCH_ITER(6, "The provided row iterator is not valid"),
NO_SUCH_CONSOLE_TIMER(7, "The started console timer does not exist"),
NO_SUCH_CONSOLE_TIMER(7, "The provided console timer does not exist"),
NO_SUCH_BYTES(8, "The provided bytes source or sink is not valid"),
NO_SPACE(9, "The provided sink has no more space left"),
BUFFER_TOO_SMALL(11, "The provided buffer is not large enough to store the data"),
Expand Down
10 changes: 5 additions & 5 deletions modules/perf-test/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use spacetimedb::{query, time_span::Span};
use spacetimedb::{log_stopwatch::LogStopwatch, query};

#[spacetimedb::table(name = location, index(name = coordinates, btree(columns = [x, z, dimension])))]
#[derive(Debug, PartialEq, Eq)]
Expand Down Expand Up @@ -42,7 +42,7 @@ const CHUNK: u64 = ID / ROWS_PER_CHUNK;
#[spacetimedb::reducer]
/// Probing a single column index for a single row should be fast!
pub fn test_index_scan_on_id() {
let span = Span::start("Index scan on {id}");
let span = LogStopwatch::new("Index scan on {id}");
let location = Location::filter_by_id(&ID).unwrap();
span.end();
assert_eq!(ID, location.id);
Expand All @@ -51,7 +51,7 @@ pub fn test_index_scan_on_id() {
#[spacetimedb::reducer]
/// Scanning a single column index for `ROWS_PER_CHUNK` rows should also be fast!
pub fn test_index_scan_on_chunk() {
let span = Span::start("Index scan on {chunk}");
let span = LogStopwatch::new("Index scan on {chunk}");
let n = Location::filter_by_chunk(&CHUNK).count();
span.end();
assert_eq!(n as u64, ROWS_PER_CHUNK);
Expand All @@ -62,7 +62,7 @@ pub fn test_index_scan_on_chunk() {
pub fn test_index_scan_on_x_z_dimension() {
let z = CHUNK as i32;
let dimension = ID as u32;
let span = Span::start("Index scan on {x, z, dimension}");
let span = LogStopwatch::new("Index scan on {x, z, dimension}");
let n = query!(|r: Location| r.x == 0 && r.z == z && r.dimension == dimension).count();
span.end();
assert_eq!(n, 1);
Expand All @@ -72,7 +72,7 @@ pub fn test_index_scan_on_x_z_dimension() {
/// Probing a multi-column index for `ROWS_PER_CHUNK` rows should also be fast!
pub fn test_index_scan_on_x_z() {
let z = CHUNK as i32;
let span = Span::start("Index scan on {x, z}");
let span = LogStopwatch::new("Index scan on {x, z}");
let n = query!(|r: Location| r.x == 0 && r.z == z).count();
span.end();
assert_eq!(n as u64, ROWS_PER_CHUNK);
Expand Down

2 comments on commit 14e5098

@github-actions
Copy link

@github-actions github-actions bot commented on 14e5098 Sep 18, 2024

Choose a reason for hiding this comment

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

Benchmarking failed. Please check the workflow run for details.

@github-actions
Copy link

@github-actions github-actions bot commented on 14e5098 Sep 18, 2024

Choose a reason for hiding this comment

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

Benchmarking failed. Please check the workflow run for details.

Please sign in to comment.