/***************************************************************************** * Copyright (c) 2006, 2008 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: * Christof Klausecker GUP, JKU - initial API and implementation *****************************************************************************/ package eu.geclipse.traceview.nope.tracereader; import java.io.File; import java.io.FileFilter; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.Arrays; import java.util.Enumeration; import java.util.LinkedList; import java.util.List; import java.util.TreeSet; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import eu.geclipse.traceview.EventType; 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.nope.Activator; import eu.geclipse.traceview.nope.preferences.PreferenceConstants; import eu.geclipse.traceview.utils.AbstractTraceFileCache; import eu.geclipse.traceview.utils.ClockCalculator; import eu.geclipse.traceview.utils.LamportEventComparator; /** * NOPE (NOndeterministic Program Evaluator) Trace. */ public class Trace extends AbstractTraceFileCache implements ILamportTrace, IPhysicalTrace, ITraceReader { private String tracedir; private Process[] processes; private int maximumLamportClock = 0; private boolean supportsVectorClocks; private int estimatedMaxLogClock; private void updatePartnerClocks(final IProgressMonitor monitor) { for( int procId = 0; procId < getNumberOfProcesses(); procId++ ) { IProcess process = getProcess( procId ); for( int i = 0; i <= process.getMaximumLogicalClock(); i++ ) { Event event = ( Event )process.getEventByLogicalClock( i ); if( event.getType() == EventType.RECV ) { IProcess partnerProcess = getProcess( event.getPartnerProcessId() ); Event sendEvent = ( Event )partnerProcess.getEventByLogicalClock( event.getPartnerLogicalClock() ); sendEvent.setPartnerLogicalClock( event.getLogicalClock() ); } } if (monitor.isCanceled()) return; monitor.worked( 1 ); } } private void updateVectorClocks() { TreeSet<VecEvent> events = new TreeSet<VecEvent>( new LamportEventComparator() ); try { // set to first event for( int i = 0; i < this.processes.length; i++ ) { events.add( (VecEvent) this.processes[ i ].getEventByLogicalClock( 0 ) ); } while( !events.isEmpty() ) { VecEvent first = events.first(); VecEvent next = ( VecEvent )first.getNextEvent(); // increment local clock; int[] vectorClock = first.getVectorClock(); vectorClock[ first.getProcessId() ]++; first.setVectorClock( vectorClock ); // pass vector clock to partner if( first.getType() == EventType.SEND && first.getSubType() != EventSubtype.MPI_BCAST ) { VecEvent partner = ( VecEvent )first.getPartnerEvent(); if( partner != null ) { int[] partnerVectorClock = partner.getVectorClock(); // partnerVectorClock[ partner.getProcess() ]++; for( int i = 0; i < this.getNumberOfProcesses(); i++ ) { if( vectorClock[ i ] > partnerVectorClock[ i ] ) { partnerVectorClock[ i ] = vectorClock[ i ]; } } partner.setVectorClock( partnerVectorClock ); } } else if( first.getType() == EventType.RECV && first.getSubType() == EventSubtype.MPI_BCAST ) { VecEvent partner = ( VecEvent )first.getPartnerEvent(); if( partner != null ) { int[] partnerVectorClock = partner.getVectorClock(); for( int i = 0; i < this.getNumberOfProcesses(); i++ ) { if( vectorClock[ i ] > partnerVectorClock[ i ] ) { partnerVectorClock[ i ] = vectorClock[ i ]; } } first.setVectorClock( partnerVectorClock ); } } if( next != null ) { // pass vector clock to next event int[] f = first.getVectorClock(); int[] n = next.getVectorClock(); for( int i = 0; i < this.getNumberOfProcesses(); i++ ) { if( f[ i ] > n[ i ] ) { n[ i ] = f[ i ]; } } next.setVectorClock( n ); // add next event to set events.add( next ); } events.remove( first ); } } catch( IndexOutOfBoundsException exception ) { Activator.logException( exception ); } } /** * Opens NOPE trace files. * * @param trace NOPE trace directory. * @throws IOException thrown if a read error occurs. */ public ITrace openTrace( final IPath trace, final IProgressMonitor monitor ) throws IOException { int numProcs; long maxFileLen = 0; long modTime; ZipFile zipFile = null; List fileList = new LinkedList(); if( trace.lastSegment().endsWith( ".zip" ) ) { this.tracePath = trace; File file = this.tracePath.toFile(); zipFile = new ZipFile( file ); Enumeration entries = zipFile.entries(); numProcs = zipFile.size(); // currently no other files are allowed in the zip file while( entries.hasMoreElements() ) { ZipEntry entry = ( ZipEntry )entries.nextElement(); long len = entry.getSize(); if( len > maxFileLen ) maxFileLen = len; fileList.add( entry ); } modTime = file.lastModified(); } else { this.tracePath = trace.removeLastSegments( 1 ); File dir = this.tracePath.toFile(); this.tracedir = this.tracePath.toPortableString(); File[] files = dir.listFiles( new FileFilter() { public boolean accept( final File file ) { return !file.isDirectory() && file.getName().startsWith( "trace" ) //$NON-NLS-1$ && file.getName().charAt( file.getName().length() - 4 ) == '.'; } } ); Arrays.sort( files ); numProcs = files.length; modTime = dir.lastModified(); for (File file : files) { long len = file.length(); if (len > maxFileLen) maxFileLen = len; if (file.lastModified() > modTime) modTime = file.lastModified(); fileList.add(file); } } this.processes = new Process[ numProcs ]; this.estimatedMaxLogClock = (int) (maxFileLen / 47); Event.addIds( this ); String traceOptions = ""; this.supportsVectorClocks = Activator.getDefault() .getPreferenceStore() .getBoolean( PreferenceConstants.vectorClocks ); if( supportsVectorClocks() ) { VecEvent.addIds( this ); traceOptions += "vectorClocks "; } // part of the workspace ? String projectName = ""; //$NON-NLS-1$ boolean workspace = ResourcesPlugin.getWorkspace() .getRoot() .getLocation() .isPrefixOf( this.tracePath ); if( workspace ) { IPath path = this.tracePath.removeFirstSegments( ResourcesPlugin.getWorkspace() .getRoot() .getLocation() .segmentCount() ); projectName = path.uptoSegment( 1 ).toPortableString(); String device = path.getDevice(); if( device != null ) { projectName = projectName.substring( device.length() ); } } monitor.beginTask( "Loading trace data", this.processes.length * 3 ); monitor.subTask( "Opening trace cache" ); boolean hasCache = openCacheDir( this.tracePath.toFile().getAbsolutePath(), traceOptions, modTime ); for( Object fileObj : fileList ) { if( monitor.isCanceled() ) return null; String filename; long filesize; InputStream inputStream; if( fileObj instanceof ZipEntry ) { ZipEntry zipEntry = ( ZipEntry )fileObj; filename = zipEntry.getName(); filesize = zipEntry.getSize(); inputStream = zipFile.getInputStream( zipEntry ); } else { File file = ( File )fileObj; filename = file.getName(); filesize = file.length(); File inputFile = new File( this.tracedir, filename ); inputStream = new FileInputStream( inputFile ); } int traceProc = Integer.parseInt( filename.substring( filename.length() - 3 ) ); monitor.subTask( "Loading process " + traceProc ); Process processTrace = new Process( inputStream, filename, filesize, traceProc, hasCache, this ); this.processes[ traceProc ] = processTrace; monitor.worked( 1 ); } enableMemoryMap(); if( !hasCache ) { if (monitor.isCanceled()) return null; monitor.subTask( "Updating logical clocks" ); updatePartnerClocks(monitor); if (monitor.isCanceled()) return null; monitor.subTask( "Calculating lamport clocks" ); ClockCalculator.calcLamportClock( this, monitor ); if (monitor.isCanceled()) return null; if( this.supportsVectorClocks ) { monitor.subTask( "Calculating vector clocks" ); updateVectorClocks(); if (monitor.isCanceled()) return null; } saveCacheMetadata(); } for( Process process : this.processes ) { if( this.maximumLamportClock < process.getMaximumLamportClock() ) this.maximumLamportClock = process.getMaximumLamportClock(); } return this; } public int getNumberOfProcesses() { return this.processes.length; } public IProcess getProcess( final int processId ) throws IndexOutOfBoundsException { return this.processes[ processId ]; } public String getName() { String name = this.tracePath.removeFirstSegments( 1 ).lastSegment(); int index = name.indexOf( ".traces" ); //$NON-NLS-1$ if( index != -1 ) { name = name.substring( 0, index ); } return name; } public int getMaximumLamportClock() { return this.maximumLamportClock; } protected Process[] getProcesses() { return this.processes; } 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; } protected boolean supportsVectorClocks() { return this.supportsVectorClocks; } @Override public int estimateMaxLogicalClock() { return this.estimatedMaxLogClock; } }