/*****************************************************************************
* Copyright (c) 2009, 2010 g-Eclipse Consortium
* 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
*
* Initial development of the original code was made for the
* g-Eclipse project founded by European Union
* project number: FP6-IST-034327 http://www.geclipse.eu/
*
* Contributors:
* Thomas Koeckerbauer MNM-Team, LMU Munich - initial API and implementation
* Christof Klausecker MNM-Team, LMU Munich - improved event support
*****************************************************************************/
package eu.geclipse.eventgraph.tracereader.otf;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.ui.views.properties.IPropertyDescriptor;
import org.eclipse.ui.views.properties.PropertyDescriptor;
import eu.geclipse.eventgraph.tracereader.otf.preferences.PreferenceConstants;
import eu.geclipse.eventgraph.tracereader.otf.util.Node;
import eu.geclipse.traceview.ILamportProcess;
import eu.geclipse.traceview.ILamportTrace;
import eu.geclipse.traceview.IPhysicalEvent;
import eu.geclipse.traceview.IPhysicalTrace;
import eu.geclipse.traceview.IProcess;
import eu.geclipse.traceview.ITrace;
import eu.geclipse.traceview.ITraceReader;
import eu.geclipse.traceview.utils.AbstractTraceFileCache;
import eu.geclipse.traceview.utils.ClockCalculator;
/**
* Reader for the Open Trace Format (OTF)
*/
@SuppressWarnings("boxing")
public class OTFReader extends AbstractTraceFileCache implements IPhysicalTrace, ILamportTrace, ITraceReader {
private static final String PROP_TRACE_VERSION = "OTF.TraceVersion"; //$NON-NLS-1$
private static final String PROP_TRACE_CODENAME= "OTF.TraceCodename"; //$NON-NLS-1$
private static final String PROP_TRACE_CREATOR= "OTF.TraceCreator"; //$NON-NLS-1$
private static final String PROP_TRACE_PROCESSGROUPS= "OTF.TraceProcessGroups"; //$NON-NLS-1$
private static final String PROP_TRACE_FUNCTIONGROUPS= "OTF.TraceFunctionGroups"; //$NON-NLS-1$
private static IPropertyDescriptor[] otfTracePropertyDescriptors = new IPropertyDescriptor[]{
new PropertyDescriptor( PROP_TRACE_VERSION, "Version" ), //$NON-NLS-1$
new PropertyDescriptor( PROP_TRACE_CODENAME, "Codename" ), //$NON-NLS-1$
new PropertyDescriptor( PROP_TRACE_CREATOR, "Creator" ), //$NON-NLS-1$
new PropertyDescriptor( PROP_TRACE_PROCESSGROUPS, "Process Groups" ), //$NON-NLS-1$
new PropertyDescriptor( PROP_TRACE_FUNCTIONGROUPS, "Function Groups" ), //$NON-NLS-1$
};
private BufferedReader input;
private int numProcs = 0;
// Mapping of OTF Ids
private Map<Integer, List<Integer>> streamMap;
private Map<Integer, Integer> processIdMap;
private Map<Integer, Integer>[] entered;
private Process[] processes;
private String filenameBase;
private String filename;
private OTFUtils otfUtils = new OTFUtils();
private OTFDefinitionReader otfDefinitionReader;
private Node[] nodes;
/**
* Creates a new Trace Reader
*/
public OTFReader() {
this.streamMap = new HashMap<Integer, List<Integer>>();
this.processIdMap = new HashMap<Integer, Integer>();
this.processIdMap.put( 0, -1 ); // OTFs 0 is Trace Viewers -1
}
/*
* (non-Javadoc)
* @see eu.geclipse.traceview.utils.AbstractTrace#getPropertyDescriptors()
*/
@Override
public IPropertyDescriptor[] getPropertyDescriptors() {
IPropertyDescriptor[] abstractPropertyDescriptors = super.getPropertyDescriptors();
IPropertyDescriptor[] propertyDescriptors = new IPropertyDescriptor[ abstractPropertyDescriptors.length + otfTracePropertyDescriptors.length ];
System.arraycopy( abstractPropertyDescriptors, 0, propertyDescriptors, 0, abstractPropertyDescriptors.length );
System.arraycopy( otfTracePropertyDescriptors, 0, propertyDescriptors, abstractPropertyDescriptors.length, otfTracePropertyDescriptors.length );
return propertyDescriptors;
}
/*
* (non-Javadoc)
* @see eu.geclipse.traceview.utils.AbstractTrace#getPropertyValue(java.lang.Object)
*/
@Override
public Object getPropertyValue( final Object id ) {
Object result = null;
if( PROP_TRACE_VERSION.equals( id ) ) {
result = this.otfDefinitionReader.getVersion();
} else if( PROP_TRACE_CODENAME.equals( id ) ) {
result = this.otfDefinitionReader.getCodename();
} else if( PROP_TRACE_CREATOR.equals( id ) ) {
result = this.otfDefinitionReader.getCreator();
} else if( PROP_TRACE_FUNCTIONGROUPS.equals( id ) ) {
String[] functionGroupNames = this.otfDefinitionReader.getFunctionGroupNames();
StringBuffer functionGroupNameString = new StringBuffer();
for(int i = 0; i<functionGroupNames.length; i++){
functionGroupNameString.append( functionGroupNames[i] + ", " ); //$NON-NLS-1$
}
result = functionGroupNameString.toString();
} else if( PROP_TRACE_PROCESSGROUPS.equals( id ) ) {
String[] processGroupNames = this.otfDefinitionReader.getProcessGroupNames();
StringBuffer processGroupNameString = new StringBuffer();
for(int i = 0; i<processGroupNames.length; i++){
processGroupNameString.append( processGroupNames[i] + ", " ); //$NON-NLS-1$
}
result = processGroupNameString.toString();
} else {
result = super.getPropertyValue( id );
}
return result;
}
public ITrace openTrace( final IPath tracePath, final IProgressMonitor monitor ) throws IOException {
this.tracePath = tracePath;
File file = tracePath.toFile();
long modTime = file.lastModified();
this.input = new BufferedReader( new FileReader( file ) );
this.filenameBase = file.getAbsolutePath().substring( 0, file.getAbsolutePath().length() - 4 );
this.filename = file.getName();
readOTFMapping( monitor );
this.otfDefinitionReader = new OTFDefinitionReader( new File( this.filenameBase + ".0.def" )); //$NON-NLS-1$
this.nodes = new Node[this.numProcs+1];
Event.addIds( this,this.otfDefinitionReader );
String traceOptions = ""; //$NON-NLS-1$
if( Activator.getDefault().getPreferenceStore().getBoolean( PreferenceConstants.readFunctions ) ) {
traceOptions += "readFunctions"; //$NON-NLS-1$
}
boolean hasCache = openCacheDir( file.getAbsolutePath(), traceOptions, modTime );
if( !readOTFData( hasCache, monitor ) )
return null;
enableMemoryMap();
if( !hasCache ) {
if( monitor.isCanceled() )
return null;
try {
monitor.subTask( "Calculating logical clocks" );
ClockCalculator.calcPartnerLogicalClocks( this );
if( monitor.isCanceled() )
return null;
monitor.subTask( "Calculating lamport clocks" );
ClockCalculator.calcLamportClock(this, new NullProgressMonitor());
saveCacheMetadata();
} catch (IndexOutOfBoundsException e) {
Activator.logException(new Exception("Clock calculation failed for trace \"" + file.getAbsolutePath() + '"', e));
}
}
return this;
}
private void readOTFMapping( final IProgressMonitor monitor ) throws IOException {
while( ( this.otfUtils.line = this.input.readLine() ) != null ) {
this.otfUtils.lineIdx = 0;
parseStreamFileDef();
}
this.processes = new Process[ this.numProcs ];
for( int i = 0; i < this.numProcs; i++ ) {
this.processes[ i ] = new Process( i, this );
}
}
private boolean readOTFData( final boolean hasCache, final IProgressMonitor monitor ) throws IOException {
if( !hasCache ) {
Set<Integer> streamNrs = this.streamMap.keySet();
monitor.beginTask( "Loading trace", streamNrs.size() );
for( Integer streamNr : streamNrs ) {
if( monitor.isCanceled() )
return false;
monitor.subTask( "Loading stream " + streamNr );
loadStream( streamNr.intValue() );
monitor.worked( 1 );
}
}
return true;
}
private void loadStream( final int nr ) throws IOException {
String eventsFilename = this.filenameBase + '.' + Integer.toHexString( nr ) + ".events"; //$NON-NLS-1$
OTFStreamReader otfStreamReader = new OTFStreamReader( new File( eventsFilename ), this, this.entered );
otfStreamReader.readStream();
this.nodes[this.processIdMap.get( nr )] = otfStreamReader.getNode();
}
public Node getRootNode(final int processId){
return this.nodes[processId];
}
@SuppressWarnings("unchecked")
private void parseStreamFileDef() {
Integer streamNr = Integer.valueOf( this.otfUtils.readNumber() );
this.otfUtils.checkChar( ':' );
do {
Integer processNr = Integer.valueOf( this.otfUtils.readNumber() );
List<Integer> processList = this.streamMap.get( streamNr );
if( processList == null ) {
processList = new LinkedList<Integer>();
this.streamMap.put( streamNr, processList );
}
processList.add( processNr );
this.processIdMap.put( processNr, Integer.valueOf( this.numProcs ) );
this.numProcs++;
} while( this.otfUtils.read() == ',' );
this.entered = new HashMap[ this.numProcs ];
for( int i = 0; i < this.entered.length; i++ ) {
this.entered[ i ] = new HashMap<Integer, Integer>();
}
}
public int getNumberOfProcesses() {
return this.numProcs;
}
public IProcess getProcess( final int processId ) throws IndexOutOfBoundsException {
return this.processes[ processId ];
}
int getProcessIdForOTFIndex( final int processId ) {
return this.processIdMap.get( Integer.valueOf( processId ) ).intValue();
}
Process getProcessTraceForOTFIndex( final int processId ) throws IndexOutOfBoundsException {
return this.processes[ getProcessIdForOTFIndex( processId ) ];
}
public int getMaximumLamportClock() {
int result = 0;
for( ILamportProcess proc : this.processes ) {
int numEvents = proc.getMaximumLamportClock();
if( numEvents > result ) {
result = numEvents;
}
}
return result;
}
public String getName() {
return this.filename;
}
public int getMaximumPhysicalClock() {
int maxTimeStop = 0;
for( Process process : this.processes ) {
if( maxTimeStop < ( ( ( IPhysicalEvent )process.getEventByLogicalClock( process.getMaximumLogicalClock() ) ).getPhysicalStopClock() ) ) {
maxTimeStop = ( ( ( IPhysicalEvent )process.getEventByLogicalClock( process.getMaximumLogicalClock() ) ).getPhysicalStopClock() );
}
}
return maxTimeStop;
}
public String getFunctionName( final int functionId ) {
return this.otfDefinitionReader.getFunctionName( functionId );
}
public OTFDefinitionReader getDefinition(){
return this.otfDefinitionReader;
}
public int estimateMaxLogicalClock() {
return Integer.MAX_VALUE;
}
}