Commit | Line | Data |
---|---|---|
1c6660ca | 1 | /******************************************************************************* |
60ae41e1 | 2 | * Copyright (c) 2013, 2014 Ericsson |
1c6660ca AM |
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 | * Contributors: | |
10 | * Alexandre Montplaisir - Initial API and implementation | |
ac31f2fb | 11 | * Patrick Tasse - Add support for thread id |
1c6660ca AM |
12 | *******************************************************************************/ |
13 | ||
9bc60be7 | 14 | package org.eclipse.tracecompass.internal.lttng2.ust.core.trace.callstack; |
1c6660ca AM |
15 | |
16 | import java.util.HashSet; | |
17 | import java.util.Set; | |
18 | ||
2bdf0193 AM |
19 | import org.eclipse.tracecompass.tmf.core.callstack.CallStackStateProvider; |
20 | import org.eclipse.tracecompass.tmf.core.event.ITmfEvent; | |
21 | import org.eclipse.tracecompass.tmf.core.event.ITmfEventField; | |
22 | import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; | |
9722e5d7 | 23 | import org.eclipse.tracecompass.tmf.ctf.core.event.CtfTmfEvent; |
1c6660ca AM |
24 | |
25 | /** | |
26 | * Callstack provider for LTTng-UST traces. | |
27 | * | |
28 | * If the traces contains 'func_entry' and 'func_exit' event (see the | |
29 | * lttng-ust-cyg-profile manpage), AND contains vtid and procname contexts, we | |
30 | * can use this information to populate the TMF Callstack View. | |
31 | * | |
32 | * Granted, most UST traces will not contain this information. In this case, | |
33 | * this will simply build an empty state system, and the view will remain | |
34 | * unavailable. | |
35 | * | |
36 | * @author Alexandre Montplaisir | |
37 | */ | |
38 | public class LttngUstCallStackProvider extends CallStackStateProvider { | |
39 | ||
40 | // ------------------------------------------------------------------------ | |
41 | // Event strings | |
42 | // ------------------------------------------------------------------------ | |
43 | ||
44 | /** Name of the fake field for the vtid contexts */ | |
45 | private static final String CONTEXT_VTID = "context._vtid"; //$NON-NLS-1$ | |
46 | ||
47 | /** Name of the fake field for the procname context */ | |
48 | private static final String CONTEXT_PROCNAME = "context._procname"; //$NON-NLS-1$ | |
49 | ||
50 | /** Field name for the target function address */ | |
51 | private static final String FIELD_ADDR = "addr"; //$NON-NLS-1$ | |
52 | ||
53 | /** Event names indicating function entry */ | |
e0838ca1 | 54 | private static final Set<String> FUNC_ENTRY_EVENTS = new HashSet<>(); |
1c6660ca AM |
55 | |
56 | /** Event names indicating function exit */ | |
e0838ca1 | 57 | private static final Set<String> FUNC_EXIT_EVENTS = new HashSet<>(); |
1c6660ca AM |
58 | |
59 | static { | |
60 | /* This seems overkill, but it will be checked every event. Gotta go FAST! */ | |
61 | FUNC_ENTRY_EVENTS.add("lttng_ust_cyg_profile:func_entry"); //$NON-NLS-1$ | |
62 | FUNC_ENTRY_EVENTS.add("lttng_ust_cyg_profile_fast:func_entry"); //$NON-NLS-1$ | |
63 | ||
64 | FUNC_EXIT_EVENTS.add("lttng_ust_cyg_profile:func_exit"); //$NON-NLS-1$ | |
65 | FUNC_EXIT_EVENTS.add("lttng_ust_cyg_profile_fast:func_exit"); //$NON-NLS-1$ | |
66 | } | |
67 | ||
5da83da5 AM |
68 | /** |
69 | * Version number of this state provider. Please bump this if you modify | |
70 | * the contents of the generated state history in some way. | |
71 | */ | |
aaee1ffb | 72 | private static final int VERSION = 2; |
5da83da5 | 73 | |
1c6660ca AM |
74 | // ------------------------------------------------------------------------ |
75 | // Constructor | |
76 | // ------------------------------------------------------------------------ | |
77 | ||
78 | /** | |
79 | * Constructor | |
80 | * | |
81 | * @param trace | |
82 | * The UST trace | |
83 | */ | |
50659279 | 84 | public LttngUstCallStackProvider(ITmfTrace trace) { |
1c6660ca AM |
85 | super(trace); |
86 | } | |
87 | ||
88 | // ------------------------------------------------------------------------ | |
89 | // Methods from AbstractTmfStateProvider | |
90 | // ------------------------------------------------------------------------ | |
91 | ||
1c6660ca AM |
92 | @Override |
93 | public LttngUstCallStackProvider getNewInstance() { | |
94 | return new LttngUstCallStackProvider(getTrace()); | |
95 | } | |
96 | ||
5da83da5 AM |
97 | @Override |
98 | public int getVersion() { | |
99 | return VERSION; | |
100 | } | |
101 | ||
1c6660ca AM |
102 | // ------------------------------------------------------------------------ |
103 | // Methods from CallStackStateProvider | |
104 | // ------------------------------------------------------------------------ | |
105 | ||
106 | /** | |
107 | * Check that this event contains the required information we need to be | |
108 | * used in the call stack view. We need at least the "procname" and "vtid" | |
109 | * contexts. | |
110 | */ | |
111 | @Override | |
112 | protected boolean considerEvent(ITmfEvent event) { | |
113 | if (!(event instanceof CtfTmfEvent)) { | |
114 | return false; | |
115 | } | |
116 | ITmfEventField content = ((CtfTmfEvent) event).getContent(); | |
117 | if (content.getField(CONTEXT_VTID) == null || | |
118 | content.getField(CONTEXT_PROCNAME) == null) { | |
119 | return false; | |
120 | } | |
121 | return true; | |
122 | } | |
123 | ||
124 | @Override | |
125 | public String functionEntry(ITmfEvent event) { | |
33803b9b | 126 | String eventName = event.getType().getName(); |
1c6660ca AM |
127 | if (!FUNC_ENTRY_EVENTS.contains(eventName)) { |
128 | return null; | |
129 | } | |
130 | Long address = (Long) event.getContent().getField(FIELD_ADDR).getValue(); | |
5da83da5 | 131 | return Long.toHexString(address); |
1c6660ca AM |
132 | } |
133 | ||
134 | @Override | |
135 | public String functionExit(ITmfEvent event) { | |
33803b9b | 136 | String eventName = event.getType().getName(); |
1c6660ca AM |
137 | if (!FUNC_EXIT_EVENTS.contains(eventName)) { |
138 | return null; | |
139 | } | |
140 | /* | |
141 | * The 'addr' field may or may not be present in func_exit events, | |
142 | * depending on if cyg-profile.so or cyg-profile-fast.so was used. | |
143 | */ | |
144 | ITmfEventField field = event.getContent().getField(FIELD_ADDR); | |
145 | if (field == null) { | |
146 | return CallStackStateProvider.UNDEFINED; | |
147 | } | |
148 | Long address = (Long) field.getValue(); | |
5da83da5 | 149 | return Long.toHexString(address); |
1c6660ca AM |
150 | } |
151 | ||
152 | @Override | |
153 | public String getThreadName(ITmfEvent event) { | |
154 | /* Class type and content was already checked if we get called here */ | |
155 | ITmfEventField content = ((CtfTmfEvent) event).getContent(); | |
156 | String procName = (String) content.getField(CONTEXT_PROCNAME).getValue(); | |
157 | Long vtid = (Long) content.getField(CONTEXT_VTID).getValue(); | |
158 | ||
159 | if (procName == null || vtid == null) { | |
160 | throw new IllegalStateException(); | |
161 | } | |
162 | ||
163 | return new String(procName + '-' + vtid.toString()); | |
164 | } | |
ac31f2fb PT |
165 | |
166 | @Override | |
167 | protected Long getThreadId(ITmfEvent event) { | |
168 | ITmfEventField content = ((CtfTmfEvent) event).getContent(); | |
169 | return (Long) content.getField(CONTEXT_VTID).getValue(); | |
170 | } | |
1c6660ca | 171 | } |