Skip to content

Commit

Permalink
Update to the new fuel APIs introduced in bytecodealliance/wasmtime#7298
Browse files Browse the repository at this point in the history
. (#281)
  • Loading branch information
kpreisser authored Oct 24, 2023
1 parent 4eccd70 commit 9fbad84
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 178 deletions.
9 changes: 7 additions & 2 deletions examples/consumefuel/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@
"expensive",
Function.FromCallback(store, (Caller caller) =>
{
var remaining = caller.ConsumeFuel(1000UL);
checked
{
caller.Fuel -= 1000UL;
}
var remaining = caller.Fuel;
Console.WriteLine($"Called an expensive function which consumed 1000 fuel. {remaining} units of fuel remaining.");
}
));
Expand All @@ -26,7 +31,7 @@
return;
}

store.AddFuel(5000UL);
store.Fuel += 5000UL;
Console.WriteLine("Added 5000 units of fuel");

for (var i = 0; i < 4; i++)
Expand Down
38 changes: 14 additions & 24 deletions src/Caller.cs
Original file line number Diff line number Diff line change
Expand Up @@ -137,33 +137,23 @@ public bool TryGetMemorySpan<T>(string name, long address, int length, out Span<
public Store Store => store;

/// <summary>
/// Adds fuel to this store for WebAssembly code to consume while executing.
/// Gets or sets the fuel available for WebAssembly code to consume while executing.
/// </summary>
/// <param name="fuel">The fuel to add to the store.</param>
public void AddFuel(ulong fuel) => context.AddFuel(fuel);

/// <summary>
/// Synthetically consumes fuel from this store.
///
/// For this method to work fuel consumption must be enabled via <see cref="Config.WithFuelConsumption(bool)"/>.
///
/// <remarks>
/// <para>
/// For this property to work, fuel consumption must be enabled via <see cref="Config.WithFuelConsumption(bool)"/>.
/// </para>
/// <para>
/// WebAssembly execution will automatically consume fuel but if so desired the embedder can also consume fuel manually
/// to account for relative costs of host functions, for example.
///
/// This method will attempt to consume <paramref name="fuel"/> units of fuel from within this store. If the remaining
/// amount of fuel allows this then the amount of remaining fuel is returned. Otherwise, a <see cref="WasmtimeException"/>
/// is thrown and no fuel is consumed.
/// </summary>
/// <param name="fuel">The fuel to consume from the store.</param>
/// <returns>Returns the remaining amount of fuel.</returns>
/// <exception cref="WasmtimeException">Thrown if more fuel is consumed than the store currently has.</exception>
public ulong ConsumeFuel(ulong fuel) => context.ConsumeFuel(fuel);

/// <summary>
/// Gets the fuel consumed by the executing WebAssembly code.
/// </summary>
/// <returns>Returns the fuel consumed by the executing WebAssembly code or 0 if fuel consumption was not enabled.</returns>
public ulong GetConsumedFuel() => context.GetConsumedFuel();
/// </para>
/// </remarks>
/// <value>The fuel available for WebAssembly code to consume while executing.</value>
public ulong Fuel
{
get => context.GetFuel();
set => context.SetFuel(value);
}

/// <summary>
/// Gets the user-defined data from the Store.
Expand Down
116 changes: 44 additions & 72 deletions src/Store.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,20 @@ internal void GC()
Native.wasmtime_context_gc(handle);
}

internal void AddFuel(ulong fuel)
internal ulong GetFuel()
{
var error = Native.wasmtime_context_add_fuel(handle, fuel);
var error = Native.wasmtime_context_get_fuel(handle, out ulong fuel);
if (error != IntPtr.Zero)
{
throw WasmtimeException.FromOwnedError(error);
}

return fuel;
}

internal void SetFuel(ulong fuel)
{
var error = Native.wasmtime_context_set_fuel(handle, fuel);
if (error != IntPtr.Zero)
{
throw WasmtimeException.FromOwnedError(error);
Expand All @@ -49,27 +60,6 @@ internal Store Store
}
}

internal ulong ConsumeFuel(ulong fuel)
{
var error = Native.wasmtime_context_consume_fuel(handle, fuel, out var remaining);
if (error != IntPtr.Zero)
{
throw WasmtimeException.FromOwnedError(error);
}

return remaining;
}

internal ulong GetConsumedFuel()
{
if (!Native.wasmtime_context_fuel_consumed(handle, out var fuel))
{
return 0;
}

return fuel;
}

internal void SetWasiConfiguration(WasiConfiguration config)
{
var wasi = config.Build();
Expand Down Expand Up @@ -97,14 +87,10 @@ private static class Native
public static extern void wasmtime_context_gc(IntPtr handle);

[DllImport(Engine.LibraryName)]
public static extern IntPtr wasmtime_context_add_fuel(IntPtr handle, ulong fuel);
public static extern IntPtr wasmtime_context_set_fuel(IntPtr handle, ulong fuel);

[DllImport(Engine.LibraryName)]
public static extern IntPtr wasmtime_context_consume_fuel(IntPtr handle, ulong fuel, out ulong remaining);

[DllImport(Engine.LibraryName)]
[return: MarshalAs(UnmanagedType.I1)]
public static extern bool wasmtime_context_fuel_consumed(IntPtr handle, out ulong fuel);
public static extern IntPtr wasmtime_context_get_fuel(IntPtr handle, out ulong fuel);

[DllImport(Engine.LibraryName)]
public static extern IntPtr wasmtime_context_set_wasi(IntPtr handle, IntPtr config);
Expand Down Expand Up @@ -158,6 +144,35 @@ public Store(Engine engine, object? data)
handle = new Handle(Native.wasmtime_store_new(engine.NativeHandle, (IntPtr)storeHandle, Finalizer));
}

