mirror of
https://github.com/stashapp/stash.git
synced 2025-12-06 16:34:02 +01:00
parent
bc9aa02835
commit
16fe21138f
5 changed files with 59 additions and 5 deletions
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:
|
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`
|
`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
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"runtime/pprof"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
"github.com/stashapp/stash/pkg/api"
|
"github.com/stashapp/stash/pkg/api"
|
||||||
"github.com/stashapp/stash/pkg/manager"
|
"github.com/stashapp/stash/pkg/manager"
|
||||||
|
|
||||||
|
|
@ -12,9 +17,16 @@ import (
|
||||||
func main() {
|
func main() {
|
||||||
manager.Initialize()
|
manager.Initialize()
|
||||||
api.Start()
|
api.Start()
|
||||||
|
|
||||||
|
// stop any profiling at exit
|
||||||
|
defer pprof.StopCPUProfile()
|
||||||
blockForever()
|
blockForever()
|
||||||
}
|
}
|
||||||
|
|
||||||
func 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 {
|
type Instance struct {
|
||||||
|
cpuProfilePath string
|
||||||
isNewSystem bool
|
isNewSystem bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -162,6 +163,13 @@ func (i *Instance) SetConfigFile(fn string) {
|
||||||
viper.SetConfigFile(fn)
|
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{}) {
|
func (i *Instance) Set(key string, value interface{}) {
|
||||||
viper.Set(key, value)
|
viper.Set(key, value)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,18 +17,20 @@ var once sync.Once
|
||||||
|
|
||||||
type flagStruct struct {
|
type flagStruct struct {
|
||||||
configFilePath string
|
configFilePath string
|
||||||
|
cpuProfilePath string
|
||||||
}
|
}
|
||||||
|
|
||||||
func Initialize() (*Instance, error) {
|
func Initialize() (*Instance, error) {
|
||||||
var err error
|
var err error
|
||||||
once.Do(func() {
|
once.Do(func() {
|
||||||
instance = &Instance{}
|
|
||||||
|
|
||||||
flags := initFlags()
|
flags := initFlags()
|
||||||
|
instance = &Instance{
|
||||||
|
cpuProfilePath: flags.cpuProfilePath,
|
||||||
|
}
|
||||||
|
|
||||||
if err = initConfig(flags); err != nil {
|
if err = initConfig(flags); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
initEnvs()
|
initEnvs()
|
||||||
|
|
||||||
if instance.isNewSystem {
|
if instance.isNewSystem {
|
||||||
|
|
@ -46,6 +48,7 @@ func Initialize() (*Instance, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func initConfig(flags flagStruct) error {
|
func initConfig(flags flagStruct) error {
|
||||||
|
|
||||||
// The config file is called config. Leave off the file extension.
|
// The config file is called config. Leave off the file extension.
|
||||||
viper.SetConfigName("config")
|
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.IP("host", net.IPv4(0, 0, 0, 0), "ip address for the host")
|
||||||
pflag.Int("port", 9999, "port to serve from")
|
pflag.Int("port", 9999, "port to serve from")
|
||||||
pflag.StringVarP(&flags.configFilePath, "config", "c", "", "config file to use")
|
pflag.StringVarP(&flags.configFilePath, "config", "c", "", "config file to use")
|
||||||
|
pflag.StringVar(&flags.cpuProfilePath, "cpuprofile", "", "write cpu profile to file")
|
||||||
|
|
||||||
pflag.Parse()
|
pflag.Parse()
|
||||||
if err := viper.BindPFlags(pflag.CommandLine); err != nil {
|
if err := viper.BindPFlags(pflag.CommandLine); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"runtime/pprof"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -55,6 +56,7 @@ func Initialize() *singleton {
|
||||||
}
|
}
|
||||||
|
|
||||||
initLog()
|
initLog()
|
||||||
|
initProfiling(cfg.GetCPUProfilePath())
|
||||||
|
|
||||||
instance = &singleton{
|
instance = &singleton{
|
||||||
Config: cfg,
|
Config: cfg,
|
||||||
|
|
@ -92,6 +94,22 @@ func Initialize() *singleton {
|
||||||
return instance
|
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() {
|
func initFFMPEG() {
|
||||||
configDirectory := paths.GetStashHomeDirectory()
|
configDirectory := paths.GetStashHomeDirectory()
|
||||||
ffmpegPath, ffprobePath := ffmpeg.GetPaths(configDirectory)
|
ffmpegPath, ffprobePath := ffmpeg.GetPaths(configDirectory)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue