/******************************************************************************* * Copyright (c) 2016 Ericsson * * 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.analysis.timing.core.segmentstore.statistics; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import java.util.function.Function; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.tracecompass.analysis.timing.core.segmentstore.ISegmentStoreProvider; import org.eclipse.tracecompass.analysis.timing.core.statistics.IStatistics; import org.eclipse.tracecompass.analysis.timing.core.statistics.Statistics; import org.eclipse.tracecompass.segmentstore.core.ISegment; import org.eclipse.tracecompass.segmentstore.core.ISegmentStore; import org.eclipse.tracecompass.tmf.core.analysis.IAnalysisModule; import org.eclipse.tracecompass.tmf.core.analysis.TmfAbstractAnalysisModule; import org.eclipse.tracecompass.tmf.core.exceptions.TmfAnalysisException; import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange; import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; import com.google.common.collect.ImmutableList; /** * Abstract analysis to build statistics data for a segment store * * @author Jean-Christian Kouame */ public abstract class AbstractSegmentStatisticsAnalysis extends TmfAbstractAnalysisModule { private static Function<ISegment, Long> FCT_LENGTH = s -> s.getLength(); private @Nullable ISegmentStoreProvider fSegmentStoreProviderModule; private @Nullable IStatistics<ISegment> fTotalStats; private Map<String, IStatistics<ISegment>> fPerSegmentTypeStats = new HashMap<>(); @Override protected Iterable<IAnalysisModule> getDependentAnalyses() { ITmfTrace trace = getTrace(); if (trace != null) { ISegmentStoreProvider provider = getSegmentProviderAnalysis(trace); fSegmentStoreProviderModule = provider; if (provider instanceof IAnalysisModule) { return ImmutableList.of((IAnalysisModule) provider); } } return super.getDependentAnalyses(); } @Override protected boolean executeAnalysis(IProgressMonitor monitor) throws TmfAnalysisException { if (monitor.isCanceled()) { return false; } IStatistics<ISegment> totalStats = getTotalStats(TmfTimeRange.ETERNITY.getStartTime().toNanos(), TmfTimeRange.ETERNITY.getEndTime().toNanos(), monitor); if (totalStats == null) { return false; } Map<String, IStatistics<ISegment>> perTypeStats = getPerTypeStats(TmfTimeRange.ETERNITY.getStartTime().toNanos(), TmfTimeRange.ETERNITY.getEndTime().toNanos(), monitor); fTotalStats = totalStats; fPerSegmentTypeStats = perTypeStats; return true; } private @Nullable IStatistics<ISegment> getTotalStats(long start, long end, IProgressMonitor monitor) { Iterable<@NonNull ISegment> store = getSegmentStore(start, end); if (store == null) { return null; } if (monitor.isCanceled()) { return null; } return calculateTotalManual(store, monitor); } /** * Get the total statistics for a specific range. If the range start is * TmfTimeRange.ETERNITY.getStartTime().toNanos() and the range end is * TmfTimeRange.ETERNITY.getEndTime().toNanos(), it will return the * statistics for the whole trace. * * @param start * The start time of the range * @param end * The end time of the range * @param monitor * The progress monitor * @return The total statistics, or null if segment store is not valid or if * the request is canceled * @since 1.2 * @deprecated use {@link #getStatsForRange(long, long, IProgressMonitor)} instead */ @Deprecated public @Nullable SegmentStoreStatistics getTotalStatsForRange(long start, long end, IProgressMonitor monitor) { IStatistics<@NonNull ISegment> stats = getStatsForRange(start, end, monitor); return (stats == null) ? null : new SegmentStoreStatistics(stats); } /** * Get the total statistics for a specific range. If the range start is * TmfTimeRange.ETERNITY.getStartTime().toNanos() and the range end is * TmfTimeRange.ETERNITY.getEndTime().toNanos(), it will return the * statistics for the whole trace. * * @param start * The start time of the range * @param end * The end time of the range * @param monitor * The progress monitor * @return The total statistics, or null if segment store is not valid or if * the request is canceled * @since 1.3 */ public @Nullable IStatistics<ISegment> getStatsForRange(long start, long end, IProgressMonitor monitor) { ITmfTrace trace = getTrace(); if (trace != null && (start == TmfTimeRange.ETERNITY.getStartTime().toNanos() && end == TmfTimeRange.ETERNITY.getEndTime().toNanos())) { waitForCompletion(); return getStatsTotal(); } return getTotalStats(start, end, monitor); } private Map<@NonNull String, org.eclipse.tracecompass.analysis.timing.core.statistics.IStatistics<ISegment>> getPerTypeStats(long start, long end, IProgressMonitor monitor) { Iterable<@NonNull ISegment> store = getSegmentStore(start, end); if (monitor.isCanceled() || store == null) { return Collections.EMPTY_MAP; } return calculateTotalPerType(store, monitor); } /** * Get the per segment type statistics for a specific range. If the range * start is TmfTimeRange.ETERNITY.getStartTime().toNanos() and the range end * is TmfTimeRange.ETERNITY.getEndTime().toNanos(), it will return the * statistics for the whole trace. * * @param start * The start time of the range * @param end * The end time of the range * @param monitor * The progress monitor * @return The per segment type statistics, or null if segment store is not * valid or if the request is canceled * @since 1.2 * @deprecated use {@link #getStatsPerTypeForRange(long, long, IProgressMonitor)} instead */ @Deprecated public @Nullable Map<String, SegmentStoreStatistics> getPerSegmentTypeStatsForRange(long start, long end, IProgressMonitor monitor) { Map<String, IStatistics<ISegment>> stats = getStatsPerTypeForRange(start, end, monitor); Map<String, SegmentStoreStatistics> map = new HashMap<>(); for (Entry<String, IStatistics<ISegment>> entry : stats.entrySet()) { map.put(entry.getKey(), new SegmentStoreStatistics(entry.getValue())); } return map; } /** * Get the per segment type statistics for a specific range. If the range * start is TmfTimeRange.ETERNITY.getStartTime().toNanos() and the range end * is TmfTimeRange.ETERNITY.getEndTime().toNanos(), it will return the * statistics for the whole trace. * * @param start * The start time of the range * @param end * The end time of the range * @param monitor * The progress monitor * @return The per segment type statistics, or null if segment store is not * valid or if the request is canceled * @since 1.3 */ public Map<@NonNull String, org.eclipse.tracecompass.analysis.timing.core.statistics.IStatistics<ISegment>> getStatsPerTypeForRange(long start, long end, IProgressMonitor monitor) { ITmfTrace trace = getTrace(); if (trace != null && (start == TmfTimeRange.ETERNITY.getStartTime().toNanos() && end == TmfTimeRange.ETERNITY.getEndTime().toNanos())) { waitForCompletion(); return getStatsPerType(); } return getPerTypeStats(start, end, monitor); } /** * Get the segment store from which we want the statistics * * @return The segment store */ private @Nullable Iterable<@NonNull ISegment> getSegmentStore(long start, long end) { ISegmentStoreProvider segmentStoreProviderModule = fSegmentStoreProviderModule; if (segmentStoreProviderModule == null) { return null; } if (segmentStoreProviderModule instanceof IAnalysisModule) { ((IAnalysisModule) segmentStoreProviderModule).waitForCompletion(); } ISegmentStore<@NonNull ISegment> segmentStore = segmentStoreProviderModule.getSegmentStore(); return segmentStore != null ? start != TmfTimeRange.ETERNITY.getStartTime().toNanos() || end != TmfTimeRange.ETERNITY.getEndTime().toNanos() ? (Iterable<@NonNull ISegment>) segmentStore.getIntersectingElements(start, end) : segmentStore : Collections.EMPTY_LIST; } private static @Nullable IStatistics<ISegment> calculateTotalManual(Iterable<@NonNull ISegment> segments, IProgressMonitor monitor) { IStatistics<ISegment> total = new Statistics<>(FCT_LENGTH); Iterator<@NonNull ISegment> iter = segments.iterator(); while (iter.hasNext()) { if (monitor.isCanceled()) { return null; } ISegment segment = iter.next(); total.update(segment); } return total; } private Map<@NonNull String, org.eclipse.tracecompass.analysis.timing.core.statistics.IStatistics<ISegment>> calculateTotalPerType(Iterable<ISegment> segments, IProgressMonitor monitor) { Map<String, IStatistics<ISegment>> perSegmentTypeStats = new HashMap<>(); Iterator<ISegment> iter = segments.iterator(); while (iter.hasNext()) { if (monitor.isCanceled()) { return Collections.EMPTY_MAP; } ISegment segment = iter.next(); String segmentType = getSegmentType(segment); if (segmentType != null) { IStatistics<ISegment> values = perSegmentTypeStats.get(segmentType); if (values == null) { values = new Statistics<>(FCT_LENGTH); } values.update(segment); perSegmentTypeStats.put(segmentType, values); } } return perSegmentTypeStats; } /** * Get the type of a segment. Statistics per type will use this type as a * key * * @param segment * the segment for which to get the type * @return The type of the segment */ protected abstract @Nullable String getSegmentType(ISegment segment); /** * Find the segment store provider used for this analysis * * @param trace * The active trace * * @return The segment store provider */ protected abstract @Nullable ISegmentStoreProvider getSegmentProviderAnalysis(ITmfTrace trace); @Override protected void canceling() { } /** * The total statistics * * @return the total statistics * @deprecated use {@link #getStatsTotal()} instead */ @Deprecated public @Nullable SegmentStoreStatistics getTotalStats() { IStatistics<@NonNull ISegment> totalStats = fTotalStats; return totalStats == null ? null : new SegmentStoreStatistics(totalStats); } /** * Get the statistics for the full segment store * * @return The complete statistics * @since 1.3 */ public @Nullable IStatistics<ISegment> getStatsTotal() { return fTotalStats; } /** * The per syscall statistics * * @return the per syscall statistics * @deprecated use {@link #getStatsPerType()} instead */ @Deprecated public @Nullable Map<String, SegmentStoreStatistics> getPerSegmentTypeStats() { Map<String, SegmentStoreStatistics> map = new HashMap<>(); for (Entry<String, IStatistics<ISegment>> entry : fPerSegmentTypeStats.entrySet()) { map.put(entry.getKey(), new SegmentStoreStatistics(entry.getValue())); } return map; } /** * Get the statistics for each type of segment in this segment store * * @return the map of statistics per type * @since 1.3 */ public Map<String, IStatistics<ISegment>> getStatsPerType() { return fPerSegmentTypeStats; } }