+ synchronizeTraces();
+ }
+
+ /*
+ * For all traces on the same host, if two or more specify different
+ * clock offsets, adjust their clock offset by the average of all of them.
+ *
+ * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=484620
+ */
+ Function<ITmfPropertiesProvider, @Nullable Long> offsetGetter = trace -> {
+ String offset = trace.getProperties().get(CLOCK_OFFSET_PROPERTY);
+ if (offset == null) {
+ return null;
+ }
+ try {
+ return Long.parseLong(offset);
+ } catch (NumberFormatException e) {
+ return null;
+ }
+ };
+
+ for (String host : tracesPerHost.keySet()) {
+ /*
+ * Only attempt to synchronize traces that provide a clock_offset
+ * property.
+ */
+ Collection<ITmfPropertiesProvider> tracesToSynchronize = tracesPerHost.get(host).stream()
+ .filter(trace -> trace instanceof ITmfPropertiesProvider)
+ .map(trace -> (ITmfPropertiesProvider) trace)
+ .filter(trace -> offsetGetter.apply(trace) != null)
+ .collect(Collectors.toList());
+
+ if (tracesToSynchronize.size() < 2) {
+ continue;
+ }
+
+ /* Only synchronize traces if they haven't previously been synchronized */
+ if (tracesToSynchronize.stream()
+ .map(trace -> ((ITmfTrace) trace).getTimestampTransform())
+ .anyMatch(transform -> !transform.equals(TmfTimestampTransform.IDENTITY))) {
+ continue;
+ }
+
+ /* Calculate the average of all clock offsets */
+ BigInteger sum = BigInteger.ZERO;
+ for (ITmfPropertiesProvider trace : tracesToSynchronize) {
+ long offset = checkNotNull(offsetGetter.apply(trace));
+ sum = sum.add(BigInteger.valueOf(offset));
+ }
+ long average = sum.divide(BigInteger.valueOf(tracesToSynchronize.size())).longValue();
+
+ if (average > CLOCK_OFFSET_THRESHOLD_NS) {
+ Activator.logWarning("Average clock correction (" + average + ") is higher than threshold of " + //$NON-NLS-1$ //$NON-NLS-2$
+ CLOCK_OFFSET_THRESHOLD_NS + " ns for experiment " + this.toString()); //$NON-NLS-1$
+ }
+
+ /*
+ * Apply the offset correction to all identified traces, but only if
+ * they do not already have an equivalent one (for example, closing
+ * and re-opening the same experiment should not retrigger building
+ * all supplementary files).
+ */
+ tracesToSynchronize.forEach(t -> {
+ long offset = checkNotNull(offsetGetter.apply(t));
+ long delta = average - offset;
+
+ ITmfTrace trace = (ITmfTrace) t;
+ ITmfTimestampTransform currentTransform = trace.getTimestampTransform();
+ ITmfTimestampTransform newTransform = TimestampTransformFactory.createWithOffset(delta);
+
+ if (!newTransform.equals(currentTransform)) {
+ TmfTraceManager.deleteSupplementaryFiles(trace);
+ trace.setTimestampTransform(newTransform);
+ }
+ });