Skip to content

Commit ee029a3

Browse files
committed
profilingmetrics: add syscall metric
Signed-off-by: Florian Lehner <florian.lehner@elastic.co>
1 parent bf8fecc commit ee029a3

File tree

1 file changed

+103
-6
lines changed
  • connector/profilingmetricsconnector

1 file changed

+103
-6
lines changed

connector/profilingmetricsconnector/frame.go

Lines changed: 103 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,10 @@ type frameInfo struct {
3838
filename string
3939
}
4040

41-
const nativeLibraryAttrName = "shlib_name"
41+
const (
42+
nativeLibraryAttrName = "shlib_name"
43+
syscallAttrName = "syscall_name"
44+
)
4245

4346
var (
4447
metricUser = metric{name: "samples.user.count", desc: "Number of samples executing userspace code (self)"}
@@ -70,10 +73,14 @@ var (
7073
frameTypeBeam: metricBeam,
7174
}
7275

76+
// match shared libraries
7377
rx = regexp.MustCompile(`(?:.*/)?(.+)\.so`)
78+
79+
// match syscalls
80+
syscallRx = regexp.MustCompile(`^__(?:x64|arm64)_sys_(\w+)`)
7481
)
7582

76-
func fetchFrameInfo(dictionary pprofile.ProfilesDictionary,
83+
func fetchLeafFrameInfo(dictionary pprofile.ProfilesDictionary,
7784
locationIndices pcommon.Int32Slice,
7885
sampleLocationIndex int,
7986
) (frameInfo, error) {
@@ -153,12 +160,12 @@ func classifyFrame(dictionary pprofile.ProfilesDictionary,
153160
counts map[metric]int64,
154161
nativeCounts map[string]int64,
155162
) error {
156-
fi, err := fetchFrameInfo(dictionary, locationIndices, 0)
163+
leaf, err := fetchLeafFrameInfo(dictionary, locationIndices, 0)
157164
if err != nil {
158165
return err
159166
}
160167

161-
leafFrameType := fi.typ
168+
leafFrameType := leaf.typ
162169
// We don't need a separate metric for total number of samples, as this can always be
163170
// derived from summing the metricKernel and metricUser counts.
164171
metric := allowedFrameTypes[leafFrameType]
@@ -177,7 +184,7 @@ func classifyFrame(dictionary pprofile.ProfilesDictionary,
177184
}
178185

179186
// Extract native library name and increment associated count
180-
if sm := rx.FindStringSubmatch(fi.filename); sm != nil {
187+
if sm := rx.FindStringSubmatch(leaf.filename); sm != nil {
181188
nativeCounts[sm[1]]++
182189
} else {
183190
counts[metric]++
@@ -186,13 +193,82 @@ func classifyFrame(dictionary pprofile.ProfilesDictionary,
186193
return nil
187194
}
188195

196+
// identifySyscall walks the frames and extracts the syscall information.
197+
func identifySyscall(dictionary pprofile.ProfilesDictionary,
198+
locationIndices pcommon.Int32Slice,
199+
syscallCounts map[string]int64,
200+
) error {
201+
// TODO: Scale syscallCounts by number of events in each Sample. Currently,
202+
// this logic assumes 1 event per Sample (thus the increments by 1 below),
203+
// which isn't necessarily the case.
204+
attrTable := dictionary.AttributeTable()
205+
locationTable := dictionary.LocationTable()
206+
strTable := dictionary.StringTable()
207+
funcTable := dictionary.FunctionTable()
208+
209+
attrTblLen := attrTable.Len()
210+
locTblLen := locationTable.Len()
211+
strTblLen := strTable.Len()
212+
funcTblLen := funcTable.Len()
213+
214+
for _, li := range locationIndices.All() {
215+
if li >= int32(locTblLen) {
216+
// log error
217+
continue
218+
}
219+
loc := locationTable.At(int(li))
220+
for _, attrIdx := range loc.AttributeIndices().All() {
221+
if attrIdx >= int32(attrTblLen) {
222+
// log error
223+
continue
224+
}
225+
attr := attrTable.At(int(attrIdx))
226+
if int(attr.KeyStrindex()) >= strTblLen {
227+
// log error
228+
continue
229+
}
230+
231+
if strTable.At(int(attr.KeyStrindex())) == string(semconv.ProfileFrameTypeKey) {
232+
frameType := attr.Value().Str()
233+
if frameType == frameTypeKernel {
234+
for _, ln := range loc.Line().All() {
235+
if ln.FunctionIndex() >= int32(funcTblLen) {
236+
// log error
237+
continue
238+
}
239+
fn := funcTable.At(int(ln.FunctionIndex()))
240+
if fn.NameStrindex() >= int32(strTblLen) {
241+
// log error
242+
continue
243+
}
244+
fnName := strTable.At(int(fn.NameStrindex()))
245+
246+
// Avoid string allocations by using indices to string location.
247+
indices := syscallRx.FindStringSubmatchIndex(fnName)
248+
if len(indices) == 4 {
249+
syscall := fnName[indices[2]:indices[3]]
250+
syscallCounts[syscall]++
251+
return nil
252+
}
253+
}
254+
255+
}
256+
}
257+
258+
}
259+
260+
}
261+
return nil
262+
}
263+
189264
func (c *profilesToMetricsConnector) addFrameMetrics(dictionary pprofile.ProfilesDictionary,
190265
profile pprofile.Profile, scopeMetrics pmetric.ScopeMetrics,
191266
) {
192267
stackTable := dictionary.StackTable()
193268

194269
counts := make(map[metric]int64)
195270
nativeCounts := make(map[string]int64)
271+
syscallCounts := make(map[string]int64)
196272

197273
// Process all samples and extract metric counts
198274
for _, sample := range profile.Sample().All() {
@@ -201,7 +277,12 @@ func (c *profilesToMetricsConnector) addFrameMetrics(dictionary pprofile.Profile
201277
sample, counts, nativeCounts); err != nil {
202278
// Should not happen with well-formed profile data
203279
// TODO: Add error metric or log error
204-
continue
280+
}
281+
282+
if err := identifySyscall(dictionary, stack.LocationIndices(),
283+
syscallCounts); err != nil {
284+
// Should not happen with well-formed profile data
285+
// TODO: Add error metric or log error
205286
}
206287
}
207288

@@ -236,4 +317,20 @@ func (c *profilesToMetricsConnector) addFrameMetrics(dictionary pprofile.Profile
236317
dp.SetIntValue(count)
237318
dp.Attributes().PutStr(nativeLibraryAttrName, libraryName)
238319
}
320+
321+
for sysCall, count := range syscallCounts {
322+
m := scopeMetrics.Metrics().AppendEmpty()
323+
m.SetName(c.config.MetricsPrefix + metricNative.name)
324+
m.SetDescription(metricNative.desc)
325+
m.SetUnit("1")
326+
327+
sum := m.SetEmptySum()
328+
sum.SetIsMonotonic(true)
329+
sum.SetAggregationTemporality(pmetric.AggregationTemporalityDelta)
330+
331+
dp := sum.DataPoints().AppendEmpty()
332+
dp.SetTimestamp(profile.Time())
333+
dp.SetIntValue(count)
334+
dp.Attributes().PutStr(syscallAttrName, sysCall)
335+
}
239336
}

0 commit comments

Comments
 (0)