Skip to content

Commit 3f9f510

Browse files
dmathieucodeboten
andauthored
pprofile: introduce SetStack helper method (#14007)
This introduces the `SetStack` helper method for pprofile, as we already have `SetFunction`, `SetMapping`, `SetString`, ... This is needed to help with setting up merging of profiles. #13106 --------- Co-authored-by: Alex Boten <[email protected]>
1 parent c79745f commit 3f9f510

File tree

3 files changed

+171
-0
lines changed

3 files changed

+171
-0
lines changed

.chloggen/pprofile-set-stack.yaml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Use this changelog template to create an entry for release notes.
2+
3+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
4+
change_type: enhancement
5+
6+
# The name of the component, or a single word describing the area of concern, (e.g. otlpreceiver)
7+
component: pdata/pprofile
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: Introduce `SetStack` method
11+
12+
# One or more tracking issues or pull requests related to the change
13+
issues: [14007]
14+
15+
# (Optional) One or more lines of additional information to render under the primary note.
16+
# These lines will be padded with 2 spaces and then inserted directly into the document.
17+
# Use pipe (|) for multiline entries.
18+
subtext:
19+
20+
# Optional: The change log or logs in which this entry should be included.
21+
# e.g. '[user]' or '[user, api]'
22+
# Include 'user' if the change is relevant to end users.
23+
# Include 'api' if there is a change to a library API.
24+
# Default: '[user]'
25+
change_logs: [api]

pdata/pprofile/stacks.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package pprofile // import "go.opentelemetry.io/collector/pdata/pprofile"
5+
6+
import (
7+
"errors"
8+
"math"
9+
)
10+
11+
var errTooManyStackTableEntries = errors.New("too many entries in StackTable")
12+
13+
// SetStack updates a StackSlice, adding or providing a stack and returns its
14+
// index.
15+
func SetStack(table StackSlice, st Stack) (int32, error) {
16+
for j, l := range table.All() {
17+
if l.Equal(st) {
18+
if j > math.MaxInt32 {
19+
return 0, errTooManyStackTableEntries
20+
}
21+
return int32(j), nil //nolint:gosec // G115 overflow checked
22+
}
23+
}
24+
25+
if table.Len() >= math.MaxInt32 {
26+
return 0, errTooManyStackTableEntries
27+
}
28+
29+
st.CopyTo(table.AppendEmpty())
30+
return int32(table.Len() - 1), nil //nolint:gosec // G115 overflow checked
31+
}

pdata/pprofile/stacks_test.go

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package pprofile
5+
6+
import (
7+
"testing"
8+
9+
"github.com/stretchr/testify/assert"
10+
"github.com/stretchr/testify/require"
11+
)
12+
13+
func TestSetStack(t *testing.T) {
14+
table := NewStackSlice()
15+
s := NewStack()
16+
s.LocationIndices().Append(1)
17+
s2 := NewStack()
18+
s.LocationIndices().Append(2)
19+
20+
// Put a first stack
21+
idx, err := SetStack(table, s)
22+
require.NoError(t, err)
23+
assert.Equal(t, 1, table.Len())
24+
assert.Equal(t, int32(0), idx)
25+
26+
// Put the same stack
27+
// This should be a no-op.
28+
idx, err = SetStack(table, s)
29+
require.NoError(t, err)
30+
assert.Equal(t, 1, table.Len())
31+
assert.Equal(t, int32(0), idx)
32+
33+
// Set a new stack
34+
// This sets the index and adds to the table.
35+
idx, err = SetStack(table, s2)
36+
require.NoError(t, err)
37+
assert.Equal(t, 2, table.Len())
38+
assert.Equal(t, int32(table.Len()-1), idx) //nolint:gosec // G115
39+
40+
// Set an existing stack
41+
idx, err = SetStack(table, s)
42+
require.NoError(t, err)
43+
assert.Equal(t, 2, table.Len())
44+
assert.Equal(t, int32(0), idx)
45+
// Set another existing stack
46+
idx, err = SetStack(table, s2)
47+
require.NoError(t, err)
48+
assert.Equal(t, 2, table.Len())
49+
assert.Equal(t, int32(table.Len()-1), idx) //nolint:gosec // G115
50+
}
51+
52+
func BenchmarkSetStack(b *testing.B) {
53+
for _, bb := range []struct {
54+
name string
55+
stack Stack
56+
57+
runBefore func(*testing.B, StackSlice)
58+
}{
59+
{
60+
name: "with a new stack",
61+
stack: NewStack(),
62+
},
63+
{
64+
name: "with an existing stack",
65+
stack: func() Stack {
66+
s := NewStack()
67+
s.LocationIndices().Append(1)
68+
return s
69+
}(),
70+
71+
runBefore: func(_ *testing.B, table StackSlice) {
72+
s := table.AppendEmpty()
73+
s.LocationIndices().Append(1)
74+
},
75+
},
76+
{
77+
name: "with a duplicate stack",
78+
stack: NewStack(),
79+
80+
runBefore: func(_ *testing.B, table StackSlice) {
81+
_, err := SetStack(table, NewStack())
82+
require.NoError(b, err)
83+
},
84+
},
85+
{
86+
name: "with a hundred stacks to loop through",
87+
stack: func() Stack {
88+
s := NewStack()
89+
s.LocationIndices().Append(1)
90+
return s
91+
}(),
92+
93+
runBefore: func(_ *testing.B, table StackSlice) {
94+
for range 100 {
95+
table.AppendEmpty()
96+
}
97+
},
98+
},
99+
} {
100+
b.Run(bb.name, func(b *testing.B) {
101+
table := NewStackSlice()
102+
103+
if bb.runBefore != nil {
104+
bb.runBefore(b, table)
105+
}
106+
107+
b.ResetTimer()
108+
b.ReportAllocs()
109+
110+
for b.Loop() {
111+
_, _ = SetStack(table, bb.stack)
112+
}
113+
})
114+
}
115+
}

0 commit comments

Comments
 (0)