GLES2Debugger: Make command exchange async to improve performance.

In message loop, use select to check for available commands from client,
 rather than always expecting commands in eglSwapBuffers.
Client can send commands at any time.

Change-Id: I607c8fa571a896996c0a3300de904b6e263fc281
Signed-off-by: David Li <davidxli@google.com>
This commit is contained in:
David Li
2011-03-11 11:11:41 -08:00
parent 8b2eabd60d
commit 6f85d436f3
4 changed files with 88 additions and 76 deletions

View File

@@ -218,7 +218,6 @@ public final class DebuggerMessage {
CONTINUE(188, 188), CONTINUE(188, 188),
SKIP(189, 189), SKIP(189, 189),
SETPROP(190, 190), SETPROP(190, 190),
CAPTURE(191, 191),
; ;
@@ -417,7 +416,6 @@ public final class DebuggerMessage {
case 188: return CONTINUE; case 188: return CONTINUE;
case 189: return SKIP; case 189: return SKIP;
case 190: return SETPROP; case 190: return SETPROP;
case 191: return CAPTURE;
default: return null; default: return null;
} }
} }

View File

@@ -16,12 +16,14 @@
package com.android.glesv2debugger; package com.android.glesv2debugger;
import com.android.glesv2debugger.DebuggerMessage.Message;
import org.eclipse.swt.graphics.Device; import org.eclipse.swt.graphics.Device;
import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData; import org.eclipse.swt.graphics.ImageData;
public class MessageData { public class MessageData {
public DebuggerMessage.Message.Function function; public Message.Function function;
public Image image; // texture public Image image; // texture
public String shader; // shader source public String shader; // shader source
public String[] columns; public String[] columns;
@@ -29,14 +31,14 @@ public class MessageData {
public int maxAttrib; // used for formatting data public int maxAttrib; // used for formatting data
public GLEnum dataType; // could be float, int; mainly for formatting use public GLEnum dataType; // could be float, int; mainly for formatting use
public MessageData(final Device device, final DebuggerMessage.Message msg) { public MessageData(final Device device, final Message msg) {
image = null; image = null;
shader = null; shader = null;
data = null; data = null;
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
function = msg.getFunction(); function = msg.getFunction();
ImageData imageData = null; ImageData imageData = null;
if (function != DebuggerMessage.Message.Function.ACK) if (function != Message.Function.ACK)
assert msg.hasTime(); assert msg.hasTime();
columns = new String [4]; columns = new String [4];
columns[0] = function.toString(); columns[0] = function.toString();

View File

@@ -16,6 +16,8 @@
package com.android.glesv2debugger; package com.android.glesv2debugger;
import com.android.glesv2debugger.DebuggerMessage.Message;
import com.android.glesv2debugger.DebuggerMessage.Message.Function;
import com.android.glesv2debugger.DebuggerMessage.Message.Type; import com.android.glesv2debugger.DebuggerMessage.Message.Type;
import java.io.DataInputStream; import java.io.DataInputStream;
@@ -30,8 +32,8 @@ public class MessageQueue implements Runnable {
boolean running = false; boolean running = false;
Thread thread = null; Thread thread = null;
ArrayList<DebuggerMessage.Message> complete = new ArrayList<DebuggerMessage.Message>(); ArrayList<Message> complete = new ArrayList<Message>();
ArrayList<DebuggerMessage.Message> commands = new ArrayList<DebuggerMessage.Message>(); ArrayList<Message> commands = new ArrayList<Message>();
SampleView sampleView; SampleView sampleView;
HashMap<Integer, GLServerVertex> serversVertex = new HashMap<Integer, GLServerVertex>(); HashMap<Integer, GLServerVertex> serversVertex = new HashMap<Integer, GLServerVertex>();
@@ -58,24 +60,24 @@ public class MessageQueue implements Runnable {
return running; return running;
} }
void SendCommands(final DataOutputStream dos, final int contextId) throws IOException { boolean SendCommands(final DataOutputStream dos, final int contextId) throws IOException {
boolean sent = false;
synchronized (commands) { synchronized (commands) {
for (int i = 0; i < commands.size(); i++) { for (int i = 0; i < commands.size(); i++) {
DebuggerMessage.Message command = commands.get(i); Message command = commands.get(i);
if (command.getContextId() == contextId || contextId == 0) { // FIXME: // FIXME: proper context id
// proper if (command.getContextId() == contextId || contextId == 0) {
// context
// id
SendMessage(dos, command); SendMessage(dos, command);
commands.remove(i); commands.remove(i);
i--; i--;
sent = true;
} }
} }
} }
SendResponse(dos, contextId, DebuggerMessage.Message.Function.SKIP); return sent;
} }
public void AddCommand(DebuggerMessage.Message command) { public void AddCommand(Message command) {
synchronized (commands) { synchronized (commands) {
commands.add(command); commands.add(command);
} }
@@ -86,7 +88,7 @@ public class MessageQueue implements Runnable {
Socket socket = new Socket(); Socket socket = new Socket();
DataInputStream dis = null; DataInputStream dis = null;
DataOutputStream dos = null; DataOutputStream dos = null;
HashMap<Integer, ArrayList<DebuggerMessage.Message>> incoming = new HashMap<Integer, ArrayList<DebuggerMessage.Message>>(); HashMap<Integer, ArrayList<Message>> incoming = new HashMap<Integer, ArrayList<Message>>();
try { try {
socket.connect(new java.net.InetSocketAddress("127.0.0.1", 5039)); socket.connect(new java.net.InetSocketAddress("127.0.0.1", 5039));
dis = new DataInputStream(socket.getInputStream()); dis = new DataInputStream(socket.getInputStream());
@@ -98,9 +100,9 @@ public class MessageQueue implements Runnable {
// try { // try {
while (running) { while (running) {
DebuggerMessage.Message msg = null; Message msg = null;
if (incoming.size() > 0) { // find queued incoming if (incoming.size() > 0) { // find queued incoming
for (ArrayList<DebuggerMessage.Message> messages : incoming for (ArrayList<Message> messages : incoming
.values()) .values())
if (messages.size() > 0) { if (messages.size() > 0) {
msg = messages.get(0); msg = messages.get(0);
@@ -111,20 +113,7 @@ public class MessageQueue implements Runnable {
if (null == msg) { // get incoming from network if (null == msg) { // get incoming from network
try { try {
msg = ReadMessage(dis); msg = ReadMessage(dis);
if (msg.getExpectResponse()) { SendResponse(dos, msg);
if (msg.getType() == Type.BeforeCall)
SendResponse(dos, msg.getContextId(),
DebuggerMessage.Message.Function.CONTINUE);
else if (msg.getType() == Type.AfterCall)
// after GL function call
SendCommands(dos, 0); // FIXME: proper context id
// SendResponse(dos, msg.getContextId(),
// DebuggerMessage.Message.Function.SKIP);
else if (msg.getType() == Type.Response)
assert true;
else
assert false;
}
} catch (IOException e) { } catch (IOException e) {
Error(e); Error(e);
running = false; running = false;
@@ -135,13 +124,13 @@ public class MessageQueue implements Runnable {
int contextId = msg.getContextId(); int contextId = msg.getContextId();
if (!incoming.containsKey(contextId)) if (!incoming.containsKey(contextId))
incoming.put(contextId, incoming.put(contextId,
new ArrayList<DebuggerMessage.Message>()); new ArrayList<Message>());
// FIXME: the expected sequence will change for interactive mode // FIXME: the expected sequence will change for interactive mode
while (msg.getType() == Type.BeforeCall) { while (msg.getType() == Type.BeforeCall) {
DebuggerMessage.Message next = null; Message next = null;
// get existing message part for this context // get existing message part for this context
ArrayList<DebuggerMessage.Message> messages = incoming ArrayList<Message> messages = incoming
.get(contextId); .get(contextId);
if (messages.size() > 0) { if (messages.size() > 0) {
next = messages.get(0); next = messages.get(0);
@@ -150,21 +139,7 @@ public class MessageQueue implements Runnable {
if (null == next) { // read new part for message if (null == next) { // read new part for message
try { try {
next = ReadMessage(dis); next = ReadMessage(dis);
SendResponse(dos, next);
if (next.getExpectResponse()) {
if (next.getType() == Type.BeforeCall)
SendResponse(
dos,
next.getContextId(),
DebuggerMessage.Message.Function.CONTINUE);
else if (next.getType() == Type.AfterCall)
SendCommands(dos, 0); // FIXME: proper context
// id
else if (msg.getType() == Type.Response)
assert true;
else
assert false;
}
} catch (IOException e) { } catch (IOException e) {
Error(e); Error(e);
running = false; running = false;
@@ -176,13 +151,13 @@ public class MessageQueue implements Runnable {
if (!incoming.containsKey(next.getContextId())) if (!incoming.containsKey(next.getContextId()))
incoming.put( incoming.put(
next.getContextId(), next.getContextId(),
new ArrayList<DebuggerMessage.Message>()); new ArrayList<Message>());
incoming.get(next.getContextId()).add(next); incoming.get(next.getContextId()).add(next);
continue; continue;
} }
} }
DebuggerMessage.Message.Builder builder = msg.toBuilder(); Message.Builder builder = msg.toBuilder();
// builder.mergeFrom(next); seems to merge incorrectly // builder.mergeFrom(next); seems to merge incorrectly
if (next.hasRet()) if (next.hasRet())
builder.setRet(next.getRet()); builder.setRet(next.getRet());
@@ -277,18 +252,18 @@ public class MessageQueue implements Runnable {
// } // }
} }
public DebuggerMessage.Message RemoveMessage(int contextId) { public Message RemoveMessage(int contextId) {
synchronized (complete) { synchronized (complete) {
if (complete.size() == 0) if (complete.size() == 0)
return null; return null;
if (0 == contextId) // get a message of any if (0 == contextId) // get a message for any context
{ {
DebuggerMessage.Message msg = complete.get(0); Message msg = complete.get(0);
complete.remove(0); complete.remove(0);
return msg; return msg;
} }
for (int i = 0; i < complete.size(); i++) { for (int i = 0; i < complete.size(); i++) {
DebuggerMessage.Message msg = complete.get(i); Message msg = complete.get(i);
if (msg.getContextId() == contextId) { if (msg.getContextId() == contextId) {
complete.remove(i); complete.remove(i);
return msg; return msg;
@@ -298,7 +273,7 @@ public class MessageQueue implements Runnable {
return null; return null;
} }
DebuggerMessage.Message ReadMessage(final DataInputStream dis) Message ReadMessage(final DataInputStream dis)
throws IOException { throws IOException {
int len = 0; int len = 0;
try { try {
@@ -321,25 +296,29 @@ public class MessageQueue implements Runnable {
} else } else
readLen += read; readLen += read;
} }
DebuggerMessage.Message msg = DebuggerMessage.Message.parseFrom(buffer); Message msg = Message.parseFrom(buffer);
return msg; return msg;
} }
void SendMessage(final DataOutputStream dos, final DebuggerMessage.Message message) void SendMessage(final DataOutputStream dos, final Message message)
throws IOException { throws IOException {
final byte[] data = message.toByteArray(); final byte[] data = message.toByteArray();
dos.writeInt(data.length); dos.writeInt(data.length);
dos.write(data); dos.write(data);
} }
void SendResponse(final DataOutputStream dos, final int contextId, void SendResponse(final DataOutputStream dos, final Message msg) throws IOException {
final DebuggerMessage.Message.Function function) throws IOException { Message.Builder builder = Message.newBuilder();
DebuggerMessage.Message.Builder builder = DebuggerMessage.Message builder.setContextId(msg.getContextId());
.newBuilder(); if (msg.getType() == Type.BeforeCall)
builder.setContextId(contextId); builder.setFunction(Function.CONTINUE);
builder.setFunction(function); else if (msg.getType() == Type.AfterCall)
builder.setFunction(Function.SKIP);
builder.setType(Type.Response); builder.setType(Type.Response);
builder.setExpectResponse(false); builder.setExpectResponse(false);
// FIXME: consider using proper context id
if (SendCommands(dos, 0) || msg.getExpectResponse())
if (builder.hasFunction())
SendMessage(dos, builder.build()); SendMessage(dos, builder.build());
} }

View File

@@ -16,6 +16,7 @@
package com.android.glesv2debugger; package com.android.glesv2debugger;
import com.android.glesv2debugger.DebuggerMessage.Message;
import com.android.glesv2debugger.DebuggerMessage.Message.Function; import com.android.glesv2debugger.DebuggerMessage.Message.Function;
import com.android.glesv2debugger.DebuggerMessage.Message.Prop; import com.android.glesv2debugger.DebuggerMessage.Message.Prop;
import com.android.glesv2debugger.DebuggerMessage.Message.Type; import com.android.glesv2debugger.DebuggerMessage.Message.Type;
@@ -66,7 +67,12 @@ import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.PlatformUI; import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.ViewPart; import org.eclipse.ui.part.ViewPart;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar;
/** /**
* This sample class demonstrates how to plug-in a new workbench view. The view * This sample class demonstrates how to plug-in a new workbench view. The view
@@ -115,7 +121,7 @@ public class SampleView extends ViewPart implements Runnable {
*/ */
class ViewContentProvider implements IStructuredContentProvider { class ViewContentProvider implements IStructuredContentProvider {
ArrayList<com.android.glesv2debugger.MessageData> entries = new ArrayList<com.android.glesv2debugger.MessageData>(); ArrayList<MessageData> entries = new ArrayList<MessageData>();
public void add(final ArrayList<MessageData> msgs) { public void add(final ArrayList<MessageData> msgs) {
entries.addAll(msgs); entries.addAll(msgs);
@@ -152,7 +158,7 @@ public class SampleView extends ViewPart implements Runnable {
ITableLabelProvider { ITableLabelProvider {
@Override @Override
public String getColumnText(Object obj, int index) { public String getColumnText(Object obj, int index) {
com.android.glesv2debugger.MessageData msgData = (com.android.glesv2debugger.MessageData) obj; MessageData msgData = (MessageData) obj;
if (null == msgData) if (null == msgData)
return getText(obj); return getText(obj);
if (index >= msgData.columns.length) if (index >= msgData.columns.length)
@@ -164,7 +170,7 @@ public class SampleView extends ViewPart implements Runnable {
public Image getColumnImage(Object obj, int index) { public Image getColumnImage(Object obj, int index) {
if (index > 0) if (index > 0)
return null; return null;
com.android.glesv2debugger.MessageData msgData = (com.android.glesv2debugger.MessageData) obj; MessageData msgData = (MessageData) obj;
if (null == msgData) if (null == msgData)
return getImage(obj); return getImage(obj);
if (null == msgData.image) if (null == msgData.image)
@@ -186,7 +192,7 @@ public class SampleView extends ViewPart implements Runnable {
@Override @Override
public boolean select(Viewer viewer, Object parentElement, public boolean select(Viewer viewer, Object parentElement,
Object element) { Object element) {
com.android.glesv2debugger.MessageData msgData = (com.android.glesv2debugger.MessageData) element; MessageData msgData = (MessageData) element;
if (null == filters) if (null == filters)
return true; return true;
for (int i = 0; i < filters.length; i++) for (int i = 0; i < filters.length; i++)
@@ -430,7 +436,7 @@ public class SampleView extends ViewPart implements Runnable {
actionCapture = new Action("Capture", Action.AS_CHECK_BOX) { actionCapture = new Action("Capture", Action.AS_CHECK_BOX) {
@Override @Override
public void run() { public void run() {
DebuggerMessage.Message.Builder builder = DebuggerMessage.Message.newBuilder(); Message.Builder builder = Message.newBuilder();
builder.setContextId(0); // FIXME: proper context id builder.setContextId(0); // FIXME: proper context id
builder.setType(Type.Response); builder.setType(Type.Response);
builder.setExpectResponse(false); builder.setExpectResponse(false);
@@ -455,11 +461,11 @@ public class SampleView extends ViewPart implements Runnable {
}; };
int i = java.util.Arrays.asList(timeModes).indexOf(this.getText()); int i = java.util.Arrays.asList(timeModes).indexOf(this.getText());
i = (i + 1) % timeModes.length; i = (i + 1) % timeModes.length;
DebuggerMessage.Message.Builder builder = DebuggerMessage.Message.newBuilder(); Message.Builder builder = Message.newBuilder();
builder.setContextId(0); // FIXME: proper context id builder.setContextId(0); // FIXME: proper context id
builder.setType(Type.Response); builder.setType(Type.Response);
builder.setExpectResponse(false); builder.setExpectResponse(false);
builder.setFunction(DebuggerMessage.Message.Function.SETPROP); builder.setFunction(Message.Function.SETPROP);
builder.setProp(Prop.TimeMode); builder.setProp(Prop.TimeMode);
builder.setArg0(i); builder.setArg0(i);
messageQueue.AddCommand(builder.build()); messageQueue.AddCommand(builder.build());
@@ -638,14 +644,24 @@ public class SampleView extends ViewPart implements Runnable {
@Override @Override
public void run() { public void run() {
boolean refresh = false; FileWriter file = null;
PrintWriter writer = null;
try {
file = new FileWriter("GLES2Debugger.log", true);
writer = new PrintWriter(file);
writer.write("\n\n");
writer.write(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Calendar.getInstance()
.getTime()));
} catch (IOException e1) {
showError(e1);
}
ArrayList<MessageData> msgs = new ArrayList<MessageData>(); ArrayList<MessageData> msgs = new ArrayList<MessageData>();
while (running) { while (running) {
if (!messageQueue.IsRunning()) if (!messageQueue.IsRunning())
break; break;
DebuggerMessage.Message msg = messageQueue.RemoveMessage(0); Message msg = messageQueue.RemoveMessage(0);
if (msgs.size() > 20) { if (msgs.size() > 40) {
viewContentProvider.add(msgs); viewContentProvider.add(msgs);
msgs.clear(); msgs.clear();
} }
@@ -659,9 +675,26 @@ public class SampleView extends ViewPart implements Runnable {
} }
final MessageData msgData = new MessageData(this.getViewSite() final MessageData msgData = new MessageData(this.getViewSite()
.getShell().getDisplay(), msg); .getShell().getDisplay(), msg);
if (null != writer) {
writer.write(msgData.columns[0]);
for (int i = 0; i < 30 - msgData.columns[0].length(); i++)
writer.write(" ");
writer.write("\t");
writer.write(msgData.columns[1] + " \t ");
writer.write(msgData.columns[2] + " \t ");
writer.write(msgData.columns[3] + " \n");
if (msgData.columns[0] == "eglSwapBuffers") {
writer.write("\n-------\n");
writer.flush();
}
}
msgs.add(msgData); msgs.add(msgData);
} }
if (running) if (running)
ConnectDisconnect(); // error occurred, disconnect ConnectDisconnect(); // error occurred, disconnect
if (null != writer) {
writer.flush();
writer.close();
}
} }
} }