Skip to content

Commit 68e13df

Browse files
opm: always serve pprof endpoints, improve server allocations (#1129)
* pkg/cache: use a shared buffer to limit allocations Previously, new buffers were allocated on each file we read in, which was unnecessary and wasteful. Signed-off-by: Steve Kuznetsov <[email protected]> * cmd/opm: serve pprof endpoints by default There is no substantial runtime cost to serving pprof endpoints, and when things hit the fan and we need to investigate performance in situ, there is no time to restart pods and change flags. Capturing profiles remains opt-in, since those are costly. Signed-off-by: Steve Kuznetsov <[email protected]> --------- Signed-off-by: Steve Kuznetsov <[email protected]>
1 parent 52190e4 commit 68e13df

File tree

4 files changed

+22
-10
lines changed

4 files changed

+22
-10
lines changed

cmd/opm/serve/serve.go

+9-5
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,9 @@ type serve struct {
3636
port string
3737
terminationLog string
3838

39-
debug bool
40-
pprofAddr string
39+
debug bool
40+
pprofAddr string
41+
captureProfiles bool
4142

4243
logger *logrus.Entry
4344
}
@@ -80,7 +81,8 @@ will not be reflected in the served content.
8081
cmd.Flags().BoolVar(&s.debug, "debug", false, "enable debug logging")
8182
cmd.Flags().StringVarP(&s.terminationLog, "termination-log", "t", "/dev/termination-log", "path to a container termination log file")
8283
cmd.Flags().StringVarP(&s.port, "port", "p", "50051", "port number to serve on")
83-
cmd.Flags().StringVar(&s.pprofAddr, "pprof-addr", "", "address of startup profiling endpoint (addr:port format)")
84+
cmd.Flags().StringVar(&s.pprofAddr, "pprof-addr", "localhost:6060", "address of startup profiling endpoint (addr:port format)")
85+
cmd.Flags().BoolVar(&s.captureProfiles, "pprof-capture-profiles", false, "capture pprof CPU profiles")
8486
cmd.Flags().StringVar(&s.cacheDir, "cache-dir", "", "if set, sync and persist server cache directory")
8587
cmd.Flags().BoolVar(&s.cacheOnly, "cache-only", false, "sync the serve cache and exit without serving")
8688
cmd.Flags().BoolVar(&s.cacheEnforceIntegrity, "cache-enforce-integrity", false, "exit with error if cache is not present or has been invalidated. (default: true when --cache-dir is set and --cache-only is false, false otherwise), ")
@@ -92,8 +94,10 @@ func (s *serve) run(ctx context.Context) error {
9294
if err := p.startEndpoint(); err != nil {
9395
return fmt.Errorf("could not start pprof endpoint: %v", err)
9496
}
95-
if err := p.startCpuProfileCache(); err != nil {
96-
return fmt.Errorf("could not start CPU profile: %v", err)
97+
if s.captureProfiles {
98+
if err := p.startCpuProfileCache(); err != nil {
99+
return fmt.Errorf("could not start CPU profile: %v", err)
100+
}
97101
}
98102

99103
// Immediately set up termination log

pkg/cache/json.go

+5-2
Original file line numberDiff line numberDiff line change
@@ -165,13 +165,16 @@ func (q *JSON) existingDigest() (string, error) {
165165
}
166166

167167
func (q *JSON) computeDigest(fbcFsys fs.FS) (string, error) {
168+
// We are not sensitive to the size of this buffer, we just need it to be shared.
169+
// For simplicity, do the same as io.Copy() would.
170+
buf := make([]byte, 32*1024)
168171
computedHasher := fnv.New64a()
169-
if err := fsToTar(computedHasher, fbcFsys); err != nil {
172+
if err := fsToTar(computedHasher, fbcFsys, buf); err != nil {
170173
return "", err
171174
}
172175

173176
if cacheFS, err := fs.Sub(os.DirFS(q.baseDir), jsonDir); err == nil {
174-
if err := fsToTar(computedHasher, cacheFS); err != nil && !errors.Is(err, os.ErrNotExist) {
177+
if err := fsToTar(computedHasher, cacheFS, buf); err != nil && !errors.Is(err, os.ErrNotExist) {
175178
return "", fmt.Errorf("compute hash: %v", err)
176179
}
177180
}

pkg/cache/tar.go

+7-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,12 @@ import (
1313
// This function unsets user and group information in the tar archive so that readers
1414
// of archives produced by this function do not need to account for differences in
1515
// permissions between source and destination filesystems.
16-
func fsToTar(w io.Writer, fsys fs.FS) error {
16+
func fsToTar(w io.Writer, fsys fs.FS, buf []byte) error {
17+
if buf == nil || len(buf) == 0 {
18+
// We are not sensitive to the size of this buffer, we just need it to be shared.
19+
// For simplicity, do the same as io.Copy() would.
20+
buf = make([]byte, 32*1024)
21+
}
1722
tw := tar.NewWriter(w)
1823
if err := fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, err error) error {
1924
if err != nil {
@@ -52,7 +57,7 @@ func fsToTar(w io.Writer, fsys fs.FS) error {
5257
return fmt.Errorf("open file %q: %v", path, err)
5358
}
5459
defer f.Close()
55-
if _, err := io.Copy(tw, f); err != nil {
60+
if _, err := io.CopyBuffer(tw, f, buf); err != nil {
5661
return fmt.Errorf("write tar data for %q: %v", path, err)
5762
}
5863
return nil

pkg/cache/tar_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ func Test_fsToTar(t *testing.T) {
5151
for _, tc := range testCases {
5252
t.Run(tc.name, func(t *testing.T) {
5353
w := bytes.Buffer{}
54-
err := fsToTar(&w, tc.fsys())
54+
err := fsToTar(&w, tc.fsys(), nil)
5555
tc.expect(t, w.Bytes(), err)
5656
})
5757
}

0 commit comments

Comments
 (0)