Make simulation use a transition matrix for block size
This enables simulating periods of high load, and periods of low to no load. (low load because future ops will still terminate in that time frame)
This commit is contained in:
parent
855e0ac70a
commit
e4b5e2c9f3
|
@ -37,6 +37,7 @@ IMPROVEMENTS
|
||||||
|
|
||||||
* SDK
|
* SDK
|
||||||
- #2573 [x/distribution] add accum invariance
|
- #2573 [x/distribution] add accum invariance
|
||||||
|
- \#1924 [simulation] Use a transition matrix for block size
|
||||||
|
|
||||||
* Tendermint
|
* Tendermint
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@ func generateSelfSignedCert(host string) (certBytes []byte, priv *ecdsa.PrivateK
|
||||||
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
|
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
|
||||||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||||||
BasicConstraintsValid: true,
|
BasicConstraintsValid: true,
|
||||||
IsCA: true,
|
IsCA: true,
|
||||||
}
|
}
|
||||||
hosts := strings.Split(host, ",")
|
hosts := strings.Split(host, ",")
|
||||||
for _, h := range hosts {
|
for _, h := range hosts {
|
||||||
|
|
|
@ -28,4 +28,10 @@ var (
|
||||||
{10, 50, 5},
|
{10, 50, 5},
|
||||||
{0, 10, 1000},
|
{0, 10, 1000},
|
||||||
})
|
})
|
||||||
|
// 3 states: rand in range [0, 4*provided blocksize], rand in range [0, 2 * provided blocksize], 0
|
||||||
|
blockSizeTransitionMatrix, _ = CreateTransitionMatrix([][]int{
|
||||||
|
{85, 5, 0},
|
||||||
|
{15, 92, 1},
|
||||||
|
{0, 3, 99},
|
||||||
|
})
|
||||||
)
|
)
|
||||||
|
|
|
@ -108,7 +108,7 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp,
|
||||||
blockLogBuilders = make([]*strings.Builder, numBlocks)
|
blockLogBuilders = make([]*strings.Builder, numBlocks)
|
||||||
}
|
}
|
||||||
displayLogs := logPrinter(testingMode, blockLogBuilders)
|
displayLogs := logPrinter(testingMode, blockLogBuilders)
|
||||||
blockSimulator := createBlockSimulator(testingMode, tb, t, event, invariants, ops, operationQueue, timeOperationQueue, numBlocks, displayLogs)
|
blockSimulator := createBlockSimulator(testingMode, tb, t, event, invariants, ops, operationQueue, timeOperationQueue, numBlocks, blockSize, displayLogs)
|
||||||
if !testingMode {
|
if !testingMode {
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
} else {
|
} else {
|
||||||
|
@ -142,7 +142,6 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp,
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := app.NewContext(false, header)
|
ctx := app.NewContext(false, header)
|
||||||
thisBlockSize := getBlockSize(r, blockSize)
|
|
||||||
|
|
||||||
// Run queued operations. Ignores blocksize if blocksize is too small
|
// Run queued operations. Ignores blocksize if blocksize is too small
|
||||||
logWriter("Queued operations")
|
logWriter("Queued operations")
|
||||||
|
@ -153,9 +152,8 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp,
|
||||||
assertAllInvariants(t, app, header, invariants, "QueuedOperations", displayLogs)
|
assertAllInvariants(t, app, header, invariants, "QueuedOperations", displayLogs)
|
||||||
}
|
}
|
||||||
|
|
||||||
thisBlockSize = thisBlockSize - numQueuedOpsRan - numQueuedTimeOpsRan
|
|
||||||
logWriter("Standard operations")
|
logWriter("Standard operations")
|
||||||
operations := blockSimulator(thisBlockSize, r, app, ctx, accs, header, logWriter)
|
operations := blockSimulator(r, app, ctx, accs, header, logWriter)
|
||||||
opCount += operations + numQueuedOpsRan + numQueuedTimeOpsRan
|
opCount += operations + numQueuedOpsRan + numQueuedTimeOpsRan
|
||||||
if testingMode {
|
if testingMode {
|
||||||
// Make sure invariants hold at end of block
|
// Make sure invariants hold at end of block
|
||||||
|
@ -200,9 +198,14 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp,
|
||||||
|
|
||||||
// Returns a function to simulate blocks. Written like this to avoid constant parameters being passed everytime, to minimize
|
// Returns a function to simulate blocks. Written like this to avoid constant parameters being passed everytime, to minimize
|
||||||
// memory overhead
|
// memory overhead
|
||||||
func createBlockSimulator(testingMode bool, tb testing.TB, t *testing.T, event func(string), invariants []Invariant, ops []WeightedOperation, operationQueue map[int][]Operation, timeOperationQueue []FutureOperation, totalNumBlocks int, displayLogs func()) func(
|
func createBlockSimulator(testingMode bool, tb testing.TB, t *testing.T, event func(string), invariants []Invariant, ops []WeightedOperation, operationQueue map[int][]Operation, timeOperationQueue []FutureOperation, totalNumBlocks int, avgBlockSize int, displayLogs func()) func(
|
||||||
blocksize int, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accounts []Account, header abci.Header, logWriter func(string)) (opCount int) {
|
r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accounts []Account, header abci.Header, logWriter func(string)) (opCount int) {
|
||||||
totalOpWeight := 0
|
var (
|
||||||
|
lastBlocksizeState = 0 // state for [4 * uniform distribution]
|
||||||
|
totalOpWeight = 0
|
||||||
|
blocksize int
|
||||||
|
)
|
||||||
|
|
||||||
for i := 0; i < len(ops); i++ {
|
for i := 0; i < len(ops); i++ {
|
||||||
totalOpWeight += ops[i].Weight
|
totalOpWeight += ops[i].Weight
|
||||||
}
|
}
|
||||||
|
@ -217,8 +220,10 @@ func createBlockSimulator(testingMode bool, tb testing.TB, t *testing.T, event f
|
||||||
// shouldn't happen
|
// shouldn't happen
|
||||||
return ops[0].Op
|
return ops[0].Op
|
||||||
}
|
}
|
||||||
return func(blocksize int, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
|
||||||
|
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
||||||
accounts []Account, header abci.Header, logWriter func(string)) (opCount int) {
|
accounts []Account, header abci.Header, logWriter func(string)) (opCount int) {
|
||||||
|
lastBlocksizeState, blocksize = getBlockSize(r, lastBlocksizeState, avgBlockSize)
|
||||||
for j := 0; j < blocksize; j++ {
|
for j := 0; j < blocksize; j++ {
|
||||||
logUpdate, futureOps, err := selectOp(r)(r, app, ctx, accounts, event)
|
logUpdate, futureOps, err := selectOp(r)(r, app, ctx, accounts, event)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -253,16 +258,18 @@ func getTestingMode(tb testing.TB) (testingMode bool, t *testing.T, b *testing.B
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func getBlockSize(r *rand.Rand, blockSize int) int {
|
func getBlockSize(r *rand.Rand, lastBlockSizeState, avgBlockSize int) (state, blocksize int) {
|
||||||
load := r.Float64()
|
// TODO: Make blockSizeTransitionMatrix non-global
|
||||||
switch {
|
// TODO: Make default blocksize transitition matrix actually make the average blocksize equal to avgBlockSize
|
||||||
case load < 0.33:
|
state = blockSizeTransitionMatrix.NextState(r, lastBlockSizeState)
|
||||||
return 0
|
if state == 0 {
|
||||||
case load < 0.66:
|
blocksize = r.Intn(avgBlockSize * 4)
|
||||||
return r.Intn(blockSize * 2)
|
} else if state == 1 {
|
||||||
default:
|
blocksize = r.Intn(avgBlockSize * 2)
|
||||||
return r.Intn(blockSize * 4)
|
} else {
|
||||||
|
blocksize = 0
|
||||||
}
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// adds all future operations into the operation queue.
|
// adds all future operations into the operation queue.
|
||||||
|
|
Loading…
Reference in New Issue