From 6acc9a62f83450eb51e22c5062b82730d482f41b Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Thu, 11 Jun 2020 20:37:14 +0200 Subject: [PATCH 1/3] Split gas internally into compute gas and storage gas Signed-off-by: Jakub Sztandera --- chain/vm/gas.go | 53 ++++++++++++++++++++++++++++++------------ chain/vm/gas_v0.go | 56 +++++++++++++++++++++++---------------------- chain/vm/runtime.go | 11 +++++---- chain/vm/vm.go | 4 ++-- 4 files changed, 75 insertions(+), 49 deletions(-) diff --git a/chain/vm/gas.go b/chain/vm/gas.go index f1cf89845..c030621f6 100644 --- a/chain/vm/gas.go +++ b/chain/vm/gas.go @@ -12,34 +12,57 @@ import ( "github.com/ipfs/go-cid" ) +const ( + GasStorageMulti = 1 + GasComputeMulti = 1 +) + +type GasCharge struct { + Name string + ComputeGas int64 + StorageGas int64 +} + +func (g GasCharge) Total() int64 { + return g.ComputeGas*GasComputeMulti + g.StorageGas*GasStorageMulti +} + +func newGasCharge(name string, computeGas int64, storageGas int64) GasCharge { + return GasCharge{ + Name: name, + ComputeGas: computeGas, + StorageGas: storageGas, + } +} + // Pricelist provides prices for operations in the VM. // // Note: this interface should be APPEND ONLY since last chain checkpoint type Pricelist interface { // OnChainMessage returns the gas used for storing a message of a given size in the chain. - OnChainMessage(msgSize int) int64 + OnChainMessage(msgSize int) GasCharge // OnChainReturnValue returns the gas used for storing the response of a message in the chain. - OnChainReturnValue(dataSize int) int64 + OnChainReturnValue(dataSize int) GasCharge // OnMethodInvocation returns the gas used when invoking a method. - OnMethodInvocation(value abi.TokenAmount, methodNum abi.MethodNum) int64 + OnMethodInvocation(value abi.TokenAmount, methodNum abi.MethodNum) GasCharge // OnIpldGet returns the gas used for storing an object - OnIpldGet(dataSize int) int64 + OnIpldGet(dataSize int) GasCharge // OnIpldPut returns the gas used for storing an object - OnIpldPut(dataSize int) int64 + OnIpldPut(dataSize int) GasCharge // OnCreateActor returns the gas used for creating an actor - OnCreateActor() int64 + OnCreateActor() GasCharge // OnDeleteActor returns the gas used for deleting an actor - OnDeleteActor() int64 + OnDeleteActor() GasCharge - OnVerifySignature(sigType crypto.SigType, planTextSize int) (int64, error) - OnHashing(dataSize int) int64 - OnComputeUnsealedSectorCid(proofType abi.RegisteredProof, pieces []abi.PieceInfo) int64 - OnVerifySeal(info abi.SealVerifyInfo) int64 - OnVerifyPost(info abi.WindowPoStVerifyInfo) int64 - OnVerifyConsensusFault() int64 + OnVerifySignature(sigType crypto.SigType, planTextSize int) (GasCharge, error) + OnHashing(dataSize int) GasCharge + OnComputeUnsealedSectorCid(proofType abi.RegisteredProof, pieces []abi.PieceInfo) GasCharge + OnVerifySeal(info abi.SealVerifyInfo) GasCharge + OnVerifyPost(info abi.WindowPoStVerifyInfo) GasCharge + OnVerifyConsensusFault() GasCharge } var prices = map[abi.ChainEpoch]Pricelist{ @@ -93,7 +116,7 @@ func PricelistByEpoch(epoch abi.ChainEpoch) Pricelist { type pricedSyscalls struct { under vmr.Syscalls pl Pricelist - chargeGas func(int64) + chargeGas func(GasCharge) } // Verifies that a signature is valid for an address and plaintext. @@ -146,6 +169,6 @@ func (ps pricedSyscalls) VerifyConsensusFault(h1 []byte, h2 []byte, extra []byte } func (ps pricedSyscalls) BatchVerifySeals(inp map[address.Address][]abi.SealVerifyInfo) (map[address.Address][]bool, error) { - ps.chargeGas(0) // TODO: this is only called by the cron actor. Should we even charge gas? + ps.chargeGas(newGasCharge("BatchVerifySeals", 0, 0)) // TODO: this is only called by the cron actor. Should we even charge gas? return ps.under.BatchVerifySeals(inp) } diff --git a/chain/vm/gas_v0.go b/chain/vm/gas_v0.go index a20ac927d..0b6196377 100644 --- a/chain/vm/gas_v0.go +++ b/chain/vm/gas_v0.go @@ -2,6 +2,7 @@ package vm import ( "fmt" + "github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/crypto" @@ -84,17 +85,17 @@ type pricelistV0 struct { var _ Pricelist = (*pricelistV0)(nil) // OnChainMessage returns the gas used for storing a message of a given size in the chain. -func (pl *pricelistV0) OnChainMessage(msgSize int) int64 { - return pl.onChainMessageBase + pl.onChainMessagePerByte*int64(msgSize) +func (pl *pricelistV0) OnChainMessage(msgSize int) GasCharge { + return newGasCharge("OnChainMessage", 0, pl.onChainMessageBase+pl.onChainMessagePerByte*int64(msgSize)) } // OnChainReturnValue returns the gas used for storing the response of a message in the chain. -func (pl *pricelistV0) OnChainReturnValue(dataSize int) int64 { - return int64(dataSize) * pl.onChainReturnValuePerByte +func (pl *pricelistV0) OnChainReturnValue(dataSize int) GasCharge { + return newGasCharge("OnChainReturnValue", 0, int64(dataSize)*pl.onChainReturnValuePerByte) } // OnMethodInvocation returns the gas used when invoking a method. -func (pl *pricelistV0) OnMethodInvocation(value abi.TokenAmount, methodNum abi.MethodNum) int64 { +func (pl *pricelistV0) OnMethodInvocation(value abi.TokenAmount, methodNum abi.MethodNum) GasCharge { ret := pl.sendBase if value != abi.NewTokenAmount(0) { ret += pl.sendTransferFunds @@ -102,62 +103,63 @@ func (pl *pricelistV0) OnMethodInvocation(value abi.TokenAmount, methodNum abi.M if methodNum != builtin.MethodSend { ret += pl.sendInvokeMethod } - return ret + return newGasCharge("OnMethodInvocation", ret, 0) } // OnIpldGet returns the gas used for storing an object -func (pl *pricelistV0) OnIpldGet(dataSize int) int64 { - return pl.ipldGetBase + int64(dataSize)*pl.ipldGetPerByte +func (pl *pricelistV0) OnIpldGet(dataSize int) GasCharge { + return newGasCharge("OnIpldGet", pl.ipldGetBase+int64(dataSize)*pl.ipldGetPerByte, 0) } // OnIpldPut returns the gas used for storing an object -func (pl *pricelistV0) OnIpldPut(dataSize int) int64 { - return pl.ipldPutBase + int64(dataSize)*pl.ipldPutPerByte +func (pl *pricelistV0) OnIpldPut(dataSize int) GasCharge { + return newGasCharge("OnIpldPut", pl.ipldPutBase, int64(dataSize)*pl.ipldPutPerByte) } // OnCreateActor returns the gas used for creating an actor -func (pl *pricelistV0) OnCreateActor() int64 { - return pl.createActorBase + pl.createActorExtra +func (pl *pricelistV0) OnCreateActor() GasCharge { + return newGasCharge("OnCreateActor", pl.createActorBase, pl.createActorExtra) } // OnDeleteActor returns the gas used for deleting an actor -func (pl *pricelistV0) OnDeleteActor() int64 { - return pl.deleteActor +func (pl *pricelistV0) OnDeleteActor() GasCharge { + return newGasCharge("OnDeleteActor", 0, pl.deleteActor) } // OnVerifySignature -func (pl *pricelistV0) OnVerifySignature(sigType crypto.SigType, planTextSize int) (int64, error) { +func (pl *pricelistV0) OnVerifySignature(sigType crypto.SigType, planTextSize int) (GasCharge, error) { costFn, ok := pl.verifySignature[sigType] if !ok { - return 0, fmt.Errorf("cost function for signature type %d not supported", sigType) + return GasCharge{}, fmt.Errorf("cost function for signature type %d not supported", sigType) } - return costFn(int64(planTextSize)), nil + sigName, _ := sigType.Name() + return newGasCharge("OnVerifySignature/"+sigName, costFn(int64(planTextSize)), 0), nil } // OnHashing -func (pl *pricelistV0) OnHashing(dataSize int) int64 { - return pl.hashingBase + int64(dataSize)*pl.hashingPerByte +func (pl *pricelistV0) OnHashing(dataSize int) GasCharge { + return newGasCharge("OnHashing", pl.hashingBase+int64(dataSize)*pl.hashingPerByte, 0) } // OnComputeUnsealedSectorCid -func (pl *pricelistV0) OnComputeUnsealedSectorCid(proofType abi.RegisteredProof, pieces []abi.PieceInfo) int64 { +func (pl *pricelistV0) OnComputeUnsealedSectorCid(proofType abi.RegisteredProof, pieces []abi.PieceInfo) GasCharge { // TODO: this needs more cost tunning, check with @lotus - return pl.computeUnsealedSectorCidBase + return newGasCharge("OnComputeUnsealedSectorCid", pl.computeUnsealedSectorCidBase, 0) } // OnVerifySeal -func (pl *pricelistV0) OnVerifySeal(info abi.SealVerifyInfo) int64 { +func (pl *pricelistV0) OnVerifySeal(info abi.SealVerifyInfo) GasCharge { // TODO: this needs more cost tunning, check with @lotus - return pl.verifySealBase + return newGasCharge("OnVerifySeal", pl.verifySealBase, 0) } // OnVerifyPost -func (pl *pricelistV0) OnVerifyPost(info abi.WindowPoStVerifyInfo) int64 { +func (pl *pricelistV0) OnVerifyPost(info abi.WindowPoStVerifyInfo) GasCharge { // TODO: this needs more cost tunning, check with @lotus - return pl.verifyPostBase + return newGasCharge("OnVerifyPost", pl.verifyPostBase, 0) } // OnVerifyConsensusFault -func (pl *pricelistV0) OnVerifyConsensusFault() int64 { - return pl.verifyConsensusFault +func (pl *pricelistV0) OnVerifyConsensusFault() GasCharge { + return newGasCharge("OnVerifyConsensusFault", pl.verifyConsensusFault, 0) } diff --git a/chain/vm/runtime.go b/chain/vm/runtime.go index 70583e47f..ae3a60616 100644 --- a/chain/vm/runtime.go +++ b/chain/vm/runtime.go @@ -484,14 +484,15 @@ func (rt *Runtime) stateCommit(oldh, newh cid.Cid) aerrors.ActorError { return nil } -func (rt *Runtime) ChargeGas(toUse int64) { - err := rt.chargeGasInternal(toUse) +func (rt *Runtime) ChargeGas(gas GasCharge) { + err := rt.chargeGasInternal(gas) if err != nil { panic(err) } } -func (rt *Runtime) chargeGasInternal(toUse int64) aerrors.ActorError { +func (rt *Runtime) chargeGasInternal(gas GasCharge) aerrors.ActorError { + toUse := gas.Total() if rt.gasUsed+toUse > rt.gasAvailable { rt.gasUsed = rt.gasAvailable return aerrors.Newf(exitcode.SysErrOutOfGas, "not enough gas: used=%d, available=%d", rt.gasUsed, rt.gasAvailable) @@ -500,8 +501,8 @@ func (rt *Runtime) chargeGasInternal(toUse int64) aerrors.ActorError { return nil } -func (rt *Runtime) chargeGasSafe(toUse int64) aerrors.ActorError { - return rt.chargeGasInternal(toUse) +func (rt *Runtime) chargeGasSafe(gas GasCharge) aerrors.ActorError { + return rt.chargeGasInternal(gas) } func (rt *Runtime) Pricelist() Pricelist { diff --git a/chain/vm/vm.go b/chain/vm/vm.go index 42d6d373e..11db0d419 100644 --- a/chain/vm/vm.go +++ b/chain/vm/vm.go @@ -62,7 +62,7 @@ func ResolveToKeyAddr(state types.StateTree, cst cbor.IpldStore, addr address.Ad var _ cbor.IpldBlockstore = (*gasChargingBlocks)(nil) type gasChargingBlocks struct { - chargeGas func(int64) + chargeGas func(GasCharge) pricelist Pricelist under cbor.IpldBlockstore } @@ -294,7 +294,7 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet, pl := PricelistByEpoch(vm.blockHeight) - msgGasCost := pl.OnChainMessage(cmsg.ChainLength()) + msgGasCost := pl.OnChainMessage(cmsg.ChainLength()).Total() // this should never happen, but is currently still exercised by some tests if msgGasCost > msg.GasLimit { return &ApplyRet{ From c90d35869bd74ab1992971a9f1ed62419313838b Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Thu, 11 Jun 2020 21:59:39 +0200 Subject: [PATCH 2/3] Add gas tracing Signed-off-by: Jakub Sztandera --- chain/sync.go | 2 +- chain/types/execresult.go | 55 +++++++++++++++++++++++++++++++++++---- chain/vm/runtime.go | 38 +++++++++++++++++++++++---- chain/vm/vm.go | 40 +++++++++++++++++++--------- cli/state.go | 15 +++++++++++ miner/miner.go | 2 +- 6 files changed, 127 insertions(+), 25 deletions(-) diff --git a/chain/sync.go b/chain/sync.go index 03ccc3ab7..f4b32f2bc 100644 --- a/chain/sync.go +++ b/chain/sync.go @@ -857,7 +857,7 @@ func (syncer *Syncer) checkBlockMessages(ctx context.Context, b *types.FullBlock // Phase 1: syntactic validation, as defined in the spec minGas := vm.PricelistByEpoch(baseTs.Height()).OnChainMessage(msg.ChainLength()) - if err := m.ValidForBlockInclusion(minGas); err != nil { + if err := m.ValidForBlockInclusion(minGas.Total()); err != nil { return err } diff --git a/chain/types/execresult.go b/chain/types/execresult.go index dd5c8fa3e..41372b832 100644 --- a/chain/types/execresult.go +++ b/chain/types/execresult.go @@ -1,12 +1,57 @@ package types -import "time" +import ( + "encoding/json" + "fmt" + "runtime" + "strings" + "time" +) type ExecutionTrace struct { - Msg *Message - MsgRct *MessageReceipt - Error string - Duration time.Duration + Msg *Message + MsgRct *MessageReceipt + Error string + Duration time.Duration + GasCharges []*GasTrace Subcalls []ExecutionTrace } + +type GasTrace struct { + Name string + Location string + TotalGas int64 + ComputeGas int64 + StorageGas int64 + + TimeTaken time.Duration + + Callers []uintptr `json:"-"` +} + +func (gt *GasTrace) MarshalJSON() ([]byte, error) { + type GasTraceCopy GasTrace + if gt.Location == "" { + if len(gt.Callers) != 0 { + frames := runtime.CallersFrames(gt.Callers) + for { + frame, more := frames.Next() + fn := strings.Split(frame.Function, "/") + + split := strings.Split(frame.File, "/") + file := strings.Join(split[len(split)-2:], "/") + gt.Location += fmt.Sprintf("%s@%s:%d", fn[len(fn)-1], file, frame.Line) + if !more { + break + } + gt.Location += "|" + } + } else { + gt.Location = "n/a" + } + } + + cpy := (*GasTraceCopy)(gt) + return json.Marshal(cpy) +} diff --git a/chain/vm/runtime.go b/chain/vm/runtime.go index ae3a60616..902ef94bb 100644 --- a/chain/vm/runtime.go +++ b/chain/vm/runtime.go @@ -5,6 +5,8 @@ import ( "context" "encoding/binary" "fmt" + gruntime "runtime" + "time" "github.com/filecoin-project/go-address" "github.com/filecoin-project/specs-actors/actors/abi" @@ -50,10 +52,12 @@ type Runtime struct { origin address.Address originNonce uint64 - executionTrace types.ExecutionTrace - numActorsCreated uint64 - allowInternal bool - callerValidated bool + executionTrace types.ExecutionTrace + numActorsCreated uint64 + allowInternal bool + callerValidated bool + lastGasChargeTime time.Time + lastGasCharge *types.GasTrace } func (rt *Runtime) TotalFilCircSupply() abi.TokenAmount { @@ -392,7 +396,7 @@ func (rt *Runtime) internalSend(from, to address.Address, method abi.MethodNum, } defer st.ClearSnapshot() - ret, errSend, subrt := rt.vm.send(ctx, msg, rt, 0) + ret, errSend, subrt := rt.vm.send(ctx, msg, rt, nil) if errSend != nil { if errRevert := st.Revert(); errRevert != nil { return nil, aerrors.Escalate(errRevert, "failed to revert state tree after failed subcall") @@ -490,9 +494,33 @@ func (rt *Runtime) ChargeGas(gas GasCharge) { panic(err) } } +func (rt *Runtime) finilizeGasTracing() { + if rt.lastGasCharge != nil { + rt.lastGasCharge.TimeTaken = time.Since(rt.lastGasChargeTime) + } +} func (rt *Runtime) chargeGasInternal(gas GasCharge) aerrors.ActorError { toUse := gas.Total() + var callers [3]uintptr + cout := gruntime.Callers(3, callers[:]) + + now := time.Now() + if rt.lastGasCharge != nil { + rt.lastGasCharge.TimeTaken = now.Sub(rt.lastGasChargeTime) + } + + gasTrace := types.GasTrace{ + Name: gas.Name, + TotalGas: toUse, + ComputeGas: gas.ComputeGas, + StorageGas: gas.StorageGas, + Callers: callers[:cout], + } + rt.executionTrace.GasCharges = append(rt.executionTrace.GasCharges, &gasTrace) + rt.lastGasChargeTime = now + rt.lastGasCharge = &gasTrace + if rt.gasUsed+toUse > rt.gasAvailable { rt.gasUsed = rt.gasAvailable return aerrors.Newf(exitcode.SysErrOutOfGas, "not enough gas: used=%d, available=%d", rt.gasUsed, rt.gasAvailable) diff --git a/chain/vm/vm.go b/chain/vm/vm.go index 11db0d419..75bbdfedb 100644 --- a/chain/vm/vm.go +++ b/chain/vm/vm.go @@ -96,13 +96,14 @@ func (vm *VM) makeRuntime(ctx context.Context, msg *types.Message, origin addres originNonce: originNonce, height: vm.blockHeight, - gasUsed: usedGas, - gasAvailable: msg.GasLimit, - numActorsCreated: nac, - pricelist: PricelistByEpoch(vm.blockHeight), - allowInternal: true, - callerValidated: false, - executionTrace: types.ExecutionTrace{Msg: msg}, + gasUsed: usedGas, + gasAvailable: msg.GasLimit, + numActorsCreated: nac, + pricelist: PricelistByEpoch(vm.blockHeight), + allowInternal: true, + callerValidated: false, + executionTrace: types.ExecutionTrace{Msg: msg}, + lastGasChargeTime: time.Now(), } rt.cst = &cbor.BasicIpldStore{ @@ -171,17 +172,17 @@ type ApplyRet struct { } func (vm *VM) send(ctx context.Context, msg *types.Message, parent *Runtime, - gasCharge int64) ([]byte, aerrors.ActorError, *Runtime) { + gasCharge *GasCharge) ([]byte, aerrors.ActorError, *Runtime) { start := time.Now() st := vm.cstate - gasUsed := gasCharge origin := msg.From on := msg.Nonce var nac uint64 = 0 + var gasUsed int64 if parent != nil { - gasUsed = parent.gasUsed + gasUsed + gasUsed = parent.gasUsed origin = parent.origin on = parent.originNonce nac = parent.numActorsCreated @@ -189,11 +190,22 @@ func (vm *VM) send(ctx context.Context, msg *types.Message, parent *Runtime, rt := vm.makeRuntime(ctx, msg, origin, on, gasUsed, nac) if parent != nil { + rt.lastGasChargeTime = parent.lastGasChargeTime + rt.lastGasCharge = parent.lastGasCharge defer func() { parent.gasUsed = rt.gasUsed + parent.lastGasChargeTime = rt.lastGasChargeTime + parent.lastGasCharge = rt.lastGasCharge }() } + if gasCharge != nil { + if err := rt.chargeGasSafe(*gasCharge); err != nil { + // this should never happen + return nil, aerrors.Wrap(err, "not enough gas for initial message charge, this should not happen"), rt + } + } + ret, err := func() ([]byte, aerrors.ActorError) { if aerr := rt.chargeGasSafe(rt.Pricelist().OnMethodInvocation(msg.Value, msg.Method)); aerr != nil { return nil, aerrors.Wrap(aerr, "not enough gas for method invocation") @@ -261,7 +273,7 @@ func checkMessage(msg *types.Message) error { func (vm *VM) ApplyImplicitMessage(ctx context.Context, msg *types.Message) (*ApplyRet, error) { start := time.Now() - ret, actorErr, rt := vm.send(ctx, msg, nil, 0) + ret, actorErr, rt := vm.send(ctx, msg, nil, nil) return &ApplyRet{ MessageReceipt: types.MessageReceipt{ ExitCode: aerrors.RetCode(actorErr), @@ -294,7 +306,8 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet, pl := PricelistByEpoch(vm.blockHeight) - msgGasCost := pl.OnChainMessage(cmsg.ChainLength()).Total() + msgGas := pl.OnChainMessage(cmsg.ChainLength()) + msgGasCost := msgGas.Total() // this should never happen, but is currently still exercised by some tests if msgGasCost > msg.GasLimit { return &ApplyRet{ @@ -377,7 +390,8 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet, } defer st.ClearSnapshot() - ret, actorErr, rt := vm.send(ctx, msg, nil, msgGasCost) + ret, actorErr, rt := vm.send(ctx, msg, nil, &msgGas) + rt.finilizeGasTracing() if aerrors.IsFatal(actorErr) { return nil, xerrors.Errorf("[from=%s,to=%s,n=%d,m=%d,h=%d] fatal error: %w", msg.From, msg.To, msg.Nonce, msg.Method, vm.blockHeight, actorErr) } diff --git a/cli/state.go b/cli/state.go index 1b6f676f2..c65eb1713 100644 --- a/cli/state.go +++ b/cli/state.go @@ -975,6 +975,7 @@ func computeStateHtml(ts *types.TipSet, o *api.ComputeStateOutput, getCode func( } .slow-true-false { color: #660; } .slow-true-true { color: #f80; } + table { font-size: 12px; } @@ -1026,6 +1027,13 @@ func computeStateHtml(ts *types.TipSet, o *api.ComputeStateOutput, getCode func( if ir.MsgRct.ExitCode != 0 { fmt.Printf(`
Error:
%s
`, ir.Error) } + fmt.Printf("\n
Gas Trace" + + "") + for _, gc := range ir.ExecutionTrace.GasCharges { + fmt.Printf("", + gc.Name, gc.TotalGas, gc.ComputeGas, gc.StorageGas, gc.TimeTaken, gc.Location) + } + fmt.Printf("
NameTotal/Compute/StorageTime TakenLocation
%s%d/%d/%d%s%s
\n") fmt.Println("
Execution trace:
") if err := printInternalExecutionsHtml(cid.String(), ir.ExecutionTrace.Subcalls, getCode); err != nil { @@ -1082,6 +1090,13 @@ func printInternalExecutionsHtml(hashName string, trace []types.ExecutionTrace, if im.MsgRct.ExitCode != 0 { fmt.Printf(`
Error:
%s
`, im.Error) } + fmt.Printf("\n
Gas Trace" + + "") + for _, gc := range im.GasCharges { + fmt.Printf("", + gc.Name, gc.TotalGas, gc.ComputeGas, gc.StorageGas, gc.TimeTaken, gc.Location) + } + fmt.Printf("
NameTotal/Compute/StorageTime TakenLocation
%s%d/%d/%d%s%s
\n") if len(im.Subcalls) > 0 { fmt.Println("
Subcalls:
") if err := printInternalExecutionsHtml(hashName, im.Subcalls, getCode); err != nil { diff --git a/miner/miner.go b/miner/miner.go index f2059ef7f..23f40338d 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -485,7 +485,7 @@ func SelectMessages(ctx context.Context, al ActorLookup, ts *types.TipSet, msgs vmstart := time.Now() minGas := vm.PricelistByEpoch(ts.Height()).OnChainMessage(msg.ChainLength()) // TODO: really should be doing just msg.ChainLength() but the sync side of this code doesnt seem to have access to that - if err := msg.VMMessage().ValidForBlockInclusion(minGas); err != nil { + if err := msg.VMMessage().ValidForBlockInclusion(minGas.Total()); err != nil { log.Warnf("invalid message in message pool: %s", err) continue } From 071ddf6563f37ef1d0a361102ed95f8411153c8a Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Thu, 11 Jun 2020 22:25:24 +0200 Subject: [PATCH 3/3] Add aggregate number, add number of bytes for storage calls Signed-off-by: Jakub Sztandera --- chain/vm/gas_v0.go | 4 ++-- cli/state.go | 24 +++++++++++++++++++++++- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/chain/vm/gas_v0.go b/chain/vm/gas_v0.go index 0b6196377..c631beaee 100644 --- a/chain/vm/gas_v0.go +++ b/chain/vm/gas_v0.go @@ -108,12 +108,12 @@ func (pl *pricelistV0) OnMethodInvocation(value abi.TokenAmount, methodNum abi.M // OnIpldGet returns the gas used for storing an object func (pl *pricelistV0) OnIpldGet(dataSize int) GasCharge { - return newGasCharge("OnIpldGet", pl.ipldGetBase+int64(dataSize)*pl.ipldGetPerByte, 0) + return newGasCharge(fmt.Sprintf("OnIpldGet:%db", dataSize), pl.ipldGetBase+int64(dataSize)*pl.ipldGetPerByte, 0) } // OnIpldPut returns the gas used for storing an object func (pl *pricelistV0) OnIpldPut(dataSize int) GasCharge { - return newGasCharge("OnIpldPut", pl.ipldPutBase, int64(dataSize)*pl.ipldPutPerByte) + return newGasCharge(fmt.Sprintf("OnIpldPut:%db", dataSize), pl.ipldPutBase, int64(dataSize)*pl.ipldPutPerByte) } // OnCreateActor returns the gas used for creating an actor diff --git a/cli/state.go b/cli/state.go index c65eb1713..acc648c23 100644 --- a/cli/state.go +++ b/cli/state.go @@ -975,7 +975,11 @@ func computeStateHtml(ts *types.TipSet, o *api.ComputeStateOutput, getCode func( } .slow-true-false { color: #660; } .slow-true-true { color: #f80; } - table { font-size: 12px; } + table { + font-size: 12px; + border-collapse: collapse; + } + tr.sum { border-top: 1px solid black; } @@ -1029,10 +1033,20 @@ func computeStateHtml(ts *types.TipSet, o *api.ComputeStateOutput, getCode func( } fmt.Printf("\n
Gas Trace" + "") + + var sumTotal, sumCompute, sumStorage int64 + var sumTime time.Duration for _, gc := range ir.ExecutionTrace.GasCharges { fmt.Printf("", gc.Name, gc.TotalGas, gc.ComputeGas, gc.StorageGas, gc.TimeTaken, gc.Location) + sumTotal += gc.TotalGas + sumCompute += gc.ComputeGas + sumStorage += gc.StorageGas + sumTime += gc.TimeTaken } + fmt.Printf("", + "Sum", sumTotal, sumCompute, sumStorage, sumTime, "") + fmt.Printf("
NameTotal/Compute/StorageTime TakenLocation
%s%d/%d/%d%s%s
%s%d/%d/%d%s%s
\n") fmt.Println("
Execution trace:
") @@ -1092,10 +1106,18 @@ func printInternalExecutionsHtml(hashName string, trace []types.ExecutionTrace, } fmt.Printf("\n
Gas Trace" + "") + var sumTotal, sumCompute, sumStorage int64 + var sumTime time.Duration for _, gc := range im.GasCharges { fmt.Printf("", gc.Name, gc.TotalGas, gc.ComputeGas, gc.StorageGas, gc.TimeTaken, gc.Location) + sumTotal += gc.TotalGas + sumCompute += gc.ComputeGas + sumStorage += gc.StorageGas + sumTime += gc.TimeTaken } + fmt.Printf("", + "Sum", sumTotal, sumCompute, sumStorage, sumTime, "") fmt.Printf("
NameTotal/Compute/StorageTime TakenLocation
%s%d/%d/%d%s%s
%s%d/%d/%d%s%s
\n") if len(im.Subcalls) > 0 { fmt.Println("
Subcalls:
")