• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 package ohos.devtools.views.applicationtrace;
17 
18 import ohos.devtools.views.applicationtrace.bean.AppFunc;
19 import ohos.devtools.views.applicationtrace.bean.TreeTableBean;
20 import ohos.devtools.views.applicationtrace.util.TimeUtils;
21 
22 import javax.swing.tree.DefaultMutableTreeNode;
23 import javax.swing.tree.TreeNode;
24 import java.util.ArrayList;
25 import java.util.Enumeration;
26 import java.util.HashMap;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Objects;
30 import java.util.concurrent.TimeUnit;
31 import java.util.stream.Collectors;
32 
33 import static java.util.stream.Collectors.groupingBy;
34 
35 /**
36  * DataProcess
37  *
38  * @since 2021/5/12 16:34
39  */
40 public class DataProcess {
41     /**
42      * get the get TopDown FuncTree by startNS、endNS and threadIds
43      *
44      * @param funcMap funcMap
45      * @param startNS startNS
46      * @param endNS endNS
47      * @param threadIds threadIds
48      * @return list <DefaultMutableTreeNode> nodes
49      */
getFuncTreeTopDown(Map<Integer, List<AppFunc>> funcMap, long startNS, long endNS, List<Integer> threadIds)50     public static List<DefaultMutableTreeNode> getFuncTreeTopDown(Map<Integer, List<AppFunc>> funcMap, long startNS,
51         long endNS, List<Integer> threadIds) {
52         if (Objects.isNull(funcMap)) {
53             return new ArrayList<>();
54         }
55         List<AppFunc> funcs =
56             funcMap.entrySet().stream().filter(entry -> threadIds == null || threadIds.contains(entry.getKey()))
57                 .flatMap(entry -> entry.getValue().stream()).collect(Collectors.toList());
58         Map<String, TreeTableBean> map = funcGroupByStackId(startNS, endNS, funcs, null);
59         List<TreeTableBean> treeTableBeans = setNumForNodes(map);
60         Map<String, DefaultMutableTreeNode> treeNodeMap = treeTableBeans.stream()
61             .collect(Collectors.toMap(TreeTableBean::getPrefStackId, DefaultMutableTreeNode::new));
62         treeTableBeans.forEach(treeTableBean -> {
63             if (!treeTableBean.getPrefParentStackId().isEmpty()) {
64                 if (treeNodeMap.containsKey(treeTableBean.getPrefParentStackId())) {
65                     treeNodeMap.get(treeTableBean.getPrefParentStackId())
66                         .add(treeNodeMap.get(treeTableBean.getPrefStackId()));
67                 }
68             }
69         });
70         return treeNodeMap.values().stream().filter(node -> {
71             if (node.getUserObject() instanceof TreeTableBean) {
72                 return ((TreeTableBean) node.getUserObject()).getPrefParentStackId().isEmpty();
73             }
74             return false;
75         }).collect(Collectors.toList());
76     }
77 
78     /**
79      * get the get BottomUp FuncTree by startNS、endNS and threadIds
80      *
81      * @param funcMap funcMap
82      * @param startNS startNS
83      * @param endNS endNS
84      * @param threadIds threadIds
85      * @return list <DefaultMutableTreeNode> nodes
86      */
87     public static List<DefaultMutableTreeNode> getFuncTreeBottomUp(Map<Integer, List<AppFunc>> funcMap, long startNS,
88         long endNS, List<Integer> threadIds) {
89         long dur = TimeUnit.NANOSECONDS.toMicros(endNS - startNS);
90         ArrayList<DefaultMutableTreeNode> nodes = new ArrayList<>();
91         Map<String, List<String>> nameToId = new HashMap<>();
92         List<AppFunc> funcs =
93             funcMap.entrySet().stream().filter(entry -> threadIds == null || threadIds.contains(entry.getKey()))
94                 .flatMap(entry -> entry.getValue().stream()).collect(Collectors.toList());
95         Map<String, TreeTableBean> treeNodeMap = funcGroupByStackId(startNS, endNS, funcs, nameToId);
96         setNumForNodes(treeNodeMap);
97         nameToId.forEach((name, ids) -> {
98             DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode();
99             TreeTableBean treeTableBean = new TreeTableBean(dur);
100             treeTableBean.setName(name);
101             long totalNum = 0L;
102             long childrenNum = 0L;
103             long selfNum = 0L;
104             for (String id : ids) {
105                 TreeTableBean tableBean = treeNodeMap.get(id);
106                 totalNum += tableBean.getTotalNum();
107                 childrenNum += tableBean.getChildrenNum();
108                 selfNum += tableBean.getSelfNum();
109             }
110             treeTableBean.setTotalNum(totalNum);
111             treeTableBean.setSelfNum(selfNum);
112             treeTableBean.setChildrenNum(childrenNum);
113             rootNode.setUserObject(treeTableBean);
114             ids.forEach(id -> recursionNode(rootNode, treeNodeMap.get(id).getPrefParentStackId(), treeNodeMap, id));
115             nodes.add(rootNode);
116         });
117         return nodes;
118     }
119 
120     private static Map<String, TreeTableBean> funcGroupByStackId(long startNS, long endNS, List<AppFunc> list,
121         Map<String, List<String>> nameToId) { // Group by stacked
122         long dur = TimeUnit.NANOSECONDS.toMicros(endNS - startNS);
123         List<Map.Entry<String, List<AppFunc>>> list1 = list.stream().filter(func -> {
124             long funcEndTs = func.getEndTs();
125             long funcStartTs = func.getStartTs();
126             return funcEndTs >= startNS && funcStartTs <= endNS;
127         }).collect(groupingBy(AppFunc::getBloodId)).entrySet().stream().collect(Collectors.toList());
128         return list1.stream().collect(Collectors.toMap(Map.Entry::getKey, a1 -> {
129             TreeTableBean uniteBean = new TreeTableBean(dur);
130             uniteBean.setThreadDur(dur);
131             uniteBean.setPrefStackId(a1.getKey());
132             if (a1.getValue().size() > 0) {
133                 uniteBean.setName(a1.getValue().get(0).getFuncName());
134                 uniteBean.setPrefParentStackId(a1.getValue().get(0).getParentBloodId());
135                 if (nameToId != null) {
136                     if (nameToId.containsKey(a1.getValue().get(0).getFuncName())) {
137                         nameToId.get(a1.getValue().get(0).getFuncName()).add(a1.getValue().get(0).getBloodId());
138                     } else {
139                         List<String> arrayList = new ArrayList<>();
140                         arrayList.add(a1.getValue().get(0).getBloodId());
141                         nameToId.put(a1.getValue().get(0).getFuncName(), arrayList);
142                     }
143                 }
144             }
145             long childrenTotal = a1.getValue().stream()
146                 .mapToLong(child -> TimeUtils.getIntersection(startNS, endNS, child.getStartTs(), child.getEndTs()))
147                 .sum();
148             uniteBean.setTotalNum(childrenTotal);
149             uniteBean.setChildrenNS(a1.getValue().stream()
150                 .mapToLong(child -> TimeUtils.getNanoIntersection(startNS, endNS, child.getStartTs(), child.getEndTs()))
151                 .sum());
152             return uniteBean;
153         }));
154     }
155 
156     /**
157      * Set up presentation data
158      *
159      * @param map map
160      * @return list <TreeTableBean>
161      */
162     private static List<TreeTableBean> setNumForNodes(Map<String, TreeTableBean> map) {
163         List<TreeTableBean> treeNodes = new ArrayList<>(map.values()); // Sort the array
164         for (TreeTableBean ts : treeNodes) { // Loop set children and total data
165             ts.setSelfNum(ts.getTotalNum() - ts.getChildrenNum());
166             if (map.containsKey(ts.getPrefParentStackId())) {
167                 TreeTableBean mapUserObject = map.get(ts.getPrefParentStackId());
168                 mapUserObject.setChildrenNum(mapUserObject.getChildrenNum() + ts.getTotalNum());
169                 mapUserObject.setSelfNum(mapUserObject.getTotalNum() - mapUserObject.getChildrenNum());
170             }
171         }
172         return treeNodes;
173     }
174 
175     private static void recursionNode(DefaultMutableTreeNode rootNode, String parentId,
176         Map<String, TreeTableBean> treeNodeMap, String id) {
177         if (rootNode.getUserObject() instanceof TreeTableBean) {
178             TreeTableBean topBean = (TreeTableBean) rootNode.getUserObject();
179             TreeTableBean timeBean = treeNodeMap.get(id);
180             if (parentId.isEmpty()) { // Leaf node
181                 recursionNodeLeaf(rootNode, timeBean);
182             } else { // Non-leaf nodes
183                 Map<String, String> Ids = new HashMap();
184                 Ids.put("parentId", parentId);
185                 Ids.put("id", id);
186                 recursionNodeNonLeaf(rootNode, timeBean, topBean, treeNodeMap, Ids);
187             }
188         }
189     }
190 
191     private static void recursionNodeNonLeaf(DefaultMutableTreeNode rootNode, TreeTableBean timeBean,
192         TreeTableBean topBean, Map<String, TreeTableBean> treeNodeMap, Map<String, String> Ids) {
193         final TreeTableBean idBean = treeNodeMap.get(Ids.get("parentId"));
194         boolean sameName = false;
195         Enumeration<TreeNode> enumeration = rootNode.children();
196         while (enumeration.hasMoreElements()) {
197             /* Compare whether there are node names in the current hierarchy that need to be merged */
198             TreeNode treeNode = enumeration.nextElement();
199             if (treeNode instanceof DefaultMutableTreeNode) {
200                 DefaultMutableTreeNode nextElement = (DefaultMutableTreeNode) treeNode;
201                 if (nextElement.getUserObject() instanceof TreeTableBean) {
202                     TreeTableBean nextElementUserObject = (TreeTableBean) nextElement.getUserObject();
203                     if (nextElementUserObject.getName().equals(idBean.getName())) { // The merge time difference
204                         nextElementUserObject.mergeTime(timeBean);
205                         recursionNode(nextElement, idBean.getPrefParentStackId(), treeNodeMap, Ids.get("id"));
206                         sameName = true;
207                     }
208                 }
209             }
210         }
211         if (!sameName) { // No same node needs to be merged
212             DefaultMutableTreeNode addNode = new DefaultMutableTreeNode();
213             TreeTableBean treeTableBean = new TreeTableBean(topBean.getThreadDur());
214             treeTableBean.setName(idBean.getName());
215             treeTableBean.setTime(timeBean);
216             addNode.setUserObject(treeTableBean);
217             rootNode.add(addNode);
218             recursionNode(addNode, idBean.getPrefParentStackId(), treeNodeMap, Ids.get("id"));
219         }
220     }
221 
222     private static void recursionNodeLeaf(DefaultMutableTreeNode rootNode, TreeTableBean timeBean) {
223         if (rootNode.getChildCount() != 0) { // The child node is thread and there are currently no child nodes
224             TreeNode child = rootNode.getChildAt(rootNode.getChildCount() - 1);
225             if (child instanceof DefaultMutableTreeNode) {
226                 DefaultMutableTreeNode leafNode = (DefaultMutableTreeNode) child;
227                 if (leafNode.getUserObject() instanceof TreeTableBean) {
228                     TreeTableBean leafNodeUserObject = (TreeTableBean) leafNode.getUserObject();
229                     leafNodeUserObject.mergeTime(timeBean);
230                     leafNode.setUserObject(leafNodeUserObject);
231                 }
232             }
233         }
234     }
235 }
236