-
Notifications
You must be signed in to change notification settings - Fork 483
Fix memory usage for polymorphic types. #7049
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
for polymorphic types]. | ||
-} | ||
|
||
{- Note [ExMemoryUsage for polymorphic types]. For polymorphic types such as |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@effectfully I'm not confident that this comment is completely accurate, so feel free to make corrections.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should say something about this in Builtins.hs
as well, although there's already hundreds of lines of comments in there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great comment.
Yeah, maybe Builtins
needs to talk about costing too, but we can do that separately.
plutus-core/plutus-core/src/PlutusCore/Evaluation/Machine/ExMemoryUsage.hs
Outdated
Show resolved
Hide resolved
plutus-core/plutus-core/src/PlutusCore/Evaluation/Machine/ExMemoryUsage.hs
Outdated
Show resolved
Hide resolved
memoryUsage _ = singletonRose 1 | ||
{-# INLINE memoryUsage #-} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The indentation is inconsistent across these instances: some use 4 spaces, some 3.
I suggest raking the whole file with fourmolu
memoryUsage _ = singletonRose 1 | |
{-# INLINE memoryUsage #-} | |
memoryUsage _ = singletonRose 1 | |
{-# INLINE memoryUsage #-} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest raking the whole file with fourmolu
I'll do that before merging. It changes almost every line though, so I won't do it right now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
1 + defaultConstantMeasure (tmCon t x) | ||
+ defaultConstantMeasure (tmCon u y) | ||
defaultConstantMeasure (tmCon (list t) l) = Utils.length l | ||
defaultConstantMeasure (tmCon (pair t u) (x , y)) = 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am wondering why pair has cost 1 a not, say, 2? What logic is applied here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What logic is applied here?
No logic. Nothing we ever do with pairs should depend on the size (famous last words), so it shouldn't matter what it is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It may, if add a builtin serializing a list of pairs or whatever.
But for the time being let's just make it maxBound
or whatever instead of 1
? So that if our assumption that we'll never need a builtin where that matters gets violated, we'll notice that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It may, if add a builtin serializing a list of pairs or whatever.
I don't think that we can do that polymorphically unless we assume that everything in the universe of types is serialisable. We could write a function that would serialise (integer,bytestring)
pairs or something but that would be monomorphic and I think that in that case it'd be ok to use a wrapper.
{-# INLINE memoryUsage #-} | ||
|
||
instance ExMemoryUsage [a] where | ||
memoryUsage l = singletonRose . fromIntegral $ length l |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
memoryUsage l = singletonRose . fromIntegral $ length l | |
memoryUsage = singletonRose . fromIntegral . length |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For some reason I thought that we weren't doing that in this file, but maybe I'm just imagining that.
{-# INLINE memoryUsage #-} | ||
|
||
instance ExMemoryUsage (Vector a) where | ||
memoryUsage l = singletonRose . fromIntegral $ Vector.length l |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
memoryUsage l = singletonRose . fromIntegral $ Vector.length l | |
memoryUsage = singletonRose . fromIntegral . Vector.length |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good! (modulo formatting/typos).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great stuff.
plutus-core/plutus-core/src/PlutusCore/Evaluation/Machine/ExMemoryUsage.hs
Outdated
Show resolved
Hide resolved
plutus-core/plutus-core/src/PlutusCore/Evaluation/Machine/ExMemoryUsage.hs
Outdated
Show resolved
Hide resolved
for polymorphic types]. | ||
-} | ||
|
||
{- Note [ExMemoryUsage for polymorphic types]. For polymorphic types such as |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great comment.
Yeah, maybe Builtins
needs to talk about costing too, but we can do that separately.
plutus-core/plutus-core/src/PlutusCore/Evaluation/Machine/ExMemoryUsage.hs
Show resolved
Hide resolved
{- A naive traversal for size. This accounts for the number of nodes in a Data | ||
object and also the sizes of the contents of the nodes. This is not ideal, | ||
but it seems to be the best we can do. At present this only comes into play | ||
for 'equalsData', which is implemented using the derived implementation of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not just equalsData
, but also serialiseData
?
1 + defaultConstantMeasure (tmCon t x) | ||
+ defaultConstantMeasure (tmCon u y) | ||
defaultConstantMeasure (tmCon (list t) l) = Utils.length l | ||
defaultConstantMeasure (tmCon (pair t u) (x , y)) = 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It may, if add a builtin serializing a list of pairs or whatever.
But for the time being let's just make it maxBound
or whatever instead of 1
? So that if our assumption that we'll never need a builtin where that matters gets violated, we'll notice that.
Why was it ignored- is it a bug and is it fixed in this PR? I'm asking because there are other newtype wrappers like |
@effectfully will be able to fill in the details, but my understanding is that this only happens for wrappers around polymorphic types: the code that converts those back into Haskell types is unaware of the wrappers and so it always uses the default size measure. For monomorphic types like integers, bytestrings, etc, the wrappers are recognised and the correct size measure is used. This hasn't shown up before because all of the functions that we have that operate on polymorphic types were constant time, unlike |
Fixes https://github.com/IntersectMBO/plutus-private/issues/1498
While costing the array builtins it appeared that the time taken by
listToArray
differed for different types of list elements. What was actually happening was that the list was wrapped in aListCostedByLength
wrapper but this was ignored when the denotation was executed, so the default size measure was used instead, and this measured the total memory footprint of the list. So two lists of the same length could have different "sizes" and when working out the dependency of time on size you would get different slopes for lists with elements of different types.This fixes that problem (which should only happen when
SomeConstant
is involved, which at present only happens for polymorphic types) by changing the default memory usage for lists and arrays to be the length, and the memory usage for pairs to be equal to 1. This is arguably the correct thing to do because polymorphic builtins should be parametrically polymorphic, and the time taken by such functions should not depend on the contents of polymorhpic arguments (although if you really want to you can do weird things with the builtin machinery, so it may be possible to produce counterexamples to this) . The polymorphic builtins which have previously been deployed on the chain all have constant time and memory usage, so this change will not affect any existing code. The only function which this will affect islistToArray
, which has not yet been deployed.This also has the benefit of making a number of Agda conformance tests pass which did not pass previously, because the Agda code has the default cost measures hard-coded and doesn't know about newtype wrappers for alternative size measures. Since we now only have one size measure for the polymorphic types this problem has now gone away for polymorphic functions, although it still persists for a few non-polymorphic functions.
This may still be a bit fragile: see https://github.com/IntersectMBO/plutus-private/issues/1046 for a possible longer-term solution.