gnolang / gno

Gno: An interpreted, stack-based Go virtual machine to build succinct and composable apps + Gno.land: a blockchain for timeless code and fair open-source.
https://gno.land/
Other
880 stars 364 forks source link

Add gno `std` package function `GasUsed` #1998

Open deelawn opened 5 months ago

deelawn commented 5 months ago

Description

Let's add a function called GasUsed, or some name with the same sentiment, that returns the gas used until the current point in execution. It can obtain gas used from the gas meter recently added to the machine -- https://github.com/gnolang/gno/blob/master/gnovm/pkg/gnolang/machine.go#L61. To prevent abusing this function, we should define a reasonable amount of gas to be consumed when it is invoked. The documentation should also be updated as a part of the PR that adds this.

There are two potential use cases for this:

  1. This can be helpful for benchmarking gno code -- users trying to figure out which parts of their code is consuming large amounts of gas
  2. This can be used to measure performance of running a bit of code if someone would like to deploy a leetcode style realm that accepts interfaces with methods for solving a posed coding problem.
notJoon commented 5 months ago

If it's possible to pull various data from the Machine, how about creating a package like runtime? I think it would be useful if we could directly check the memory usage by using Alloc field including gas usage, within the code.

https://github.com/gnolang/gno/blob/de2fc456c1cdf141def2a4ac77d5d0d5bf757a2d/gnovm/pkg/gnolang/alloc.go#L9-L12

zivkovicmilos commented 4 months ago

I like this idea a lot, we can take inspiration from what Solidity has:

https://docs.soliditylang.org/en/develop/units-and-global-variables.html#block-and-transaction-properties

thinhnx-var commented 4 months ago

I am interested in this issue. I gonna try to implement this one 🙏

thinhnx-var commented 4 months ago

To prevent abusing this function, we should define a reasonable amount of gas to be consumed when it is invoked.

-> Should we defined the amount of gas in DefaultGasConfig in tm2 types package, or as const somewhere reasonable, and consumed it immediately when GasUsed() is invoked successfully? Can you give me some suggestions on this? @deelawn @notJoon ... Sorry if this tag is wrong targets 🙏

thehowl commented 3 months ago

I was discussing with @moul on whether we want something like this.

We should always consider the implication of all the information we're giving to the developer. Like for the discussions we've had about whether to have PrevRealm/GetOrigCaller. If we're building a fully-deterministic system, any additional "context information" being passed in to the developer can be seen as an extra parameter to a "pure" function (in the mathematical sense; ie., a pure function with the same input will always yield the same output).

Let's take a look at the two use cases in the OP:

This can be helpful for benchmarking gno code -- users trying to figure out which parts of their code is consuming large amounts of gas This can be used to measure performance of running a bit of code if someone would like to deploy a leetcode style realm that accepts interfaces with methods for solving a posed coding problem.

I'm unsure about the second one; but the first one sounds like it's more of a candidate for testing. It's something we partly have with the --print-runtime-metrics feature of gno test; and we should improve:

Exposing gas on-chain, I think, also poses the risk of restricting us more if we want to change the way we count gas in the future.

So I'm thinking we should have this function either just as a testing standard library, or not at all.

moul commented 3 months ago

I suggest we start by replacing execution time in unit tests with consumed gas, or keeping both side by side.

CleanShot 2024-06-18 at 12 00 12

This should be sufficient for most optimization needs, in my opinion.


Next, I believe the best targets are:

I would avoid adding std.GasUsed completely, and I've considered this option for a long time, but I've since changed my mind. Instead, I propose adding std.TestGasUsed, limiting it to the testing context, only if the previous suggestions are not enough, but I guess they will be enough.

thinhnx-var commented 3 months ago

In my view, displaying gasUsed in unit test and the gno test -cover / adding it to -print-runtime-metrics is clear enough for information and testing purpose. Since this gasUsed is limited in testing scope, we just need to consider about where and how to display it. I am not so familiar with the debugger in gno, hence I dont have any idea.

Beside it, the -cpuprofile or profiling system is much more complex and gonna out of this discussion (as discussion in #2222 ).

montoya83 commented 3 months ago

A display with the execution time+consumed gas isn't something that is going to tire anyone's eyes. Keeping both -side by side- is much better, in my opinion.

gfant commented 2 months ago

This would be a great feature for Shiken @moul , since it would be useful to run the code onchain instead of off chain and avoid certain tasks for the API.