Skip to content

Commit

Permalink
move interval merge inside MergeContinuousProfileCandidate
Browse files Browse the repository at this point in the history
  • Loading branch information
viglia committed Sep 12, 2024
1 parent 6b203a3 commit 4fa9747
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 52 deletions.
Empty file added cmd/vroom/__debug_bin802580351
Empty file.
5 changes: 2 additions & 3 deletions internal/flamegraph/flamegraph.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ func GetFlamegraphFromProfiles(
// the profile.timestamps to be consistent with the sample/node
// 'start' and 'end'
relativeIntervalsFromAbsoluteTimestamp(&spans, uint64(p.Timestamp().UnixNano()))
sortedSpans := mergeIntervals(&spans)
sortedSpans := utils.MergeIntervals(&spans)
for tid, callTree := range callTrees {
callTrees[tid] = sliceCallTree(&callTree, &sortedSpans)
}
Expand Down Expand Up @@ -572,8 +572,7 @@ func GetFlamegraphFromCandidates(

for tid, callTree := range result.CallTrees {
if intervals, ok := result.Intervals[tid]; ok {
sortedAndMergedIntervals := mergeIntervals(&intervals)
for _, interval := range sortedAndMergedIntervals {
for _, interval := range intervals {
intervalExample := utils.NewExampleFromProfilerChunk(
result.Chunk.ProjectID,
result.Chunk.ProfilerID,
Expand Down
24 changes: 0 additions & 24 deletions internal/flamegraph/span_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,12 @@ package flamegraph

import (
"math"
"sort"
"time"

"github.com/getsentry/vroom/internal/nodetree"
"github.com/getsentry/vroom/internal/utils"
)

func mergeIntervals(intervals *[]utils.Interval) []utils.Interval {
if len(*intervals) == 0 {
return *intervals
}
sort.SliceStable((*intervals), func(i, j int) bool {
if (*intervals)[i].Start == (*intervals)[j].Start {
return (*intervals)[i].End < (*intervals)[j].End
}
return (*intervals)[i].Start < (*intervals)[j].Start
})

newIntervals := []utils.Interval{(*intervals)[0]}
for _, interval := range (*intervals)[1:] {
if interval.Start <= newIntervals[len(newIntervals)-1].End {
newIntervals[len(newIntervals)-1].End = max(newIntervals[len(newIntervals)-1].End, interval.End)
} else {
newIntervals = append(newIntervals, interval)
}
}

return newIntervals
}

func relativeIntervalsFromAbsoluteTimestamp(intervals *[]utils.Interval, t uint64) {
for i, v := range *intervals {
// safety check: in case the start/end should be
Expand Down
24 changes: 2 additions & 22 deletions internal/flamegraph/span_util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,6 @@ import (
"github.com/getsentry/vroom/internal/utils"
)

func TestMergeIntervals(t *testing.T) {
inputIntervals := []utils.Interval{
{Start: 8, End: 11},
{Start: 3, End: 6},
{Start: 7, End: 12},
{Start: 1, End: 3},
}

expectedResult := []utils.Interval{
{Start: 1, End: 6},
{Start: 7, End: 12},
}

result := mergeIntervals(&inputIntervals)

if diff := testutil.Diff(result, expectedResult); diff != "" {
t.Fatalf("Result mismatch: got - want +\n%s", diff)
}
}

func TestGetTotalOvelappingDuration(t *testing.T) {
tests := []struct {
name string
Expand Down Expand Up @@ -91,7 +71,7 @@ func TestGetTotalOvelappingDuration(t *testing.T) {

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
intervals := mergeIntervals(&test.intervals)
intervals := utils.MergeIntervals(&test.intervals)
result := getTotalOverlappingDuration(&test.node, &intervals)

if diff := testutil.Diff(result, test.output); diff != "" {
Expand Down Expand Up @@ -302,7 +282,7 @@ func TestSliceCallTree(t *testing.T) {

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
intervals := mergeIntervals(&test.intervals)
intervals := utils.MergeIntervals(&test.intervals)
result := sliceCallTree(&test.callTree, &intervals)
if diff := testutil.Diff(result, test.output); diff != "" {
t.Fatalf("Result mismatch: got - want +\n%s", diff)
Expand Down
57 changes: 54 additions & 3 deletions internal/utils/struct_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,7 @@ func TestMergeContinuousProfileCandidate(t *testing.T) {
ChunkID: "1111",
Intervals: map[string][]Interval{
t1: {
{Start: 100, End: 200},
{Start: 200, End: 400},
{Start: 100, End: 400},
},
t2: {
{Start: 100, End: 300},
Expand All @@ -75,13 +74,65 @@ func TestMergeContinuousProfileCandidate(t *testing.T) {
},
}, // end want
},
{
name: "Merge candidates with overlapping time-range",
candidates: []ContinuousProfileCandidate{
{
ProjectID: 1,
ProfilerID: "1111",
ChunkID: "1111",
ThreadID: &t1,
Start: 100,
End: 200,
},
{
ProjectID: 1,
ProfilerID: "1111",
ChunkID: "1111",
ThreadID: &t1,
Start: 190,
End: 300,
},
}, // end candidates
want: []ContinuousProfileCandidate{
{
ProjectID: 1,
ProfilerID: "1111",
ChunkID: "1111",
Intervals: map[string][]Interval{
t1: {
{Start: 100, End: 300},
},
},
},
}, // end want
},
} // end tests

for _, test := range tests {
newCandidates := MergeContinuousProfileCandidate(test.candidates)
t.Logf("%+v\n", newCandidates)
if diff := testutil.Diff(newCandidates, test.want); diff != "" {
t.Fatalf("Result mismatch: got - want +\n%s", diff)
}
}
}

func TestMergeIntervals(t *testing.T) {
inputIntervals := []Interval{
{Start: 8, End: 11},
{Start: 3, End: 6},
{Start: 7, End: 12},
{Start: 1, End: 3},
}

expectedResult := []Interval{
{Start: 1, End: 6},
{Start: 7, End: 12},
}

result := MergeIntervals(&inputIntervals)

if diff := testutil.Diff(result, expectedResult); diff != "" {
t.Fatalf("Result mismatch: got - want +\n%s", diff)
}
}
35 changes: 35 additions & 0 deletions internal/utils/structs.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package utils

import (
"sort"
)

type (
Interval struct {
Start uint64 `json:"start,string"`
Expand Down Expand Up @@ -128,5 +132,36 @@ func MergeContinuousProfileCandidate(candidates []ContinuousProfileCandidate) []
newCandidates = append(newCandidates, candidate)
}
} // end loop candidates
for i, candidate := range newCandidates {
if len(candidate.Intervals) > 0 {
for tid, intervals := range candidate.Intervals {
sortedMergedIntervals := MergeIntervals(&intervals)
newCandidates[i].Intervals[tid] = sortedMergedIntervals
}
}
}
return newCandidates
}

func MergeIntervals(intervals *[]Interval) []Interval {
if len(*intervals) == 0 {
return *intervals
}
sort.SliceStable((*intervals), func(i, j int) bool {
if (*intervals)[i].Start == (*intervals)[j].Start {
return (*intervals)[i].End < (*intervals)[j].End
}
return (*intervals)[i].Start < (*intervals)[j].Start
})

newIntervals := []Interval{(*intervals)[0]}
for _, interval := range (*intervals)[1:] {
if interval.Start <= newIntervals[len(newIntervals)-1].End {
newIntervals[len(newIntervals)-1].End = max(newIntervals[len(newIntervals)-1].End, interval.End)
} else {
newIntervals = append(newIntervals, interval)
}
}

return newIntervals
}

0 comments on commit 4fa9747

Please sign in to comment.