/******************************************************************************* * Copyright (c) 2016 École Polytechnique de Montréal * * 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 *******************************************************************************/ package org.eclipse.tracecompass.internal.analysis.os.linux.core.inputoutput; import java.util.HashMap; import java.util.Map; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.tracecompass.analysis.os.linux.core.inputoutput.Attributes; import org.eclipse.tracecompass.analysis.os.linux.core.inputoutput.Disk; import org.eclipse.tracecompass.analysis.os.linux.core.inputoutput.IoOperationType; import org.eclipse.tracecompass.analysis.os.linux.core.inputoutput.StateValues; import org.eclipse.tracecompass.internal.analysis.os.linux.core.Activator; import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem; import org.eclipse.tracecompass.statesystem.core.ITmfStateSystemBuilder; import org.eclipse.tracecompass.statesystem.core.StateSystemBuilderUtils; import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException; import org.eclipse.tracecompass.statesystem.core.exceptions.StateValueTypeException; import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue; import org.eclipse.tracecompass.statesystem.core.statevalue.TmfStateValue; import org.eclipse.tracecompass.tmf.core.statesystem.TmfAttributePool; import org.eclipse.tracecompass.tmf.core.statesystem.TmfAttributePool.QueueType; import org.eclipse.tracecompass.tmf.core.util.Pair; /** * Class that represents a disk on a system. This class provides operation to * save the analysis data in a state system. * * @author Houssem Daoud * @since 2.0 */ public class DiskWriteModel extends Disk { private final Map<Long, Pair<Request, Integer>> fDriverQueue = new HashMap<>(); private final Map<Long, Pair<Request, Integer>> fWaitingQueue = new HashMap<>(); private final ITmfStateSystemBuilder fSs; private final TmfAttributePool fWaitingQueueAttrib; private final TmfAttributePool fDriverQueueAttrib; /** * Constructor * * @param dev * The device number of the disk * @param ss * The state system this disk will be saved to */ public DiskWriteModel(Integer dev, ITmfStateSystemBuilder ss) { super(dev, ss, ss.getQuarkAbsoluteAndAdd(Attributes.DISKS, String.valueOf(dev))); fSs = ss; int diskQuark = getQuark(); /* Initialize the state system for this disk */ fSs.getQuarkRelativeAndAdd(diskQuark, Attributes.SECTORS_WRITTEN); fSs.getQuarkRelativeAndAdd(diskQuark, Attributes.SECTORS_READ); int wqQuark = fSs.getQuarkRelativeAndAdd(diskQuark, Attributes.WAITING_QUEUE); fWaitingQueueAttrib = new TmfAttributePool(fSs, wqQuark, QueueType.PRIORITY); fSs.getQuarkRelativeAndAdd(diskQuark, Attributes.WAITING_QUEUE_LENGTH); int dqQuark = fSs.getQuarkRelativeAndAdd(diskQuark, Attributes.DRIVER_QUEUE); fDriverQueueAttrib = new TmfAttributePool(fSs, dqQuark, QueueType.PRIORITY); fSs.getQuarkRelativeAndAdd(diskQuark, Attributes.DRIVER_QUEUE_LENGTH); } @Override public void setDiskName(String diskname) { super.setDiskName(diskname); try { fSs.modifyAttribute(fSs.getCurrentEndTime(), TmfStateValue.newValueString(diskname), getQuark()); } catch (StateValueTypeException e) { Activator.getDefault().logError("Cannot set the diskname for disk " + diskname, e); //$NON-NLS-1$ } } /** * Return a request from the waiting queue starting at requested base sector * * @param sector * The sector where the requests starts * @return The request corresponding to this sector, or null if no request * available */ public @Nullable Request getWaitingRequest(Long sector) { Pair<Request, Integer> reqQuark = fWaitingQueue.get(sector); if (reqQuark == null) { return null; } return reqQuark.getFirst(); } /** * Removes the request starting at sector from the waiting queue * * @param ts * The timestamp at which to add this request * @param sector * The sector where the requests starts * @return The quark of the request that was removed or * {@link ITmfStateSystem.INVALID_ATTRIBUTE} if the request was not * present */ private int removeWaitingRequest(long ts, Long sector) { Pair<Request, Integer> reqQuark = fWaitingQueue.remove(sector); if (reqQuark == null) { return ITmfStateSystem.INVALID_ATTRIBUTE; } int slotQuark = reqQuark.getSecond(); fWaitingQueueAttrib.recycle(slotQuark, ts); return slotQuark; } /** * Add a request to the waiting queue. Also saves this request to the state * system * * @param ts * The timestamp at which to add this request * @param request * The requests to put * @return The quark of the request that has been added */ public int addWaitingRequest(long ts, Request request) { int slotQuark = insertInWaitingQueue(ts, request); updateQueuesLength(ts); return slotQuark; } private int insertInWaitingQueue(long ts, Request request) { ITmfStateValue statusState = request.getType() == IoOperationType.READ ? StateValues.READING_REQUEST_VALUE : StateValues.WRITING_REQUEST_VALUE; int slotQuark = fWaitingQueueAttrib.getAvailable(); /* Insertion in waiting queue */ try { fSs.modifyAttribute(ts, statusState, slotQuark); int currentRequestQuark = fSs.getQuarkRelativeAndAdd(slotQuark, Attributes.CURRENT_REQUEST); fSs.modifyAttribute(ts, TmfStateValue.newValueLong(request.getSector()), currentRequestQuark); int requestSizeQuark = fSs.getQuarkRelativeAndAdd(slotQuark, Attributes.REQUEST_SIZE); fSs.modifyAttribute(ts, TmfStateValue.newValueInt(request.getNrSector()), requestSizeQuark); int mergedInQuark = fSs.getQuarkRelativeAndAdd(slotQuark, Attributes.MERGED_IN); fSs.modifyAttribute(ts, TmfStateValue.nullValue(), mergedInQuark); } catch (StateValueTypeException e) { Activator.getDefault().logError("Error inserting request", e); //$NON-NLS-1$ } fWaitingQueue.put(request.getSector(), new Pair<>(request, slotQuark)); return slotQuark; } /** * Update a request in the waiting queue. Also saves this request to the * state system. If the request did not exist previously, it will be added * to the queue. Since the sector may have been updated, the initialSector * parameters allows to say which was the original sector this request was * known for. * * @param ts * The timestamp at which to add this request * @param request * The requests to put * @param initialSector * The original base sector of this request. * @return The quark of the request that has been updated */ public int updateWaitingRequest(long ts, Request request, Long initialSector) { Pair<Request, Integer> reqQuark = fWaitingQueue.get(initialSector); if (reqQuark == null) { return addWaitingRequest(ts, request); } else if (!initialSector.equals(request.getSector())) { fWaitingQueue.remove(initialSector); fWaitingQueue.put(request.getSector(), reqQuark); } int slotQuark = reqQuark.getSecond(); /* * Update the sector, number of sectors and merged in request in waiting * queue */ try { int currentRequestQuark = fSs.getQuarkRelativeAndAdd(slotQuark, Attributes.CURRENT_REQUEST); fSs.modifyAttribute(ts, TmfStateValue.newValueLong(request.getSector()), currentRequestQuark); int requestSizeQuark = fSs.getQuarkRelativeAndAdd(slotQuark, Attributes.REQUEST_SIZE); fSs.modifyAttribute(ts, TmfStateValue.newValueInt(request.getNrSector()), requestSizeQuark); int mergedInQuark = fSs.getQuarkRelativeAndAdd(slotQuark, Attributes.MERGED_IN); fSs.modifyAttribute(ts, TmfStateValue.nullValue(), mergedInQuark); } catch (StateValueTypeException e) { Activator.getDefault().logError("Error inserting request", e); //$NON-NLS-1$ } updateQueuesLength(ts); return slotQuark; } /** * Get the size of the waiting queue * * @return The waiting queue size */ public int getWaitingQueueSize() { return fWaitingQueue.size(); } /** * Return a request from the driver queue starting at requested base sector * * @param sector * The sector where the requests starts * @return The request corresponding to this sector, or null if no request * available */ public @Nullable Request getDriverRequest(Long sector) { Pair<Request, Integer> reqQuark = fDriverQueue.get(sector); if (reqQuark == null) { return null; } return reqQuark.getFirst(); } /** * Removes the request starting at sector from the driver queue * * @param ts * The timestamp at which to add this request * @param sector * The sector where the requests starts */ private void removeDriverRequest(long ts, Long sector) { Pair<Request, Integer> reqQuark = fDriverQueue.remove(sector); if (reqQuark == null) { return; } fDriverQueueAttrib.recycle(reqQuark.getSecond(), ts); } /** * Issues a request to the disk. This method removes the request from the * waiting queue if necessary and adds it to the driver queue. * * @param ts * The timestamp of this operation * @param request * The requests to put * @return The quark of the request that was just issued */ public int issueRequest(long ts, Request request) { /* Remove from waiting queue */ TmfStateValue issuedFromValue = TmfStateValue.nullValue(); int fromQuark = removeWaitingRequest(ts, request.getSector()); if (fromQuark != ITmfStateSystem.INVALID_ATTRIBUTE) { String reqQueueId = fSs.getAttributeName(fromQuark); issuedFromValue = TmfStateValue.newValueInt(Integer.parseInt(reqQueueId)); } ITmfStateValue statusState = request.getType() == IoOperationType.READ ? StateValues.READING_REQUEST_VALUE : StateValues.WRITING_REQUEST_VALUE; int slotQuark = fDriverQueueAttrib.getAvailable(); /* Insertion in driver queue */ try { fSs.modifyAttribute(ts, statusState, slotQuark); int currentRequestQuark = fSs.getQuarkRelativeAndAdd(slotQuark, Attributes.CURRENT_REQUEST); fSs.modifyAttribute(ts, TmfStateValue.newValueLong(request.getSector()), currentRequestQuark); int requestSizeQuark = fSs.getQuarkRelativeAndAdd(slotQuark, Attributes.REQUEST_SIZE); fSs.modifyAttribute(ts, TmfStateValue.newValueInt(request.getNrSector()), requestSizeQuark); int issuedFromQuark = fSs.getQuarkRelativeAndAdd(slotQuark, Attributes.ISSUED_FROM); fSs.modifyAttribute(ts, issuedFromValue, issuedFromQuark); } catch (StateValueTypeException e) { Activator.getDefault().logError("Error issuing request", e); //$NON-NLS-1$ } fDriverQueue.put(request.getSector(), new Pair<>(request, slotQuark)); updateQueuesLength(ts); return slotQuark; } /** * Completes a request on the disk. It adds to the total of sectors read and * written on this disk. It also removes the request from the driver queue * if necessary. * * @param ts * The timestamp of this operation * @param request * The requests to put */ public void completeRequest(long ts, Request request) { /* Add the total number of sectors read or written */ try { switch (request.getType()) { case READ: int readQuark = fSs.getQuarkRelativeAndAdd(getQuark(), Attributes.SECTORS_READ); StateSystemBuilderUtils.incrementAttributeInt(fSs, ts, readQuark, request.getNrSector()); break; case WRITE: int writtenQuark = fSs.getQuarkRelativeAndAdd(getQuark(), Attributes.SECTORS_WRITTEN); StateSystemBuilderUtils.incrementAttributeInt(fSs, ts, writtenQuark, request.getNrSector()); break; default: throw new IllegalStateException("Complete request: the request cannot be other than READ or WRITE:" + request.getType()); //$NON-NLS-1$ } } catch (StateValueTypeException | AttributeNotFoundException e) { Activator.getDefault().logError("Error completing request", e); //$NON-NLS-1$ } /* Remove the request from driver queue */ removeDriverRequest(ts, request.getSector()); updateQueuesLength(ts); } /** * Merges 2 requests from the waiting queue. The second request will be * removed from the queue while the first one will be udpated * * @param ts * The timestamp of this operation * @param baseRequest * The base request that will be kept * @param mergedRequest * The merged request to be removed from the queue */ public void mergeRequests(long ts, Request baseRequest, Request mergedRequest) { int mergedQuark = removeWaitingRequest(ts, mergedRequest.getSector()); Long baseSector = baseRequest.getSector(); baseRequest.mergeRequest(mergedRequest); int baseQuark = updateWaitingRequest(ts, baseRequest, baseSector); if (mergedQuark != ITmfStateSystem.INVALID_ATTRIBUTE) { /* Add the merge information */ try { String reqQueueId = fSs.getAttributeName(baseQuark); int issuedFromQuark = fSs.getQuarkRelativeAndAdd(mergedQuark, Attributes.MERGED_IN); fSs.modifyAttribute(ts, TmfStateValue.newValueInt(Integer.parseInt(reqQueueId)), issuedFromQuark); } catch (StateValueTypeException e) { Activator.getDefault().logError("Error adding the merged request information", e); //$NON-NLS-1$ } } updateQueuesLength(ts); } /** * Get the size of the driver queue * * @return The driver queue size */ public int getDriverQueueSize() { return fDriverQueue.size(); } private void updateQueuesLength(long ts) { try { int fDriverQueueLength = fSs.getQuarkRelativeAndAdd(getQuark(), Attributes.DRIVER_QUEUE_LENGTH); fSs.modifyAttribute(ts, TmfStateValue.newValueInt(getDriverQueueSize()), fDriverQueueLength); int fWaitinQueueLength = fSs.getQuarkRelativeAndAdd(getQuark(), Attributes.WAITING_QUEUE_LENGTH); fSs.modifyAttribute(ts, TmfStateValue.newValueInt(getWaitingQueueSize()), fWaitinQueueLength); } catch (StateValueTypeException e) { Activator.getDefault().logError("Error updating queues lengths", e); //$NON-NLS-1$ } } }