Skip to content

Commit

Permalink
[2/2] Add differential flamegraph script (#2044)
Browse files Browse the repository at this point in the history
Summary: Add differential flamegraph script

This depends on #2043.

Relevant Issues: N/A

Type of change: /kind new-pxl-script

Test Plan: Ran the local UI and verified that the non negated version
works as expected

![differential](https://github.com/user-attachments/assets/e021d5f6-e3e2-4d5c-a3a6-17612695e429)

Changelog Message: Add `px/differential_flamegraph` script for comparing
flamegraphs profiles between pods. See [this
post](https://www.brendangregg.com/blog/2014-11-09/differential-flame-graphs.html)
for more background on how to use a differential flamegraph.

---------

Signed-off-by: Dom Del Nano <[email protected]>
  • Loading branch information
ddelnano authored Nov 13, 2024
1 parent 4778ba1 commit fd5cd63
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 0 deletions.
77 changes: 77 additions & 0 deletions src/pxl_scripts/px/differential_flamegraph/differential.pxl
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Copyright 2018- The Pixie Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0

import px

negate = False
# TODO(ddelnano): negation requires switching the type of join from right to left
# or returning a different DataFrame. This might not be possible with pxl's current
# functionality, but this should be implemented once it's possible.

def merge_and_compute_delta(pod1, pod2, negate: bool):

diff = pod1.merge(
pod2,
how='right',
left_on='stack_trace',
right_on='stack_trace'
suffixes=['_1', '_2'],
)
# TODO(ddelnano): This needs to be switched with pod1 if the flamegraph should
# be negated.
percentage_agg = pod2.groupby(['pod']).agg(
count=('count', px.sum),
)
diff.pod = px.select(negate, diff.pod_1, diff.pod_2)
diff.stack_trace = px.select(negate, diff.stack_trace_1, diff.stack_trace_2)
diff.stack_trace = px.replace(' ', diff.stack_trace, '')
diff.count = px.select(negate, diff.count_1, diff.count_2)
diff.delta = diff.count_2 - diff.count_1
diff.delta = px.select(negate, px.negate(diff.delta), diff.delta)

merged = diff.merge(
percentage_agg,
how='inner',
left_on='pod',
right_on='pod',
suffixes=['', '_x']
)
merged.percent = 100 * merged.count / merged.count_x
return merged

def differential_flamegraph(start_time: str, namespace: str, pod: str, baseline_pod: str):
stack_traces = px.DataFrame(table='stack_traces.beta', start_time=start_time)
stack_traces.namespace = stack_traces.ctx['namespace']
stack_traces = stack_traces[stack_traces.namespace == namespace]
stack_traces.node = px.Node(px._exec_hostname())
stack_traces.pod = stack_traces.ctx['pod']
stack_traces.keep_row = stack_traces.pod == baseline_pod
stack_traces.keep_row = px.select(stack_traces.keep_row or stack_traces.pod == pod, True, False)
stack_traces = stack_traces[stack_traces.keep_row]

stack_traces = stack_traces.groupby(['node', 'namespace', 'pod', 'stack_trace_id']).agg(
stack_trace=('stack_trace', px.any),
count=('count', px.sum)
)

pod1 = stack_traces[stack_traces.pod == baseline_pod]
pod1 = pod1.drop(['node', 'namespace', 'stack_trace_id'])

pod2 = stack_traces[stack_traces.pod == pod]
pod2 = pod2.drop(['node', 'namespace', 'stack_trace_id'])

merged = merge_and_compute_delta(pod1, pod2, negate)
return merged[['stack_trace', 'count', 'delta', 'percent', 'pod']]
5 changes: 5 additions & 0 deletions src/pxl_scripts/px/differential_flamegraph/manifest.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
short: Differential Flame Graph
long: >
This live view shows a differential CPU flame graph. This is helpful in identifying what code
paths have changed between deployments, different container instances, etc.
66 changes: 66 additions & 0 deletions src/pxl_scripts/px/differential_flamegraph/vis.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
{
"variables": [
{
"name": "start_time",
"type": "PX_STRING",
"description": "The relative start time of the window. Current time is assumed to be now",
"defaultValue": "-5m"
},
{
"name": "namespace",
"type": "PX_NAMESPACE",
"description": "The namespace to filter on."
},
{
"name": "pod",
"type": "PX_POD",
"description": "The pod that will have its flamegraph analyzed compared to the baseline_pod"
},
{
"name": "baseline_pod",
"type": "PX_POD",
"description": "The pod to serve as the baseline. The resulting flamegraph will show the difference from this pod's profile."
}
],
"globalFuncs": [],
"widgets": [
{
"name": "Flamegraph",
"position": {
"x": 0,
"y": 0,
"w": 12,
"h": 6
},
"func": {
"name": "differential_flamegraph",
"args": [
{
"name": "start_time",
"variable": "start_time"
},
{
"name": "namespace",
"variable": "namespace"
},
{
"name": "pod",
"variable": "pod"
},
{
"name": "baseline_pod",
"variable": "baseline_pod"
}
]
},
"displaySpec": {
"@type": "types.px.dev/px.vispb.StackTraceFlameGraph",
"stacktraceColumn": "stack_trace",
"countColumn": "count",
"percentageColumn": "percent",
"podColumn": "pod",
"differenceColumn": "delta"
}
}
]
}

0 comments on commit fd5cd63

Please sign in to comment.