Add a debug() method to Serial

This commit also turns a 100ns wait inside JSSC in a yield() and removes the invocation of serialEvent outside the synchronized block.
This commit is contained in:
gohai
2013-11-24 20:52:38 -08:00
parent 0ef72e25c9
commit 541cab2bd9

View File

@@ -48,6 +48,28 @@ public class Serial implements SerialPortEventListener {
volatile boolean invokeSerialAvailable = false;
// DEBUG
int baudRate = 0;
int countEvents = 0; // number of event handler invocations
int countFuncs = 0; // number of SerialEvent invocations
int countReads = 0; // number of read operations
int countSyncs = 0; // number of synchronizations
int countWrites = 0; // number of write operations
long firstEvent = 0; // timestamp of first event handler invocation
int maxBufferLength = 0; // maximum size of input buffer
long maxFuncTime = 0; // maximum time spend invoking SerialEvent
int maxRead = 0; // maximum number of bytes read
long maxReadTime = 0; // maximum time spent on read operations
long maxReadSyncTime = 0; // maximum time spent on a synchronization in the event handler
long maxSyncTime = 0; // maximum time spent on a synchronization elsewhere
long maxWriteTime = 0; // maximum time spent on a write operation
long sumFuncTime = 0; // sum of time spent in SerialEvent
int sumRead = 0; // sum of bytes read
long sumReadSyncTime = 0; // sum of time spent on synchonizations in the event handler
long sumReadTime = 0; // sum of time spent on read operations
long sumSyncTime = 0; // sum of time spent on synchonizations elsewhere
long sumWriteTime = 0; // sum of time spent on write operations
// Things we are currently not exposing:
// * hardware flow control
// * state of the RING, RLSD line
@@ -79,6 +101,8 @@ public class Serial implements SerialPortEventListener {
parent.registerMethod("dispose", this);
parent.registerMethod("pre", this);
this.baudRate = baudRate;
// setup parity
if (parity == 'O') {
parity = SerialPort.PARITY_ODD;
@@ -160,13 +184,37 @@ public class Serial implements SerialPortEventListener {
public void clear() {
long start = System.nanoTime();
synchronized (buffer) {
long len = System.nanoTime()-start;
if (maxSyncTime < len) {
maxSyncTime = len;
}
sumSyncTime += len;
countSyncs++;
inBuffer = 0;
readOffset = 0;
}
}
public void debug() {
float secs = (System.nanoTime()-firstEvent)/1000000000.0f;
System.out.println("\nSerial: test #3");
System.out.println(port.getPortName()+" @ "+baudRate+" bps");
System.out.println(secs+" sec receiving data:");
System.out.println(countEvents+" events, "+(countEvents/secs)+" per sec");
System.out.println(countReads+" reads, "+(countReads/secs)+" per sec, "+(sumReadTime/(float)countReads)+" ns avg, "+maxReadTime+" ns max");
System.out.println((sumRead/(float)countReads)+" bytes avg per read, "+(sumRead/secs)+" per sec, "+maxRead+" bytes max");
System.out.println("Max buffer length: "+maxBufferLength);
System.out.println(sumReadSyncTime/(float)countReads+" ns avg read synchronizations, "+maxReadSyncTime+" ns max");
System.out.println(countFuncs+" callbacks, "+(sumFuncTime/(float)countFuncs)+" ns avg, "+maxFuncTime+" ns max");
System.out.println(countWrites+" writes, "+(sumWriteTime/(float)countWrites)+" ns avg, "+maxWriteTime+" ns max");
System.out.println(countSyncs+" synchonizations, "+(sumSyncTime/(float)countSyncs)+" ns avg, "+maxSyncTime+" ns max");
port.debug();
}
public boolean getCTS() {
try {
return port.isCTS();
@@ -189,13 +237,20 @@ public class Serial implements SerialPortEventListener {
return SerialPortList.getPortProperties(portName);
}
public int last() {
if (inBuffer == readOffset) {
return -1;
}
long start = System.nanoTime();
synchronized (buffer) {
long len = System.nanoTime()-start;
if (maxSyncTime < len) {
maxSyncTime = len;
}
sumSyncTime += len;
countSyncs++;
int ret = buffer[inBuffer-1] & 0xFF;
inBuffer = 0;
readOffset = 0;
@@ -221,7 +276,14 @@ public class Serial implements SerialPortEventListener {
return -1;
}
long start = System.nanoTime();
synchronized (buffer) {
long len = System.nanoTime()-start;
if (maxSyncTime < len) {
maxSyncTime = len;
}
sumSyncTime += len;
countSyncs++;
int ret = buffer[readOffset++] & 0xFF;
if (inBuffer == readOffset) {
inBuffer = 0;
@@ -237,7 +299,14 @@ public class Serial implements SerialPortEventListener {
return null;
}
long start = System.nanoTime();
synchronized (buffer) {
long len = System.nanoTime()-start;
if (maxSyncTime < len) {
maxSyncTime = len;
}
sumSyncTime += len;
countSyncs++;
byte[] ret = new byte[inBuffer-readOffset];
System.arraycopy(buffer, readOffset, ret, 0, ret.length);
inBuffer = 0;
@@ -252,7 +321,14 @@ public class Serial implements SerialPortEventListener {
return 0;
}
long start = System.nanoTime();
synchronized (buffer) {
long len = System.nanoTime()-start;
if (maxSyncTime < len) {
maxSyncTime = len;
}
sumSyncTime += len;
countSyncs++;
int toCopy = inBuffer-readOffset;
if (dest.length < toCopy) {
toCopy = dest.length;
@@ -273,7 +349,14 @@ public class Serial implements SerialPortEventListener {
return null;
}
long start = System.nanoTime();
synchronized (buffer) {
long len = System.nanoTime()-start;
if (maxSyncTime < len) {
maxSyncTime = len;
}
sumSyncTime += len;
countSyncs++;
// look for needle in buffer
int found = -1;
for (int i=readOffset; i < inBuffer; i++) {
@@ -304,7 +387,14 @@ public class Serial implements SerialPortEventListener {
return 0;
}
long start = System.nanoTime();
synchronized (buffer) {
long len = System.nanoTime()-start;
if (maxSyncTime < len) {
maxSyncTime = len;
}
sumSyncTime += len;
countSyncs++;
// look for needle in buffer
int found = -1;
for (int i=readOffset; i < inBuffer; i++) {
@@ -362,41 +452,72 @@ public class Serial implements SerialPortEventListener {
public void serialEvent(SerialPortEvent event) {
if (event.getEventType() == SerialPortEvent.RXCHAR) {
int toRead;
countEvents++;
if (firstEvent == 0) {
firstEvent = System.nanoTime();
}
try {
while (0 < (toRead = port.getInputBufferBytesCount())) {
long start = System.nanoTime();
// this method can be called from the context of another thread
synchronized (buffer) {
long len = System.nanoTime()-start;
if (maxReadSyncTime < len) {
maxReadSyncTime = len;
}
sumReadSyncTime += len;
// enlarge buffer if necessary
if (buffer.length < inBuffer+toRead) {
byte temp[] = new byte[buffer.length<<1];
System.arraycopy(buffer, 0, temp, 0, inBuffer);
buffer = temp;
}
if (maxBufferLength < buffer.length) {
maxBufferLength = buffer.length;
}
// read an array of bytes and copy it into our buffer
start = System.nanoTime();
byte[] read = port.readBytes(toRead);
len = System.nanoTime()-start;
if (maxReadTime < len) {
maxReadTime = len;
}
sumReadTime += len;
if (maxRead < read.length) {
maxRead = read.length;
}
sumRead += read.length;
countReads++;
System.arraycopy(read, 0, buffer, inBuffer, read.length);
inBuffer += read.length;
if (serialEventMethod != null) {
if ((0 < bufferUntilSize && bufferUntilSize <= inBuffer-readOffset) ||
(0 == bufferUntilSize && bufferUntilByte == buffer[inBuffer-1])) {
try {
// serialEvent() is invoked in the context of the current (serial) thread
// which means that serialization and atomic variables need to be used to
// guarantee reliable operation (and better not draw() etc..)
// serialAvailable() does not provide any real benefits over using
// available() and read() inside draw - but this function has no
// thread-safety issues since it's being invoked during pre in the context
// of the Processing applet
serialEventMethod.invoke(parent, new Object[] { this });
} catch (Exception e) {
System.err.println("Error, disabling serialEvent() for "+port.getPortName());
System.err.println(e.getLocalizedMessage());
serialEventMethod = null;
}
if (serialEventMethod != null) {
if ((0 < bufferUntilSize && bufferUntilSize <= inBuffer-readOffset) ||
(0 == bufferUntilSize && bufferUntilByte == buffer[inBuffer-1])) {
try {
// serialEvent() is invoked in the context of the current (serial) thread
// which means that serialization and atomic variables need to be used to
// guarantee reliable operation (and better not draw() etc..)
// serialAvailable() does not provide any real benefits over using
// available() and read() inside draw - but this function has no
// thread-safety issues since it's being invoked during pre in the context
// of the Processing applet
start = System.nanoTime();
serialEventMethod.invoke(parent, new Object[] { this });
long len = System.nanoTime()-start;
if (maxFuncTime < len) {
maxFuncTime = len;
}
sumFuncTime += len;
countFuncs++;
} catch (Exception e) {
System.err.println("Error, disabling serialEvent() for "+port.getPortName());
System.err.println(e.getLocalizedMessage());
serialEventMethod = null;
}
}
invokeSerialAvailable = true;
}
invokeSerialAvailable = true;
}
} catch (SerialPortException e) {
throw new RuntimeException("Error reading from serial port " + e.getPortName() + ": " + e.getExceptionType());
@@ -439,7 +560,14 @@ public class Serial implements SerialPortEventListener {
public void write(byte[] src) {
try {
// this might block if the serial device is not yet ready (esp. tty devices under OS X)
long start = System.nanoTime();
port.writeBytes(src);
long len = System.nanoTime()-start;
if (maxWriteTime < len) {
maxWriteTime = len;
}
sumWriteTime += len;
countWrites++;
// we used to call flush() here
} catch (SerialPortException e) {
throw new RuntimeException("Error writing to serial port " + e.getPortName() + ": " + e.getExceptionType());
@@ -449,7 +577,14 @@ public class Serial implements SerialPortEventListener {
public void write(int src) {
try {
long start = System.nanoTime();
port.writeInt(src);
long len = System.nanoTime()-start;
if (maxWriteTime < len) {
maxWriteTime = len;
}
sumWriteTime += len;
countWrites++;
} catch (SerialPortException e) {
throw new RuntimeException("Error writing to serial port " + e.getPortName() + ": " + e.getExceptionType());
}
@@ -458,7 +593,14 @@ public class Serial implements SerialPortEventListener {
public void write(String src) {
try {
long start = System.nanoTime();
port.writeString(src);
long len = System.nanoTime()-start;
if (maxWriteTime < len) {
maxWriteTime = len;
}
sumWriteTime += len;
countWrites++;
} catch (SerialPortException e) {
throw new RuntimeException("Error writing to serial port " + e.getPortName() + ": " + e.getExceptionType());
}