/***************************************************************************** * 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.FileInputStream; import java.io.FileReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.Stack; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; // import java.util.zip.InflaterInputStream; import com.jcraft.jzlib.ZInputStream; import eu.geclipse.eventgraph.tracereader.otf.preferences.PreferenceConstants; import eu.geclipse.eventgraph.tracereader.otf.util.Node; import eu.geclipse.traceview.EventType; class OTFStreamReader extends OTFUtils { private BufferedReader input; private OTFReader trace; /* Preferences */ /** read function events **/ private boolean readFunctions; /** build calltree **/ private boolean buildCalltree = true; /* Options */ /** MPI process number */ private int processId; /** physical time */ private int timestamp = 0; /** unknown event types */ private Map<String, int[]> unknownEventTypes; /** Stack or mapped Enter Events **/ private int stacked = 0; /** stack to match Enter and Leave Events **/ private Stack<Integer> enteredStack; /** map to match Enter and Leave Events */ private Map<Integer, Integer>[] enteredMap; /** unmatched Leave Events */ private Set<Integer> unmatchedLeaves; private Node node; private int logicalClock = 0; OTFStreamReader( final File file, final OTFReader trace, final Map<Integer, Integer>[] entered ) throws IOException { this.readFunctions = Activator.getDefault().getPreferenceStore().getBoolean( PreferenceConstants.readFunctions ); this.trace = trace; this.enteredMap = entered; this.enteredStack = new Stack<Integer>(); this.unknownEventTypes = new HashMap<String, int[]>(); this.unmatchedLeaves = new HashSet<Integer>(); if( file.exists() ) { this.input = new BufferedReader( new FileReader( file ) ); } else { File zFile = new File( file.getParentFile(), file.getName() + ".z" ); //$NON-NLS-1$ // jcraft inflater this.input = new BufferedReader( new InputStreamReader( new ZInputStream( new FileInputStream( zFile ) ) ) ); // SUN inflater, suffers from java bug # 4040920 // this.input = new BufferedReader( new InputStreamReader( new InflaterInputStream( new FileInputStream( zFile ) ) ) ); } if( this.buildCalltree ) { this.node = new Node( this.trace.getDefinition(), -1 ); } } @SuppressWarnings("boxing") public void readStream() throws IOException { while( ( this.line = this.input.readLine() ) != null ) { this.lineIdx = 0; char ch = this.line.charAt( this.lineIdx ); // read TimeStamp if( Character.isDigit( ch ) || Character.isLowerCase( ch ) ) { readTimestamp(); } // read Enter else if( ch == 'E' && this.readFunctions ) { this.lineIdx++; // skip 'E' readEnter(); } // read Leave else if( ch == 'L' && this.readFunctions ) { this.lineIdx++; // skip 'L' readLeave(); } // read ProcessChange else if( ch == '*' ) { this.lineIdx++; // skip '*' readProcessId(); } // read Send else if( ch == 'S' ) { this.lineIdx++; // skip 'S' readSend(); } // read Receive else if( ch == 'R' ) { this.lineIdx++; // skip 'R' readRecv(); } // read Collective Operation else if( this.line.startsWith( "COP" ) ) { //$NON-NLS-1$ this.lineIdx += 3; readCollective(); } // read Counter else if( this.line.startsWith( "CNT" ) ) { //$NON-NLS-1$ // TODO implement CNT } // unknown else { StringBuffer stringBuffer = new StringBuffer(); while( !( ch >= '0' && ch <= '9' ) && !( ch >= 'a' && ch <= 'f' ) ) { stringBuffer.append( ch ); this.lineIdx++; if( this.lineIdx < this.line.length() ) { ch = this.line.charAt( this.lineIdx ); } else { break; } } int[] value = this.unknownEventTypes.get( stringBuffer.toString() ); if( value == null ) { value = new int[ 1 ]; value[ 0 ] = 1; this.unknownEventTypes.put( stringBuffer.toString(), value ); } else { value[ 0 ]++; } } } for( String key : this.unknownEventTypes.keySet() ) { int[] value = this.unknownEventTypes.get( key ); Activator.getDefault().getLog().log( new Status( IStatus.WARNING, Activator.PLUGIN_ID, "Unsupported OTF Event Type " + key + " occured " + value[ 0 ] + " times in file" ) ); } } @SuppressWarnings("boxing") private void readEnter() { int functionId = readNumber(); ( ( Process )this.trace.getProcess( this.processId ) ).appendFunctionEvent( EventType.OTHER, functionId, this.timestamp ); if( this.stacked > 0 ) { this.enteredStack.push( this.trace.getProcess( this.processId ).getMaximumLogicalClock() ); } else if( this.stacked < 0 ) { this.enteredMap[ this.processId ].put( functionId, this.trace.getProcess( this.processId ).getMaximumLogicalClock() ); } else { this.enteredStack.push( this.trace.getProcess( this.processId ).getMaximumLogicalClock() ); this.enteredMap[ this.processId ].put( functionId, this.trace.getProcess( this.processId ).getMaximumLogicalClock() ); } if( this.buildCalltree ) { this.node = this.node.enter( functionId, this.timestamp ); } this.logicalClock++; if( this.logicalClock % 1000 == 0 ) { ( ( Process )this.trace.getProcess( this.processId ) ).addPreviousEvents( this.enteredStack.toArray( new Integer[ 0 ] ) ); } } @SuppressWarnings("boxing") private void readLeave() { int functionId = readNumber(); Integer eventId = null; if( this.stacked > 0 ) { eventId = this.enteredStack.pop(); } else if( this.stacked < 0 ) { eventId = this.enteredMap[ this.processId ].remove( functionId ); } else if( !this.enteredStack.isEmpty() ) { eventId = this.enteredStack.pop(); this.stacked = 1; } else { eventId = this.enteredMap[ this.processId ].remove( functionId ); this.stacked = -1; } if( eventId != null ) { ( ( Event )this.trace.getProcess( this.processId ).getEventByLogicalClock( eventId ) ).setPhysicalStopClock( this.timestamp ); } else { if( !this.unmatchedLeaves.contains( functionId ) ) { this.unmatchedLeaves.add( functionId ); Activator.getDefault().getLog().log( new Status( IStatus.WARNING, Activator.PLUGIN_ID, "OTF Event Type Leave with function ID " + functionId + " occured without Enter on process " + this.processId ) ); } } if( this.buildCalltree ) { this.node = this.node.leave( this.timestamp ); } } private void readRecv() { int otfPartnerId = readNumber(); int length = -1; int type = -1; int group = -1; while( this.lineIdx != this.line.length() - 1 ) { // Read Length if( this.line.charAt( this.lineIdx ) == 'L' ) { this.lineIdx++; // skip L length = readNumber(); } // Read type else if( this.line.charAt( this.lineIdx ) == 'T' ) { this.lineIdx++; // skip T type = readNumber(); } // Read Communicator else if( this.line.charAt( this.lineIdx ) == 'C' ) { this.lineIdx++; group = readNumber(); } // Read Unknown else { // System.out.println( "Receive contains unknown information " + ( char )this.line.charAt( this.lineIdx ) ); this.lineIdx++; readNumber(); } } int partnerId = this.trace.getProcessIdForOTFIndex( otfPartnerId ); if( this.readFunctions ) { Process process = ( Process )this.trace.getProcess( this.processId ); Event event = process.getEventByLogicalClock( process.getMaximumLogicalClock() ); event.setType( EventType.RECV ); event.setPartnerProcessId( partnerId ); event.setMessageGroup( group ); event.setReceivedMessageLength( length ); event.setMessageType( type ); } else { ( ( Process )this.trace.getProcess( this.processId ) ).appendEvent( EventType.RECV, partnerId, 0, length, type, group, this.timestamp ); } } private void readSend() { int otfPartnerId = readNumber(); int length = -1; int type = -1; int group = -1; while( this.lineIdx != this.line.length() - 1 ) { // Read Length if( this.line.charAt( this.lineIdx ) == 'L' ) { this.lineIdx++; // skip L length = readNumber(); } // Read type else if( this.line.charAt( this.lineIdx ) == 'T' ) { this.lineIdx++; // skip T type = readNumber(); } // Read Communicator else if( this.line.charAt( this.lineIdx ) == 'C' ) { this.lineIdx++; group = readNumber(); } // Read Unknown else { this.lineIdx++; } } int partnerId = this.trace.getProcessIdForOTFIndex( otfPartnerId ); if( this.readFunctions ) { Process process = ( Process )this.trace.getProcess( this.processId ); Event event = process.getEventByLogicalClock( process.getMaximumLogicalClock() ); event.setType( EventType.SEND ); event.setPartnerProcessId( partnerId ); event.setMessageGroup( group ); event.setSentMessageLength( length ); event.setMessageType( type ); } else { ( ( Process )this.trace.getProcess( this.processId ) ).appendEvent( EventType.SEND, partnerId, length, 0, type, group, this.timestamp ); } } private void readCollective() { // TODO add support for COPE if( this.line.charAt( this.lineIdx ) == 'E' ) { int[] value = this.unknownEventTypes.get( "COPE" ); //$NON-NLS-1$ if( value == null ) { value = new int[ 1 ]; value[ 0 ] = 1; this.unknownEventTypes.put( "COPE", value ); //$NON-NLS-1$ } else { value[ 0 ]++; } return; } int collectiveOperationId; // TODO improve support for COPB if( this.line.charAt( this.lineIdx ) == 'B' ) { this.lineIdx++; collectiveOperationId = readNumber(); if( this.line.charAt( this.lineIdx ) == 'H' ) { this.lineIdx++; // skip H readNumber(); // skip value } }else{ collectiveOperationId = readNumber(); } int group = -1; int root = -1; int sent = -1; int received = -1; if( this.line.charAt( this.lineIdx ) == 'C' ) { this.lineIdx++; // skip C group = readNumber(); } if( this.line.indexOf( "RT" ) == this.lineIdx ) { //$NON-NLS-1$ this.lineIdx += 2; // skip RT root = readNumber(); } if( this.line.charAt( this.lineIdx ) == 'S' ) { this.lineIdx++; // skip S sent = readNumber(); } if( this.line.charAt( this.lineIdx ) == 'R' ) { this.lineIdx++; // skip R received = readNumber(); } if( this.readFunctions ) { Process process = ( Process )this.trace.getProcess( this.processId ); Event event = process.getEventByLogicalClock( process.getMaximumLogicalClock() ); event.setType( EventType.COLLECTIVE ); event.setMessageGroup( group ); event.setPartnerProcessId( this.trace.getProcessIdForOTFIndex( root ) ); event.setSentMessageLength( sent ); event.setReceivedMessageLength( received ); } else { ( ( Process )this.trace.getProcess( this.processId ) ).appendEvent( EventType.COLLECTIVE, this.trace.getProcessIdForOTFIndex( root ), sent, received, -1, group, this.timestamp ); } } private void readProcessId() { this.processId = this.trace.getProcessIdForOTFIndex( readNumber() ); } private void readTimestamp() { this.timestamp = readTime(); } public Node getNode() { return this.node; } }