Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

simulation: Write logs on panic #2285

Merged
merged 3 commits into from
Sep 11, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions PENDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ IMPROVEMENTS
* [store] \#1952, \#2281 Update IAVL dependency to v0.11.0
* [simulation] Make timestamps randomized [#2153](https://github.com/cosmos/cosmos-sdk/pull/2153)
* [simulation] Make logs not just pure strings, speeding it up by a large factor at greater block heights \#2282
* [simulation] Logs get written to file if large, and also get printed on panics \#2285

* Tendermint

Expand Down
9 changes: 7 additions & 2 deletions cmd/gaia/app/sim_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ func BenchmarkFullGaiaSimulation(b *testing.B) {

// Run randomized simulation
// TODO parameterize numbers, save for a later PR
simulation.SimulateFromSeed(
err := simulation.SimulateFromSeed(
b, app.BaseApp, appStateFn, seed,
testAndRunTxs(app),
[]simulation.RandSetup{},
Expand All @@ -140,6 +140,10 @@ func BenchmarkFullGaiaSimulation(b *testing.B) {
blockSize,
commit,
)
if err != nil {
fmt.Println(err)
b.Fail()
}
if commit {
fmt.Println("GoLevelDB Stats")
fmt.Println(db.Stats()["leveldb.stats"])
Expand All @@ -164,7 +168,7 @@ func TestFullGaiaSimulation(t *testing.T) {
require.Equal(t, "GaiaApp", app.Name())

// Run randomized simulation
simulation.SimulateFromSeed(
err := simulation.SimulateFromSeed(
t, app.BaseApp, appStateFn, seed,
testAndRunTxs(app),
[]simulation.RandSetup{},
Expand All @@ -176,6 +180,7 @@ func TestFullGaiaSimulation(t *testing.T) {
if commit {
fmt.Println("Database Size", db.Stats()["database.size"])
}
require.Nil(t, err)
}

// TODO: Make another test for the fuzzer itself, which just has noOp txs
Expand Down
2 changes: 1 addition & 1 deletion store/transientstore.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package store

import (
dbm "github.com/tendermint/tendermint/libs/db"
sdk "github.com/cosmos/cosmos-sdk/types"
dbm "github.com/tendermint/tendermint/libs/db"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Linting was failing here, so I just ran make format.

)

var _ KVStore = (*transientStore)(nil)
Expand Down
47 changes: 33 additions & 14 deletions x/mock/simulation/random_simulate_blocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ package simulation

import (
"encoding/json"
"errors"
"fmt"
"math"
"math/rand"
"os"
"os/signal"
"runtime/debug"
"sort"
"strings"
"syscall"
Expand All @@ -26,9 +28,9 @@ import (
func Simulate(
t *testing.T, app *baseapp.BaseApp, appStateFn func(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress) json.RawMessage, ops []Operation, setups []RandSetup,
invariants []Invariant, numBlocks int, blockSize int, commit bool,
) {
) error {
time := time.Now().UnixNano()
SimulateFromSeed(t, app, appStateFn, time, ops, setups, invariants, numBlocks, blockSize, commit)
return SimulateFromSeed(t, app, appStateFn, time, ops, setups, invariants, numBlocks, blockSize, commit)
}

func initChain(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress, setups []RandSetup, app *baseapp.BaseApp,
Expand Down Expand Up @@ -56,7 +58,9 @@ func randTimestamp(r *rand.Rand) time.Time {
func SimulateFromSeed(
tb testing.TB, app *baseapp.BaseApp, appStateFn func(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress) json.RawMessage, seed int64, ops []Operation, setups []RandSetup,
invariants []Invariant, numBlocks int, blockSize int, commit bool,
) {
) (simError error) {
// in case we have to end early, don't os.Exit so that we can run cleanup code.
stopEarly := false
testingMode, t, b := getTestingMode(tb)
fmt.Printf("Starting SimulateFromSeed with randomness created with seed %d\n", int(seed))
r := rand.New(rand.NewSource(seed))
Expand All @@ -79,12 +83,12 @@ func SimulateFromSeed(

// Setup code to catch SIGTERM's
c := make(chan os.Signal)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
signal.Notify(c, os.Interrupt, syscall.SIGTERM, syscall.SIGINT)
go func() {
<-c
fmt.Printf("Exiting early due to SIGTERM, on block %d, operation %d\n", header.Height, opCount)
DisplayEvents(events)
os.Exit(128 + int(syscall.SIGTERM))
fmt.Printf("Exiting early due to SIGTERM/SIGINT, on block %d, operation %d\n", header.Height, opCount)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not:

sig := <-c
fmt.Printf("Exiting early due to %s, on block %d, operation %d\n", sig, header.Height, opCount)

simError = errors.New("Exited due to SIGTERM/SIGINT")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto

stopEarly = true
}()

var pastTimes []time.Time
Expand All @@ -95,15 +99,27 @@ func SimulateFromSeed(
operationQueue := make(map[int][]Operation)
var blockLogBuilders []*strings.Builder

if !testingMode {
b.ResetTimer()
} else {
if testingMode {
blockLogBuilders = make([]*strings.Builder, numBlocks)
}
displayLogs := logPrinter(testingMode, blockLogBuilders)
blockSimulator := createBlockSimulator(testingMode, tb, t, event, invariants, ops, operationQueue, numBlocks, displayLogs)
if !testingMode {
b.ResetTimer()
} else {
// Recover logs in case of panic
defer func() {
if r := recover(); r != nil {
fmt.Println("Panic with err\n", r)
stackTrace := string(debug.Stack())
fmt.Println(stackTrace)
displayLogs()
simError = fmt.Errorf("Simulation halted due to panic on block %d", header.Height)
}
}()
}

for i := 0; i < numBlocks; i++ {
for i := 0; i < numBlocks && !stopEarly; i++ {
// Log the header time for future lookup
pastTimes = append(pastTimes, header.Time)
pastSigningValidators = append(pastSigningValidators, request.LastCommitInfo.Validators)
Expand All @@ -122,10 +138,9 @@ func SimulateFromSeed(

// Run queued operations. Ignores blocksize if blocksize is too small
numQueuedOpsRan := runQueuedOperations(operationQueue, int(header.Height), tb, r, app, ctx, keys, logWriter, displayLogs, event)
opCount += numQueuedOpsRan
thisBlockSize -= numQueuedOpsRan
operations := blockSimulator(thisBlockSize, r, app, ctx, keys, header, logWriter)
opCount += operations
opCount += operations + numQueuedOpsRan

res := app.EndBlock(abci.RequestEndBlock{})
header.Height++
Expand All @@ -146,9 +161,13 @@ func SimulateFromSeed(
// Update the validator set
validators = updateValidators(tb, r, validators, res.ValidatorUpdates, event)
}

if stopEarly {
DisplayEvents(events)
return
}
fmt.Printf("\nSimulation complete. Final height (blocks): %d, final time (seconds), : %v, operations ran %d\n", header.Height, header.Time, opCount)
DisplayEvents(events)
return nil
}

// Returns a function to simulate blocks. Written like this to avoid constant parameters being passed everytime, to minimize
Expand Down
29 changes: 26 additions & 3 deletions x/mock/simulation/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ package simulation
import (
"fmt"
"math/rand"
"os"
"sort"
"strings"
"testing"
"time"

"github.com/tendermint/tendermint/crypto"

Expand Down Expand Up @@ -94,13 +96,34 @@ func assertAllInvariants(t *testing.T, app *baseapp.BaseApp, invariants []Invari
func logPrinter(testingmode bool, logs []*strings.Builder) func() {
if testingmode {
return func() {
numLoggers := 0
for i := 0; i < len(logs); i++ {
// We're passed the last created block
if logs[i] == nil {
return
numLoggers = i - 1
break
}
}
var f *os.File
if numLoggers > 10 {
fileName := fmt.Sprintf("simulation_log_%s.txt", time.Now().Format("2006-01-02 15:04:05"))
fmt.Printf("Too many logs to display, instead writing to %s\n", fileName)
f, _ = os.Create(fileName)
}
for i := 0; i < numLoggers; i++ {
if f != nil {
_, err := f.WriteString(fmt.Sprintf("Begin block %d\n", i))
if err != nil {
panic("Failed to write logs to file")
}
_, err = f.WriteString((*logs[i]).String())
if err != nil {
panic("Failed to write logs to file")
}
} else {
fmt.Printf("Begin block %d\n", i)
fmt.Println((*logs[i]).String())
}
fmt.Printf("Begin block %d\n", i)
fmt.Println((*logs[i]).String())
}
}
}
Expand Down