Skip to content

Commit 0ecc23c

Browse files
committed
Send flamegraph row with grouping by executable name
1 parent 302475f commit 0ecc23c

File tree

5 files changed

+80
-29
lines changed

5 files changed

+80
-29
lines changed

x-pack/plugin/profiling/src/main/java/org/elasticsearch/xpack/profiling/action/GetStackTracesResponseBuilder.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class GetStackTracesResponseBuilder {
2020
private Map<String, String> executables;
2121
private Map<String, TraceEvent> stackTraceEvents;
2222
private List<TransportGetStackTracesAction.HostEventCount> hostEventCounts;
23-
private List<TransportGetStackTracesAction.ExecutableEventCount> executableEventCounts;
23+
private Map<TransportGetStackTracesAction.TraceEventMetadata, TraceEvent> executableEvents;
2424
private double samplingRate;
2525
private long totalSamples;
2626
private Double requestedDuration;
@@ -76,16 +76,16 @@ public void setHostEventCounts(List<TransportGetStackTracesAction.HostEventCount
7676
this.hostEventCounts = hostEventCounts;
7777
}
7878

79-
public void setExecutableEventCounts(List<TransportGetStackTracesAction.ExecutableEventCount> executableEventCounts) {
80-
this.executableEventCounts = executableEventCounts;
79+
public void setExecutableEvents(Map<TransportGetStackTracesAction.TraceEventMetadata, TraceEvent> executableEvents) {
80+
this.executableEvents = executableEvents;
8181
}
8282

8383
public List<TransportGetStackTracesAction.HostEventCount> getHostEventCounts() {
8484
return hostEventCounts;
8585
}
8686

87-
public List<TransportGetStackTracesAction.ExecutableEventCount> getExecutableEventCounts() {
88-
return executableEventCounts;
87+
public Map<TransportGetStackTracesAction.TraceEventMetadata, TraceEvent> getExecutableEvents() {
88+
return executableEvents;
8989
}
9090

9191
public Map<String, TraceEvent> getStackTraceEvents() {
@@ -164,6 +164,7 @@ public GetStackTracesResponse build() {
164164
if (event != null) {
165165
StackTrace stackTrace = entry.getValue();
166166
stackTrace.count = event.count;
167+
stackTrace.executableName = event.executableName;
167168
if (event.subGroups != null) {
168169
stackTrace.subGroups = event.subGroups;
169170
}

x-pack/plugin/profiling/src/main/java/org/elasticsearch/xpack/profiling/action/StackTrace.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ final class StackTrace implements ToXContentObject {
3030
double annualCO2Tons;
3131
double annualCostsUSD;
3232
long count;
33+
String executableName;
3334

3435
StackTrace(
3536
int[] addressOrLines,
@@ -47,6 +48,7 @@ final class StackTrace implements ToXContentObject {
4748
this.annualCO2Tons = annualCO2Tons;
4849
this.annualCostsUSD = annualCostsUSD;
4950
this.count = count;
51+
this.executableName = "";
5052
}
5153

5254
private static final int BASE64_FRAME_ID_LENGTH = 32;
@@ -222,6 +224,14 @@ public void forNativeAndKernelFrames(Consumer<String> consumer) {
222224
}
223225
}
224226

227+
public String getExecutableName() {
228+
if (executableName.isEmpty() && this.typeIds.length > 0 && this.typeIds[0] == KERNEL_FRAME_TYPE) {
229+
// kernel threads are not associated with an executable
230+
return "kernel";
231+
}
232+
return executableName;
233+
}
234+
225235
@Override
226236
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
227237
builder.startObject();
@@ -232,6 +242,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
232242
builder.field("annual_co2_tons", this.annualCO2Tons);
233243
builder.field("annual_costs_usd", this.annualCostsUSD);
234244
builder.field("count", this.count);
245+
builder.field("executable_name", this.executableName);
235246
builder.endObject();
236247
return builder;
237248
}
@@ -246,7 +257,8 @@ public boolean equals(Object o) {
246257
return Arrays.equals(addressOrLines, that.addressOrLines)
247258
&& Arrays.equals(fileIds, that.fileIds)
248259
&& Arrays.equals(frameIds, that.frameIds)
249-
&& Arrays.equals(typeIds, that.typeIds);
260+
&& Arrays.equals(typeIds, that.typeIds)
261+
&& executableName.equals(that.executableName);
250262
// Don't compare metadata like annualized co2, annualized costs, subGroups and count.
251263
}
252264

@@ -257,6 +269,7 @@ public int hashCode() {
257269
result = 31 * result + Arrays.hashCode(fileIds);
258270
result = 31 * result + Arrays.hashCode(frameIds);
259271
result = 31 * result + Arrays.hashCode(typeIds);
272+
result = 31 * result + executableName.hashCode();
260273
return result;
261274
}
262275
}

x-pack/plugin/profiling/src/main/java/org/elasticsearch/xpack/profiling/action/TraceEvent.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
final class TraceEvent {
1313
final String stacktraceID;
14+
String executableName;
1415
double annualCO2Tons;
1516
double annualCostsUSD;
1617
long count;
@@ -23,6 +24,7 @@ final class TraceEvent {
2324
TraceEvent(String stacktraceID, long count) {
2425
this.stacktraceID = stacktraceID;
2526
this.count = count;
27+
this.executableName = "";
2628
}
2729

2830
@Override
@@ -48,6 +50,9 @@ public String toString() {
4850
+ "stacktraceID='"
4951
+ stacktraceID
5052
+ '\''
53+
+ ", executableName='"
54+
+ executableName
55+
+ '\''
5156
+ ", annualCO2Tons="
5257
+ annualCO2Tons
5358
+ ", annualCostsUSD="

x-pack/plugin/profiling/src/main/java/org/elasticsearch/xpack/profiling/action/TransportGetFlamegraphAction.java

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,14 @@
2424
import java.util.HashMap;
2525
import java.util.List;
2626
import java.util.Map;
27+
import java.util.Objects;
2728
import java.util.SortedMap;
2829
import java.util.TreeMap;
2930

3031
public class TransportGetFlamegraphAction extends TransportAction<GetStackTracesRequest, GetFlamegraphResponse> {
32+
private static final int FRAMETYPE_ROOT = 0x100;
33+
private static final int FRAMETYPE_EXECUTABLE = 0x101;
34+
private static final int FRAMETYPE_THREAD = 0x102;
3135
private static final Logger log = LogManager.getLogger(TransportGetFlamegraphAction.class);
3236
private final NodeClient nodeClient;
3337
private final TransportService transportService;
@@ -79,16 +83,18 @@ static GetFlamegraphResponse buildFlamegraph(GetStackTracesResponse response) {
7983
builder.setCurrentNode(0);
8084

8185
long samples = stackTrace.count;
82-
builder.addSamplesInclusive(0, samples);
83-
builder.addSamplesExclusive(0, 0L);
84-
8586
double annualCO2Tons = stackTrace.annualCO2Tons;
86-
builder.addAnnualCO2TonsInclusive(0, annualCO2Tons);
87-
builder.addAnnualCO2TonsExclusive(0, 0.0d);
88-
8987
double annualCostsUSD = stackTrace.annualCostsUSD;
90-
builder.addAnnualCostsUSDInclusive(0, annualCostsUSD);
91-
builder.addAnnualCostsUSDExclusive(0, 0.0d);
88+
89+
builder.addToRootNode(samples, annualCO2Tons, annualCostsUSD);
90+
builder.addOrUpdateAggregationNode(
91+
stackTrace.getExecutableName(),
92+
samples,
93+
annualCO2Tons,
94+
annualCostsUSD,
95+
FRAMETYPE_EXECUTABLE
96+
);
97+
// builder.addOrUpdateAggregationNode(stackTrace.getThreadName(), samples, annualCO2Tons, annualCostsUSD, FRAMETYPE_THREAD);
9298

9399
int frameCount = stackTrace.frameIds.length;
94100
for (int i = 0; i < frameCount; i++) {
@@ -103,9 +109,8 @@ static GetFlamegraphResponse buildFlamegraph(GetStackTracesResponse response) {
103109
stackFrame.forEach(frame -> {
104110
String frameGroupId = FrameGroupID.create(fileId, addressOrLine, executable, frame.fileName(), frame.functionName());
105111

106-
int nodeId;
107-
if (builder.isExists(frameGroupId)) {
108-
nodeId = builder.getNodeId(frameGroupId);
112+
int nodeId = builder.getNodeId(frameGroupId);
113+
if (nodeId != -1) {
109114
builder.addSamplesInclusive(nodeId, samples);
110115
builder.addAnnualCO2TonsInclusive(nodeId, annualCO2Tons);
111116
builder.addAnnualCostsUSDInclusive(nodeId, annualCostsUSD);
@@ -186,10 +191,11 @@ private static class FlamegraphBuilder {
186191
this.annualCostsUSDInclusive = new ArrayList<>(capacity);
187192
this.annualCostsUSDExclusive = new ArrayList<>(capacity);
188193
this.totalSamples = totalSamples;
194+
this.samplingRate = samplingRate;
195+
189196
// always insert root node
190-
int nodeId = this.addNode("", 0, false, "", 0, "", 0, "", 0, 0, 0.0, 0.0, null);
197+
int nodeId = this.addNode("", FRAMETYPE_ROOT, false, "", 0, "", 0, "", 0, 0, 0.0, 0.0, null);
191198
this.setCurrentNode(nodeId);
192-
this.samplingRate = samplingRate;
193199
}
194200

195201
// returns the new node's id
@@ -233,6 +239,26 @@ public int addNode(
233239
return node;
234240
}
235241

242+
public void addToRootNode(long samples, double annualCO2Tons, double annualCostsUSD) {
243+
addSamplesInclusive(0, samples);
244+
addAnnualCO2TonsInclusive(0, annualCO2Tons);
245+
addAnnualCostsUSDInclusive(0, annualCostsUSD);
246+
}
247+
248+
public void addOrUpdateAggregationNode(String name, long samples, double annualCO2Tons, double annualCostsUSD, int frameType) {
249+
String frameGroupId = Integer.toString(Objects.hash(name, frameType));
250+
int nodeId = getNodeId(frameGroupId);
251+
252+
if (nodeId != -1) {
253+
addSamplesInclusive(nodeId, samples);
254+
addAnnualCO2TonsInclusive(nodeId, annualCO2Tons);
255+
addAnnualCostsUSDInclusive(nodeId, annualCostsUSD);
256+
setCurrentNode(nodeId);
257+
} else {
258+
setCurrentNode(addNode("", frameType, false, name, 0, "", 0, "", 0, samples, annualCO2Tons, annualCostsUSD, frameGroupId));
259+
}
260+
}
261+
236262
public void setCurrentNode(int nodeId) {
237263
this.currentNode = nodeId;
238264
}
@@ -242,7 +268,7 @@ public boolean isExists(String frameGroupId) {
242268
}
243269

244270
public int getNodeId(String frameGroupId) {
245-
return this.edges.get(currentNode).get(frameGroupId);
271+
return this.edges.get(currentNode).getOrDefault(frameGroupId, -1);
246272
}
247273

248274
public void addSamplesInclusive(int nodeId, long sampleCount) {

x-pack/plugin/profiling/src/main/java/org/elasticsearch/xpack/profiling/action/TransportGetStackTracesAction.java

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@ private void searchEventGroupedByStackTrace(
372372
// needed to load it.
373373
long totalFinalCount = 0;
374374
List<HostEventCount> hostEventCounts = new ArrayList<>(MAX_TRACE_EVENTS_RESULT_SIZE);
375-
List<ExecutableEventCount> executableEventCounts = new ArrayList<>(MAX_TRACE_EVENTS_RESULT_SIZE);
375+
Map<TraceEventMetadata, TraceEvent> executableEvents = new HashMap<>(MAX_TRACE_EVENTS_RESULT_SIZE);
376376
Map<String, TraceEvent> stackTraceEvents = new TreeMap<>();
377377

378378
Terms executableNames = searchResponse.getAggregations().get("group_by");
@@ -394,12 +394,6 @@ private void searchEventGroupedByStackTrace(
394394

395395
String stackTraceID = stacktraceBucket.getKeyAsString();
396396

397-
/*
398-
The same stacktraces may come from different executables.
399-
We make a list of the triples here.
400-
*/
401-
executableEventCounts.add(new ExecutableEventCount(executableName, stackTraceID, finalCount));
402-
403397
/*
404398
The same stacktraces may come from different hosts (eventually from different datacenters).
405399
We make a list of the triples here. As soon as we have the host metadata, we can calculate
@@ -410,16 +404,20 @@ The same stacktraces may come from different hosts (eventually from different da
410404
TraceEvent event = stackTraceEvents.get(stackTraceID);
411405
if (event == null) {
412406
event = new TraceEvent(stackTraceID);
407+
event.executableName = executableName; // THIS IS A HACK (need a proper data model)
413408
stackTraceEvents.put(stackTraceID, event);
414409
}
415410
event.count += finalCount;
416411
subGroups.collectResults(stacktraceBucket, event);
412+
413+
TraceEventMetadata meta = new TraceEventMetadata(executableName, stackTraceID);
414+
executableEvents.putIfAbsent(meta, event);
417415
}
418416
}
419417
}
420418
responseBuilder.setTotalSamples(totalFinalCount);
421419
responseBuilder.setHostEventCounts(hostEventCounts);
422-
responseBuilder.setExecutableEventCounts(executableEventCounts);
420+
responseBuilder.setExecutableEvents(executableEvents);
423421
log.debug(
424422
"Found [{}] stacktrace events, resampled with sample rate [{}] to [{}] events ([{}] unique stack traces).",
425423
totalCount,
@@ -858,5 +856,13 @@ private void mget(Client client, List<Index> indices, List<String> slice, Action
858856

859857
record HostEventCount(String hostID, String stacktraceID, int count) {}
860858

861-
record ExecutableEventCount(String executableName, String stacktraceID, int count) {}
859+
public static class TraceEventMetadata {
860+
final String stackTraceID;
861+
final String executableName;
862+
863+
TraceEventMetadata(String executableName, String stackTraceID) {
864+
this.stackTraceID = stackTraceID;
865+
this.executableName = executableName;
866+
}
867+
}
862868
}

0 commit comments

Comments
 (0)