tmf: Refactor TMF statistics
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.ui / src / org / eclipse / linuxtools / tmf / ui / viewers / statistics / model / TmfStatisticsTree.java
CommitLineData
79e08fd0 1/*******************************************************************************
b544077e 2 * Copyright (c) 2011, 2012 Ericsson
013a5f1c 3 *
79e08fd0
BH
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
013a5f1c 8 *
79e08fd0 9 * Contributors:
36033ff0
AM
10 * Mathieu Denis <mathieu.denis@polymtl.ca> - Implementation and Initial API
11 *
79e08fd0
BH
12 *******************************************************************************/
13
cfd22ad0 14package org.eclipse.linuxtools.tmf.ui.viewers.statistics.model;
79e08fd0 15
36033ff0
AM
16import java.util.Arrays;
17import java.util.HashMap;
79e08fd0
BH
18import java.util.HashSet;
19import java.util.LinkedList;
5673a177 20import java.util.List;
79e08fd0
BH
21import java.util.Map;
22import java.util.Set;
23
79e08fd0 24/**
36033ff0
AM
25 * Base class for the statistics storage. It allow to implement a tree structure
26 * while avoiding the need to run through the tree each time you need to add a
27 * node at a given place.
013a5f1c 28 *
b544077e 29 * @author Mathieu Denis
36033ff0 30 * @version 2.0
cfd22ad0 31 * @since 2.0
79e08fd0 32 */
36033ff0
AM
33public class TmfStatisticsTree {
34
35 /**
36 * Identification of the root.
37 */
38 public static final String[] ROOT = new String[] { "root" }; //$NON-NLS-1$
79e08fd0
BH
39
40 /**
25a042b3 41 * Header for the event type categories.
79e08fd0 42 */
66711dc8 43 public static final String HEADER_EVENT_TYPES = Messages.TmfStatisticsData_EventTypes;
79e08fd0
BH
44
45 /**
09667aa4
MD
46 * Indicate that it's a value.
47 *
79e08fd0 48 * Used when checking the possible child node for a node.
09667aa4 49 *
79e08fd0 50 * It differentiate a category of a value by being appended to a value.
79e08fd0 51 */
66711dc8 52 protected static final String NODE = "z"; //$NON-NLS-1$
09667aa4 53
b544077e
BH
54 /**
55 * Root node key.
56 */
5673a177 57 protected static final String ROOT_NODE_KEY = mergeString(ROOT[0], NODE);
79e08fd0 58
36033ff0
AM
59 /**
60 * Define what children a node can have. The management and usage of this map
61 * is done by subclasses. HashSet are always faster than TreeSet for String keys.
62 */
63 protected Map<String, Set<String>> fKeys;
64
65 /**
66 * The nodes in the tree.
67 */
68 protected Map<List<String>, TmfStatisticsTreeNode> fNodes;
69
b544077e
BH
70 /**
71 * Default constructor. Creates base statistics tree for counting total
72 * number of events and number of events per event type.
73 */
36033ff0
AM
74 public TmfStatisticsTree() {
75 fNodes = new HashMap<List<String>, TmfStatisticsTreeNode>();
76 fKeys = new HashMap<String, Set<String>>();
77
79e08fd0
BH
78 Map<String, Set<String>> keys = getKeys();
79
80 // //////////// Adding category sets
81 // common
82 keys.put(HEADER_EVENT_TYPES, new HashSet<String>());
83
84 // /////////// Adding value sets
85 // Under a trace
86 Set<String> temp = new HashSet<String>(8);
87 temp.add(HEADER_EVENT_TYPES);
88 keys.put(ROOT_NODE_KEY, temp);
89 // Under an event type
90 temp = new HashSet<String>(16);
91 keys.put(mergeString(HEADER_EVENT_TYPES, NODE), temp);
92
93 // //////////// CREATE root
5673a177 94 keys.put(ROOT[0], new HashSet<String>(2)); // 1 trace at the time
79e08fd0
BH
95 getOrCreate(ROOT);
96 }
97
36033ff0
AM
98 /**
99 * Get a node.
100 *
101 * @param path
102 * Path to the node.
103 * @return The node or null.
104 */
105 public TmfStatisticsTreeNode get(String... path) {
106 List<String> pathAsList = Arrays.asList(path);
107 return fNodes.get(pathAsList);
108 }
109
110 /**
111 * Get the children of a node.
09667aa4 112 *
36033ff0
AM
113 * @param path
114 * Path to the node.
115 * @return Collection containing the children.
79e08fd0 116 */
5673a177
AM
117 public List<TmfStatisticsTreeNode> getChildren(String... path) {
118 List<TmfStatisticsTreeNode> result = new LinkedList<TmfStatisticsTreeNode>();
79e08fd0 119
5673a177 120 if (path.length % 2 == 0) { // if we are at a Category
79e08fd0 121 TmfStatisticsTreeNode current = null;
5673a177
AM
122 for (String value : getKeys().get(path[path.length - 1])) {
123 current = get(addToArray(path, value));
124 if (current != null) {
125 if (current.getValues().getTotal() > 0 || current.getValues().getPartial() > 0) {
126 result.add(current);
127 }
013a5f1c 128 }
79e08fd0 129 }
5673a177 130 } else if (path.length == 1) { // Special case.
013a5f1c 131 if (path.equals(ROOT)) {
5673a177
AM
132 for (String value : getKeys().get(ROOT[0])) {
133 result.add(getOrCreate(value));
013a5f1c
AM
134 }
135 } else {
79e08fd0 136 // Get value under the root
013a5f1c 137 for (String value : getKeys().get(ROOT_NODE_KEY)) {
5673a177 138 result.add(getOrCreate(addToArray(path, value)));
013a5f1c
AM
139 }
140 }
79e08fd0 141 } else {// If we are at a value
5673a177 142 for (String value : getKeys().get(mergeString(path[path.length - 2], NODE))) {
79e08fd0 143 // Search the parent name + NODE
5673a177 144 result.add(getOrCreate(addToArray(path, value)));
013a5f1c 145 }
79e08fd0
BH
146 }
147
148 return result;
149 }
150
36033ff0
AM
151 /**
152 * Get every children of a node, even if it doesn't have any registered
153 * events, as opposed to getChildren
09667aa4 154 *
36033ff0
AM
155 * @param path
156 * Path to the node.
157 * @return Collection containing all the children.
79e08fd0 158 */
36033ff0 159 public List<TmfStatisticsTreeNode> getAllChildren(String... path) {
79e08fd0
BH
160 LinkedList<TmfStatisticsTreeNode> result = new LinkedList<TmfStatisticsTreeNode>();
161
5673a177 162 if (path.length % 2 == 0) { // if we are at a Category
79e08fd0 163 TmfStatisticsTreeNode current = null;
5673a177
AM
164 for (String value : getKeys().get(path[path.length - 1])) {
165 current = get(addToArray(path, value));
013a5f1c 166 if (current != null) {
79e08fd0 167 result.add(current);
013a5f1c 168 }
79e08fd0 169 }
5673a177 170 } else if (path.length == 1) { // Special case.
013a5f1c 171 if (path.equals(ROOT)) {
5673a177
AM
172 for (String value : getKeys().get(ROOT[0])) {
173 result.add(getOrCreate(value));
013a5f1c
AM
174 }
175 } else {
79e08fd0 176 // Get value under the root
013a5f1c 177 for (String value : getKeys().get(ROOT_NODE_KEY)) {
5673a177 178 result.add(getOrCreate(addToArray(path, value)));
013a5f1c
AM
179 }
180 }
79e08fd0 181 } else {// If we are at a value
5673a177 182 for (String value : getKeys().get(mergeString(path[path.length - 2], NODE))) {
79e08fd0 183 // Search the parent name + NODE
5673a177 184 result.add(getOrCreate(addToArray(path, value)));
013a5f1c 185 }
79e08fd0
BH
186 }
187 return result;
188 }
189
36033ff0
AM
190 /**
191 * Get the map of existing elements of path classified by parent.
192 *
193 * @return The map.
194 */
195 public Map<String, Set<String>> getKeys() {
196 return fKeys;
197 }
198
199 /**
200 * Get or create a node.
201 *
202 * @param path
203 * Path to the node.
204 * @return The node.
205 */
206 public TmfStatisticsTreeNode getOrCreate(String... path) {
207 List<String> pathAsList = Arrays.asList(path);
208 TmfStatisticsTreeNode current = fNodes.get(pathAsList);
209
210 if (current == null) {
211 registerName(path);
212 current = new TmfStatisticsTreeNode(this, path);
213 fNodes.put(pathAsList, current);
214 }
215 return current;
216 }
217
218 /**
219 * Get the parent of a node.
220 *
221 * @param path
222 * Path to the node.
223 * @return Parent node or null.
224 */
225 public TmfStatisticsTreeNode getParent(final String... path) {
226 if (path.length == 1) {
227 if (path.equals(ROOT)) {
228 return null;
229 }
230 return get(ROOT);
231 }
232
233 String[] parentPath = new String[path.length - 1];
234 System.arraycopy(path, 0, parentPath, 0, parentPath.length);
235 return get(parentPath);
236 }
237
238 /**
239 * Set the value to display in the "total" cells. This means the row
240 * indicating the total count of events for a trace.
241 *
242 * @param traceName
243 * The name of the trace (will be used as a sub-tree in the view)
244 * @param isGlobal
245 * Is this a for a global or a time range request? Determines if
246 * this goes in the Global column or the Selected Time Range one.
247 * @param qty
248 * The value to display
249 */
89c06060 250 public void setTotal(String traceName, boolean isGlobal, long qty) {
5673a177
AM
251 String[][] paths = getNormalPaths(traceName);
252 for (String path[] : paths) {
89c06060 253 getOrCreate(path).getValues().setValue(isGlobal, qty);
73fbf6be 254 }
25a042b3
MD
255 }
256
36033ff0
AM
257 /**
258 * Set the value to display in the "Type count" cells. These are the counts
259 * for each event types.
260 *
261 * @param traceName
262 * The name of the trace (will be used as a sub-tree in the view)
263 * @param type
264 * The event type
265 * @param isGlobal
266 * Is this a for a global or a time range request? Determines if
267 * this goes in the Global column or the Selected Time Range one.
268 * @param qty
269 * The value to display
270 */
89c06060 271 public void setTypeCount(String traceName, String type, boolean isGlobal, long qty) {
5673a177
AM
272 String[][] paths = getTypePaths(traceName, type);
273 for (String[] path : paths) {
89c06060 274 getOrCreate(path).getValues().setValue(isGlobal, qty);
25a042b3
MD
275 }
276 }
277
79e08fd0 278 /**
09667aa4 279 * Get the event types paths.
013a5f1c 280 *
79e08fd0
BH
281 * @param event
282 * Event to get the path for.
283 * @param extraInfo
284 * Extra information to pass along with the event
285 * @return Array of FixedArray representing the paths.
286 */
5673a177
AM
287 protected String[][] getTypePaths(String traceName, String type) {
288 String[][] paths = { new String[] {traceName, HEADER_EVENT_TYPES, type } };
79e08fd0
BH
289 return paths;
290 }
291
292 /**
09667aa4 293 * Get the standard paths for an event.
013a5f1c 294 *
79e08fd0
BH
295 * @param event
296 * Event to get the path for.
297 * @param extraInfo
298 * Extra information to pass along with the event
299 * @return Array of FixedArray representing the paths.
300 */
5673a177
AM
301 protected String[][] getNormalPaths(String traceName) {
302 String[][] paths = { new String[] { traceName } };
79e08fd0
BH
303 return paths;
304 }
013a5f1c 305
36033ff0
AM
306 /**
307 * Register that a new node was created.
308 *
309 * Must make sure the {@link #getChildren(TmfFixedArray)} on the parent node
310 * will return the newly created node.
09667aa4 311 *
36033ff0
AM
312 * @param path
313 * Path of the new node.
79e08fd0 314 */
5673a177
AM
315 protected void registerName(String... path) {
316 if (path.length == 1) {
013a5f1c 317 if (!path.equals(ROOT)) {
5673a177 318 getKeys().get(ROOT[0]).add(path[0]);
013a5f1c 319 }
5673a177
AM
320 } else if (path.length % 2 != 0) {
321 getKeys().get(path[path.length - 2]).add(path[path.length - 1]);
013a5f1c 322 }
79e08fd0 323 }
5673a177 324
36033ff0
AM
325 /**
326 * Resets a node.
327 *
328 * Works recursively.
329 *
330 * @param path
331 * Path to the node.
332 */
333 public void reset(final String... path) {
334 for (TmfStatisticsTreeNode node : getAllChildren(path)) {
335 reset(node.getPath());
336 List<String> nodePathList = Arrays.asList(node.getPath());
337 fNodes.remove(nodePathList);
338 }
339 }
340
341 /**
342 * Reset the global value of a node.
343 *
344 * Works recursively.
345 *
346 * @param path
347 * Path to the node.
348 * @since 2.0
349 */
350 public void resetGlobalValue(final String... path) {
351 for (TmfStatisticsTreeNode node : getChildren(path)) {
352 node.resetGlobalValue();
353 }
354 }
355
356 /**
357 * Reset the time range value of a node.
358 *
359 * Works recursively.
360 *
361 * @param path
362 * Path to the node.
363 * @since 2.0
364 */
365 public void resetTimeRangeValue(final String... path) {
366 for (TmfStatisticsTreeNode node : getChildren(path)) {
367 node.resetTimeRangeValue();
368 }
369 }
370
371 /**
372 * Function to merge many string more efficiently.
373 *
374 * @param strings
375 * Strings to merge.
376 * @return A new string containing all the strings.
377 */
378 protected static String mergeString(String... strings) {
379 StringBuilder builder = new StringBuilder();
380 for (String s : strings) {
381 builder.append(s);
382 }
383 return builder.toString();
384 }
385
5673a177
AM
386 /**
387 * Return a new array that's a copy of the old one, plus 'newElem' added at
388 * the end.
389 */
390 private static String[] addToArray(String[] array, String newElem) {
391 String[] newArray = new String[array.length + 1];
392 System.arraycopy(array, 0, newArray, 0, array.length);
393 newArray[array.length] = newElem;
394 return newArray;
395 }
79e08fd0 396}
This page took 0.050551 seconds and 5 git commands to generate.