-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathscriptedDataProvider.js
More file actions
198 lines (175 loc) · 7.44 KB
/
scriptedDataProvider.js
File metadata and controls
198 lines (175 loc) · 7.44 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
/*******************************************************************************
* Copyright (c) 2019 Geneviève Bastien
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* scriptedDataProvider.js
*******************************************************************************/
// load Trace Compass modules
loadModule('/TraceCompass/Analysis');
loadModule('/TraceCompass/DataProvider');
loadModule('/TraceCompass/View');
loadModule('/TraceCompass/Utils');
// Create an analysis named mpiring.js.
var analysis = getAnalysis("mpiring.js");
if (analysis == null) {
print("Trace is null");
exit();
}
// Get the analysis's state system so we can fill it, false indicates to create a new state system even if one already exists, true would re-use an existing state system
var ss = analysis.getStateSystem(false);
// Variable to save the arrow information
var arrows = [];
// The analysis itself is in this function
function runAnalysis() {
// Get the event iterator for the trace
var iter = analysis.getEventIterator();
var event = null;
// Associate a TID with an mpi resource
var tidToResMap = {};
// Save information on the pending arrows
var pendingArrows = {};
// Parse all events
while (iter.hasNext()) {
event = iter.next();
// Do something when the event if it is one we are interested in
name = event.getName();
if (name == "mpi:mpi_init_exit") {
// This function is a wrapper to get the value of field CPU in the event, or return null if the field is not present
resourceId = getFieldValue(event, "res");
tid = getFieldValue(event, "tid");
if ((resourceId != null) && (tid != null)) {
// Save the association between tid and resource
tidToResMap[tid] = resourceId;
}
} else if (name == "mpi:mpi_recv_entry") {
// First get the current resource from its tid
tid = getFieldValue(event, "tid");
if (tid != null) {
resourceId = tidToResMap[tid];
if (resourceId != null) {
// Save the state of the resource as waiting for reception
quark = ss.getQuarkAbsoluteAndAdd(resourceId);
ss.modifyAttribute(event.getTimestamp().toNanos(), "Waiting for reception", quark);
}
}
} else if (name == "mpi:mpi_recv_exit") {
tid = getFieldValue(event, "tid");
if (tid != null) {
resourceId = tidToResMap[tid];
if (resourceId != null) {
// Close the receiving state of the resource
quark = ss.getQuarkAbsoluteAndAdd(resourceId);
ss.removeAttribute(event.getTimestamp().toNanos(), quark);
}
// We received a message, see if we can close a pending arrow
source = getFieldValue(event, "source");
if (source != null) {
pending = pendingArrows[resourceId];
if (pending != null) {
// There is a pending arrow (ie send) for this message
pendingArrows[resourceId] = null;
pending["endTime"] = event.getTimestamp().toNanos();
arrows.push(pending);
}
}
}
} else if (name == "mpi:mpi_send_entry") {
tid = getFieldValue(event, "tid");
if (tid != null) {
resourceId = tidToResMap[tid];
if (resourceId != null) {
// Save the state of this resource as "Sending message"
quark = ss.getQuarkAbsoluteAndAdd(resourceId);
ss.modifyAttribute(event.getTimestamp().toNanos(), "Sending message", quark);
}
// Prepare the start of an arrow
dest = getFieldValue(event, "dest");
if (dest != null) {
pendingArrows[dest] = {"time" : event.getTimestamp().toNanos(), "source" : resourceId, "dest" : dest};
}
}
} else if (name == "mpi:mpi_send_exit") {
tid = getFieldValue(event, "tid");
if (tid != null) {
resourceId = tidToResMap[tid];
if (resourceId != null) {
// Close the sending state of this resource
quark = ss.getQuarkAbsoluteAndAdd(resourceId);
ss.removeAttribute(event.getTimestamp().toNanos(), quark);
}
}
}
}
// Done parsing the events, close the state system at the time of the last event, it needs to be done manually otherwise the state system will still be waiting for values and will not be considered finished building
if (event != null) {
ss.closeHistory(event.getTimestamp().toNanos());
}
}
// This condition verifies if the state system is completed. For instance, if it had been built in a previous run of the script, it wouldn't run again.
if (!ss.waitUntilBuilt(0)) {
// State system not built, run the analysis
runAnalysis();
}
// Get list wrappers from Trace Compass for the entries and arrows. The conversion between javascript list and java list is not direct, so we need a wrapper
var tgEntries = createListWrapper();
var tgArrows = createListWrapper();
// Prepare the time graph data, there is few enough entries and arrows that it can be done once and returned once
function prepareTimeGraph() {
// Map the resource to an entry ID
var mpiResToId = {};
// Prepare the entries
quarks = ss.getQuarks("*");
// Prepare the entry names and sort them
var mpiEntries = [];
for (i = 0; i < quarks.size(); i++) {
quark = quarks.get(i);
mpiEntries.push(ss.getAttributeName(quark));
}
mpiEntries.sort(function(a,b){return Number(a) - Number(b)});
// With the sorted entry name, actually create the entries
var entries = [];
for (i = 0; i < mpiEntries.length; i++) {
// Get the mpi resource ID, and find its quark
mpiResId = mpiEntries[i];
quark = ss.getQuarkAbsolute(mpiResId);
// Create an entry with the resource ID as name and the quark. The quark value will be used to populate the entry's data.
entry = createEntry(mpiResId, {'quark' : quark});
// Add the entry to the entry list
tgEntries.getList().add(entry);
// Map the resource ID with the entry ID. This information will be useful to create the arrows later
mpiResToId[mpiResId] = entry.getId();
}
// Prepare the arrows
for (i=0; i < arrows.length; i++) {
arrow = arrows[i];
// For each arrow, we get the source and destination entry ID from its mpi resource ID
srcId = mpiResToId[arrow["source"]];
dstId = mpiResToId[arrow["dest"]];
// Get the start time and calculate the duration
startTime = arrow["time"];
duration = arrow["endTime"] - startTime;
// Add the arrow to the arrows list
tgArrows.getList().add(createArrow(srcId, dstId, startTime, duration, 1));
}
}
// Call the preparation of the time graph data
prepareTimeGraph();
// A function used to return the entries to the data provider. It receives the filter in parameter, which contains the requested time range and any additional information
function getEntries(parameters) {
// The list is static once built, return all entries
return tgEntries.getList();
}
// A function used to return the arrows to the data provider. It receives the filter in parameter, which contains the requested time range and any additional information
function getArrows(parameters) {
// Just return all the arrows, the view will take those in the range
return tgArrows.getList();
}
// Create a scripted data provider for this analysis, using script functions to get the entries, row model data and arrows. Since the entries have a quark associated with them which contains the data to display, there is no need for a scripted getRowData function, so we send null
provider = createScriptedTimeGraphProvider(analysis, getEntries, null, getArrows);
if (provider != null) {
// Open a time graph view displaying this provider
openTimeGraphView(provider);
}