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