/******************************************************************************* * Copyright (c) 2013 É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 * * Contributors: * Geneviève Bastien - Initial implementation and API *******************************************************************************/ package fr.inria.linuxtools.tmf.core.event.matching; import java.util.Collection; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import fr.inria.linuxtools.tmf.core.event.ITmfEvent; import fr.inria.linuxtools.tmf.core.trace.ITmfTrace; /** * This class matches events typically network-style, ie. where some events are * 'send' events and the other 'receive' events or out/in events * * @author Geneviève Bastien * @since 3.0 */ public class TmfNetworkEventMatching extends TmfEventMatching { /** * Hashtables for unmatches incoming events */ private final Map<ITmfTrace, Map<List<Object>, ITmfEvent>> fUnmatchedIn = new LinkedHashMap<>(); /** * Hashtables for unmatches outgoing events */ private final Map<ITmfTrace, Map<List<Object>, ITmfEvent>> fUnmatchedOut = new LinkedHashMap<>(); /** * Enum for in and out types */ public enum Direction { /** * The event is a 'receive' type of event */ IN, /** * The event is a 'send' type of event */ OUT, } /** * Constructor with multiple traces and match processing object * * @param traces * The set of traces for which to match events */ public TmfNetworkEventMatching(Collection<ITmfTrace> traces) { this(traces, new TmfEventMatches()); } /** * Constructor with multiple traces and match processing object * * @param traces * The set of traces for which to match events * @param tmfEventMatches * The match processing class */ public TmfNetworkEventMatching(Collection<ITmfTrace> traces, IMatchProcessingUnit tmfEventMatches) { super(traces, tmfEventMatches); } /** * Method that initializes any data structure for the event matching */ @Override public void initMatching() { // Initialize the matching infrastructure (unmatched event lists) fUnmatchedIn.clear(); fUnmatchedOut.clear(); for (ITmfTrace trace : getTraces()) { fUnmatchedIn.put(trace, new HashMap<List<Object>, ITmfEvent>()); fUnmatchedOut.put(trace, new HashMap<List<Object>, ITmfEvent>()); } super.initMatching(); } /** * Function that counts the events in a hashtable. * * @param tbl * The table to count events for * @return The number of events */ protected int countEvents(Map<List<Object>, ITmfEvent> tbl) { return tbl.size(); } @Override protected MatchingType getMatchingType() { return MatchingType.NETWORK; } @Override public void matchEvent(ITmfEvent event, ITmfTrace trace) { if (!(getEventDefinition(event.getTrace()) instanceof ITmfNetworkMatchDefinition)) { return; } ITmfNetworkMatchDefinition def = (ITmfNetworkMatchDefinition) getEventDefinition(event.getTrace()); Direction evType = def.getDirection(event); if (evType == null) { return; } /* Get the event's unique fields */ List<Object> eventKey = def.getUniqueField(event); Map<ITmfTrace, Map<List<Object>, ITmfEvent>> unmatchedTbl, companionTbl; /* Point to the appropriate table */ switch (evType) { case IN: unmatchedTbl = fUnmatchedIn; companionTbl = fUnmatchedOut; break; case OUT: unmatchedTbl = fUnmatchedOut; companionTbl = fUnmatchedIn; break; default: return; } boolean found = false; TmfEventDependency dep = null; /* Search for the event in the companion table */ for (Map<List<Object>, ITmfEvent> map : companionTbl.values()) { if (map.containsKey(eventKey)) { found = true; ITmfEvent companionEvent = map.get(eventKey); /* Remove the element from the companion table */ map.remove(eventKey); /* Create the dependency object */ switch (evType) { case IN: dep = new TmfEventDependency(companionEvent, event); break; case OUT: dep = new TmfEventDependency(event, companionEvent); break; default: break; } } } /* * If no companion was found, add the event to the appropriate unMatched * lists */ if (found) { getProcessingUnit().addMatch(dep); } else { /* * If an event is already associated with this key, do not add it * again, we keep the first event chronologically, so if its match * is eventually found, it is associated with the first send or * receive event. At best, it is a good guess, at worst, the match * will be too far off to be accurate. Too bad! * * TODO: maybe instead of just one event, we could have a list of * events as value for the unmatched table. Not necessary right now * though */ if (!unmatchedTbl.get(trace).containsKey(eventKey)) { unmatchedTbl.get(trace).put(eventKey, event); } } } /** * Prints stats from the matching * * @return string of statistics */ @SuppressWarnings("nls") @Override public String toString() { final String cr = System.getProperty("line.separator"); StringBuilder b = new StringBuilder(); b.append(getProcessingUnit()); int i = 0; for (ITmfTrace trace : getTraces()) { b.append("Trace " + i++ + ":" + cr + " " + countEvents(fUnmatchedIn.get(trace)) + " unmatched incoming events" + cr + " " + countEvents(fUnmatchedOut.get(trace)) + " unmatched outgoing events" + cr); } return b.toString(); } }