analysis: introduce latency table view
[deliverable/tracecompass.git] / analysis / org.eclipse.tracecompass.analysis.os.linux.core / src / org / eclipse / tracecompass / analysis / os / linux / core / latency / LatencyAnalysis.java
CommitLineData
7b79ee46
FLN
1/*******************************************************************************
2 * Copyright (c) 2015 EfficiOS Inc., Ericsson
3 *
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 *******************************************************************************/
9
10package org.eclipse.tracecompass.analysis.os.linux.core.latency;
11
12import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
13
14import java.io.IOException;
15import java.io.ObjectInputStream;
16import java.io.ObjectOutputStream;
17import java.nio.file.Files;
18import java.nio.file.Path;
19import java.nio.file.Paths;
20import java.util.HashMap;
21import java.util.HashSet;
22import java.util.Map;
23import java.util.Set;
24
25import org.eclipse.core.runtime.IProgressMonitor;
26import org.eclipse.jdt.annotation.Nullable;
27import org.eclipse.tracecompass.analysis.os.linux.core.kernelanalysis.KernelTidAspect;
28import org.eclipse.tracecompass.analysis.os.linux.core.trace.IKernelAnalysisEventLayout;
29import org.eclipse.tracecompass.analysis.os.linux.core.trace.IKernelTrace;
30import org.eclipse.tracecompass.common.core.NonNullUtils;
31import org.eclipse.tracecompass.segmentstore.core.ISegment;
32import org.eclipse.tracecompass.segmentstore.core.ISegmentStore;
33import org.eclipse.tracecompass.segmentstore.core.treemap.TreeMapStore;
34import org.eclipse.tracecompass.tmf.core.analysis.TmfAbstractAnalysisModule;
35import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
36import org.eclipse.tracecompass.tmf.core.exceptions.TmfAnalysisException;
37import org.eclipse.tracecompass.tmf.core.request.ITmfEventRequest;
38import org.eclipse.tracecompass.tmf.core.request.TmfEventRequest;
39import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
40
41import com.google.common.base.Function;
42import com.google.common.collect.FluentIterable;
43
44/**
45 * @author Alexandre Montplaisir
46 * @since 1.1
47 */
48public class LatencyAnalysis extends TmfAbstractAnalysisModule {
49
50 /**
51 * The ID of this analysis
52 */
53 public static final String ID = "org.eclipse.tracecompass.analysis.os.linux.latency"; //$NON-NLS-1$
54
55 private static final String DATA_FILENAME = "latency-analysis.dat"; //$NON-NLS-1$
56
57 private @Nullable ISegmentStore<ISegment> fSystemCalls;
58
59 private final Set<LatencyAnalysisListener> fListeners = new HashSet<>();
60
61 @Override
62 public String getId() {
63 return ID;
64 }
65
66 /**
67 * Listener for the viewers
68 *
69 * @param listener
70 * listener for each type of viewer
71 */
72 public void addListener(LatencyAnalysisListener listener) {
73 fListeners.add(listener);
74 }
75
76 @Override
77 protected boolean executeAnalysis(IProgressMonitor monitor) throws TmfAnalysisException {
78 IKernelTrace trace = checkNotNull((IKernelTrace) getTrace());
79 IKernelAnalysisEventLayout layout = trace.getKernelEventLayout();
80
81 /* See if the data file already exists on disk */
82 String dir = TmfTraceManager.getSupplementaryFileDir(trace);
83 final Path file = Paths.get(dir, DATA_FILENAME);
84
85 if (Files.exists(file)) {
86 /* Attempt to read the existing file */
87 try (ObjectInputStream ois = new ObjectInputStream(Files.newInputStream(file))) {
88 @SuppressWarnings("unchecked")
89 ISegmentStore<ISegment> syscalls = (ISegmentStore<ISegment>) ois.readObject();
90 fSystemCalls = syscalls;
91 return true;
92 } catch (IOException | ClassNotFoundException | ClassCastException e) {
93 /*
94 * We did not manage to read the file successfully, we will just
95 * fall-through to rebuild a new one.
96 */
97 try {
98 Files.delete(file);
99 } catch (IOException e1) {
100 }
101 }
102 }
103
104 ISegmentStore<ISegment> syscalls = new TreeMapStore<>();
105 ITmfEventRequest req = new LatencyAnalysisRequest(layout, syscalls);
106 trace.sendRequest(req);
107 try {
108 req.waitForCompletion();
109 } catch (InterruptedException e) {
110 }
111 /* The request will fill 'syscalls' */
112 fSystemCalls = syscalls;
113
114 /* Serialize the collections to disk for future usage */
115 try (ObjectOutputStream oos = new ObjectOutputStream(Files.newOutputStream(file))) {
116 oos.writeObject(syscalls);
117 } catch (IOException e) {
118 /* Didn't work, oh well. We will just re-read the trace next time */
119 }
120
121 for (LatencyAnalysisListener listener : fListeners) {
122 listener.onComplete(this, syscalls);
123 }
124
125 return true;
126 }
127
128 @Override
129 protected void canceling() {
130
131 }
132
133 /**
134 * @return Results from the analysis in a ISegmentStore
135 */
136 public @Nullable ISegmentStore<ISegment> getResults() {
137 return fSystemCalls;
138 }
139
140 private static class LatencyAnalysisRequest extends TmfEventRequest {
141
142 private final IKernelAnalysisEventLayout fLayout;
143 private final ISegmentStore<ISegment> fFullSyscalls;
144 private final Map<Integer, SystemCall.InitialInfo> fOngoingSystemCalls = new HashMap<>();
145
146 public LatencyAnalysisRequest(IKernelAnalysisEventLayout layout, ISegmentStore<ISegment> syscalls) {
147 super(ITmfEvent.class, 0, ITmfEventRequest.ALL_DATA, ExecutionType.BACKGROUND);
148 fLayout = layout;
149 /*
150 * We do NOT make a copy here! We want to modify the list that was
151 * passed in parameter.
152 */
153 fFullSyscalls = syscalls;
154 }
155
156 @Override
157 public void handleData(final ITmfEvent event) {
158 super.handleData(event);
159 final String eventName = event.getType().getName();
160
161 if (eventName.startsWith(fLayout.eventSyscallEntryPrefix()) ||
162 eventName.startsWith(fLayout.eventCompatSyscallEntryPrefix())) {
163 /* This is a system call entry event */
164
165 Integer tid = KernelTidAspect.INSTANCE.resolve(event);
166 if (tid == null) {
167 // no information on this event/trace ?
168 return;
169 }
170
171 /* Record the event's data into the intial system call info */
172 // String syscallName = fLayout.getSyscallNameFromEvent(event);
173 long startTime = event.getTimestamp().getValue();
174 String syscallName = eventName.substring(fLayout.eventSyscallEntryPrefix().length());
175 FluentIterable<String> argNames = FluentIterable.from(event.getContent().getFieldNames());
176 Map<String, String> args = argNames.toMap(new Function<String, String>() {
177 @Override
178 public String apply(@Nullable String input) {
179 return checkNotNull(event.getContent().getField(input).getValue().toString());
180 }
181 });
182 SystemCall.InitialInfo newSysCall = new SystemCall.InitialInfo(startTime, NonNullUtils.checkNotNull(syscallName), NonNullUtils.checkNotNull(args));
183 fOngoingSystemCalls.put(tid, newSysCall);
184
185 } else if (eventName.startsWith(fLayout.eventSyscallExitPrefix())) {
186 /* This is a system call exit event */
187
188 Integer tid = KernelTidAspect.INSTANCE.resolve(event);
189 if (tid == null) {
190 return;
191 }
192
193 SystemCall.InitialInfo info = fOngoingSystemCalls.remove(tid);
194 if (info == null) {
195 /*
196 * We have not seen the entry event corresponding to this
197 * exit (lost event, or before start of trace).
198 */
199 return;
200 }
201
202 long endTime = event.getTimestamp().getValue();
203 int ret = ((Long) event.getContent().getField("ret").getValue()).intValue(); //$NON-NLS-1$
204 ISegment syscall = new SystemCall(info, endTime, ret);
205 fFullSyscalls.addElement(syscall);
206 }
207 }
208
209 @Override
210 public void handleCompleted() {
211 fOngoingSystemCalls.clear();
212 }
213 }
214
215}
This page took 0.03151 seconds and 5 git commands to generate.