mirror of https://github.com/stashapp/stash.git
parent
bc9aa02835
commit
16fe21138f
12
README.md
12
README.md
|
@ -145,3 +145,15 @@ where the app can be cross-compiled. This process is kicked off by CI via the `
|
|||
command to open a bash shell to the container to poke around:
|
||||
|
||||
`docker run --rm --mount type=bind,source="$(pwd)",target=/stash -w /stash -i -t stashappdev/compiler:latest /bin/bash`
|
||||
|
||||
## Profiling
|
||||
|
||||
Stash can be profiled using the `--cpuprofile <output profile filename>` command line flag.
|
||||
|
||||
The resulting file can then be used with pprof as follows:
|
||||
|
||||
`go tool pprof <path to binary> <path to profile filename>`
|
||||
|
||||
With `graphviz` installed and in the path, a call graph can be generated with:
|
||||
|
||||
`go tool pprof -svg <path to binary> <path to profile filename> > <output svg file>`
|
||||
|
|
14
main.go
14
main.go
|
@ -2,6 +2,11 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/signal"
|
||||
"runtime/pprof"
|
||||
"syscall"
|
||||
|
||||
"github.com/stashapp/stash/pkg/api"
|
||||
"github.com/stashapp/stash/pkg/manager"
|
||||
|
||||
|
@ -12,9 +17,16 @@ import (
|
|||
func main() {
|
||||
manager.Initialize()
|
||||
api.Start()
|
||||
|
||||
// stop any profiling at exit
|
||||
defer pprof.StopCPUProfile()
|
||||
blockForever()
|
||||
}
|
||||
|
||||
func blockForever() {
|
||||
select {}
|
||||
// handle signals
|
||||
signals := make(chan os.Signal, 1)
|
||||
signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM)
|
||||
|
||||
<-signals
|
||||
}
|
||||
|
|
|
@ -142,6 +142,7 @@ func (e MissingConfigError) Error() string {
|
|||
}
|
||||
|
||||
type Instance struct {
|
||||
cpuProfilePath string
|
||||
isNewSystem bool
|
||||
}
|
||||
|
||||
|
@ -162,6 +163,13 @@ func (i *Instance) SetConfigFile(fn string) {
|
|||
viper.SetConfigFile(fn)
|
||||
}
|
||||
|
||||
// GetCPUProfilePath returns the path to the CPU profile file to output
|
||||
// profiling info to. This is set only via a commandline flag. Returns an
|
||||
// empty string if not set.
|
||||
func (i *Instance) GetCPUProfilePath() string {
|
||||
return i.cpuProfilePath
|
||||
}
|
||||
|
||||
func (i *Instance) Set(key string, value interface{}) {
|
||||
viper.Set(key, value)
|
||||
}
|
||||
|
|
|
@ -17,18 +17,20 @@ var once sync.Once
|
|||
|
||||
type flagStruct struct {
|
||||
configFilePath string
|
||||
cpuProfilePath string
|
||||
}
|
||||
|
||||
func Initialize() (*Instance, error) {
|
||||
var err error
|
||||
once.Do(func() {
|
||||
instance = &Instance{}
|
||||
|
||||
flags := initFlags()
|
||||
instance = &Instance{
|
||||
cpuProfilePath: flags.cpuProfilePath,
|
||||
}
|
||||
|
||||
if err = initConfig(flags); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
initEnvs()
|
||||
|
||||
if instance.isNewSystem {
|
||||
|
@ -46,6 +48,7 @@ func Initialize() (*Instance, error) {
|
|||
}
|
||||
|
||||
func initConfig(flags flagStruct) error {
|
||||
|
||||
// The config file is called config. Leave off the file extension.
|
||||
viper.SetConfigName("config")
|
||||
|
||||
|
@ -98,6 +101,7 @@ func initFlags() flagStruct {
|
|||
pflag.IP("host", net.IPv4(0, 0, 0, 0), "ip address for the host")
|
||||
pflag.Int("port", 9999, "port to serve from")
|
||||
pflag.StringVarP(&flags.configFilePath, "config", "c", "", "config file to use")
|
||||
pflag.StringVar(&flags.cpuProfilePath, "cpuprofile", "", "write cpu profile to file")
|
||||
|
||||
pflag.Parse()
|
||||
if err := viper.BindPFlags(pflag.CommandLine); err != nil {
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime/pprof"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
|
@ -55,6 +56,7 @@ func Initialize() *singleton {
|
|||
}
|
||||
|
||||
initLog()
|
||||
initProfiling(cfg.GetCPUProfilePath())
|
||||
|
||||
instance = &singleton{
|
||||
Config: cfg,
|
||||
|
@ -92,6 +94,22 @@ func Initialize() *singleton {
|
|||
return instance
|
||||
}
|
||||
|
||||
func initProfiling(cpuProfilePath string) {
|
||||
if cpuProfilePath == "" {
|
||||
return
|
||||
}
|
||||
|
||||
f, err := os.Create(cpuProfilePath)
|
||||
if err != nil {
|
||||
logger.Fatalf("unable to create cpu profile file: %s", err.Error())
|
||||
}
|
||||
|
||||
logger.Infof("profiling to %s", cpuProfilePath)
|
||||
|
||||
// StopCPUProfile is defer called in main
|
||||
pprof.StartCPUProfile(f)
|
||||
}
|
||||
|
||||
func initFFMPEG() {
|
||||
configDirectory := paths.GetStashHomeDirectory()
|
||||
ffmpegPath, ffprobePath := ffmpeg.GetPaths(configDirectory)
|
||||
|
|
Loading…
Reference in New Issue