| /******************************************************************************* |
| * Copyright (c) 2019 É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.incubator.internal.scripting.core.analysis; |
| |
| import java.io.IOException; |
| import java.nio.file.FileVisitResult; |
| import java.nio.file.Files; |
| import java.nio.file.Path; |
| import java.nio.file.Paths; |
| import java.nio.file.SimpleFileVisitor; |
| import java.nio.file.attribute.BasicFileAttributes; |
| import java.util.HashMap; |
| import java.util.Map; |
| import java.util.Objects; |
| |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.jdt.annotation.Nullable; |
| import org.eclipse.tracecompass.incubator.internal.scripting.core.Activator; |
| import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem; |
| import org.eclipse.tracecompass.statesystem.core.ITmfStateSystemBuilder; |
| import org.eclipse.tracecompass.statesystem.core.StateSystemFactory; |
| import org.eclipse.tracecompass.statesystem.core.backend.IStateHistoryBackend; |
| import org.eclipse.tracecompass.statesystem.core.backend.StateHistoryBackendFactory; |
| import org.eclipse.tracecompass.tmf.core.analysis.TmfAbstractAnalysisModule; |
| import org.eclipse.tracecompass.tmf.core.exceptions.TmfAnalysisException; |
| import org.eclipse.tracecompass.tmf.core.statesystem.ITmfAnalysisModuleWithStateSystems; |
| import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; |
| import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager; |
| |
| /** |
| * An analysis class to encapsulate all scripted analyses and views, so that |
| * they are part of Trace Compass and views API. |
| * |
| * The state systems generated by this analysis are to be handled and built by |
| * the callers of this analysis, this only provides the state systems. It is the |
| * builder's responsibility to close them at appropriate time by calling |
| * {@link ITmfStateSystemBuilder#closeHistory(long)} method at the end of |
| * reading the trace. |
| * |
| * @author Geneviève Bastien |
| */ |
| public class TmfScriptAnalysis extends TmfAbstractAnalysisModule implements ITmfAnalysisModuleWithStateSystems { |
| |
| /** |
| * ID of this analysis |
| */ |
| public static final String ID = "org.eclipse.tracecompass.incubator.scripting.analysis"; //$NON-NLS-1$ |
| private static final String SUPP_FOLDER = "scripts"; //$NON-NLS-1$ |
| private static final String STATE_SYSTEM_FOLDER = "stateSystem"; //$NON-NLS-1$ |
| /* |
| * Size of the blocking queue to use when building a state history |
| */ |
| private final int QUEUE_SIZE = 10000; |
| |
| // Save the state systems |
| private final Map<String, ITmfStateSystem> fStateSystems = new HashMap<>(); |
| |
| private Path getStateSystemFolder() { |
| // Get the supplementary files associated with this analysis |
| ITmfTrace trace = Objects.requireNonNull(getTrace()); |
| |
| /* All state systems should be in a supplementary folder */ |
| String suppDir = TmfTraceManager.getSupplementaryFileDir(trace); |
| return Objects.requireNonNull(Paths.get(suppDir, SUPP_FOLDER, STATE_SYSTEM_FOLDER)); |
| } |
| |
| @Override |
| protected boolean executeAnalysis(IProgressMonitor monitor) throws TmfAnalysisException { |
| |
| // Read the state systems of this analysis |
| Path suppFolder = getStateSystemFolder(); |
| if (Files.exists(suppFolder)) { |
| try { |
| Files.walkFileTree(suppFolder, new SimpleFileVisitor<Path>() { |
| |
| @Override |
| public FileVisitResult visitFile(Path file, @Nullable BasicFileAttributes attrs) throws IOException { |
| try { |
| |
| String ssid = String.valueOf(file.getFileName()); |
| IStateHistoryBackend backend = StateHistoryBackendFactory.createHistoryTreeBackendExistingFile( |
| ssid, Objects.requireNonNull(file.toFile()), 1); |
| ITmfStateSystem stateSystem = StateSystemFactory.newStateSystem(backend, false); |
| fStateSystems.put(ssid, stateSystem); |
| } catch (IOException e) { |
| /* |
| * This may happen if the file is not a state |
| * system. A script may save other files in the |
| * supplementary file, like segment stores or |
| * internal files. |
| * |
| * TODO: Support a version ID? |
| */ |
| Activator.getInstance().logWarning("Error opening a file that should contain a state system: " + file.getFileName(), e); //$NON-NLS-1$ |
| } |
| return FileVisitResult.CONTINUE; |
| } |
| |
| }); |
| } catch (IOException e) { |
| Activator.getInstance().logWarning("Uncaught error opening state system files", e); //$NON-NLS-1$ |
| } |
| } |
| |
| return true; |
| } |
| |
| @Override |
| protected void canceling() { |
| // Nothing to do |
| } |
| |
| @Override |
| public @Nullable ITmfStateSystem getStateSystem(String id) { |
| return fStateSystems.get(id); |
| } |
| |
| /** |
| * Get a state system, using an existing one if already available |
| * |
| * @param id |
| * The ID of the state system to get |
| * @param useExisting |
| * Whether to use a pre-existing state system with that name or |
| * create a new one |
| * @return A new state system |
| */ |
| public @Nullable ITmfStateSystem getStateSystem(String id, boolean useExisting) { |
| ITmfStateSystem ss = fStateSystems.get(id); |
| if (ss != null && useExisting) { |
| return ss; |
| } |
| // Create a state system with that ID |
| try { |
| ITmfTrace trace = Objects.requireNonNull(getTrace()); |
| Path ssFolder = getStateSystemFolder(); |
| Files.createDirectories(ssFolder); |
| Path ssFile = Paths.get(ssFolder.toString(), id); |
| IStateHistoryBackend backend = StateHistoryBackendFactory.createHistoryTreeBackendNewFile( |
| id, Objects.requireNonNull(ssFile.toFile()), 1, trace.getStartTime().toNanos(), QUEUE_SIZE); |
| ITmfStateSystemBuilder stateSystem = StateSystemFactory.newStateSystem(backend); |
| fStateSystems.put(id, stateSystem); |
| return stateSystem; |
| } catch (IOException e) { |
| Activator.getInstance().logError("Error creating the state system", e); //$NON-NLS-1$ |
| } |
| return ss; |
| } |
| |
| @Override |
| public Iterable<ITmfStateSystem> getStateSystems() { |
| return fStateSystems.values(); |
| } |
| |
| @Override |
| public boolean waitForInitialization() { |
| // Wait for state systems to be read. Since the analysis is to just |
| // create the state systems, wait for the analysis to be completed |
| |
| // FIXME: When the script analyses support segment stores as well, maybe |
| // this will need to change |
| return waitForCompletion(); |
| } |
| |
| } |