Skip to content

Commit b1bc08e

Browse files
xor-gatetechknowlogick
authored andcommitted
cmd/serve: pprof cpu and memory profile dumps to disk (#4560)
1 parent ed3589f commit b1bc08e

File tree

4 files changed

+70
-1
lines changed

4 files changed

+70
-1
lines changed

cmd/serv.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616

1717
"code.gitea.io/gitea/models"
1818
"code.gitea.io/gitea/modules/log"
19+
"code.gitea.io/gitea/modules/pprof"
1920
"code.gitea.io/gitea/modules/private"
2021
"code.gitea.io/gitea/modules/setting"
2122
"code.gitea.io/gitea/modules/util"
@@ -42,6 +43,9 @@ var CmdServ = cli.Command{
4243
Value: "custom/conf/app.ini",
4344
Usage: "Custom configuration file path",
4445
},
46+
cli.BoolFlag{
47+
Name: "enable-pprof",
48+
},
4549
},
4650
}
4751

@@ -143,6 +147,18 @@ func runServ(c *cli.Context) error {
143147
username := strings.ToLower(rr[0])
144148
reponame := strings.ToLower(strings.TrimSuffix(rr[1], ".git"))
145149

150+
if setting.EnablePprof || c.Bool("enable-pprof") {
151+
if err := os.MkdirAll(setting.PprofDataPath, os.ModePerm); err != nil {
152+
fail("Error while trying to create PPROF_DATA_PATH", "Error while trying to create PPROF_DATA_PATH: %v", err)
153+
}
154+
155+
stopCPUProfiler := pprof.DumpCPUProfileForUsername(setting.PprofDataPath, username)
156+
defer func() {
157+
stopCPUProfiler()
158+
pprof.DumpMemProfileForUsername(setting.PprofDataPath, username)
159+
}()
160+
}
161+
146162
isWiki := false
147163
unitType := models.UnitTypeCode
148164
if strings.HasSuffix(reponame, ".wiki") {

custom/conf/app.ini.sample

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,12 @@ STATIC_ROOT_PATH =
187187
APP_DATA_PATH = data
188188
; Application level GZIP support
189189
ENABLE_GZIP = false
190+
; Application profiling (memory and cpu)
191+
; For "web" command it listens on localhost:6060
192+
; For "serve" command it dumps to disk at PPROF_DATA_PATH as (cpuprofile|memprofile)_<username>_<temporary id>
193+
ENABLE_PPROF = false
194+
; PPROF_DATA_PATH, use an absolute path when you start gitea as service
195+
PPROF_DATA_PATH = data/tmp/pprof
190196
; Landing page, can be "home", "explore", or "organizations"
191197
LANDING_PAGE = home
192198
; Enables git-lfs support. true or false, default is false.
@@ -215,7 +221,7 @@ USER = root
215221
PASSWD =
216222
; For "postgres" only, either "disable", "require" or "verify-full"
217223
SSL_MODE = disable
218-
; For "sqlite3" and "tidb", use absolute path when you start gitea as service
224+
; For "sqlite3" and "tidb", use an absolute path when you start gitea as service
219225
PATH = data/gitea.db
220226
; For "sqlite3" only. Query timeout
221227
SQLITE_TIMEOUT = 500

modules/pprof/pprof.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright 2018 The Gitea Authors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
package pprof
6+
7+
import (
8+
"fmt"
9+
"io/ioutil"
10+
"runtime"
11+
"runtime/pprof"
12+
13+
"code.gitea.io/gitea/modules/log"
14+
)
15+
16+
// DumpMemProfileForUsername dumps a memory profile at pprofDataPath as memprofile_<username>_<temporary id>
17+
func DumpMemProfileForUsername(pprofDataPath, username string) {
18+
f, err := ioutil.TempFile(pprofDataPath, fmt.Sprintf("memprofile_%s_", username))
19+
if err != nil {
20+
log.GitLogger.Fatal(4, "Could not create memory profile: %v", err)
21+
}
22+
defer f.Close()
23+
runtime.GC() // get up-to-date statistics
24+
if err := pprof.WriteHeapProfile(f); err != nil {
25+
log.GitLogger.Fatal(4, "Could not write memory profile: %v", err)
26+
}
27+
}
28+
29+
// DumpCPUProfileForUsername dumps a CPU profile at pprofDataPath as cpuprofile_<username>_<temporary id>
30+
// it returns the stop function which stops, writes and closes the CPU profile file
31+
func DumpCPUProfileForUsername(pprofDataPath, username string) func() {
32+
f, err := ioutil.TempFile(pprofDataPath, fmt.Sprintf("cpuprofile_%s_", username))
33+
if err != nil {
34+
log.GitLogger.Fatal(4, "Could not create cpu profile: %v", err)
35+
}
36+
37+
pprof.StartCPUProfile(f)
38+
return func() {
39+
pprof.StopCPUProfile()
40+
f.Close()
41+
}
42+
}

modules/setting/setting.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ var (
111111
LandingPageURL LandingPage
112112
UnixSocketPermission uint32
113113
EnablePprof bool
114+
PprofDataPath string
114115

115116
SSH = struct {
116117
Disabled bool `ini:"DISABLE_SSH"`
@@ -775,6 +776,10 @@ func NewContext() {
775776
AppDataPath = sec.Key("APP_DATA_PATH").MustString(path.Join(AppWorkPath, "data"))
776777
EnableGzip = sec.Key("ENABLE_GZIP").MustBool()
777778
EnablePprof = sec.Key("ENABLE_PPROF").MustBool(false)
779+
PprofDataPath = sec.Key("PPROF_DATA_PATH").MustString(path.Join(AppWorkPath, "data/tmp/pprof"))
780+
if !filepath.IsAbs(PprofDataPath) {
781+
PprofDataPath = filepath.Join(AppWorkPath, PprofDataPath)
782+
}
778783

779784
switch sec.Key("LANDING_PAGE").MustString("home") {
780785
case "explore":

0 commit comments

Comments
 (0)