/******************************************************************************* * Copyright (c) 2014 É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 org.eclipse.tracecompass.internal.tmf.core.synchronization.graph; import java.math.BigDecimal; import java.util.List; import java.util.SortedSet; import java.util.TreeSet; import org.eclipse.tracecompass.internal.tmf.core.synchronization.ITmfTimestampTransformInvertible; import org.eclipse.tracecompass.tmf.core.synchronization.ITmfTimestampTransform; import org.eclipse.tracecompass.tmf.core.synchronization.TimestampTransformFactory; /** * Implements a tree to calculate the synchronization between hosts * * TODO: This minimal implementation does not take into account the accuracy of * the synchronization or the number of hops between 2 traces. A great * improvement would be to implement Masoume Jabbarifar's minimal spanning tree * algorithm to select reference trace(s) and optimal path to each node of the * tree. * * @author Geneviève Bastien */ public class SyncSpanningTree { private final SyncGraph<String, ITmfTimestampTransform> fSyncGraph; /* * Using a TreeSet here to make sure the order of the hosts, and thus the * reference node, is predictable, mostly for unit tests. */ private SortedSet<String> fHosts = new TreeSet<>(); private final String fRootNode; /** * Default constructor */ public SyncSpanningTree() { this(null); } /** * Constructor with a root node. * * @param rootNode * Root node that will be used. */ public SyncSpanningTree(String rootNode) { fSyncGraph = new SyncGraph<>(); fRootNode = rootNode; } /** * Add a synchronization formula between hostFrom and hostTo with a given * accuracy * * @param hostFrom * Host from which the transform applies * @param hostTo * Host to which the transform applies * @param transform * The timestamp transform * @param accuracy * The accuracy of the synchronization between hostFrom and * hostTo */ public void addSynchronization(String hostFrom, String hostTo, ITmfTimestampTransform transform, BigDecimal accuracy) { fHosts.add(hostFrom); fHosts.add(hostTo); fSyncGraph.addEdge(hostFrom, hostTo, transform); if (transform instanceof ITmfTimestampTransformInvertible) { fSyncGraph.addEdge(hostTo, hostFrom, ((ITmfTimestampTransformInvertible) transform).inverse()); } } /** * Get the timestamp transform to a host * * FIXME: This might not work in situations where we have disjoint graphs * since we only calculate 1 root node and each tree has its own root. When * implementing the algorithm with minimal spanning tree, we will solve this * problem. * * @param host * The host to reach * @return The timestamp transform to host */ public ITmfTimestampTransform getTimestampTransform(String host) { ITmfTimestampTransform result = TimestampTransformFactory.getDefaultTransform(); String rootNode = getRootNode(); /* * Compute the path from reference node to the given host id */ if (rootNode != null) { List<Edge<String, ITmfTimestampTransform>> path = fSyncGraph.path(rootNode, host); /* * Compute the resulting transform by chaining each transforms on * the path. */ for (Edge<String, ITmfTimestampTransform> edge : path) { result = result.composeWith(edge.getLabel()); } } return result; } private String getRootNode() { /** * Get the root node from which all other paths will be calculated. For * now, we take the first node alphabetically if the rootNode was not * set. */ if (fHosts.size() == 0) { return null; } if (fRootNode == null) { return fHosts.first(); } return fRootNode; } /** * Check if this multi-host synchronization tree is connected, ie all nodes * have a synchronization path to a reference node. * * @return true if the tree is connected, false otherwise */ public boolean isConnected() { return fSyncGraph.isConnected(); } }