Commit | Line | Data |
---|---|---|
6d02c5c1 HD |
1 | /******************************************************************************* |
2 | * Copyright (c) 2016 École Polytechnique de Montréal | |
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.eclipse.tracecompass.internal.analysis.os.linux.core.inputoutput; | |
11 | ||
12 | import java.util.HashMap; | |
13 | import java.util.Map; | |
14 | ||
15 | import org.eclipse.jdt.annotation.Nullable; | |
16 | import org.eclipse.tracecompass.analysis.os.linux.core.inputoutput.Attributes; | |
17 | import org.eclipse.tracecompass.analysis.os.linux.core.inputoutput.IoOperationType; | |
18 | import org.eclipse.tracecompass.analysis.os.linux.core.inputoutput.StateValues; | |
19 | import org.eclipse.tracecompass.common.core.NonNullUtils; | |
20 | import org.eclipse.tracecompass.internal.analysis.os.linux.core.Activator; | |
21 | import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem; | |
22 | import org.eclipse.tracecompass.statesystem.core.ITmfStateSystemBuilder; | |
23 | import org.eclipse.tracecompass.statesystem.core.StateSystemBuilderUtils; | |
24 | import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException; | |
25 | import org.eclipse.tracecompass.statesystem.core.exceptions.StateValueTypeException; | |
26 | import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue; | |
27 | import org.eclipse.tracecompass.statesystem.core.statevalue.TmfStateValue; | |
28 | import org.eclipse.tracecompass.tmf.core.statesystem.TmfAttributePool; | |
29 | import org.eclipse.tracecompass.tmf.core.statesystem.TmfAttributePool.QueueType; | |
30 | import org.eclipse.tracecompass.tmf.core.util.Pair; | |
31 | ||
32 | import com.google.common.hash.HashFunction; | |
33 | import com.google.common.hash.Hashing; | |
34 | ||
35 | /** | |
36 | * Class that represents a disk on a system. This class provides operation to | |
37 | * save the analysis data in a state system. | |
38 | * | |
39 | * @author Houssem Daoud | |
40 | * @since 2.0 | |
41 | */ | |
42 | public class DiskWriteModel { | |
43 | ||
44 | private static final HashFunction HF = NonNullUtils.checkNotNull(Hashing.goodFastHash(32)); | |
45 | ||
46 | private final Integer fDev; | |
47 | private final Map<Long, Pair<Request, Integer>> fDriverQueue = new HashMap<>(); | |
48 | private final Map<Long, Pair<Request, Integer>> fWaitingQueue = new HashMap<>(); | |
49 | private final ITmfStateSystemBuilder fSs; | |
50 | private final int fDiskQuark; | |
51 | private final TmfAttributePool fWaitingQueueAttrib; | |
52 | private final TmfAttributePool fDriverQueueAttrib; | |
53 | private @Nullable String fDiskname = null; | |
54 | ||
55 | /** | |
56 | * Constructor | |
57 | * | |
58 | * @param dev | |
59 | * The device number of the disk | |
60 | * @param ss | |
61 | * The state system this disk will be saved to | |
62 | */ | |
63 | public DiskWriteModel(Integer dev, ITmfStateSystemBuilder ss) { | |
64 | fDev = dev; | |
65 | fSs = ss; | |
66 | /* Initialize the state system for this disk */ | |
67 | fDiskQuark = fSs.getQuarkAbsoluteAndAdd(Attributes.DISKS, String.valueOf(dev)); | |
68 | fSs.getQuarkRelativeAndAdd(fDiskQuark, Attributes.SECTORS_WRITTEN); | |
69 | fSs.getQuarkRelativeAndAdd(fDiskQuark, Attributes.SECTORS_READ); | |
70 | int wqQuark = fSs.getQuarkRelativeAndAdd(fDiskQuark, Attributes.WAITING_QUEUE); | |
71 | fWaitingQueueAttrib = new TmfAttributePool(fSs, wqQuark, QueueType.PRIORITY); | |
72 | fSs.getQuarkRelativeAndAdd(fDiskQuark, Attributes.WAITING_QUEUE_LENGTH); | |
73 | int dqQuark = fSs.getQuarkRelativeAndAdd(fDiskQuark, Attributes.DRIVER_QUEUE); | |
74 | fDriverQueueAttrib = new TmfAttributePool(fSs, dqQuark, QueueType.PRIORITY); | |
75 | fSs.getQuarkRelativeAndAdd(fDiskQuark, Attributes.DRIVER_QUEUE_LENGTH); | |
76 | } | |
77 | ||
78 | /** | |
79 | * Set the human readable disk name of this device | |
80 | * | |
81 | * @param diskname | |
82 | * The human readable name of the disk | |
83 | */ | |
84 | public void setDiskName(String diskname) { | |
85 | try { | |
86 | fSs.modifyAttribute(fSs.getCurrentEndTime(), TmfStateValue.newValueString(diskname), fDiskQuark); | |
87 | } catch (StateValueTypeException | AttributeNotFoundException e) { | |
88 | Activator.getDefault().logError("Cannot set the diskname for disk " + diskname, e); //$NON-NLS-1$ | |
89 | } | |
90 | } | |
91 | ||
92 | /** | |
93 | * Return a request from the waiting queue starting at requested base sector | |
94 | * | |
95 | * @param sector | |
96 | * The sector where the requests starts | |
97 | * @return The request corresponding to this sector, or null if no request | |
98 | * available | |
99 | */ | |
100 | public @Nullable Request getWaitingRequest(Long sector) { | |
101 | Pair<Request, Integer> reqQuark = fWaitingQueue.get(sector); | |
102 | if (reqQuark == null) { | |
103 | return null; | |
104 | } | |
105 | return reqQuark.getFirst(); | |
106 | } | |
107 | ||
108 | /** | |
109 | * Removes the request starting at sector from the waiting queue | |
110 | * | |
111 | * @param ts | |
112 | * The timestamp at which to add this request | |
113 | * @param sector | |
114 | * The sector where the requests starts | |
115 | * @return The quark of the request that was removed or | |
116 | * {@link ITmfStateSystem.INVALID_ATTRIBUTE} if the request was not | |
117 | * present | |
118 | */ | |
119 | private int removeWaitingRequest(long ts, Long sector) { | |
120 | Pair<Request, Integer> reqQuark = fWaitingQueue.remove(sector); | |
121 | if (reqQuark == null) { | |
122 | return ITmfStateSystem.INVALID_ATTRIBUTE; | |
123 | } | |
124 | int slotQuark = reqQuark.getSecond(); | |
125 | fWaitingQueueAttrib.recycle(slotQuark, ts); | |
126 | return slotQuark; | |
127 | } | |
128 | ||
129 | /** | |
130 | * Add a request to the waiting queue. Also saves this request to the state | |
131 | * system | |
132 | * | |
133 | * @param ts | |
134 | * The timestamp at which to add this request | |
135 | * @param request | |
136 | * The requests to put | |
137 | * @return The quark of the request that has been added | |
138 | */ | |
139 | public int addWaitingRequest(long ts, Request request) { | |
140 | int slotQuark = insertInWaitingQueue(ts, request); | |
141 | updateQueuesLength(ts); | |
142 | return slotQuark; | |
143 | } | |
144 | ||
145 | private int insertInWaitingQueue(long ts, Request request) { | |
146 | ITmfStateValue statusState = request.getType() == IoOperationType.READ ? StateValues.READING_REQUEST_VALUE : StateValues.WRITING_REQUEST_VALUE; | |
147 | int slotQuark = fWaitingQueueAttrib.getAvailable(); | |
148 | ||
149 | /* Insertion in waiting queue */ | |
150 | try { | |
151 | fSs.modifyAttribute(ts, statusState, slotQuark); | |
152 | ||
153 | int currentRequestQuark = fSs.getQuarkRelativeAndAdd(slotQuark, Attributes.CURRENT_REQUEST); | |
154 | fSs.modifyAttribute(ts, TmfStateValue.newValueLong(request.getSector()), currentRequestQuark); | |
155 | ||
156 | int requestSizeQuark = fSs.getQuarkRelativeAndAdd(slotQuark, Attributes.REQUEST_SIZE); | |
157 | fSs.modifyAttribute(ts, TmfStateValue.newValueInt(request.getNrSector()), requestSizeQuark); | |
158 | ||
159 | int mergedInQuark = fSs.getQuarkRelativeAndAdd(slotQuark, Attributes.MERGED_IN); | |
160 | fSs.modifyAttribute(ts, TmfStateValue.nullValue(), mergedInQuark); | |
161 | } catch (StateValueTypeException | AttributeNotFoundException e) { | |
162 | Activator.getDefault().logError("Error inserting request", e); //$NON-NLS-1$ | |
163 | } | |
164 | fWaitingQueue.put(request.getSector(), new Pair<>(request, slotQuark)); | |
165 | ||
166 | return slotQuark; | |
167 | } | |
168 | ||
169 | /** | |
170 | * Update a request in the waiting queue. Also saves this request to the | |
171 | * state system. If the request did not exist previously, it will be added | |
172 | * to the queue. Since the sector may have been updated, the initialSector | |
173 | * parameters allows to say which was the original sector this request was | |
174 | * known for. | |
175 | * | |
176 | * @param ts | |
177 | * The timestamp at which to add this request | |
178 | * @param request | |
179 | * The requests to put | |
180 | * @param initialSector | |
181 | * The original base sector of this request. | |
182 | * @return The quark of the request that has been updated | |
183 | */ | |
184 | public int updateWaitingRequest(long ts, Request request, Long initialSector) { | |
185 | Pair<Request, Integer> reqQuark = fWaitingQueue.get(initialSector); | |
186 | if (reqQuark == null) { | |
187 | return addWaitingRequest(ts, request); | |
188 | } else if (initialSector != request.getSector()) { | |
189 | fWaitingQueue.remove(initialSector); | |
190 | fWaitingQueue.put(request.getSector(), reqQuark); | |
191 | } | |
192 | ||
193 | int slotQuark = reqQuark.getSecond(); | |
194 | ||
195 | /* | |
196 | * Update the sector, number of sectors and merged in request in waiting | |
197 | * queue | |
198 | */ | |
199 | try { | |
200 | int currentRequestQuark = fSs.getQuarkRelativeAndAdd(slotQuark, Attributes.CURRENT_REQUEST); | |
201 | fSs.modifyAttribute(ts, TmfStateValue.newValueLong(request.getSector()), currentRequestQuark); | |
202 | ||
203 | int requestSizeQuark = fSs.getQuarkRelativeAndAdd(slotQuark, Attributes.REQUEST_SIZE); | |
204 | fSs.modifyAttribute(ts, TmfStateValue.newValueInt(request.getNrSector()), requestSizeQuark); | |
205 | ||
206 | int mergedInQuark = fSs.getQuarkRelativeAndAdd(slotQuark, Attributes.MERGED_IN); | |
207 | fSs.modifyAttribute(ts, TmfStateValue.nullValue(), mergedInQuark); | |
208 | } catch (StateValueTypeException | AttributeNotFoundException e) { | |
209 | Activator.getDefault().logError("Error inserting request", e); //$NON-NLS-1$ | |
210 | } | |
211 | ||
212 | updateQueuesLength(ts); | |
213 | return slotQuark; | |
214 | } | |
215 | ||
216 | /** | |
217 | * Get the size of the waiting queue | |
218 | * | |
219 | * @return The waiting queue size | |
220 | */ | |
221 | public int getWaitingQueueSize() { | |
222 | return fWaitingQueue.size(); | |
223 | } | |
224 | ||
225 | /** | |
226 | * Return a request from the driver queue starting at requested base sector | |
227 | * | |
228 | * @param sector | |
229 | * The sector where the requests starts | |
230 | * @return The request corresponding to this sector, or null if no request | |
231 | * available | |
232 | */ | |
233 | public @Nullable Request getDriverRequest(Long sector) { | |
234 | Pair<Request, Integer> reqQuark = fDriverQueue.get(sector); | |
235 | if (reqQuark == null) { | |
236 | return null; | |
237 | } | |
238 | return reqQuark.getFirst(); | |
239 | } | |
240 | ||
241 | /** | |
242 | * Removes the request starting at sector from the driver queue | |
243 | * | |
244 | * @param ts | |
245 | * The timestamp at which to add this request | |
246 | * @param sector | |
247 | * The sector where the requests starts | |
248 | */ | |
249 | private void removeDriverRequest(long ts, Long sector) { | |
250 | Pair<Request, Integer> reqQuark = fDriverQueue.remove(sector); | |
251 | if (reqQuark == null) { | |
252 | return; | |
253 | } | |
254 | fDriverQueueAttrib.recycle(reqQuark.getSecond(), ts); | |
255 | } | |
256 | ||
257 | /** | |
258 | * Issues a request to the disk. This method removes the request from the | |
259 | * waiting queue if necessary and adds it to the driver queue. | |
260 | * | |
261 | * @param ts | |
262 | * The timestamp of this operation | |
263 | * @param request | |
264 | * The requests to put | |
265 | * @return The quark of the request that was just issued | |
266 | */ | |
267 | public int issueRequest(long ts, Request request) { | |
268 | /* Remove from waiting queue */ | |
269 | TmfStateValue issuedFromValue = TmfStateValue.nullValue(); | |
270 | int fromQuark = removeWaitingRequest(ts, request.getSector()); | |
271 | if (fromQuark != ITmfStateSystem.INVALID_ATTRIBUTE) { | |
272 | String reqQueueId = fSs.getAttributeName(fromQuark); | |
273 | issuedFromValue = TmfStateValue.newValueInt(Integer.parseInt(reqQueueId)); | |
274 | } | |
275 | ||
276 | ITmfStateValue statusState = request.getType() == IoOperationType.READ ? StateValues.READING_REQUEST_VALUE : StateValues.WRITING_REQUEST_VALUE; | |
277 | int slotQuark = fDriverQueueAttrib.getAvailable(); | |
278 | ||
279 | /* Insertion in driver queue */ | |
280 | try { | |
281 | fSs.modifyAttribute(ts, statusState, slotQuark); | |
282 | ||
283 | int currentRequestQuark = fSs.getQuarkRelativeAndAdd(slotQuark, Attributes.CURRENT_REQUEST); | |
284 | fSs.modifyAttribute(ts, TmfStateValue.newValueLong(request.getSector()), currentRequestQuark); | |
285 | ||
286 | int requestSizeQuark = fSs.getQuarkRelativeAndAdd(slotQuark, Attributes.REQUEST_SIZE); | |
287 | fSs.modifyAttribute(ts, TmfStateValue.newValueInt(request.getNrSector()), requestSizeQuark); | |
288 | ||
289 | int issuedFromQuark = fSs.getQuarkRelativeAndAdd(slotQuark, Attributes.ISSUED_FROM); | |
290 | fSs.modifyAttribute(ts, issuedFromValue, issuedFromQuark); | |
291 | } catch (StateValueTypeException | AttributeNotFoundException e) { | |
292 | Activator.getDefault().logError("Error issuing request", e); //$NON-NLS-1$ | |
293 | } | |
294 | ||
295 | fDriverQueue.put(request.getSector(), new Pair<>(request, slotQuark)); | |
296 | updateQueuesLength(ts); | |
297 | return slotQuark; | |
298 | } | |
299 | ||
300 | /** | |
301 | * Completes a request on the disk. It adds to the total of sectors read and | |
302 | * written on this disk. It also removes the request from the driver queue | |
303 | * if necessary. | |
304 | * | |
305 | * @param ts | |
306 | * The timestamp of this operation | |
307 | * @param request | |
308 | * The requests to put | |
309 | */ | |
310 | public void completeRequest(long ts, Request request) { | |
311 | /* Add the total number of sectors read or written */ | |
312 | try { | |
313 | switch (request.getType()) { | |
314 | case READ: | |
315 | int readQuark = fSs.getQuarkRelativeAndAdd(fDiskQuark, Attributes.SECTORS_READ); | |
316 | StateSystemBuilderUtils.incrementAttributeInt(fSs, ts, readQuark, request.getNrSector()); | |
317 | break; | |
318 | case WRITE: | |
319 | int writtenQuark = fSs.getQuarkRelativeAndAdd(fDiskQuark, Attributes.SECTORS_WRITTEN); | |
320 | StateSystemBuilderUtils.incrementAttributeInt(fSs, ts, writtenQuark, request.getNrSector()); | |
321 | break; | |
322 | default: | |
323 | throw new IllegalStateException("Complete request: the request cannot be other than READ or WRITE:" + request.getType()); //$NON-NLS-1$ | |
324 | } | |
325 | } catch (StateValueTypeException | AttributeNotFoundException e) { | |
326 | Activator.getDefault().logError("Error completing request", e); //$NON-NLS-1$ | |
327 | } | |
328 | ||
329 | /* Remove the request from driver queue */ | |
330 | removeDriverRequest(ts, request.getSector()); | |
331 | updateQueuesLength(ts); | |
332 | } | |
333 | ||
334 | /** | |
335 | * Merges 2 requests from the waiting queue. The second request will be | |
336 | * removed from the queue while the first one will be udpated | |
337 | * | |
338 | * @param ts | |
339 | * The timestamp of this operation | |
340 | * @param baseRequest | |
341 | * The base request that will be kept | |
342 | * @param mergedRequest | |
343 | * The merged request to be removed from the queue | |
344 | */ | |
345 | public void mergeRequests(long ts, Request baseRequest, Request mergedRequest) { | |
346 | int mergedQuark = removeWaitingRequest(ts, mergedRequest.getSector()); | |
347 | Long baseSector = baseRequest.getSector(); | |
348 | baseRequest.mergeRequest(mergedRequest); | |
349 | int baseQuark = updateWaitingRequest(ts, baseRequest, baseSector); | |
350 | if (mergedQuark != ITmfStateSystem.INVALID_ATTRIBUTE) { | |
351 | /* Add the merge information */ | |
352 | try { | |
353 | String reqQueueId = fSs.getAttributeName(baseQuark); | |
354 | ||
355 | int issuedFromQuark = fSs.getQuarkRelativeAndAdd(mergedQuark, Attributes.MERGED_IN); | |
356 | fSs.modifyAttribute(ts, TmfStateValue.newValueInt(Integer.parseInt(reqQueueId)), issuedFromQuark); | |
357 | } catch (StateValueTypeException | AttributeNotFoundException e) { | |
358 | Activator.getDefault().logError("Error adding the merged request information", e); //$NON-NLS-1$ | |
359 | } | |
360 | } | |
361 | updateQueuesLength(ts); | |
362 | } | |
363 | ||
364 | /** | |
365 | * Get the size of the driver queue | |
366 | * | |
367 | * @return The driver queue size | |
368 | */ | |
369 | public int getDriverQueueSize() { | |
370 | return fDriverQueue.size(); | |
371 | } | |
372 | ||
373 | /** | |
374 | * Get the quark corresponding to this disk | |
375 | * | |
376 | * @return The quark in the state system of this disk | |
377 | */ | |
378 | public int getDiskQuark() { | |
379 | return fDiskQuark; | |
380 | } | |
381 | ||
382 | private void updateQueuesLength(long ts) { | |
383 | try { | |
384 | int fDriverQueueLength = fSs.getQuarkRelativeAndAdd(fDiskQuark, Attributes.DRIVER_QUEUE_LENGTH); | |
385 | fSs.modifyAttribute(ts, TmfStateValue.newValueInt(getDriverQueueSize()), fDriverQueueLength); | |
386 | int fWaitinQueueLength = fSs.getQuarkRelativeAndAdd(fDiskQuark, Attributes.WAITING_QUEUE_LENGTH); | |
387 | fSs.modifyAttribute(ts, TmfStateValue.newValueInt(getWaitingQueueSize()), fWaitinQueueLength); | |
388 | } catch (StateValueTypeException | AttributeNotFoundException e) { | |
389 | Activator.getDefault().logError("Error updating queues lengths", e); //$NON-NLS-1$ | |
390 | } | |
391 | } | |
392 | ||
393 | // ---------------------------------------------------- | |
394 | // Object methods | |
395 | // ---------------------------------------------------- | |
396 | ||
397 | @Override | |
398 | public int hashCode() { | |
399 | return HF.newHasher().putInt(fDev).hash().asInt(); | |
400 | } | |
401 | ||
402 | @Override | |
403 | public boolean equals(@Nullable Object o) { | |
404 | if (o instanceof DiskWriteModel) { | |
405 | DiskWriteModel disk = (DiskWriteModel) o; | |
406 | if (fDev.equals(disk.fDev)) { | |
407 | return true; | |
408 | } | |
409 | } | |
410 | return false; | |
411 | } | |
412 | ||
413 | @Override | |
414 | public String toString() { | |
415 | return "Disk: [" + fDev + ',' + fDiskname + ']'; //$NON-NLS-1$ | |
416 | } | |
417 | ||
418 | } |