diff options
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/TraceFileParserTask.java')
-rw-r--r-- | eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/TraceFileParserTask.java | 254 |
1 files changed, 254 insertions, 0 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/TraceFileParserTask.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/TraceFileParserTask.java new file mode 100644 index 000000000..b90c004b0 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/TraceFileParserTask.java @@ -0,0 +1,254 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.ide.eclipse.gltrace; + +import com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage; +import com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.Function; +import com.android.ide.eclipse.gltrace.format.GLAPISpec; +import com.android.ide.eclipse.gltrace.format.GLMessageFormatter; +import com.android.ide.eclipse.gltrace.model.GLCall; +import com.android.ide.eclipse.gltrace.model.GLFrame; +import com.android.ide.eclipse.gltrace.model.GLTrace; +import com.android.ide.eclipse.gltrace.state.transforms.StateTransformFactory; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jface.operation.IRunnableWithProgress; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; + +public class TraceFileParserTask implements IRunnableWithProgress { + private static final TraceFileReader sReader = new TraceFileReader(); + + private static final GLMessageFormatter sGLMessageFormatter = + new GLMessageFormatter(GLAPISpec.getSpecs()); + + private String mTraceFilePath; + private RandomAccessFile mFile; + + private List<GLCall> mGLCalls; + private Set<Integer> mGLContextIds; + + private GLTrace mTrace; + + /** + * Construct a GL Trace file parser. + * @param path path to trace file + */ + public TraceFileParserTask(String path) { + try { + mFile = new RandomAccessFile(path, "r"); //$NON-NLS-1$ + } catch (FileNotFoundException e) { + throw new IllegalArgumentException(e); + } + + mTraceFilePath = path; + mGLCalls = new ArrayList<GLCall>(); + mGLContextIds = new TreeSet<Integer>(); + } + + private void addMessage(int index, long traceFileOffset, GLMessage msg, long startTime) { + String formattedMsg; + try { + formattedMsg = sGLMessageFormatter.formatGLMessage(msg); + } catch (Exception e) { + formattedMsg = String.format("%s()", msg.getFunction().toString()); //$NON-NLS-1$ + } + + GLCall c = new GLCall(index, + startTime, + traceFileOffset, + formattedMsg, + msg.getFunction(), + msg.hasFb(), + msg.getContextId(), + msg.getDuration(), + msg.getThreadtime()); + + addProperties(c, msg); + + try { + c.setStateTransformations(StateTransformFactory.getTransformsFor(msg)); + } catch (Exception e) { + c.setStateTransformationCreationError(e.getMessage()); + GlTracePlugin.getDefault().logMessage("Error while creating transformations for " + + c.toString() + ":"); + GlTracePlugin.getDefault().logMessage(e.getMessage()); + } + + mGLCalls.add(c); + mGLContextIds.add(Integer.valueOf(c.getContextId())); + } + + /** Save important values from the {@link GLMessage} in the {@link GLCall} as properties. */ + private void addProperties(GLCall c, GLMessage msg) { + switch (msg.getFunction()) { + case glPushGroupMarkerEXT: + // void PushGroupMarkerEXT(sizei length, const char *marker); + // save the marker name + c.addProperty(GLCall.PROPERTY_MARKERNAME, + msg.getArgs(1).getCharValue(0).toStringUtf8()); + break; + case glVertexAttribPointerData: + // void glVertexAttribPointerData(GLuint indx, GLint size, GLenum type, + // GLboolean normalized, GLsizei stride, const GLvoid* ptr, + // int minIndex, int maxIndex) + c.addProperty(GLCall.PROPERTY_VERTEX_ATTRIB_POINTER_SIZE, + Integer.valueOf(msg.getArgs(1).getIntValue(0))); + c.addProperty(GLCall.PROPERTY_VERTEX_ATTRIB_POINTER_TYPE, + GLEnum.valueOf(msg.getArgs(2).getIntValue(0))); + c.addProperty(GLCall.PROPERTY_VERTEX_ATTRIB_POINTER_DATA, + msg.getArgs(5).getRawBytes(0).toByteArray()); + break; + default: + break; + } + } + + /** + * Parse the entire file and create a {@link GLTrace} object that can be retrieved + * using {@link #getTrace()}. + */ + @Override + public void run(IProgressMonitor monitor) throws InvocationTargetException, + InterruptedException { + long fileLength; + try { + fileLength = mFile.length(); + } catch (IOException e1) { + fileLength = 0; + } + + monitor.beginTask("Parsing OpenGL Trace File", + fileLength > 0 ? 100 : IProgressMonitor.UNKNOWN); + + List<GLFrame> glFrames = null; + + try { + GLMessage msg = null; + int msgCount = 0; + long filePointer = mFile.getFilePointer(); + int percentParsed = 0; + + // counters that maintain some statistics about the trace messages + long minTraceStartTime = Long.MAX_VALUE; + + while ((msg = sReader.getMessageAtOffset(mFile, -1)) != null) { + if (minTraceStartTime > msg.getStartTime()) { + minTraceStartTime = msg.getStartTime(); + } + + addMessage(msgCount, filePointer, msg, msg.getStartTime() - minTraceStartTime); + + filePointer = mFile.getFilePointer(); + msgCount++; + + if (monitor.isCanceled()) { + throw new InterruptedException(); + } + + if (fileLength > 0) { + int percentParsedNow = (int)((filePointer * 100) / fileLength); + monitor.worked(percentParsedNow - percentParsed); + percentParsed = percentParsedNow; + } + } + + if (mGLContextIds.size() > 1) { + // if there are multiple contexts, then the calls may arrive at the + // host out of order. So we perform a sort based on the invocation time. + Collections.sort(mGLCalls, new Comparator<GLCall>() { + @Override + public int compare(GLCall c1, GLCall c2) { + long diff = (c1.getStartTime() - c2.getStartTime()); + + // We could return diff casted to an int. But in Java, casting + // from a long to an int truncates the bits and will not preserve + // the sign. So we resort to comparing the diff to 0 and returning + // the sign. + if (diff == 0) { + return 0; + } else if (diff > 0) { + return 1; + } else { + return -1; + } + } + }); + + // reassign indices after sorting + for (int i = 0; i < mGLCalls.size(); i++) { + mGLCalls.get(i).setIndex(i); + } + } + + glFrames = createFrames(mGLCalls); + } catch (Exception e) { + throw new InvocationTargetException(e); + } finally { + try { + mFile.close(); + } catch (IOException e) { + // ignore exception while closing file + } + monitor.done(); + } + + File f = new File(mTraceFilePath); + TraceFileInfo fileInfo = new TraceFileInfo(mTraceFilePath, f.length(), f.lastModified()); + mTrace = new GLTrace(fileInfo, glFrames, mGLCalls, new ArrayList<Integer>(mGLContextIds)); + } + + /** Assign GL calls to GL Frames. */ + private List<GLFrame> createFrames(List<GLCall> calls) { + List<GLFrame> glFrames = new ArrayList<GLFrame>(); + int startCallIndex = 0; + int frameIndex = 0; + + for (int i = 0; i < calls.size(); i++) { + GLCall c = calls.get(i); + if (c.getFunction() == Function.eglSwapBuffers) { + glFrames.add(new GLFrame(frameIndex, startCallIndex, i + 1)); + startCallIndex = i + 1; + frameIndex++; + } + } + + // assign left over calls at the end to the last frame + if (startCallIndex != mGLCalls.size()) { + glFrames.add(new GLFrame(frameIndex, startCallIndex, mGLCalls.size())); + } + + return glFrames; + } + + /** + * Retrieve the trace object constructed from messages in the trace file. + */ + public GLTrace getTrace() { + return mTrace; + } +} |