Skip to content

Enable realtime profiling refactoring #716

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 2 commits into from
Apr 1, 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
51 changes: 14 additions & 37 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@ import (
"flag"
"fmt"
"net/http"
_ "net/http/pprof"
"os"
"os/signal"
"path/filepath"
"runtime"
"runtime/pprof"
"strings"
"syscall"
"time"
Expand Down Expand Up @@ -54,6 +53,7 @@ var (
db *sql.DB
badgerDb *badger.DB
apiRPCPort, apiHTTPPort, monitoringPort int
cpuProfilingPort int
apiCertFile, apiKeyFile string
peerPort uint32
p2pServiceInstance p2p.Peer2PeerServiceInterface
Expand Down Expand Up @@ -96,7 +96,7 @@ var (
mainchainForkProcessor, spinechainForkProcessor blockchainsync.ForkingProcessorInterface
defaultSignatureType *crypto.Ed25519Signature
nodeKey *model.NodeKey
cpuProfile, memProfile bool
cpuProfile bool
)

func init() {
Expand All @@ -110,7 +110,6 @@ func init() {
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 @@ -248,6 +247,7 @@ func loadNodeConfig(configPath, configFileName, configExtension string) {
monitoringPort = viper.GetInt("monitoringPort")
apiRPCPort = viper.GetInt("apiRPCPort")
apiHTTPPort = viper.GetInt("apiHTTPPort")
cpuProfilingPort = viper.GetInt("cpuProfilingPort")
ownerAccountAddress = viper.GetString("ownerAccountAddress")
wellknownPeers = viper.GetStringSlice("wellknownPeers")
smithing = viper.GetBool("smithing")
Expand Down Expand Up @@ -295,6 +295,9 @@ func loadNodeConfig(configPath, configFileName, configExtension string) {
log.Printf("monitoringPort: %d", monitoringPort)
log.Printf("apiRPCPort: %d", apiRPCPort)
log.Printf("apiHTTPPort: %d", apiHTTPPort)
if cpuProfile {
log.Printf("cpuProfilingPort: %d", cpuProfilingPort)
}
log.Printf("ownerAccountAddress: %s", ownerAccountAddress)
log.Printf("nodePublicKey: %s", base64.StdEncoding.EncodeToString(nodeKey.PublicKey))
log.Printf("wellknownPeers: %s", strings.Join(wellknownPeers, ","))
Expand Down Expand Up @@ -421,8 +424,9 @@ func startNodeMonitoring() {
monitoring.SetMonitoringActive(true)
monitoring.SetNodePublicKey(defaultSignatureType.GetPublicKeyFromSeed(nodeSecretPhrase))
go func() {
http.Handle("/metrics", promhttp.Handler())
err := http.ListenAndServe(fmt.Sprintf(":%d", monitoringPort), nil)
mux := http.NewServeMux()
mux.Handle("/metrics", promhttp.Handler())
err := http.ListenAndServe(fmt.Sprintf(":%d", monitoringPort), mux)
if err != nil {
panic(fmt.Sprintf("failed to start monitoring service: %s", err))
}
Expand Down Expand Up @@ -867,38 +871,11 @@ 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)
go func() {
if err := http.ListenAndServe(fmt.Sprintf("localhost:%d", cpuProfilingPort), nil); err != nil {
log.Fatalf(fmt.Sprintf("failed to start profiling http server: %s", 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}
Expand Down
17 changes: 2 additions & 15 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,21 +89,8 @@ 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
4. `cpu-profile` (bool): enable realtime profiling for the running instance, via http server.
See [http pprof](https://golang.org/pkg/net/http/pprof/) for documentation on how to use this tool

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

Expand All @@ -16,6 +15,7 @@ apiRPCPort=7000
# comment out or set to 0 to disable http proxy, only enable in dev mode
apiHTTPPort=3031
monitoringPort=9090
cpuProfilingPort=6060
apiReqTimeoutSec=2

ownerAccountAddress = "BCZEGOb3WNx3fDOVf9ZS4EjvOIv_UeW4TVBQJ_6tHKlE"
Expand Down
2 changes: 1 addition & 1 deletion resource/config2.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ 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 All @@ -15,6 +14,7 @@ wellknownPeers=["127.0.0.1:8001"]
apiRPCPort=3002
apiHTTPPort=3032
monitoringPort=9092
cpuProfilingPort=6062
apiReqTimeoutSec=2

ownerAccountAddress = "OnEYzI-EMV6UTfoUEzpQUjkSlnqB82-SyRN7469lJTWH"
Expand Down
2 changes: 1 addition & 1 deletion resource/config3.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ 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 All @@ -15,6 +14,7 @@ wellknownPeers=["127.0.0.1:8002"]
apiRPCPort=3003
apiHTTPPort=3033
monitoringPort=9093
cpuProfilingPort=6063
apiReqTimeoutSec=2

ownerAccountAddress = "iSJt3H8wFOzlWKsy_UoEWF_OjF6oymHMqthyUMDKSyxb"
Expand Down
2 changes: 1 addition & 1 deletion resource/config4.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ 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 All @@ -15,6 +14,7 @@ wellknownPeers=["127.0.0.1:8001"]
apiRPCPort=3004
apiHTTPPort=3034
monitoringPort=9094
cpuProfilingPort=6064
apiReqTimeoutSec=2

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

# Peer
Expand All @@ -16,6 +15,7 @@ apiRPCPort=3005
# comment out or set to 0 to disable http proxy, only enable in dev mode
apiHTTPPort=3035
monitoringPort=9095
cpuProfilingPort=6065
apiReqTimeoutSec=2

ownerAccountAddress = "iSJt3H8wFOzlWKsy_UoEWF_OjF6oymHMqthyUMDKSyxb"
Expand Down