peterhuene opened PR #2736 from limiter
to main
:
This PR adds a
ResourceLimiter
trait to the Wasmtime API.When used in conjunction with
Store::new_with_limiter
, this can be used to
monitor and prevent WebAssembly code from growing linear memories and tables.This is particularly useful when hosts need to take into account host resource
usage to determine if WebAssembly code can consume more resources.A simple
StaticResourceLimiter
is also included with these changes that will
simply limit the size of linear memories or tables for all instances created in
the store based on static values.
peterhuene requested pchickey for a review on PR #2736.
peterhuene updated PR #2736 from limiter
to main
.
peterhuene updated PR #2736 from limiter
to main
.
peterhuene updated PR #2736 from limiter
to main
.
peterhuene updated PR #2736 from limiter
to main
.
alexcrichton submitted PR Review.
alexcrichton created PR Review Comment:
If this ends up being stored in individual tables/memories then this could probably turn into
&'a Arc<dyn ...>
alexcrichton created PR Review Comment:
To make sure I understand this right, if any
maximum
is in play then this field is set to the minimum of all those maximums? The sources ofmaximum
are:
- The actual wasm type itself
- The pooling allocator's configured maximum
- A custom implementation of
RuntimeMemory
has a configured maximumIf my understanding is right, could this be clarified a bit? Basically
None
is only returned if literally nothing is limiting the memory growth, but otherwiseSome
doesn't imply that the wasm type itself had a maximum listed, just that something else somewhere is placing a constraint.Also, presumably, this function isn't called unless
desired
is already known to be less thanmaximum
, right? (or is it called even in those cases?)
alexcrichton created PR Review Comment:
Would it be possible to store the
limiter
into theMemory
itself rather than in theInstance
?
alexcrichton created PR Review Comment:
Could the docs here clarify that this is about the runtime limit maximum of the memory, not the maximum size as prescribed by the type in wasm?
alexcrichton submitted PR Review.
alexcrichton created PR Review Comment:
This structure looks ripe for expansion to limiting other resources in the future, so perhaps this could use a builder-api pattern to avoid future API breakage?
alexcrichton created PR Review Comment:
I think this needs to be specified? Otherwise are memories created via
Memory::new
(or tables) limited via the limiter?
alexcrichton created PR Review Comment:
It looks like this value doesn't change over time, so I don't think it needs to be backed by a
RefCell
?
alexcrichton created PR Review Comment:
To avoid double-allocations and double-indirection could
ResourceLimiterProxy
have a type variable perhaps?
peterhuene submitted PR Review.
peterhuene created PR Review Comment:
Your understanding is correct and I can expand upon it in the docs for clarity.
The function is called even when desired exceeds the maximum as some implementers will want to know when the maximum was reached even if it was not directly limited by the limiter.
If that feels a little strange, perhaps a different function with the intention that it is only called when the memory couldn't grow due to it exceeding the maximum (from wasm / pooling allocator / custom runtime memory)?
peterhuene submitted PR Review.
peterhuene created PR Review Comment:
Good idea. I'll implement a builder.
peterhuene submitted PR Review.
peterhuene created PR Review Comment:
Good point. I'll fix.
peterhuene submitted PR Review.
peterhuene created PR Review Comment:
It currently does as it needs to sit on
inner
which is behindRc
and there's a circular reference between the proxy and theStore
, which is why there is ugliness inStore::new_with_limiter
to set this thing.I'm not happy about it at all, so if there's a better way to do this such that the limiter can pass the store along in the callbacks, I'm definitely open to it.
peterhuene edited PR Review Comment.
peterhuene submitted PR Review.
peterhuene created PR Review Comment:
I will expand these docs.
peterhuene submitted PR Review.
peterhuene created PR Review Comment:
Can do.
peterhuene submitted PR Review.
peterhuene created PR Review Comment:
I'll change this, no reason to clone it for the request until a memory / table needs it.
alexcrichton submitted PR Review.
alexcrichton created PR Review Comment:
Ah ok nah I think for now this is fine. It runs a possible risk of making it difficult to optimize
memory.grow
ortable.grow
in the future but I don't think that's going to be the bottleneck of anything for a long time.
peterhuene edited PR #2736 from limiter
to main
:
This PR adds a
ResourceLimiter
trait to the Wasmtime API.When used in conjunction with
Store::new_with_limiter
, this can be used to
monitor and prevent WebAssembly code from growing linear memories and tables.This is particularly useful when hosts need to take into account host resource
usage to determine if WebAssembly code can consume more resources.A simple
Limiter
is also included with these changes that will
simply limit the size of linear memories or tables for all instances created in
the store based on static values.
peterhuene updated PR #2736 from limiter
to main
.
peterhuene updated PR #2736 from limiter
to main
.
peterhuene updated PR #2736 from limiter
to main
.
peterhuene has marked PR #2736 as ready for review.
peterhuene requested alexcrichton and pchickey for a review on PR #2736.
alexcrichton submitted PR Review.
alexcrichton created PR Review Comment:
Arc
is used here but I thinkRc
may suffice? (I didn't see any location that seemed to require thread-safety here)
alexcrichton created PR Review Comment:
One alternative design perhaps is that the
Store
isn't passed as an argument here and users manuallyRefCell
andWeak
themselves with theStore
. Do you think, though, that this will be commonly desired such that we may as well go ahead and expose it?
alexcrichton submitted PR Review.
alexcrichton created PR Review Comment:
Hm ok, I had a question above about the
Store
argument and whether we can possibly remove that, but also here do you think it would make sense to remove theOption
to effectively always have a limiting strategy?
alexcrichton created PR Review Comment:
Could the tests here be expanded with tests where the initial memory/table size exceed the maximum? Additionally API requests like
Memory::new
andTable::new
should fail as well if they exceed the maximum? (ideally also tests where API-created objects will also fail togrow
past the maximum)
peterhuene submitted PR Review.
peterhuene created PR Review Comment:
Okay, getting back to this PR: I guess we don't have to expose the
Store
and let them capture whatever context they want since it's a custom implementation anyway.I'll remove the
Store
parameter and that'll simplify things a bit.
peterhuene submitted PR Review.
peterhuene created PR Review Comment:
The limiter needs to be an
Option
in the runtime for both table and memory so that the pooling allocator is able to "take" the memory/table when deallocating the instance (swaps inNone
).I don't think having it also
Option
inStore
makes it that much worse and it does have the benefit of not boxing a new trait object every time aStore
is created just to returntrue
on memory/table grow operations.If you're okay with it, I'd like to leave this one as-is.
peterhuene edited PR Review Comment.
peterhuene updated PR #2736 from limiter
to main
.
peterhuene requested alexcrichton and pchickey for a review on PR #2736.
peterhuene updated PR #2736 from limiter
to main
.
alexcrichton submitted PR Review.
alexcrichton submitted PR Review.
alexcrichton created PR Review Comment:
To confirm, are there tests for this? It seems a bit fishy that we're deallocating a half-initialized instance without many modifications below. I'd expect, for example
decommit_memory_pages
to fail one one way or another if called on an othewise unmapped region?
alexcrichton created PR Review Comment:
I suppose one other possible option is to store
*mut dyn ResourceLimiter
in the*mut VMContext
so we can useBox
here instead ofRc
, but let's only do that if the need actually arises.
alexcrichton created PR Review Comment:
Could the documentation here be expanded to indicate that the created
Store
has no limits on usage of memory and such in wasm modules?
alexcrichton created PR Review Comment:
Could this link to the
new_with_limits
API?
alexcrichton created PR Review Comment:
Could the documentation here link to the
ResourceLimiter
trait which discussed which limits can be configured?
alexcrichton created PR Review Comment:
Oh also, could this link to
StoreLimits
andStoreLimitsBuilder
for a built-in way to limit resources?
peterhuene submitted PR Review.
peterhuene created PR Review Comment:
The
test_pooling_allocator_initial_limits_exceeded
test does cover this, albeit with empty memory/table lists ondeallocate
, as that test is what caught the problem: with an instance limit of 1, it failed to allocate any more instances because it wasn't being added back to the free list. I will add another memory to the module definition such that the list of initialized memories isn't empty, just in case.While the instance isn't completely initialized, it should be safe to call
deallocate
on it as we iterate back through only initializedMemory
andTable
to calldecommit_memory_pages
on pages that were either made accessible (forMemory
) or explicitly committed (forTable
) prior to inserting into those lists.
peterhuene updated PR #2736 from limiter
to main
.
peterhuene submitted PR Review.
peterhuene created PR Review Comment:
:+1: I'm going to leave this as-is and we can revisit in the the future if needed.
alexcrichton submitted PR Review.
alexcrichton merged PR #2736.
Last updated: Dec 23 2024 at 12:05 UTC