Change profile stack element data structure (#4332)
* Change profile stack element to single level, not using tree
This commit is contained in:
parent
f29fc4bcb3
commit
e01829aa57
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
package org.apache.skywalking.oap.server.core.profile.analyze;
|
||||
|
||||
import org.apache.skywalking.oap.server.core.query.entity.ProfileStackElement;
|
||||
import org.apache.skywalking.oap.server.core.query.entity.ProfileStackTree;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
|
|
@ -32,7 +32,7 @@ import java.util.stream.Collector;
|
|||
/**
|
||||
* Work for {@link ProfileAnalyzer} to analyze.
|
||||
*/
|
||||
public class ProfileAnalyzeCollector implements Collector<ProfileStack, ProfileStackNode, ProfileStackElement> {
|
||||
public class ProfileAnalyzeCollector implements Collector<ProfileStack, ProfileStackNode, ProfileStackTree> {
|
||||
@Override
|
||||
public Supplier<ProfileStackNode> supplier() {
|
||||
return ProfileStackNode::newNode;
|
||||
|
|
@ -49,7 +49,7 @@ public class ProfileAnalyzeCollector implements Collector<ProfileStack, ProfileS
|
|||
}
|
||||
|
||||
@Override
|
||||
public Function<ProfileStackNode, ProfileStackElement> finisher() {
|
||||
public Function<ProfileStackNode, ProfileStackTree> finisher() {
|
||||
return ProfileStackNode::buildAnalyzeResult;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
package org.apache.skywalking.oap.server.core.profile.analyze;
|
||||
|
||||
import org.apache.skywalking.oap.server.core.query.entity.ProfileAnalyzation;
|
||||
import org.apache.skywalking.oap.server.core.query.entity.ProfileStackElement;
|
||||
import org.apache.skywalking.oap.server.core.query.entity.ProfileStackTree;
|
||||
import org.apache.skywalking.oap.server.library.util.CollectionUtils;
|
||||
|
||||
import java.util.*;
|
||||
|
|
@ -45,13 +45,13 @@ public class ProfileAnalyzer {
|
|||
}
|
||||
|
||||
// using parallel stream
|
||||
Map<String, ProfileStackElement> stackTrees = stacks.parallelStream()
|
||||
Map<String, ProfileStackTree> stackTrees = stacks.parallelStream()
|
||||
// stack list cannot be empty
|
||||
.filter(s -> CollectionUtils.isNotEmpty(s.getStack()))
|
||||
.collect(Collectors.groupingBy(s -> s.getStack().get(0), ANALYZE_COLLECTOR));
|
||||
|
||||
ProfileAnalyzation analyzer = new ProfileAnalyzation();
|
||||
analyzer.setStack(new ArrayList<>(stackTrees.values()));
|
||||
analyzer.setTrees(new ArrayList<>(stackTrees.values()));
|
||||
return analyzer;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,10 +20,10 @@ package org.apache.skywalking.oap.server.core.profile.analyze;
|
|||
|
||||
import com.google.common.base.Objects;
|
||||
import org.apache.skywalking.oap.server.core.query.entity.ProfileStackElement;
|
||||
import org.apache.skywalking.oap.server.core.query.entity.ProfileStackTree;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Work for profiling stacks, intermediate state of the {@link ProfileStackElement} and {@link ProfileStack}
|
||||
|
|
@ -149,10 +149,12 @@ public class ProfileStackNode {
|
|||
* build GraphQL result, calculate duration and count data using parallels
|
||||
* @return
|
||||
*/
|
||||
public ProfileStackElement buildAnalyzeResult() {
|
||||
public ProfileStackTree buildAnalyzeResult() {
|
||||
// all nodes add to single-level list (such as flat), work for parallel calculating
|
||||
LinkedList<Pair<ProfileStackElement, ProfileStackNode>> nodeMapping = new LinkedList<>();
|
||||
ProfileStackElement root = buildElement();
|
||||
int idGenerator = 1;
|
||||
|
||||
ProfileStackElement root = buildElement(idGenerator++);
|
||||
nodeMapping.add(new Pair<>(root, this));
|
||||
|
||||
// same with combine logic
|
||||
|
|
@ -163,21 +165,24 @@ public class ProfileStackNode {
|
|||
ProfileStackElement respElement = mergingPair.key;
|
||||
|
||||
// generate children node and add to stack and all node mapping
|
||||
respElement.setChildren(mergingPair.value.children.stream().map(c -> {
|
||||
ProfileStackElement element = c.buildElement();
|
||||
Pair<ProfileStackElement, ProfileStackNode> pair = new Pair<>(element, c);
|
||||
for (ProfileStackNode children : mergingPair.value.children) {
|
||||
ProfileStackElement element = children.buildElement(idGenerator++);
|
||||
element.setParentId(respElement.getId());
|
||||
|
||||
Pair<ProfileStackElement, ProfileStackNode> pair = new Pair<>(element, children);
|
||||
stack.add(pair);
|
||||
nodeMapping.add(pair);
|
||||
|
||||
return element;
|
||||
}).collect(Collectors.toList()));
|
||||
}
|
||||
}
|
||||
|
||||
// calculate durations
|
||||
nodeMapping.parallelStream().forEach(t -> t.value.calculateDuration(t.key));
|
||||
nodeMapping.parallelStream().forEach(t -> t.value.calculateDurationExcludeChild(t.key));
|
||||
|
||||
return root;
|
||||
ProfileStackTree tree = new ProfileStackTree();
|
||||
nodeMapping.forEach(n -> tree.getElements().add(n.key));
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
private void detectedBy(ProfileStack stack) {
|
||||
|
|
@ -188,10 +193,10 @@ public class ProfileStackNode {
|
|||
this.detectedStacks.addAll(node.detectedStacks);
|
||||
}
|
||||
|
||||
private ProfileStackElement buildElement() {
|
||||
private ProfileStackElement buildElement(int id) {
|
||||
ProfileStackElement element = new ProfileStackElement();
|
||||
element.setId(id);
|
||||
element.setCodeSignature(this.codeSignature);
|
||||
element.setChildren(new LinkedList<>());
|
||||
element.setCount(this.detectedStacks.size());
|
||||
return element;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,11 @@ import java.util.List;
|
|||
@Setter
|
||||
public class ProfileAnalyzation {
|
||||
|
||||
private List<ProfileStackElement> stack;
|
||||
// if not empty means backend has information gave to the user
|
||||
// such as: a large number of snapshots, only analyze part of the data
|
||||
private String tip;
|
||||
|
||||
// thread stack dump analyze trees
|
||||
private List<ProfileStackTree> trees;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,15 +21,14 @@ package org.apache.skywalking.oap.server.core.query.entity;
|
|||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author MrPro
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class ProfileStackElement {
|
||||
|
||||
// work for tree building, id matches multiple parentId
|
||||
private int id;
|
||||
private int parentId;
|
||||
|
||||
// stack code signature
|
||||
private String codeSignature;
|
||||
|
||||
|
|
@ -42,7 +41,4 @@ public class ProfileStackElement {
|
|||
// continuous dump count
|
||||
private int count;
|
||||
|
||||
// children of this stack code sign
|
||||
private List<ProfileStackElement> children;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*
|
||||
*/
|
||||
package org.apache.skywalking.oap.server.core.query.entity;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class ProfileStackTree {
|
||||
|
||||
private List<ProfileStackElement> elements = new ArrayList<>();
|
||||
|
||||
}
|
||||
|
|
@ -36,9 +36,9 @@ public class ProfileStackAnalyze {
|
|||
List<ProfileStack> stacks = data.transform();
|
||||
ProfileAnalyzation analyze = ProfileAnalyzer.analyze(stacks);
|
||||
|
||||
assertEquals(analyze.getStack().size(), expected.size());
|
||||
for (int i = 0; i < analyze.getStack().size(); i++) {
|
||||
expected.get(i).verify(analyze.getStack().get(i));
|
||||
assertEquals(analyze.getTrees().size(), expected.size());
|
||||
for (int i = 0; i < analyze.getTrees().size(); i++) {
|
||||
expected.get(i).verify(analyze.getTrees().get(i));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ package org.apache.skywalking.oap.server.core.profile.bean;
|
|||
|
||||
import lombok.Data;
|
||||
import org.apache.skywalking.oap.server.core.query.entity.ProfileStackElement;
|
||||
import org.apache.skywalking.oap.server.core.query.entity.ProfileStackTree;
|
||||
import org.apache.skywalking.oap.server.library.util.CollectionUtils;
|
||||
import org.junit.Assert;
|
||||
|
||||
|
|
@ -27,6 +28,7 @@ import java.util.Comparator;
|
|||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
|
|
@ -38,37 +40,56 @@ public class ProfileStackElementMatcher {
|
|||
private String code;
|
||||
private String duration;
|
||||
private int count;
|
||||
private int id = 0;
|
||||
private List<ProfileStackElementMatcher> children;
|
||||
|
||||
public void verify(ProfileStackElement element) {
|
||||
public void verify(ProfileStackTree tree) {
|
||||
// assert root
|
||||
List<ProfileStackElement> fromParent = getFromParentId(tree, 0);
|
||||
assertEquals(fromParent.size(), 1);
|
||||
assertCurrentNode(fromParent.get(0));
|
||||
|
||||
setId(fromParent.get(0).getId());
|
||||
assertChildren(tree, fromParent.get(0));
|
||||
}
|
||||
|
||||
private void assertChildren(ProfileStackTree tree, ProfileStackElement parent) {
|
||||
List<ProfileStackElement> analyzedChildren = getFromParentId(tree, parent.getId());
|
||||
|
||||
if (CollectionUtils.isEmpty(analyzedChildren)) {
|
||||
analyzedChildren = Collections.emptyList();
|
||||
}
|
||||
if (CollectionUtils.isEmpty(getChildren())) {
|
||||
setChildren(Collections.emptyList());
|
||||
}
|
||||
assertEquals(analyzedChildren.size(), children.size());
|
||||
|
||||
// children code signature not sorted, need sort it, then verify
|
||||
Collections.sort(children, Comparator.comparing(c -> c.code));
|
||||
Collections.sort(analyzedChildren, Comparator.comparing(c -> c.getCodeSignature()));
|
||||
|
||||
for (int i = 0; i < children.size(); i++) {
|
||||
children.get(i).setId(analyzedChildren.get(i).getId());
|
||||
children.get(i).assertCurrentNode(analyzedChildren.get(i));
|
||||
children.get(i).assertChildren(tree, analyzedChildren.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
private List<ProfileStackElement> getFromParentId(ProfileStackTree tree, int fromParentId) {
|
||||
return tree.getElements().stream().filter(e -> e.getParentId() == fromParentId).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private void assertCurrentNode(ProfileStackElement element) {
|
||||
// analyze duration
|
||||
Matcher durationInfo = DURATION_PATTERN.matcher(duration);
|
||||
Assert.assertTrue("duration field pattern not match", durationInfo.find());
|
||||
int duration = Integer.parseInt(durationInfo.group(1));
|
||||
int durationExcludeChild = Integer.parseInt(durationInfo.group(2));
|
||||
|
||||
// assert
|
||||
assertEquals(code, element.getCodeSignature());
|
||||
assertEquals(duration, element.getDuration());
|
||||
assertEquals(durationExcludeChild, element.getDurationChildExcluded());
|
||||
assertEquals(count, element.getCount());
|
||||
|
||||
if (CollectionUtils.isEmpty(children)) {
|
||||
children = Collections.emptyList();
|
||||
}
|
||||
if (CollectionUtils.isEmpty(element.getChildren())) {
|
||||
element.setChildren(Collections.emptyList());
|
||||
}
|
||||
assertEquals(children.size(), element.getChildren().size());
|
||||
|
||||
// children code signature not sorted, need sort it, then verify
|
||||
Collections.sort(children, Comparator.comparing(c -> c.code));
|
||||
Collections.sort(element.getChildren(), Comparator.comparing(c -> c.getCodeSignature()));
|
||||
|
||||
for (int i = 0; i < children.size(); i++) {
|
||||
children.get(i).verify(element.getChildren().get(i));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ public class ProfileQuery implements GraphQLQueryResolver {
|
|||
|
||||
public ProfileAnalyzation getProfileAnalyze(final String segmentId, final long start, final long end) {
|
||||
ProfileAnalyzation analyzation = new ProfileAnalyzation();
|
||||
analyzation.setStack(Collections.emptyList());
|
||||
analyzation.setTrees(Collections.emptyList());
|
||||
return analyzation;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit f4e314de312a5bc053c6dbd6a07b561885b33888
|
||||
Subproject commit 6104df8f0debce4c81142e5b1fc696d61bb673c5
|
||||
Loading…
Reference in New Issue