mirror of https://github.com/contiki-ng/mspsim
added profiling of events and added event system
git-svn-id: https://mspsim.svn.sourceforge.net/svnroot/mspsim/mspsim@451 23d1a52b-0c3c-0410-b72d-8f29ab48fe35
This commit is contained in:
parent
0ba734ffcb
commit
b5da4d2acf
|
|
@ -45,6 +45,7 @@ Run the default example on the Sky node emulator by typing:
|
|||
- Emulates some external hardware such as TR1001 and CC2420.
|
||||
- Command Line Interface, CLI, for setting up breakpoints and output
|
||||
to files or windows.
|
||||
- GDB remote debugging support (initial)
|
||||
|
||||
* What is emulated of the MSP430
|
||||
- CPU (instruction level simulation)
|
||||
|
|
|
|||
|
|
@ -628,10 +628,13 @@ public class CC2420 extends Chip implements USARTListener, RFListener {
|
|||
if(txfifoFlush) {
|
||||
txCursor = 0;
|
||||
txfifoFlush = false;
|
||||
}
|
||||
}
|
||||
if (DEBUG) log("Writing data: " + data + " to tx: " + txCursor);
|
||||
|
||||
memory[RAM_TXFIFO + txCursor++] = data & 0xff;
|
||||
if (sendEvents) {
|
||||
sendEvent("WRITE_TXFIFO", null);
|
||||
}
|
||||
break;
|
||||
case RAM_ACCESS:
|
||||
if (pos == 0) {
|
||||
|
|
@ -707,6 +710,9 @@ public class CC2420 extends Chip implements USARTListener, RFListener {
|
|||
(stateMachine == RadioState.RX_WAIT)) {
|
||||
status |= STATUS_TX_ACTIVE;
|
||||
setState(RadioState.TX_CALIBRATE);
|
||||
if (sendEvents) {
|
||||
sendEvent("STXON", null);
|
||||
}
|
||||
// Starting up TX subsystem - indicate that we are in TX mode!
|
||||
if (DEBUG) log("Strobe STXON - transmit on! at " + cpu.cycles);
|
||||
}
|
||||
|
|
@ -719,6 +725,11 @@ public class CC2420 extends Chip implements USARTListener, RFListener {
|
|||
(stateMachine == RadioState.RX_FRAME) ||
|
||||
(stateMachine == RadioState.RX_OVERFLOW) ||
|
||||
(stateMachine == RadioState.RX_WAIT)) {
|
||||
|
||||
if (sendEvents) {
|
||||
sendEvent("STXON_CCA", null);
|
||||
}
|
||||
|
||||
if(cca) {
|
||||
status |= STATUS_TX_ACTIVE;
|
||||
setState(RadioState.TX_CALIBRATE);
|
||||
|
|
|
|||
|
|
@ -39,9 +39,13 @@
|
|||
*/
|
||||
|
||||
package se.sics.mspsim.cli;
|
||||
import se.sics.mspsim.core.Chip;
|
||||
import se.sics.mspsim.core.EventListener;
|
||||
import se.sics.mspsim.core.EventSource;
|
||||
import se.sics.mspsim.core.MSP430;
|
||||
import se.sics.mspsim.core.Profiler;
|
||||
import se.sics.mspsim.util.ComponentRegistry;
|
||||
import se.sics.mspsim.util.SimpleProfiler;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -105,6 +109,56 @@ public class ProfilerCommands implements CommandBundle {
|
|||
}
|
||||
|
||||
});
|
||||
|
||||
ch.registerCommand("logevents", new BasicAsyncCommand("log events", "") {
|
||||
Chip chip;
|
||||
public int executeCommand(CommandContext context) {
|
||||
chip = cpu.getChip(context.getArgument(0));
|
||||
if (chip == null) {
|
||||
context.err.println("Can not find chip: " + context.getArgument(0));
|
||||
}
|
||||
chip.setEventListener(new EventListener() {
|
||||
public void event(EventSource source, String event, Object data) {
|
||||
System.out.println("Event:" + source.getName() + ":" + event);
|
||||
}
|
||||
});
|
||||
return 0;
|
||||
}
|
||||
public void stopCommand(CommandContext context) {
|
||||
chip.setEventListener(null);
|
||||
}
|
||||
});
|
||||
|
||||
ch.registerCommand("tagprof", new BasicCommand("profile between two events", "") {
|
||||
public int executeCommand(CommandContext context) {
|
||||
String event1 = context.getArgument(0);
|
||||
String event2 = context.getArgument(1);
|
||||
String chip1[] = event1.split("\\.");
|
||||
String chip2[] = event2.split("\\.");
|
||||
Chip chipE1 = cpu.getChip(chip1[0]);
|
||||
if (chipE1 == null) {
|
||||
context.err.println("Can not find chip: " + chip1[0]);
|
||||
}
|
||||
Chip chipE2 = cpu.getChip(chip2[0]);
|
||||
if (chipE2 == null) {
|
||||
context.err.println("Can not find chip: " + chip2[0]);
|
||||
}
|
||||
Profiler profiler = cpu.getProfiler();
|
||||
SimpleProfiler sprof = (SimpleProfiler) profiler;
|
||||
sprof.addProfileTag(context.getArgument(2), chipE1, chip1[1],
|
||||
chipE2, chip2[1]);
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
|
||||
ch.registerCommand("printtags", new BasicCommand("print tags profile", "") {
|
||||
public int executeCommand(CommandContext context) {
|
||||
Profiler profiler = cpu.getProfiler();
|
||||
SimpleProfiler sprof = (SimpleProfiler) profiler;
|
||||
sprof.printTagProfile(context.out);
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
ch.registerCommand("logcalls", new BasicAsyncCommand("log function calls", "") {
|
||||
|
|
|
|||
|
|
@ -47,9 +47,11 @@ import se.sics.mspsim.util.Utils;
|
|||
* @author Joakim
|
||||
*
|
||||
*/
|
||||
public abstract class Chip implements Loggable {
|
||||
public abstract class Chip implements Loggable, EventSource {
|
||||
|
||||
private OperatingModeListener[] omListeners;
|
||||
private EventListener eventListener;
|
||||
protected boolean sendEvents = false;
|
||||
private String[] modeNames = null;
|
||||
private int mode;
|
||||
private PrintStream log;
|
||||
|
|
@ -83,6 +85,18 @@ public abstract class Chip implements Loggable {
|
|||
modeNames = names;
|
||||
}
|
||||
|
||||
|
||||
public void setEventListener(EventListener e) {
|
||||
eventListener = e;
|
||||
sendEvents = true;
|
||||
}
|
||||
|
||||
protected void sendEvent(String event, Object data) {
|
||||
if (eventListener != null) {
|
||||
eventListener.event(this, event, data);
|
||||
}
|
||||
}
|
||||
|
||||
public String getModeName(int index) {
|
||||
if (modeNames == null) {
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
package se.sics.mspsim.core;
|
||||
|
||||
public interface EventListener {
|
||||
public void event(EventSource source, String event, Object data);
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
package se.sics.mspsim.core;
|
||||
|
||||
public interface EventSource {
|
||||
public String getName();
|
||||
}
|
||||
|
|
@ -53,11 +53,6 @@ public abstract class IOUnit implements InterruptHandler {
|
|||
|
||||
public void reset(int type) {
|
||||
}
|
||||
|
||||
// Should return the cycle it wants the next tick...
|
||||
public long ioTick(long cycles) {
|
||||
return cycles + 1000000;
|
||||
}
|
||||
|
||||
// write
|
||||
// write a value to the IO unit
|
||||
|
|
|
|||
|
|
@ -329,6 +329,7 @@ public class MSP430 extends MSP430Core {
|
|||
/* When we got the map table we can also profile! */
|
||||
if (profiler == null) {
|
||||
this.profiler = new SimpleProfiler();
|
||||
this.profiler.setCPU(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -80,10 +80,6 @@ public class Multiplier extends IOUnit {
|
|||
this.core = core;
|
||||
}
|
||||
|
||||
public boolean needsTick() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public int read(int address, boolean word, long cycles) {
|
||||
switch (address) {
|
||||
case MPY:
|
||||
|
|
|
|||
|
|
@ -40,6 +40,9 @@
|
|||
*/
|
||||
|
||||
package se.sics.mspsim.util;
|
||||
import se.sics.mspsim.core.Chip;
|
||||
import se.sics.mspsim.core.EventListener;
|
||||
import se.sics.mspsim.core.EventSource;
|
||||
import se.sics.mspsim.core.MSP430Core;
|
||||
import se.sics.mspsim.core.Profiler;
|
||||
import java.io.PrintStream;
|
||||
|
|
@ -48,9 +51,12 @@ import java.util.Hashtable;
|
|||
import java.util.regex.Pattern;
|
||||
|
||||
|
||||
public class SimpleProfiler implements Profiler {
|
||||
public class SimpleProfiler implements Profiler, EventListener {
|
||||
|
||||
private Hashtable<MapEntry,CallEntry> profileData;
|
||||
private Hashtable<String, TagEntry> tagProfiles;
|
||||
private Hashtable<String, TagEntry> startTags;
|
||||
private Hashtable<String, TagEntry> endTags;
|
||||
private CallEntry[] callStack;
|
||||
private int cSP = 0;
|
||||
private MSP430Core cpu;
|
||||
|
|
@ -58,6 +64,9 @@ public class SimpleProfiler implements Profiler {
|
|||
|
||||
public SimpleProfiler() {
|
||||
profileData = new Hashtable<MapEntry, CallEntry>();
|
||||
tagProfiles = new Hashtable<String, TagEntry>();
|
||||
startTags = new Hashtable<String, TagEntry>();
|
||||
endTags = new Hashtable<String, TagEntry>();
|
||||
callStack = new CallEntry[2048];
|
||||
}
|
||||
|
||||
|
|
@ -113,7 +122,7 @@ public class SimpleProfiler implements Profiler {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void printProfile(PrintStream out) {
|
||||
printProfile(out, null);
|
||||
}
|
||||
|
|
@ -163,7 +172,7 @@ public class SimpleProfiler implements Profiler {
|
|||
out.println(" " + callStack[cSP - i - 1].function.getInfo());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class CallEntry implements Comparable<CallEntry> {
|
||||
MapEntry function;
|
||||
long cycles;
|
||||
|
|
@ -177,7 +186,88 @@ public class SimpleProfiler implements Profiler {
|
|||
}
|
||||
}
|
||||
|
||||
private static class TagEntry implements Comparable<TagEntry> {
|
||||
String tag;
|
||||
long cycles;
|
||||
long lastCycles;
|
||||
int calls;
|
||||
|
||||
public int compareTo(TagEntry o) {
|
||||
long diff = o.cycles - cycles;
|
||||
if (diff > 0) return 1;
|
||||
if (diff < 0) return -1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void setLogger(PrintStream out) {
|
||||
logger = out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Tag profiling.
|
||||
*/
|
||||
public void measureStart(String tag) {
|
||||
TagEntry tagEntry = tagProfiles.get(tag);
|
||||
if (tagEntry == null) {
|
||||
tagEntry = new TagEntry();
|
||||
tagEntry.tag = tag;
|
||||
tagProfiles.put(tag, tagEntry);
|
||||
}
|
||||
/* only the first occurrence of event will set the lastCycles */
|
||||
if (tagEntry.lastCycles == 0) {
|
||||
tagEntry.lastCycles = cpu.cycles;
|
||||
}
|
||||
}
|
||||
|
||||
public void measureEnd(String tag) {
|
||||
TagEntry tagEntry = tagProfiles.get(tag);
|
||||
if (tagEntry != null) {
|
||||
if (tagEntry.lastCycles != 0) {
|
||||
tagEntry.calls++;
|
||||
tagEntry.cycles += cpu.cycles - tagEntry.lastCycles;
|
||||
tagEntry.lastCycles = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void printTagProfile(PrintStream out) {
|
||||
TagEntry[] entries = tagProfiles.values().toArray(new TagEntry[tagProfiles.size()]);
|
||||
Arrays.sort(entries);
|
||||
for (int i = 0; i < entries.length; i++) {
|
||||
TagEntry entry = entries[i];
|
||||
System.out.println(entry.tag + "\t" + entry.calls + "\t" + entry.cycles);
|
||||
}
|
||||
}
|
||||
|
||||
public void addProfileTag(String tag, Chip chip, String start,
|
||||
Chip chip2, String end) {
|
||||
System.out.println("Add profile: " + tag +
|
||||
" start: " + start + " end: " + end);
|
||||
TagEntry tagEntry = new TagEntry();
|
||||
tagEntry.tag = tag;
|
||||
startTags.put(start, tagEntry);
|
||||
endTags.put(end, tagEntry);
|
||||
tagProfiles.put(tag, tagEntry);
|
||||
chip.setEventListener(this);
|
||||
chip2.setEventListener(this);
|
||||
}
|
||||
|
||||
public void event(EventSource source, String event, Object data) {
|
||||
TagEntry tagEntry = null;
|
||||
if ((tagEntry = startTags.get(event)) != null) {
|
||||
/* only the first occurrence of event will set the lastCycles */
|
||||
if (tagEntry.lastCycles == 0) {
|
||||
tagEntry.lastCycles = cpu.cycles;
|
||||
}
|
||||
} else if ((tagEntry = endTags.get(event)) != null) {
|
||||
if (tagEntry.lastCycles != 0) {
|
||||
tagEntry.calls++;
|
||||
tagEntry.cycles += cpu.cycles - tagEntry.lastCycles;
|
||||
tagEntry.lastCycles = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue