Merge pull request #4830 from filecoin-project/time/vm-flush

Gas Balancing
This commit is contained in:
Łukasz Magiera 2020-11-18 01:34:08 +01:00 committed by GitHub
commit c5470ee17e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 176 additions and 45 deletions

View File

@ -3,21 +3,17 @@ package vm
import ( import (
"fmt" "fmt"
vmr2 "github.com/filecoin-project/specs-actors/v2/actors/runtime" "github.com/filecoin-project/lotus/build"
proof2 "github.com/filecoin-project/specs-actors/v2/actors/runtime/proof"
"github.com/filecoin-project/go-address" "github.com/filecoin-project/go-address"
addr "github.com/filecoin-project/go-address" addr "github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/go-state-types/crypto"
vmr2 "github.com/filecoin-project/specs-actors/v2/actors/runtime"
proof2 "github.com/filecoin-project/specs-actors/v2/actors/runtime/proof"
"github.com/ipfs/go-cid" "github.com/ipfs/go-cid"
) )
const (
GasStorageMulti = 1000
GasComputeMulti = 1
)
type GasCharge struct { type GasCharge struct {
Name string Name string
Extra interface{} Extra interface{}
@ -132,6 +128,54 @@ var prices = map[abi.ChainEpoch]Pricelist{
verifyPostDiscount: true, verifyPostDiscount: true,
verifyConsensusFault: 495422, verifyConsensusFault: 495422,
}, },
abi.ChainEpoch(build.UpgradeCalicoHeight): &pricelistV0{
computeGasMulti: 1,
storageGasMulti: 1300,
onChainMessageComputeBase: 38863,
onChainMessageStorageBase: 36,
onChainMessageStoragePerByte: 1,
onChainReturnValuePerByte: 1,
sendBase: 29233,
sendTransferFunds: 27500,
sendTransferOnlyPremium: 159672,
sendInvokeMethod: -5377,
ipldGetBase: 114617,
ipldPutBase: 353640,
ipldPutPerByte: 1,
createActorCompute: 1108454,
createActorStorage: 36 + 40,
deleteActor: -(36 + 40), // -createActorStorage
verifySignature: map[crypto.SigType]int64{
crypto.SigTypeBLS: 16598605,
crypto.SigTypeSecp256k1: 1637292,
},
hashingBase: 31355,
computeUnsealedSectorCidBase: 98647,
verifySealBase: 2000, // TODO gas , it VerifySeal syscall is not used
verifyPostLookup: map[abi.RegisteredPoStProof]scalingCost{
abi.RegisteredPoStProof_StackedDrgWindow512MiBV1: {
flat: 117680921,
scale: 43780,
},
abi.RegisteredPoStProof_StackedDrgWindow32GiBV1: {
flat: 117680921,
scale: 43780,
},
abi.RegisteredPoStProof_StackedDrgWindow64GiBV1: {
flat: 117680921,
scale: 43780,
},
},
verifyPostDiscount: false,
verifyConsensusFault: 495422,
},
} }
// PricelistByEpoch finds the latest prices for the given epoch // PricelistByEpoch finds the latest prices for the given epoch

View File

@ -133,13 +133,13 @@ func (pl *pricelistV0) OnMethodInvocation(value abi.TokenAmount, methodNum abi.M
// OnIpldGet returns the gas used for storing an object // OnIpldGet returns the gas used for storing an object
func (pl *pricelistV0) OnIpldGet() GasCharge { func (pl *pricelistV0) OnIpldGet() GasCharge {
return newGasCharge("OnIpldGet", pl.ipldGetBase, 0) return newGasCharge("OnIpldGet", pl.ipldGetBase, 0).WithVirtual(114617, 0)
} }
// OnIpldPut returns the gas used for storing an object // OnIpldPut returns the gas used for storing an object
func (pl *pricelistV0) OnIpldPut(dataSize int) GasCharge { func (pl *pricelistV0) OnIpldPut(dataSize int) GasCharge {
return newGasCharge("OnIpldPut", pl.ipldPutBase, int64(dataSize)*pl.ipldPutPerByte*pl.storageGasMulti). return newGasCharge("OnIpldPut", pl.ipldPutBase, int64(dataSize)*pl.ipldPutPerByte*pl.storageGasMulti).
WithExtra(dataSize) WithExtra(dataSize).WithVirtual(400000, int64(dataSize)*1300)
} }
// OnCreateActor returns the gas used for creating an actor // OnCreateActor returns the gas used for creating an actor
@ -209,6 +209,7 @@ func (pl *pricelistV0) OnVerifyPost(info proof2.WindowPoStVerifyInfo) GasCharge
} }
return newGasCharge("OnVerifyPost", gasUsed, 0). return newGasCharge("OnVerifyPost", gasUsed, 0).
WithVirtual(117680921+43780*int64(len(info.ChallengedSectors)), 0).
WithExtra(map[string]interface{}{ WithExtra(map[string]interface{}{
"type": sectorSize, "type": sectorSize,
"size": len(info.ChallengedSectors), "size": len(info.ChallengedSectors),

View File

@ -539,12 +539,19 @@ func (rt *Runtime) chargeGasInternal(gas GasCharge, skip int) aerrors.ActorError
ComputeGas: gas.ComputeGas, ComputeGas: gas.ComputeGas,
StorageGas: gas.StorageGas, StorageGas: gas.StorageGas,
TotalVirtualGas: gas.VirtualCompute*GasComputeMulti + gas.VirtualStorage*GasStorageMulti,
VirtualComputeGas: gas.VirtualCompute, VirtualComputeGas: gas.VirtualCompute,
VirtualStorageGas: gas.VirtualStorage, VirtualStorageGas: gas.VirtualStorage,
Callers: callers[:cout], Callers: callers[:cout],
} }
if gasTrace.VirtualStorageGas == 0 {
gasTrace.VirtualStorageGas = gasTrace.StorageGas
}
if gasTrace.VirtualComputeGas == 0 {
gasTrace.VirtualComputeGas = gasTrace.ComputeGas
}
gasTrace.TotalVirtualGas = gasTrace.VirtualComputeGas + gasTrace.VirtualStorageGas
rt.executionTrace.GasCharges = append(rt.executionTrace.GasCharges, &gasTrace) rt.executionTrace.GasCharges = append(rt.executionTrace.GasCharges, &gasTrace)
rt.lastGasChargeTime = now rt.lastGasChargeTime = now
rt.lastGasCharge = &gasTrace rt.lastGasCharge = &gasTrace

View File

@ -9,6 +9,7 @@ import (
"time" "time"
"github.com/filecoin-project/lotus/chain/actors/builtin" "github.com/filecoin-project/lotus/chain/actors/builtin"
"github.com/filecoin-project/lotus/metrics"
block "github.com/ipfs/go-block-format" block "github.com/ipfs/go-block-format"
cid "github.com/ipfs/go-cid" cid "github.com/ipfs/go-cid"
@ -16,6 +17,7 @@ import (
logging "github.com/ipfs/go-log/v2" logging "github.com/ipfs/go-log/v2"
mh "github.com/multiformats/go-multihash" mh "github.com/multiformats/go-multihash"
cbg "github.com/whyrusleeping/cbor-gen" cbg "github.com/whyrusleeping/cbor-gen"
"go.opencensus.io/stats"
"go.opencensus.io/trace" "go.opencensus.io/trace"
"golang.org/x/xerrors" "golang.org/x/xerrors"
@ -606,6 +608,8 @@ func (vm *VM) ActorBalance(addr address.Address) (types.BigInt, aerrors.ActorErr
return act.Balance, nil return act.Balance, nil
} }
type vmFlushKey struct{}
func (vm *VM) Flush(ctx context.Context) (cid.Cid, error) { func (vm *VM) Flush(ctx context.Context) (cid.Cid, error) {
_, span := trace.StartSpan(ctx, "vm.Flush") _, span := trace.StartSpan(ctx, "vm.Flush")
defer span.End() defer span.End()
@ -618,7 +622,7 @@ func (vm *VM) Flush(ctx context.Context) (cid.Cid, error) {
return cid.Undef, xerrors.Errorf("flushing vm: %w", err) return cid.Undef, xerrors.Errorf("flushing vm: %w", err)
} }
if err := Copy(ctx, from, to, root); err != nil { if err := Copy(context.WithValue(ctx, vmFlushKey{}, true), from, to, root); err != nil {
return cid.Undef, xerrors.Errorf("copying tree: %w", err) return cid.Undef, xerrors.Errorf("copying tree: %w", err)
} }
@ -675,21 +679,48 @@ func linksForObj(blk block.Block, cb func(cid.Cid)) error {
func Copy(ctx context.Context, from, to blockstore.Blockstore, root cid.Cid) error { func Copy(ctx context.Context, from, to blockstore.Blockstore, root cid.Cid) error {
ctx, span := trace.StartSpan(ctx, "vm.Copy") // nolint ctx, span := trace.StartSpan(ctx, "vm.Copy") // nolint
defer span.End() defer span.End()
start := time.Now()
var numBlocks int var numBlocks int
var totalCopySize int var totalCopySize int
var batch []block.Block const batchSize = 128
const bufCount = 3
freeBufs := make(chan []block.Block, bufCount)
toFlush := make(chan []block.Block, bufCount)
for i := 0; i < bufCount; i++ {
freeBufs <- make([]block.Block, 0, batchSize)
}
errFlushChan := make(chan error)
go func() {
for b := range toFlush {
if err := to.PutMany(b); err != nil {
close(freeBufs)
errFlushChan <- xerrors.Errorf("batch put in copy: %w", err)
return
}
freeBufs <- b[:0]
}
close(errFlushChan)
close(freeBufs)
}()
var batch = <-freeBufs
batchCp := func(blk block.Block) error { batchCp := func(blk block.Block) error {
numBlocks++ numBlocks++
totalCopySize += len(blk.RawData()) totalCopySize += len(blk.RawData())
batch = append(batch, blk) batch = append(batch, blk)
if len(batch) > 100 {
if err := to.PutMany(batch); err != nil { if len(batch) >= batchSize {
return xerrors.Errorf("batch put in copy: %w", err) toFlush <- batch
var ok bool
batch, ok = <-freeBufs
if !ok {
return <-errFlushChan
} }
batch = batch[:0]
} }
return nil return nil
} }
@ -699,15 +730,22 @@ func Copy(ctx context.Context, from, to blockstore.Blockstore, root cid.Cid) err
} }
if len(batch) > 0 { if len(batch) > 0 {
if err := to.PutMany(batch); err != nil { toFlush <- batch
return xerrors.Errorf("batch put in copy: %w", err) }
} close(toFlush) // close the toFlush triggering the loop to end
err := <-errFlushChan // get error out or get nil if it was closed
if err != nil {
return err
} }
span.AddAttributes( span.AddAttributes(
trace.Int64Attribute("numBlocks", int64(numBlocks)), trace.Int64Attribute("numBlocks", int64(numBlocks)),
trace.Int64Attribute("copySize", int64(totalCopySize)), trace.Int64Attribute("copySize", int64(totalCopySize)),
) )
if yes, ok := ctx.Value(vmFlushKey{}).(bool); yes && ok {
took := metrics.SinceInMilliseconds(start)
stats.Record(ctx, metrics.VMFlushCopyCount.M(int64(numBlocks)), metrics.VMFlushCopyDuration.M(took))
}
return nil return nil
} }

View File

@ -73,6 +73,8 @@ const (
// MethodInspectRuntime is the identifier for the method that returns the // MethodInspectRuntime is the identifier for the method that returns the
// current runtime values. // current runtime values.
MethodInspectRuntime MethodInspectRuntime
// MethodCreateState is the identifier for the method that creates the chaos actor's state.
MethodCreateState
) )
// Exports defines the methods this actor exposes publicly. // Exports defines the methods this actor exposes publicly.
@ -87,6 +89,7 @@ func (a Actor) Exports() []interface{} {
MethodMutateState: a.MutateState, MethodMutateState: a.MutateState,
MethodAbortWith: a.AbortWith, MethodAbortWith: a.AbortWith,
MethodInspectRuntime: a.InspectRuntime, MethodInspectRuntime: a.InspectRuntime,
MethodCreateState: a.CreateState,
} }
} }
@ -227,6 +230,14 @@ type MutateStateArgs struct {
Branch MutateStateBranch Branch MutateStateBranch
} }
// CreateState creates the chaos actor's state
func (a Actor) CreateState(rt runtime2.Runtime, _ *abi.EmptyValue) *abi.EmptyValue {
rt.ValidateImmediateCallerAcceptAny()
rt.StateCreate(&State{})
return nil
}
// MutateState attempts to mutate a state value in the actor. // MutateState attempts to mutate a state value in the actor.
func (a Actor) MutateState(rt runtime2.Runtime, args *MutateStateArgs) *abi.EmptyValue { func (a Actor) MutateState(rt runtime2.Runtime, args *MutateStateArgs) *abi.EmptyValue {
rt.ValidateImmediateCallerAcceptAny() rt.ValidateImmediateCallerAcceptAny()

View File

@ -129,8 +129,9 @@ func TestMutateStateInTransaction(t *testing.T) {
var a Actor var a Actor
rt.ExpectValidateCallerAny() rt.ExpectValidateCallerAny()
rt.StateCreate(&State{}) rt.Call(a.CreateState, nil)
rt.ExpectValidateCallerAny()
val := "__mutstat test" val := "__mutstat test"
rt.Call(a.MutateState, &MutateStateArgs{ rt.Call(a.MutateState, &MutateStateArgs{
Value: val, Value: val,
@ -155,23 +156,30 @@ func TestMutateStateAfterTransaction(t *testing.T) {
var a Actor var a Actor
rt.ExpectValidateCallerAny() rt.ExpectValidateCallerAny()
rt.StateCreate(&State{}) rt.Call(a.CreateState, nil)
rt.ExpectValidateCallerAny()
val := "__mutstat test" val := "__mutstat test"
defer func() {
if r := recover(); r == nil {
t.Fatal("The code did not panic")
} else {
var st State
rt.GetState(&st)
// state should be updated successfully _in_ the transaction but not outside
if st.Value != val+"-in" {
t.Fatal("state was not updated")
}
rt.Verify()
}
}()
rt.Call(a.MutateState, &MutateStateArgs{ rt.Call(a.MutateState, &MutateStateArgs{
Value: val, Value: val,
Branch: MutateAfterTransaction, Branch: MutateAfterTransaction,
}) })
var st State
rt.GetState(&st)
// state should be updated successfully _in_ the transaction but not outside
if st.Value != val+"-in" {
t.Fatal("state was not updated")
}
rt.Verify()
} }
func TestMutateStateReadonly(t *testing.T) { func TestMutateStateReadonly(t *testing.T) {
@ -182,22 +190,30 @@ func TestMutateStateReadonly(t *testing.T) {
var a Actor var a Actor
rt.ExpectValidateCallerAny() rt.ExpectValidateCallerAny()
rt.StateCreate(&State{}) rt.Call(a.CreateState, nil)
rt.ExpectValidateCallerAny()
val := "__mutstat test" val := "__mutstat test"
defer func() {
if r := recover(); r == nil {
t.Fatal("The code did not panic")
} else {
var st State
rt.GetState(&st)
if st.Value != "" {
t.Fatal("state was not expected to be updated")
}
rt.Verify()
}
}()
rt.Call(a.MutateState, &MutateStateArgs{ rt.Call(a.MutateState, &MutateStateArgs{
Value: val, Value: val,
Branch: MutateReadonly, Branch: MutateReadonly,
}) })
var st State
rt.GetState(&st)
if st.Value != "" {
t.Fatal("state was not expected to be updated")
}
rt.Verify()
} }
func TestMutateStateInvalidBranch(t *testing.T) { func TestMutateStateInvalidBranch(t *testing.T) {
@ -254,11 +270,13 @@ func TestInspectRuntime(t *testing.T) {
receiver := atesting2.NewIDAddr(t, 101) receiver := atesting2.NewIDAddr(t, 101)
builder := mock2.NewBuilder(context.Background(), receiver) builder := mock2.NewBuilder(context.Background(), receiver)
rt := builder.Build(t)
rt.SetCaller(caller, builtin2.AccountActorCodeID)
rt.StateCreate(&State{})
var a Actor var a Actor
rt := builder.Build(t)
rt.ExpectValidateCallerAny()
rt.Call(a.CreateState, nil)
rt.SetCaller(caller, builtin2.AccountActorCodeID)
rt.ExpectValidateCallerAny() rt.ExpectValidateCallerAny()
ret := rt.Call(a.InspectRuntime, abi.Empty) ret := rt.Call(a.InspectRuntime, abi.Empty)
rtr, ok := ret.(*InspectRuntimeReturn) rtr, ok := ret.(*InspectRuntimeReturn)

2
go.mod
View File

@ -40,7 +40,7 @@ require (
github.com/filecoin-project/go-statestore v0.1.0 github.com/filecoin-project/go-statestore v0.1.0
github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b
github.com/filecoin-project/specs-actors v0.9.13 github.com/filecoin-project/specs-actors v0.9.13
github.com/filecoin-project/specs-actors/v2 v2.3.0 github.com/filecoin-project/specs-actors/v2 v2.3.2
github.com/filecoin-project/specs-storage v0.1.1-0.20201105051918-5188d9774506 github.com/filecoin-project/specs-storage v0.1.1-0.20201105051918-5188d9774506
github.com/filecoin-project/test-vectors/schema v0.0.5 github.com/filecoin-project/test-vectors/schema v0.0.5
github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1 github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1

4
go.sum
View File

@ -289,8 +289,8 @@ github.com/filecoin-project/specs-actors v0.9.12/go.mod h1:TS1AW/7LbG+615j4NsjMK
github.com/filecoin-project/specs-actors v0.9.13 h1:rUEOQouefi9fuVY/2HOroROJlZbOzWYXXeIh41KF2M4= github.com/filecoin-project/specs-actors v0.9.13 h1:rUEOQouefi9fuVY/2HOroROJlZbOzWYXXeIh41KF2M4=
github.com/filecoin-project/specs-actors v0.9.13/go.mod h1:TS1AW/7LbG+615j4NsjMK1qlpAwaFsG9w0V2tg2gSao= github.com/filecoin-project/specs-actors v0.9.13/go.mod h1:TS1AW/7LbG+615j4NsjMK1qlpAwaFsG9w0V2tg2gSao=
github.com/filecoin-project/specs-actors/v2 v2.0.1/go.mod h1:v2NZVYinNIKA9acEMBm5wWXxqv5+frFEbekBFemYghY= github.com/filecoin-project/specs-actors/v2 v2.0.1/go.mod h1:v2NZVYinNIKA9acEMBm5wWXxqv5+frFEbekBFemYghY=
github.com/filecoin-project/specs-actors/v2 v2.3.0 h1:V7lHeF2ylfFi84F4y80u5FE4BpPHYGvB71kLrhXkJto= github.com/filecoin-project/specs-actors/v2 v2.3.2 h1:2Vcf4CGa29kRh4JJ02m+FbvD/p3YNnLGsaHfw7Uj49g=
github.com/filecoin-project/specs-actors/v2 v2.3.0/go.mod h1:UuJQLoTx/HPvvWeqlIFmC/ywlOLHNe8SNQ3OunFbu2Y= github.com/filecoin-project/specs-actors/v2 v2.3.2/go.mod h1:UuJQLoTx/HPvvWeqlIFmC/ywlOLHNe8SNQ3OunFbu2Y=
github.com/filecoin-project/specs-storage v0.1.1-0.20201105051918-5188d9774506 h1:Ur/l2+6qN+lQiqjozWWc5p9UDaAMDZKTlDS98oRnlIw= github.com/filecoin-project/specs-storage v0.1.1-0.20201105051918-5188d9774506 h1:Ur/l2+6qN+lQiqjozWWc5p9UDaAMDZKTlDS98oRnlIw=
github.com/filecoin-project/specs-storage v0.1.1-0.20201105051918-5188d9774506/go.mod h1:nJRRM7Aa9XVvygr3W9k6xGF46RWzr2zxF/iGoAIfA/g= github.com/filecoin-project/specs-storage v0.1.1-0.20201105051918-5188d9774506/go.mod h1:nJRRM7Aa9XVvygr3W9k6xGF46RWzr2zxF/iGoAIfA/g=
github.com/filecoin-project/test-vectors/schema v0.0.5 h1:w3zHQhzM4pYxJDl21avXjOKBLF8egrvwUwjpT8TquDg= github.com/filecoin-project/test-vectors/schema v0.0.5 h1:w3zHQhzM4pYxJDl21avXjOKBLF8egrvwUwjpT8TquDg=

View File

@ -53,6 +53,8 @@ var (
PubsubSendRPC = stats.Int64("pubsub/send_rpc", "Counter for total sent RPCs", stats.UnitDimensionless) PubsubSendRPC = stats.Int64("pubsub/send_rpc", "Counter for total sent RPCs", stats.UnitDimensionless)
PubsubDropRPC = stats.Int64("pubsub/drop_rpc", "Counter for total dropped RPCs", stats.UnitDimensionless) PubsubDropRPC = stats.Int64("pubsub/drop_rpc", "Counter for total dropped RPCs", stats.UnitDimensionless)
APIRequestDuration = stats.Float64("api/request_duration_ms", "Duration of API requests", stats.UnitMilliseconds) APIRequestDuration = stats.Float64("api/request_duration_ms", "Duration of API requests", stats.UnitMilliseconds)
VMFlushCopyDuration = stats.Float64("vm/flush_copy_ms", "Time spent in VM Flush Copy", stats.UnitMilliseconds)
VMFlushCopyCount = stats.Int64("vm/flush_copy_count", "Number of copied objects", stats.UnitDimensionless)
) )
var ( var (
@ -146,6 +148,14 @@ var (
Aggregation: defaultMillisecondsDistribution, Aggregation: defaultMillisecondsDistribution,
TagKeys: []tag.Key{APIInterface, Endpoint}, TagKeys: []tag.Key{APIInterface, Endpoint},
} }
VMFlushCopyDurationView = &view.View{
Measure: VMFlushCopyDuration,
Aggregation: view.Sum(),
}
VMFlushCopyCountView = &view.View{
Measure: VMFlushCopyCount,
Aggregation: view.Sum(),
}
) )
// DefaultViews is an array of OpenCensus views for metric gathering purposes // DefaultViews is an array of OpenCensus views for metric gathering purposes
@ -171,6 +181,8 @@ var DefaultViews = append([]*view.View{
PubsubSendRPCView, PubsubSendRPCView,
PubsubDropRPCView, PubsubDropRPCView,
APIRequestDurationView, APIRequestDurationView,
VMFlushCopyCountView,
VMFlushCopyDurationView,
}, },
rpcmetrics.DefaultViews...) rpcmetrics.DefaultViews...)