| OLD | NEW |
| 1 // Copyright 2016 The LUCI Authors. All rights reserved. | 1 // Copyright 2016 The LUCI Authors. All rights reserved. |
| 2 // Use of this source code is governed under the Apache License, Version 2.0 | 2 // Use of this source code is governed under the Apache License, Version 2.0 |
| 3 // that can be found in the LICENSE file. | 3 // that can be found in the LICENSE file. |
| 4 | 4 |
| 5 package profiling | 5 package profiling |
| 6 | 6 |
| 7 import ( | 7 import ( |
| 8 "flag" | 8 "flag" |
| 9 "fmt" | 9 "fmt" |
| 10 "net" | 10 "net" |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 88 return errors.New("-profile-cpu requires -profile-output
-dir to be set") | 88 return errors.New("-profile-cpu requires -profile-output
-dir to be set") |
| 89 } | 89 } |
| 90 if p.ProfileHeap { | 90 if p.ProfileHeap { |
| 91 return errors.New("-profile-heap requires -profile-outpu
t-dir to be set") | 91 return errors.New("-profile-heap requires -profile-outpu
t-dir to be set") |
| 92 } | 92 } |
| 93 } | 93 } |
| 94 | 94 |
| 95 if p.ProfileCPU { | 95 if p.ProfileCPU { |
| 96 out, err := os.Create(p.generateOutPath("cpu")) | 96 out, err := os.Create(p.generateOutPath("cpu")) |
| 97 if err != nil { | 97 if err != nil { |
| 98 » » » return errors.Annotate(err).Reason("failed to create CPU
profile output file").Err() | 98 » » » return errors.Annotate(err, "failed to create CPU profil
e output file").Err() |
| 99 } | 99 } |
| 100 pprof.StartCPUProfile(out) | 100 pprof.StartCPUProfile(out) |
| 101 p.profilingCPU = true | 101 p.profilingCPU = true |
| 102 } | 102 } |
| 103 | 103 |
| 104 if p.BindHTTP != "" { | 104 if p.BindHTTP != "" { |
| 105 if err := p.startHTTP(); err != nil { | 105 if err := p.startHTTP(); err != nil { |
| 106 » » » return errors.Annotate(err).Reason("failed to start HTTP
server").Err() | 106 » » » return errors.Annotate(err, "failed to start HTTP server
").Err() |
| 107 } | 107 } |
| 108 } | 108 } |
| 109 | 109 |
| 110 return nil | 110 return nil |
| 111 } | 111 } |
| 112 | 112 |
| 113 func (p *Profiler) startHTTP() error { | 113 func (p *Profiler) startHTTP() error { |
| 114 // Register paths: https://golang.org/src/net/http/pprof/pprof.go | 114 // Register paths: https://golang.org/src/net/http/pprof/pprof.go |
| 115 router := httprouter.New() | 115 router := httprouter.New() |
| 116 router.HandlerFunc("GET", "/debug/pprof/", httpProf.Index) | 116 router.HandlerFunc("GET", "/debug/pprof/", httpProf.Index) |
| 117 router.HandlerFunc("GET", "/debug/pprof/cmdline", httpProf.Cmdline) | 117 router.HandlerFunc("GET", "/debug/pprof/cmdline", httpProf.Cmdline) |
| 118 router.HandlerFunc("GET", "/debug/pprof/profile", httpProf.Profile) | 118 router.HandlerFunc("GET", "/debug/pprof/profile", httpProf.Profile) |
| 119 router.HandlerFunc("GET", "/debug/pprof/symbol", httpProf.Symbol) | 119 router.HandlerFunc("GET", "/debug/pprof/symbol", httpProf.Symbol) |
| 120 router.HandlerFunc("GET", "/debug/pprof/trace", httpProf.Trace) | 120 router.HandlerFunc("GET", "/debug/pprof/trace", httpProf.Trace) |
| 121 for _, p := range pprof.Profiles() { | 121 for _, p := range pprof.Profiles() { |
| 122 name := p.Name() | 122 name := p.Name() |
| 123 router.Handler("GET", fmt.Sprintf("/debug/pprof/%s", name), http
Prof.Handler(name)) | 123 router.Handler("GET", fmt.Sprintf("/debug/pprof/%s", name), http
Prof.Handler(name)) |
| 124 } | 124 } |
| 125 | 125 |
| 126 // Bind to our profiling port. | 126 // Bind to our profiling port. |
| 127 l, err := net.Listen("tcp4", p.BindHTTP) | 127 l, err := net.Listen("tcp4", p.BindHTTP) |
| 128 if err != nil { | 128 if err != nil { |
| 129 » » return errors.Annotate(err).Reason("failed to bind to TCP4 addre
ss: %(addr)q"). | 129 » » return errors.Annotate(err, "failed to bind to TCP4 address: %q"
, p.BindHTTP).Err() |
| 130 » » » D("addr", p.BindHTTP).Err() | |
| 131 } | 130 } |
| 132 | 131 |
| 133 server := http.Server{ | 132 server := http.Server{ |
| 134 Handler: http.HandlerFunc(router.ServeHTTP), | 133 Handler: http.HandlerFunc(router.ServeHTTP), |
| 135 } | 134 } |
| 136 go func() { | 135 go func() { |
| 137 if err := server.Serve(l); err != nil { | 136 if err := server.Serve(l); err != nil { |
| 138 p.getLogger().Errorf("Error serving profile HTTP: %s", e
rr) | 137 p.getLogger().Errorf("Error serving profile HTTP: %s", e
rr) |
| 139 } | 138 } |
| 140 }() | 139 }() |
| (...skipping 20 matching lines...) Expand all Loading... |
| 161 | 160 |
| 162 // DumpSnapshot dumps a profile snapshot to the configured output directory. If | 161 // DumpSnapshot dumps a profile snapshot to the configured output directory. If |
| 163 // no output directory is configured, nothing will happen. | 162 // no output directory is configured, nothing will happen. |
| 164 func (p *Profiler) DumpSnapshot() error { | 163 func (p *Profiler) DumpSnapshot() error { |
| 165 if p.Dir == "" { | 164 if p.Dir == "" { |
| 166 return nil | 165 return nil |
| 167 } | 166 } |
| 168 | 167 |
| 169 if p.ProfileHeap { | 168 if p.ProfileHeap { |
| 170 if err := p.dumpHeapProfile(); err != nil { | 169 if err := p.dumpHeapProfile(); err != nil { |
| 171 » » » return errors.Annotate(err).Reason("failed to dump heap
profile").Err() | 170 » » » return errors.Annotate(err, "failed to dump heap profile
").Err() |
| 172 } | 171 } |
| 173 } | 172 } |
| 174 | 173 |
| 175 return nil | 174 return nil |
| 176 } | 175 } |
| 177 | 176 |
| 178 func (p *Profiler) dumpHeapProfile() error { | 177 func (p *Profiler) dumpHeapProfile() error { |
| 179 fd, err := os.Create(p.generateOutPath("memory")) | 178 fd, err := os.Create(p.generateOutPath("memory")) |
| 180 if err != nil { | 179 if err != nil { |
| 181 » » return errors.Annotate(err).Reason("failed to create output file
").Err() | 180 » » return errors.Annotate(err, "failed to create output file").Err(
) |
| 182 } | 181 } |
| 183 defer fd.Close() | 182 defer fd.Close() |
| 184 | 183 |
| 185 // Get up-to-date statistics. | 184 // Get up-to-date statistics. |
| 186 runtime.GC() | 185 runtime.GC() |
| 187 if err := pprof.WriteHeapProfile(fd); err != nil { | 186 if err := pprof.WriteHeapProfile(fd); err != nil { |
| 188 » » return errors.Annotate(err).Reason("failed to write heap profile
").Err() | 187 » » return errors.Annotate(err, "failed to write heap profile").Err(
) |
| 189 } | 188 } |
| 190 return nil | 189 return nil |
| 191 } | 190 } |
| 192 | 191 |
| 193 func (p *Profiler) generateOutPath(base string) string { | 192 func (p *Profiler) generateOutPath(base string) string { |
| 194 clk := p.Clock | 193 clk := p.Clock |
| 195 if clk == nil { | 194 if clk == nil { |
| 196 clk = clock.GetSystemClock() | 195 clk = clock.GetSystemClock() |
| 197 } | 196 } |
| 198 now := clk.Now() | 197 now := clk.Now() |
| 199 counter := atomic.AddUint32(&p.pathCounter, 1) - 1 | 198 counter := atomic.AddUint32(&p.pathCounter, 1) - 1 |
| 200 return filepath.Join(p.Dir, fmt.Sprintf("%s_%d_%d.prof", base, now.Unix(
), counter)) | 199 return filepath.Join(p.Dir, fmt.Sprintf("%s_%d_%d.prof", base, now.Unix(
), counter)) |
| 201 } | 200 } |
| 202 | 201 |
| 203 func (p *Profiler) getLogger() logging.Logger { | 202 func (p *Profiler) getLogger() logging.Logger { |
| 204 if p.Logger != nil { | 203 if p.Logger != nil { |
| 205 return p.Logger | 204 return p.Logger |
| 206 } | 205 } |
| 207 return logging.Null | 206 return logging.Null |
| 208 } | 207 } |
| OLD | NEW |