near / nearcore

Reference client for NEAR Protocol
https://near.org
GNU General Public License v3.0
2.32k stars 622 forks source link

Add debug-only host function to snapshot gas profile #5127

Open matklad opened 2 years ago

matklad commented 2 years ago

Awesome idea by @birchmd: inside a contract, we want to get a hierarchical profile of gas breakdown, a-la https://github.com/matklad/tracing-span-tree but for gas.

One way to get this is via contract-side instrumentation. Strawman: add the following to gas counter and execution outcomes:

pub struct GasCounter {
 ...
 profile: ProfileData,
 profile_snapshots: Vec
 ,
 }

pub struct VMOutcome {
 ...
 profile: ProfileData,
 profile_snapshots: Vec
 
 ,
 }
 
 

and the following host function:

fn snapshot_gas_usage(self) -> u32

{ self.gas_counter.profile_snapshots.push(self.gas_counter.profile.clone()) }

This should give all all the requried data to then compute per-span profile. We might want to add some metadata to snapshot_gas_usage though...

bowenwang1996 commented 2 years ago

This will affect the performance right? How do we plan to enable it?

matklad commented 2 years ago

More so than performance, this'll add more logic to vm-logic (so, correctness concerns). I think we'll need some more structured discussion about how we'd enable such things. Will tackle the design properly after we make our current gas counter not slow.

My current thinking is that this should be compile-time gated sandbox-only functionality. So, on contract-runtime side, we'll add ability to have sandbox-only host functions. On dev-platform side, we'll expose this as nice profiling APIs in the SDK (would be cool to just use tracing-span) + some way to feed data from the sandbox to whatever the developer uses to view test/benchmark results.

austinabell commented 2 years ago

On dev-platform side, we'll expose this as nice profiling APIs in the SDK (would be cool to just use tracing-span) + some way to feed data from the sandbox to whatever the developer uses to view test/benchmark results.

I don't think anything should be added in the SDK, because the gas usage in mocked contexts for unit tests is not a good reflection of actual gas usage afaik. To have something this granular would only really be beneficial for e2e tests through sandbox and then hook into that API with whatever language's workspace, I think.

cc @ChaoticTempest

stale[bot] commented 2 years ago

This issue has been automatically marked as stale because it has not had recent activity in the last 2 months. It will be closed in 7 days if no further activity occurs. Thank you for your contributions.

matklad commented 2 years ago

Another interesting option: add a (debug only, obviously) way for the contract to suspend gas accounting. That'll allow the contract to implement custom gas-profiling logic internally:

stop_gas();
current_gas = used_gas();
start_gas();

// logic we want to profile

stop_gas();
let gas_diff = used_gas() - current_gas();
log(&format("used this amount of gas: {}", gas_diff));
start_gas();
matklad commented 2 years ago

Very non-production impl is here: https://github.com/near/nearcore/pull/6274

birchmd commented 2 years ago

I had given a crack at this some time ago as well: https://github.com/birchmd/nearcore/commit/b43863cfdd9c7e072625e8cad15435c181241f7e

I found it very useful at the time and would love to see this feature land in nearcore eventually!

stale[bot] commented 2 years ago

This issue has been automatically marked as stale because it has not had recent activity in the last 2 months. It will be closed in 7 days if no further activity occurs. Thank you for your contributions.