From 1b4aea8c783d32e15a07f14f795787d24fa0c82c Mon Sep 17 00:00:00 2001 From: Frederic Branczyk Date: Wed, 27 Apr 2022 21:32:57 +0200 Subject: [PATCH 1/4] Set time and duration of profile --- fgprof.go | 12 +++++++++++- format.go | 9 ++++++--- 2 files changed, 17 insertions(+), 4 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 317027b..0f899ae 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 = endTime.UnixNano() - p.TimeNanos p.Mapping = []*profile.Mapping{m} p.SampleType = []*profile.ValueType{ { From b6b7c93585b56d1b8d0d5962f10c2e087ea764b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Geisend=C3=B6rfer?= Date: Sat, 27 Aug 2022 14:29:27 +0200 Subject: [PATCH 2/4] fix: use monotonic clock to calculate duration --- format.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/format.go b/format.go index 20c55dc..a6e0190 100644 --- a/format.go +++ b/format.go @@ -52,7 +52,7 @@ func toPprof(s map[string]int, hz int, startTime, endTime time.Time) *profile.Pr m := &profile.Mapping{ID: 1, HasFunctions: true} p.Period = int64(1e9 / hz) // Number of nanoseconds between samples. p.TimeNanos = startTime.UnixNano() - p.DurationNanos = endTime.UnixNano() - p.TimeNanos + p.DurationNanos = int64(endTime.Sub(startTime)) p.Mapping = []*profile.Mapping{m} p.SampleType = []*profile.ValueType{ { From 22340eb78ee3f18a1bec41a227a9202bdd618b8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Geisend=C3=B6rfer?= Date: Sat, 27 Aug 2022 14:33:08 +0200 Subject: [PATCH 3/4] fix test after merging master --- format_test.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/format_test.go b/format_test.go index 18be251..76f3a48 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,9 @@ func Test_toPprof(t *testing.T) { "foo": 1, } - p := toPprof(s, 99) + 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 +22,8 @@ func Test_toPprof(t *testing.T) { want := strings.TrimSpace(` PeriodType: wallclock nanoseconds Period: 10101010 +Time: 2022-08-27 16:32:23 +0200 CEST +Duration: 1s Samples: samples/count time/nanoseconds 1 10101010: 1 From 1bcfc7787c62b8ecb92f9db3f2c28143616fcb6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Geisend=C3=B6rfer?= Date: Sat, 27 Aug 2022 14:36:19 +0200 Subject: [PATCH 4/4] fix test to work in all time zones --- format_test.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/format_test.go b/format_test.go index 76f3a48..f19263e 100644 --- a/format_test.go +++ b/format_test.go @@ -12,6 +12,10 @@ func Test_toPprof(t *testing.T) { "foo": 1, } + 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) @@ -22,7 +26,7 @@ func Test_toPprof(t *testing.T) { want := strings.TrimSpace(` PeriodType: wallclock nanoseconds Period: 10101010 -Time: 2022-08-27 16:32:23 +0200 CEST +Time: 2022-08-27 14:32:23 +0000 UTC Duration: 1s Samples: samples/count time/nanoseconds