Commit | Line | Data |
---|---|---|
af3275f8 AM |
1 | /******************************************************************************* |
2 | * Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir | |
3 | * | |
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 | |
8 | *******************************************************************************/ | |
9 | ||
10 | package org.lttng.scope.lttng.kernel.core.views.timegraph.threads; | |
11 | ||
12 | import static java.util.Objects.requireNonNull; | |
13 | ||
14 | import java.util.Collections; | |
15 | import java.util.Comparator; | |
16 | import java.util.List; | |
17 | import java.util.function.Function; | |
18 | import java.util.function.Supplier; | |
19 | import java.util.stream.Collectors; | |
20 | import java.util.stream.Stream; | |
21 | ||
22 | import org.lttng.scope.lttng.kernel.core.analysis.os.Attributes; | |
23 | import org.lttng.scope.lttng.kernel.core.analysis.os.KernelAnalysisModule; | |
24 | import org.lttng.scope.tmf2.views.core.timegraph.model.provider.arrows.ITimeGraphModelArrowProvider; | |
25 | import org.lttng.scope.tmf2.views.core.timegraph.model.provider.states.ITimeGraphModelStateProvider; | |
26 | import org.lttng.scope.tmf2.views.core.timegraph.model.provider.statesystem.StateSystemModelProvider; | |
27 | import org.lttng.scope.tmf2.views.core.timegraph.model.render.tree.TimeGraphTreeElement; | |
28 | import org.lttng.scope.tmf2.views.core.timegraph.model.render.tree.TimeGraphTreeRender; | |
29 | ||
30 | import com.google.common.annotations.VisibleForTesting; | |
31 | import com.google.common.collect.ImmutableList; | |
32 | ||
33 | import ca.polymtl.dorsal.libdelorean.ITmfStateSystem; | |
34 | import ca.polymtl.dorsal.libdelorean.StateSystemUtils; | |
35 | import ca.polymtl.dorsal.libdelorean.exceptions.AttributeNotFoundException; | |
36 | import ca.polymtl.dorsal.libdelorean.interval.ITmfStateInterval; | |
37 | ||
38 | public class ThreadsModelProvider extends StateSystemModelProvider { | |
39 | ||
40 | private static final Supplier<ITimeGraphModelStateProvider> STATE_PROVIDER = () -> { | |
41 | return new ThreadsModelStateProvider(); | |
42 | }; | |
43 | ||
44 | private static final Supplier<List<ITimeGraphModelArrowProvider>> ARROW_PROVIDERS = () -> { | |
45 | return ImmutableList.of( | |
46 | new ThreadsModelArrowProviderCpus() | |
47 | ); | |
48 | }; | |
49 | ||
50 | private static final List<SortingMode> SORTING_MODES = ImmutableList.of( | |
51 | ThreadsConfigModes.SORTING_BY_TID, | |
52 | ThreadsConfigModes.SORTING_BY_THREAD_NAME); | |
53 | ||
54 | private static final List<FilterMode> FILTER_MODES = ImmutableList.of( | |
55 | ThreadsConfigModes.FILTERING_INACTIVE_ENTRIES); | |
56 | ||
57 | // ------------------------------------------------------------------------ | |
58 | // Tree render | |
59 | // ------------------------------------------------------------------------ | |
60 | ||
61 | /** | |
62 | * State values that are considered inactive, for purposes of filtering out | |
63 | * when the "filter inactive entries" mode is enabled. | |
64 | */ | |
65 | // private static final Set<ITmfStateValue> INACTIVE_STATE_VALUES = ImmutableSet.of( | |
66 | // TmfStateValue.nullValue(), | |
67 | // StateValues.PROCESS_STATUS_UNKNOWN_VALUE, | |
68 | // StateValues.PROCESS_STATUS_WAIT_UNKNOWN_VALUE, | |
69 | // StateValues.PROCESS_STATUS_WAIT_BLOCKED_VALUE | |
70 | // ); | |
71 | ||
72 | /** | |
73 | * Each "Thread" attribute has the following children: | |
74 | * | |
75 | * <ul> | |
76 | * <li>Prio</li> | |
77 | * <li>System_call</li> | |
78 | * <li>Exec_name</li> | |
79 | * <li>PPID</li> | |
80 | * </ul> | |
81 | * | |
82 | * The "Thread" is considered the base quark. | |
83 | */ | |
84 | private static final String[] BASE_QUARK_PATTERN = { Attributes.THREADS, "*" }; //$NON-NLS-1$ | |
85 | ||
86 | /** | |
87 | * Get the tree element name for every thread. It consists of the TID | |
88 | * followed by the first available exec_name for this thread. | |
89 | * | |
90 | * FIXME This implies a static tree definition for every TID, which does not | |
91 | * handle TID re-use correctly. The state system structure should be updated | |
92 | * accordingly. | |
93 | */ | |
94 | @VisibleForTesting | |
95 | public static final Function<TreeRenderContext, TimeGraphTreeRender> SS_TO_TREE_RENDER_FUNCTION = (treeContext) -> { | |
96 | ITmfStateSystem ss = treeContext.ss; | |
97 | // List<ITmfStateInterval> fullState = treeContext.fullQueryAtRangeStart; | |
98 | ||
99 | Stream<ThreadsTreeElement> treeElems = ss.getQuarks(BASE_QUARK_PATTERN).stream() | |
100 | .map(baseQuark -> { | |
101 | String tid = ss.getAttributeName(baseQuark); | |
102 | ||
103 | String threadName; | |
104 | try { | |
105 | int execNameQuark = ss.getQuarkRelative(baseQuark, Attributes.EXEC_NAME); | |
106 | // TODO We should look starting at | |
107 | // treeContext.renderTimeRangeStart first, and if we | |
108 | // don't find anything use ss.getStartTime(), so that we | |
109 | // catch subsequent process name changes | |
110 | ITmfStateInterval firstInterval = StateSystemUtils.queryUntilNonNullValue(ss, | |
111 | execNameQuark, ss.getStartTime(), Long.MAX_VALUE); | |
112 | if (firstInterval == null) { | |
113 | threadName = null; | |
114 | } else { | |
115 | threadName = firstInterval.getStateValue().unboxStr(); | |
116 | } | |
117 | } catch (AttributeNotFoundException e) { | |
118 | threadName = null; | |
119 | } | |
120 | ||
121 | return new ThreadsTreeElement(tid, threadName, Collections.emptyList(), baseQuark); | |
122 | }); | |
123 | ||
124 | /* Run the entries through the active filter modes */ | |
125 | // Set<FilterMode> filterModes = treeContext.filterModes; | |
126 | // if (filterModes.contains(ControlFlowConfigModes.FILTERING_INACTIVE_ENTRIES)) { | |
127 | // /* | |
128 | // * Filter out the tree elements whose state is considered inactive | |
129 | // * for the whole duration of the configured time range. | |
130 | // */ | |
131 | // treeElems = treeElems.filter(elem -> { | |
132 | // ITmfStateInterval interval = fullState.get(elem.getSourceQuark()); | |
133 | // if (interval.getEndTime() > treeContext.renderTimeRangeEnd && | |
134 | // INACTIVE_STATE_VALUES.contains(interval.getStateValue())) { | |
135 | // return false; | |
136 | // } | |
137 | // return true; | |
138 | // }); | |
139 | // } | |
140 | ||
141 | /* Sort entries according to the active sorting mode */ | |
142 | SortingMode sortingMode = treeContext.sortingMode; | |
143 | if (sortingMode == ThreadsConfigModes.SORTING_BY_TID) { | |
144 | treeElems = treeElems.sorted(Comparator.comparingInt(ThreadsTreeElement::getTid)); | |
145 | } else if (sortingMode == ThreadsConfigModes.SORTING_BY_THREAD_NAME) { | |
146 | treeElems = treeElems.sorted((elem1, elem2) -> { | |
147 | return elem1.getThreadName().compareToIgnoreCase(elem2.getThreadName()); | |
148 | }); | |
149 | } | |
150 | ||
151 | List<TimeGraphTreeElement> treeElemsList = treeElems.collect(Collectors.toList()); | |
152 | TimeGraphTreeElement rootElement = new TimeGraphTreeElement(treeContext.traceName, treeElemsList); | |
153 | return new TimeGraphTreeRender(rootElement); | |
154 | }; | |
155 | ||
156 | /** | |
157 | * Constructor | |
158 | */ | |
159 | public ThreadsModelProvider() { | |
160 | super(requireNonNull(Messages.threadsProviderName), | |
161 | SORTING_MODES, | |
162 | FILTER_MODES, | |
163 | STATE_PROVIDER.get(), | |
164 | ARROW_PROVIDERS.get(), | |
165 | /* Parameters specific to state system render providers */ | |
166 | KernelAnalysisModule.ID, | |
167 | SS_TO_TREE_RENDER_FUNCTION); | |
168 | ||
169 | enableFilterMode(0); | |
170 | } | |
171 | ||
172 | } |