From 3cad7992550652cc145fb8fe3ccc126ab35af9fa Mon Sep 17 00:00:00 2001 From: Frederic Branczyk Date: Sat, 27 Aug 2022 14:42:33 +0200 Subject: [PATCH] Set time and duration of profile (#18) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Felix Geisendörfer --- fgprof.go | 12 +++++++++++- format.go | 9 ++++++--- format_test.go | 11 ++++++++++- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/fgprof.go b/fgprof.go index 31871c8..a79d2a3 100644 --- a/fgprof.go +++ b/fgprof.go @@ -14,6 +14,8 @@ import ( // that needs to be invoked by the caller to stop the profiling and write the // results to w using the given format. func Start(w io.Writer, format Format) func() error { + startTime := time.Now() + // Go's CPU profiler uses 100hz, but 99hz might be less likely to result in // accidental synchronization with the program we're profiling. const hz = 99 @@ -39,7 +41,15 @@ func Start(w io.Writer, format Format) func() error { return func() error { stopCh <- struct{}{} - return writeFormat(w, stackCounts.HumanMap(prof.SelfFrame()), format, hz) + endTime := time.Now() + return writeFormat( + w, + stackCounts.HumanMap(prof.SelfFrame()), + format, + hz, + startTime, + endTime, + ) } } diff --git a/format.go b/format.go index 1d239ae..8a81ad7 100644 --- a/format.go +++ b/format.go @@ -5,6 +5,7 @@ import ( "io" "sort" "strings" + "time" "github.com/google/pprof/profile" ) @@ -21,12 +22,12 @@ const ( FormatPprof Format = "pprof" ) -func writeFormat(w io.Writer, s map[string]int, f Format, hz int) error { +func writeFormat(w io.Writer, s map[string]int, f Format, hz int, startTime, endTime time.Time) error { switch f { case FormatFolded: return writeFolded(w, s) case FormatPprof: - return toPprof(s, hz).Write(w) + return toPprof(s, hz, startTime, endTime).Write(w) default: return fmt.Errorf("unknown format: %q", f) } @@ -42,7 +43,7 @@ func writeFolded(w io.Writer, s map[string]int) error { return nil } -func toPprof(s map[string]int, hz int) *profile.Profile { +func toPprof(s map[string]int, hz int, startTime, endTime time.Time) *profile.Profile { functionID := uint64(1) locationID := uint64(1) line := int64(1) @@ -50,6 +51,8 @@ func toPprof(s map[string]int, hz int) *profile.Profile { p := &profile.Profile{} m := &profile.Mapping{ID: 1, HasFunctions: true} p.Period = int64(1e9 / hz) // Number of nanoseconds between samples. + p.TimeNanos = startTime.UnixNano() + p.DurationNanos = int64(endTime.Sub(startTime)) p.Mapping = []*profile.Mapping{m} p.SampleType = []*profile.ValueType{ { diff --git a/format_test.go b/format_test.go index 18be251..f19263e 100644 --- a/format_test.go +++ b/format_test.go @@ -3,6 +3,7 @@ package fgprof import ( "strings" "testing" + "time" ) func Test_toPprof(t *testing.T) { @@ -11,7 +12,13 @@ func Test_toPprof(t *testing.T) { "foo": 1, } - p := toPprof(s, 99) + before := time.Local + defer func() { time.Local = before }() + time.Local = time.UTC + + start := time.Date(2022, 8, 27, 14, 32, 23, 0, time.UTC) + end := start.Add(time.Second) + p := toPprof(s, 99, start, end) if err := p.CheckValid(); err != nil { t.Fatal(err) } @@ -19,6 +26,8 @@ func Test_toPprof(t *testing.T) { want := strings.TrimSpace(` PeriodType: wallclock nanoseconds Period: 10101010 +Time: 2022-08-27 14:32:23 +0000 UTC +Duration: 1s Samples: samples/count time/nanoseconds 1 10101010: 1