From e01829aa570fe7a14f69a8cf82deb99382df22a4 Mon Sep 17 00:00:00 2001 From: mrproliu <741550557@qq.com> Date: Sun, 9 Feb 2020 16:37:45 +0800 Subject: [PATCH] Change profile stack element data structure (#4332) * Change profile stack element to single level, not using tree --- .../analyze/ProfileAnalyzeCollector.java | 6 +- .../core/profile/analyze/ProfileAnalyzer.java | 6 +- .../profile/analyze/ProfileStackNode.java | 29 +++++---- .../core/query/entity/ProfileAnalyzation.java | 7 ++- .../query/entity/ProfileStackElement.java | 12 ++-- .../core/query/entity/ProfileStackTree.java | 32 ++++++++++ .../profile/bean/ProfileStackAnalyze.java | 6 +- .../bean/ProfileStackElementMatcher.java | 59 +++++++++++++------ .../query/graphql/resolver/ProfileQuery.java | 2 +- .../src/main/resources/query-protocol | 2 +- 10 files changed, 110 insertions(+), 51 deletions(-) create mode 100644 oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/entity/ProfileStackTree.java diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profile/analyze/ProfileAnalyzeCollector.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profile/analyze/ProfileAnalyzeCollector.java index 2a1cb2d34..d8875dc66 100644 --- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profile/analyze/ProfileAnalyzeCollector.java +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profile/analyze/ProfileAnalyzeCollector.java @@ -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 { +public class ProfileAnalyzeCollector implements Collector { @Override public Supplier supplier() { return ProfileStackNode::newNode; @@ -49,7 +49,7 @@ public class ProfileAnalyzeCollector implements Collector finisher() { + public Function finisher() { return ProfileStackNode::buildAnalyzeResult; } diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profile/analyze/ProfileAnalyzer.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profile/analyze/ProfileAnalyzer.java index 72857f857..bc5ef3995 100644 --- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profile/analyze/ProfileAnalyzer.java +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profile/analyze/ProfileAnalyzer.java @@ -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 stackTrees = stacks.parallelStream() + Map 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; } diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profile/analyze/ProfileStackNode.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profile/analyze/ProfileStackNode.java index 6afdde0c3..289347912 100644 --- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profile/analyze/ProfileStackNode.java +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profile/analyze/ProfileStackNode.java @@ -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> 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 pair = new Pair<>(element, c); + for (ProfileStackNode children : mergingPair.value.children) { + ProfileStackElement element = children.buildElement(idGenerator++); + element.setParentId(respElement.getId()); + + Pair 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; } diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/entity/ProfileAnalyzation.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/entity/ProfileAnalyzation.java index f6b444e2e..f18698e18 100644 --- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/entity/ProfileAnalyzation.java +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/entity/ProfileAnalyzation.java @@ -30,6 +30,11 @@ import java.util.List; @Setter public class ProfileAnalyzation { - private List 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 trees; } diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/entity/ProfileStackElement.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/entity/ProfileStackElement.java index 423329e9b..26470ba18 100644 --- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/entity/ProfileStackElement.java +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/entity/ProfileStackElement.java @@ -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 children; - } diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/entity/ProfileStackTree.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/entity/ProfileStackTree.java new file mode 100644 index 000000000..c569e1912 --- /dev/null +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/entity/ProfileStackTree.java @@ -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 elements = new ArrayList<>(); + +} diff --git a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/profile/bean/ProfileStackAnalyze.java b/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/profile/bean/ProfileStackAnalyze.java index 78b49d457..bc1639ee1 100644 --- a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/profile/bean/ProfileStackAnalyze.java +++ b/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/profile/bean/ProfileStackAnalyze.java @@ -36,9 +36,9 @@ public class ProfileStackAnalyze { List 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)); } } diff --git a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/profile/bean/ProfileStackElementMatcher.java b/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/profile/bean/ProfileStackElementMatcher.java index e8886e3db..183df990e 100644 --- a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/profile/bean/ProfileStackElementMatcher.java +++ b/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/profile/bean/ProfileStackElementMatcher.java @@ -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 children; - public void verify(ProfileStackElement element) { + public void verify(ProfileStackTree tree) { + // assert root + List 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 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 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)); - } - } } diff --git a/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/ProfileQuery.java b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/ProfileQuery.java index 350157aec..9898ae96a 100644 --- a/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/ProfileQuery.java +++ b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/ProfileQuery.java @@ -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; } diff --git a/oap-server/server-query-plugin/query-graphql-plugin/src/main/resources/query-protocol b/oap-server/server-query-plugin/query-graphql-plugin/src/main/resources/query-protocol index f4e314de3..6104df8f0 160000 --- a/oap-server/server-query-plugin/query-graphql-plugin/src/main/resources/query-protocol +++ b/oap-server/server-query-plugin/query-graphql-plugin/src/main/resources/query-protocol @@ -1 +1 @@ -Subproject commit f4e314de312a5bc053c6dbd6a07b561885b33888 +Subproject commit 6104df8f0debce4c81142e5b1fc696d61bb673c5