/// <summary>
/// Gets or sets the fuel available for WebAssembly code to consume while executing.
/// </summary>
/// <remarks>
/// <para>
/// For this property to work fuel consumption must be enabled via <see cref="Config.WithFuelConsumption(bool)"/>.
/// </para>
/// <para>
/// WebAssembly execution will automatically consume fuel but if so desired the embedder can also consume fuel manually
/// to account for relative costs of host functions, for example.
/// </para>
/// </remarks>
/// <value>The fuel available for WebAssembly code to consume while executing.</value>
public ulong Fuel
{
get
{
ulong fuel = Context.GetFuel();
System.GC.KeepAlive(this);
return fuel;
}

set
{
Context.SetFuel(value);
System.GC.KeepAlive(this);
}
}

/// <summary>
/// Limit the resources that this store may consume. Note that the limits are only used to limit the creation/growth of resources in the future,
/// this does not retroactively attempt to apply limits to the store.
Expand Down Expand Up @@ -212,49 +227,6 @@ public void GC()
System.GC.KeepAlive(this);
}

/// <summary>
/// Adds fuel to this store for WebAssembly code to consume while executing.
/// </summary>
/// <param name="fuel">The fuel to add to the store.</param>
public void AddFuel(ulong fuel)
{
Context.AddFuel(fuel);
System.GC.KeepAlive(this);
}

/// <summary>
/// Synthetically consumes fuel from this store.
///
/// For this method to work fuel consumption must be enabled via <see cref="Config.WithFuelConsumption(bool)"/>.
///
/// WebAssembly execution will automatically consume fuel but if so desired the embedder can also consume fuel manually
/// to account for relative costs of host functions, for example.
///
/// This method will attempt to consume <paramref name="fuel"/> units of fuel from within this store. If the remaining
/// amount of fuel allows this then the amount of remaining fuel is returned. Otherwise, a <see cref="WasmtimeException"/>
/// is thrown and no fuel is consumed.
/// </summary>
/// <param name="fuel">The fuel to consume from the store.</param>
/// <returns>Returns the remaining amount of fuel.</returns>
/// <exception cref="WasmtimeException">Thrown if more fuel is consumed than the store currently has.</exception>
public ulong ConsumeFuel(ulong fuel)
{
var result = Context.ConsumeFuel(fuel);
System.GC.KeepAlive(this);
return result;
}

/// <summary>
/// Gets the fuel consumed by the executing WebAssembly code.
/// </summary>
/// <returns>Returns the fuel consumed by the executing WebAssembly code or 0 if fuel consumption was not enabled.</returns>
public ulong GetConsumedFuel()
{
var result = Context.GetConsumedFuel();
System.GC.KeepAlive(this);
return result;
}

/// <summary>
/// Configures WASI within the store.
/// </summary>
Expand Down
19 changes: 10 additions & 9 deletions tests/CallerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public CallerTests(CallerFixture fixture)
Linker = new Linker(Fixture.Engine);
Store = new Store(Fixture.Engine);

Store.AddFuel(1000000);
Store.Fuel = 1000000;
}

[Fact]
Expand Down Expand Up @@ -309,11 +309,12 @@ public void ItCanSetData()


[Fact]
public void ItCanConsumeFuel()
public void ItCanRemoveFuel()
{
Linker.DefineFunction("env", "callback", (Caller c) =>
{
c.ConsumeFuel(10).Should().Be(1000000 - (10 + 2));
c.Fuel -= 10;
c.Fuel.Should().Be(1000000 - (10 + 2));
});

var instance = Linker.Instantiate(Store, Fixture.Module);
Expand All @@ -323,16 +324,16 @@ public void ItCanConsumeFuel()

// 10 is consumed by the explicit fuel consumption
// 2 is consumed by the rest of the WASM which executes behind the scenes in this test
Store.GetConsumedFuel().Should().Be(10 + 2);
Store.Fuel.Should().Be(1000000 - (10 + 2));
}

[Fact]
public void ItCanAddFuel()
{
Linker.DefineFunction("env", "callback", (Caller c) =>
{
c.AddFuel(2);
c.ConsumeFuel(0).Should().Be(1000000);
c.Fuel += 2;
c.Fuel.Should().Be(1000000);
});

var instance = Linker.Instantiate(Store, Fixture.Module);
Expand All @@ -341,15 +342,15 @@ public void ItCanAddFuel()
callback.Invoke();

// 2 is consumed by the WASM which executes behind the scenes in this test
Store.GetConsumedFuel().Should().Be(2);
Store.Fuel.Should().Be(1000000);
}

[Fact]
public void ItCanGetConsumedFuel()
public void ItCanGetFuel()
{
Linker.DefineFunction("env", "callback", (Caller c) =>
{
c.GetConsumedFuel().Should().Be(2);
c.Fuel.Should().Be(1000000 - 2);
});

var instance = Linker.Instantiate(Store, Fixture.Module);
Expand Down
Loading

0 comments on commit 9fbad84

Please sign in to comment.