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 |