Skip to content

Adding runtime cpu profiling for core node #712

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

Merged
merged 3 commits into from
Mar 31, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
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 .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ coverage.*
resource/zoobc_*
resource/snapshots*
resource_cluster/zoobc_*
resource/*.prof
cmd/*.new
accounts.txt
.editorconfig
Expand Down
3 changes: 0 additions & 3 deletions cmd/transaction/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,6 @@ var (
nodeOwnerAccountAddress string
nodeAddress string
lockedBalance int64
poowMessageByte []byte
signatureByte []byte
nodePubKey []byte
proofOfOwnershipHex string
databasePath string
databaseName string
Expand Down
45 changes: 44 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import (
"os"
"os/signal"
"path/filepath"
"runtime"
"runtime/pprof"
"strings"
"syscall"
"time"
Expand Down Expand Up @@ -46,7 +48,7 @@ import (

var (
dbPath, dbName, badgerDbPath, badgerDbName, nodeSecretPhrase, nodeKeyPath,
nodeKeyFile, nodePreSeed, ownerAccountAddress, myAddress, nodeKeyFilePath, snapshotPath string
nodeKeyFile, nodePreSeed, ownerAccountAddress, myAddress, nodeKeyFilePath, snapshotPath, profilingFilePathName string
dbInstance *database.SqliteDB
badgerDbInstance *database.BadgerDB
db *sql.DB
Expand Down Expand Up @@ -94,6 +96,7 @@ var (
mainchainForkProcessor, spinechainForkProcessor blockchainsync.ForkingProcessorInterface
defaultSignatureType *crypto.Ed25519Signature
nodeKey *model.NodeKey
cpuProfile, memProfile bool
)

func init() {
Expand All @@ -106,6 +109,8 @@ func init() {
flag.StringVar(&configPostfix, "config-postfix", "", "Usage")
flag.StringVar(&configPath, "config-path", "./resource", "Usage")
flag.BoolVar(&isDebugMode, "debug", false, "Usage")
flag.BoolVar(&cpuProfile, "cpu-profile", false, "if this flag is used, write cpu profile to file")
flag.BoolVar(&memProfile, "mem-profile", false, "if this flag is used, write memory (heap) profile to file")
flag.Parse()

loadNodeConfig(configPath, "config"+configPostfix, "toml")
Expand Down Expand Up @@ -257,6 +262,7 @@ func loadNodeConfig(configPath, configFileName, configExtension string) {
apiCertFile = viper.GetString("apiapiCertFile")
apiKeyFile = viper.GetString("apiKeyFile")
snapshotPath = viper.GetString("snapshotPath")
profilingFilePathName = viper.GetString("profilingFilePathName")

// get the node private key
nodeKeyFilePath = filepath.Join(nodeKeyPath, nodeKeyFile)
Expand Down Expand Up @@ -859,6 +865,42 @@ func startBlockchainSyncronizers() {
}

func main() {
// start cpu profiling if enabled
if cpuProfile {
if profilingFilePathName == "" {
log.Error("missing profilingFilePathName configuration parameter")
} else {
// add cpu to prof file name
f, err := os.Create(fmt.Sprintf(profilingFilePathName, "cpu"))
if err != nil {
log.Fatal("could not create CPU profile: ", err)
}
defer f.Close() // error handling omitted for example
if err := pprof.StartCPUProfile(f); err != nil {
log.Error("could not start CPU profile: ", err)
}
defer pprof.StopCPUProfile()
}
}

// start memory profiling if enabled
if memProfile {
if profilingFilePathName == "" {
log.Error("missing profilingFilePathName configuration parameter")
} else {
// add mem to prof file name
f, err := os.Create(fmt.Sprintf(profilingFilePathName, "mem"))
if err != nil {
log.Fatal("could not create memory profile: ", err)
}
defer f.Close() // error handling omitted for example
runtime.GC() // get up-to-date statistics
if err := pprof.WriteHeapProfile(f); err != nil {
log.Error("could not write memory profile: ", err)
}
}
}

migration := database.Migration{Query: queryExecutor}
if err := migration.Init(); err != nil {
loggerCoreService.Fatal(err)
Expand Down Expand Up @@ -886,6 +928,7 @@ func main() {
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
<-sigs
loggerCoreService.Info("Shutting down node...")

if mainchainProcessor != nil {
mainchainProcessor.Stop()
}
Expand Down
9 changes: 5 additions & 4 deletions p2p/service/p2pServerService_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,8 @@ func TestNewP2PServerService(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := NewP2PServerService(tt.args.fileService, tt.args.peerExplorer, tt.args.blockServices, tt.args.mempoolServices, tt.args.nodeSecretPhrase, tt.args.observer); !reflect.DeepEqual(got, tt.want) {
if got := NewP2PServerService(tt.args.fileService, tt.args.peerExplorer, tt.args.blockServices, tt.args.mempoolServices,
tt.args.nodeSecretPhrase, tt.args.observer); !reflect.DeepEqual(got, tt.want) {
t.Errorf("NewP2PServerService() = %v, want %v", got, tt.want)
}
})
Expand Down Expand Up @@ -1495,7 +1496,7 @@ func (*mockSendTransactionsMempoolServiceSuccess) ReceivedBlockTransactions(
lastBlock *model.Block,
nodeSecretPhrase string,
) ([]*model.BatchReceipt, error) {
return []*model.BatchReceipt{&model.BatchReceipt{
return []*model.BatchReceipt{{
SenderPublicKey: []byte{1},
}}, nil
}
Expand Down Expand Up @@ -1608,7 +1609,7 @@ func TestP2PServerService_SendBlockTransactions(t *testing.T) {
chainType: &mockChainType,
},
want: &model.SendBlockTransactionsResponse{
BatchReceipts: []*model.BatchReceipt{&model.BatchReceipt{
BatchReceipts: []*model.BatchReceipt{{
SenderPublicKey: []byte{1},
}},
},
Expand Down Expand Up @@ -1821,7 +1822,7 @@ func TestP2PServerService_RequestDownloadFile(t *testing.T) {
fileChunkNames: []string{mockRequestDownloadFileName},
},
want: &model.FileDownloadResponse{
FileChunks: [][]byte{[]byte{1}},
FileChunks: [][]byte{{1}},
},
wantErr: false,
},
Expand Down
16 changes: 16 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,22 @@ go run main.go
1. `debug` (bool): enters debug mode with capabilities like `prometheus monitoring` (uses port defined by `monitoringPort` in the config file).
2. `config-postfix` (string): defines which config file with defined postfix to use. It will use the config file in `./resource/config{postfix}`.toml.
3. `config-path` (string): defines the directory that will hold the resources and configs. by default it will use `./resource`. This will be useful particularly for robust resource placements, for example while used in Zoobc-Testing-Framework.
4. `cpu-profile` (bool): enable cpu profiling *(1)* for the running instance. A profile (node_cpu.prof) file will be persisted to storage
at a
location defined in profilingFilePathName config parameter.
5. `mem-profile` (bool): enable memory (heap) profiling *(1)* for the running instance. A profile (node_mem.prof) file will be persisted
to
storage at a
location defined in profilingFilePathName config parameter.

*(1)* Profiles can then be visualized with the pprof tool:
```
go tool pprof .resource/node_cpu.prof
```

See [Getting started with Go CPU and memory profiling](https://flaviocopes.com/golang-profiling/)
for documentation on how to use goLang pprof tool

- Command line tools
```bash
cd cmd
Expand Down
1 change: 1 addition & 0 deletions resource/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ dbName = "zoobc.db"
badgerDbPath="./resource"
badgerDbName="zoobc_1_kv/"
configPath = "./resource/"
profilingFilePathName = "./resource/node_%s.prof"
nodeKeyFile = "node_keys.json"
snapshotPath = "./resource/snapshots"

Expand Down
1 change: 1 addition & 0 deletions resource/config2.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ dbName = "zoobc_2.db"
badgerDbPath="./resource"
badgerDbName="zoobc_2_kv/"
configPath = "./resource/"
profilingFilePathName = "./resource/node_2_%s.prof"
nodeKeyFile = "node_keys_2.json"
snapshotPath = "./resource/snapshots_2"

Expand Down
1 change: 1 addition & 0 deletions resource/config3.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ dbName = "zoobc_3.db"
badgerDbPath="./resource"
badgerDbName="zoobc_3_kv/"
configPath = "./resource/"
profilingFilePathName = "./resource/node_3_%s.prof"
nodeKeyFile = "node_keys_3.json"
snapshotPath = "./resource/snapshots"

Expand Down
1 change: 1 addition & 0 deletions resource/config4.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ dbName = "zoobc_4.db"
badgerDbPath="./resource"
badgerDbName="zoobc_4_kv/"
configPath = "./resource/"
profilingFilePathName = "./resource/node_4_%s.prof"
nodeKeyFile = "node_keys_4.json"
snapshotPath = "./resource/snapshots"

Expand Down
1 change: 1 addition & 0 deletions resource/config5.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ badgerDbPath="./resource"
badgerDbName="zoobc_5_kv/"
configPath = "./resource/"
nodeKeyFile = "node_keys_5.json"
profilingFilePathName = "./resource/node_5_%s.prof"
snapshotPath = "./resource/snapshots"

# Peer
Expand Down