SmallNetwork

advertisement
SmallNetwork
import no.uio.ifi.gruns.*;
import no.uio.ifi.gruns.infiniband.*;
import
import
import
import
java.text.DateFormat;
java.util.Date;
java.util.HashMap;
java.util.Iterator;
import java.io.*;
/**
* A small IBA-network to thoroughly test the no.uio.ifi.gruns.infiniband
* classes. Sends only unidirectionally, the network is only connected from
* left to right and top to down, not the other way around.
*/
public class SmallNetwork {
public static final int STOP_TIME = 500000;
public static final String LOG_FILE =
"/tmp/erikbra_no.uio.ifi.gruns_run.log";
public static boolean verbose = false;
public static final Kernel kernel = new Kernel(STOP_TIME);
// The switches in our network
public static IBASwitch[] ibasw;
public static java.text.DateFormat df =
DateFormat.getTimeInstance(DateFormat.LONG);
public static long realStartTime, realStopTime;
public static void preInfo(){
realStartTime = System.currentTimeMillis();
Reporter.println("Started
simulation of "+Utils.formatNumber(STOP_TIME)+
" time units. Time is "+
df.format(new Date(realStartTime)));
Reporter.println("Press
Crtl-C to stop simulation on the "+
"current time step.");
}
public static void postInfo(){
realStopTime = System.currentTimeMillis();
Reporter.getOutputStream().flush();
Reporter.println();
Reporter.println("Finished
simulation of "+
kernel.currentTime()+" time units.
df.format(new Date(realStopTime)));
Time is "+
long timeUsed = realStopTime - realStartTime;
Reporter.println("Total
Reporter.println();
time used: "+Utils.timeFormat(timeUsed));
// Avoid returning an error value because Crtl-C is pressed.
// It’s perfectly legal to stop the simulation before it’s finished.
Runtime.getRuntime().halt(0);
}
public static void main(String [] args){
FileOutputStream outFile = null;
long realStartTime, realStopTime;
Reporter.setOutputStream(System.out);
/*
try{
outFile = new FileOutputStream(LOG_FILE);
Reporter.setOutputStream(new PrintStream(outFile));
1
}catch(FileNotFoundException fnfe){
System.err.println("Error creating log file "+LOG_FILE);
}
*/
// Print out some info before we start
preInfo();
// Make sure there’s _some_ sensible output
// if the simulation is aborted.
Runtime.getRuntime().addShutdownHook(new Thread(){
public void run(){
SmallNetwork.postInfo();
}});
try{
IBAConnectionTools.setKernel(kernel);
//
buildNetwork();
gridNetwork();
}catch(RuntimeException e){
Reporter.println("RuntimeException occured!");
// Print out some info about the unit that crashed
if (kernel.currentUnit() != null){
Reporter.println("kernel.currentUnit = "+
((Reporting)kernel.currentUnit()).report());
}
e.printStackTrace(Reporter.getOutputStream());
}
// Print out some summarizing info
postInfo();
// Close the output file
if (outFile != null){
try{
outFile.close();
}catch(IOException ioe){
System.err.println("Error
closing log file: "+LOG_FILE);
}
}
}
public static void gridNetwork(){
int height = 4;
int width = 4;
int numVLs = 2;
int inputBufferSize = 4 * Integer.parseInt(System.getProperty("infiniband.EXP_PACKET_SIZE"));
int outputBufferSize = 4 * Integer.parseInt(System.getProperty("infiniband.EXP_PACKET_SIZE"));
IBASourceNode[] ibas = new IBASourceNode[height];
IBADrainNode ibad;
// DEBUG
long freeMem;
Reporter.println();
System.gc();
freeMem = Runtime.getRuntime().freeMemory();
Reporter.debugln("Free
Memory before allocation: \t"+
Utils.formatNumber(Runtime.getRuntime().freeMemory()/(1024))+"
//
// DO NOT REMOVE!!
ibasw = IBAConnectionTools.simplexGrid(height, width, numVLs,
inputBufferSize, outputBufferSize);
//
// DEBUG
Reporter.debugln("Size
of grid ("+height+"x"+width+"): \t\t"+
2
kB");
Utils.formatNumber((freeMem-Runtime.getRuntime().freeMemory())/(1024))+"
kB");
System.gc();
freeMem = Runtime.getRuntime().freeMemory();
"jalla", kernel);
of switch: \t\t\t"+
//Utils.formatNumber((freeMem-Runtime.getRuntime().freeMemory()))+" B");
Utils.formatNumber(((freeMem-Runtime.getRuntime().freeMemory())/1024))+" kB");
IBASwitch test = new IBASwitch(3, 3, numVLs, inputBufferSize, outputBufferSize,
Reporter.debugln("Size
System.gc();
freeMem = Runtime.getRuntime().freeMemory();
Link link = new Link(kernel);
Reporter.debugln("Size
of link: \t\t\t"+
//Utils.formatNumber((freeMem-Runtime.getRuntime().freeMemory()))+" B");
Utils.formatNumber(((freeMem-Runtime.getRuntime().freeMemory())/1024))+" kB");
System.gc();
freeMem = Runtime.getRuntime().freeMemory();
"Test source", kernel);
of source node: \t\t"+
//Utils.formatNumber((freeMem-Runtime.getRuntime().freeMemory()))+" B");
Utils.formatNumber(((freeMem-Runtime.getRuntime().freeMemory())/1024))+" kB");
IBASourceNode s = new IBASourceNode(1, numVLs,
Reporter.debugln("Size
System.gc();
freeMem = Runtime.getRuntime().freeMemory();
"Test drain", kernel);
of drain node: \t\t"+
//Utils.formatNumber((freeMem-Runtime.getRuntime().freeMemory()))+" B");
Utils.formatNumber(((freeMem-Runtime.getRuntime().freeMemory())/1024))+" kB");
IBADrainNode d = new IBADrainNode(1, numVLs,
Reporter.debugln("Size
System.gc();
freeMem = Runtime.getRuntime().freeMemory();
IBAPacket p = new IBAPacket();
p.lrh.setLNH(IBAPacket.LNH_IBA_local);
p.bth.setOpCode(IBAPacket.RD_SEND_ONLY);
StringBuffer str = new StringBuffer();
int numChars = Integer.parseInt(System.getProperty("infiniband.EXP_PAYLOAD_SIZE"));
for (int i=0; i < numChars; i++){
str.append((char) ((int) ’A’));
}
p.pyld.setContent(str.toString().getBytes());
p.updatePacketLength();
Reporter.debugln("Size
of IBA packet: \t\t"+
Utils.formatNumber((freeMem-Runtime.getRuntime().freeMemory()))+"
B");
//Utils.formatNumber(((freeMem-Runtime.getRuntime().freeMemory())/1024))+" kB");
System.gc();
Reporter.debugln("Free
Memory after allocation: \t"+
Utils.formatNumber(Runtime.getRuntime().freeMemory()/(1024))+"
Reporter.println();
//
kB");
System.exit(0);
//
// Connect source nodes
for (int i=0; i < height; i++){
ibas[i] = new IBASourceNode(1, numVLs,
"Source "+(i+1),
kernel);
ibas[i].setOwnAddress("1."+(i+1));
IBAConnectionTools.connect(ibas[i], 0, ibasw[i*width], 1);
}
// Drain node
ibad = new IBADrainNode(1, numVLs, "Drain 1", kernel);
IBAConnectionTools.connect(ibasw[7], 1, ibad, 0);
// Configure each path
int blocksPerPacket = (int) Math.ceil(((double)Integer.parseInt(System.getProperty("infiniband.EXP_PACKET_SIZE")))/
Integer.parseInt(System.getProperty("infiniband.BLOCK_SIZE")));
// Path 1 (from Source 1 to Drain 1)
3
ibas[0].addDestinationAddresses("2.1");
ibas[0].addRoutingInterval("2.1", 0);
ibas[0].addHighPriority(0,0,1);
// For debugging
ibas[0].addHighPriority(0,1,1);
ibasw[0].addRoutingInterval("2.1",1);
ibasw[1].addRoutingInterval("2.1",1);
ibasw[2].addRoutingInterval("2.1",2);
ibasw[6].addRoutingInterval("2.1",1);
ibasw[7].addRoutingInterval("2.1",1);
// Path 2 (from Source 3 to Drain 1)
ibas[2].addDestinationAddresses("2.1");
ibas[2].addRoutingInterval("2.1", 0);
ibas[2].addHighPriority(0,1,1);
// For debugging
ibas[2].addHighPriority(0,0,1);
ibasw[8].addRoutingInterval("2.1",1);
ibasw[9].addRoutingInterval("2.1",1);
ibasw[10].addRoutingInterval("2.1",0);
// Priorities
/*
ibasw[8].addHighPriority(1,1,1);
ibasw[9].addHighPriority(1,1,1);
ibasw[10].addHighPriority(0,1,1);
ibasw[6].addLowPriority(1,1,1);
ibasw[7].addLowPriority(1,1,1);
*/
/*
ibasw[0].addHighPriority(1,0,1);
ibasw[1].addHighPriority(1,0,1);
ibasw[2].addHighPriority(2,0,1);
ibasw[6].addHighPriority(1,0,1);
ibasw[7].addHighPriority(1,0,1);
*/
for (int i=0; i < ibasw.length; i++){
// Configure weights on output ports on the switches.
for (int j=0; j < 3; j++){
for (int k=0; k < numVLs/2; k++){
ibasw[i].addLowPriority(j, k, 1);
}
for
(int k=numVLs/2; k < numVLs; k++){
ibasw[i].addHighPriority(j, k, 1);
}
// limit of high priority
//ibasw[i].setLimitOfHighPriority(j, 1 * blocksPerPacket);
}
}
//
//
ibasw[6].setLimitOfHighPriority(1, 10 * blocksPerPacket);
ibasw[7].setLimitOfHighPriority(1, 10 * blocksPerPacket);
ibasw[6].setLimitOfHighPriority(1, 255);
ibasw[7].setLimitOfHighPriority(1, 255);
// Set service level
ibas[0].setSL(0);
4
ibas[2].setSL(1);
// Schedule sources
kernel.schedule(ibas[0], 0);
kernel.schedule(ibas[2], 0);
// Start simulation
kernel.simulate();
// Print out some stats
Reporter.println();
Reporter.println("Simulation
statistics:");
Reporter.println("==================================================");
// Print out report for all source nodes
for (int i=0; i < height; i++){
Reporter.println(ibas[i].report());
}
// Print out report for drain node
Reporter.println(ibad.report());
// Print out info about dropped packets
Reporter.println();
HashMap dropped = IBAStatistics.getDroppedPacketStats();
int totalDropped = 0;
if
(dropped.keySet().size() > 0){
Iterator it = dropped.keySet().iterator();
while
(it.hasNext()){
IBASourceNode node = (IBASourceNode) it.next();
totalDropped += ((Integer) dropped.get(node)).intValue();
}
}
Reporter.println("Total number
totalDropped);
of dropped packets = "+
// DEBUG
/*
Reporter.println("Switch 7:");
Reporter.println("Total number of packets scheduled:");
Reporter.println("VL 0: "+ibasw[6].outputPorts[1].getTotalNumberOfPacketsScheduled(0));
Reporter.println("VL 1: "+ibasw[6].outputPorts[1].getTotalNumberOfPacketsScheduled(1));
Reporter.println("Total number of packets sent:");
Reporter.println("VL 0: "+ibasw[6].outputPorts[1].getTotalNumberOfPacketsSent(0));
Reporter.println("VL 1: "+ibasw[6].outputPorts[1].getTotalNumberOfPacketsSent(1));
Reporter.println("Switch 8:");
Reporter.println("Total number of packets scheduled:");
Reporter.println("VL 0: "+ibasw[7].outputPorts[1].getTotalNumberOfPacketsScheduled(0));
Reporter.println("VL 1: "+ibasw[7].outputPorts[1].getTotalNumberOfPacketsScheduled(1));
Reporter.println("Total number of packets sent:");
Reporter.println("VL 0: "+ibasw[7].outputPorts[1].getTotalNumberOfPacketsSent(0));
Reporter.println("VL 1: "+ibasw[7].outputPorts[1].getTotalNumberOfPacketsSent(1));
*/
}
public static void buildNetwork(){
int i;
int
int
int
int
int
numSourceNodes = 2;
numDrainNodes[] = {2,1};
numVirtualLanes = 1;
numIngressSwitches = 2;
numSwitches = numIngressSwitches + 2;
IBADrainNode[] ibad1 = new IBADrainNode[numDrainNodes[0]];
IBADrainNode[] ibad2 = new IBADrainNode[numDrainNodes[1]];
IBASourceNode[][] ibas = new IBASourceNode[2][numSourceNodes];
ibasw = new IBASwitch[numSwitches];
5
Link tmpLink;
IBAConnectionTools.setKernel(kernel);
// First and second Switch
for
(int j=0; j < numIngressSwitches; j++){
ibasw[j] = new IBASwitch(numSourceNodes,
2, numVirtualLanes,
kernel);
"Sw"+(j+1),
ibasw[j].addRoutingInterval("126.100-126.101",0);
ibasw[j].addRoutingInterval("126.102",1);
ibasw[j].addHighPriority(0, 0, 1);
ibasw[j].addHighPriority(1, 0, 1);
for
(i=0; i < numSourceNodes; i++){
ibas[j][i] = new IBASourceNode(1,1,"I"+(j+1)+","+
"S"+(i+1),
kernel);
ibas[j][i].setOwnAddress("127."+(j*10)+i);
ibas[j][i].addDestinationAddresses("126.100-126.102");
ibas[j][i].addRoutingInterval("126.100-126.102", 0);
ibas[j][i].addHighPriority(0, 0, 1);
IBAConnectionTools.connect(ibas[j][i], 0,
ibasw[j], i);
kernel.schedule(ibas[j][i], 0);
}
}
// Third Switch
ibasw[2] =
new IBASwitch(2,
2, numVirtualLanes,
kernel);
"Sw3",
ibasw[2].addRoutingInterval("126.100",0);
ibasw[2].addHighPriority(0, 0, 1);
ibasw[2].addRoutingInterval("126.101",1);
ibasw[2].addHighPriority(1, 0, 1);
// Fourth Switch
ibasw[3] = new IBASwitch(2,
2, numVirtualLanes,
kernel);
"Sw4",
ibasw[3].addRoutingInterval("126.102",0);
ibasw[3].addHighPriority(0, 0, 1);
// Connect switches
IBAConnectionTools.connect(ibasw[0],
IBAConnectionTools.connect(ibasw[0],
IBAConnectionTools.connect(ibasw[1],
IBAConnectionTools.connect(ibasw[1],
0,
1,
0,
1,
ibasw[2],
ibasw[3],
ibasw[2],
ibasw[3],
0);
0);
1);
1);
// Drain nodes
for
(i=0; i < numDrainNodes[0]; i++){
ibad1[i] = new IBADrainNode(1, 1, "E1,D"+(i+1), kernel);
IBAConnectionTools.connect(ibasw[2], i, ibad1[i], 0);
}
for
(i=0; i < numDrainNodes[1]; i++){
ibad2[i] = new IBADrainNode(1, 1, "E2,D"+(i+1), kernel);
IBAConnectionTools.connect(ibasw[3], i, ibad2[i], 0);
}
// Start simulation
kernel.simulate();
// Print out some stats
6
Reporter.println();
Reporter.println("Simulation
statistics:");
Reporter.println("==================================================");
// Print out report for all source nodes
for (int j=0; j < numIngressSwitches; j++){
for (i=0; i < numSourceNodes; i++){
Reporter.println(ibas[j][i].report());
}
}
// Print out report for all drain nodes
for (i=0; i < numDrainNodes[0]; i++){
Reporter.println(ibad1[i].report());
}
for
(i=0; i < numDrainNodes[1]; i++){
Reporter.println(ibad2[i].report());
}
// Print out info about dropped packets
Reporter.println();
Reporter.println("Dropped packets: ");
HashMap dropped = IBAStatistics.getDroppedPacketStats();
if
(dropped.keySet().size() > 0){
Iterator it = dropped.keySet().iterator();
while
(it.hasNext()){
String id = (String) it.next();
Reporter.println("Node \""+id+"\": number of dropped
((Integer) dropped.get(id)).toString());
}
}
else{
Reporter.println("No
dropped packets. Nice work! ;)");
}
}
}
7
packets: "+
IBAUnitComparatorTest
import no.uio.ifi.gruns.*;
import no.uio.ifi.gruns.infiniband.*;
public class IBAUnitComparatorTest {
public static void main(String [] args) {
String[] sources = new String[150];
Kernel kernel = new Kernel(0);
IBAUnitComparator comp = new IBAUnitComparator();
for (int i=0; i < sources.length; i++) {
sources[i] = "1."+i;
}
//comp.compare(sources[0], sources[1]);
for (int i=0; i < sources.length; i++) {
int compVal = comp.compare(sources[75], sources[i]);
System.err.println("sources[75] is "+
(compVal < 0 ?
"smaller than":
compVal == 0 ?
"equal to":
"bigger than")+
" sources["+i+"].");
}
}
}
8
GrunsTest
import no.uio.ifi.gruns.*;
import no.uio.ifi.gruns.infiniband.*;
import
import
import
import
java.text.DateFormat;
java.util.Date;
java.util.HashMap;
java.util.Iterator;
import java.io.*;
/**
* This class is just made for testing the classes
* in the no.uio.ifi.gruns package separately.
*/
public class GrunsTest {
public static final int STOP_TIME = 5000000;
public static final String LOG_FILE =
"/tmp/erikbra_no.uio.ifi.gruns_run.log";
public static boolean verbose = false;
public static final Kernel kernel = new Kernel(STOP_TIME);
public static java.text.DateFormat df = DateFormat.getTimeInstance(DateFormat.LONG);
public static long realStartTime, realStopTime;
public static IBASourceNode[] ibas;
public static IBASwitch[] ibasw;
public static IBADrainNode[] ibad;
public static void preInfo(){
realStartTime = System.currentTimeMillis();
Reporter.println("Started simulation of "+STOP_TIME+"
df.format(new Date(realStartTime)));
Reporter.println("Press
time units. Time is "+
Crtl-C to stop simulation on the current time step.");
}
public static void postInfo(){
realStopTime = System.currentTimeMillis();
Reporter.getOutputStream().flush();
// Print out some stats
Reporter.println();
Reporter.println("Simulation
statistics:");
Reporter.println("==================================================");
// Print out report for all source nodes
for (int i=0; i < ibas.length; i++){
Reporter.println(ibas[i].report());
}
// Print out report for drain nodes
for (int i=0; i < ibad.length; i++){
Reporter.println(ibad[i].report());
}
// Print out info about dropped packets
Reporter.println();
HashMap dropped = IBAStatistics.getDroppedPacketStats();
int totalDropped = 0;
if
(dropped.keySet().size() > 0){
Iterator it = dropped.keySet().iterator();
while
(it.hasNext()){
IBASourceNode node = (IBASourceNode) it.next();
totalDropped += ((Integer) dropped.get(node)).intValue();
}
}
9
Reporter.println("Total number of dropped
Utils.formatInt(totalDropped));
packets = "+
// Simulation summary
Reporter.println();
Reporter.println("Finished simulation of "+
Utils.formatLong(kernel.currentTime())+
" time units. Time is "+
df.format(new Date(realStopTime)));
long timeUsed = realStopTime - realStartTime;
Reporter.println("Total
Reporter.println();
time used: "+Utils.timeFormat(timeUsed));
}
public static void main(String [] args){
FileOutputStream outFile = null;
long realStartTime, realStopTime;
Reporter.setOutputStream(System.out);
Reporter.setKernel(kernel);
// Initialize system properties
IBAConstants.loadProperties();
/*
try{
outFile = new FileOutputStream(LOG_FILE);
Reporter.setOutputStream(new PrintStream(outFile));
}catch(FileNotFoundException fnfe){
System.err.println("Error creating log file "+LOG_FILE);
}
*/
// Print out some info before we start
preInfo();
// Make sure there’s _some_ sensible output
// if the simulation is aborted.
Runtime.getRuntime().addShutdownHook(new Thread(){
public void run(){
GrunsTest.postInfo();
}});
try{
//
//
//
testPackets();
testRandomAddress();
testKernel();
testIBAPackets();
// testLink();
// testIBAOutputPort();
// testIBASourceNode();
//testIBASwitch();
}catch(RuntimeException e){
Reporter.println("RuntimeException occured!");
// Print out some info about the unit that crashed
if (kernel.currentUnit() != null){
Reporter.println("kernel.currentUnit = "+((Reporting)kernel.currentUnit()).report());
}
e.printStackTrace(Reporter.getOutputStream());
}
// Print out some summarizing info
postInfo();
// Close the output file
10
if
(outFile != null){
try{
outFile.close();
}catch(IOException ioe){
System.err.println("Error
closing log file: "+LOG_FILE);
}
}
}
/** Testing packets and addresses */
public static void testPackets(){
Reporter.println("IBAPacket.RD_SEND_ONLY
= "+Utils.asBitString(IBAPacket.RD_SEND_ONLY));
Reporter.println("IBAPacket.RD_TYPE = "+Utils.asBitString(IBAPacket.RD_TYPE));
new IBAPacket().bth.setOpCode(IBAPacket.RD_SEND_ONLY);
Reporter.println("\nTesting
packets and addresses");
"192.168";
"Hello World";
String addr =
String msg =
Address a = new Address(addr);
Packet p = new Packet(a, msg.getBytes());
Reporter.println("Sent
packet to\t\t"+addr+" containing \""+msg+"\"");
StringBuffer sb = new StringBuffer();
byte [] address = { p.getNextByte(), p.getNextByte() };
sb.append(new Address(address).getAddressAsString());
sb.append("
");
byte [] payload = new byte[p.getSize() - 2];
for
(int i = 0; i < p.getSize() - 2; i++){
payload[i] = p.getNextByte();
}
sb.append(new String(payload));
Reporter.println("Received packet to\t"+
new Address(address).getAddressAsString()+
" containing \""+
new String(payload)+"\"");
}
/** Testing IBA Packets */
public static void testIBAPackets(){
Address localAddress = new Address("127.100");
Address destination = new Address("127.101");
IBAPacket p = new IBAPacket(destination, localAddress);
// Tell that this packet is a local packet
p.lrh.setLNH(IBAPacket.LNH_IBA_local);
// Make this a "Send Only" packet.
p.bth.setOpCode(IBAPacket.RD_SEND_ONLY);
p.lrh.setVL(5);
p.lrh.setSL(14);
StringBuffer str = new StringBuffer();
// Fill up with a random number of random characters
//
int numChars = random.nextInt(2000);
// Use fixed number instead, for predicatability
int numChars = Integer.parseInt(System.getProperty("infiniband.EXP_PAYLOAD_SIZE"));
for (int i=0; i < numChars; i++){
// Should be a random character between A and Z
//str.append((char) ((int) ’A’ + random.nextInt(26)));
11
str.append(’A’);
}
p.pyld.setContent(str.toString().getBytes());
p.updatePacketLength();
p.lrh.setVL(5);
p.lrh.setLVer(13);
p.lrh.setSL(14);
Reporter.println("p.lrh.VL
= "+p.lrh.VL());
= "+p.lrh.LVer());
Reporter.println("p.lrh.SL = "+p.lrh.SL());
Reporter.println("IBAPacketParser.packetLength(p.lrh) = "+IBAPacketParser.packetLength(p.lrh));
Reporter.println("p.lrh.PktLen() = "+p.lrh.PktLen());
Reporter.println("p.getSize() = "+p.getSize());
Reporter.println("p.getContent().length = "+p.getContent().length);
Reporter.println("p.lrh.LVer
}
/** Testing link */
public static void testLink(){
Link l = new Link(kernel);
byte[] source = {1,2,3,4,5,6,7,8};
byte[] copy = new byte[source.length];
for
(int i=0; i < source.length; i++){
l.sendByte(source[i]);
}
l.act();
for
(int i=0; i < copy.length; i++){
copy[i] = l.receiveByte();
}
Reporter.print("source
for
= {");
(int i=0; i < source.length-1; i++){
Reporter.print(source[i]+",");
}
Reporter.print(source[source.length-1]+"}");
Reporter.println();
Reporter.print("copy
for
= {");
(int i=0; i < copy.length-1; i++){
Reporter.print(copy[i]+",");
}
Reporter.print(copy[copy.length-1]+"}");
Reporter.println();
}
public static void testIBASourceNode(){
if (verbose){
Reporter.println("\nTesting IBA source node");
}
int numLinks = 8;
ibad = new IBADrainNode[1];
ibad[0] = new IBADrainNode(numLinks, 1,
"D1",
kernel);
ibas = new IBASourceNode[numLinks];
Link[] links = new Link[numLinks];
for
(int i=0; i < numLinks; i++){
ibas[i] = new IBASourceNode(1,1,"S"+i, kernel);
ibas[i].setOwnAddress("127."+(50+i));
ibas[i].addDestinationAddresses("126.100-126.110");
ibas[i].addRoutingInterval("126.100-126.110", 0);
ibas[i].addHighPriority(0, 0, 1);
links[i] = new Link(kernel);
ibas[i].attach(links[i], 0);
ibad[0].attach(links[i], i);
kernel.schedule(ibas[i], 0);
12
}
kernel.simulate();
// Print out some stats
Reporter.println();
Reporter.println("Simulation
statistics:");
Reporter.println("==================================================");
// Print out report for all source nodes
for (int i=0; i < ibas.length; i++){
Reporter.println(ibas[i].report());
}
// Print out report for drain node
Reporter.println(ibad[0].report());
}
public static void testIBASwitch(){
if (verbose){
Reporter.println("\nTesting IBA switch");
}
IBAConnectionTools.setKernel(kernel);
int numSourceNodes = 2;
int numDrainNodes = 1;
int inputBufferSize = 4 * Integer.parseInt(System.getProperty("infiniband.EXP_PACKET_SIZE"));
int outputBufferSize = 4 * Integer.parseInt(System.getProperty("infiniband.EXP_PACKET_SIZE"));
int numVirtualLanes = 2;
int numSwitches = 2;
ibad = new IBADrainNode[numDrainNodes];
ibas = new IBASourceNode[numSourceNodes];
ibasw = new IBASwitch[numSwitches];
for
(int i=0; i < numSwitches; i++){
ibasw[i] = new IBASwitch(numSourceNodes,
numDrainNodes,
numVirtualLanes,
inputBufferSize,
outputBufferSize,
"TestSwitch "+i,
kernel);
}
int bytesPerPacket = Integer.parseInt(System.getProperty("infiniband.EXP_PACKET_SIZE"));
// int limitOfHighPriority = (int) Math.ceil( ((double)
1 * bytesPerPacket) / 4096);
int limitOfHighPriority = 0;
// DEBUG
Reporter.debugln("bytes
per packet = "+bytesPerPacket);
of high pri = "+limitOfHighPriority);
Reporter.debugln("Switch processing time = "+
System.getProperty("infiniband.PACKET_PROCESSING_TIME"));
//
Reporter.debugln("limit
ibasw[0].setLimitOfHighPriority(0, limitOfHighPriority);
ibasw[1].setLimitOfHighPriority(0, limitOfHighPriority);
// Source nodes
for (int i=0; i < numSourceNodes;
i++){
ibas[i] = new IBASourceNode(1, numVirtualLanes,"Source
"+i,
kernel);
ibas[i].setOwnAddress("127."+i);
ibas[i].addDestinationAddresses("126.100-126.100");
ibas[i].addRoutingInterval("126.100-126.100", 0);
IBAConnectionTools.connect(ibas[i], 0, ibasw[0], i);
// Configure weights on output ports on the source nodes
for (int j=0; j < numVirtualLanes/2; j++){
ibas[i].addLowPriority(0, j, 1);
}
13
for
(int j=numVirtualLanes/2; j < numVirtualLanes; j++){
ibas[i].addHighPriority(0, j, 1);
}
kernel.schedule(ibas[i], 0);
}
ibas[0].setSL(0);
ibas[1].setSL(1);
//
//
ibas[2].setSL(8);
ibas[3].setSL(9);
// Configure weights on output ports on switch 1
for (int j=0; j < numVirtualLanes/2; j++){
ibasw[0].addLowPriority(0, j, 1);
}
for
(int j=numVirtualLanes/2; j < numVirtualLanes; j++){
ibasw[0].addHighPriority(0, j, 1);
}
// Connect switches
IBAConnectionTools.connect(ibasw[0], 0, ibasw[1], 0);
// Drain nodes and switch 2
for (int i=0; i < numDrainNodes; i++){
ibad[i] = new IBADrainNode(1, numVirtualLanes, "Drain
IBAConnectionTools.connect(ibasw[1], 0, ibad[i], i);
"+i,
kernel);
for
(int j=0; j < numVirtualLanes/2; j++){
ibasw[1].addLowPriority(i, j, 1);
}
for
(int j=numVirtualLanes/2; j < numVirtualLanes; j++){
ibasw[1].addHighPriority(i, j, 1);
}
}
// Configure switch with routing tables
// All to one
for (int i=0; i <
numSwitches; i++){
ibasw[i].addRoutingInterval("126.100-126.127", 0);
}
// Start simulation
kernel.simulate();
// Print out some stats
Reporter.println();
Reporter.println("Simulation
statistics:");
Reporter.println("==================================================");
// Print out report for all source nodes
for (int i=0; i < numSourceNodes; i++){
Reporter.println(ibas[i].report());
}
// Print out report for all drain nodes
for (int i=0; i < numDrainNodes; i++){
Reporter.println(ibad[i].report());
}
}
/** Testing random address generator */
public static void testRandomAddress(){
int NUM_ITERATIONS=10000;
Address [] addresses = { new Address("0.0"),
new Address("0.1"),
new Address("120.138"),
new Address("255.255"),
new Address("192.168"),
new Address("129.240")
14
};
int [] results = new int[addresses.length];
Reporter.println("\nTesting Random
NUM_ITERATIONS+
Address generator on "+
" iterations.");
Address a;
for
(int i = 0; i < NUM_ITERATIONS; i++){
a = RandomAddress.nextAddress(addresses);
for (int j = 0; j < addresses.length; j++){
if (a.getAddress() == addresses[j].getAddress()){
results[j]++;
}
}
//
Reporter.println("Iteration "+i+", address "+a.getAddressAsString());
}
Reporter.println("Address\t\tNumber
for
of times returned");
(int i=0; i < addresses.length; i++){
Reporter.println(addresses[i]+"\t\t"+results[i]);
}
}
public static void testKernel(){
/*
final int TIME = 1000 ;
Scheduleable[] tmpUnit = new Scheduleable[3];
Reporter.println("\nTesting Kernel scheduling with "+
TIME +
" time units.");
Kernel k = new Kernel(TIME);
for (int i=0; i < 3; i++){
tmpUnit[i] = new Unit(kernel){
public void act(){
Reporter.println("Scheduled for running on time "+
nextTimeScheduled);
}};
}
for (int i=0; i < TIME; i+=3){
k.schedule(tmpUnit[0], i);
}
for (int i=1; i < TIME; i+=2){
k.schedule(tmpUnit[1], i);
}
for (int i=78; i < TIME; i+=1){
k.schedule(tmpUnit[2], i);
}
15
k.simulate(); */
}
public static void testIBAOutputPort(){
int
int
int
int
N=1010;
numVLs = 10;
pyldSize = 500;
numHighPriPackets = 2;
int[] droppedPackets = new int[numVLs];
float pktSizeInUnits = ((float)(pyldSize + 38)) / Integer.parseInt(System.getProperty("infiniband.BLOCK_SIZE"));
IBAOutputPort outputPort;
IBADrainNode drainNode;
IBAPacket packet;
java.util.Random random = new java.util.Random();
outputPort = new IBAOutputPort(numVLs, kernel);
outputPort.setID("TestOutputPort");
int n;
for
(n = 0; n < 1; n++){
outputPort.addHighPriority(n,1);
}
for
(int m = n; m < numVLs; m++){
outputPort.addLowPriority(m,1);
}
//int limitOfHighPriority = (int)Math.ceil(pktSizeInUnits)*numHighPriPackets;
int limitOfHighPriority = 255;
//
Reporter.debugln("limitOfHighPriority = "+limitOfHighPriority);
outputPort.setLimitOfHighPriority(limitOfHighPriority);
drainNode = new IBADrainNode(1, numVLs,
"TestDrain",
kernel);
// connect the output port and the drain node
Link l = new Link(kernel);
drainNode.attach(l, 0);
outputPort.attach(l);
Address destAddr = new Address("127.110");
Address sourceAddr;
for (int i=0; i <
for (int j=0;
N; i++){
j < numVLs; j++){
sourceAddr = new Address("127."+(100+j));
// Make a packet to the specified address
packet = new IBAPacket(destAddr,sourceAddr);
// Tell that this packet is a local packet
packet.lrh.setLNH(IBAPacket.LNH_IBA_local);
// Make this a "Send Only" packet.
packet.bth.setOpCode(IBAPacket.RD_SEND_ONLY);
packet.lrh.setVL(j);
packet.lrh.setSL(j);
StringBuffer str = new StringBuffer();
// Fill up with a random number of random characters
//
int numChars = random.nextInt(2000);
// Use fixed number instead, to find errors
int numChars = pyldSize;
for (int k=0; k < numChars; k++){
// Should be a random character between A and Z
str.append((char) ((int) ’A’ + random.nextInt(26)));
}
packet.pyld.setContent(str.toString().getBytes());
packet.updatePacketLength();
if
(outputPort.canSend(j, IBAPacketParser.packetLength(packet.lrh))){
outputPort.sendIBAPacket(packet, j);
}else{
droppedPackets[j]++;
16
}
}
kernel.schedule(outputPort, i);
}
kernel.simulate();
// Print out status
Reporter.println(drainNode.report());
Reporter.println("Dropped
for
stats:");
(int i=0; i < droppedPackets.length; i++){
Reporter.println("VL
"+i+": "+droppedPackets[i]);
}
}
}
17
Main
// {{{
import no.uio.ifi.gruns.*;
import no.uio.ifi.gruns.infiniband.*;
import
import
import
import
java.text.DateFormat;
java.util.Date;
java.util.HashMap;
java.util.Iterator;
import java.io.*;
import javax.swing.*;
import no.uio.ifi.gruns.gui.*;
// For displaying host name on the gui title line.
import java.net.InetAddress;
/**
* The main program that connects all the classes in the
* no.uio.ifi.gruns packages to form a network simulator.
*/
public class Main {
// {{{ Public static variables
public static final int STOP_TIME = 200000;
public static boolean verbose = false;
public static Kernel kernel;
/* The core switches in our network */
public static IBASwitch[] coreIbaSw;
/* The edge switches in our network */
public static IBASwitch[] edgeIbaSw;
/* The source nodes in our network */
public static IBASourceNode[] ibas;
/* The drain nodes in our network */
public static IBADrainNode[] ibad;
// Used to connect source and
public static final int WEST
public static final int NORTH
public static final int EAST
public static final int SOUTH
drain nodes
= 0;
= 1;
= 2;
= 3;
// }}}
/** Width of the switch mesh */
public static int width = 4;
/** Height of the switch mesh */
public static int height = 4;
/** Size of the input buffers in switches */
public static int inputBufferSize;
18
/** Size of the output buffers in switches */
public static int outputBufferSize;
/** Number of virtual lanes used */
public static int numberOfVLs;
/** Number of ports on the source nodes */
public static int numberOfPortsOnSourceNodes;
/** Number of ports on the drain nodes */
public static int numberOfPortsOnDrainNodes;
public static java.text.DateFormat df =
DateFormat.getTimeInstance(DateFormat.LONG);
public static long realStartTime, realStopTime;
/** Indicates whether we should display the gui */
public static boolean guiIsEnabled = false;
// {{{ preInfo()
public static void preInfo(){
realStartTime = System.currentTimeMillis();
Reporter.setStartTime(realStartTime);
Reporter.println("Started simulation of "+Utils.formatLong(STOP_TIME)+
" time units. Time is "+
df.format(new Date(realStartTime)));
Reporter.println("Press Crtl-C to stop simulation on the "+
"current time step.");
}
// }}}
// {{{ postInfo()
public static void postInfo(){
realStopTime = Reporter.stopTime();
// Won’t update this in Kernel if we are aborted with
// Ctrl-C or equivalents, so we have to register it here
// instead.
if (realStopTime == 0) {
realStopTime = System.currentTimeMillis();
}
Reporter.getOutputStream().flush();
if (! guiIsEnabled) {
// Print out some stats
Reporter.println();
Reporter.println("Simulation statistics:");
Reporter.println("========================="+
"=========================");
// Print out report for all source nodes
for (int i=0; i < ibas.length; i++){
Reporter.println(ibas[i].report());
}
// Print out report for drain nodes
String report = null;
for (int i=0; i < ibad.length; i++){
report = ibad[i].report();
if (report != null) {
Reporter.println(report);
}
}
19
// Print out info about dropped packets
Reporter.println();
HashMap dropped = IBAStatistics.getDroppedPacketStats();
int totalDropped = 0;
if (dropped.keySet().size() > 0){
Iterator it = dropped.keySet().iterator();
while (it.hasNext()){
IBASourceNode node = (IBASourceNode) it.next();
totalDropped += ((Integer) dropped.get(node)).intValue();
}
}
}
// Simulation summary
Reporter.println();
Reporter.println("Finished simulation of "+
Utils.formatLong(kernel.currentTime())+
" time units. Time is "+
df.format(new Date(realStopTime)));
long timeUsed = realStopTime - realStartTime;
Reporter.println("Total time used: "+Utils.timeFormat(timeUsed));
Reporter.println();
}
// }}}
// {{{ public static void gui()
public static void gui() {
String localhost;
try {
localhost = InetAddress.getLocalHost().getHostName();
} catch (java.net.UnknownHostException uhe) {
localhost = "localhost";
}
JFrame f = new JFrame("GRUNS - GRand Unified Network Simulator "+
" - Running on "+localhost);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
/*
StatusPanel panel = new
StatusPanel(width*2 + (height-2)*2, // Source nodes
width*2 + (height-2)*2, // Drain nodes
width*2 + (height-2)*2, // Edge switches
width * height,
// Core switches
realStartTime);
*/
int ibasLength, ibadLength, edgeLength, coreLength;
ibasLength = (ibas != null) ? ibas.length : 0;
ibadLength = (ibad != null) ? ibad.length : 0;
edgeLength = (edgeIbaSw != null) ? edgeIbaSw.length : 0;
coreLength = (coreIbaSw != null) ? coreIbaSw.length : 0;
20
StatusPanel panel = new
StatusPanel(ibasLength,
ibadLength,
edgeLength,
coreLength,
realStartTime)
;
f.getContentPane().add(panel);
f.setSize(800,600);
f.setVisible(true);
Reporter.setGuiParams(panel,
ibas,
ibad,
edgeIbaSw,
coreIbaSw
);
}
// }}}
// {{{ public static void main(String[] args)
public static void main(String [] args){
// Initialize system properties
IBAConstants.loadProperties();
// Do we want a gui?
guiIsEnabled = Boolean.getBoolean("infiniband.GUI_ENABLED");
// Use the new kernel.
int stopTime = Integer.getInteger("infiniband.STOP_TIME",
STOP_TIME).intValue();
System.setProperty("infiniband.STOP_TIME", ""+stopTime);
kernel = new NewKernel(stopTime);
Reporter.setOutputStream(System.out);
Reporter.setKernel(kernel);
IBAStatistics.setKernel(kernel);
// Print out some info before we start
preInfo();
// Make sure there’s _some_ sensible output
// if the simulation is aborted.
Runtime.getRuntime().addShutdownHook(new Thread(){
public synchronized void run(){
Main.postInfo();
// Avoid returning an error value because Crtl-C
// is pressed.
// It’s perfectly legal to stop the simulation
// before it’s finished.
Runtime.getRuntime().halt(0);
21
}});
try{
IBAConnectionTools.setKernel(kernel);
// Parse command line arguments
for (int i=0; i < args.length; i++){
if (args[i].equals("--duplexGrid")){
duplexGrid();
break;
} else if (args[i].equals("--smallPriTest")) {
smallPriTest();
} else if (args[i].equals("--aBitBiggerPriTest")) {
aBitBiggerPriTest();
}
}
}catch(RuntimeException e){
Reporter.println("RuntimeException occured!");
// Print out some info about the unit that crashed
if (kernel.currentUnit() != null){
Reporter.println("kernel.currentUnit = "+
((Reporting)kernel.currentUnit()).report());
}
e.printStackTrace(Reporter.getOutputStream());
}
}
// }}}
// {{{ public static void connectSourceAndDrain(...)
public static void connectSourceAndDrain(int numberOfPortsOnSourceNodes,
int numberOfVLs,
int numberOfPortsOnDrainNodes,
int addrPrefix,
int addrSuffix,
int currIndex,
int edge){
int edgePortNumber = -1;
switch (edge){
case WEST: edgePortNumber = 0; break;
case NORTH: edgePortNumber = 1; break;
case EAST: edgePortNumber = 2; break;
case SOUTH: edgePortNumber = 3; break;
default:
throw new java.lang.
IllegalArgumentException("Illegal edge number "+
"supplied. Value must be either "+
"WEST, NORTH, EAST or SOUTH.");
}
// Source node
ibas[addrSuffix] = new IBASourceNode(numberOfPortsOnSourceNodes,
numberOfVLs,
"Source "+(addrPrefix)+"."+
(addrSuffix),
kernel);
ibas[addrSuffix].setOwnAddress((addrPrefix)+"."+(addrSuffix));
22
// Drain node
ibad[addrSuffix] = new IBADrainNode(numberOfPortsOnDrainNodes,
numberOfVLs,
"Drain "+(addrPrefix)+"."+
(addrSuffix),
kernel);
ibad[addrSuffix].setOwnAddress((addrPrefix)+"."+(addrSuffix));
// Edge switch
edgeIbaSw[addrSuffix] = new IBASwitch(2,2,numberOfVLs,"Edge switch "+
addrSuffix,kernel);
// Connect source and drain node to edge switch
IBAConnectionTools.connect(ibas[addrSuffix], 0,
edgeIbaSw[addrSuffix], 0);
IBAConnectionTools.connect(edgeIbaSw[addrSuffix], 0 ,
ibad[addrSuffix], 0);
// Connect edge switch to core switch
IBAConnectionTools.connect(edgeIbaSw[addrSuffix], 1 ,
coreIbaSw[currIndex], edge);
IBAConnectionTools.connect(coreIbaSw[currIndex], edge ,
edgeIbaSw[addrSuffix], 1);
}
// }}}
// {{{ public static void duplexGrid()
public static void duplexGrid(){
int numberOfVLs = 2;
int inputBufferSize = 2 * Integer.parseInt(
System.getProperty(
"infiniband.EXP_PACKET_SIZE"));
int outputBufferSize = 2 * Integer.parseInt(
System.getProperty(
"infiniband.EXP_PACKET_SIZE"));
int numberOfEdgeSwitches = 2 * (width + (height - 2));
int numberOfSourceNodes = numberOfEdgeSwitches;
int numberOfDrainNodes = numberOfEdgeSwitches;
int
int
int
int
numberOfPortsOnSourceNodes = 1;
numberOfPortsOnDrainNodes = 1;
numberOfOutputPortsOnSwitches = 4;
numberOfOutputPortsOnEdgeSwitches = 2;
double fourKblocksPerPacket =
Double.parseDouble(System.
getProperty("infiniband.EXP_PACKET_SIZE")) /
4096;
double ibaBlocksPerPacket =
/*Math.ceil*/((Double.
parseDouble(System.
getProperty("infiniband.EXP_PACKET_SIZE"))
23
+ 2) /
Double.
parseDouble(System.
getProperty("infiniband.BLOCK_SIZE")));
int limitOfHighPriority;
String pri = System.getProperty("infiniband.LIMIT_OF_HIGH_PRIORITY");
if (pri != null){
limitOfHighPriority =
Integer.parseInt(System.
getProperty("infiniband.LIMIT_OF_HIGH_PRIORITY"));
}else{
limitOfHighPriority = 255;
}
// Simulation parameter summary
if (! guiIsEnabled) {
Reporter.println("limitOfHighPriority = "+limitOfHighPriority);
Reporter.println("packet size = "+System.
getProperty("infiniband.REAL_PACKET_SIZE"));
Reporter.println("4 K blocks per packet = "+fourKblocksPerPacket);
Reporter.println("IBA (64 B) blocks per packet = "+
ibaBlocksPerPacket);
}
//
// init
IBAConnectionTools.setKernel(kernel);
// Build base mesh
coreIbaSw = IBAConnectionTools.duplexGrid(width, height, numberOfVLs);
edgeIbaSw = new IBASwitch[numberOfEdgeSwitches];
ibas = new IBASourceNode[numberOfSourceNodes];
ibad = new IBADrainNode[numberOfDrainNodes];
// Connect source and drain nodes to mesh
// The prefix of the source and drain nodes’ addresses.
int addrPrefix=1;
// The suffix of the address on the source and drain nodes,
// also the number of the edge switch, source and drain nodes.
int addrSuffix = 0;
// The index of the core switch we are connecting to
int currIndex = 0;
// Top row
for (int i=0; i < width; i++){
currIndex = i;
connectSourceAndDrain(numberOfPortsOnSourceNodes,
numberOfVLs,
numberOfPortsOnDrainNodes,
addrPrefix,
24
addrSuffix,
currIndex,
NORTH);
addrSuffix++;
}
// East (right) row
for (int i=1; i < height-1; i++){
currIndex = (width*i) + (width-1);
connectSourceAndDrain(numberOfPortsOnSourceNodes,
numberOfVLs,
numberOfPortsOnDrainNodes,
addrPrefix,
addrSuffix,
currIndex,
EAST);
addrSuffix++;
}
// Bottom (south) row
for (int i=0; i < width; i++){
currIndex = (width*height)-i-1;
connectSourceAndDrain(numberOfPortsOnSourceNodes,
numberOfVLs,
numberOfPortsOnDrainNodes,
addrPrefix,
addrSuffix,
currIndex,
SOUTH);
addrSuffix++;
}
// West (left) row
for (int i=1; i < height-1; i++){
currIndex = (width*(height-i-1));
connectSourceAndDrain(numberOfPortsOnSourceNodes,
numberOfVLs,
numberOfPortsOnDrainNodes,
addrPrefix,
addrSuffix,
currIndex,
WEST);
addrSuffix++;
}
// Paths in the net (from sources to drains)
if (Boolean.getBoolean("infiniband.OPTIMISTIC_ROUTING")){
// Optimistic routing in the net, to achieve higher capacity,
// at the risk of routing loops
IBAConnectionTools.buildOptimisticRoutingTable(coreIbaSw,
edgeIbaSw,
width,
height);
} else {
25
// Normal routing in a grid/mesh (first vertical, then horizontal),
// to avoid routing loops.
IBAConnectionTools.buildDefaultRoutingTable(coreIbaSw,
edgeIbaSw,
width,
height);
}
// To make packets leave the source nodes
// we must add a priority to the packets sent from them.
for (int i=0; i < ibas.length; i++){
for (int j=0; j < numberOfVLs; j++){
ibas[i].addHighPriority(0, j, 1);
}
}
// Configure weights on output ports on the core and edge switches.
// Makes the lower half of the VLs low priority, and the
// upper half high priority.
// Core
for (int i=0; i < coreIbaSw.length; i++){
for (int j=0; j < numberOfOutputPortsOnSwitches; j++){
for (int k=0; k < numberOfVLs/2; k++){
coreIbaSw[i].addLowPriority(j, k, 1);
}
for (int k=numberOfVLs/2; k < numberOfVLs; k++){
coreIbaSw[i].addHighPriority(j, k, 1);
}
// limit of high priority
coreIbaSw[i].setLimitOfHighPriority(j, limitOfHighPriority);
}
}
// Edge
for (int i=0; i < edgeIbaSw.length; i++){
for (int j=0; j < numberOfOutputPortsOnEdgeSwitches; j++){
for (int k=0; k < numberOfVLs/2; k++){
edgeIbaSw[i].addLowPriority(j, k, 1);
}
for (int k=numberOfVLs/2; k < numberOfVLs; k++){
edgeIbaSw[i].addHighPriority(j, k, 1);
}
// limit of high priority
edgeIbaSw[i].setLimitOfHighPriority(j, limitOfHighPriority);
}
}
// Source nodes
// Set up which source nodes send to which address
int usagePercent = 100;
System.setProperty("infiniband.USAGE_PERCENTAGE", ""+usagePercent);
// High pri traffic
ibas[0].addDestinationAddress("1.4");
26
ibas[0].addRoutingInterval("1.4", 0);
ibas[0].setUsage(usagePercent);
ibas[0].setSL(1);
kernel.schedule(ibas[0], 0);
/*
ibas[9].addDestinationAddress("1.4");
ibas[9].addRoutingInterval("1.4", 0);
ibas[9].setUsage(50);
ibas[9].setSL(1);
kernel.schedule(ibas[9], 0);
*/
/*
// High pri traffic from 1.0 to everywhere
for (int i=0; i < ibad.length; i++) {
ibas[0].addDestinationAddress("1."+i);
ibas[0].addRoutingInterval("1."+i, 0);
}
ibas[0].setUsage(usagePercent);
ibas[0].setSL(1);
kernel.schedule(ibas[0],0);
*/
/*
// Hi pri background traffic from 1.1 to 1.4
ibas[1].addDestinationAddress("1.4");
ibas[1].addRoutingInterval("1.4", 0);
ibas[1].setUsage(usagePercent);
ibas[1].setSL(1);
// Turn on
kernel.schedule(ibas[1], 0);
*/
/*
// Low pri background traffic from 1.9 to 1.4
ibas[9].addDestinationAddress("1.4");
ibas[9].addRoutingInterval("1.4", 0);
ibas[9].setUsage(usagePercent);
ibas[9].setSL(0);
// Turn on
kernel.schedule(ibas[9], 0);
*/
// Low pri background traffic from everywhere
// to everywhere.
//for (int i=0; i < ibas.length; i++) {
for (int i=1; i < ibas.length; i++) {
//if (i != 9) {
//for (int i=0; i < ibas.length; i++) {
for (int j=0; j < ibad.length; j++) {
ibas[i].addDestinationAddress("1."+j);
ibas[i].addRoutingInterval("1."+j, 0);
}
ibas[i].setUsage(usagePercent);
ibas[i].setSL(0);
// Turn on
kernel.schedule(ibas[i], 0);
//}
}
/*
27
// Low pri background traffic
for (int i=1; i <= 3; i++) {
//for (int i=3; i <= 3; i++) {
ibas[i].addDestinationAddress("1.5");
ibas[i].addRoutingInterval("1.5", 0);
ibas[i].setUsage(usagePercent);
ibas[i].setSL(0);
// Turn on
kernel.schedule(ibas[i], 0);
}
*/
/*
for (int i=6; i <= 9; i++) {
//for (int i=8; i <= 8; i++) {
ibas[i].addDestinationAddress("1.4");
ibas[i].addRoutingInterval("1.4", 0);
ibas[i].setUsage(usagePercent);
ibas[i].setSL(0);
// Turn on
kernel.schedule(ibas[i], 0);
}
*/
// Enable the gui if wanted
if (guiIsEnabled) {
gui();
}
// Start simulation
kernel.simulate();
}
// }}}
// {{{ public static void smallPriTest()
public static void smallPriTest() {
int numberOfVLs = 2;
int inputBufferSize = 2 * Integer.parseInt(
System.getProperty(
"infiniband.EXP_PACKET_SIZE"));
int outputBufferSize = 2 * Integer.parseInt(
System.getProperty(
"infiniband.EXP_PACKET_SIZE"));
int numberOfSourceNodes = 2;
int numberOfDrainNodes = 1;
int numberOfCoreSwitches = 2;
int numberOfPortsOnSourceNodes = 1;
int numberOfPortsOnDrainNodes = 1;
double fourKblocksPerPacket =
Double.parseDouble(System.
getProperty("infiniband.EXP_PACKET_SIZE")) /
4096;
28
double ibaBlocksPerPacket =
/*Math.ceil*/((Double.
parseDouble(System.
getProperty("infiniband.EXP_PACKET_SIZE"))
+ 2) /
Double.
parseDouble(System.
getProperty("infiniband.BLOCK_SIZE")));
int limitOfHighPriority;
int usagePercent = 100;
System.setProperty("infiniband.USAGE_PERCENTAGE", ""+usagePercent);
String pri = System.getProperty("infiniband.LIMIT_OF_HIGH_PRIORITY");
if (pri != null){
limitOfHighPriority =
Integer.parseInt(System.
getProperty("infiniband.LIMIT_OF_HIGH_PRIORITY"));
}else{
limitOfHighPriority = 255;
}
// Simulation parameter summary
if (! guiIsEnabled) {
Reporter.println("limitOfHighPriority = "+limitOfHighPriority);
Reporter.println("packet size = "+System.
getProperty("infiniband.REAL_PACKET_SIZE"));
Reporter.println("4 K blocks per packet = "+fourKblocksPerPacket);
Reporter.println("IBA (64 B) blocks per packet = "+
ibaBlocksPerPacket);
}
//
// init
IBAConnectionTools.setKernel(kernel);
ibas = new IBASourceNode[numberOfSourceNodes];
ibad = new IBADrainNode[numberOfDrainNodes];
coreIbaSw = new IBASwitch[numberOfCoreSwitches];
// Source nodes
for (int i=0; i < ibas.length; i++) {
ibas[i] = new IBASourceNode(numberOfPortsOnSourceNodes,
numberOfVLs,
"Source 1."+i,
kernel);
ibas[i].setOwnAddress("1."+i);
ibas[i].addDestinationAddress("2.0");
ibas[i].addRoutingInterval("2.0", 0);
ibas[i].setUsage(usagePercent);
// Service level differs
ibas[i].setSL(i);
// Make the packets leave the source nodes by adding a hi pri
// entry to the output port.
for (int j=0; j < numberOfVLs; j++) {
ibas[i].addHighPriority(0, j, 1);
}
// Turn on
kernel.schedule(ibas[i], 0);
29
}
// Switches
for (int i=0; i < coreIbaSw.length; i++) {
coreIbaSw[i] = new IBASwitch(2,1,numberOfVLs, "Switch "+i, kernel);
for (int j=0; j < numberOfVLs/2; j++){
coreIbaSw[i].addLowPriority(0, j, 1);
}
for (int j=numberOfVLs/2; j < numberOfVLs; j++){
coreIbaSw[i].addHighPriority(0, j, 1);
}
for (int j=0; j < numberOfDrainNodes; j++) {
// limit of high priority
coreIbaSw[i].setLimitOfHighPriority(j, limitOfHighPriority);
// Routing
coreIbaSw[i].addRoutingInterval("2."+j, 0);
}
}
// Drain node
for (int i=0; i < numberOfDrainNodes; i++) {
ibad[i] = new IBADrainNode(1, numberOfVLs, "Drain 2."+i, kernel);
}
// Connect them
IBAConnectionTools.connect(ibas[0], 0, coreIbaSw[0], 0);
IBAConnectionTools.connect(ibas[1], 0, coreIbaSw[0], 1);
IBAConnectionTools.connect(coreIbaSw[0], 0, coreIbaSw[1], 0);
IBAConnectionTools.connect(coreIbaSw[1], 0, ibad[0], 0);
// Enable the gui if wanted
if (guiIsEnabled) {
gui();
}
// Start the show
kernel.simulate();
}
// }}}
// {{{ public static void aBitBiggerPriTest()
public static void aBitBiggerPriTest() {
int numberOfVLs = 2;
int inputBufferSize = 2 * Integer.parseInt(
System.getProperty(
"infiniband.EXP_PACKET_SIZE"));
int outputBufferSize = 2 * Integer.parseInt(
System.getProperty(
"infiniband.EXP_PACKET_SIZE"));
int numberOfSourceNodes = 2;
int numberOfDrainNodes = 1;
int numberOfCoreSwitches = 4;
int numberOfPortsOnSourceNodes = 1;
int numberOfPortsOnDrainNodes = 1;
30
double fourKblocksPerPacket =
Double.parseDouble(System.
getProperty("infiniband.EXP_PACKET_SIZE")) /
4096;
double ibaBlocksPerPacket =
/*Math.ceil*/((Double.
parseDouble(System.
getProperty("infiniband.EXP_PACKET_SIZE"))
+ 2) /
Double.
parseDouble(System.
getProperty("infiniband.BLOCK_SIZE")));
int limitOfHighPriority;
int usagePercent = 100;
System.setProperty("infiniband.USAGE_PERCENTAGE", ""+usagePercent);
String pri = System.getProperty("infiniband.LIMIT_OF_HIGH_PRIORITY");
if (pri != null){
limitOfHighPriority =
Integer.parseInt(System.
getProperty("infiniband.LIMIT_OF_HIGH_PRIORITY"));
}else{
limitOfHighPriority = 255;
}
// Simulation parameter summary
if (!guiIsEnabled) {
Reporter.println("limitOfHighPriority = "+limitOfHighPriority);
Reporter.println("packet size = "+System.
getProperty("infiniband.REAL_PACKET_SIZE"));
Reporter.println("4 K blocks per packet = "+fourKblocksPerPacket);
Reporter.println("IBA (64 B) blocks per packet = "+
ibaBlocksPerPacket);
}
//
// init
IBAConnectionTools.setKernel(kernel);
ibas = new IBASourceNode[numberOfSourceNodes];
ibad = new IBADrainNode[numberOfDrainNodes];
coreIbaSw = new IBASwitch[numberOfCoreSwitches];
// Source nodes
for (int i=0; i < ibas.length; i++) {
ibas[i] = new IBASourceNode(numberOfPortsOnSourceNodes,
numberOfVLs,
"Source 1."+i,
kernel);
ibas[i].setOwnAddress("1."+i);
ibas[i].addDestinationAddress("2.0");
ibas[i].addRoutingInterval("2.0", 0);
ibas[i].setUsage(usagePercent);
// Service level differs
ibas[i].setSL(i);
// Make the packets leave the source nodes by adding a hi pri
// entry to the output port.
31
for (int j=0; j < numberOfVLs; j++) {
ibas[i].addHighPriority(0, j, 1);
}
// Turn on
kernel.schedule(ibas[i], 0);
}
// Switches
for (int i=0; i < coreIbaSw.length; i++) {
coreIbaSw[i] = new IBASwitch(2,1,numberOfVLs, "Switch "+i, kernel);
for (int j=0; j < numberOfVLs/2; j++){
coreIbaSw[i].addLowPriority(0, j, 1);
}
for (int j=numberOfVLs/2; j < numberOfVLs; j++){
coreIbaSw[i].addHighPriority(0, j, 1);
}
for (int j=0; j < numberOfDrainNodes; j++) {
// limit of high priority
coreIbaSw[i].setLimitOfHighPriority(j, limitOfHighPriority);
// Routing
coreIbaSw[i].addRoutingInterval("2."+j, 0);
}
}
// Drain node
for (int i=0; i < numberOfDrainNodes; i++) {
ibad[i] = new IBADrainNode(1, numberOfVLs, "Drain 2."+i, kernel);
}
// Connect them
IBAConnectionTools.connect(ibas[0], 0, coreIbaSw[0], 0);
IBAConnectionTools.connect(ibas[1], 0, coreIbaSw[1], 0);
IBAConnectionTools.connect(coreIbaSw[0], 0, coreIbaSw[2], 0);
IBAConnectionTools.connect(coreIbaSw[1], 0, coreIbaSw[2], 1);
IBAConnectionTools.connect(coreIbaSw[2], 0, coreIbaSw[3], 0);
IBAConnectionTools.connect(coreIbaSw[3], 0, ibad[0], 0);
// Enable the gui if wanted
if (guiIsEnabled) {
gui();
}
// Start the show
kernel.simulate();
}
// }}}
}
32
TestJavaPriQ
import java.util.*;
import no.uio.ifi.tools.JavaPriorityQueue;
public class TestJavaPriQ {
public static void main (String args[]) {
List list = Arrays.asList(args);
JavaPriorityQueue queue = new JavaPriorityQueue(list);
System.out.println(queue);
queue = new JavaPriorityQueue();
try {
System.out.println(queue.removeFirst());
} catch (NoSuchElementException e) {
System.out.println(
"Received expected exception");
}
queue.insert("Joy", 8);
queue.insert("Joy", 8);
queue.insert("Scott", 9);
queue.insert("Sueltz", 5);
queue.insert("Bill", 8);
queue.insert("McNealy", 9);
queue.insert("Patricia", 5);
queue.insert("C.", 5);
queue.insert("Papadopoulos", 4);
queue.insert("Greg", 4);
System.out.println(queue);
queue.addAll(list);
System.out.println(queue);
while (queue.size() != 0) {
System.out.println(queue.removeFirst());
}
}
}
33
no.uio.ifi.gruns.Kernel
package no.uio.ifi.gruns;
import no.uio.ifi.tools.*;
/**
*<p>
* This is the heart of the simulator.
*</p>
*
*<p>
* It is responsible for scheduling scheduleable objects on
* certain times, and keep a list of objects that wait to
* be executed. When the given stop time has passed,
* the kernel stops the simulation.
*/
public class Kernel implements Reporting{
/**
* Holds a list of the units that are scheduled for excecution
*/
protected PriorityQueue scheduledUnits;
/**
* The current job to execute
*/
protected Scheduleable currentUnit;
/**
* The time to stop the simulation
*/
protected int stopTime;
/**
* The current time in the kernel
*/
protected int currentTime;
/**
* Returns the current time in the kernel
*/
public int currentTime(){
return this.currentTime;
}
/**
* Returns the current running unit
*/
public Scheduleable currentUnit(){
return this.currentUnit;
}
/**
* Returns the number of items in the queue of scheduled items.
* For logging puurposes.
*/
public int itemQueueLength(){
34
return scheduledUnits.getSize();
}
/** For logging purposes, the number of times runCurrent() is called. */
protected int numRunCurrent = 0;
/** For logging purposes, the number of times schedule() is called. */
protected int numSchedule = 0;
public Kernel() {}
public Kernel(int stopTime){
scheduledUnits = new SimplePriorityQueue(new ItemComparator());
this.stopTime = stopTime;
}
/**
* Picks the next scheduleable object to execute
*/
protected Scheduleable pickNext(){
// Increase the current time to
// be synchronized with the current running unit.
if (scheduledUnits.getMinKey() != null){
currentTime = ((Integer) scheduledUnits.getMinKey()).intValue();
}
return (Scheduleable) scheduledUnits.removeMinElement();
}
/**
* Executes the current scheduleable object.
*/
protected void runCurrent(){
// logging
numRunCurrent++;
/*
// DEBUG
Reporter.debugln("Time: "+currentTime+", "+
"Running "+((Unit)currentUnit).getID());
//
*/
currentUnit.act();
}
/**
* States whether an item is already scheduled.
* To avoid unnecessary resceduling, e.g. in the IBASwitch.
*/
public boolean isScheduled(Scheduleable s){
return scheduledUnits.contains(s);
}
35
/**
* Schedules a scheduleable object for excecution
* at at specified time.
*/
public void schedule(Scheduleable s, int time){
// Error if time is below current time
if (time < currentTime){
Reporter.error("Kernel.schedule: "+
"Can’t schedule events back in time!");
}
// Check if the object is already scheduled for running
// on that time step, if not, schedule it.
if (! scheduledUnits.contains(time, s)){
/*
// DEBUG
Reporter.debugln("Scheduling "+((Unit)s).getID()+ " on time "+time);
//
*/
numSchedule++;
scheduledUnits.insertItem(new Integer(time), s);
}
}
/**
* The main loop, runs the simulation.
*/
public void simulate(){
long tmpTime=0;
while (currentTime < stopTime) {
int prevTime = currentTime;
// Picks the next and updates current time
currentUnit = pickNext();
/*
// DEBUG
System.err.println("currentTime = "+currentTime+
", currentUnit = "+((Unit)currentUnit).getID());
Utils.pause();
//
*/
// Break if there is nothing more to simulate
if (currentUnit == null){
break;
}
// Break if we have exceeded time limit
if (currentTime > stopTime) {
// Register when we finished
Reporter.setStopTime(System.currentTimeMillis());
break;
}
36
// Progress monitor
Reporter.proceed(currentTime);
// Print out the time steps to stay in control with lots of
// debugging info coming.
/*
if (prevTime != currentTime){
Reporter.println();
Reporter.println("Time step "+currentTime);
Reporter.println("-----------------------"+
"---------------------------");
}
// Print out info on current unit before running
Reporter.println("current unit before = "+
((currentUnit instanceof Reporting)?((Reporting)currentUnit).report():
currentUnit.toString()));
*/
runCurrent();
}
}
public String report
return "Kernel";
}
(){
// For benchmarking
public long timeSpentPickingAndScheduling = 0;
public long timeSpentRunningCurrent = 0;
}
37
no.uio.ifi.gruns.Link
package no.uio.ifi.gruns;
/**
* Represents a simplex physical link, i.e. communication
* flows in just one direction.
*/
public class Link extends Unit implements ByteSender,
ByteReceiver,
Reporting,
Scheduleable{
public Link(Kernel kernel){
super(kernel);
//maxSize = 65536; // Just some number (64 K bytes)
//maxSize = 32768; // Just some number (32 K bytes)
//maxSize = 512; // Just some number
maxSize = 1024; // Just some number
inBuffer = new ByteBuffer(maxSize);
outBuffer = new ByteBuffer(maxSize);
numberOfBytesSent = numberOfBytesReceived = 0;
sizesOfBlocksInTransit = new java.util.Vector();
}
/** The bytes to send are put in this buffer */
protected ByteBuffer inBuffer;
/** The bytes to receive are put in this buffer */
protected ByteBuffer outBuffer;
/**
* The maximum size of the input and output buffers.
* The total number of bytes on the link can be twice
* this size.
*/
protected int maxSize;
/**
* The upstream unit of this link, e.g. the unit
* that will be calling {@link #sendByte} on this link
*/
protected OutputPort source;
/**
* The downstream unit of this link, e.g. the unit
* that will be calling {@link #receiveByte} on this link
*/
protected InputPort sink;
/**
* Number of bytes sent on this link, i.e. that have been
* put on the link for sending. They need not have been
* propagated through the link. (just for logging purposes)
*/
protected int numberOfBytesSent;
/**
38
* Number of bytes received from this link, i.e that is
* received in the other end, and is no longer on the link
* (just for logging purposes)
*/
protected int numberOfBytesReceived;
/**
* Number of bytes transferred on this link, i.e. that has
* actually moved across the link.
* (just for logging purposes)
*/
protected int numberOfBytesPropagated;
/**
* List of sizes of blocks received
*/
protected java.util.Vector sizesOfBlocksInTransit;
/**
* Sets the upstream unit of this link, e.g. the unit
* that will be calling {@link #sendByte} on this link
*/
public void setSource(OutputPort port){
this.source = port;
}
/**
* Gets the upstream unit of this link, e.g. the unit
* that will be calling {@link #sendByte} on this link
*/
public OutputPort getSource(){
return source;
}
/**
* Sets the downstream unit of this link, e.g. the unit
* that will be calling {@link #receiveByte} on this link
*/
public void setSink(InputPort port){
this.sink = port;
}
/**
* Gets the downstream unit of this link, e.g. the unit
* that will be calling {@link #receiveByte} on this link
*/
public InputPort getSink(){
return sink;
}
/** Sends a byte on the link */
public void sendByte(byte b) throws LinkFullException{
if (inBuffer.isFull()){
throw new
LinkFullException(ID+": Link.send: Trying to send to a full buffer! "+
"In buffer size = "+inBuffer.getSize()+
", Out buffer size = "+outBuffer.getSize()+
", Maximum buffer size = "+maxSize);
}
39
inBuffer.put(b);
// Update for logging
numberOfBytesSent++;
}
/** receives a byte from the link */
public byte receiveByte() throws LinkEmptyException{
byte b;
if (outBuffer.isEmpty()){
throw new
LinkEmptyException(ID+": Link.receive: Trying to receive from "+
"empty buffer! "+
"Out buffer size = "+outBuffer.getSize()+
", In buffer size = "+inBuffer.getSize()+
", Maximum buffer size = "+maxSize);
}
b = outBuffer.get();
// Update for logging
numberOfBytesReceived++;
return b;
}
/**
* Tells the link that we have just sent a block of this size
* on it. To avoid moving e.g. 64 bytes in the next step if we have only put
* 38 on the link. This is because the input port in the other end will just
* remove 38 bytes from the link, and hence we will get a traffic jam in
* our own output port.
*
* @param numBytesInBlock The number of bytes in the last block
*/
public void addBlock(int numBytesInBlock){
sizesOfBlocksInTransit.add(new Integer(numBytesInBlock));
}
/**
* States whether there is no more room for packets to
* be input on the link
*/
public boolean isFull(){
return (inBuffer.isFull());
}
/**
* States whether there are no more packets to be output
* from the link
*/
public boolean isEmpty(){
return (outBuffer.isEmpty());
}
/**
* Returns the size of the next block to transfer on
* the link.
*/
private int getSizeOfNextBlock(){
Integer integer = (Integer)sizesOfBlocksInTransit.remove(0);
40
return integer.intValue();
}
/**
* Move one block (64 bytes)
* from input buffer to output buffer.
* Reschedule if there’s more data in the input buffer.
*/
public void act(){
int numberOfBytesMovedThisTurn = 0;
int numberOfBytesToMoveThisTurn = getSizeOfNextBlock();
/*
// DEBUG
if (ID.equals("(Switch 7 -> Drain 0)")){
Reporter.debugln(ID+": Sending "+numberOfBytesToMoveThisTurn+" bytes");
}
//
*/
for (int i=0; i < numberOfBytesToMoveThisTurn; i++){
if (inBuffer.isEmpty()){
// Actually no error, just no more data.
// Reporter.error("Link.act: Input buffer is empty!");
break;
}
numberOfBytesMovedThisTurn++;
if (outBuffer.isFull()){
Reporter.error("Link.act: Output buffer is full!");
}
outBuffer.put(inBuffer.get());
numberOfBytesPropagated++;
}
// Make sure we don’t schedule the sink if there is
// no data to read.
if (numberOfBytesMovedThisTurn != 0){
kernel.schedule(sink, kernel.currentTime() + 1);
}
//
//
//
//
//
//
Reshcedule if there’s more data waiting to be moved.
Not necessary, I think.
if (!inBuffer.isEmpty()){
kernel.schedule(this, kernel.currentTime() +1);
}
}
public String report(){
return("Link "+
ID+
", # bytes sent = "+numberOfBytesSent+
", # bytes rec. = "+numberOfBytesReceived+
", inBufferSize = "+inBuffer.getSize()+
41
", outBufferSize = "+outBuffer.getSize()
/*
", # bytes moved this turn = "
+numberOfBytesMovedThisTurn
*/
);
}
}
42
no.uio.ifi.gruns.Packet
package no.uio.ifi.gruns;
/**
* Represents a packet on the network.
* Consists of a series of bytes.
*/
public class Packet{
/** The packet itself */
protected byte [] packet;
/** The size of the packet */
protected int size;
/** The current byte number */
protected int currentByteNumber;
protected static final int BYTE_SIZE = 8;
/** Default constructor that does nothing */
public Packet(){
}
/**
* Creates a new packet with the content specified
*/
public Packet(byte [] content){
this.packet = content;
size = content.length;
}
/**
* Creates a new packet with the specified to-address
* and the specified payload.
* <br>
*/
public Packet(Address destination, byte[] payload){
int addrLength = destination.getSize()/BYTE_SIZE;
byte[] content = new byte[addrLength + payload.length];
byte[] address = destination.getAddress();
// Place the address at the beginning of the packet
for (int i=0; i < addrLength; i++){
content[i] = address[i];
}
// Fill in the payload
for (int i = 0; i < payload.length; i++){
content[i + addrLength] = payload[i];
}
this.packet = content;
this.size = content.length;
}
public Address getAddress(){
byte [] addr = { packet[0], packet[1] };
Address address = new Address(addr);
return address;
43
}
/**
* Returns the total size of the packet,
* including all headers and payload.
*/
public int getSize(){
return packet.length;
}
/**
* Gets the next byte of this packet
*/
public byte getNextByte(){
return (currentByteNumber >= size) ? -1 : packet[currentByteNumber++];
}
}
44
no.uio.ifi.gruns.PacketReceiver
package no.uio.ifi.gruns;
/**
* All classes that are able to receive packets
* should implement this interface.
*/
public interface PacketReceiver {
/**
* Receives a packet
* @return The packet received
* @param portNumber The physical output port number
* to receive the packet on
* @param VLNumber The virtual lane number
* to receive the packet on
*/
public Packet receivePacket(int portNumber, int VLNumber);
}
45
no.uio.ifi.gruns.RoutingTable
package no.uio.ifi.gruns;
import java.util.HashMap;
import java.util.Iterator;
/**
* Represents the routing table for a switch
*/
public class RoutingTable implements Reporting{
public RoutingTable(){
routingTableEntries = new HashMap();
}
/** The routing table entries for this routing table */
protected HashMap routingTableEntries;
/**
* Adds a possible output route for the supplied address
* @param a The address to add a route for
* @param outgoingPortNumber The port number of the route
* @param outgoingVLNumber The virtual lane number of the route
*/
public void addRoute(Address a,
int outgoingPortNumber,
int outgoingVLNumber){
RoutingTableEntry entry = null;
// Fetch the routing table entry for the specified address,
// create a new one if it is not found.
if (routingTableEntries.containsKey(a.getAddressAsString())){
entry = (RoutingTableEntry)
routingTableEntries.get(a.getAddressAsString());
}else{
entry = new RoutingTableEntry();
routingTableEntries.put(a.getAddressAsString(), entry);
}
// Make a new Route
Route r = new Route();
r.portNumber = outgoingPortNumber;
r.VLNumber = outgoingVLNumber;
// Add the new route to the routing table entry
entry.addRoute(r);
}
/**
* Deletes a possible output route for the supplied address
* @param a The address to delete a route for
* @param outgoingPortNumber The port number of the route
* @param outgoingVLNumber The virtual lane number of the route
*/
public void deleteRoute(Address a,
int outgoingPortNumber,
int outgoingVLNumber){
46
RoutingTableEntry entry = null;
// Fetch the routing table entry for the specified address.
if (routingTableEntries.containsKey(a.getAddressAsString())){
entry = (RoutingTableEntry)
routingTableEntries.get(a.getAddressAsString());
}
else{
// No need to remove a route that doesn’t exist,
// so just return silently.
return;
}
// Make a new dummy Route
Route r = new Route();
r.portNumber = outgoingPortNumber;
r.VLNumber = outgoingVLNumber;
// Delete the route from the routing table entry
entry.deleteRoute(r);
}
/**
* Looks up an address in the routing table.
* If multiple routes are found, multiple calls will return
* the routes in turn, starting with the first route added.
*
* @return The Route to send the packet out on.
*
<tt>null</tt> if no route is found.
* @param a The address to look up.
*/
public Route lookUp(Address a){
RoutingTableEntry entry = null;
Route retVal = null;
// Fetch the routing table entry for the specified address.
if (routingTableEntries.containsKey(a.getAddressAsString())){
entry = (RoutingTableEntry)
routingTableEntries.get(a.getAddressAsString());
}
// Return null if no entry is found for the supplied address
if (entry == null){
retVal = null;
}else{
retVal = entry.getNextRoute();
}
return retVal;
}
public String report(){
return "RoutingTable";
}
}
47
no.uio.ifi.gruns.Scheduleable
package no.uio.ifi.gruns;
/**
* All classes that can be scheduled to be run on a {@link no.uio.ifi.gruns.Kernel}
* should implement this interface.
*/
public interface Scheduleable{
/**
* Called by the simulator kernel whenever the scheduleable unit
* is executed.
*/
public void act();
}
48
no.uio.ifi.gruns.Address
package no.uio.ifi.gruns;
/**
* Represents the address of a packet with 16 bytes.
* This corresponds to the 16-bit LID (Local Identifier)
* in the InfiniBand Architecture.
*/
public class Address {
// {{{ Protected members
protected byte[] address;
/**
* Used to store 256 values at any range (e.g. 0 to 255)
* pr. byte, not just -127 to 128.
*/
protected byte base = 0;
/**
* Used to store 256 values at any range (e.g. 0 to 255)
* pr. byte, not just -127 to 128.
*/
protected byte offset = (byte) (0 - (base - (byte) Byte.MIN_VALUE ) );
// }}}
// {{{ protected int getSize()
/**
* Returns the size of the address in bits
*/
protected int getSize(){
return 16;
}
// }}}
// {{{ Constuctors
// {{{ public Address(byte [] address
/**
* Makes a new address from the supplied byte array.
*/
public Address(byte [] address){
this.address = address;
}
// }}}
// {{{ public Address(String address)
/**
* Translates the supplied String to a valid address
* and stores it in this object.
* <br>
* The format should be on the form <tt>aaa.bbb</tt>, where
* <b>aaa</b> and <b>bbb</b> are numbers between 0 and 255.
*/
public Address(String address){
this.address = stringToByteArray(address);
}
// }}}
49
// }}}
// {{{ public byte[] getAddress()
/**
* Gets the address in its raw byte[] format.
*/
public byte[] getAddress(){
return address;
}
// }}}
// {{{ public String getAddressAsString()
/**
* Gets the address in a more human-readable form
*/
public String getAddressAsString(){
return byteArrayToString(address);
}
// }}}
// {{{ protected String byteArrayToString(byte[] address)
/**
* Converts a byte array to a more human-readable string
*/
protected String byteArrayToString(byte[] address){
StringBuffer sb = new StringBuffer();
byte[] addr = getAddress();
int addr1=0, addr2=0;
// Do it manually!
int MASK = 0x00000001;
for (int i=0; i < 8; i++){
addr1 += (addr[0] & MASK);
// Reporter.println("addr1 = "+addr1);
MASK = (MASK << 1);
}
MASK = 0x00000001;
for (int i=0; i < 8; i++){
addr2 += (addr[1] & MASK);
// Reporter.println("addr2 = "+addr2);
MASK = (MASK << 1);
}
sb.append(addr1);
sb.append(".");
sb.append(addr2);
return sb.toString();
}
// }}}
// {{{ protected byte [] stringToByteArray(String address)
/**
* Converts a human-readable string to a valid byte[] address
* The format should be on the form <tt>aaa.bbb</tt>, where
* <b>aaa</b> and <b>bbb</b> are numbers between 0 and 255.
*/
protected byte [] stringToByteArray(String address){
50
byte [] addr = new byte[2];
int separator = address.indexOf(".");
addr[0] = (byte) Integer.parseInt(address.trim().
substring(0, separator));
addr[1] = (byte) Integer.parseInt(address.trim().
substring(separator + 1));
return addr;
}
// }}}
// {{{ public String toString()
public String toString(){
return getAddressAsString();
}
// }}}
}
51
no.uio.ifi.gruns.AddressVector
package no.uio.ifi.gruns;
import java.util.Vector;
/**
* Specialized form of Vector which holds Address objects.
* All methods correspond to those of {@link java.util.Vector}
*/
public class AddressVector extends Vector{
// {{{ Constructors
// {{{ public AddressVector()
public AddressVector(){
super();
}
// }}}
// {{{ public AddressVector(int initialCapacity)
public AddressVector(int initialCapacity){
super(initialCapacity);
}
// }}}
// }}}
// {{{ public Address[] toAddressArray()
public Address[] toAddressArray(){
Address[] addresses = new Address[size()];
toArray(addresses);
return addresses;
}
// }}}
}
52
no.uio.ifi.gruns.ByteBuffer
package no.uio.ifi.gruns;
/**
* This class represents a buffer in e.g. a source node,
* a drain node, a link or a switch.
*/
public class ByteBuffer{
/** The actual buffer */
protected byte[] buffer;
/** The actual size of the buffer */
protected int size;
/** The maximum size of the buffer */
protected int maxSize;
/** We get data from the tail of the buffer */
protected int tail;
/** We put data at the head of the buffer */
protected int head;
/**
* Creates a byte buffer with the specified capacity.
*/
public ByteBuffer(int capacity){
size = 0;
maxSize = capacity;
buffer = new byte[capacity];
tail = 0;
head = 0;
}
/** Puts data at the end of the buffer */
public void put(byte b){
if (size >= maxSize){
Reporter.error("ByteBuffer.put: "+
"Trying to put to a full buffer! "+
"Buffer size = "+size+
", Maximum buffer size = "+maxSize);
return;
}
buffer[head] = b;
head = (head + 1) % maxSize;
size++;
}
/** Gets data at the beginning of the buffer */
public byte get(){
byte b;
if (size <= 0){
Reporter.error("ByteBuffer.get: "+
"Trying to receive from empty buffer! "+
"Buffer Size = "+size+
", Maximum buffer size = "+maxSize);
return (byte) -1;
53
}
b = buffer[tail];
tail = (tail + 1) % maxSize;
size--;
return b;
}
/** Returns the data as a byte array */
public byte[] toByteArray(){
byte[] retVal = new byte[size];
for (int i=0; i < retVal.length; i++){
retVal[i] = buffer[i];
}
return retVal;
}
/** Returns the size of the buffer */
public int getSize(){
return size;
}
/** Returns the total capacity of the buffer */
public int getCapacity(){
return maxSize;
}
/** Returns the remaining capacity of the buffer */
public int getRemainingCapacity(){
return maxSize - size;
}
/** States whether the buffer is full */
public boolean isFull(){
return (size == maxSize);
}
/** States whether the buffer is empty */
public boolean isEmpty(){
return (size == 0);
}
/** Clears the buffer content */
public void clear(){
for (int i=0; i < maxSize; i++){
buffer[i] = 0;
}
size=0;
tail=0;
head=0;
}
}
54
no.uio.ifi.gruns.ByteReceiver
package no.uio.ifi.gruns;
/**
* All classes that receive single bytes should implement this interface.
*/
public interface ByteReceiver{
/**
* Receives a single byte
*/
public byte receiveByte();
}
55
no.uio.ifi.gruns.DrainNode
package no.uio.ifi.gruns;
/**
* <p>
* This class represents a drain node in a network. Its task is to
* receive packets from the network and do something with them.
* </p>
*
* <p>
* It has a set of input ports which it can receive from, and each of
* these input ports provide one or more virtual lanes to
* receive packets from.
* </p>
*/
public class DrainNode extends Unit
implements PacketReceiver, Scheduleable {
/** The address of this drain node */
protected Address address;
public DrainNode(Kernel kernel){
super(kernel);
}
/** The input ports to receive packets on */
protected InputPort [] inputPorts;
/** Receives a packet */
public Packet receivePacket(int portNumber, int VLNumber){
return null;
}
/**
* Processes a received packet.
*/
protected void processPacket(){
}
public void act(){
}
public String report(){
return "DrainNode";
}
}
56
no.uio.ifi.gruns.LinkFullException
package no.uio.ifi.gruns;
public class LinkFullException extends RuntimeException{
public LinkFullException(){
super();
}
public LinkFullException(String message){
super(message);
}
}
57
no.uio.ifi.gruns.OutputPort
package no.uio.ifi.gruns;
/**
*<p>
* Represents the output part of a physical port on a switch, a
* source node, a drain node etc. It is used to send packets
* from the unit. Each node/switch typically has many ports.
*</p>
*
*<p>
* There is also a counterpart, the {@link no.uio.ifi.gruns.InputPort},
* which is used to receive packets.
*</p>
*/
public class OutputPort extends Unit implements Reporting, Scheduleable{
/**
* The capacity of the buffers in the virtual lanes
*/
protected int bufferSize = 65536;
/**
* The port which this output port is sending to
*/
protected Link link;
/**
* The number of virtual lanes this port supports
*/
protected int numberOfVLs;
/**
* The virtual lane we are currently sending on
*/
protected int currentVL;
/**
* The packet currently under transmission
*/
protected Packet currentPacket;
/**
* The output buffers in this port.
* There are {@link #numberOfVLs} output buffers.
*/
protected ByteBuffer buffer[];
public OutputPort(Kernel kernel){
super(kernel);
}
/**
* Creates an output port with the supplied number of
* virtual lanes
*
* @param numberOfVirtualLanes The number of virtual lanes to provide
58
*/
public OutputPort(int numberOfVirtualLanes, Kernel kernel){
this(kernel);
this.numberOfVLs = numberOfVirtualLanes;
this.buffer = new ByteBuffer[numberOfVLs];
for (int i=0; i < numberOfVLs; i++){
buffer[i] = new ByteBuffer(bufferSize);
}
currentVL = -1;
ID = "";
}
/**
* Connects this output port to a link
*/
public void attach(Link link){
this.link = link;
link.setSource(this);
}
/**
* Sends a single packet on the supplied virtual lane number.
*/
public void sendPacket(Packet p, int VLNumber){
int i;
for (i = 0;
i < p.getSize() && !buffer[VLNumber].isFull();
i++){
buffer[VLNumber].put(p.getNextByte());
}
// Error message if error sending packet
if (i < p.getSize()){
Reporter.error("OutputPort.sendPacket("+p+
", "+VLNumber+"): "+
"Not enough buffer space left!");
Reporter.error("\n");
}
}
/**
* <p>
* Sends a single packet on the link (one byte per call).
* If there’s not enough time to send the whole packet
* in this time unit, it reschedules itself on the next time unit.
* </p>
* <p>
* No default implementation.
* </p>
*/
public void act(){
}
public String report(){
59
return "OutputPort";
}
}
60
no.uio.ifi.gruns.PacketSender
package no.uio.ifi.gruns;
/**
* All classes that are able to send packets
* should implement this interface.
*/
public interface PacketSender {
/**
* Sends a packet
* @param p The packet to send
* @param portNumber The physical output port number to send the packet on
* @param VLNumber The virtual lane number to send the packet on
*/
public void sendPacket(Packet p, int portNumber, int VLNumber);
}
61
no.uio.ifi.gruns.Reporter
package no.uio.ifi.gruns;
import java.io.PrintStream;
import no.uio.ifi.gruns.infiniband.*;
/**
* Used to report from all the classes in the simulator.
*/
public final class Reporter{
/**
* Prints an error message
*/
public static void error(String message){
out.println("Error: "+message);
// An error is serious enough to abort
throw new RuntimeException(message);
}
/**
* Prints the report from the supplied Reporting unit
*/
public static void report(Reporting unit){
out.println(unit.report());
}
/**
* Prints a message
*/
public static void print(String message){
out.print(message);
}
/**
* Prints an object by calling the appropriate toString() method.
*/
public static void print(Object o) {
out.print(o);
}
/**
* Prints a message (with ending newline)
*/
public static void println(String message){
out.println(message);
}
/**
* Prints an object by calling the appropriate toString() method.
*/
public static void println(Object o) {
out.println(o);
}
/**
* Prints a newline
62
*/
public static void println(){
out.println();
}
// JUST CHANGE THESE TO DO NOTHING TO TEMPORARILY TURN OFF DEBUGGING
/**
* Prints a debug message.
*/
public static void debug(String message) {
out.print("DEBUG: Time "+kernel.currentTime()+": "+message);
}
/**
* Prints an object by calling the appropriate toString() method.
*/
public static void debug(Object o) {
out.print("DEBUG: Time "+kernel.currentTime()+": "+o);
}
/**
* Prints a debug message (with ending newline)
*/
public static void debugln(String message){
out.println("DEBUG: Time "+kernel.currentTime()+": "+message);
}
/**
* Prints an object by calling the appropriate toString() method.
*/
public static void debugln(Object o) {
out.println("DEBUG: Time "+kernel.currentTime()+": "+o);
}
/**
* Prints a debug newline
*/
public static void debugln(){
out.println("DEBUG: Time "+kernel.currentTime()+": ");
}
/**
* Sets the outputstream we write error messages to.
* e.g:
*<ul>
* <li>Reporter.setOutputStream(new PrintStream(
*
new FileOutputStream("filename")))</li>
* <li>Reporter.setOutputStream(System.out)</li>
*</ul>
*/
public static void setOutputStream(PrintStream stream){
out = stream;
}
public static PrintStream getOutputStream(){
return out;
}
/**
63
* Just so that the reporter should have access to current time etc.
*/
public static void setKernel(Kernel k){
kernel = k;
}
/**
* Gui
*/
public static void setGuiParams(
no.uio.ifi.gruns.gui.StatusPanel p,
no.uio.ifi.gruns.infiniband.IBASourceNode[] sources,
no.uio.ifi.gruns.infiniband.IBADrainNode[] drains,
no.uio.ifi.gruns.infiniband.IBASwitch[] edges,
no.uio.ifi.gruns.infiniband.IBASwitch[] cores
) {
statusPanel = p;
sourceNodes = sources;
drainNodes = drains;
edgeSwitches = edges;
coreSwitches = cores;
}
/**
* Indicats that we have proceeded some steps in our simuation.
* could be changed to update a JProgressbar, e.g, hence the
* general method, not just a "print(".")" from the Kernel.
*/
public static void proceed(int currentTime){
acc += (currentTime - previousTime);
acc2 += (currentTime - previousTime);
// Display status in gui
if (statusPanel != null && acc2 >= 50) {
statusPanel.setTime(kernel.currentTime());
if (sourceNodes != null) {
for (int i=0; i < sourceNodes.length; i++) {
statusPanel.setSourceStats(i,
sourceNodes[i].getSentPackets(),
sourceNodes[i].getWaitingPackets()
);
}
}
if (drainNodes != null) {
no.uio.ifi.gruns.infiniband.IBAStatistics.IBADrainNodeStats stats = null;
int total = 0;
for (int i=0; i < drainNodes.length; i++) {
stats = no.uio.ifi.gruns.infiniband.IBAStatistics.
getReceivedPacketStats(drainNodes[i]);
if (stats != null) {
statusPanel.setDrainStats(i, stats);
}
}
}
if (edgeSwitches != null) {
for (int i=0; i < edgeSwitches.length; i++) {
statusPanel.setEdgeStats(i,
edgeSwitches[i].getTotalNumberOfPacketsSent()
64
);
}
}
if (coreSwitches != null) {
for (int i=0; i < coreSwitches.length; i++) {
statusPanel.setCoreStats(i,
coreSwitches[i].getTotalNumberOfPacketsSent()
);
}
}
statusPanel.setQueueLen(kernel.itemQueueLength());
statusPanel.updateMemUsage();
acc2 = 0;
}
if (statusPanel == null) {
// Print a "." for every time step
for (int i=0; i < (currentTime - previousTime); i++){
// Just for debugging
//out.print(currentTime+"\n");
//out.flush();
out.print(".");
out.flush();
}
}
// Prints a message for approx. every 5000 time steps.
if (acc >= 5000){
if (statusPanel == null) {
out.println("Simulating time step: "+Utils.formatInt(currentTime)+".");
}
// Make sure that the garbage collector gets to run every
// once in a while
System.gc();
acc = 0;
}
previousTime = currentTime;
}
public static void setStartTime(long time) {
realStartTime = time;
}
public static long startTime() {
return realStartTime;
}
public static void setStopTime(long time) {
realStopTime = time;
}
public static long stopTime() {
return realStopTime;
}
65
/**
* The stream to print messages to
*/
private static PrintStream out;
/**
* The kernel
*/
private static Kernel kernel;
/** The previous time */
private static int previousTime;
/** To tell if we are to print out a wordy status msg.*/
private static int acc;
/** To tell if we are to update the gui*/
private static int acc2;
/**
* For displaying results inline
*/
protected static no.uio.ifi.gruns.gui.StatusPanel statusPanel = null;
/**
* For displaying results inline
*/
protected static no.uio.ifi.gruns.infiniband.IBASourceNode[] sourceNodes = null;
/**
* For displaying results inline
*/
protected static no.uio.ifi.gruns.infiniband.IBADrainNode[] drainNodes = null;
/**
* For displaying results inline
*/
protected static no.uio.ifi.gruns.infiniband.IBASwitch[] edgeSwitches = null;
/**
* For displaying results inline
*/
protected static no.uio.ifi.gruns.infiniband.IBASwitch[] coreSwitches = null;
/**
* For registering when we started
*/
protected static long realStartTime;
/**
* For registering when we stopped
*/
protected static long realStopTime;
// initialization
static {
realStartTime = 0;
realStopTime = 0;
66
}
}
67
no.uio.ifi.gruns.Route
package no.uio.ifi.gruns;
/**
* This class represents a pair of (portNumber, VLNumber),
* and is used in routing tables (more specifically in
* {@link no.uio.ifi.gruns.RoutingTableEntry}.
*/
public class Route implements Reporting {
/** The physical port number */
public int portNumber;
/** The virtual lane number */
public int VLNumber;
public String report(){
return ("Route: Port number: "+
this.portNumber+
", virtual lane number: "+
this.VLNumber);
}
}
68
no.uio.ifi.gruns.SourceNode
package no.uio.ifi.gruns;
/**
* <p>
* This class represents a sourcenode in a network. Its task is to
* generate packets and send them out on the network.
* </p>
*
* <p>
* It has a set of output ports which it can send to, and each of
* these output ports provide one or more virtual lanes to
* send packets on.
* </p>
*
* <p>
* Subclasses of this node can be made to have the source node
* make other kinds of packets etc.
* </p>
*/
public class SourceNode extends Unit implements PacketSender,
Reporting,
Scheduleable{
/** The output ports to send packets on */
protected OutputPort [] outputPorts;
/** The addresses that this source node produces packets for */
protected AddressVector addresses;
/** The address of this source node */
protected Address address;
/**
* Creates a new source node.
*
* @param numberOfOutputPorts The number of output ports
* on this source node
* @param numberOfVirtualLanes The number of virtual
* lanes per output port
*/
public SourceNode(int numberOfOutputPorts,
int numberOfVirtualLanes,
Kernel kernel){
this(numberOfOutputPorts, numberOfVirtualLanes, "", kernel);
}
/**
* Creates a new source node.
*
* @param numberOfOutputPorts The number of output ports
* on this source node
* @param numberOfVirtualLanes The number of virtual lanes
* per output port
* @param ID A String to identify the source node
*/
public SourceNode(int numberOfOutputPorts,
int numberOfVirtualLanes,
69
String ID,
Kernel kernel){
super(kernel);
this.outputPorts = new OutputPort[numberOfOutputPorts];
for (int i = 0; i < numberOfOutputPorts; i++){
outputPorts[i] = new OutputPort(numberOfVirtualLanes, kernel);
}
addresses = new AddressVector();
this.ID = ID;
}
/**
* Attaches a link to this source node on the
* supplied output port number
*/
public void attach(Link l, int outputPortNumber)
throws IllegalArgumentException {
if (outputPorts == null){
throw new IllegalArgumentException("This source node "+
"has no output ports.");
}
if (outputPortNumber < 0 || outputPortNumber > outputPorts.length){
throw new IllegalArgumentException("Output port number "+
"out of range. Must be"+
"between 0 and "+
outputPorts.length);
}
outputPorts[outputPortNumber].attach(l);
}
/**
* Adds a destination address to the list of addresses
* that this source node produces packets for.
*/
public void addDestinationAddress(Address destination) {
addresses.add(destination);
}
/**
* Sends a packet
* @param p The packet to send
* @param portNumber The physical output port number to send the packet on
* @param VLNumber The virtual lane number to send the packet on
*/
public void sendPacket(Packet p, int portNumber, int VLNumber){
outputPorts[portNumber].sendPacket(p, VLNumber);
// Schedule the output port so that the packet moves on
kernel.schedule(outputPorts[portNumber], kernel.currentTime() + 1);
}
/**
* Makes a packet with a test message.
*/
protected Packet makePacket(){
Address a = RandomAddress.nextAddress(addresses.toAddressArray());
70
Packet p = new Packet(a, ("Test packet from "+ID).getBytes());
return p;
}
public void act(){
Packet p = makePacket();
sendPacket(p, 0, 0);
}
public String report(){
return "SourceNode: "+ID;
}
}
71
no.uio.ifi.gruns.Unit
package no.uio.ifi.gruns;
/**
* Just a parent class for all units that exist in
* the simulator, to have some common methods in all
* the units.
*/
public abstract class Unit {
public Unit(Kernel kernel){
this.kernel = kernel;
}
/** Sets the ID of this unit */
public void setID(String ID){
this.ID = ID;
}
/** Gets the ID of this unit */
public String getID(){
return ID;
}
/** To identify this unit */
public String ID;
/**
* The simulator kernel
*/
protected Kernel kernel;
}
72
no.uio.ifi.gruns.ByteSender
package no.uio.ifi.gruns;
/**
* All classes that sends single bytes should implement this interface.
*/
public interface ByteSender{
/**
* Send a single byte
*/
public void sendByte(byte b);
}
73
no.uio.ifi.gruns.InputPort
package no.uio.ifi.gruns;
/**
*<p>
* Represents the input part of a physical port on a switch, a
* source node, a drain node etc. It is used to receive packets
* to the unit. Each node/switch typically has many ports.
*</p>
*
*<p>
* There is also a counterpart, the {@link no.uio.ifi.gruns.OutputPort},
* which is used to send packets.
*</p>
*/
public abstract class InputPort extends Unit implements Reporting, Scheduleable{
public InputPort(Kernel kernel){
super(kernel);
}
/**
* Creates an input port with the supplied number of
* virtual lanes
*
* @param numberOfVirtualLanes The number of virtual lanes to provide
*/
public InputPort(int numberOfVirtualLanes, Kernel kernel){
this(kernel);
this.numberOfVLs = numberOfVirtualLanes;
this.buffer = new ByteBuffer[numberOfVLs];
for (int i=0; i < numberOfVLs; i++){
buffer[i] = new ByteBuffer(bufferSize);
}
currentVL = -1;
ID = "";
}
/**
* The capacity of the buffers in the virtual lanes.
* Currently set to 1 kB.
*/
protected int bufferSize = 1024; // 1 kB buffer on each VL
/**
* The link which this input port is receiving from
*/
protected Link link;
/**
* The number of virtual lanes this port supports
*/
protected int numberOfVLs;
74
/**
* The number of virtual lanes this port supports
*/
public int numberOfVLs(){
return numberOfVLs;
}
/**
* The virtual lane we are currently receiving from
*/
protected int currentVL;
/**
* The packet currently being received
*/
protected Packet currentPacket;
/**
* The output buffers in this port.
* There are {@link #numberOfVLs} output buffers.
*/
protected ByteBuffer buffer[];
/**
* Connects this input port to a link
*/
public void attach(Link link){
this.link = link;
link.setSink(this);
}
/**
* Receives a single packet from the supplied virtual lane number.
* Called from the unit (e.g. drainnode, switch) that this
* input port is connected to. DON’T USE THIS!
* <b>No default implementation</b>
*/
public abstract Packet receivePacket(int VLNumber);
/**
* Receives a single packet.
* Called from the unit (e.g. drainnode, switch) that this
* input port is connected to.
* <b>No default implementation</b>
*/
public abstract Packet receivePacket();
public abstract void act();
public String report(){
return "InputPort";
}
}
75
no.uio.ifi.gruns.LinkEmptyException
package no.uio.ifi.gruns;
public class LinkEmptyException extends RuntimeException{
public LinkEmptyException(){
super();
}
public LinkEmptyException(String message){
super(message);
}
}
76
no.uio.ifi.gruns.NewKernel
package no.uio.ifi.gruns;
import no.uio.ifi.tools.*;
/**
*<p>
* This is the heart of the simulator, the new version using
* JavaPriorityQueue, which is much faster.
*</p>
*
*<p>
* It is responsible for scheduling scheduleable objects on
* certain times, and keep a list of objects that wait to
* be executed. When the given stop time has passed,
* the kernel stops the simulation.
*/
public class NewKernel extends Kernel{
/**
* Holds a list of the units that are scheduled for excecution
*/
protected JavaPriorityQueue scheduledUnits;
/**
* Returns the number of items in the queue of scheduled items.
* For logging puurposes.
*/
public int itemQueueLength(){
return scheduledUnits.size();
}
public NewKernel(int stopTime){
scheduledUnits = new JavaPriorityQueue();
this.stopTime = stopTime;
}
/**
* Picks the next scheduleable object to execute
*/
protected Scheduleable pickNext(){
Scheduleable s;
// Increase the current time to
// be synchronized with the current running unit.
currentTime = scheduledUnits.minValue();
s = (Scheduleable) scheduledUnits.removeFirst();
return s;
}
/**
* States whether an item is already scheduled.
* To avoid unnecessary resceduling, e.g. in the IBASwitch.
*/
public boolean isScheduled(Scheduleable s){
return scheduledUnits.indexOf(s) != -1;
77
}
/**
* Schedules a scheduleable object for excecution
* at at specified time.
*/
public void schedule(Scheduleable s, int time){
// Error if time is below current time
if (time < currentTime){
Reporter.error("NewKernel.schedule: "+
"Can’t schedule events back in time!");
}
// The JavaPriorityQueue will not schedule an item twice on the
// same time step. It’s a feature, not a bug...
/*
// DEBUG
Reporter.debugln("Scheduling "+((Unit)s).getID()+ " on time "+time);
//
*/
numSchedule++;
scheduledUnits.insert(s, time);
}
public String report (){
return "NewKernel";
}
// For benchmarking
public long timeSpentPickingAndScheduling = 0;
public long timeSpentRunningCurrent = 0;
}
78
no.uio.ifi.gruns.RandomAddress
package no.uio.ifi.gruns;
import java.util.Random;
/**
* Generates random addresses
*/
public class RandomAddress{
static Random random = new Random();
/**
* Sets the seed used to return the random addresses
*/
public static void setSeed(int seed){
random.setSeed(seed);
}
/**
* Returns one of the addresses supplied at random
*/
public static Address nextAddress(Address [] addresses){
return addresses[random.nextInt(addresses.length)];
}
}
79
no.uio.ifi.gruns.Reporting
package no.uio.ifi.gruns;
public interface Reporting {
/**
* Reports some information about this unit.
*/
public String report();
}
80
no.uio.ifi.gruns.RoutingTableEntry
package no.uio.ifi.gruns;
import java.util.ArrayList;
/**
* Represents the entry of one address in the routing table.
* Contains a number of possible routes for this address.
*/
public class RoutingTableEntry {
/**
* Keeps track of which route to return the next time
*/
protected int nextRouteIndex;
/**
* The possible routes of this address
*/
protected ArrayList routes;
public RoutingTableEntry(){
nextRouteIndex = 0;
routes = new ArrayList();
}
/**
* Adds a route to this address
*/
public void addRoute(Route r){
routes.add(r);
}
/**
* Deletes a route from this address
*/
public void deleteRoute(Route r){
int index = -1;
if ( (index = routes.indexOf(r)) >= 0 ){
routes.remove(index);
}
}
/**
* Gets the next route to send the packet out on.
*/
public Route getNextRoute(){
Route retVal = (Route) routes.get(nextRouteIndex);
nextRouteIndex = ( nextRouteIndex + 1 ) % routes.size();
return retVal;
}
}
81
no.uio.ifi.gruns.Switch
package no.uio.ifi.gruns;
/**
* Represents a switch, which receives packets on input ports,
* looks up the address in the routing table and forwards the
* packet on the correct output link.
*/
public class Switch extends Unit implements Scheduleable {
public Switch(Kernel kernel){
super(kernel);
}
/**
* Processes the packet
*/
protected void processPacket(Packet p){
}
/**
* Forwards the packet
*/
protected void forwardPacket(Packet p,
int portNumber,
int VLNumber) {
}
public String report(){
return "Switch";
}
public void act(){
}
}
82
no.uio.ifi.gruns.Utils
package no.uio.ifi.gruns;
import java.text.NumberFormat;
import java.util.Locale;
/**
* This class contains some common methods that
* can be useful from any class
*/
public class Utils {
private static final int BITS_PER_BYTE = 8;
private static int MASK = 0x80;
private static final NumberFormat numberFormat;
private static final Locale locale;
static{
locale = Locale.ENGLISH;
numberFormat = NumberFormat.getInstance(locale);
}
/**
* Prints a byte[] as a bit string (of 1’s and 0’s).
* Prints four bytes per line if more that four bytes.
* @param b The bytes to print
*/
public static void printAsBitString(byte[] b){
Reporter.println(asBitString(b));
}
/**
* Returns a byte[] as a bit string (of 1’s and 0’s).
* Prints four bytes per line if more that four bytes.
* @param b The bytes to return as a bit string
* @return a bit string of the bytes supplied.
*/
public static String asBitString(byte[] b){
StringBuffer retVal = new StringBuffer();
for (int i=0; i < b.length; i++){
retVal.append(asBitString(b[i]));
retVal.append(" ");
if( (i + 1) % 4 == 0) retVal.append("\n");
}
// Strip off last character if it is a space.
return retVal.toString().trim();
}
/**
* Returns a byte as a bit string (of 1’s and 0’s).
* @param b The byte to return as a bit string
* @return a bit string of the byte supplied.
*/
83
public static String asBitString(byte b){
StringBuffer retVal = new StringBuffer();
MASK = 0x80;
for (int j=0; j < BITS_PER_BYTE; j++){
if ( (b & MASK) != 0){
retVal.append("1");
}else {
retVal.append("0");
}
MASK = MASK >> 1;
}
return retVal.toString().trim();
}
/**
* Returns a String with large number on a more readable form.
*/
public static String formatInt(int number){
return numberFormat.format(number);
}
/**
* Returns a String with large number on a more readable form.
*/
public static String formatLong(long number){
return numberFormat.format(number);
}
/**
* Returns a String with a double on a more readable form.
*/
public static String formatDouble(double number){
return numberFormat.format(number);
}
/**
* Prints <i>"Press Enter to continue!"</i> and
* waits for keyboard press <Enter> before we continue.
*/
public static void pause(){
Reporter.print("Press Enter to continue!");
Reporter.getOutputStream().flush();
try{
new java.io.BufferedReader(
new java.io.InputStreamReader(System.in)).readLine();
}catch(Exception e) {
Reporter.println("Error pausing!");
e.printStackTrace(Reporter.getOutputStream());
}
}
/**
* Parses a string with an address range and returns an array
* containing each address in the range.
* The format of the string can be one of the following,
* where aaa, bbb, ccc and ddd represents integers between 0 and 255:
* <table>
84
* <tr><td>aaa.bbb</td><td>Adds the specified address</tr>
* <tr><td>aaa.bbb-ccc.ddd</td><td>Adds addresses ranging from
*
aaa.bbb to ccc.ddd, inclusive.</td></tr>
* </table>
* @param range A string describing the address range.
*/
public static Address[] getAddresses(String range){
AddressVector retVal = new AddressVector();
int dashIndex = range.indexOf(’-’);
// No range specified, just add the address
if (dashIndex == -1){
Address[] a = { new Address(range)};
return a;
}
else{
String startAddr = range.substring(0, dashIndex);
String endAddr = range.substring(dashIndex+1);
int[] startAddress = { Integer.
parseInt(startAddr.
substring(0, range.indexOf(’.’))),
Integer.
parseInt(startAddr.
substring(range.indexOf(’.’)+1)) };
int[] endAddress = { Integer.
parseInt(endAddr.
substring(0, range.indexOf(’.’))),
Integer.
parseInt(endAddr.
substring(range.indexOf(’.’)+1)) } ;
int[] currentAddress = new int[2];
// Check the input parameters
// Range check
checkAddress(startAddr);
checkAddress(endAddr);
// Start must be smaller than end
if (
(endAddress[0] < startAddress[0]) ||
( (endAddress[0] == startAddress[0]) &&
(endAddress[1] < startAddress[1]) ) )
{
throw new IllegalArgumentException("\nStart address "+
"must be smaller than "+
"end address. "+
startAddr+" is larger "+
"than "+endAddr+".");
}
// Loop through all the addresses and add them
int limit = 255;
currentAddress[1] = startAddress[1];
for (currentAddress[0] = startAddress[0];
currentAddress[0] <= endAddress[0];
currentAddress[0]++){
85
// Adjust the limit of the last part of the address if
// the last prefix is reached
if (currentAddress[0] == endAddress[0]){
limit = endAddress[1];
}
while( currentAddress[1] <= limit ){
retVal.add(new Address(currentAddress[0]+
"."+currentAddress[1]));
currentAddress[1]++;
}
// Reset last part of address for next run
currentAddress[1] = 0;
}
}
return retVal.toAddressArray();
}
/**
* Checks an address on string form for validity
*/
private static void checkAddress(String address)
throws IllegalArgumentException {
int[] addr = { Integer.
parseInt(address.
substring(0, address.indexOf(’.’))),
Integer.
parseInt(address.
substring(address.indexOf(’.’)+1)) } ;
if (addr[0] < 0 || addr[0] > 255){
throw new IllegalArgumentException("Address parts must be "+
"in the range 0 to 255. "+
addr[0]+" is out of range.");
}
if (addr[1] < 0 || addr[1] > 255){
throw new IllegalArgumentException("Address parts must be "+
"in the range 0 to 255. "+
addr[1]+" is out of range.");
}
}
/**
* Converts a time in milliseconds to a string on the form:
* hh:mm:ss.msc
*/
public static String timeFormat(long time){
StringBuffer retVal = new StringBuffer();
long
long
long
long
millis = time;
hours = millis / (60 * 60 * 1000);
minutes = (millis - (hours * 60 * 60 * 1000) ) / (60 * 1000);
seconds = (millis - (minutes * (60 * 1000)) (hours * 60 * 60 * 1000) ) / 1000;
86
//Subtract the millis used up in hours,
//mins and seconds from the milli time.
millis = time - (hours * 60 * 60 * 1000) (minutes * (60 * 1000)) - (seconds * 1000);
retVal.append(hours < 10 ? "0" : "");
retVal.append(hours + ":");
retVal.append(minutes < 10 ? "0" : "");
retVal.append(minutes+ ":");
retVal.append(seconds < 10 ? "0" : "");
retVal.append(seconds + ".");
retVal.append(millis < 100 ? "0" : "");
retVal.append(millis < 10 ? "0" : "");
retVal.append(millis);
return retVal.toString();
}
}
87
no.uio.ifi.gruns.gui.CustomTableModel
/**
* Used to display the simulation data in a table
*/
package no.uio.ifi.gruns.gui;
import javax.swing.table.*;
public class CustomTableModel extends AbstractTableModel {
protected Object[][] rowData;
protected Object[] columnNames;
public CustomTableModel(int numRows, int numCols) {
this.rowData = new Object[numRows][numCols];
this.columnNames = new Object[numCols];
}
public CustomTableModel(Object[][] rowData, Object[] columnNames) {
this.rowData = rowData;
this.columnNames = columnNames;
}
public String getColumnName(int col) {
return columnNames[col].toString();
}
public int getRowCount() { return rowData.length; }
public int getColumnCount() {
return columnNames.length;
}
public Object getValueAt(int row, int col) {
return rowData[row][col];
}
public boolean isCellEditable(int row, int col)
{ return false; }
public void setValueAt(Object value, int row, int col) {
rowData[row][col] = value;
fireTableCellUpdated(row, col);
}
public int rowOfKey(Object key) {
int retVal = -1;
for (int i=0; i < rowData.length; i++) {
if (rowData[i][0].equals(key)) {
retVal = i;
}
}
return retVal;
}
public int colOfKey(Object key) {
int retVal = -1;
for (int i=0; i < columnNames.length; i++) {
if (columnNames[i].equals(key)) {
88
retVal = i;
}
}
return retVal;
}
public String toString() {
StringBuffer retVal = new StringBuffer();
for (int i=0; i < columnNames.length; i++) {
retVal.append(columnNames[i]);
retVal.append(";");
}
retVal.append("\n");
for (int i=0; i < rowData.length; i++) {
for (int j=0; j < rowData[i].length-1; j++) {
retVal.append(rowData[i][j]);
retVal.append(";");
}
// No ";" on the end of the line
retVal.append(rowData[i][rowData[i].length-1]);
retVal.append("\n");
}
return retVal.toString();
}
}
89
no.uio.ifi.gruns.gui.StatusPanel
/*
* StatusPanel.java
*
* Created on 18. desember 2002, 19:38
*/
package no.uio.ifi.gruns.gui;
import no.uio.ifi.gruns.*;
import no.uio.ifi.gruns.infiniband.*;
import no.uio.ifi.tools.*;
import
import
import
import
java.awt.*;
javax.swing.*;
javax.swing.border.*;
javax.swing.table.*;
import java.util.Properties;
import java.util.Enumeration;
import java.util.*;
/**
*
* @author erikbra
*/
public class StatusPanel extends javax.swing.JPanel
protected
protected
protected
protected
final
final
final
final
static
static
static
static
int
int
int
int
{
BORDER_LEFT = 15;
BORDER_RIGHT = 15;
BORDER_TOP = 15;
BORDER_BOTTOM = 15;
protected final static int addrPrefix = 1;
JTabbedPane tabs;
protected BorderLayout layout;
protected JSplitPane summary;
//protected JPanel sources,drains,edges,cores;
protected JPanel north;
protected CustomTableModel paramsModel, counterModel,
sourcesModel, drainsModel, edgesModel, coresModel;
protected
protected
protected
protected
JLabel
JLabel
JLabel
JLabel
timeStepLabel;
realTimeLabel;
speedLabel;
avgSpeedLabel;
protected JLabel queueLenLabel;
protected JLabel allocatedMemLabel;
protected JLabel freeMemLabel;
protected JLabel maxMemLabel;
protected
protected
protected
protected
JLabel[][] sourceNodes;
JLabel[] drainNodes;
JLabel[][] edgeSwitches;
JLabel[][] coreSwitches;
protected long startTime;
protected int lastTimeStep;
protected long lastRealTime;
90
/** Used to calculate effective usage percentage on switches’ ports. */
protected int currentTimeStep = 0;
/** Creates a new instance of StatusPanel */
public StatusPanel(int numSourceNodes,
int numDrainNodes,
int numEdgeSwitches,
int numCoreSwitches,
long startTime) {
tabs = new JTabbedPane();
layout = new BorderLayout();
this.setLayout(layout);
this.add(tabs, BorderLayout.CENTER);
north = new JPanel();
north.setLayout(new FlowLayout());
JButton dumpAll;
north.add(dumpAll = new JButton("Dump all data"));
dumpAll.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent e) {
dumpData();
}});
JButton dumpParams;
north.add(dumpParams = new JButton("Dump params"));
dumpParams.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent e) {
dumpParams();
}});
JButton dumpCounter;
north.add(dumpCounter = new JButton("Dump counter"));
dumpCounter.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent e) {
dumpCounter();
}});
JButton dumpSources;
north.add(dumpSources = new JButton("Dump sources"));
dumpSources.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent e) {
dumpSources();
}});
JButton dumpDrains;
north.add(dumpDrains = new JButton("Dump drains"));
dumpDrains.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent e) {
dumpDrains();
}});
JButton dumpEdges;
north.add(dumpEdges = new JButton("Dump edges"));
dumpEdges.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent e) {
dumpEdges();
}});
JButton dumpCores;
north.add(dumpCores = new JButton("Dump cores"));
dumpCores.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent e) {
dumpCores();
}});
this.add(north, BorderLayout.NORTH);
summary = new JSplitPane();
this.startTime=startTime;
91
JTable simParams = new JTable();
String [] columnNames = {"Parameter", "Value"};
Properties props = System.getProperties();
Enumeration keys = props.propertyNames();
String key=null;
int val=0;
int num=0;
// Find number of infiniband properties
while(keys.hasMoreElements()) {
key = (String) keys.nextElement();
if
(key.startsWith("infiniband.")) {
num++;
}
}
String [][] data = new String[num][2];
// Read properties
keys = props.propertyNames();
for(int
i=0; keys.hasMoreElements();) {
key = (String) keys.nextElement();
if
(key.startsWith("infiniband.")) {
data[i][0] = key;
try{
val = Integer.parseInt(props.getProperty(key));
data[i][1] = Utils.formatInt(val);
}catch(NumberFormatException nfe){
data[i][1] = props.getProperty(key);
}
i++;
}
}
simParams.setModel(paramsModel = new CustomTableModel(data, columnNames));
summary.setLeftComponent(new JScrollPane(simParams,
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED));
// Stats about approximate object sizes
long freeMem;
long switchSize, linkSize, sourceNodeSize, drainNodeSize, packetSize;
IBASwitch test; Link link; IBASourceNode s; IBADrainNode d; IBAPacket p;
Kernel kernel = new Kernel(Integer.getInteger("infiniband.STOP_TIME", 0).intValue());
int numberOfVLs = 16;
int inputBufferSize =
2 * Integer.parseInt(
System.getProperty(
"infiniband.EXP_PACKET_SIZE"));
int outputBufferSize =
2 * Integer.parseInt(
System.getProperty(
"infiniband.EXP_PACKET_SIZE"));
System.gc();
freeMem = Runtime.getRuntime().freeMemory();
test = new IBASwitch(4, 4, numberOfVLs, inputBufferSize, outputBufferSize,
"TestSwitch", kernel);
switchSize = freeMem-Runtime.getRuntime().freeMemory();
test = null;
System.gc();
freeMem = Runtime.getRuntime().freeMemory();
link = new Link(kernel);
linkSize = freeMem-Runtime.getRuntime().freeMemory();
link = null;
System.gc();
freeMem = Runtime.getRuntime().freeMemory();
s = new IBASourceNode(1, numberOfVLs, "Test source", kernel);
sourceNodeSize = freeMem-Runtime.getRuntime().freeMemory();
s = null;
92
System.gc();
freeMem = Runtime.getRuntime().freeMemory();
d = new IBADrainNode(1, numberOfVLs, "Test drain", kernel);
drainNodeSize = freeMem-Runtime.getRuntime().freeMemory();
d = null;
System.gc();
freeMem = Runtime.getRuntime().freeMemory();
p = new IBAPacket();
p.lrh.setLNH(IBAPacket.LNH_IBA_local);
p.bth.setOpCode(IBAPacket.RD_SEND_ONLY);
StringBuffer str = new StringBuffer();
int numChars = Integer.parseInt(System.getProperty("infiniband.EXP_PAYLOAD_SIZE"));
for
(int i=0; i < numChars; i++){
str.append((char) ((int) ’A’));
}
p.pyld.setContent(str.toString().getBytes());
p.updatePacketLength();
packetSize = freeMem-Runtime.getRuntime().freeMemory();
p = null;
kernel = null;
System.gc();
// Counting/time stats
JTable counter = new JTable();
columnNames = new String[2];
columnNames[0] =
"Variable";
columnNames[1] =
"Value";
String [][] statVars = {
{"Time
step", "0"},
threshold",
{"Transient
Utils.formatInt(Integer.getInteger("infiniband.TRANSIENT_PERIOD",0).intValue())},
{"Transient
period finished", "NO"},
time used", "0"},
{"Instant speed", "0 time steps/second"},
{"Average speed", "0 time steps/second"},
{"Kernel’s item queue length", "0"},
{"Total allocated memory", Utils.formatLong(Runtime.getRuntime().totalMemory())+" B"},
{"Free memory of allocated", Utils.formatLong(Runtime.getRuntime().freeMemory())+" B"},
{"Maximum memory", Utils.formatLong(Runtime.getRuntime().maxMemory())+" B"},
{"Size of a switch", Utils.formatLong(switchSize)+" B"},
{"Size of a link", Utils.formatLong(linkSize)+" B"},
{"Size of a source node", Utils.formatLong(sourceNodeSize)+" B"},
{"Size of a drain node", Utils.formatLong(drainNodeSize)+" B"},
{"Size of a packet", Utils.formatLong(packetSize)+" B"}
{"Real
};
counter.setModel(counterModel = new CustomTableModel(statVars, columnNames));
summary.setRightComponent(new JScrollPane(counter,
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED));
summary.setDividerLocation(400);
tabs.addTab("Simulation
summary",
summary);
sourceNodes = new JLabel[numSourceNodes][3];
drainNodes = new JLabel[numDrainNodes];
edgeSwitches = new JLabel[numEdgeSwitches][8];
coreSwitches = new JLabel[numCoreSwitches][8];
// Sources
JTable sourcesTable = new JTable();
columnNames = new String[4];
columnNames[0] =
columnNames[1] =
"Node name";
"Packets sent";
93
columnNames[2] =
columnNames[3] =
"Packets waiting";
"Effective usage";
data = new String[numSourceNodes][4];
for
(int i=0; i < numSourceNodes; i++){
data[i][0] =
data[i][1] =
data[i][2] =
data[i][3] =
"Source "+addrPrefix+"."+i;
"0%";
"0%";
"0%";
}
sourcesTable.setModel(sourcesModel = new CustomTableModel(data, columnNames));
tabs.addTab("Source
nodes",
new JScrollPane(sourcesTable,
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED));
// Drains
JTable drainsTable = new JTable();
columnNames = new String[numSourceNodes + 1];
columnNames[0] =
for
"Node name";
(int i=0; i < numSourceNodes; i++) {
columnNames[i+1] =
"Source "+addrPrefix+"."+i;
}
data = new String[numDrainNodes][numSourceNodes+1];
for
(int i=0; i < numDrainNodes; i++) {
data[i][0] =
for
"Drain "+addrPrefix+"."+i;
(int j = 1; j < data[i].length; j++) {
data[i][j] =
"0";
}
}
drainsTable.setModel(drainsModel = new CustomTableModel(data, columnNames));
tabs.addTab("Drain
nodes",
new JScrollPane(drainsTable,
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED));
/*
// Fix width of cells in the table
TableColumn column = null;
Component comp = null;
int headerWidth = 0;
int cellWidth = 0;
for (int i = 0; i < data[0].length; i++) {
column = drainsTable.getColumnModel().getColumn(i);
comp = drainsTable.getTableHeader().getDefaultRenderer().
getTableCellRendererComponent(
null, column.getHeaderValue(),
false, false, 0, 0);
headerWidth = comp.getPreferredSize().width;
comp = drainsTable.getDefaultRenderer(drainsModel.getColumnClass(i)).
getTableCellRendererComponent(
drainsTable, ""+data[0][i],
false, false, 0, i);
cellWidth = comp.getPreferredSize().width;
column.setPreferredWidth(Math.max(headerWidth, cellWidth));
94
}
*/
// Edge switches
JTable edgesTable = new JTable();
String[] switchHeading = {"Switch
Name",
Port 0",
Utilization",
Port 1",
Utilization",
Port 2",
Utilization",
Port 3",
Utilization"};
"Packets
"Port 0,
"Packets
"Port 1,
"Packets
"Port 2,
"Packets
"Port 3,
data = new String[numEdgeSwitches][switchHeading.length];
for
(int i=0; i < numEdgeSwitches; i++) {
data[i][0] =
for
"Edge Switch "+i;
(int j=1; j < data[i].length; j+=2) {
data[i][j] =
"0";
"0%";
data[i][j+1] =
}
}
edgesTable.setModel(edgesModel = new CustomTableModel(data, switchHeading));
tabs.addTab("Edge
switches",
new JScrollPane(edgesTable,
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED));
// Core switches
JTable coresTable = new JTable();
data = new String[numCoreSwitches][switchHeading.length];
for
(int i=0; i < numCoreSwitches; i++) {
data[i][0] =
for
"Core Switch "+i;
(int j=1; j < data[i].length; j+=2) {
data[i][j] =
"0";
"0%";
data[i][j+1] =
}
}
coresTable.setModel(coresModel = new CustomTableModel(data, switchHeading));
tabs.addTab("Core
switches",
new JScrollPane(coresTable,
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED));
}
public void setSourceStats(int sourceNo, int sent, int waiting){
sourcesModel.setValueAt(""+sent, sourceNo, 1);
sourcesModel.setValueAt(""+waiting,sourceNo, 2 );
if (sent > 0) {
int usagePercentage =
Integer.getInteger("infiniband.USAGE_PERCENTAGE", 100).intValue();
sourcesModel.setValueAt(""+Utils.formatDouble(((double)sent)/(sent+waiting)*
usagePercentage)+"%",
sourceNo, 3);
}
}
95
public void setDrainStats(int drainNo,
no.uio.ifi.gruns.infiniband.IBAStatistics.IBADrainNodeStats stats){
HashMap sources;
Set keys;
SortedSet sortedKeys;
Iterator it;
String key;
sources = stats.getPacketsReceivedPerSource();
int col = 0;
keys = sources.keySet();
sortedKeys = new TreeSet(new IBAUnitComparator());
sortedKeys.addAll(keys);
it = sortedKeys.iterator();
while(it.hasNext())
{
key = (String) it.next();
//System.err.println("colOfKey(Source "+key+") = "+drainsModel.colOfKey("Source "+key));
col = drainsModel.colOfKey("Source "+key);
drainsModel.setValueAt(""+sources.get(key), drainNo, col);
}
}
/**
* Calculates the percentage of utilization of a unit in the network.
* Divides the total number of bytes sent with the theoretical
* maximum which is the number of time steps elapsed, <b>t</b>, times
* the number of bytes per block, <b>n</b>. Since the simulator
* can process one block per time step, this should give a good percentage
* estimation.
*/
private double usagePercentage(int bytesSent) {
return 100 * ((double) (bytesSent *
Integer.getInteger("infiniband.REAL_PACKET_SIZE").intValue())) /
((currentTimeStep-Integer.getInteger("infiniband.TRANSIENT_PERIOD", 0).intValue())
Integer.getInteger("infiniband.BLOCK_SIZE").intValue());
*
}
public void setEdgeStats(int edgeNo, int[] sent) {
for (int i=0; i < sent.length; i++) {
edgesModel.setValueAt(""+sent[i], edgeNo, (i*2)+1);
// Percent
edgesModel.setValueAt(""+Utils.formatDouble(usagePercentage(sent[i]))+"%",
edgeNo, (i*2)+2);
}
}
public void setCoreStats(int coreNo, int[] sent) {
for (int i=0; i < sent.length; i++) {
coresModel.setValueAt(""+sent[i], coreNo, (i*2)+1);
// Percent
coresModel.setValueAt(""+Utils.formatDouble(usagePercentage(sent[i]))+"%",
coreNo, (i*2)+2);
}
}
public void setTime(int time) {
/*
String [][] statVars = {
{"Time step", "0"},
{"Real time used", "0"},
{"Instant speed", "0 time steps/second"},
{"Average speed", "0 time steps/second"},
{"Kernel’s item queue length", "0"},
{"Total allocated memory", Utils.formatLong(Runtime.getRuntime().totalMemory())+" KB"},
{"Free memory of allocated", Utils.formatLong(Runtime.getRuntime().freeMemory())+" KB"},
{"Maximum memory", Utils.formatLong(Runtime.getRuntime().maxMemory())+" KB"}
};
*/
96
currentTimeStep = time;
long currTime = System.currentTimeMillis();
int rowNum;
rowNum = counterModel.rowOfKey("Time
step");
counterModel.setValueAt(Utils.formatInt(time)+" of "+
Utils.formatInt(Integer.parseInt(
System.getProperty("infiniband.STOP_TIME"))),
rowNum, 1);
rowNum = counterModel.rowOfKey("Real time used");
counterModel.setValueAt(Utils.timeFormat(currTime - startTime), rowNum, 1);
long speed = (1000 * (lastTimeStep - time)) / (lastRealTime - currTime);
long avgSpeed = (1000 * time) / (currTime-startTime);
rowNum = counterModel.rowOfKey("Instant
speed");
" time steps/second",
counterModel.setValueAt(Utils.formatLong(speed)+
rowNum = counterModel.rowOfKey("Average
rowNum, 1);
speed");
" time steps/second",
counterModel.setValueAt(Utils.formatLong(avgSpeed)+
rowNum = counterModel.rowOfKey("Transient
rowNum, 1);
period finished");
counterModel.setValueAt((time > Integer.getInteger("infiniband.TRANSIENT_PERIOD", 0).intValue())
?"YES"
:"NO", rowNum, 1);
lastTimeStep = time;
lastRealTime = currTime;
}
public void setQueueLen(int length) {
int rowNum = counterModel.rowOfKey("Kernel’s item queue length");
counterModel.setValueAt(Utils.formatInt(length), rowNum, 1);
}
public void updateMemUsage()
{
int rowNum;
rowNum = counterModel.rowOfKey("Total
allocated memory");
counterModel.setValueAt(Utils.formatLong(Runtime.getRuntime().totalMemory())+"
rowNum, 1);
rowNum = counterModel.rowOfKey("Free
memory of allocated");
counterModel.setValueAt(Utils.formatLong(Runtime.getRuntime().freeMemory())+"
rowNum, 1);
rowNum = counterModel.rowOfKey("Maximum
B",
memory");
counterModel.setValueAt(Utils.formatLong(Runtime.getRuntime().maxMemory())+"
rowNum, 1);
}
public String getData()
{
StringBuffer retVal = new StringBuffer();
retVal.append(paramsModel);
retVal.append("\n\n");
retVal.append(counterModel);
retVal.append("\n\n");
retVal.append(sourcesModel);
retVal.append("\n\n");
retVal.append(drainsModel);
retVal.append("\n\n");
retVal.append(edgesModel);
retVal.append("\n\n");
retVal.append(coresModel);
return
B",
retVal.toString();
}
97
B",
public void dumpData()
{
Reporter.println(getData());
}
public void dumpSources()
{
Reporter.println(sourcesModel);
}
public void dumpDrains()
{
Reporter.println(drainsModel);
}
public void dumpEdges()
{
Reporter.println(edgesModel);
}
public void dumpCores()
{
Reporter.println(coresModel);
}
public void dumpParams()
{
Reporter.println(paramsModel);
}
public void dumpCounter()
{
Reporter.println(counterModel);
}
public static void main(String [] args)
{
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
StatusPanel panel = new StatusPanel(12,12,12,16,System.currentTimeMillis());
f.setContentPane(panel);
f.setSize(500,500);
f.setVisible(true);
}
}
98
no.uio.ifi.gruns.infiniband.IBAConstants
package no.uio.ifi.gruns.infiniband;
/**
* Defines some constants needed in some of the IBA classes.
*/
public final class IBAConstants{
/**
* Indicates for how long to wait for the network to
* enter a steady state. Then we can start collecting data.
*/
public static final int IBA_TRANSIENT_PERIOD = 10000;
/**
* The size of an IBA block in bytes.
* One block is processed on a given time step in the simulator.
*/
public static final int IBA_BLOCK_SIZE = 64;
/**
* The number of time steps it takes to process an IBA
* packet in a switch (i.e. to look up the address)
*/
public static final int IBA_PACKET_PROCESSING_TIME = 5;
/**
* The time to wait before rescheduling
* in a switch if the output VL is not free.
*/
public static final int IBA_SLEEP_TIME = 1;
/**
* The maximum number of virtual lanes on a link
*/
public static final int MAX_NUMBER_OF_VLS = 16;
/**
* The overhead of the packets used in the
* experiments
*/
public static final int EXP_OVERHEAD = 38;
/**
* The packet size used in experiments
*/
public static final int EXP_PACKET_SIZE = 4096;
//public static final int EXP_PACKET_SIZE = 1024;
/**
* The size of the payload used in the
* experiments
*/
public static final int EXP_PAYLOAD_SIZE = EXP_PACKET_SIZE - EXP_OVERHEAD;
// the one above used to test priorities. The limit of high priority
// states how many chunks of 4K bytes can be sent on hi pri before
// we get to send a packet on low pri.
/**
* Loads all the constants as system properties.
*/
99
public static final void loadProperties(){
if (System.getProperty("infiniband.TRANSIENT_PERIOD")
System.setProperty("infiniband.TRANSIENT_PERIOD",
== null) {
Integer.toString(IBA_TRANSIENT_PERIOD));
}
if
(System.getProperty("infiniband.BLOCK_SIZE") == null){
System.setProperty("infiniband.BLOCK_SIZE",
Integer.toString(IBA_BLOCK_SIZE));
}
if
(System.getProperty("infiniband.PACKET_PROCESSING_TIME") == null){
System.setProperty("infiniband.PACKET_PROCESSING_TIME",
Integer.toString(IBA_PACKET_PROCESSING_TIME));
}
if
(System.getProperty("infiniband.SLEEP_TIME") == null){
System.setProperty("infiniband.SLEEP_TIME",
Integer.toString(IBA_SLEEP_TIME));
}
if
(System.getProperty("infiniband.MAX_NUMBER_OF_VLS") == null){
System.setProperty("infiniband.MAX_NUMBER_OF_VLS",
Integer.toString(MAX_NUMBER_OF_VLS));
}
if
(System.getProperty("infiniband.EXP_OVERHEAD") == null){
System.setProperty("infiniband.EXP_OVERHEAD",
Integer.toString(EXP_OVERHEAD));
}
if
(System.getProperty("infiniband.EXP_PACKET_SIZE") == null){
System.setProperty("infiniband.EXP_PACKET_SIZE",
Integer.toString(EXP_PACKET_SIZE));
}
if
(System.getProperty("infiniband.EXP_PAYLOAD_SIZE") == null){
int pyld_size = Integer.parseInt(
System.getProperty("infiniband.EXP_PACKET_SIZE")) Integer.parseInt(System.getProperty("infiniband.EXP_OVERHEAD"));
System.setProperty("infiniband.EXP_PAYLOAD_SIZE",
Integer.toString(pyld_size));
}
int realPktSize = Integer.parseInt(System.getProperty("infiniband.EXP_PACKET_SIZE")) + 2;
System.setProperty("infiniband.REAL_PACKET_SIZE",
}
}
100
""+(realPktSize));
/* VCRC */
no.uio.ifi.gruns.infiniband.IBADelayedSwitch
package no.uio.ifi.gruns.infiniband;
import no.uio.ifi.gruns.*;
/**
* Introduces a delay in the sending of packets in the output port
* by trying to figure out if there’s traffic coming on the high priority lanes
* in the output ports, and waiting until this data is available before
* sending from the output port. The goal is to avoid sending a packet on low
* priority just because the high priority packets are delayed in the switch.
*
* However, this doesn’t work very well, because it is impossible to know anything
* about the next packet on a particular VL when the switch has not yet read this packet
* since it hasn’t arrived in the switch yet.
*/
public class IBADelayedSwitch extends IBASwitch {
// {{{ public IBADelayedSwitch(...)
/**
* @param numberOfInputPorts The number of input ports
* @param numberOfOutputPorts The number of output ports
* @param inputBufferSize The size of the buffers in the input
*
ports. Affects how the switch acts,
*
because when the output buffers go full, the low
*
priority queues get more priority than when
*
there’s still plenty of space.
* @param outputBufferSize The size of the buffers in the output
*
ports.
* @param numberOfVirtualLanes The number of virtual lanes on
*
input and output ports.
* @param ID A string identifying the switch
* @param kernel The kernel to use for simulation
*/
public IBADelayedSwitch(int numberOfInputPorts,
int numberOfOutputPorts,
int numberOfVirtualLanes,
int inputBufferSize,
int outputBufferSize,
String ID,
Kernel kernel){
super(kernel);
int i;
// {{{ DEBUG
Reporter.debugln("IBADelayedSwitch");
// }}}
this.inputBufferSize = inputBufferSize;
this.outputBufferSize = outputBufferSize;
// Create input and output ports
inputPorts = new IBAInputPort[numberOfInputPorts];
for (i=0; i < numberOfInputPorts; i++){
inputPorts[i] = new IBAInputPort(numberOfVirtualLanes,
inputBufferSize,
kernel);
inputPorts[i].setSink(this);
inputPorts[i].setID(ID+", input port "+i);
}
outputPorts = new IBADelayedOutputPort[numberOfOutputPorts];
101
for (i=0; i < numberOfOutputPorts; i++){
outputPorts[i] = new IBADelayedOutputPort(numberOfVirtualLanes,
outputBufferSize,
kernel,this,i);
outputPorts[i].setID(ID+", delayed output port "+i);
}
// Assign ID
this.ID = ID+ " (delayed) ";
// Other initialization
VLstates = new VLstate[inputPorts.length][numberOfVirtualLanes];
for (i=0; i < VLstates.length; i++){
for (int j=0; j < VLstates[i].length; j++){
VLstates[i][j] = new VLstate();
}
}
}
// }}}
/**
* Returns all the states that have the output port
* of the specified output port number.
* TODO: This is impossible, because the packets have not yet been
* processed, we don’t know if there are coming any packets to this
* particular output port.
*
*/
VLstate[][] getStates(){
// {{{ Kommentert ut
/*
Reporter.println("IBADelayedSwtich.getStates: VLstates.length = "+VLstates.length);
java.util.Vector states = new java.util.Vector(VLstates.length);
VLstate st = null;
for (int i=0; i < VLstates.length; i++){
for (int j=0; j < VLstates[i].length; j++){
if (st != null){
Reporter.println("st = "+st);
if (st.outputPort != null){
Reporter.println("st.outputPort.portNumber = "+
st.outputPort.portNumber+", "+
"st.outputPort.VLNumber = "+
st.outputPort.VLNumber);
}
}
st = VLstates[i][j];
if (st != null && st.outputPort!=null && st.outputPort.portNumber == portNumber){
states.add(st);
}
}
}
VLstate[] retVal = new VLstate[states.size()];
retVal = (VLstate[]) states.toArray(retVal);
return retVal;
*/
// }}}
102
return VLstates;
}
}
103
no.uio.ifi.gruns.infiniband.IBADelayedSwitch2
package no.uio.ifi.gruns.infiniband;
import no.uio.ifi.gruns.*;
/**
* Introduces a delay between each packet in the output port equal to the
* time the switch uses to process a packet.
* The thought is to avoid sending packets on low priority when there are packets
* on their way on high priority.
*
* The problem is of course that we introduce a delay on all packets, even if there
* aren’t coming any more packets on high priority.
*/
public class IBADelayedSwitch2 extends IBASwitch {
// {{{ public IBADelayedSwitch2(...)
/**
* @param numberOfInputPorts The number of input ports
* @param numberOfOutputPorts The number of output ports
* @param inputBufferSize The size of the buffers in the input
*
ports. Affects how the switch acts,
*
because when the output buffers go full, the low
*
priority queues get more priority than when
*
there’s still plenty of space.
* @param outputBufferSize The size of the buffers in the output
*
ports.
* @param numberOfVirtualLanes The number of virtual lanes on
*
input and output ports.
* @param ID A string identifying the switch
* @param kernel The kernel to use for simulation
*/
public IBADelayedSwitch2(int numberOfInputPorts,
int numberOfOutputPorts,
int numberOfVirtualLanes,
int inputBufferSize,
int outputBufferSize,
String ID,
Kernel kernel){
super(kernel);
int i;
// {{{ DEBUG
Reporter.debugln("IBADelayedSwitch");
// }}}
this.inputBufferSize = inputBufferSize;
this.outputBufferSize = outputBufferSize;
// Create input and output ports
inputPorts = new IBAInputPort[numberOfInputPorts];
for (i=0; i < numberOfInputPorts; i++){
inputPorts[i] = new IBAInputPort(numberOfVirtualLanes,
inputBufferSize,
kernel);
inputPorts[i].setSink(this);
inputPorts[i].setID(ID+", input port "+i);
}
outputPorts = new IBADelayedOutputPort2[numberOfOutputPorts];
for (i=0; i < numberOfOutputPorts; i++){
outputPorts[i] = new IBADelayedOutputPort2(numberOfVirtualLanes,
outputBufferSize,
104
kernel,this,i);
outputPorts[i].setID(ID+", delayed output port "+i);
}
// Assign ID
this.ID = ID+ " (delayed) ";
// Other initialization
VLstates = new VLstate[inputPorts.length][numberOfVirtualLanes];
for (i=0; i < VLstates.length; i++){
for (int j=0; j < VLstates[i].length; j++){
VLstates[i][j] = new VLstate();
}
}
}
// }}}
/**
* Returns all the states that have the output port
* of the specified output port number.
* TODO: This is impossible, because the packets have not yet been
* processed, we don’t know if there are coming any packets to this
* particular output port.
*
*/
VLstate[][] getStates(){
// {{{ Kommentert ut
/*
Reporter.println("IBADelayedSwtich.getStates: VLstates.length = "+VLstates.length);
java.util.Vector states = new java.util.Vector(VLstates.length);
VLstate st = null;
for (int i=0; i < VLstates.length; i++){
for (int j=0; j < VLstates[i].length; j++){
if (st != null){
Reporter.println("st = "+st);
if (st.outputPort != null){
Reporter.println("st.outputPort.portNumber = "+
st.outputPort.portNumber+", "+
"st.outputPort.VLNumber = "+
st.outputPort.VLNumber);
}
}
st = VLstates[i][j];
if (st != null && st.outputPort!=null && st.outputPort.portNumber == portNumber){
states.add(st);
}
}
}
VLstate[] retVal = new VLstate[states.size()];
retVal = (VLstate[]) states.toArray(retVal);
return retVal;
*/
// }}}
return VLstates;
}
}
105
no.uio.ifi.gruns.infiniband.IBAPacket
package no.uio.ifi.gruns.infiniband;
import no.uio.ifi.gruns.*;
/**
* Represents
* The packet
*
* <pre>
*
* Bit number
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
an InfiniBand Architecture (IBA) Packet.
format is the following:
0
4
8
12
16
20
24
28
32
----------------------------------------------------------------|VL
|LVer
|SL
|r |L | Destination
|
|
|
|
|s |N | Local
|
|
|
|
|v |H | ID
|
----------------------------------------------------------------| r
|
| Source
|
| s
| PktLen
| Local
|
| v
|
| ID
|
--------------------------------------------------------------------------------------------------------------------------------|IP
|TClass
| Flow Label
|
|ver
|
| 20 bits
|
----------------------------------------------------------------|Payload Length
|NxtHdr
|HopLmt
|
|
16 bits
| 8b
| 8b
|
----------------------------------------------------------------|
Source GID 127-96
|
----------------------------------------------------------------|
Source GID 95-64
|
----------------------------------------------------------------|
Source GID 63-32
|
----------------------------------------------------------------|
Source GID 31-0
|
----------------------------------------------------------------|
Destination GID 127-96
|
----------------------------------------------------------------|
Destination GID 95-64
|
----------------------------------------------------------------|
Destination GID 63-32
|
----------------------------------------------------------------|
Destination GID 31-0
|
--------------------------------------------------------------------------------------------------------------------------------| OpCode
|S|M|Pad| TVer | Partition Key
|
|
|E| |Cnt|
|
|
----------------------------------------------------------------| Reserved
|
Destination Queue Pair (QP) Number
|
| (variant)
|
|
----------------------------------------------------------------|A| Reserved
| Packet Sequence Number (PSN)
|
--------------------------------------------------------------------------------------------------------------------------------| resv
| EE-Context
|
-----------------------------------------------------------------
106
Local Routing
Header - LRH
8 bytes
Present in all
packets of a
message
Global Routing
Header - GRH
40 bytes
Present in all
packets of a
message, if indicate
by Link Next Header
in LRH
Base Transport
Header - BTH
12 bytes
Present in all
packets of a message
if indicated by LNH,
i.e. not a raw packe
Reliable Datagram
Extended Transport
Header - RDETH
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
4 bytes
----------------------------------------------------------------| Queue Key
|
----------------------------------------------------------------| resv 8b
| Source QP (SrcQP) 24b
|
-----------------------------------------------------------------
Datagram Extended
Transport Header - D
8 bytes
Present in every pac
of datagram request
messages
----------------------------------------------------------------| Virtual Address 63-32
|
----------------------------------------------------------------| Virtual Address 31-0
|
----------------------------------------------------------------| Remote Key
|
----------------------------------------------------------------| DMA Length
|
--------------------------------------------------------------------------------------------------------------------------------| Virtual Address 63-32
|
----------------------------------------------------------------| Virtual Address 31-0
|
----------------------------------------------------------------| Remote Key
|
----------------------------------------------------------------| Swap (or Add) Data 63-32
|
----------------------------------------------------------------| Swap (or Add) Data 31-0
|
----------------------------------------------------------------| Compare Data 63-32
|
----------------------------------------------------------------| Compare Data 31-0
|
--------------------------------------------------------------------------------------------------------------------------------| Syndrome
| Message Sequence Number
|
-----------------------------------------------------------------
RDMA Extended
Transport Header - R
16 bytes
Present in first pac
of RDMA request mess
Atomic Extended
Transport Header - A
28 bytes
Present in Atomic
request message
Ack extended Transpo
Header - AETH
4 bytes
Present in all ACK p
----------------------------------------------------------------| Original Remote Data 63-32
|
----------------------------------------------------------------| Original Remote data 31-0
|
-----------------------------------------------------------------
Atomic ACK Extended
Transport Header
AtomicAckETH - 8 byt
Present in all Atomi
packets
----------------------------------------------------------------| Immediate Data
|
-----------------------------------------------------------------
Immeditate Data - 4
Present in last pack
of requests with
immediate data
----------------------------------------------------------------| Payload
|
|
|
107
Payload
0-4096 bytes
*
|
|
*
|
|
*
|
------------------------------------------------|
*
|
| Pad 0-3 bytes
|
*
----------------------------------------------------------------*
*
----------------------------------------------------------------*
| ICRC
|
*
----------------------------------------------------------------*
*
*
*
*
*
*
--------------------------------*
| VCRC
|
*
--------------------------------*
*
*
*
*/
public class IBAPacket extends Packet{
/** The number of bits in a byte (8) */
public static final int BITS_PER_BYTE = 8;
// Size of the different header fields
/** The size of the Local Route Header */
public static final int LRH_SIZE
=
8 * BITS_PER_BYTE;
/** The size of the Global Route Header */
public static final int GRH_SIZE
= 40 * BITS_PER_BYTE;
/** The size of the Base Transport Header */
public static final int BTH_SIZE
= 12 * BITS_PER_BYTE;
/** The size of the Reliable Datagram Extended Transport Header */
public static final int RDETH_SIZE
=
4 * BITS_PER_BYTE;
/** The size of the Datagram Extended Transport Header */
public static final int DETH_SIZE
=
8 * BITS_PER_BYTE;
/** The size of the RDMA Extended Transport Header */
public static final int RETH_SIZE
= 16 * BITS_PER_BYTE;
/** The size of the Atomic Extended Transport Header */
public static final int ATOMIC_ETH_SIZE
= 28 * BITS_PER_BYTE;
/** The size of the ACK Extended Transport Header */
public static final int AETH_SIZE
=
4 * BITS_PER_BYTE;
/** The size of the Atomic ACK Extended Transport Header */
public static final int ATOMIC_ACK_ETH_SIZE
=
8 * BITS_PER_BYTE;
/** The size of the Immediate Data Extended Transport Header */
public static final int IMM_DT_SIZE
=
4 * BITS_PER_BYTE;
=
4 * BITS_PER_BYTE;
=
2 * BITS_PER_BYTE;
/** The size of the ICRC */
public static final int ICRC_SIZE
/** The size of the VCRC */
public static final int VCRC_SIZE
/**
108
Invariant CRC
4 bytes
Present in all packe
of message, if indic
by Link Next Header
(i.e. not a raw pack
Variant CRC
2 bytes
Present in all packe
of message.
* The
* The
* But
* the
* See
*/
maximum size of an IBA packet in bytes.
actual max value in IBA is 4096 + 126.
we don’t have any fields befor the LRH, and only 2 bytes after
Variant CRC, so we don’t add 126 bytes, only 2.
section 7.7.8 in the IBA spec.
public static final int MAX_SIZE
= (4096 + 2) ;
// Needed for the LRH
/** Indicates that this is a global packet */
public static byte LNH_IBA_global = (byte) 0x03;
/** Indicates that this is a local packet */
public static byte LNH_IBA_local
= (byte) 0x02;
/** Indicates that this is a non-IBA packet */
public static byte LNH_IP_non_IBA = (byte) 0x01;
/** Indicates that this is a raw packet */
public static byte LNH_raw
= (byte) 0x00;
// Needed for the OpCode field in the BTH. Types of packets.
public static byte RD_TYPE = 0x40;
/**
* Indicates that the type of the packet is
* Reliable Datagram, SEND First.
*/
public static byte RD_SEND_FIRST = (byte) (RD_TYPE | 0x00);
/**
*Indicates that the type of the packet is
* Reliable Datagram, SEND Middle.
*/
public static byte RD_SEND_MIDDLE = (byte) (RD_TYPE | 0x01);
/**
* Indicates that the type of the packet is
* Reliable Datagram, SEND Last.
*/
public static byte RD_SEND_LAST = (byte) (RD_TYPE | 0x02);
/**
* Indicates that the type of the packet is
* Reliable Datagram, SEND Last with Immediate.
*/
public static byte RD_SEND_LAST_WITH_IMMEDIATE =
(byte) (RD_TYPE | 0x03);
/**
* Indicates that the type of the packet is
* Reliable Datagram, SEND Only.
*/
public static byte RD_SEND_ONLY = (byte) (RD_TYPE | 0x04);
/**
* Indicates that the type of the packet is
* Reliable Datagram, SEND Only with Immediate.
*/
public static byte RD_SEND_ONLY_WITH_IMMEDIATE =
(byte) (RD_TYPE | 0x05);
/**
* Indicates that the type of the packet is
* Reliable Datagram, RDMA WRITE First.
*/
public static byte RD_RDMA_WRITE_FIRST = (byte) (RD_TYPE | 0x06);
109
/**
* Indicates that the type of the packet is
* Reliable Datagram, RDMA WRITE Middle.
*/
public static byte RD_RDMA_WRITE_MIDDLE = (byte) (RD_TYPE | 0x07);
/**
* Indicates that the type of the packet is
* Reliable Datagram, RDMA WRITE Last.
*/
public static byte RD_RDMA_WRITE_LAST = (byte)( RD_TYPE | 0x08);
/**
* Indicates that the type of the packet is
* Reliable Datagram, RDMA WRITE Last with Immediate.
*/
public static byte RD_RDMA_WRITE_LAST_WITH_IMMEDIATE =
(byte) (RD_TYPE | 0x09);
/**
* Indicates that the type of the packet is
* Reliable Datagram, RDMA WRITE Only.
*/
public static byte RD_RDMA_WRITE_ONLY = (byte) (RD_TYPE | 0x0A);
/**
* Indicates that the type of the packet is
* Reliable Datagram, RDMA WRITE Only with Immediate.
*/
public static byte RD_RDMA_WRITE_ONLY_WITH_IMMEDIATE =
(byte) (RD_TYPE | 0x0B);
/**
* Indicates that the type of the packet is
* Reliable Datagram, RDMA READ Request.
*/
public static byte RD_RDMA_READ_REQUEST = (byte) (RD_TYPE | 0x0C);
/**
* Indicates that the type of the packet is
* Reliable Datagram, RDMA READ response First.
*/
public static byte RD_RDMA_READ_RESPONSE_FIRST =
(byte) (RD_TYPE | 0x0D);
/**
* Indicates that the type of the packet is
* Reliable Datagram, RDMA READ response Middle.
*/
public static byte RD_RDMA_READ_RESPONSE_MIDDLE =
(byte) (RD_TYPE | 0x0E);
/**
* Indicates that the type of the packet is
* Reliable Datagram, RDMA READ response Last.
*/
public static byte RD_RDMA_READ_RESPONSE_LAST =
(byte) (RD_TYPE | 0x0F);
/**
* Indicates that the type of the packet is
* Reliable Datagram, RDMA READ response Only.
*/
public static byte RD_RDMA_READ_RESPONSE_ONLY =
(byte) (RD_TYPE | 0x10);
/**
* Indicates that the type of the packet is
110
* Reliable Datagram, Acknowledge.
*/
public static byte RD_ACKNOWLEDGE = (byte) (RD_TYPE | 0x11);
/**
* Indicates that the type of the packet is
* Reliable Datagram, ATOMIC acknowledge.
*/
public static byte RD_ATOMIC_ACKNOWLEDGE = (byte) (RD_TYPE | 0x12);
/**
* Indicates that the type of the packet is
* Reliable Datagram, CmpSwap.
*/
public static byte RD_CMPSWAP = (byte) (RD_TYPE | 0x13);
/**
* Indicates that the type of the packet is
* Reliable Datagram, FetchAdd.
*/
public static byte RD_FETCHADD = (byte) (RD_TYPE | 0x14);
/**
* Indicates that the type of the packet is
* Reliable Datagram, RESYNC.
*/
public static byte RD_RESYNC = (byte) (RD_TYPE | 0x15);
// Header types
/**
* <b>The Local Route Header</b> - 8 bytes / 64 bits<br>
*
*<p>
* The Local Routing Header (LRH) contains fields used for local routing by
* switches within the IBA subnet.
*</p>
*
* Header format:
*<pre>
*
* Bit number
*
0
4
8
12
16
20
24
28
32
*
----------------------------------------------------------------*
|VL
|LVer
|SL
|r |L | Destination
|
*
0-31
|
|
|
|s 1|N | Local
|
*
|
|
|
|v |H | ID
|
*
----------------------------------------------------------------*
| r
|
| Source
|
*
32-63
| s 2
| PktLen
| Local
|
*
| v
|
| ID
|
*
----------------------------------------------------------------*
*</pre>
*
*/
public class LRH{
/** Size of the header in bits */
protected int size = LRH_SIZE;
111
/** The actual bytes that form the header */
protected byte[] content;
/**
* <b>Virtual lane</b> - 4 bits <br>
* This field identifies the virtual lane that the packet
* is using.
*/
public int VL(){
return ((content[0] & VL_MASK) >> 4) & 0x0F;
}
/**
* <b>Virtual lane</b> - 4 bits <br>
* Sets the field that identifies the virtual lane that the packet
* is using.
*/
public void setVL(int VL){
// Throw an error message if the supplied value
// is out of range
if (VL > 15 || VL < 0){
throw new IllegalArgumentException("VL number out "+
"of range! "+
VL+" is not in "+
"the range (0-15).");
}
content[0] = clear(content[0], VL_MASK);
content[0] |= (byte) ((VL << 4) & VL_MASK);
// Sanity check
if (VL() != VL){
Reporter.error("ERROR setting VL!!!");
}
//
}
/**
* <b>Link Version</b> - 4 bits <br>
* This field identifies the Link level protocol of this packet.
* This version applies to the general packet
* structure including the LRH fields and the variant CRC.
*/
public int LVer(){
int LVer = (content[0] & LVer_MASK) & 0x0F;
return
LVer;
}
/**
* <b>Link Version</b> - 4 bits <br>
* Sets the field that identifies the Link level protocol of
* this packet.
* This version applies to the general packet
* structure including the LRH fields and the variant CRC.
*/
public void setLVer(int LVer){
// Throw an error message if the supplied value
// is out of range
if (LVer > 15 || LVer < 0) {
throw new IllegalArgumentException("LVer out of range! "+
LVer+" is not in "+
"the range (0-15).");
}
content[0] = clear(content[0], LVer_MASK);
112
content[0] |= (byte) (LVer & LVer_MASK);
}
/**
* <b>Service Level</b> - 4 bits <br>
* This field indicates what service level the packet
* is requesting within the subnet.
*/
public int SL(){
int SL = ((content[1] & SL_MASK) >> 4) & 0x0F;
return
SL;
}
/**
* <b>Service Level</b> - 4 bits <br>
* Sets the field that indicates what service level the packet
* is requesting within the subnet.
*/
public void setSL(int SL){
// Throw an error message if the supplied value
// is out of range
if (SL > 15 || SL < 0) {
throw new IllegalArgumentException("SL value out "+
"of range! "+
SL+" is not in the "+
"range (0-15).");
}
content[1] = clear(content[1], SL_MASK);
content[1] |= ( ((byte) (SL << 4)) & SL_MASK);
}
/**
* <b>Link Next Header</b> - 2 bits <br>
* This field identifies the headers that follow the LRH.
* The bit values are in the last two bits of the byte returned.
*/
public byte LNH(){
return (byte) (content[1] & LNH_MASK);
}
/**
* <b>Link Next Header</b> - 2 bits <br>
* Sets the field that identifies the headers that follow the LRH.
* The bit values should be in the last two bits of the byte.
*/
public void setLNH(byte LNH){
content[1] = clear(content[1], LNH_MASK);
content[1] |= (byte) (LNH & LNH_MASK);
}
/**
* <b>Destination Local ID</b> - 16 bits <br>
* This field identifies the destination port and path (data sink)
* on the local subnet.
*/
public byte[] DLID(){
byte[] DLID = { content[2], content[3] };
return
DLID;
}
/**
* <b>Destination Local ID</b> - 16 bits <br>
* Sets the field that identifies the destination
* port and path (data sink) on the local subnet.
*/
113
public void setDLID(byte[] DLID){
// Throw an error message if the supplied array
// is of the wrong length.
if (DLID.length != 2){
throw new IllegalArgumentException("Length of supplied "+
"array is incorrect! "+
DLID.length +"!=2");
}
content[2] = DLID[0];
content[3] = DLID[1];
}
/**
* <b>Packet Length</b> - 11 bits <br>
* This field identifies the size of the Packet in four-byte
* words.
* This field includes the first byte of LRH to the last byte
* before the variant CRC. See the IBA specification, section
* <i>7.7.8 Packet Length (PktLen) - 11 bits</i> on page 167 for
* details on max and min values of PktLen.
* The bit values are in the last eleven bits of the bytes
* returned.
*/
public byte[] PktLenByte(){
byte [] PktLen = {(byte) (content[4] & PktLen_MASK[0]),
(byte) (content[5] & PktLen_MASK[1]) };
return
PktLen;
}
/**
* <b>Packet Length</b> - 11 bits <br>
* This field identifies the size of the Packet in four-byte
* words.
* This field includes the first byte of LRH to the last byte
* before the variant CRC. See the IBA specification, section
* <i>7.7.8 Packet Length (PktLen) - 11 bits</i> on page 167 for
* details on max and min values of PktLen.
*/
public int PktLen(){
// Update the packet length in the lrh
updatePacketLength();
int firstByte = (PktLenByte()[0] & PktLen_MASK[0]) << 8;
int secondByte = (PktLenByte()[1] & PktLen_MASK[1]) & 0xFF;
int pktLen = firstByte | secondByte;
return
pktLen;
}
/**
* <b>Packet Length</b> - 11 bits <br>
* Sets the field that identifies the size of the Packet in
* four-byte words.
* This field includes the first byte of LRH to the last byte
* before the variant CRC. See the IBA specification, section
* <i>7.7.8 Packet Length (PktLen) - 11 bits</i> on page 167 for
* details on max and min values of PktLen.
* The bit values should be in the last eleven bits of the bytes.
*/
public void setPktLen(byte[] PktLen){
114
// Throw an error message if the supplied array
// is of the wrong length.
if (PktLen.length != 2){
throw new IllegalArgumentException("Length of supplied "+
"array is incorrect! "+
PktLen.length+"!=2");
}
// zero out previous values of the length
// to avoid or’ing e.g. 00010000 with 1111, expecting 00001111,
// but getting 00011111
content[4] = clear(content[4], PktLen_MASK[0]);
content[5] = clear(content[5], PktLen_MASK[1]);
// Fill in right values.
content[4] |= (byte) (PktLen[0] & PktLen_MASK[0]);
content[5] |= (byte) (PktLen[1] & PktLen_MASK[1]);
}
public void setPktLen(int length){
if
(length > (MAX_SIZE-2) / 4 ) {
throw
new IllegalArgumentException("Length
"+length+" * 4 is too large. "+
"Maximum is "+
(((MAX_SIZE-2) / 4)-1)+" * 4");
}
byte tmp1,tmp2;
tmp1
tmp1
tmp2
tmp2
= (byte) ((length & 0xFF00) >> 8);
&= PktLen_MASK[0];
= (byte) (length & 0x00FF);
&= PktLen_MASK[1];
// zero out previous values of the length
// to avoid or’ing e.g. 00010000 with 1111, expecting 00001111,
// but getting 00011111
content[4] = clear(content[4],PktLen_MASK[0]);
content[5] = clear(content[5],PktLen_MASK[1]);
// Fill in the right values
content[4] |= tmp1;
content[5] |= tmp2;
}
/**
* <b>Source Local ID</b> - 16 bits <br>
* This field identifies the source port (injection point)
* on the local subnet.
*/
public byte[] SLID(){
byte[] SLID = { content[6], content[7] };
return
SLID;
}
/**
* <b>Source Local ID</b> - 16 bits <br>
* Sets the field that identifies the source port
* (injection point) on the local subnet.
*/
public void setSLID(byte[] SLID){
// Throw an error message if the supplied array
// is of the wrong length.
if (SLID.length != 2){
throw new IllegalArgumentException("Length of supplied "+
"array is incorrect! "+
SLID.length+"!=2");
115
}
content[6] = clear(content[6], SLID_MASK[0]);
content[7] = clear(content[7], SLID_MASK[1]);
content[6] |= (byte) (SLID[0] & SLID_MASK[0]);
content[7] |= (byte) (SLID[1] & SLID_MASK[1]);
}
/** Used to mask the VL */
protected final byte VL_MASK
= (byte) 0xF0;
/** Used to mask the LVer */
protected final byte LVer_MASK
= (byte) 0x0F;
/** Used to mask the SL */
protected final byte SL_MASK
= (byte) 0xF0;
/** Used to mask the LNH */
protected final byte LNH_MASK
= (byte) 0x03;
/** Used to mask the DLID */
protected final byte[] DLID_MASK
= { (byte) 0xFF,
(byte) 0xFF };
/** Used to mask the PktLen */
protected final byte[] PktLen_MASK
= { (byte) 0x07,
(byte) 0xFF };
/** Used to mask the SLID */
protected final byte[] SLID_MASK
= { (byte) 0xFF,
(byte) 0xFF };
/**
* Creates an empty LRH (all zeros)
*/
protected LRH(){
// Create an empty content array
this.content = new byte[size / BITS_PER_BYTE];
}
/**
* Creates a new LRH from the supplied byte array.
* @param content This array must be 8 bytes.
*/
protected LRH(byte [] content){
// Throw an error message if the supplied array
// is of the wrong length.
if (content.length != size/BITS_PER_BYTE){
throw new IllegalArgumentException("Length of supplied "+
"array is incorrect! "+
content.length+"!="+
size/BITS_PER_BYTE);
}
this.content = content;
}
/**
* Indicates whether this part of the header is present
* in this packet.
*/
protected boolean isPresent(){
return true;
}
}
/**
*<b>The Global Route Header</b> <br>
*
116
*<p>
* Global Route Header (GRH) contains fields for routing the packet between
* subnets. THe presence of the GRH is indicated by the Link Next Header (LNH)
* field in the LRH. The layout of the GRH is the same as the IPv6 Header
* defined in RFC 2640. Note, however, that IBA does not define a relationship
* between a device GID and IPv6 address (i.e. There is no defined mapping between
* GID and IPv6 address for any IB device of port).
*</p>
*
* Header format:
*
*<pre>
*
0
4
8
12
16
20
24
28
32
*
----------------------------------------------------------------*
|IP
|TClass
| Flow Label
|
*
|ver
|
| 20 bits
|
*
----------------------------------------------------------------*
|Payload Length
|NxtHdr
|HopLmt
|
*
|
16 bits
| 8b
| 8b
|
*
----------------------------------------------------------------*
|
Source GID 127-96
|
*
----------------------------------------------------------------*
|
Source GID 95-64
|
*
----------------------------------------------------------------*
|
Source GID 63-32
|
*
----------------------------------------------------------------*
|
Source GID 31-0
|
*
----------------------------------------------------------------*
|
Destination GID 127-96
|
*
----------------------------------------------------------------*
|
Destination GID 95-64
|
*
----------------------------------------------------------------*
|
Destination GID 63-32
|
*
----------------------------------------------------------------*
|
Destination GID 31-0
|
*
----------------------------------------------------------------*</pre>
*
*/
public class GRH{
/** Size of the header in bits */
protected int size = GRH_SIZE;
/** The actual bytes that form the header */
protected byte[] content;
/**
* <b>IP Version</b> - 4 bits <br>
* This field indicates version of the GRH.
* The bit values are in the first four bits of the
* bytes returned.
*/
public byte IPVer(){
return (byte) (content[0] & IPVer_MASK);
}
/**
* <b>IP Version</b> - 4 bits <br>
* This field indicates version of the GRH.
* The bit values should be in the first four bits of the bytes.
*/
public void setIPVer(byte IPVer){
117
content[0] = clear(content[0], IPVer_MASK);
content[0] |= (byte) (content[0] & IPVer_MASK);
}
/**
* <b>Traffic Class</b> - 8 bits <br>
* This field is used by IBA to communicate global service level.
* The bit values are in the last four bits of the first byte
* and the first four bits of the last byte returned.
*/
public byte[] TClass(){
byte [] TClass = { (byte) (content[0] & TClass_MASK[0]),
(byte) (content[1] & TClass_MASK[1]) };
return
TClass;
}
/**
* <b>Traffic Class</b> - 8 bits <br>
* This field is used by IBA to communicate global service level.
* The bit values should be in the last four bits of
* the first byte and the first four bits of the last byte.
*/
public void setTClass(byte[] TClass){
// Throw an error message if the supplied array
// is of the wrong length.
if (TClass.length != 2){
throw new IllegalArgumentException("Length of supplied "+
" array is "+
"incorrect! "+
TClass.length+"!=2");
}
content[0] = clear(content[0], TClass_MASK[0]);
content[1] = clear(content[1], TClass_MASK[1]);
content[0] |= (byte) (TClass[0] & TClass_MASK[0]);
content[1] |= (byte) (TClass[1] & TClass_MASK[1]);
}
/**
* <b>Flow Label</b> - 20 bits <br>
* This field identifies sequences of packets requiring
* special handling.
* The bit values are in the last four bits of the first byte
* and inn all of the last two bytes that are returned.
*/
public byte[] FlowLabel(){
byte[] FlowLabel = { (byte) (content[1] & FlowLabel_MASK[0]),
(byte) (content[2] & FlowLabel_MASK[1]),
(byte) (content[3] & FlowLabel_MASK[2])};
return
FlowLabel;
}
/**
* <b>Flow Label</b> - 20 bits <br>
* This field identifies sequences of packets requiring special
* handling.
* The bit values should be in the last four bits
* of the first byte and all the bits of the last two bytes.
*/
public void setFlowLabel(byte[] FlowLabel){
// Throw an error message if the supplied array
// is of the wrong length.
if (FlowLabel.length != 3){
throw new IllegalArgumentException("Length of supplied "+
"array is incorrect! "+
118
FlowLabel.length+
"!=3");
}
content[1] = clear(content[1], FlowLabel_MASK[0]);
content[2] = clear(content[2], FlowLabel_MASK[1]);
content[3] = clear(content[3], FlowLabel_MASK[2]);
content[1] |= (byte) (FlowLabel[0] & FlowLabel_MASK[0]);
content[2] |= (byte) (FlowLabel[1] & FlowLabel_MASK[1]);
content[3] |= (byte) (FlowLabel[2] & FlowLabel_MASK[2]);
}
/**
* <b>Payload length</b> - 16 bits <br>
* For an IBA packet this field specifies the number of
* bytes starting from the first byte after the GRH, up to and
* including the last byte of the ICRC. For a raw IPv6 datagram
* this field specifies the number of bytes starting from the
* first byte after the GRH, up to but not including either
* the VCRC or any padding, to achieve a multiple of 4 byte
* packet length.
* For raw IPv6 datagrams padding is determined from the
* lower 2 bits of the GRH:PayLen field.<br>
* Note: GRH:PayLen is different from LRH:PktLen.
*/
public byte[] PayLen(){
byte[] PayLen = { (byte) (content[4] & PayLen_MASK[0]),
(byte) (content[5] & PayLen_MASK[1]) };
return
PayLen;
}
/**
* <b>Payload length</b> - 16 bits <br>
* For an IBA packet this field specifies the number of
* bytes starting from the first byte after the GRH, up to and
* including the last byte of the ICRC. For a raw IPv6 datagram
* this field specifies the number of bytes starting from the
* first byte after the GRH, up to but not including either
* the VCRC or any padding, to achieve a multiple of 4 byte
* packet length.
* For raw IPv6 datagrams padding is determined from the
* lower 2 bits of the GRH:PayLen field.<br>
* Note: GRH:PayLen is different from LRH:PktLen.
*/
public void setPayLen (byte[] PayLen){
// Throw an error message if the supplied array
// is of the wrong length.
if (PayLen.length != 2){
throw new IllegalArgumentException("Length of supplied "+
"array is incorrect! "+
PayLen.length+"!=2");
}
content[4] = clear(content[4], PayLen_MASK[0]);
content[5] = clear(content[5], PayLen_MASK[1]);
content[4] |= (byte) (PayLen[0] & PayLen_MASK[0]);
content[5] |= (byte) (PayLen[1] & PayLen_MASK[1]);
}
/**
*
*
*
*
<b>Next Header</b> - 8 bits <br>
This field identifies the header following the GRH.
This field is included for compatibility with IPv6 headers.
It should indicate IBA transport.
119
*/
public byte NxtHdr(){
return (byte) (content[6]
& NxtHdr_MASK);
}
/**
* <b>Next Header</b> - 8 bits <br>
* Sets the field that identifies the header following the GRH.
* This field is included for conpatibility with IPv6 headers.
* It should indicate IBA transport.
*/
public void setNxtHdr(byte NxtHdr){
content[6] = clear(content[6], NxtHdr_MASK);
content[6] |= (byte) (NxtHdr & NxtHdr_MASK);
}
/**
* <b>Hop Limit</b> - 8 bits <br>
* This field sets a strict bound on the number of hops between
* subnets a packet can make before being discarded.
* This is enforced only by routers.
*/
public byte HopLmt(){
return (byte) (content[7] & HopLmt_MASK);
}
/**
* <b>Hop Limit</b> - 8 bits <br>
* Sets the field that sets a strict bound on the number of hops
* between subnets a packet can make before being discarded.
* This is enforced only by routers.
*/
public void setHopLmt(byte HopLmt){
content[7] = clear(content[7], HopLmt_MASK);
content[7] |= (byte) (HopLmt & HopLmt_MASK);
}
/**
* <b>Source GID</b> - 128 bits <br>
* This field identifies the Global Identifier (GID) for the
* port which injected the packet into the network.
*/
public byte[] SGID(){
byte[] SGID = new byte[16];
for
(int i=0; i < 16; i++){
SGID[i] |= (byte) (content[i+8] & SGID_MASK[i]);
}
return
SGID;
}
/**
* <b>Source GID</b> - 128 bits <br>
* Sets the field that identifies the Global Identifier (GID)
* for the port which injected the packet into the network.
*/
public void setSGID(byte[] SGID){
// Throw an error message if the supplied array
// is of the wrong length.
if (SGID.length != 16){
throw new IllegalArgumentException("Length of supplied "+
" array is "+
"incorrect! "+
SGID.length+"!=16");
}
120
for
(int i=0; i < 16; i++){
content[i+8] = clear(content[i+8], SGID_MASK[i]);
content[i+8] |= (byte) (SGID[i] & SGID_MASK[i]);
}
}
/**
* <b>Destination GID</b> - 128 bits <br>
* This field identifies the GID for the port which will
* consume the packet from the network.
*/
public byte[] DGID(){
byte[] DGID = new byte[16];
for
(int i=0; i < 16; i++){
DGID[i] |= (byte) (content[i+24] & DGID_MASK[i]);
}
return
DGID;
}
/**
* <b>Destination GID</b> - 128 bits <br>
* This field identifies the GID for the port which
* will consume the packet from the network.
*/
public void setDGID(byte[] DGID){
// Throw an error message if the supplied array
// is of the wrong length.
if (DGID.length != 16){
throw new IllegalArgumentException("Length of supplied "+
"array is incorrect! "+
DGID.length+"!=16");
}
for
(int i=0; i < 16; i++){
content[i+24] = clear(content[i+24], DGID_MASK[i]);
content[i+24] |= (byte) (DGID[i] & DGID_MASK[i]);
}
}
/**
* Creates an empty GRH (all zeros)
*/
protected GRH(){
// Create an empty content array
this.content = new byte[size / BITS_PER_BYTE];
}
/**
* Creates a new GRH from the supplied byte array.
* @param content This array must be 40 bytes.
*/
protected GRH(byte [] content){
// Throw an error message if the supplied array
// is of the wrong length.
if (content.length != size/BITS_PER_BYTE){
throw new IllegalArgumentException("Length of supplied "+
" array is "+
"incorrect! "+
content.length+"!="+
size/BITS_PER_BYTE);
121
}
this.content = content;
}
/**
* Indicates whether this part of the header is
* present in this packet.
*/
protected boolean isPresent(){
return ( lrh.LNH() & lrh.LNH_MASK ) == LNH_IBA_global;
}
/** Used to mask the IPVer */
protected byte IPVer_MASK
= (byte) 0xF0;
/** Used to mask the TClass */
protected byte[] TClass_MASK
= { (byte) 0x0F, (byte) 0xF0 };
/** Used to mask the FlowLabel */
protected byte[] FlowLabel_MASK = { (byte) 0x0F,
(byte) 0xFF,
(byte) 0xFF };
/** Used to mask the PayLen */
protected byte[] PayLen_MASK
= { (byte) 0xFF, (byte) 0xFF };
/** Used to mask the NxtHdr */
protected byte NxtHdr_MASK
= (byte) 0xFF;
/** Used to mask the HopLmt */
protected byte HopLmt_MASK
= (byte) 0xFF;
/** Used to mask the SGID */
protected byte[] SGID_MASK
= { (byte)
(byte)
(byte)
(byte)
(byte)
(byte)
(byte)
(byte)
0xFF,
0xFF,
0xFF,
0xFF,
0xFF,
0xFF,
0xFF,
0xFF,
(byte)
(byte)
(byte)
(byte)
(byte)
(byte)
(byte)
(byte)
0xFF,
0xFF,
0xFF,
0xFF,
0xFF,
0xFF,
0xFF,
0xFF };
0xFF,
0xFF,
0xFF,
0xFF,
0xFF,
0xFF,
0xFF,
0xFF,
(byte)
(byte)
(byte)
(byte)
(byte)
(byte)
(byte)
(byte)
0xFF,
0xFF,
0xFF,
0xFF,
0xFF,
0xFF,
0xFF,
0xFF };
/** Used to mask the DGID */
protected byte[] DGID_MASK
= { (byte)
(byte)
(byte)
(byte)
(byte)
(byte)
(byte)
(byte)
}
/**
* <b>The Base Transport Header</b> <br>
*
*<p>
* Base Transport Header (BTH) contains the fields for IBA transports.
* The presence of BTH is indicated by the Next Header field of the last
* previous header (i.e. either LRH:LNH or GRH:NextHdr depending on
* which was the last previous header).
*</p>
*
* Header format:
*
0
4
8
12
16
20
24
28
32
*
----------------------------------------------------------------*
| OpCode
|S|M|Pad| TVer | Partition Key
|
*
|
|E| |Cnt|
|
|
122
*
*
*
*
*
*
*
*
*/
----------------------------------------------------------------| Reserved
|
Destination Queue Pair (QP) Number
|
| (variant)
|
|
----------------------------------------------------------------|A| Reserved
| Packet Sequence Number (PSN)
|
-----------------------------------------------------------------
public class BTH{
/** Size of the header in bits */
protected int size = BTH_SIZE ;
/** The actual bytes that form the header */
protected byte[] content;
/**
* <b>Opcode</b> - 8 bits <br>
* This field indicates the IBA packet type.
* The OpCode also specifies which extension headers
* follow the Base Transport Header
*/
public byte OpCode(){
return (byte) (content[0] & OpCode_MASK);
}
/**
* <b>Opcode</b> - 8 bits <br>
* Sets the field that indicates the IBA packet type.
* The OpCode also specifies which extension headers
* follow the Base Transport Header
*/
public void setOpCode(byte OpCode){
content[0] = clear(content[0], OpCode_MASK);
content[0] |= (byte) (OpCode & OpCode_MASK);
}
/**
* <b>Solicited Event</b> - 1 bit <br>
* This bit indicates that an event should be generated by
* the responder.
* The bit values are in the first bit of the byte returned.
*/
public byte SE(){
return (byte) (content[1] & SE_MASK);
}
/**
* <b>Solicited Event</b> - 1 bit <br>
* Sets the bit that indicates that an event should be
* generated by the responder.
* The bit values should be in the first bit of the byte.
*/
public void setSE(byte SE){
content[1] = clear(content[1], SE_MASK);
content[1] |= (byte) (SE & SE_MASK);
}
/**
* <b>MigReq</b> - 1 bit <br>
* This bit is used to communicate migration state.
* The bit values are in the second bit of the byte returned.
*/
public byte M(){
return (byte) (content[1] & M_MASK);
}
123
/**
* <b>MigReq</b> - 1 bit <br>
* This bit is used to communicate migration state.
* The bit values should be in the second bit of the byte.
*/
public void setM(byte M){
content[1] = clear(content[1], M_MASK);
content[1] |= (byte) (M & M_MASK);
}
/**
* <b>Pad Count</b> - 2 bits <br>
* This field indicates how many extra bytes are added to the
* payload to align to a 4 byte boundary
* The bit values are in the third and fourth bit of the
* byte returned.
* @deprecated Use {@link #PadCnt()} instead.
*/
public byte PadCntInBytes(){
return (byte) (content[1] & PadCnt_MASK);
}
/**
* <b>Pad Count</b> - 2 bits <br>
* This field indicates how many extra bytes are added to the
* payload to align to a 4 byte boundary
* The bit values should be in the third and fourth bit of
* the byte.
* @deprecated Use {@link #setPadCnt(int PadCnt)} instead.
*/
public void setPadCntInBytes(byte PadCnt){
content[1] = clear(content[1], PadCnt_MASK);
content[1] |= (byte) (PadCnt & PadCnt_MASK);
}
/**
* <b>Pad Count</b> - 2 bits <br>
* This field indicates how many extra bytes are added to the
* payload to align to a 4 byte boundary
* The bit values are in the third and fourth bit of the
* byte returned.
*/
public int PadCnt(){
return (int) ( (content[1] & PadCnt_MASK) >> 4);
}
/**
* <b>Pad Count</b> - 2 bits <br>
* This field indicates how many extra bytes are added to the
* payload to align to a 4 byte boundary
*/
public void setPadCnt(int PadCnt){
content[1] = clear(content[1], PadCnt_MASK);
content[1] |= (byte) ((PadCnt << 4) & PadCnt_MASK);
}
/**
* <b>Transport Header Version</b> - 4 bits <br>
* This field indicates the version of the IBA Transport Headers.
* The bit values are in the last four bits of the byte
* returned.
*/
public byte TVer(){
return (byte) (content[1] & TVer_MASK);
}
124
/**
* <b>Transport Header Version</b> - 4 bits <br>
* This field indicates the version of the IBA Transport Headers.
* The bit values should be in the last four bits of the byte.
*/
public void setTVer(byte TVer){
content[1] = clear(content[1], TVer_MASK);
content[1] |= (byte) (TVer & TVer_MASK);
}
/**
* <b>Partition Key</b> - 16 bits <br>
* This field indicates which logical Partition is associated
* with this packet (see <i>10.9 Partitioning</i>,
* page 454 in the IBA specification
*/
public byte[] P_KEY(){
byte[] P_KEY = { (byte) (content[2] & P_KEY_MASK[0]),
(byte) (content[3] & P_KEY_MASK[1]) };
return
P_KEY;
}
/**
* <b>Partition Key</b> - 16 bits <br>
* Sets the field that indicates which logical Partition is
* associated with this packet (see <i>10.9 Partitioning</i>,
* page 454 in the IBA specification
*/
public void setP_KEY(byte[] P_KEY){
// Throw an error message if the supplied array
// is of the wrong length.
if (P_KEY.length != 16/BITS_PER_BYTE){
throw new IllegalArgumentException("Length of supplied "+
"array is incorrect! "+
P_KEY.length+"!="+
16/BITS_PER_BYTE);
}
content[2] = clear(content[2], P_KEY_MASK[0]);
content[3] = clear(content[3], P_KEY_MASK[1]);
content[2] |= (byte) (P_KEY[0] & P_KEY_MASK[0]);
content[3] |= (byte) (P_KEY[1] & P_KEY_MASK[1]);
}
/**
* <b>Destination QP</b> - 24 bits <br>
* This field indicates the Work Queue Pair Number (a.k.a QP)
* at the destination.
*/
public byte[] DestQP(){
byte[] DestQP = { (byte) (content[5] & DestQP_MASK[0]),
(byte) (content[6] & DestQP_MASK[1]),
(byte) (content[7] & DestQP_MASK[2]) };
return
DestQP;
}
/**
* <b>Destination QP</b> - 24 bits <br>
* Sets the field that indicates the Work Queue Pair Number
* (a.k.a QP) at the destination.
*/
public void setDestQP(byte[] QP){
// Throw an error message if the supplied array
// is of the wrong length.
125
if
(QP.length != 24/BITS_PER_BYTE){
throw
new IllegalArgumentException("Length
of supplied "+
" array is "+
"incorrect! "+
QP.length+"!="+
24/BITS_PER_BYTE);
}
content[5] = clear(content[5], DestQP_MASK[0]);
content[6] = clear(content[6], DestQP_MASK[1]);
content[7] = clear(content[7], DestQP_MASK[2]);
content[5] |= (byte) (QP[0] & DestQP_MASK[0]);
content[6] |= (byte) (QP[1] & DestQP_MASK[1]);
content[7] |= (byte) (QP[2] & DestQP_MASK[2]);
}
/**
* <b>Acknowledge request</b> - 1 bit <br>
* This bit is used to indicate that an acknowledge (for this
* packet) should be scheduled by the responder.
* The bit value is in the first bit of the byte returned.
*/
public byte A(){
return (byte) (content[8] & A_MASK);
}
/**
* <b>Acknowledge request</b> - 1 bit <br>
* Sets the bit that is used to indicate that an acknowledge
* (for this packet) should be scheduled by the responder.
* The bit value should be in the first bit of the byte.
*/
public void setA(byte A){
content[8] = clear(content[8], A_MASK);
content[8] |= (byte) (A & A_MASK);
}
/**
* <b>Packet Sequence Number</b> - 24 bits <br>
* This field is used to detect a missing or duplicate Packet.
* See <i>9.7.1. Packet Sequence Numbers (PSN)</i> on page 248
* in the IBA specification for a detailed description of PSN.
*/
public byte[] PSN(){
byte[] PSN = { (byte) (content[9] & PSN_MASK[0]),
(byte) (content[10] & PSN_MASK[1]),
(byte) (content[11] & PSN_MASK[2]) };
return
PSN;
}
/**
* <b>Packet Sequence Number</b> - 24 bits <br>
* Sets the field that is used to detect a missing or duplicate
* Packet.
* See <i>9.7.1. Packet Sequence Numbers (PSN)</i> on page 248
* in the IBA specification for a detailed description of PSN.
*/
public void setPSN(byte[] PSN){
// Throw an error message if the supplied array
// is of the wrong length.
if (PSN.length != 24/BITS_PER_BYTE){
throw new IllegalArgumentException("Length of supplied "+
"array is incorrect! "+
PSN.length+"!="+
24/BITS_PER_BYTE);
126
}
content[9] = clear(content[9], PSN_MASK[0]);
content[10] = clear(content[10], PSN_MASK[1]);
content[10] = clear(content[10], PSN_MASK[2]);
content[9] |= (byte) (PSN[0] & PSN_MASK[0]);
content[10] |= (byte) (PSN[1] & PSN_MASK[1]);
content[11] |= (byte) (PSN[2] & PSN_MASK[2]);
}
/**
* Creates an empty BTH (all zeros)
*/
protected BTH(){
// Create an empty content array
this.content = new byte[size / BITS_PER_BYTE];
}
/**
* Creates a new BTH from the supplied byte array.
* @param content This array must be 12 bytes.
*/
protected BTH(byte [] content){
// Throw an error message if the supplied array
// is of the wrong length.
if (content.length != size/BITS_PER_BYTE){
throw new IllegalArgumentException("Length of supplied "+
" array is "+
"incorrect! "+
content.length+"!="+
size/BITS_PER_BYTE);
}
this.content = content;
}
/**
* Indicates whether this part of the header is present
* in this packet.
*/
protected boolean isPresent(){
return ( lrh.LNH() & lrh.LNH_MASK ) == 0x02;
}
// Masks
/** Used to mask the OpCode */
protected final byte OpCode_MASK
= (byte) 0xFF;
/** Used to mask the SE */
protected final byte SE_MASK
= (byte) 0x80;
/** Used to mask the M */
protected final byte M_MASK
= (byte) 0x40;
/** Used to mask the PadCnt */
protected final byte PadCnt_MASK
= (byte) 0x30;
/** Used to mask the TVer */
protected final byte TVer_MASK
= (byte) 0x0F;
/** Used to mask the P_KEY */
protected final byte[] P_KEY_MASK
= { (byte) 0xFF,
(byte) 0xFF };
/** Used to mask the DestQP */
protected final byte[] DestQP_MASK
= { (byte) 0xFF,
(byte) 0xFF,
(byte) 0xFF };
127
/** Used to mask the A_MASK */
protected final byte A_MASK
= (byte) 0x80;
/** Used to mask the PSN */
protected final byte[] PSN_MASK
= { (byte) 0xFF,
(byte) 0xFF,
(byte) 0xFF };
}
/**
* <b>The Reliable Datagram Extended Transport Header</b> <br>
*
*<p>
* Reliable Datagram Extended Transport Header (RDETH) contains the
* additional transport fields for reliable datagram service.
* The RDETH is only in Reliable Datagram packets as indicated by
* the Base Transport Header Opcode field.
*</p>
*
* Header format:
*
*<pre>
*
0
4
8
12
16
20
24
28
32
*
----------------------------------------------------------------*
| resv
| EE-Context
|
*
----------------------------------------------------------------*</pre>
*/
public class RDETH{
/** Size of header in bits */
protected int size = RDETH_SIZE;
/** The actual bytes that form the header */
protected byte[] content;
/**
* <b>EE-Context</b> - 24 bits <br>
* This field indicates which End-to-End Context should be
* used for this Reliable Datagram packet.
* <b>NOT IMPLEMENTED YET. RETURNS NULL!</b>
*/
protected byte[] EE_Context(){
return
null;
}
/**
* Creates an empty RDETH (all zeros)
*/
protected RDETH(){
// Create an empty content array
this.content = new byte[size / BITS_PER_BYTE];
}
/**
* Creates a new RDETH from the supplied byte array.
* @param content This array must be 4 bytes.
*/
protected RDETH(byte [] content){
// Throw an error message if the supplied array
// is of the wrong length.
if (content.length != size/BITS_PER_BYTE){
128
throw
new IllegalArgumentException("Length
of supplied "+
"array is incorrect! "+
content.length+"!="+
size/BITS_PER_BYTE);
}
this.content = content;
}
/**
* Indicates whether this part of the header is present
* in this packet.
*/
protected boolean isPresent(){
return ((bth.OpCode() & 0xE0) == RD_TYPE);
}
}
/**
* <b>The Datagram Extended Transport Header (DETH)</b>
*
*<p>
* Datagram Extended Transport Header (DETH) contains the additional
* transport fiels for datagram service. The DETH is only in datagram
* packets if indicated by the Base Transport Header Opcode field.
*
* Header format:
*
*<pre>
*
0
4
8
12
16
20
24
28
32
*
----------------------------------------------------------------*
| Queue Key
|
*
----------------------------------------------------------------*
| resv 8b
| Source QP (SrcQP) 24b
|
*
----------------------------------------------------------------*</pre>
*/
public class DETH{
/** Size of header in bits */
protected int size = DETH_SIZE;
/** The actual bytes that form the header */
protected byte[] content;
/**
* <b>Queue Key</b> - 32 bits <br>
* This field is requires to authorize access to the
* receive queue.
* <b>TODO: NOT IMPLEMENTED YET. RETURNS NULL!</b>
*/
protected byte[] QueueKey(){
return
null;
}
/**
* <b>Reserved</b> - 8 bits <br>
* Transmitted as 0, ignored on receive.
* <b>TODO: NOT IMPLEMENTED YET. RETURNS NULL!</b>
*/
protected byte[] resv(){
return
null;
129
}
/**
* <b>Source QP</b> - 24 bits <br>
* This field indicates the Work Queue Pair Number (a.k.a. QP)
* at the source.
* <b>NOT IMPLEMENTED YET. RETURNS NULL!</b>
*/
protected byte[] SrcQP(){
return
null;
}
/**
* Creates an empty DETH (all zeros)
*/
protected DETH(){
// Create an empty content array
this.content = new byte[size / BITS_PER_BYTE];
}
/**
* Creates a new DETH from the supplied byte array.
* @param content This array must be 8 bytes.
*/
protected DETH(byte [] content){
// Throw an error message if the supplied array
// is of the wrong length.
if (content.length != size/BITS_PER_BYTE){
throw new IllegalArgumentException("Length of supplied "+
"array is incorrect! "+
content.length+"!="+
size/BITS_PER_BYTE);
}
this.content = content;
}
/**
* Indicates whether this part of the header is present
* in this packet.
*/
protected boolean isPresent(){
int lastBits = (bth.OpCode() & 0x1F);
return
( (bth.OpCode() & 0xE0) == RD_TYPE &&
lastBits != RD_RDMA_READ_RESPONSE_FIRST &&
lastBits != RD_RDMA_READ_RESPONSE_MIDDLE &&
lastBits != RD_RDMA_READ_RESPONSE_LAST &&
lastBits != RD_ACKNOWLEDGE &&
lastBits != RD_ATOMIC_ACKNOWLEDGE
);
}
}
/**
* <b>The RDMA Extended Transport Header (RETH)</b>
*
*<p>
* RDMA Extended Transport Header (RETH) contains the additional transport
* fields for RDMA operations. The RETH is present in only the first
* (or only) packet of an RDMA Request as indicated by the Base Transport
130
* Header Opcode field.
*</p>
*
* Header format:
*
*<pre>
*
0
4
8
12
16
20
24
28
32
*
----------------------------------------------------------------*
| Virtual Address 63-32
|
*
----------------------------------------------------------------*
| Virtual Address 31-0
|
*
----------------------------------------------------------------*
| Remote Key
|
*
----------------------------------------------------------------*
| DMA Length
|
*
----------------------------------------------------------------*</pre>
*/
public class RETH{
/** Size of header in bits */
protected int size = RETH_SIZE;
/** The actual bytes that form the header */
protected byte[] content;
/**
* <b>Virtual Address</b> - 64 bits <br>
* This field is the Virtual Address of the RDMA operation.
* <b>TODO: NOT IMPLEMENTED YET. RETURNS NULL!</b>
*/
protected byte[] VA(){
return
null;
}
/**
* <b>Remote Key</b> - 32 bits <br>
* This field is the Remote Key that authorizes access
* for the RDMA operation.
* <b>TODO: NOT IMPLEMENTED YET. RETURNS NULL!</b>
*/
protected byte[] R_Key(){
return
null;
}
/**
* <b>DMA Length</b> - 32 bits <br>
* This field indicates the length (in Bytes) of the
* DMA operation.
* <b>TODO: NOT IMPLEMENTED YET. RETURNS NULL!</b>
*/
protected byte[] DMALen(){
return
null;
}
/**
* Creates an empty RETH (all zeros)
*/
protected RETH(){
// Create an empty content array
this.content = new byte[size / BITS_PER_BYTE];
}
131
/**
* Creates a new RETH from the supplied byte array.
* @param content This array must be 16 bytes.
*/
protected RETH(byte [] content){
// Throw an error message if the supplied array
// is of the wrong length.
if (content.length != size/BITS_PER_BYTE){
throw new IllegalArgumentException("Length of supplied "+
"array is incorrect! "+
content.length+"!="+
size/BITS_PER_BYTE);
}
this.content = content;
}
/**
* Indicates whether this part of the header is present
* in this packet.
* TODO: Not implemented yet, just returns false.
*/
protected boolean isPresent(){
return false;
}
}
/**
*<b>The Atomic Extended Transport Header (AtomicETH)</b>
*
*<p>
* Atomic Extended Transport Header (AtomicETH) contains the
* additional transport fields for Atomic packets. The AtomicETH
* is only in Atomic packets as indicated by the Base Transport Header
* Opcode field.
*</p>
*
* Header format:
*<pre>
*
0
4
8
12
16
20
24
28
32
*
----------------------------------------------------------------*
| Virtual Address 63-32
|
*
----------------------------------------------------------------*
| Virtual Address 31-0
|
*
----------------------------------------------------------------*
| Remote Key
|
*
----------------------------------------------------------------*
| Swap (or Add) Data 63-32
|
*
----------------------------------------------------------------*
| Swap (or Add) Data 31-0
|
*
----------------------------------------------------------------*
| Compare Data 63-32
|
*
----------------------------------------------------------------*
| Compare Data 31-0
|
*
----------------------------------------------------------------*</pre>
*/
public class AtomicETH{
132
/** Size of header in bits */
protected int size = ATOMIC_ETH_SIZE;
/** The actual bytes that form the header */
protected byte[] content;
/**
* <b>Virtual Address</b> - 64 bits <br>
* This field is the remote virtual address.
* <b>NOT IMPLEMENTED YET. RETURNS NULL!</b>
*/
protected byte[] VA(){
return
null;
}
/**
* <b>Remote Key</b> - 32 bits <br>
* This field is the Remote Key that authorizes access to the
* remote virtual address.
* <b>NOT IMPLEMENTED YET. RETURNS NULL!</b>
*/
protected byte[] R_Key(){
return
null;
}
/**
* <b>Swap (or Add) Data</b> - 64 bits <br>
* This field is an operand in atomic operations.
* <b>NOT IMPLEMENTED YET. RETURNS NULL!</b>
*/
protected byte[] SwapDt(){
return
null;
}
/**
* <b>Compare Data</b> - 64 bits <br>
* This field is an operand in CmpSwap atomic operation.
* <b>NOT IMPLEMENTED YET. RETURNS NULL!</b>
*/
protected byte[] CmpDt(){
return
null;
}
/**
* Creates an empty AtomicETH (all zeros)
*/
protected AtomicETH(){
// Create an empty content array
this.content = new byte[size / BITS_PER_BYTE];
}
/**
* Creates a new AtomicETH from the supplied byte array.
* @param content This array must be 28 bytes.
*/
protected AtomicETH(byte [] content){
// Throw an error message if the supplied array
// is of the wrong length.
if (content.length != size/BITS_PER_BYTE){
throw new IllegalArgumentException("Length of supplied "+
"array is incorrect! "+
content.length+"!="+
size/BITS_PER_BYTE);
}
133
this.content = content;
}
/**
* Indicates whether this part of the header is present
* in this packet.
* TODO: Not implemented yet, just returns false.
*/
protected boolean isPresent(){
return false;
}
}
/**
*<b>The ACK Extended Transport Header (AETH)</b>
*
*<p>
* ACK Extended Transport Header (AETH) contains the additional
* transport fields for ACK packets. The AETH is only in Acknowledge,
* RDMA READ Response First, RDMA Response Response Last, and RDMA
* READ Response Only packets as indicated by the Base Transport
* Header Opcode field.
*</p>
*
* Header format:
*
*<pre>
*
0
4
8
12
16
20
24
28
32
*
----------------------------------------------------------------*
| Syndrome
| Message Sequence Number
|
*
----------------------------------------------------------------*</pre>
*
*/
public class AETH{
/** Size of header in bits */
protected int size = AETH_SIZE;
/** The actual bytes that form the header */
protected byte[] content;
/**
* <b>Syndrome</b> - 8 bits <br>
* This field indicates if this is an ACK or NAK packet plus
* additional information about the ACK or NAK.
* <b>NOT IMPLEMENTED YET. RETURNS NULL!</b>
*/
protected byte[] Syndrome(){
return
null;
}
/**
* <b>Message Sequence Number</b> - 24 bits <br>
* This field indicates the sequence number of the last
* message completed at the responder.
* <b>NOT IMPLEMENTED YET. RETURNS NULL!</b>
*/
protected byte[] MSN(){
return
null;
}
134
/**
* Creates an empty AETH (all zeros)
*/
protected AETH(){
// Create an empty content array
this.content = new byte[size / BITS_PER_BYTE];
}
/**
* Creates a new AETH from the supplied byte array.
* @param content This array must be 4 bytes.
*/
protected AETH(byte [] content){
// Throw an error message if the supplied array
// is of the wrong length.
if (content.length != size/BITS_PER_BYTE){
throw new IllegalArgumentException("Length of supplied "+
"array is incorrect! "+
content.length+"!="+
size/BITS_PER_BYTE);
}
this.content = content;
}
/**
* Indicates whether this part of the header is present in
* this packet.
* TODO: Not implemented yet, just returns false.
*/
protected boolean isPresent(){
return false;
}
}
/**
*<b>The Atomic ACK Extended Transport Header (AtomicAckETH)</b>
*
*<p>
* Atomic ACK Extended Transport Header (AtomicAckETH) contains the
* additional transport fields for AtomicACK packets. The AtomicAckETH
* is only in Atomic Acknowledge packets as indicated by the Base Transport
* Header Opcode field.
*</p>
*
* Header format:
*
*<pre>
*
0
4
8
12
16
20
24
28
32
*
----------------------------------------------------------------*
| Original Remote Data 63-32
|
*
----------------------------------------------------------------*
| Original Remote data 31-0
|
*
----------------------------------------------------------------*</pre>
*
*/
public class AtomicAckETH{
135
/** Size of header in bits */
protected int size = ATOMIC_ACK_ETH_SIZE;
/** The actual bytes that form the header */
protected byte[] content;
/**
* <b>Original Remote Data</b> - 64 bits <br>
* This field is the return operand in atomic operations and
* contains the data in the remote memory location before
* atomic operation.
* <b>TODO: NOT IMPLEMENTED YET. RETURNS NULL!</b>
*/
protected byte[] OrigRemDt(){
return
null;
}
/**
* Creates an empty AtomicAckETH (all zeros)
*/
protected AtomicAckETH(){
// Create an empty content array
this.content = new byte[size / BITS_PER_BYTE];
}
/**
* Creates a new AtomicAckETH from the supplied byte array.
* @param content This array must be 8 bytes.
*/
protected AtomicAckETH(byte [] content){
// Throw an error message if the supplied array
// is of the wrong length.
if (content.length != size/BITS_PER_BYTE){
throw new IllegalArgumentException("Length of supplied "+
"array is incorrect! "+
content.length+"!="+
size/BITS_PER_BYTE);
}
this.content = content;
}
/**
* Indicates whether this part of the header is present in
* this packet.
* TODO: Not implemented yet, just returns false.
*/
protected boolean isPresent(){
return false;
}
}
/**
* <b>The Immediate Data Extended Transport Header (ImmDt)</b>
*
*<p>
* Immediate Data Extended Transport Header (ImmDt) contains the
* additional data that is placed in the receive Completion Queue
136
* Element (CQE). The ImmDt is only in Send or RDMA-Write packets
* with Immediate Data if indicated by the Base Transport Header Opcode.
*</p>
*
* Header format:
*
*<pre>
*
0
4
8
12
16
20
24
28
32
*
----------------------------------------------------------------*
| Immediate Data
|
*
----------------------------------------------------------------*</pre>
*
*/
public class ImmDt{
/** Size of header in bits */
protected int size = IMM_DT_SIZE;
/** The actual bytes that form the header */
protected byte[] content;
/**
*The immediate data
* <b>TODO: NOT IMPLEMENTED YET. RETURNS NULL!</b>
*/
protected byte[] immDt(){
return
null;
}
/**
* Creates an empty ImmDt (all zeros)
*/
protected ImmDt(){
// Create an empty content array
this.content = new byte[size / BITS_PER_BYTE];
}
/**
* Creates a new ImmDt from the supplied byte array.
* @param content This array must be 4 bytes.
*/
protected ImmDt(byte [] content){
// Throw an error message if the supplied array
// is of the wrong length.
if (content.length != size/BITS_PER_BYTE){
throw new IllegalArgumentException("Length of supplied "+
"array is incorrect! "+
content.length+"!="+
size/BITS_PER_BYTE);
}
this.content = content;
}
/**
* Indicates whether this part of the header is present
* in this packet.
* TODO: Not implemented yet, just returns false.
*/
137
protected boolean isPresent(){
return false;
}
}
/**
* The payload of the packet
*/
public class PYLD{
/** Size of payload in bits */
protected int size;
/** The actual bytes that form the header */
protected byte[] content;
/**
* Creates an empty Payload
*/
protected PYLD(){
// Create an empty content array
this.content = new byte[size / BITS_PER_BYTE];
}
/**
* Creates a new Payload from the supplied byte array.
* @param content This array must be 4 bytes.
*/
protected PYLD(byte [] content){
setContent(content);
}
/*
* Sets the content. Adds padding if necessary.
* (see 5.2.11, <i>Payload</i> ( page 134) in the
* IBA specification.
*/
public void setContent(byte[] content){
int i=0;
int sizeInBytes = content.length;
// Add padding if necessary
int padding = (4 - (content.length % 4));
if
( padding > 0 && padding < 4){
sizeInBytes += padding;
bth.setPadCnt(padding);
}
// Fill in contents
this.content = new byte[sizeInBytes];
for
(i=0; i < content.length; i++){
this.content[i] = content[i];
}
// Padding should be zeros
for (; i < sizeInBytes; i++){
this.content[i] = 0;
}
this.size = sizeInBytes * BITS_PER_BYTE;
}
/*
* Returns the content (without the padding)
*/
public byte[] getContentWithoutPadding(){
138
int sizeInBytes;
byte[] retVal;
sizeInBytes = this.content.length;
sizeInBytes -= bth.PadCnt();
retVal = new byte[sizeInBytes];
// Save a for loop if there’s no padding
if (sizeInBytes == this.content.length){
return this.content;
}
// Fill up with the data (without the padding)
for (int i=0; i < sizeInBytes; i++){
retVal[i] = this.content[i];
}
return
retVal;
}
/**
* Indicates whether this part of the header is present
* in this packet.
* Always returns true.
*/
protected boolean isPresent(){
return true;
}
}
/**
* Dummy class representing the ICRC bits of the packet.
* Contains only zeros.
*/
public class ICRC{
/** Size of header in bits */
protected int size = ICRC_SIZE;
protected byte[] content;
protected ICRC(){
this.content = new byte[size / BITS_PER_BYTE];
}
protected ICRC(byte[] content){
this.content = content;
}
/**
* Indicates whether this part of the header is present
* in this packet.
*/
protected boolean isPresent(){
return ( lrh.LNH() != LNH_raw );
}
}
/**
* Dummy class representing the VCRC bits of the packet.
* Contains only zeros.
*/
public class VCRC{
/** Size of header in bits */
protected int size = VCRC_SIZE;
139
protected byte[] content;
protected VCRC(){
this.content = new byte[size / BITS_PER_BYTE];
}
protected VCRC(byte[] content){
this.content = content;
}
/**
* Indicates whether this part of the header is present
* in this packet.
* Always returns true.
*/
protected boolean isPresent(){
return true;
}
}
public IBAPacket(){
lrh = new LRH();
grh = new GRH();
bth = new BTH();
rdeth = new RDETH();
deth = new DETH();
reth = new RETH();
atomicETH = new AtomicETH();
atomicAckETH = new AtomicAckETH();
aeth = new AETH();
immDt = new ImmDt();
pyld = new PYLD();
icrc = new ICRC();
vcrc = new VCRC();
}
public IBAPacket(byte[] content){
this();
byte[] tmpByte;
// The current index in the content array
int currentIndex = 0;
// Fetch the various fields from the bytes supplied
// LRH
tmpByte = new byte[LRH_SIZE/BITS_PER_BYTE];
for
(int i=0; i < LRH_SIZE/BITS_PER_BYTE; i++, currentIndex++){
tmpByte[i] = content[currentIndex];
}
lrh = new LRH(tmpByte);
//
if
GRH
(lrh.LNH() == LNH_IBA_global){
tmpByte = new byte[GRH_SIZE/BITS_PER_BYTE];
for
(int i=0; i < GRH_SIZE/BITS_PER_BYTE;
i++, currentIndex++){
tmpByte[i] = content[currentIndex];
}
grh = new GRH(tmpByte);
}
// BTH
if (lrh.LNH()
!= LNH_raw){
tmpByte = new byte[BTH_SIZE/BITS_PER_BYTE];
for
(int i=0; i < BTH_SIZE/BITS_PER_BYTE;
i++, currentIndex++){
tmpByte[i] = content[currentIndex];
}
bth = new BTH(tmpByte);
140
}
// Just to make indexing of ’incFields’ more intuitive
final
final
final
final
final
final
final
final
final
final
int
int
int
int
int
int
int
int
int
int
nRDETH = 0;
nDETH = 1;
nRETH = 2;
nAtomicETH = 3;
nAETH = 4;
nAtomicAckETH = 5;
nImmDt = 6;
nPYLD = 7;
nICRC = 8;
nVCRC = 9;
// different types of fields
boolean[] incFields = new boolean[10];
for
(int i=0; i < incFields.length; i++){
incFields[i] = false;
}
// RDETH and onwards. See pp. 208 and onward in the IBA spec
// for information on how the packet is to be interpreted.
// All that have OpCode[7-5] (first 3 bits) other than 010
// are Connection Oriented. This is not implemented.
int firstBits = (bth.OpCode() & 0xE0) >> 5;
int lastBits = (bth.OpCode() & 0x1F);
if
( firstBits != 2){
Reporter.error("IBAPacket.IBAPacket(byte[])
: "+
"Undefined or unimplemented "+
"packet contents defined in OpCode "+
"field of BTH: "+
Utils.asBitString(bth.OpCode()));
}
else if
if (
( firstBits == 2 ){
lastBits >= 0x16 &&
// Impossible, but anyhow...
: "+
"Undefined packet contents defined "
+"in OpCode field of BTH."+
lastBits <= 0x1F ){
Reporter.error("IBAPacket.IBAPacket(byte[])
Utils.asBitString(bth.OpCode()));
}
// TODO: Do the right thing here depending on the contents
// of the packet. Check that every case is covered.
// All have ICRC and VCRC attached
incFields[nICRC] = true;
incFields[nVCRC] = true;
switch(lastBits){
case 0: // SEND
case 1: // SEND
case 2: // SEND
case 4: // SEND
case 7: // RDMA
case 8: // RDMA
First
Middle
Last
Only
WRITE Middle
WRITE Last
incFields[nRDETH] = true;
incFields[nDETH] = true;
incFields[nPYLD] = true;
break;
case 3: // SEND Last with Immediate
case 5: // SEND Only with Immediate
case 9: // RDMA WRITE Last with Immediate
incFields[nRDETH] = true;
incFields[nDETH] = true;
incFields[nImmDt] = true;
141
incFields[nPYLD] = true;
break;
case 6: // RDMA WRITE First
case 10: // RDMA WRITE Only
incFields[nRDETH] = true;
incFields[nDETH] = true;
incFields[nRETH] = true;
incFields[nPYLD] = true;
break;
case 11: // RDMA WRITE Only with Immediate
incFields[nRDETH] = true;
incFields[nDETH] = true;
incFields[nRETH] = true;
incFields[nImmDt] = true;
incFields[nPYLD] = true;
break;
case 12: // RDMA READ Request
incFields[nRDETH] = true;
incFields[nDETH] = true;
incFields[nRETH] = true;
break;
case 13: // RDMA READ response First
case 15: // RDMA READ response Last
case 16: // RDMA READ responsy Only
incFields[nRDETH] = true;
incFields[nAETH] = true;
incFields[nPYLD] = true;
break;
case 14: // RDMA READ response Middle
incFields[nRDETH] = true;
incFields[nPYLD] = true;
break;
case 17: // Acknowledge
incFields[nRDETH] = true;
incFields[nAETH] = true;
break;
case 18: // ATOMIC Acknowledge
incFields[nRDETH] = true;
incFields[nAETH] = true;
incFields[nAtomicAckETH] = true;
break;
case 19: // CmpSwap
case 20: // FetchAdd
incFields[nRDETH] = true;
incFields[nDETH] = true;
incFields[nAtomicETH] = true;
break;
case 21: // RESYNC
incFields[nRDETH] = true;
incFields[nDETH] = true;
break;
}
}
// Loop through all the headers and add them is they are present.
// RDETH
if (incFields[nRDETH]){
tmpByte = new byte[RDETH_SIZE/BITS_PER_BYTE];
for
(int i=0; i < RDETH_SIZE/BITS_PER_BYTE;
i++, currentIndex++){
tmpByte[i] = content[currentIndex];
}
rdeth = new RDETH(tmpByte);
}
// DETH
if (incFields[nDETH]){
tmpByte = new byte[DETH_SIZE/BITS_PER_BYTE];
142
for
(int i=0; i < DETH_SIZE/BITS_PER_BYTE;
i++, currentIndex++){
tmpByte[i] = content[currentIndex];
}
deth = new DETH(tmpByte);
}
// RETH
if (incFields[nRETH]){
tmpByte = new byte[RETH_SIZE/BITS_PER_BYTE];
for
(int i=0; i < RETH_SIZE/BITS_PER_BYTE;
i++, currentIndex++){
tmpByte[i] = content[currentIndex];
}
reth = new RETH(tmpByte);
}
// AtomicETH
if (incFields[nAtomicETH]){
tmpByte = new byte[ATOMIC_ETH_SIZE/BITS_PER_BYTE];
for
(int i=0; i < ATOMIC_ETH_SIZE/BITS_PER_BYTE;
i++, currentIndex++){
tmpByte[i] = content[currentIndex];
}
atomicETH = new AtomicETH(tmpByte);
}
// AETH
if (incFields[nAETH]){
tmpByte = new byte[AETH_SIZE/BITS_PER_BYTE];
for
(int i=0; i < AETH_SIZE/BITS_PER_BYTE;
i++, currentIndex++){
tmpByte[i] = content[currentIndex];
}
aeth = new AETH(tmpByte);
}
// AtomicAckETH
if (incFields[nAtomicAckETH]){
tmpByte = new byte[ATOMIC_ACK_ETH_SIZE/BITS_PER_BYTE];
for
(int i=0; i < ATOMIC_ACK_ETH_SIZE/BITS_PER_BYTE;
i++, currentIndex++){
tmpByte[i] = content[currentIndex];
}
atomicAckETH = new AtomicAckETH(tmpByte);
}
// ImmDt
if (incFields[nImmDt]){
tmpByte = new byte[IMM_DT_SIZE/BITS_PER_BYTE];
for
(int i=0; i < IMM_DT_SIZE/BITS_PER_BYTE;
i++, currentIndex++){
tmpByte[i] = content[currentIndex];
}
immDt = new ImmDt(tmpByte);
}
// PYLD
if (incFields[nPYLD]){
int payloadSize = content.length - (currentIndex +
((ICRC_SIZE + VCRC_SIZE) /
BITS_PER_BYTE));
tmpByte = new byte[payloadSize];
for
(int i=0; i < payloadSize; i++, currentIndex++){
tmpByte[i] = content[currentIndex];
}
pyld = new PYLD(tmpByte);
}
// ICRC
if
(incFields[nICRC]){
143
tmpByte = new byte[ICRC_SIZE/BITS_PER_BYTE];
for
(int i=0; i < ICRC_SIZE/BITS_PER_BYTE;
i++, currentIndex++){
tmpByte[i] = content[currentIndex];
}
icrc = new ICRC(tmpByte);
}
// VCRC
if
(incFields[nVCRC]){
tmpByte = new byte[VCRC_SIZE/BITS_PER_BYTE];
for
(int i=0; i < VCRC_SIZE/BITS_PER_BYTE;
i++, currentIndex++){
tmpByte[i] = content[currentIndex];
}
vcrc = new VCRC(tmpByte);
}
}
/**
* Clears a byte, but just some of the bits.
* Used to clear a value in a byte that’s shared between
* two fields without wiping out the other field.
* @param content The byte to celar a part of
* @param mask The mask use to mask out the bits in question.
* E.g. clear(0xF1, 0x0F) returns 0xF0).
*/
private byte clear (byte content, byte mask){
return (byte) (content & (byte) (0xFF ^ mask) & 0xFF);
}
/**
* Updates the packet length field in the lrh
* based on the contents of the rest of the packet.
*/
public void updatePacketLength(){
int packetLength = 0;
// Could be a totally "empty" packet
if ((lrh.LNH() & lrh.LNH_MASK) == 0x00 &&
(lrh.DLID()[0] & lrh.DLID_MASK[0])
(lrh.DLID()[1] & lrh.DLID_MASK[1])
(lrh.SLID()[0] & lrh.SLID_MASK[0])
(lrh.SLID()[1] & lrh.SLID_MASK[1])
lrh.setPktLen(0);
==
==
==
==
0x00 &&
0x00 &&
0x00 &&
0x00){
return;
}
// Add the LRH
packetLength += lrh.size;
// Add the GRH if present
if (grh.isPresent()){
packetLength += grh.size;
}
// Add the BTH if present
if (bth.isPresent()){
packetLength += bth.size;
}
// Add the RDETH if present
if (rdeth.isPresent()){
packetLength += rdeth.size;
144
}
// Add the DETH if present
if (deth.isPresent()){
packetLength += deth.size;
}
// Add the RETH if present
if (reth.isPresent()){
packetLength += reth.size;
}
// Add the AtomicETH if present
if (atomicETH.isPresent()){
packetLength += atomicETH.size;
}
// Add the AETH if present
if (aeth.isPresent()){
packetLength += aeth.size;
}
// Add the AtomicAckETH if present
if (atomicAckETH.isPresent()){
packetLength += atomicAckETH.size;
}
// Add the ImmDt if present
if (immDt.isPresent()){
packetLength += immDt.size;
}
// Add the PYLD if present
if (pyld.isPresent()){
packetLength += pyld.size;
}
// Add the ICRC if present
if (icrc.isPresent()){
packetLength += icrc.size;
}
// Add the VCRC if present
if (vcrc.isPresent()){
packetLength += vcrc.size;
}
// Divide by BITS_PER_BYTE and 4 to get number of words
packetLength /= (BITS_PER_BYTE * 4);
// Update the header field
lrh.setPktLen(packetLength);
}
/**
* Creates a new IBAPacket with the supplied destination
* and source address.
* @param destination - the DLID in the LRH
* @param source - the SLID in the LRH
*/
public IBAPacket(Address destination, Address source){
this();
// Fill inn the source and destination addresses in the LRH
lrh.setDLID(destination.getAddress());
lrh.setSLID(source.getAddress());
}
145
/**
* Returns the content of this IBA packet.
*/
public byte[] getContent(){
int pktLen = lrh.PktLen();
// +2 for VCRC, which is not included in the
// packet length field.
byte[] content = new byte[pktLen * 4 + 2 ];
int currentIndex = 0;
int i;
// Add the LRH
for (i=0; i < lrh.size
/ BITS_PER_BYTE; i++, currentIndex++){
content[currentIndex] = lrh.content[i];
}
// Add the GRH if present
if (grh.isPresent()){
for (i=0; i < grh.size / BITS_PER_BYTE;
i++, currentIndex++){
content[currentIndex] = grh.content[i];
}
}
// Add the BTH if present
if (bth.isPresent()){
for (i=0; i < bth.size / BITS_PER_BYTE;
i++, currentIndex++){
content[currentIndex] = bth.content[i];
}
}
// Add the RDETH if present
if (rdeth.isPresent()){
for (i=0; i < rdeth.size / BITS_PER_BYTE;
i++, currentIndex++){
content[currentIndex] = rdeth.content[i];
}
}
// Add the DETH if present
if (deth.isPresent()){
for (i=0; i < deth.size / BITS_PER_BYTE;
i++, currentIndex++){
content[currentIndex] = deth.content[i];
}
}
// Add the RETH if present
if (reth.isPresent()){
for (i=0; i < reth.size / BITS_PER_BYTE;
i++, currentIndex++){
content[currentIndex] = reth.content[i];
}
}
// Add the AtomicETH if present
if (atomicETH.isPresent()){
for (i=0; i < atomicETH.size / BITS_PER_BYTE;
i++, currentIndex++){
content[currentIndex] = atomicETH.content[i];
}
}
// Add the AETH if present
if (aeth.isPresent()){
for (i=0; i < aeth.size / BITS_PER_BYTE;
i++, currentIndex++){
content[currentIndex] = aeth.content[i];
}
}
// Add the AtomicAckETH if present
146
if
(atomicAckETH.isPresent()){
for
(i=0; i < atomicAckETH.size / BITS_PER_BYTE;
i++, currentIndex++){
content[currentIndex] = atomicAckETH.content[i];
}
}
// Add the ImmDt if present
if (immDt.isPresent()){
for (i=0; i < immDt.size / BITS_PER_BYTE;
i++, currentIndex++){
content[currentIndex] = immDt.content[i];
}
}
// Add the PYLD if present
if (pyld.isPresent()){
for (i=0; i < pyld.size / BITS_PER_BYTE;
i++, currentIndex++){
content[currentIndex] = pyld.content[i];
}
}
// Add the ICRC if present
if (icrc.isPresent()){
for (i=0; i < icrc.size / BITS_PER_BYTE;
i++, currentIndex++){
content[currentIndex] = icrc.content[i];
}
}
// Add the VCRC if present
if (vcrc.isPresent()){
for (i=0; i < vcrc.size / BITS_PER_BYTE;
i++, currentIndex++){
content[currentIndex] = vcrc.content[i];
}
}
return
content;
}
/**
* Returns the full size of the packet in bytes, including all headers
* and CRC fields and padding.
*/
public int getSize(){
int pktLen;
updatePacketLength();
// Empty packet, return 0 size
if (this.lrh.PktLen() == 0 ) return 0;
// +2 for the VCRC, not included in PktLen.
pktLen = (this.lrh.PktLen() * 4) + 2;
return
pktLen;
}
/** The Local Route Header (LRH) of this Packet */
public LRH lrh;
/** The Global Route Header (GRH) of this Packet */
public GRH grh;
/** The Base Transport Header (BTH) of this Packet */
public BTH bth;
/**
* The Reliable Datagram Extended Transport Header
147
* (RDETH) of this Packet
*/
public RDETH rdeth;
/** The Datagram Extended Transport Header (DETH) of this Packet */
public DETH deth;
/** The RDMA Extended Transport Header (RETH) of this Packet */
public RETH reth;
/** The Atomic Extended Transport Header (AtomicETH) of this Packet */
public AtomicETH atomicETH;
/**
* The Atomic ACK Extended Transport Header
* (AtomicAckETH) of this Packet
*/
public AtomicAckETH atomicAckETH;
/** The ACK Extended Transport Header (AETH of this Packet */
public AETH aeth;
/**
* The Immediate Data Extended Transport Header
* (ImmDt) of this Packet
*/
public ImmDt immDt;
/** The Payload of this Packet */
public PYLD pyld;
/** The ICRC of this Packet */
public ICRC icrc;
/** The VCRC of this Packet */
public VCRC vcrc;
}
148
no.uio.ifi.gruns.infiniband.IBAInputPort
package no.uio.ifi.gruns.infiniband;
import no.uio.ifi.gruns.*;
/**
* The input ports on IBA units
*/
public class IBAInputPort extends InputPort {
/**
* Creates a new IBA input port
*/
public IBAInputPort(Kernel kernel){
super(kernel);
init();
}
/**
* Creates a new IBA input port with the supplied number of VLs
* @param numberOfVirtualLanes The number of VLs supported
* @param bufferSize The size of the buffers on each VL
* @param kernel The kernel to use for simulation
*/
public IBAInputPort(int numberOfVirtualLanes, int bufferSize, Kernel kernel){
super(numberOfVirtualLanes, kernel);
this.bufferSize = bufferSize;
init();
ABR = new int[numberOfVirtualLanes];
numberOfBytesOnTheirWay = new int[numberOfVirtualLanes];
}
/**
* Creates a new IBA input port with the supplied number of VLs
*/
public IBAInputPort(int numberOfVirtualLanes, Kernel kernel){
super(numberOfVirtualLanes, kernel);
bufferSize = 4 * Integer.parseInt(System.getProperty("infiniband.REAL_PACKET_SIZE"));
// Just to keep track of things
System.setProperty("infiniband.INPUT_PORT_BUFSIZE",
""+bufferSize);
init();
ABR = new int[numberOfVirtualLanes];
numberOfBytesOnTheirWay = new int[numberOfVirtualLanes];
}
/** Common initialization */
protected void init(){
currentLRH = dummyPacket.new LRH();
// Need to reallocate buffers to get the right size
for (int i=0; i < numberOfVLs; i++){
buffer[i] = new ByteBuffer(bufferSize);
}
}
/**
* Receives a packet from the supplied virtual lane number.
* TODO: Not implemented. Check if we actually need this or not.
149
*/
public Packet receivePacket(int VLNumber){
return null;
}
/**
* Receives a packet from the current virtual lane. Not implemented.
*/
public Packet receivePacket(){
return null;
}
/**
* Indicate whether we have data on the VL supplied
*/
public boolean hasDataOnVL(int VLNumber){
return !buffer[VLNumber].isEmpty();
}
/**
* Receives a single byte from the supplied virtual channel number
*/
public byte receiveByte(int VLNumber){
return buffer[VLNumber].get();
}
/**
* Returns the available credits on this port to simulate
* the Flow Control Packet as described in section 7.9.4
* on pp. 183-> in the IBA specification.
* FCCL is the Flow Control Credit Limit.
*
* TODO: Be aware that there could be some bytes on
* the link which have not
* yet arrived. This shouldn’t be possible, because the FCCL is really
* sent over the link, and, hence can’t overtake the bytes
* already on the link.
*
* OK. This should be solved with the "bytesOnTheirWay" variable.
*
* @param FCTBS - the Flow Control Total Blocks Sent
* @param VLNumber - the number of the VL to get the FCCL
* for.
*/
public int getFCCL(int FCTBS, int VLNumber){
// ABR Should be set to the FCTBS when a Flow
// control packet is received.
// These numbers should not differ when we have
// no link loss, as is the case here.
ABR[VLNumber] = FCTBS;
int FCCL = 0;
//
//
//
//
//
//
TODO: Maybe this must be updated to reflect that the blocks
do not contain the LRH or the VCRC. How do we know
the largest overhead of packets received? This
decides how many blocks we can receive.
Currently assumes IBA packets only, and that the packets
have all headers present.
// Subtract the bytes in transfer, so that we don’t
150
// say we have more buffer space that we actually have.
int capacity = buffer[VLNumber].getRemainingCapacity()
- numberOfBytesOnTheirWay[VLNumber];
// If we have room for 3.5 blocks, we only have room for 3,
// hence the floor.
int bufferBlockCapacity =
(int) Math.floor(capacity / Integer.parseInt(System.getProperty("infiniband.BLOCK_SIZE")));
if (bufferBlockCapacity >= 2048){
FCCL = (ABR[VLNumber] + 2048) % 4096;
}else{
FCCL = (ABR[VLNumber] + bufferBlockCapacity) % 4096;
}
return FCCL;
}
/**
* Used to tell this unit how many bytes are in transit to
* this unit, so that the getFCCL method can subtract the bytes
* in transit from the buffer capacity when replying to a
* @link{#getFCCL} message.
*
* This is necessary because the FCCL is not sent as a real message.
* If it were, it would be guaranteed to reach us after
* we had received all the bytes we had promised that we have
* the buffer space to receive.
*/
public void increaseBytesSent(int numberOfBytes, int VLNumber){
this.numberOfBytesOnTheirWay[VLNumber] += numberOfBytes;
}
/**
* Receives a number of bytes from the supplied buffer (internally in the
* Input port)
*/
private void readBytes(int VLNumber, byte[] fromBuffer, int numBytes){
int i;
for (i=0; i < numBytes; i++){
buffer[VLNumber].put(fromBuffer[i]);
}
// update the number of bytes on their way
this.numberOfBytesOnTheirWay[VLNumber]-=i;
// update the number of bytes received from current packet
this.numberOfBytesReceived+=i;
// update the number of bytes received this turn
this.bytesReceivedThisTurn+=i;
}
/**
* Receives a number of bytes from the supplied link (internally in the
* Input port)
*/
private void readBytes(int VLNumber, Link link, int numBytes){
int i;
for (i=0; i < numBytes; i++){
if (link.isEmpty()){
Reporter.error("IBAInputPort.readBytes(int, link, int):
"Link is empty, "+i+" bytes sent, trying
}
buffer[VLNumber].put(link.receiveByte());
}
// update the number of bytes on their way
151
"+
to send "+numBytes);
this.numberOfBytesOnTheirWay[VLNumber]-=i;
// update the number of bytes received from current packet
this.numberOfBytesReceived+=i;
// update the number of bytes received this turn
this.bytesReceivedThisTurn+=i;
}
public void act(){
int numBytes=0, pktLen=0;
byte [] tmpByte = null;
// reset number of bytes received this turn
this.bytesReceivedThisTurn = 0;
switch(state){
case READY:
this.numberOfBytesReceived = 0;
this.currentLRH = null;
if (link.isEmpty()){
// Halt with an error instead of rescheduling
Reporter.error("IBAInputPort.act(): "+
"Trying to receive from empty link!");
// Not enough
// kernel.schedule(this, kernel.currentTime() + 1);
// break;
}
else{
state = RECEIVING_HEAD;
}
// fallthrough
case RECEIVING_HEAD:
// Check if we have already read the LRH,
// if not, read it.
if (currentLRH == null){
tmpByte = new byte[IBAPacket.LRH_SIZE /
IBAPacket.BITS_PER_BYTE];
// Receive LRH
for (int i=0; i < tmpByte.length; i++){
tmpByte[i] = link.receiveByte();
}
currentLRH = dummyPacket.new LRH(tmpByte);
}
/*
// DEBUG
if (ID.startsWith("Switch 0, input port")){
Reporter.println("Time: "+kernel.currentTime()+", "+ID+": "+
"Receiving header"+
" on VL "+currentLRH.VL());
}
//
*/
// put the LRH in the right buffer if there is space for it.
if (buffer[currentLRH.VL()].getRemainingCapacity() >=
IBAPacket.LRH_SIZE){
if (tmpByte == null){
tmpByte = currentLRH.content;
}
readBytes(currentLRH.VL(), tmpByte, tmpByte.length);
152
}
// Reschedule if we didn’t have enough space for the LRH.
else{
// Halt
Reporter.error("IBAInputPort.act: Not enough buffer space!");
// Not good enough to reschedule
// kernel.schedule(this, kernel.currentTime() +
//
Integer.parseInt(System.getProperty("infiniband.SLEEP_TIME")));
// break;
}
// Read more data from the link
// (up to Integer.parseInt(System.getProperty("infiniband.BLOCK_SIZE")) bytes)
// if there’s space.
numBytes = Math.min(Integer.parseInt(System.getProperty("infiniband.BLOCK_SIZE"))
- tmpByte.length,
IBAPacketParser.packetLength(currentLRH));
if (buffer[currentLRH.VL()].getRemainingCapacity() >= numBytes){
readBytes(currentLRH.VL(), link, numBytes);
}
else{
Reporter.error("IBAInputPort.act:
Not enough buffer space!");
}
// Update the state. We have read the head if we get here.
state = RECEIVING_CONTENTS;
pktLen = IBAPacketParser.packetLength(currentLRH);
// Check if we are finished reading the packet
// (shouldn’t really be possible)
if (numberOfBytesReceived == pktLen){
state = READY;
}
break;
case RECEIVING_CONTENTS:
pktLen = IBAPacketParser.packetLength(currentLRH);
// Maybe there’s less than IBA_BLOCK_SIZE to receive
numBytes = Math.min(Integer.parseInt(System.getProperty("infiniband.BLOCK_SIZE")),
pktLen-numberOfBytesReceived);
// Reschedule on the next step if there’s not enough
// space to read.
if (buffer[currentLRH.VL()].getRemainingCapacity() < numBytes){
// Halt
Reporter.error("IBAInputPort.act: Not enough buffer space!");
// Not good enough to reschedule
// kernel.schedule(this, kernel.currentTime() +
//
Integer.parseInt(System.getProperty("infiniband.SLEEP_TIME")));
// break;
}
// Read data from the link
readBytes(currentLRH.VL(), link, numBytes);
/*
// DEBUG
if (ID.startsWith("Switch 0, input port")){
Reporter.println("Time: "+kernel.currentTime()+", "+ID+": "+
"Receiving block "+(int)(Math.ceil(
((double)numberOfBytesReceived)/64))+
" on VL "+currentLRH.VL());
}
153
//
*/
// Check if we are finished reading the packet
if (numberOfBytesReceived == pktLen){
state = READY;
}
break;
default:
Reporter.error("IBAInputPort.act:
Illegal state: "+state);
}
//
//
//
//
//
if
Notify the unit we are attached to by scheduling it, so
that it can read the data that has come in.
Maybe the unit wants to start reading before a whole packet
has arrived, i.e. if it’s a switch, and wants to start
looking up the address.
(bytesReceivedThisTurn != 0){
/*
// DEBUG
if (ID.equals("Drain 0, port 0")){
Reporter.debugln(ID+", VL "+currentLRH.VL()+
": bytesReceivedThisTurn = "+bytesReceivedThisTurn+
", Bytes of current packet: "+
numberOfBytesReceived);
}
//
*/
if (sink instanceof IBADrainNode){
((IBADrainNode)sink).increaseBytesReadyToBeReceived(this,
currentLRH.VL(),
bytesReceivedThisTurn);
}
kernel.schedule(sink, kernel.currentTime() + 1);
}
/*
// DEBUG
if (this.ID.startsWith("Switch 4")){
Reporter.debugln(ID+", received "+numberOfBytesReceived+" from packet, "+
bytesReceivedThisTurn+" this turn.");
}
//
*/
/*
// DEBUG
Reporter.debugln("--------------------------------------------------");
Reporter.debugln("Time: "+kernel.currentTime()+", ID: "+ID);
Reporter.debugln("numBytes that should have been read = "+numBytes);
Reporter.debugln("bytesReceivedThisTurn = "+bytesReceivedThisTurn);
Reporter.debugln("bytes received from current = "+numberOfBytesReceived);
//
*/
}
/**
* Returns buffer number VLNumber.
*/
public ByteBuffer getByteBuffer(int VLNumber){
154
return buffer[VLNumber];
}
public String report(){
return "IBAInputPort \""+ID+"\": bytes in buffer : "+
numberOfBytesReceived+
", VL: "+(currentLRH==null?"null":""+currentLRH.VL())+
",bytes on their way[0]: "+ this.numberOfBytesOnTheirWay[0];
}
/** The number of bytes received of the current packet */
protected int numberOfBytesReceived;
/** The number of bytes received this turn. */
protected int bytesReceivedThisTurn;
/** The head of the packet we are currently receiving */
protected IBAPacket.LRH currentLRH;
/**
* The state of the input port.
* Either READY, RECEIVING_HEAD or RECEIVING_CONTENTS
*/
protected int state;
/**
* The Adjusted Blocks Received, number of blocks received
* represented by a 12-byte number (i.e. <4096), for each
* VL in the input port.
*/
protected int[] ABR;
/**
* The unit that this input port is receiving for
*/
protected Scheduleable sink;
/**
* Sets the unit that this input port is receiving for
*/
protected void setSink(Scheduleable sink){
this.sink = sink;
}
/**
* Gets the unit that this input port is receiving for
*/
protected Scheduleable getSink(){
return sink;
}
/**
* Gets the unit that this input port is receiving from
*/
protected Scheduleable getSource(){
return link.getSource();
}
/**
*
*
*
*
*
*
Used to tell this unit how many bytes are in transit to
this unit, so that the getFCCL method can subtract the bytes
in transit from the buffer capacity when replying to a
@link{#getFCCL} message.
This is necessary because the FCCL is not sent as a real message.
155
* If it were, it would be guaranteed to reach us after we
* had received all the bytes we had promised that we have the
* buffer space to receive.
*/
protected int[] numberOfBytesOnTheirWay;
protected static final int READY = 0;
protected static final int RECEIVING_HEAD = 1;
protected static final int RECEIVING_CONTENTS = 2;
protected static final IBAPacket dummyPacket = new IBAPacket();
}
156
no.uio.ifi.gruns.infiniband.IBAPacketSender
package no.uio.ifi.gruns.infiniband;
import no.uio.ifi.gruns.*;
/**
* All classes that are able to send IBA packets
* should implement this interface.
*/
public interface IBAPacketSender extends PacketSender {
/**
* Adds an entry of high priority on this output port.
* @param portNumber The output port to add an entry to
* @param VLNumber The Virtual lane to add an entry for
* @param weight The number of
* Integer.parseInt(System.getProperty("infiniband.BLOCK_SIZE"))-byte units this VL should
* be allowed to transfer on each turn
*
*/
public void addHighPriority(int portNumber, int VLNumber, int weight);
/**
* Adds an entry of low priority on this output port.
* @param portNumber The output port to add an entry to
* @param VLNumber The Virtual lane to add an entry for
* @param weight The number of
* Integer.parseInt(System.getProperty("infiniband.BLOCK_SIZE"))-byte units this VL should
* be allowed to transfer on each turn
*
*/
public void addLowPriority(int portNumber, int VLNumber, int weight);
}
157
no.uio.ifi.gruns.infiniband.IBASwitch
package no.uio.ifi.gruns.infiniband;
import no.uio.ifi.gruns.*;
import no.uio.ifi.tools.*;
import java.util.Random;
import java.util.ArrayList;
public class IBASwitch extends Switch implements Reporting{
public IBASwitch(Kernel kernel){
super(kernel);
routingTable = new IBARoutingTable();
}
public IBASwitch(int numberOfInputPorts,
int numberOfOutputPorts,
int numberOfVirtualLanes,
Kernel kernel){
this(numberOfInputPorts, numberOfOutputPorts,
numberOfVirtualLanes, "", kernel);
}
/**
* @param numberOfInputPorts The number of input ports
* @param numberOfOutputPorts The number of output ports
* @param inputBufferSize The size of the buffers in the input
*
ports. Affects how the switch acts,
*
because when the output buffers go full, the low
*
priority queues get more priority than when
*
there’s still plenty of space.
* @param outputBufferSize The size of the buffers in the output
*
ports.
* @param numberOfVirtualLanes The number of virtual lanes on
*
input and output ports.
* @param ID A string identifying the switch
* @param kernel The kernel to use for simulation
*/
public IBASwitch(int numberOfInputPorts,
int numberOfOutputPorts,
int numberOfVirtualLanes,
int inputBufferSize,
int outputBufferSize,
String ID,
Kernel kernel){
this(kernel);
int i;
this.inputBufferSize = inputBufferSize;
this.outputBufferSize = outputBufferSize;
// Create input and output ports
inputPorts = new IBAInputPort[numberOfInputPorts];
for (i=0; i < numberOfInputPorts; i++){
inputPorts[i] = new IBAInputPort(numberOfVirtualLanes,
inputBufferSize,
kernel);
inputPorts[i].setSink(this);
158
inputPorts[i].setID(ID+", input port "+i);
}
outputPorts = new IBAOutputPort[numberOfOutputPorts];
for (i=0; i < numberOfOutputPorts; i++){
outputPorts[i] = new IBAOutputPort(numberOfVirtualLanes,
outputBufferSize,
kernel);
outputPorts[i].setID(ID+", output port "+i);
}
// Assign ID
this.ID = ID;
// Other initialization
VLstates = new VLstate[inputPorts.length][numberOfVirtualLanes];
for (i=0; i < VLstates.length; i++){
for (int j=0; j < VLstates[i].length; j++){
VLstates[i][j] = new VLstate();
}
}
random = new Random(1L);
drawHistory = new int[inputPorts.length];
// prefs
this.procTime = Integer.getInteger("infiniband.PACKET_PROCESSING_TIME").intValue();
this.sleepTime = Integer.getInteger("infiniband.SLEEP_TIME").intValue();
this.blockSize = Integer.getInteger("infiniband.BLOCK_SIZE").intValue();
}
/**
* Uses the default bufferSize of the input and output ports.
*/
public IBASwitch(int numberOfInputPorts,
int numberOfOutputPorts,
int numberOfVirtualLanes,
String ID,
Kernel kernel){
this(kernel);
int i;
this.numberOfVirtualLanes = numberOfVirtualLanes;
// Create input and output ports
inputPorts = new IBAInputPort[numberOfInputPorts];
for (i=0; i < numberOfInputPorts; i++){
inputPorts[i] = new IBAInputPort(numberOfVirtualLanes,
kernel);
inputPorts[i].setSink(this);
inputPorts[i].setID(ID+", input port "+i);
}
outputPorts = new IBAOutputPort[numberOfOutputPorts];
for (i=0; i < numberOfOutputPorts; i++){
outputPorts[i] = new IBAOutputPort(numberOfVirtualLanes,
kernel);
outputPorts[i].setID(ID+", output port "+i);
}
// Assign ID
this.ID = ID;
// Other initialization
VLstates = new VLstate[inputPorts.length][numberOfVirtualLanes];
for (i=0; i < VLstates.length; i++){
for (int j=0; j < VLstates[i].length; j++){
VLstates[i][j] = new VLstate();
}
159
}
random = new Random(1L);
drawHistory = new int[inputPorts.length];
// prefs
this.procTime = Integer.getInteger("infiniband.PACKET_PROCESSING_TIME").intValue();
this.sleepTime = Integer.getInteger("infiniband.SLEEP_TIME").intValue();
this.blockSize = Integer.getInteger("infiniband.BLOCK_SIZE").intValue();
}
/**
* Sets the routing table for this switch.
*/
public void setRoutingTable(IBARoutingTable routingTable){
this.routingTable = routingTable;
}
/**
* Adds an address range that this source node can send
* to. The format of the string can be one of the following,
* where aaa, bbb, ccc and ddd represents integers between 0 and 255:
* <table>
* <tr><td>aaa.bbb</td><td>Adds the specified address</tr>
* <tr><td>aaa.bbb-ccc.ddd</td><td>Adds addresses ranging from
*
aaa.bbb to ccc.ddd, inclusive.</td></tr>
* </table>
* @param range A string describing the address range.
*/
public void addRoutingInterval(String range, int outputPortNumber){
Address[] addrs = Utils.getAddresses(range);
if (outputPortNumber < 0
|| outputPortNumber > outputPorts.length){
throw new IllegalArgumentException("Output port number "+
"out of range. Must be"+
" between 0 and "+
(outputPorts.length-1)+
".");
}
for (int i=0; i < addrs.length; i++){
routingTable.addRoute(addrs[i], outputPortNumber);
// {{{ DEBUG
/*
Reporter.debugln(ID+": Sending address \""+addrs[i]+
"\" to port "+outputPortNumber);
*/
// }}}
}
}
/**
* Deletes an address range that this source node can send
* to. The format of the string can be one of the following,
* where aaa, bbb, ccc and ddd represents integers between 0 and 255:
* <table>
* <tr><td>aaa.bbb</td><td>Adds the specified address</tr>
* <tr><td>aaa.bbb-ccc.ddd</td><td>Adds addresses ranging from
*
aaa.bbb to ccc.ddd, inclusive.</td></tr>
* </table>
* @param range A string describing the address range.
160
*/
public void deleteRoutingInterval(String range, int outputPortNumber){
Address[] addrs = Utils.getAddresses(range);
if (outputPortNumber < 0
|| outputPortNumber > outputPorts.length){
throw new IllegalArgumentException("Output port number "+
"out of range. Must be"+
" between 0 and "+
(outputPorts.length-1)+
".");
}
for (int i=0; i < addrs.length; i++){
routingTable.deleteRoute(addrs[i], outputPortNumber);
// {{{ DEBUG
/*
Reporter.debugln(ID+": Not sending address \""+addrs[i]+
"\" to port "+outputPortNumber);
*/
// }}}
}
}
/**
* Attaches a link to this switch on the
* supplied input port number
*/
public void attachInput(Link l, int inputPortNumber)
throws IllegalArgumentException {
if (inputPorts == null){
throw new IllegalArgumentException("This switch has no "+
"input ports.");
}
if (inputPortNumber < 0 || inputPortNumber > inputPorts.length){
throw new IllegalArgumentException("Input port number out "+
"of range. Must be"+
"between 0 and "+
inputPorts.length);
}
inputPorts[inputPortNumber].attach(l);
// Update the ID to be able to distinguish
// input ports from each other
inputPorts[inputPortNumber].setID(ID+", input port "+
inputPortNumber);
}
/**
* Gets the neighbor on the supplied output port
*/
public Scheduleable getOutNeighbour(int portNumber){
return ((IBAInputPort)outputPorts[portNumber].getSink()).getSink();
}
/**
* Gets the neighbor on the supplied output port
*/
public Scheduleable getInNeighbour(int portNumber){
return (Scheduleable) inputPorts[portNumber].getSource();
161
}
/**
* Returns a pointer to the output ports
*/
public IBAOutputPort[] getOutputPorts(){
return outputPorts;
}
/**
* Sets the number of units we can send from high priority
* before letting a unit from low priority send.
* @param portNumber The port number to set the limit for
* @param limit The number of units
*/
public void setLimitOfHighPriority(int portNumber, int limit){
outputPorts[portNumber].setLimitOfHighPriority(limit);
}
/**
* Adds an entry to the high priority list of this switch.
* Means that port number <tt>portNumber</tt> is allowed to send
* <tt>weight</tt> units on virtual lane number <tt>VLNumber</tt>.
* This entry has high priority, which means that it will be selected
* before any of the entries in the low priority table.
*/
public void addHighPriority(int portNumber, int VLNumber, int weight){
outputPorts[portNumber].addHighPriority(VLNumber, weight);
}
/**
* Adds an entry to the low priority list of this switch.
* Means that port number <tt>portNumber</tt> is allowed to send
* <tt>weight</tt> units on virtual lane number <tt>VLNumber</tt>.
* This entry has low priority, which means that it will be selected
* after any of the entries in the high priority table.
*/
public void addLowPriority(int portNumber, int VLNumber, int weight){
outputPorts[portNumber].addLowPriority(VLNumber, weight);
}
/**
* Attaches a link to this switch on the
* supplied output port number
*/
public void attachOutput(Link l, int outputPortNumber)
throws IllegalArgumentException {
if (outputPorts == null){
throw new IllegalArgumentException("This switch has no "+
"output ports.");
}
if (outputPortNumber < 0
|| outputPortNumber > outputPorts.length){
throw new IllegalArgumentException("Output port number out "+
"of range. Must be"+
"between 0 and "+
outputPorts.length);
}
outputPorts[outputPortNumber].attach(l);
162
// Update the ID to be able to distinguish
// output ports from each other
outputPorts[outputPortNumber].setID(ID+", output port "+
outputPortNumber);
}
protected void checkForData(VLstate state, int portNum, int vlNum){
// Reinitialize the state of this VL
state.reset();
if (inputPorts[portNum].hasDataOnVL(vlNum)){
state.state = VLstate.RECEIVING_HEADER;
state.numberOfBytesReceived = 0;
receiveHeader(state, portNum, vlNum);
}
}
protected void receiveHeader(VLstate state, int portNum, int vlNum){
/*
// DEBUG
if (ID.startsWith("Switch 0")){
Reporter.println("Time: "+kernel.currentTime()+", "+ID+": "+
"("+portNum+","+vlNum+") ,"+
"Receiving header.");
}
//
*/
int headerSize = IBAPacket.LRH_SIZE / IBAPacket.BITS_PER_BYTE;
// Read the header
for (int k=0; k < headerSize; k++) {
// Check for internal simulator errors
if (!inputPorts[portNum].hasDataOnVL(vlNum)){
Reporter.error("IBASwitch.receiveHeader: No data in "+
"input port "+portNum+", VL "+vlNum);
}
state.lrh[k] = (inputPorts[portNum].receiveByte(vlNum));
state.numberOfBytesReceived++;
}
// If we have read a whole lrh,
// start processing header.
if (state.numberOfBytesReceived == headerSize ){
state.state = VLstate.PROCESSING_HEADER;
state.remainingProcessingTime = procTime;
kernel.schedule(this,
kernel.currentTime() + 1);
// Start processing of header
processHeader(state, portNum, vlNum);
}else{
Reporter.error("IBASwitch.receiveHeader: Coulnd’t read whole header. "+
"Read "+state.numberOfBytesReceived+" bytes, needed "+
headerSize);
}
}
163
protected void processHeader(VLstate state, int portNum, int vlNum){
/*
// DEBUG
if (ID.startsWith("Switch 0")){
Reporter.println("Time: "+kernel.currentTime()+", "+ID+": "+
"("+portNum+","+vlNum+") ,"+
"Processing header. Processing time left: "
+(state.remainingProcessingTime));
}
//
*/
IBAPacket.LRH lrh;
// sanity check
if (state.remainingProcessingTime < 0 ){
Reporter.error("IBASwtich.act: Remaining "+
"processing time is negative: "+
state.remainingProcessingTime);
}
if (state.remainingProcessingTime == 0){
lrh = dummyPacket.new LRH(state.lrh);
// Find the output port and VL
Route r = routingTable.lookUp(lrh);
state.outputPort = r;
// TODO: Do something sensible if we have no
// routing table entry for that address.
if (r == null){
throw new RuntimeException(ID+": "+
"No routing table"+
" entry for "+
"address "+
new Address(lrh.DLID()).toString());
}
if (outputPorts[r.portNumber].
canSend(r.VLNumber,
IBAPacketParser.packetLength(lrh))
&& (!outputPorts[r.portNumber].
occupied(r.VLNumber)) ){
//
//
//
//
Tell the port that we want to send
on that VL to avoid that any other
packet is sent on the same VL on the same
time.
outputPorts[r.portNumber].
occupy(r.VLNumber);
state.state = VLstate.VIRTUAL_CUT_THROUGH;
state.numberOfBytesSent = 0;
kernel.schedule(this,
kernel.currentTime() + 1);
// Start Virtual cut-through
virtualCutThrough(state, portNum, vlNum);
}else{
state.state = VLstate.WAITING_FOR_OUTPUT_LINK;
state.numberOfBytesSent = 0;
kernel.schedule(this,
kernel.currentTime() + sleepTime);
}
164
}
else // if (state.remainingProcessingTime > 0)
{
// Read rest of a 64-byte block of data
// Wait ’processingTime’ time units, and then perform
// the whole lookup, instead of adding an ’act’ method
// to the routing table. Same result, simpler code.
state.remainingProcessingTime--;
kernel.schedule(this,
kernel.currentTime() + 1);
}
}
protected void waitForOutputLink(VLstate state, int portNum, int vlNum){
IBAPacket.LRH lrh;
lrh = dummyPacket.new LRH(state.lrh);
// Find the output port and VL
Route r = routingTable.lookUp(lrh);
state.outputPort = r;
// Check if the output port has space on that VL
if (outputPorts[r.portNumber].
canSend(r.VLNumber,
IBAPacketParser.packetLength(lrh))
&& (!outputPorts[r.portNumber].
occupied(r.VLNumber)) ){
// Occupy the output VL
outputPorts[r.portNumber].
occupy(r.VLNumber);
state.state = VLstate.FORWARD;
state.numberOfBytesSent = 0;
// Start forwarding of the packet
forward(state, portNum, vlNum);
}
else{
kernel.schedule(this,
kernel.currentTime() + sleepTime);
}
}
protected void virtualCutThrough(VLstate state, int portNum, int vlNum){
/*
// DEBUG
if (ID.startsWith("Switch 0")){
Reporter.println("Time: "+kernel.currentTime()+", "+ID+": "+
"("+portNum+","+vlNum+") ,"+
"Sending block "+(int)(Math.ceil(
((double)state.numberOfBytesReceived)/64))+
" on VL "+vlNum);
}
//
*/
forward(state, portNum, vlNum);
}
165
/**
* Sends a block onto the output ports of the switch.
*/
protected void sendBlock(VLstate state, int portNum, int vlNum, int numBytes)
throws NotClearToSendException{
IBAPacket.LRH lrh;
lrh = dummyPacket.new LRH(state.lrh);
/*
// DEBUG
Reporter.debugln("IBAPacketParser.packetLength(lrh) = "+
IBAPacketParser.packetLength(lrh));
Reporter.debugln("state.numberOfBytesSent = "+
state.numberOfBytesSent);
Reporter.debugln("(IBAPacketParser.packetLength(lrh) - "+
"state.numberOfBytesSent) = "+
(IBAPacketParser.packetLength(lrh) state.numberOfBytesSent));
Reporter.debugln("numBytes to send = "+numBytes);
//
*/
// To check for concistency
int limit = (IBAPacketParser.packetLength(lrh)
- state.numberOfBytesSent);
for (int k=0; k < numBytes; k++) {
if (k >= limit ||
! inputPorts[portNum].hasDataOnVL(vlNum)){
Reporter.error("IBASwitch.sendBlock: "+
"input port "+portNum+", VL "+vlNum+" is empty! Trying to send "+
numBytes+", sent "+k+".");
}
// Read one byte from input port and
// put on corresponding output port
try{
outputPorts[state.outputPort.portNumber].
sendByte(inputPorts[portNum].receiveByte(vlNum),
state.outputPort.
VLNumber);
}catch (NotClearToSendException nctse){
nctse.printStackTrace(Reporter.getOutputStream());
System.exit(1);
}
state.numberOfBytesReceived++;
state.numberOfBytesSent++;
// To know if we should schedule
// the next unit or not
bytesSentOnCurrentVLThisTurn++;
// Check if we are done
if (state.numberOfBytesSent ==
IBAPacketParser.packetLength(lrh) ){
// Release the VL
outputPorts[state.outputPort.
portNumber].
release(state.outputPort.
VLNumber);
state.state = VLstate.READY;
166
//
//
//
//
//
Reschedule in case there’s more
data immediately waiting.
We could have "lost" some schedulings by the
input port if we were already scheduled,
so there could be more data waiting.
kernel.schedule(this, kernel.currentTime() + 1);
break; // out of foor loop
}
}
}
protected void forward(VLstate state, int portNum, int vlNum){
IBAPacket.LRH lrh;
lrh = dummyPacket.new LRH(state.lrh);
// Send the lrh first
if (state.numberOfBytesSent == 0){
int numBytes = IBAPacket.LRH_SIZE / IBAPacket.BITS_PER_BYTE;
for (int k=0; k < numBytes; k++){
// Check for internal simulator errors
if (!inputPorts[portNum].hasDataOnVL(vlNum)){
Reporter.error("IBASwitch.forward: No data in "+
"input port "+portNum+", VL "+vlNum);
}
try{
outputPorts[state.outputPort.portNumber].sendByte(state.lrh[k],
state.outputPort.
VLNumber);
}catch (NotClearToSendException nctse){
nctse.printStackTrace(Reporter.getOutputStream());
System.exit(1);
}
state.numberOfBytesSent++;
// To know if we should schedule
// the next unit or not
bytesSentOnCurrentVLThisTurn++;
}
// Send rest of a IBA_BLOCK_SIZE block of the
// packet (64-8 = 56 bytes for the moment.)
numBytes = blockSize(IBAPacket.LRH_SIZE /
IBAPacket.BITS_PER_BYTE);
sendBlock(state,
portNum,
vlNum,
numBytes);
}
// If we have sent the lrh, send a block
// from the rest of the packet.
else{
int numBytes = Math.min(blockSize,
(IBAPacketParser.packetLength(lrh) state.numberOfBytesSent));
167
sendBlock(state,
portNum,
vlNum,
numBytes);
}
// Reschedule if we are not finished
if (state.numberOfBytesSent !=
IBAPacketParser.packetLength(lrh) ){
kernel.schedule(this, kernel.currentTime() + 1);
}
/*
// DEBUG
if (ID.startsWith("Switch 0")){
Reporter.println("Time: "+kernel.currentTime()+", "+ID+": "+
"("+portNum+","+vlNum+"), "+
"Sending block "+(int)(Math.ceil(
((double)state.numberOfBytesReceived)/64))+
" ("+state.numberOfBytesSent+" bytes) on VL "+vlNum);
}
//
*/
}
/**
* Loops through all VLs on all input ports and processes data
* on it. Resembles a fully parallellized swich that is able
* to process data on all incoming interfaces simultaneously.
*
* See p. 853 in the IBA spec: The packets shall not
* leave the input buffers if there’s not enough room in the output
* buffers.
*
* C18-25:
* Except for virtual lane 15, if the virtual lane on the
* outbound port does not contain sufficient space for the packet to
* be relayed, then the packet shall remain in the virtual lane on
* the inbound port until sufficient space is available or until
* the switch lifetime limit mechanism permits the discard of
* the packet.
*
*/
public void act(){
// dummy, just for jbuilder to be able to set breakpoint before
// the for loop.
int dust = 0;
//
//
//
//
//
//
//
//
//
//
//
Only loop through the input ports that have data. This is
very important when the net is congested. If we loop through
all input ports, and one of them is unused, the input port
that is numbered one above the unused port gets the empty port’s
chance to go first in addition to its own.
This results in an uneven distribution of the capacity between
the input ports, because when the buffers on the output ports are
nearly full, it’s crucial for an input port to get to try first to be
allowed to send data, since the first one to try will occupy the output
port, and hence the other input ports will not have a chance to send.
168
//
// The solution is to first check which input ports have data to send,
// and then only loop through these input ports, starting on a random port
// each time.
// Find out how many output ports have data to send
int numWithData = 0;
for (int i=0; i < inputPorts.length; i++) {
for (int j=0; j < inputPorts[i].numberOfVLs(); j++) {
if (inputPorts[i].hasDataOnVL(j)){
numWithData++;
// don’t count an input port with data on more
// than one VL more than once.
break;
}
}
}
int[] inputPortsWithData = new int[numWithData];
for (int i=0,k=0; i < inputPorts.length; i++) {
for (int j=0; j < inputPorts[i].numberOfVLs(); j++) {
if (inputPorts[i].hasDataOnVL(j)){
inputPortsWithData[k++] = i;
// don’t add an input port with data on more
// than one VL more than once.
break;
}
}
}
/*
// Loop through all ports, starting on a new one each time.
for (int i=inputPortNumberToStartOn, n=0;
n < inputPorts.length;
i = (i+1) % inputPorts.length, n++ ){
*/
// Return if there’s no data to send.
if (numWithData == 0) return;
//
//
//
//
//
//
//
Randomize order of input ports in the list of ports
with data to send, to avoid that e.g. port 3 gets to send
before port 0 both when port 1, 2 and 3 gets to try first.
In all these cases, 3 will have a go before 0, and will be able
to send more times than port 0.
Serving ports equally is not easy.
// Copy list of input port numbers to a dynamic array
ArrayList tmp = new ArrayList(inputPortsWithData.length);
for (int i=0; i < inputPortsWithData.length; i++) {
tmp.add(new Integer(inputPortsWithData[i]));
}
// Add all items randomly to the original array,
// and then the elements should be reordered randomly.
for (int i=0; i < inputPortsWithData.length; i++) {
inputPortsWithData[i] = ((Integer)tmp.remove(random.
nextInt(tmp.size()))).intValue();
}
// Loop through ports with data waiting to send
169
// No need to randomize the index to start on when
// the order of the ports in the array is random.
// This will perhaps introduce less randomness.
//int indexToStartOn = random.nextInt(numWithData);
int indexToStartOn = 0;
drawHistory[inputPortsWithData[indexToStartOn]]++;
for (int i=indexToStartOn, n=0;
n < numWithData;
i = (i+1) % numWithData, n++) {
for (int j=0; j < inputPorts[inputPortsWithData[i]].numberOfVLs(); j++){
bytesSentOnCurrentVLThisTurn = 0;
VLstate state = VLstates[inputPortsWithData[i]][j];
switch(state.state){
case(VLstate.READY):
checkForData(state, inputPortsWithData[i], j);
break;
case(VLstate.RECEIVING_HEADER):
receiveHeader(state, inputPortsWithData[i], j);
break;
case(VLstate.PROCESSING_HEADER):
processHeader(state, inputPortsWithData[i], j);
break;
case(VLstate.WAITING_FOR_OUTPUT_LINK):
waitForOutputLink(state, inputPortsWithData[i], j);
break;
case(VLstate.VIRTUAL_CUT_THROUGH):
virtualCutThrough(state, inputPortsWithData[i], j);
break;
case(VLstate.FORWARD):
forward(state, inputPortsWithData[i], j);
break;
default:
Reporter.error("IBASwitch.act: Illegal input VL "+
"state: "+state.state);
}
// Schedule the output port so that the packet moves on
// if any bytes have been sent.
if (bytesSentOnCurrentVLThisTurn != 0){
/*
// DEBUG
if (ID.startsWith("Switch 0")){
Reporter.println("Time: "+kernel.currentTime()+", "+ID+": "+
"Scheduling output port "+
outputPorts[state.
outputPort.portNumber]+
" on time "+(kernel.currentTime() + 1)+".");
}
//
*/
170
kernel.schedule(outputPorts[state.
outputPort.portNumber],
kernel.currentTime() + 1);
}
}
}
// Update which input port number we should start to check for
// incoming data the next time we are called.
/*
inputPortNumberToStartOn =
(inputPortNumberToStartOn + 1) % inputPorts.length;
*/
// Always serve packets waiting for output links first,
// to avoid filling up with a new packet from another input link
// on the next time step, and hence starving the flow waiting for
// the output port forever.
//
// If more than one flow is waiting for the output link, eventually
// all flows should be served, since on the next time step,
// the one that got prioritized this time won’t be waiting for the
// output link anymore, and then the next flow waiting will be served,
// and so on until all streams should be served.
/*
boolean changed = false;
for (int i=0; i < inputPorts.length && !changed; i++) {
for (int j=0; j < inputPorts[i].numberOfVLs(); j++) {
VLstate state = VLstates[i][j];
if (state.state == VLstate.WAITING_FOR_OUTPUT_LINK) {
inputPortNumberToStartOn = i;
// Stop iteration
changed = true;
}
}
}
if (!changed || (changed && random.nextInt(2)==0)){
// Try random value each time
inputPortNumberToStartOn = random.nextInt(inputPorts.length);
drawHistory[inputPortNumberToStartOn]++;
}
*/
/*
inputPortNumberToStartOn = random.nextInt(inputPorts.length);
drawHistory[inputPortNumberToStartOn]++;
*/
}
/**
* Returns the number of packets sent through the switch.
*/
public int[] getTotalNumberOfPacketsSent() {
int[] total = new int[outputPorts.length];
for (int i=0; i < outputPorts.length; i++) {
/*
for (int j=0; j< numberOfVirtualLanes; j++) {
171
total[i] += outputPorts[i].getTotalNumberOfPacketsSent(j);
}
*/
total[i] = outputPorts[i].getTotalNumberOfPacketsSent();
}
return total;
}
/**
* Returns the random draw history
*/
public int[] getDrawHistory() {
return drawHistory;
}
public String report(){
return "IBASwitch \""+ID+"\".";
}
/**
* The input ports of this switch
*/
protected IBAInputPort[] inputPorts;
/**
* The output ports of this switch
*/
protected IBAOutputPort[] outputPorts;
/**
* The number of virtual lanes (VLs) supported by this switch
*/
protected int numberOfVirtualLanes;
/**
* The buffer size of the input buffers
*/
protected int inputBufferSize;
/**
* The buffer size of the output buffers
*/
protected int outputBufferSize;
/**
* The routing table to look up addresses in
*/
protected IBARoutingTable routingTable;
/** Dummy packet used to create IBAPacket.LRH objects */
protected static final IBAPacket dummyPacket = new IBAPacket();
/**
* Which input port to start looking for new packets on
* when act() is called. Should start on a new one each time,
* to ensure fairness.
*/
protected int inputPortNumberToStartOn = 0;
/** To know if we should schedule the next unit or not */
protected int bytesSentOnCurrentVLThisTurn = 0;
172
/**
* To draw next input port to start checking for incoming traffic
* on.
*/
protected Random random;
/**
* To keep track of random draws
*/
protected int[] drawHistory;
// These are here to avoid reading system preferences all the time.
// I think that is rather inefficient.
/**
* The time it takes to process a packet in the switch
*/
protected int procTime;
/**
* The time to sleep if there’s no space available to send data
*/
protected int sleepTime;
/**
* The size of a block
*/
protected int blockSize;
/**
* The state of all the input VLs
*/
protected VLstate[][] VLstates;
protected class VLstate{
public int state;
public Route outputPort;
public byte[] lrh;
public int remainingProcessingTime;
public int numberOfBytesReceived;
public int numberOfBytesSent;
protected VLstate(){
init();
}
protected void init(){
state = READY;
outputPort = null;
lrh = new byte[IBAPacket.LRH_SIZE / IBAPacket.BITS_PER_BYTE];
remainingProcessingTime = -1;
numberOfBytesReceived = -1;
numberOfBytesSent = -1;
}
protected void reset(){
init();
}
public
public
public
public
public
public
static
static
static
static
static
static
final
final
final
final
final
final
int
int
int
int
int
int
READY
RECEIVING_HEADER
PROCESSING_HEADER
VIRTUAL_CUT_THROUGH
WAITING_FOR_OUTPUT_LINK
FORWARD
173
=
=
=
=
=
=
0;
1;
2;
3;
4;
5;
}
}
174
no.uio.ifi.gruns.infiniband.IBAPacketParser
package no.uio.ifi.gruns.infiniband;
import no.uio.ifi.gruns.*;
public class IBAPacketParser{
/**
* Returns the total length of the packet
* with the supplied LRH, including all CRCs and padding
*/
public static int packetLength(IBAPacket.LRH header){
int pktLen;
// +2 is for the VCRC, which is not included in PktLen.
pktLen = (header.PktLen() * 4)+ 2;
return pktLen;
}
/**
* Returns the total length of the packet
* with the supplied LRH bytes.
*/
public static int packetLength(byte[] lrh){
return packetLength(dummyPacket.new LRH(lrh));
}
/**
* Returns the next LRH from the supplied ByteBuffer.
* The header is removed from the buffer.
*/
public static IBAPacket.LRH getNextHeader(ByteBuffer buffer){
IBAPacket.LRH lrh;
byte[] tmpByte = new byte[IBAPacket.LRH_SIZE /
IBAPacket.BITS_PER_BYTE];
for (int i=0; i < tmpByte.length; i++){
tmpByte[i] = buffer.get();
}
lrh = dummyPacket.new LRH(tmpByte);
return lrh;
}
/**
* Extracts the first IBA packet from the supplied
* {@link no.uio.ifi.gruns.ByteBuffer} and returns it.
* If you have a partially filled packet and want to
* fill it up from the ByteBuffer, supply the packet in
* the second parameter.
* Otherwise, send in an empty IBAPacket.
*
* @param bytestream The stream of bytes to read from
* @param packet The packet to fill up
175
* @return true when the packet is filled up, false if there was
* not enough data to fill the packet.
*/
public static boolean getNextPacket(ByteBuffer bytestream,
IBAPacket packet){
byte[] tmpByte = null;
int tmpLen = 0;
// Read in the LRH from the byte stream if this is the
// first time called (e.g. packet.getSize() == 0)
if (packet.getSize() == 0){
// Update number of bytes read
bytesRead = 0;
// LRH
// not enough bytes to read the whole LRH yet.
if (bytestream.getSize() < IBAPacket.LRH_SIZE){
return false;
}
tmpLen = IBAPacket.LRH_SIZE / IBAPacket.BITS_PER_BYTE;
tmpByte = new byte[tmpLen];
for (int i=0; i < tmpLen; i++){
tmpByte[i] = bytestream.get();
bytesRead++;
}
packet.lrh = packet.new LRH(tmpByte);
}
//
//
//
if
If not all of the packet has arrived yet, return false.
TODO: Maybe change this later to return true when the
LRH can be read. Or not. Think it over.
(bytestream.getSize() < packet.getSize() - bytesRead){
return false;
}
// GRH
if (packet.grh.isPresent()){
tmpLen = IBAPacket.GRH_SIZE / IBAPacket.BITS_PER_BYTE;
tmpByte = new byte[tmpLen];
for (int i=0; i < tmpLen; i++){
tmpByte[i] = bytestream.get();
bytesRead++;
}
packet.grh = packet.new GRH(tmpByte);
}
// BTH
if (packet.bth.isPresent()){
tmpLen = IBAPacket.BTH_SIZE / IBAPacket.BITS_PER_BYTE;
tmpByte = new byte[tmpLen];
for (int i=0; i < tmpLen; i++){
tmpByte[i] = bytestream.get();
bytesRead++;
}
packet.bth = packet.new BTH(tmpByte);
}
// RDETH
176
if (packet.rdeth.isPresent()){
tmpLen = IBAPacket.RDETH_SIZE / IBAPacket.BITS_PER_BYTE;
tmpByte = new byte[tmpLen];
for (int i=0; i < tmpLen; i++){
tmpByte[i] = bytestream.get();
bytesRead++;
}
packet.rdeth = packet.new RDETH(tmpByte);
}
// DETH
if (packet.deth.isPresent()){
tmpLen = IBAPacket.DETH_SIZE / IBAPacket.BITS_PER_BYTE;
tmpByte = new byte[tmpLen];
for (int i=0; i < tmpLen; i++){
tmpByte[i] = bytestream.get();
bytesRead++;
}
packet.deth = packet.new DETH(tmpByte);
}
// RETH
if (packet.reth.isPresent()){
tmpLen = IBAPacket.RETH_SIZE / IBAPacket.BITS_PER_BYTE;
tmpByte = new byte[tmpLen];
for (int i=0; i < tmpLen; i++){
tmpByte[i] = bytestream.get();
bytesRead++;
}
packet.reth = packet.new RETH(tmpByte);
}
// AtomicETH
if (packet.atomicETH.isPresent()){
tmpLen = IBAPacket.ATOMIC_ETH_SIZE / IBAPacket.BITS_PER_BYTE;
tmpByte = new byte[tmpLen];
for (int i=0; i < tmpLen; i++){
tmpByte[i] = bytestream.get();
bytesRead++;
}
packet.atomicETH = packet.new AtomicETH(tmpByte);
}
// AETH
if (packet.aeth.isPresent()){
tmpLen = IBAPacket.AETH_SIZE / IBAPacket.BITS_PER_BYTE;
tmpByte = new byte[tmpLen];
for (int i=0; i < tmpLen; i++){
tmpByte[i] = bytestream.get();
bytesRead++;
}
packet.aeth = packet.new AETH(tmpByte);
}
// AtomicAckETH
if (packet.atomicAckETH.isPresent()){
tmpLen = IBAPacket.ATOMIC_ACK_ETH_SIZE /
IBAPacket.BITS_PER_BYTE;
tmpByte = new byte[tmpLen];
for (int i=0; i < tmpLen; i++){
tmpByte[i] = bytestream.get();
bytesRead++;
177
}
packet.atomicAckETH = packet.new AtomicAckETH(tmpByte);
}
// ImmDt
if (packet.immDt.isPresent()){
tmpLen = IBAPacket.IMM_DT_SIZE / IBAPacket.BITS_PER_BYTE;
tmpByte = new byte[tmpLen];
for (int i=0; i < tmpLen; i++){
tmpByte[i] = bytestream.get();
bytesRead++;
}
packet.immDt = packet.new ImmDt(tmpByte);
}
// PYLD
if (packet.pyld.isPresent()){
tmpLen = packet.getSize()
- bytesRead
- ( (IBAPacket.ICRC_SIZE + IBAPacket.VCRC_SIZE) /
IBAPacket.BITS_PER_BYTE);
tmpByte = new byte[tmpLen];
for (int i=0; i < tmpLen; i++){
tmpByte[i] = bytestream.get();
bytesRead++;
}
packet.pyld = packet.new PYLD(tmpByte);
}
// ICRC
if (packet.icrc.isPresent()){
tmpLen = IBAPacket.ICRC_SIZE / IBAPacket.BITS_PER_BYTE;
tmpByte = new byte[tmpLen];
for (int i=0; i < tmpLen; i++){
tmpByte[i] = bytestream.get();
bytesRead++;
}
packet.icrc = packet.new ICRC(tmpByte);
}
// VCRC
if (packet.vcrc.isPresent()){
tmpLen = IBAPacket.VCRC_SIZE / IBAPacket.BITS_PER_BYTE;
tmpByte = new byte[tmpLen];
for (int i=0; i < tmpLen; i++){
tmpByte[i] = bytestream.get();
bytesRead++;
}
packet.vcrc = packet.new VCRC(tmpByte);
}
return true;
}
/** Specicies the number of bytes read of the current packet. */
protected static int bytesRead = 0;
/**
* Used to avoid creating lots of useless IBAPacket objects in
* getNextHeader()
178
*/
protected static final IBAPacket dummyPacket = new IBAPacket();
}
179
no.uio.ifi.gruns.infiniband.IBAStatistics
package no.uio.ifi.gruns.infiniband;
import no.uio.ifi.gruns.*;
import java.util.HashMap;
import java.util.Iterator;
public class IBAStatistics {
/**
* Indicates when the transient period is over,
* so we should start gathering data.
*/
protected static int transientThreshold;
/**
* Indicates that the transient period is over
*/
protected static boolean transientPeriod;
public static HashMap droppedPackets;
public static HashMap drainNodes;
public static HashMap switchPriorities;
public static Kernel kernel;
static{
droppedPackets = new HashMap();
drainNodes = new HashMap();
switchPriorities = new HashMap();
transientThreshold = Integer.getInteger("infiniband.TRANSIENT_PERIOD", 0).intValue();
transientPeriod = true;
}
/**
* Sets the kernel. Needed to check if the transient period is
* over.
*/
public static void setKernel(Kernel k){
kernel = k;
}
public static void reportDroppedPacket(IBASourceNode node){
int numPackets = 0;
if (droppedPackets.containsKey(node)){
numPackets = ((Integer) droppedPackets.get(node)).intValue();
}
numPackets++;
droppedPackets.put(node, new Integer(numPackets));
}
public static HashMap getDroppedPacketStats(){
return droppedPackets;
}
public static int getDroppedPacketStats(IBASourceNode node){
if (droppedPackets.containsKey(node)){
return ((Integer)droppedPackets.get(node)).intValue();
}
return 0;
}
180
public static void reportReceivedPacket(IBADrainNode node,
int portNumber, int VLNumber,
IBAPacket.LRH lrh, int numBytes){
IBADrainNodeStats stats;
if (transientPeriod) {
if (kernel.currentTime() > transientThreshold) {
transientPeriod = false;
}
}else {
if (drainNodes.containsKey(node)){
stats = (IBADrainNodeStats) drainNodes.get(node);
}else{
stats = new IBADrainNodeStats(node);
drainNodes.put(node, stats);
}
stats.increaseReceivedPackets(lrh, portNumber, VLNumber);
stats.increaseReceivedBytes(portNumber, VLNumber, numBytes);
drainNodes.put(node, stats);
}
}
public static IBADrainNodeStats getReceivedPacketStats(IBADrainNode node){
return (IBADrainNodeStats) drainNodes.get(node);
}
public static void reportPriorities(IBAOutputPort ibao, int hiPri, int loPri){
Double prevAvgObj;
double prevAvg = 0;
double newAvg;
if (transientPeriod) {
if (kernel.currentTime() > transientThreshold) {
transientPeriod = false;
}
}else {
if (switchPriorities.containsKey(ibao)){
prevAvgObj = (Double) switchPriorities.get(ibao);
prevAvg = prevAvgObj.doubleValue();
}
if (loPri > 0){
newAvg = ((double)hiPri) / loPri;
}
else {
newAvg = -42.0;
}
// Better not to keep the old avg., because
// The errors in the beginning affects the overall avg.
// switchPriorities.put(ibao, new Double((prevAvg + newAvg) / 2));
switchPriorities.put(ibao, new Double(newAvg));
}
}
public static double getPriorities(IBAOutputPort ibao){
double retVal = -43; // No stats
if (switchPriorities.containsKey(ibao)){
retVal = ((Double) switchPriorities.get(ibao)).doubleValue();
}
181
return retVal;
}
public static double getAverageHiPriRatio(){
double retVal = 0;
Iterator it = switchPriorities.values().iterator();
while (it.hasNext()){
retVal += ((Double)it.next()).doubleValue();
}
retVal /= switchPriorities.size();
return retVal;
}
public static class IBADrainNodeStats{
public IBADrainNodeStats(IBADrainNode node){
totalNumberOfPacketsReceived =
new int[node.getNumberOfInputPorts()][node.getNumberOfVLs()];
totalNumberOfBytesReceived =
new int[node.getNumberOfInputPorts()][node.getNumberOfVLs()];
packetsReceivedFromEachSourceNode = new HashMap();
packetsReceivedOnEachSL = new int[Integer.
parseInt(System.
getProperty("infiniband.MAX_NUMBER_OF_VLS"))];
}
public int getTotalNumberOfReceivedPackets(){
int total = 0;
for (int i=0; i < totalNumberOfPacketsReceived.length; i++){
for (int j = 0; j < totalNumberOfPacketsReceived[i].length; j++){
total += totalNumberOfPacketsReceived[i][j];
}
}
return total;
}
public int getTotalNumberOfReceivedBytes(){
int total = 0;
for (int i=0; i < totalNumberOfBytesReceived.length; i++){
for (int j = 0; j < totalNumberOfBytesReceived[i].length; j++){
total += totalNumberOfBytesReceived[i][j];
}
}
return total;
}
public HashMap getPacketsReceivedPerSource(){
return packetsReceivedFromEachSourceNode;
}
private void increaseReceivedPackets(IBAPacket.LRH lrh,
int portNumber,
int VLNumber){
int numPkts=0;
String SLID = ""+new Address(lrh.SLID());
// per-source stats
if (packetsReceivedFromEachSourceNode.
containsKey(SLID)){
numPkts = ((Integer)
packetsReceivedFromEachSourceNode.
remove(SLID)).
intValue();
}
packetsReceivedFromEachSourceNode.
put(SLID,
182
new Integer(numPkts + 1));
// per-(port,VL)-stats
totalNumberOfPacketsReceived[portNumber][VLNumber]++;
// per-SL-stats
packetsReceivedOnEachSL[lrh.SL()]++;
}
public void increaseReceivedBytes(int portNumber,
int VLNumber,
int numBytes){
totalNumberOfBytesReceived[portNumber][VLNumber]+=numBytes;
}
/** The total number of received packets per VL per input port */
private int [][] totalNumberOfPacketsReceived;
/** The total number of received bytes per input VL */
private int [][] totalNumberOfBytesReceived;
/** The total number of packets received from each source node. */
private HashMap packetsReceivedFromEachSourceNode;
/** The total number of packets received on each service level */
private int[] packetsReceivedOnEachSL;
}
}
183
no.uio.ifi.gruns.infiniband.IBAOutputPort
package no.uio.ifi.gruns.infiniband;
import no.uio.ifi.gruns.*;
/**
* The output ports on IBA units
*/
public class IBAOutputPort extends OutputPort{
/**
* @param numberOfVirtualLanes The number of virtual lanes
* @param bufferSize The size of the output buffers
* @param kernel The kernel to use for simulation
*/
public IBAOutputPort(int numberOfVirtualLanes, int bufferSize, Kernel kernel) {
super(kernel);
this.numberOfVLs = numberOfVirtualLanes;
this.bufferSize = bufferSize;
init();
}
/**
* Uses bufferSize = 16 * Integer.parseInt
*
(System.getProperty("infiniband.EXP_PACKET_SIZE"));
*
* @param numberOfVirtualLanes The number of virtual lanes
* @param kernel The kernel to use for simulation
*/
public IBAOutputPort(int numberOfVirtualLanes, Kernel kernel){
super(kernel);
this.numberOfVLs = numberOfVirtualLanes;
// Do this initialization here instead of superclass
// to control the size of the buffers
//
bufferSize = 4 * IBAPacket.MAX_SIZE;
// Room for 16 packets on each outgoing buffer
bufferSize = 4*
Integer.parseInt(System.getProperty("infiniband.REAL_PACKET_SIZE"));
// Just to keep track of things
System.setProperty("infiniband.OUTPUT_PORT_BUFSIZE",
init();
}
/**
* Common initialization
*/
protected void init(){
this.buffer = new ByteBuffer[numberOfVLs];
this.VLstates = new VLstate[numberOfVLs];
for (int i=0; i < numberOfVLs; i++){
buffer[i] = new ByteBuffer(bufferSize);
VLstates[i] = new VLstate();
}
// Default "uninitialized" value
"";
ID =
bytesTransferred = 0;
184
""+bufferSize);
highPriority = new ListEntry[64];
lowPriority = new ListEntry[64];
//
//
//
//
Default to no limit on how many packets
to send on high priority before the low
priority queue get a shot.
Means the low priority queue could starve.
limitOfHighPriority = 255;
sendingLRHs = new IBAPacket.LRH[numberOfVLs];
FCTBS = new int [numberOfVLs];
sendingState = READY;
lrhIsSent = false;
transientThreshold = Integer.getInteger("infiniband.TRANSIENT_PERIOD", 0).intValue();
transientPeriod = true;
totalNumberOfPacketsSent=0;
}
/**
* Sends a single packet on the supplied virtual lane number.
* Called from the source to send a packet. Buffers the packet
* on this outgoing port.
*/
public void sendIBAPacket(IBAPacket p, int VLNumber)
throws NotClearToSendException{
byte[] content = p.getContent();
int i;
for (i = 0;
i < content.length && !buffer[VLNumber].isFull();
i++){
buffer[VLNumber].put(content[i]);
}
// Error message if error sending packet
if (i < p.getSize()){
Reporter.error("IBAOutputPort.sendIBAPacket("+p+
", "+VLNumber+"): "+
"Not enough buffer space left!");
Reporter.error("\n");
}
}
/**
* Sends a single byte on the supplied virtual lane number
*/
public void sendByte(byte b, int VLNumber)
throws NotClearToSendException{
// Update the state information
VLstates[VLNumber].numberOfBytesReceived++;
switch(VLstates[VLNumber].state){
case(VLstate.READY):
throw new NotClearToSendException("Not Clear to send! "+
"Status = VLstate.READY.");
case(VLstate.CLEAR_TO_SEND):
185
VLstates[VLNumber].state = VLstate.RECEIVING_HEAD;
// fallthrough
case(VLstate.RECEIVING_HEAD):
buffer[VLNumber].put(b);
// put the lrh in a separate array
int index = VLstates[VLNumber].
numberOfBytesReceived - 1;
VLstates[VLNumber].lrh[index] = b;
if (VLstates[VLNumber].numberOfBytesReceived ==
IBAPacket.LRH_SIZE / IBAPacket.BITS_PER_BYTE){
VLstates[VLNumber].state =
VLstate.RECEIVING_PACKET;
}
break;
case(VLstate.RECEIVING_PACKET):
buffer[VLNumber].put(b);
// Check if we have read the whole packet
if (VLstates[VLNumber].numberOfBytesReceived ==
IBAPacketParser.
packetLength(VLstates[VLNumber].lrh)){
VLstates[VLNumber].reset();
}
break;
default:
Reporter.error("IBAOutputPort
\""+ID+
"\".sendByte: Illegal state: "+
VLstates[VLNumber].state);
}
}
/**
* For logging purposes. Reports the total number of packets
* sent from this output port on each virtual lane.
* @param vl The virtual lane to get info on
*/
public int getTotalNumberOfPacketsSent(int vl){
return VLstates[vl].totalNumberOfPacketsSent;
}
/**
* Reports the total number of packets sent all in all
* on this output port.
*/
public int getTotalNumberOfPacketsSent(){
return this.totalNumberOfPacketsSent;
}
/**
* Sends a number of bytes from the supplied VL out on the link
*/
protected void sendBytes(int VLNumber, int numBytes){
int i;
for (i=0; i < numBytes; i++){
// Check for internal errors
if (buffer[VLNumber].isEmpty()){
Reporter.error("IBAOutputPort.sendBytes: "+
"Buffer is empty! Trying to send "+
numBytes+", sent "+i+".");
}
186
link.sendByte(buffer[VLNumber].get());
}
}
/**
* Sends a block from the current packet on the link
*/
protected void sendBlockFromCurrent(){
// To avoid scheduling the sink without having put data on it,
// we record how many bytes we have sent.
int bytesSentThisTurn = 0;
// Sizes of the packet with and without lrh
int packetSize = IBAPacketParser.
packetLength(sendingLRHs[current.VLNumber]);
int contentSize = packetSize (IBAPacket.LRH_SIZE / IBAPacket.BITS_PER_BYTE);
int lrhSize = (IBAPacket.LRH_SIZE / IBAPacket.BITS_PER_BYTE);
// Send header and a smaller block if header is not sent
if (!lrhIsSent){
// send header
for (int i=0; i < lrhSize ; i++, bytesTransferred++){
link.sendByte(sendingLRHs[current.VLNumber].content[i]);
// To avoid scheduling the sink without having
// put data on it.
bytesSentThisTurn++;
}
// Update the bytes in transit on the input port receiving.
((IBAInputPort) link.getSink()).
increaseBytesSent(lrhSize, current.VLNumber);
// Send a (Integer.parseInt(System.getProperty(
// "infiniband.BLOCK_SIZE")) - sendingLRHsize)// byte block of the packet on the link.
int numBytes = Math.min((Integer.parseInt(
System.getProperty("infiniband.BLOCK_SIZE")) - lrhSize),
packetSize - bytesTransferred);
sendBytes(current.VLNumber, numBytes);
bytesTransferred+=numBytes;
// To avoid scheduling the sink without having
// put data on it.
bytesSentThisTurn+=numBytes;
// Update the bytes in transit on the input port
// receiving.
((IBAInputPort) link.getSink()).
increaseBytesSent(numBytes, current.VLNumber);
lrhIsSent = true;
}
// Send a block of the packet itself
else{
// Send a Integer.parseInt(System.getProperty(
// "infiniband.BLOCK_SIZE"))-byte block
// of the packet on the link.
int numBytes = Math.min(Integer.parseInt(
System.getProperty("infiniband.BLOCK_SIZE")),
packetSize - bytesTransferred);
/*
// DEBUG
Reporter.debugln(ID+
": IBAOutputPort.sendBlockFromCurrent: packetSize = "+packetSize);
Reporter.debugln(ID+
187
": IBAOutputPort.sendBlockFromCurrent: bytesTransferred = "+
bytesTransferred);
//
*/
sendBytes(current.VLNumber, numBytes);
bytesTransferred+=numBytes;
// To avoid scheduling the sink without having
// put data on it.
bytesSentThisTurn+=numBytes;
// Update the bytes in transit on the input
// port receiving.
((IBAInputPort) link.getSink()).
increaseBytesSent(numBytes,current.VLNumber);
}
// Update the FCTBS for the current VL
FCTBS[current.VLNumber]++;
// Update the number of units sent on the current VL
unitsSentOnCurrentVL++;
// Update the number of units sent on high priority
// if we are sending from high priority
if (active == highPriority){
bytesSentOnHighPriority += bytesSentThisTurn;
}
// Schedule the link since we have put data on it
if (bytesSentThisTurn !=0){
link.addBlock(bytesSentThisTurn);
kernel.schedule(link, kernel.currentTime() + 1);
}
}
/**
* Indicates whether it is possible to send a packet according
* to the list entry supplied. Returns true if one of the
* following criteria is true:
*<UL>
* <LI><tt>entry.</LI
*</UL>
*/
protected boolean allowedToSendFrom(ListEntry entry, int unitsSentOnVL){
boolean enoughCreditsAvailable = false;
//
//
//
//
//
//
//
//
//
//
if
Check if we can send data, i.e. if there are enough credits
available on the receiving side.
FCTBS = Flow Control Total Blocks Sent
FCCL = Flow Control Credit Limit
CR = Total blocks sent since link initialization plus
the number of blocks in the data packet to be transmitted,
all modulo 4096.
CL = The last FCCL received in a flow control packet
Exception for VL 15, which should always be sent.
(entry==null || buffer[entry.VLNumber].isEmpty()){
enoughCreditsAvailable = false;
}
else if (entry.VLNumber == 15){
enoughCreditsAvailable = true;
}
else{
// Read the lrh for this output buffer if it’s not
188
// already read
if (sendingLRHs[entry.VLNumber] == null){
sendingLRHs[entry.VLNumber] =
IBAPacketParser.getNextHeader(buffer[entry.VLNumber]);
}
int CL = ((IBAInputPort) link.getSink()).
getFCCL(FCTBS[entry.VLNumber], entry.VLNumber);
int CR = (FCTBS[entry.VLNumber] +
(int) Math.ceil( IBAPacketParser.
packetLength(sendingLRHs[entry.
VLNumber])
/ Integer.parseInt(System.getProperty("infiniband.BLOCK_SIZE"))))
% 4096;
//
//
//
//
//
enoughCreditsAvailable = ((CL - CR) % 4096 <= 2048);
Must & the result with 0xfff to simulate a real
12 bit number, not just modulo 4096 on a 32-bit
integer. The bits should always be interpreted as a
number between 0 and 4095.
enoughCreditsAvailable = ( (((CL - CR) % 4096) & 0xFFF) <=
2048);
}
return (entry.weight - unitsSentOnVL > 0 &&
!buffer[entry.VLNumber].isEmpty() &&
enoughCreditsAvailable);
}
protected ListEntry findNextListEntry(ListEntry[] queue, int current){
ListEntry le;
int i;
boolean found = false;
// Check if we can continue sending on the
// same VL, if not, reset the unitsSentOnCurrentVL.
if (queue[current] != null && allowedToSendFrom(queue[current],
unitsSentOnCurrentVL)){
return queue[current];
}
// Loop through the list entries and find one
// to send from.
i = current + 1;
for (int j=0; j < queue.length; j++){
le = queue[i];
if (le != null && allowedToSendFrom(le, 0)){
found = true;
break;
}
i = (i+1) % queue.length;
}
if (found){
if (queue == highPriority){
currentHighPriority = i;
}else if (queue == lowPriority){
currentLowPriority = i;
}else{ // sanity check
Reporter.error("IBAOutputPort.findNextListEntry:
}
unitsSentOnCurrentVL = 0;
return (queue[i]);
}else{
return null;
}
189
Unknown queue supplied!");
}
/**
* Updates which VL we should send from, makes all decisions about
* if the limit of high priority has run out, if we are allowed to
* send from a particular VL etc. Called from act().
*/
protected void updateCurrent(){
ListEntry le;
// Reset sendingStates
lrhIsSent = false;
bytesTransferred = 0;
// Check if we have exceeded the limit of high priority
// packets. If we have, check the low priority queue first.
if (
// limit == 255 means no limit
limitOfHighPriority < 255
&&
(
// limit == 0 means we could send one packet.
(limitOfHighPriority == 0 &&
bytesSentOnHighPriority > (limitOfHighPriority * 4096))
||
(limitOfHighPriority > 0 &&
bytesSentOnHighPriority >= (limitOfHighPriority * 4096))
)
)
{
bytesSentOnHighPriority = 0;
le = findNextListEntry(lowPriority, currentLowPriority);
if (le != null){ // Packets to send on Low Priority
active = lowPriority;
sendingState = SENDING;
}else{
le = findNextListEntry(highPriority, currentHighPriority);
if (le != null){// Packets to send on High Priority
active = highPriority;
sendingState = SENDING;
}
}
}
// If not, check the high priority first (usual case)
else{
// Find next to send from
le = findNextListEntry(highPriority, currentHighPriority);
if (le != null){// Packets to send on High Priority
active = highPriority;
sendingState = SENDING;
}
else { // No packets to send on High Priority
bytesSentOnHighPriority = 0;
le = findNextListEntry(lowPriority, currentLowPriority);
if (le != null){ // Packets to send on Low Priority
active = lowPriority;
bytesSentOnHighPriority = 0;
sendingState = SENDING;
}
}
}
// Update the current list entry.
this.current = le;
190
// Finished if nothing to send
if (current == null){
// Reschedule if we still have data to send
// but are not able to send right now
for (int i=0; i < numberOfVLs; i++){
if (!buffer[i].isEmpty()){
kernel.schedule(this, kernel.currentTime() + 1);
break;
}
}
}else{
// Send one block of data
sending();
}
/*
// DEBUG
//if (ID.startsWith("Switch 0")
//|| ID.startsWith("Switch 6")
//|| ID.startsWith("Switch 7")
//) {
System.out.println("Time: "+kernel.currentTime()+", "
+ID+": Selected VL "+current.VLNumber+". "+
"VL 1’s buffer is "+
(buffer[1].isEmpty()?"":"NOT ")+
"empty."
);
//}
//
*/
}
/**
* Sends a block from the current VL and checks if we are finished sending
* the current packet. Reschedules if we are noe finished.
*/
protected void sending(){
// TODO: Small problem: When we are scheduled, and
// have already read all the bytes in the packet, we should
// start on the next packet, as of now, we only reset the state,
// and don’t transfer any bytes.
//
// Shouldn’t happen, really, because when we have finished reading
// all bytes, the state is reset, and we proceed to the next packet. Maybe
// it’s not happening. Find out!
sendBlockFromCurrent();
// Reschedule if not finished with current packet
if (bytesTransferred <
IBAPacketParser.packetLength(sendingLRHs[current.
VLNumber])){
kernel.schedule(this, kernel.currentTime() + 1);
}
// Clear the lrh from this VL if we are finished
// sending from it. Reset other parameters
else if (bytesTransferred ==
IBAPacketParser.packetLength(sendingLRHs[current.
VLNumber])){
sendingLRHs[current.VLNumber] = null;
191
sendingState = READY;
// Logging
if (transientPeriod) {
if (kernel.currentTime() > transientThreshold) {
transientPeriod = false;
}
}else {
totalNumberOfPacketsSent++;
VLstates[current.VLNumber].totalNumberOfPacketsSent++;
int totLo=0, totHi=0;
double ratio;
for (int i=0; i < lowPriority.length; i++){
if (lowPriority[i] != null){
totLo += VLstates[lowPriority[i].VLNumber].totalNumberOfPacketsSent;
}
}
for (int i=0; i < highPriority.length; i++){
if (highPriority[i] != null){
totHi += VLstates[highPriority[i].VLNumber].totalNumberOfPacketsSent;
}
}
IBAStatistics.reportPriorities(this, totHi, totLo);
ratio = IBAStatistics.getPriorities(this);
}
// Reschedule if we still have data to send
// but are not able to send right now
for (int i=0; i < numberOfVLs; i++){
if (!buffer[i].isEmpty()){
kernel.schedule(this, kernel.currentTime() + 1);
break;
}
}
}
// Sanity check
else if (bytesTransferred >
IBAPacketParser.packetLength(sendingLRHs[current.
VLNumber])){
Reporter.error("IBAOutputPort.act: Too many bytes sent!
bytesTransferred +" > "
+ IBAPacketParser.
packetLength(sendingLRHs[current.
VLNumber])+".");
"+
}
// Insanity check ;)
else{
throw new java.lang.RuntimeException("Serious error! "+
"Should be "+
"impossible!");
}
}
/**
* Keeps track of the limit of high priority, finds the next VL to send from
* and sends one block of data on that VL.
*/
public void act(){
switch(sendingState){
192
case READY:
// Update which VL we should send from
updateCurrent();
break;
case SENDING:
// Send a block of data and check if we are finished, etc.
sending();
break;
default:
Reporter.error("IBAOutputPort.act:
Invalid sendingState: "+sendingState);
}
}
/**
* Indicates whether this output port has any data to send
* on a given virtual lane.
*/
public boolean dataOnVL(int VLNumber){
return !buffer[VLNumber].isEmpty();
}
/**
* Returns the status of the VL number supplied.
* One of the following:
* <ul>
* <li>VLstate.READY</li>
* <li>VLstate.RECEIVING_HEAD</li>
* <li>VLstate.RECEIVING_PACKET</li>
* </ul>
*/
public int getStatus(int VLNumber){
return VLstates[VLNumber].state;
}
/**
* Occupies the supplied VLNumber,
* i.e. tells others that we are currently transferring on this VL.
*/
public void occupy(int VLNumber){
VLstates[VLNumber].state = VLstate.CLEAR_TO_SEND;
}
/**
* Indicates whether the supplied VL is occupied
*/
public boolean occupied(int VLNumber){
return VLstates[VLNumber].state != VLstate.READY;
}
/**
* Releases the supplied VLNumber,
* i.e. tells others that we are not transferring on this VL anymore.
*/
public void release(int VLNumber){
VLstates[VLNumber].state = VLstate.READY;
}
/**
* Indicates to a unit that wants to send on this output port
193
* if we are able to send that number of bytes.
* It returns whether we have the available buffer space to
* accept the bytes, not if the unit in the other end has enough
* room to receive them.
* Returns false if there’s another packet currently coming in on
* this VL.
*/
public boolean canSend(int VLNumber, int numberOfBytes){
boolean retVal = ((buffer[VLNumber].getCapacity() buffer[VLNumber].getSize()) >=
numberOfBytes)
&& !occupied(VLNumber);
return retVal;
}
/**
* Returns the remaining buffer capacity on the supplied VL number
*/
public int remainingBufferCapacity(int VLNumber){
return (buffer[VLNumber].getCapacity() buffer[VLNumber].getSize());
}
/**
* Used to add a high or low priority entry.
* @param queue Either @link{#highPriority# or @link{#lowPriority}
* For more info, see @link{#addHighPriority} and @link{#addLowPriority}.
*/
protected void addEntry(int VLNumber, int weight, ListEntry[] queue){
ListEntry le;
int i=0;
for (i=0; i < queue.length; i++){
if (queue[i] == null){
le = new ListEntry();
le.VLNumber = VLNumber;
le.weight = weight;
queue[i] = le;
break;
}
}
// Error if no vacant slots
if (i == queue.length){
Reporter.error("IBAOutputPort.addEntry("+
VLNumber+", "+weight+"): "+
"No vacant slots.");
}
}
/**
* Sets the high priority queue of this output port
*/
public void setHighPriotity(ListEntry[] queue){
this.highPriority = queue;
}
/**
* Sets the number of units we can send from high priority
* before letting a unit from low priority send.
*/
public void setLimitOfHighPriority(int limit){
limitOfHighPriority = limit;
}
194
/**
* Adds an entry of high priority on this output port.
* @param VLNumber The Virtual lane to add an entry for
* @param weight The number of
* Integer.parseInt(System.getProperty("infiniband.BLOCK_SIZE"))-byte
* units this VL should be allowed to transfer on each turn
*
*/
public void addHighPriority(int VLNumber, int weight){
addEntry(VLNumber, weight, highPriority);
}
/**
* Sets the low priority queue of this output port
*/
public void setLowPriotity(ListEntry[] queue){
this.lowPriority = queue;
}
/**
* Adds an entry of low priority on this output port.
* @param VLNumber The Virtual lane to add an entry for
* @param weight The number of
* Integer.parseInt(System.getProperty("infiniband.BLOCK_SIZE"))byte
* units this VL should be allowed to transfer on each turn
*
*/
public void addLowPriority(int VLNumber, int weight){
addEntry(VLNumber, weight, lowPriority);
}
/**
* Gets the sink of this output port
*/
public Unit getSink(){
return link.getSink();
}
public String report(){
return "IBAOutputPort "
+ID
+", sending on VL "+
((current==null?"none": ""+current.VLNumber)+
", "+buffer[0].getSize()+" in buffer[0]"+
", "+bytesTransferred+" bytes transferred."
);
}
/**
* Number of bytes successfully transferred from the current packet
*/
protected int bytesTransferred;
/** The current VL entry to transfer from */
protected ListEntry current;
/**
* The number of
* Integer.parseInt(System.getProperty("infiniband.BLOCK_SIZE"))-byte
* units sent on the current VL in this turn.
*/
195
protected int unitsSentOnCurrentVL;
/**
* The limit of high-priority packets that can be sent before the
* low-priority packets get to send some. 4K times this number bytes
* can be sent before the low-priority can send.
* <ul>
* <li>A value of 255 indicates that the limit is unbounded.</li>
* <li>A value of 0 indicates that only a single packet
*
from hi-pri can be sent.</li>
* </ul>
*/
protected int limitOfHighPriority;
/** The number of bytes sent on high priority */
protected int bytesSentOnHighPriority;
/**
* The Flow Control Total Blocks Sent.
* Indicates how many blocks that are sent
* on each VL since link initialization.
*
*/
protected int FCTBS[];
/** The list entries of the high priority packets. */
protected ListEntry[] highPriority;
/** The list entries of the low priority packets. */
protected ListEntry[] lowPriority;
/**
* The currently active priority
* (equals either high or low priority).
*/
protected ListEntry[] active;
/**
* The lrhs of all the buffers where we have read the
* lrh in order to find out if there’s enough room to
* send the packet out on the link.
*/
protected IBAPacket.LRH[] sendingLRHs;
/** The number of the current high priority entry */
protected int currentHighPriority;
/** The number of the current low priority entry */
protected int currentLowPriority;
/**
* Holds the current state of the IBAOutputPort,
* in respect to the act() method, i.e.
* the output from the output port, <b>not</b> if we can send <i>to</i>
* the outout port.
* Is either READY or SENDING.
*/
protected int sendingState;
protected final int READY = 0;
protected final int SENDING = 1;
/**
* Indicates whether we have sent the lrh of the
* packet we are currently sending (in <b>act</b>)
*/
196
protected boolean lrhIsSent;
/**
* For logging and debugging
*/
public int totalNumberOfPacketsSent;
/**
* Indicates when the transient period is over,
* so we should start gathering data.
*/
protected int transientThreshold;
/**
* Indicates that the transient period is over
*/
protected boolean transientPeriod;
/**
* The state of all the input VLs
*/
protected VLstate[] VLstates;
public class VLstate{
public int state;
public byte[] lrh;
public int numberOfBytesReceived;
// For logging
public int totalNumberOfPacketsSent = 0;
//
protected VLstate(){
init();
}
protected void init(){
state = READY;
lrh = new byte[IBAPacket.LRH_SIZE / IBAPacket.BITS_PER_BYTE];
numberOfBytesReceived = 0;
}
protected void reset(){
init();
}
public
public
public
public
static
static
static
static
final
final
final
final
int
int
int
int
READY
CLEAR_TO_SEND
RECEIVING_HEAD
RECEIVING_PACKET
=
=
=
=
0;
1;
2;
3;
}
public class ListEntry{
/** The number of the virtual lane. */
public int VLNumber;
/**
* The number of
* Integer.parseInt(System.getProperty("infiniband.BLOCK_SIZE"))-byte
* units allowed to transfer from the VL.
*/
public int weight;
}
197
}
198
no.uio.ifi.gruns.infiniband.IBARoutingTable
package no.uio.ifi.gruns.infiniband;
import no.uio.ifi.gruns.*;
public class IBARoutingTable extends RoutingTable{
/**
* Adds a possible output route for the supplied address.
* Since the virtual lane is specified in the packet in
* IBA, this information shouldn’t be part of the route.
* @param a The address to add the route for
* @param outgoingPortNumber The output port to send the packets on
*/
public void addRoute(Address a, int outgoingPortNumber){
super.addRoute(a, outgoingPortNumber, -1);
}
/**
* Deletes a possible output route for the supplied address
* Since the virtual lane is specified in the packet in
* IBA, this information shouldn’t be part of the route.
* @param a The address to delete a route for
* @param outgoingPortNumber The port number of the route
*/
public void deleteRoute(Address a, int outgoingPortNumber){
super.deleteRoute(a, outgoingPortNumber, -1);
}
/**
* Looks up the next hop for the supplied header
*/
public Route lookUp(IBAPacket.LRH lrh){
Route retVal = super.lookUp(new Address(lrh.DLID()));
if (retVal != null){
retVal.VLNumber = lrh.VL();
}
// If we just return retVal, for some reason
// this method returns exactly the _same_ object each time,
// and of course this is not what is desired. If we then
// look up another packet, the previous packets will
// get the same output route.
Route retVal2 = new Route();
retVal2.portNumber = retVal.portNumber;
retVal2.VLNumber = retVal.VLNumber;
return retVal2;
}
public String report(){
return "no.uio.ifi.gruns.infiniband.IBARoutingTable";
}
}
199
no.uio.ifi.gruns.infiniband.IBAUnitComparator
package no.uio.ifi.gruns.infiniband;
import no.uio.ifi.gruns.*;
import no.uio.ifi.tools.*;
import java.util.Comparator;
public class IBAUnitComparator implements Comparator
public int compare(Object o1, Object o2)
{
{
int compVal=0;
/*
if (! (o1.getClass().getName().startsWith("IBA") &&
o2.getClass().getName().startsWith("IBA")) ) {
throw new ClassCastException("Can only compare IBA units!!");
}
*/
String[] s = {(String) o1, (String) o2};
int
int
int
int
int
addrPrefixPos[] = new int[2];
pointPos[] = new int[2];
addrSuffixEnd[] = new int[2];
addrPrefix[] = new int[2];
addrSuffix[] = new int[2];
for
(int i = 0; i < 2; i++) {
// Find position of first digit
for (addrPrefixPos[i]=0; addrPrefixPos[i] < s[i].length(); addrPrefixPos[i]++)
if (Character.isDigit(s[i].charAt(addrPrefixPos[i]))) break;
{
}
// Find position of ".".
for (pointPos[i]=addrPrefixPos[i]; pointPos[i] <
if (s[i].charAt(pointPos[i]) == ’.’) break;
s[i].length(); pointPos[i]++) {
}
// Find last digit after ".".
for (addrSuffixEnd[i] = pointPos[i]+1; addrSuffixEnd[i] < s[i].length();
if (!Character.isDigit(s[i].charAt(addrSuffixEnd[i]))) break;
addrSuffixEnd[i]++) {
}
/*
System.err.println("s = \""+s[i]+"\"");
System.err.println("prefixpos = "+addrPrefixPos[i]+", pointpos = "+pointPos[i]+
", addrSuffixEnd = "+addrSuffixEnd[i]);
*/
addrPrefix[i] = Integer.parseInt(s[i].substring(addrPrefixPos[i], pointPos[i]));
addrSuffix[i] = Integer.parseInt(s[i].substring(pointPos[i]+1, addrSuffixEnd[i]));
//System.err.println("Prefix = "+addrPrefix[i]+", suffix = "+addrSuffix[i]);
}
if
}
(addrPrefix[0] < addrPrefix[1]) {
compVal = -1;
else if (addrPrefix[0] == addrPrefix[1])
if (addrSuffix[0] < addrSuffix[1]) {
{
compVal = -1;
}
else if
}
else
(addrSuffix[0] == addrSuffix[1]) {
compVal = 0;
{
200
compVal = 1;
}
}
else
return
compVal = 1;
compVal;
}
public boolean equals(Object obj)
return obj.equals(this);
{
}
}
201
no.uio.ifi.gruns.infiniband.IBAConnectionTools
package no.uio.ifi.gruns.infiniband;
import no.uio.ifi.gruns.*;
public class IBAConnectionTools{
// {{{ public static void setKernel(Kernel k)
/**
* Sets the kernel to use for the links.
*/
public static void setKernel(Kernel k){
kernel = k;
}
// }}}
// {{{ public static void connect(IBASourceNode s, int port, IBASwitch sw, int inputPort)
/**
* Connect a source node <tt>s</tt> on port <tt>port</tt>
* to a switch <tt>sw</tt> on inpurt port <tt>inputPort</tt>.
*/
public static void connect(IBASourceNode s, int port,
IBASwitch sw, int inputPort){
// {{{ DEBUG
/*
Reporter.debugln("Connecting source node "+s.getID()+", port "
+port+
" to switch "+sw.getID()+", input port "+inputPort);
*/
// }}}
Link tmpLink = new Link(kernel);
s.attach(tmpLink, port);
sw.attachInput(tmpLink, inputPort);
// Update the ID on the Link.
-> "+sw.getID()+")");
tmpLink.setID("("+s.getID()+"
}
// }}}
// {{{ public static void connect(IBASwitch sw1, int outputPort, IBASwitch sw2, int inputPort)
/**
* Connect a switch <tt>sw1</tt> on output port <tt>outputPort</tt>
* to another switch <tt>sw2</tt> on input port <tt>inputPort</tt>.
*/
public static void connect(IBASwitch sw1, int outputPort,
IBASwitch sw2, int inputPort){
// {{{ DEBUG
/*
Reporter.debugln("("+sw1.getID()+", "+outputPort+") -> ("+
sw2.getID()+", "+inputPort+")");
*/
// }}}
Link tmpLink = new Link(kernel);
sw1.attachOutput(tmpLink, outputPort);
sw2.attachInput(tmpLink, inputPort);
// Update the ID on the Link.
-> "+sw2.getID()+")");
tmpLink.setID("("+sw1.getID()+"
}
// }}}
202
// {{{ public static void connect(IBASwitch sw, int outputPort, IBADrainNode d, int port)
/**
* Connect a switch <tt>sw</tt> on output port <tt>outputPort</tt>
* to a drain node <tt>d</tt> on port <tt>port</tt>.
*/
public static void connect(IBASwitch sw, int outputPort,
IBADrainNode d, int port){
// {{{ DEBUG
/*
Reporter.debugln("Connecting switch "+sw.getID()+", outputPort "+outputPort+
" to drain node "+d.getID()+", port "+port);
*/
// }}}
Link tmpLink = new Link(kernel);
sw.attachOutput(tmpLink, outputPort);
d.attach(tmpLink, port);
// Update the ID on the Link.
-> "+d.getID()+")");
tmpLink.setID("("+sw.getID()+"
}
// }}}
// {{{ public static IBASwitch[] simplexGrid(int width, int height, int numberOfVLs)
public static IBASwitch[] simplexGrid(int width, int height, int numberOfVLs){
int numInputs = 3;
int numOutputs = 3;
int numVLs = numberOfVLs;
IBASwitch[] ibasw = new IBASwitch[width*height];
// Create all switches
for (int i=0; i < ibasw.length; i++){
ibasw[i] = new IBASwitch(numInputs, numOutputs, numVLs,
"Switch "+(i),kernel);
}
// Connect switches in grid
int current;
int rowOffset;
//////
// Special case: height == 1
//////
if (height == 1){
// All but last column
for (int i=0; i < width-1; i++){
current = i;
// east
connect(ibasw[current], 1,
ibasw[current + 1], 1);
}
// Last column
// no connections!"
}
else{
//////
// Top row
//////
203
if (height > 1){
// All but last column
for (int i=0; i < width-1; i++){
current = i;
// east
connect(ibasw[current], 1,
ibasw[current + 1], 1);
// south
connect(ibasw[current], 2,
ibasw[current + width], 0);
}
// Last column
current = width-1;
connect(ibasw[current], 2,
ibasw[current + width], 0);
}
//////
// Inner rows
//////
if (height > 2){
for (int j=1; j < height-1; j++){
rowOffset = width*j;
// All but last column
for (int i=0; i < width-1; i++){
current = i + rowOffset;
// north
connect(ibasw[current], 0,
ibasw[current - width], 2);
connect(ibasw[current], 2,
ibasw[current + width], 0);
// east
connect(ibasw[current], 1,
ibasw[current + 1], 1);
// south
connect(ibasw[current], 2,
ibasw[current + width], 0);
}
// Last column
current = width-1 + rowOffset;
// north
connect(ibasw[current], 0,
ibasw[current - width], 2);
// south
connect(ibasw[current], 2,
ibasw[current + width], 0);
}
}
//////
// Bottom row
//////
if (height > 1){
rowOffset = width * (height-1);
// All but last column
for (int i=0; i < width-1; i++){
current = i + rowOffset;
// north
connect(ibasw[current], 0,
ibasw[current - width], 2);
// east
connect(ibasw[current], 1,
ibasw[current + 1], 1);
}
// Last column
current = width-1 + rowOffset;
204
// north
connect(ibasw[current], 0,
ibasw[current - width], 2);
}
}
return ibasw;
}
// }}}
// {{{ public static IBASwitch[] simplexGrid(int width, int height, ..., bufferSize)
public static IBASwitch[] simplexGrid(int width, int height, int numberOfVLs,
int inputBufferSize, int outputBufferSize){
int numInputs = 3;
int numOutputs = 3;
int numVLs = numberOfVLs;
IBASwitch[] ibasw = new IBASwitch[width*height];
// Create all switches
for (int i=0; i < ibasw.length; i++){
ibasw[i] = new IBASwitch(numInputs, numOutputs, numVLs,
inputBufferSize, outputBufferSize,
"Switch "+(i),kernel);
}
// Connect switches in grid
int current;
int rowOffset;
//////
// Special case: height == 1
//////
if (height == 1){
// All but last column
for (int i=0; i < width-1; i++){
current = i;
// east
connect(ibasw[current], 1,
ibasw[current + 1], 1);
}
// Last column
// no connections!"
}
else{
//////
// Top row
//////
if (height > 1){
// All but last column
for (int i=0; i < width-1; i++){
current = i;
// east
connect(ibasw[current], 1,
ibasw[current + 1], 1);
// south
connect(ibasw[current], 2,
ibasw[current + width], 0);
}
// Last column
205
current = width-1;
connect(ibasw[current], 2,
ibasw[current + width], 0);
}
//////
// Inner rows
//////
if (height > 2){
for (int j=1; j < height-1; j++){
rowOffset = width*j;
// All but last column
for (int i=0; i < width-1; i++){
current = i + rowOffset;
// north
connect(ibasw[current], 0,
ibasw[current - width], 2);
connect(ibasw[current], 2,
ibasw[current + width], 0);
// east
connect(ibasw[current], 1,
ibasw[current + 1], 1);
// south
connect(ibasw[current], 2,
ibasw[current + width], 0);
}
// Last column
current = width-1 + rowOffset;
// north
connect(ibasw[current], 0,
ibasw[current - width], 2);
// south
connect(ibasw[current], 2,
ibasw[current + width], 0);
}
}
//////
// Bottom row
//////
if (height > 1){
rowOffset = width * (height-1);
// All but last column
for (int i=0; i < width-1; i++){
current = i + rowOffset;
// north
connect(ibasw[current], 0,
ibasw[current - width], 2);
// east
connect(ibasw[current], 1,
ibasw[current + 1], 1);
}
// Last column
current = width-1 + rowOffset;
// north
connect(ibasw[current], 0,
ibasw[current - width], 2);
}
}
return ibasw;
}
// }}}
206
// {{{ public static IBASwitch[] duplexGrid(int width, int height, int numberOfVLs)
/**
* Connects switches in a duplex grid, that is all links are bi-directional,
* there’s always an input port for every output port and vice versa.
*
* Switches look like this, with the input and output ports numbered
* as indicated below:
* <pre>
*
*
1 1
*
^ |
*
| v
*
+------+
* 0 ->|
|-> 2
*
|
|
* 0 <-|
|<- 2
*
+------+
*
| ^
*
v |
*
3 3
* </pre>
*/
public static IBASwitch[] duplexGrid(int width, int height, int numberOfVLs){
int numInputs = 4;
int numOutputs = 4;
int numVLs = numberOfVLs;
IBASwitch[] ibasw = new IBASwitch[width*height];
// Create all switches
for (int i=0; i < ibasw.length; i++){
ibasw[i] = new IBASwitch(numInputs, numOutputs, numVLs,
"Switch "+(i),kernel);
}
// Connect switches in grid
int current;
int rowOffset;
//////
// Special case: height == 1
//////
if (height == 1){
// First column
// only east
current = 0;
connect(ibasw[current], 2,
ibasw[current + 1], 0);
// All but first and last column
for (int i=1; i < width-1; i++){
current = i;
// east
connect(ibasw[current], 2,
ibasw[current + 1], 0);
// west
connect(ibasw[current], 0,
ibasw[current - 1], 2);
}
207
// Last column
// only west
current = width-1;
connect(ibasw[current], 0,
ibasw[current - 1], 2);
}
else{
//////
// Top row
//////
if (height > 1){
// First column
// only east and south
current = 0;
// east
connect(ibasw[current], 2,
ibasw[current + 1], 0);
// south
connect(ibasw[current], 3,
ibasw[current + width], 1);
// All but first and last column
for (int i=1; i < width-1; i++){
current = i;
// east
connect(ibasw[current], 2,
ibasw[current + 1], 0);
// west
connect(ibasw[current], 0,
ibasw[current - 1], 2);
// south
connect(ibasw[current], 3,
ibasw[current + width], 1);
}
// Last column
// only west and south
current = width-1;
// west
connect(ibasw[current], 0,
ibasw[current - 1], 2);
// south
connect(ibasw[current], 3,
ibasw[current + width], 1);
}
//////
// Inner rows
//////
if (height > 2){
for (int j=1; j < height-1; j++){
rowOffset = width*j;
// First column
current = 0 + rowOffset;
// north
connect(ibasw[current], 1,
ibasw[current - width], 3);
208
// east
connect(ibasw[current], 2,
ibasw[current + 1], 0);
// south
connect(ibasw[current], 3,
ibasw[current + width], 1);
// All but first and last column
for (int i=1; i < width-1; i++){
current = i + rowOffset;
// west
connect(ibasw[current], 0,
ibasw[current - 1], 2);
// north
connect(ibasw[current], 1,
ibasw[current - width], 3);
// east
connect(ibasw[current], 2,
ibasw[current + 1], 0);
// south
connect(ibasw[current], 3,
ibasw[current + width], 1);
}
// Last column
current = width-1 + rowOffset;
// west
connect(ibasw[current], 0,
ibasw[current - 1], 2);
// north
connect(ibasw[current], 1,
ibasw[current - width], 3);
// south
connect(ibasw[current], 3,
ibasw[current + width], 1);
}
}
//////
// Bottom row
//////
if (height > 1){
rowOffset = width * (height-1);
// First column
current = 0 + rowOffset;
// north
connect(ibasw[current], 1,
ibasw[current - width], 3);
// east
connect(ibasw[current], 2,
ibasw[current + 1], 0);
// All but first and last column
for (int i=1; i < width-1; i++){
current = i + rowOffset;
// west
connect(ibasw[current], 0,
ibasw[current - 1], 2);
// north
connect(ibasw[current], 1,
ibasw[current - width], 3);
// east
connect(ibasw[current], 2,
ibasw[current + 1], 0);
}
209
// Last column
current = width-1 + rowOffset;
// north
connect(ibasw[current], 1,
ibasw[current - width], 3);
// west
connect(ibasw[current], 0,
ibasw[current - 1], 2);
}
}
return ibasw;
}
// }}}
// {{{ public static void buildDefaultRoutingTable(IBASwitch[] coreIbaSw, IBAStiwch[] edgeIbaSw)
/**
*<p>
* Builds a default routing table in the net supplied. The edge switches should
* be connected to the core switches, and the core switches should be connected
* both ways, in a 2D mesh (grid). The routing that is set up, makes the switches
* first forward data vertically, then horizontally. This is to avoid routing loops.
*</p>
*<p>
* The core switches should be aligned from the top left corner of the mesh.
*</p>
*<p>
* The egde switches should be aligned around the core switches, starting at top left.
* In the corners, the edge routers should be connected to the top or bottom link of the core
* switches, not the left or right.
* The suffix of the addresses on the drain nodes should start at 0 on the top left,
* then increase by one as we move around the mesh.
*</p>
*<p>
*<b>A simple example with a 3x3 mesh:</b>
* <tt>Ex</tt> are edge switches, and <tt>Cx</tt> are core switches.
*<pre>
*
E0
E1
E2
*
|
|
|
*
*
C0
C1
C2
*
|
|
|
* E8 - C3 - C4 - C5 - E3
*
|
|
|
*
C6 - C7 - C8
*
*
|
|
|
*
E6
E5
E4
*
*/
public static void buildDefaultRoutingTable(IBASwitch[] coreIbaSw, IBASwitch[] edgeIbaSw,
int width, int height) {
// Constants to ease port number addressing
int WEST=0,NORTH=1,EAST=2,SOUTH=3;
// Build the routing table, starting from upper left.
// Core routers
210
// Find addresses of corners
Address topLeft, topRight, bottomLeft, bottomRight;
IBADrainNode dest=null;
IBASwitch tmpSw=null;
String addr=null;
int drainNodePort=-1;
int current=0;
// Top/North row
drainNodePort = 0;
for (current = 0; current < width; current ++) {
tmpSw = (IBASwitch) coreIbaSw[current].getOutNeighbour(NORTH);
dest = (IBADrainNode) tmpSw.getOutNeighbour(drainNodePort);
addr = dest.getOwnAddress().toString();
// Top row of core mesh
// The ones to the left of current
for (int i=0; i < current; i++) {
coreIbaSw[i].addRoutingInterval(addr, EAST);
}
// Current
coreIbaSw[current].addRoutingInterval(addr, NORTH);
// The ones to the east of current
for (int i=current + 1; i < width; i++) {
coreIbaSw[i].addRoutingInterval(addr, WEST);
}
// Rest of mesh (just send up).
for (int i = width; i < coreIbaSw.length; i++) {
coreIbaSw[i].addRoutingInterval(addr, NORTH);
}
}
// Right/East row
for (int currentRow = 1 ;
currentRow < height-1;
currentRow++) {
int offset = 0;
current = (currentRow+1) * width - 1;
tmpSw = (IBASwitch) coreIbaSw[current].getOutNeighbour(EAST);
dest = (IBADrainNode) tmpSw.getOutNeighbour(drainNodePort);
addr = dest.getOwnAddress().toString();
// The rows above current row
for (int row = 0; row < currentRow; row++) {
offset = row * width;
for (int col=0; col < width; col++) {
coreIbaSw[offset + col].addRoutingInterval(addr, SOUTH);
}
}
// Current row
offset = currentRow * width;
for (int col=0; col < width; col++) {
/*
// DEBUG
Reporter.println("Switch "+(offset+col)+", sending address "+addr+
" to output port "+EAST);
*/
211
coreIbaSw[offset + col].addRoutingInterval(addr, EAST);
}
// The rows below current row
for (int row = currentRow + 1; row < height; row++) {
offset = row * width;
for (int col=0; col < width; col++) {
coreIbaSw[offset + col].addRoutingInterval(addr, NORTH);
}
}
}
// Bottom/South row
for (current = width*(height-1); current < coreIbaSw.length; current ++) {
tmpSw = (IBASwitch) coreIbaSw[current].getOutNeighbour(SOUTH);
dest = (IBADrainNode) tmpSw.getOutNeighbour(drainNodePort);
addr = dest.getOwnAddress().toString();
// Bottom row of core mesh
// The ones to the left of current
for (int i=width*(height-1); i < current; i++) {
coreIbaSw[i].addRoutingInterval(addr, EAST);
}
// Current
coreIbaSw[current].addRoutingInterval(addr, SOUTH);
// The ones to the east of current
for (int i=current + 1; i < coreIbaSw.length; i++) {
coreIbaSw[i].addRoutingInterval(addr, WEST);
}
// Rest of mesh (just send down).
for (int i = 0; i < width*(height-1); i++) {
coreIbaSw[i].addRoutingInterval(addr, SOUTH);
}
}
// Left/West row
for (int currentRow = 1 ;
currentRow < height-1;
currentRow++) {
int offset = 0;
current = (currentRow) * width;
tmpSw = (IBASwitch) coreIbaSw[current].getOutNeighbour(WEST);
dest = (IBADrainNode) tmpSw.getOutNeighbour(drainNodePort);
addr = dest.getOwnAddress().toString();
// The rows above current row
for (int row = 0; row < currentRow; row++) {
offset = row * width;
for (int col=0; col < width; col++) {
coreIbaSw[offset + col].addRoutingInterval(addr, SOUTH);
}
}
// Current row
offset = currentRow * width;
for (int col=0; col < width; col++) {
coreIbaSw[offset + col].addRoutingInterval(addr, WEST);
}
// The rows below current row
212
for (int row = currentRow + 1; row < height; row++) {
offset = row * width;
for (int col=0; col < width; col++) {
coreIbaSw[offset + col].addRoutingInterval(addr, NORTH);
}
}
}
// Edge switches
for (int i = 0; i < edgeIbaSw.length; i++) {
addr = ((IBADrainNode)edgeIbaSw[i].getOutNeighbour(drainNodePort)).
getOwnAddress().toString();
// Add all out
/*
edgeIbaSw[i].addRoutingInterval("1.0-1.255", 1);
edgeIbaSw[i].deleteRoutingInterval(addr, 1);
edgeIbaSw[i].addRoutingInterval(addr, drainNodePort);
*/
// All up to current
int suff = Integer.parseInt(addr.substring(addr.indexOf(".")+1));
int prev = suff-1;
String prevAddr = null;
if (prev >= 0) {
prevAddr = "1."+(prev);
//Reporter.println("prevAddr = "+prevAddr+", addr = "+addr);
edgeIbaSw[i].addRoutingInterval("1.0-"+prevAddr, 1);
}
// Add current
edgeIbaSw[i].addRoutingInterval(addr, drainNodePort);
// All above current
int next = suff +1;
String nextAddr = null;
if (next < 255) {
nextAddr = "1."+(next);
//Reporter.println("nextAddr = "+nextAddr+", addr = "+addr);
edgeIbaSw[i].addRoutingInterval(nextAddr+"-1.255", 1);
}
}
}
// }}}
// {{{ public static void buildOptimisticRoutingTable(IBASwitch[] coreIbaSw, IBAStiwch[] edgeIbaS
/**
*<p>
* Builds an optimistic routing table in the net supplied. The edge switches should
* be connected to the core switches, and the core switches should be connected
* both ways, in a 2D mesh (grid). The routing that is set up, makes the switches
* forward packets most optimal, at the risk of routing loops, but it should improve the
* total capacity of the net drastically.
*</p>
*<p>
* The core switches should be aligned from the top left corner of the mesh.
*</p>
*<p>
* The egde switches should be aligned around the core switches, starting at top left.
* In the corners, the edge routers should be connected to the top or bottom link of the core
* switches, not the left or right.
* The suffix of the addresses on the drain nodes should start at 0 on the top left,
213
* then increase by one as we move around the mesh.
*</p>
*<p>
*<b>A simple example with a 3x3 mesh:</b>
* <tt>Ex</tt> are edge switches, and <tt>Cx</tt> are core switches.
*<pre>
*
E0
E1
E2
*
|
|
|
*
*
C0
C1
C2
*
|
|
|
* E8 - C3 - C4 - C5 - E3
*
|
|
|
*
C6 - C7 - C8
*
*
|
|
|
*
E6
E5
E4
*
*/
public static void buildOptimisticRoutingTable(IBASwitch[] coreIbaSw, IBASwitch[] edgeIbaSw,
int width, int height) {
// Constants to ease port number addressing
int WEST=0,NORTH=1,EAST=2,SOUTH=3;
// Build the routing table, starting from upper left.
// Core routers
// Find addresses of corners
Address topLeft, topRight, bottomLeft, bottomRight;
IBADrainNode dest=null;
IBASwitch tmpSw=null;
String addr=null;
int drainNodePort=-1;
int currCol=0;
int offset = 0;
int current = 0;
// Top/North row
drainNodePort = 0;
for (currCol = 0; currCol < width; currCol ++) {
tmpSw = (IBASwitch) coreIbaSw[currCol].getOutNeighbour(NORTH);
dest = (IBADrainNode) tmpSw.getOutNeighbour(drainNodePort);
addr = dest.getOwnAddress().toString();
// All rows
for (int row = 0; row < height; row++) {
offset = row * width;
current = offset + currCol;
/*
// DEBUG
Reporter.debugln("Row "+row);
Reporter.debugln("==================================================");
//
*/
// The ones to the left of currCol
for (int i=offset; i < current; i++) {
/*
214
// DEBUG
Reporter.debugln("Switch "+i+": sending packets to "+addr+" EAST");
//
*/
coreIbaSw[i].addRoutingInterval(addr, EAST);
}
// Current
/*
// DEBUG
Reporter.debugln("Switch "+current+": sending packets to "+addr+" NORTH");
//
*/
coreIbaSw[current].addRoutingInterval(addr, NORTH);
// The ones to the east of current
for (int i=current + 1; i < offset + width; i++) {
/*
// DEBUG
Reporter.debugln("Switch "+i+": sending packets to "+addr+" WEST");
//
*/
coreIbaSw[i].addRoutingInterval(addr, WEST);
}
}
}
// Right/East row
for (int currentRow = 1 ;
currentRow < height-1;
currentRow++) {
offset = 0;
current = (currentRow+1) * width - 1;
tmpSw = (IBASwitch) coreIbaSw[current].getOutNeighbour(EAST);
dest = (IBADrainNode) tmpSw.getOutNeighbour(drainNodePort);
addr = dest.getOwnAddress().toString();
// The rows above current row
for (int row = 0; row < currentRow; row++) {
offset = row * width;
for (int col=0; col < width; col++) {
/*
// DEBUG
Reporter.debugln("Switch "+(offset+col)+": sending packets to "+addr+" SOUTH");
//
*/
coreIbaSw[offset + col].addRoutingInterval(addr, SOUTH);
}
}
// Current row
offset = currentRow * width;
for (int col=0; col < width; col++) {
/*
// DEBUG
Reporter.debugln("Switch "+(offset+col)+": sending packets to "+addr+" EAST");
//
*/
coreIbaSw[offset + col].addRoutingInterval(addr, EAST);
}
// The rows below current row
for (int row = currentRow + 1; row < height; row++) {
offset = row * width;
215
for (int col=0; col < width; col++) {
/*
// DEBUG
Reporter.debugln("Switch "+(offset+col)+": sending packets to "+addr+" NORTH");
//
*/
coreIbaSw[offset + col].addRoutingInterval(addr, NORTH);
}
}
}
// Bottom/South row
for (currCol = 0; currCol < width; currCol ++) {
tmpSw = (IBASwitch) coreIbaSw[(height-1) * width + currCol].getOutNeighbour(SOUTH);
dest = (IBADrainNode) tmpSw.getOutNeighbour(drainNodePort);
addr = dest.getOwnAddress().toString();
// All rows
for (int row = 0; row < height; row++) {
offset = row * width;
current = offset + currCol;
/*
// DEBUG
Reporter.debugln("Row "+row);
Reporter.debugln("==================================================");
//
*/
// The ones to the left of current
for (int i=offset; i < current; i++) {
/*
// DEBUG
Reporter.debugln("Switch "+i+": sending packets to "+addr+" EAST");
//
*/
coreIbaSw[i].addRoutingInterval(addr, EAST);
}
// Current
/*
// DEBUG
Reporter.debugln("Switch "+current+": sending packets to "+addr+" SOUTH");
//
*/
coreIbaSw[current].addRoutingInterval(addr, SOUTH);
// The ones to the east of current
for (int i=current + 1; i < offset + width; i++) {
/*
// DEBUG
Reporter.debugln("Switch "+i+": sending packets to "+addr+" WEST");
//
*/
coreIbaSw[i].addRoutingInterval(addr, WEST);
}
}
}
// Left/West row
for (int currentRow = 1 ;
currentRow < height-1;
216
currentRow++) {
offset = 0;
current = (currentRow) * width;
tmpSw = (IBASwitch) coreIbaSw[current].getOutNeighbour(WEST);
dest = (IBADrainNode) tmpSw.getOutNeighbour(drainNodePort);
addr = dest.getOwnAddress().toString();
// The rows above current row
for (int row = 0; row < currentRow; row++) {
offset = row * width;
for (int col=0; col < width; col++) {
/*
// DEBUG
Reporter.debugln("Switch "+(offset+col)+": sending packets to "+addr+" SOUTH");
//
*/
coreIbaSw[offset + col].addRoutingInterval(addr, SOUTH);
}
}
// Current row
offset = currentRow * width;
for (int col=0; col < width; col++) {
/*
// DEBUG
Reporter.debugln("Switch "+(offset+col)+": sending packets to "+addr+" WEST");
//
*/
coreIbaSw[offset + col].addRoutingInterval(addr, WEST);
}
// The rows below current row
for (int row = currentRow + 1; row < height; row++) {
offset = row * width;
for (int col=0; col < width; col++) {
/*
// DEBUG
Reporter.debugln("Switch "+(offset+col)+": sending packets to "+addr+" NORTH");
//
*/
coreIbaSw[offset + col].addRoutingInterval(addr, NORTH);
}
}
}
// Edge switches
for (int i = 0; i < edgeIbaSw.length; i++) {
addr = ((IBADrainNode)edgeIbaSw[i].getOutNeighbour(drainNodePort)).
getOwnAddress().toString();
// Add all out
/*
edgeIbaSw[i].addRoutingInterval("1.0-1.255", 1);
edgeIbaSw[i].deleteRoutingInterval(addr, 1);
edgeIbaSw[i].addRoutingInterval(addr, drainNodePort);
*/
// All up to current
int suff = Integer.parseInt(addr.substring(addr.indexOf(".")+1));
int prev = suff-1;
String prevAddr = null;
if (prev >= 0) {
prevAddr = "1."+(prev);
217
//Reporter.println("prevAddr = "+prevAddr+", addr = "+addr);
edgeIbaSw[i].addRoutingInterval("1.0-"+prevAddr, 1);
}
// Add current
edgeIbaSw[i].addRoutingInterval(addr, drainNodePort);
// All above current
int next = suff +1;
String nextAddr = null;
if (next < 255) {
nextAddr = "1."+(next);
//Reporter.println("nextAddr = "+nextAddr+", addr = "+addr);
edgeIbaSw[i].addRoutingInterval(nextAddr+"-1.255", 1);
}
}
}
// }}}
/** Used when connecting two units.*/
//private static Link tmpLink;
private static Kernel kernel;
}
218
no.uio.ifi.gruns.infiniband.IBADelayedOutputPort
package no.uio.ifi.gruns.infiniband;
import no.uio.ifi.gruns.*;
/**
* The output ports on IBA units, delayed version.
* Waits to see if there is coming data on the high priority
* VL if it has just finished sending a packet on high priority.
* The intention is to avoid sending a packet from the low priority queue
* when there is a packet on its way on high priority, but it’s just delayed
* from the processing in the swithch.
*
* However, this doesn’t work very well, because it is impossible to know anything
* about the next packet on a particular VL when the switch has not yet read this packet
* since it hasn’t arrived in the switch yet.
*/
public class IBADelayedOutputPort extends IBAOutputPort{
/**
* @param numberOfVirtualLanes The number of virtual lanes
* @param bufferSize The size of the output buffers
* @param kernel The kernel to use for simulation
*/
public IBADelayedOutputPort(int numberOfVirtualLanes,
int bufferSize,
Kernel kernel,
IBADelayedSwitch source,
int portNumber){
super(numberOfVirtualLanes, bufferSize, kernel);
this.source = source;
this.portNumber = portNumber;
}
protected void updateCurrent(){
ListEntry le;
// Reset sendingStates
lrhIsSent = false;
bytesTransferred = 0;
// Check if we have exceeded the limit of high priority
// packets. If we have, check the low priority queue first.
if (
// limit == 255 means no limit
limitOfHighPriority < 255
&&
(
// limit == 0 means we could send one packet.
(limitOfHighPriority == 0 &&
bytesSentOnHighPriority > (limitOfHighPriority * 4096))
||
(limitOfHighPriority > 0 &&
bytesSentOnHighPriority >= (limitOfHighPriority * 4096))
)
)
{
bytesSentOnHighPriority = 0;
le = findNextListEntry(lowPriority, currentLowPriority);
if (le != null){ // Packets to send on Low Priority
active = lowPriority;
219
sendingState = SENDING;
}else{
le = findNextListEntry(highPriority, currentHighPriority);
if (le != null){// Packets to send on High Priority
active = highPriority;
sendingState = SENDING;
}
}
}
// If not, check the high priority first (usual case)
else{
// Find next to send from
le = findNextListEntry(highPriority, currentHighPriority);
if (le != null){// Packets to send on High Priority
// {{{ DEBUG
Reporter.debugln(ID+": Sending from high priority.");
// }}}
active = highPriority;
sendingState = SENDING;
}
else { // No packets to send on High Priority
//
//
//
//
//
//
//
//
//
//
//
//
Check to see if there’s data on its way on high pri,
and wait as many time steps as the processing time in the
switch so that we avoid sending from low priority and
lose a lot of time for the high pri VLs. If we have data
coming in on a high-pri VL, just set current to null, and then
the we will find out below that we have data to
send (on low priority), but not right now (since current is
null), and we will reshedule ourselves. Then, eventually,
when the data is ready from the switch, we will have the data
available in our buffers, so we don’t need to check
how many time steps the switch has left of the packet
processing time.
//
//
//
//
//
//
//
//
//
TODO: The problem is that if we are only receiving
packets on low priority, and the switch is sending out packets
on high priority to some other output port, we could end up
waiting forever, since no high priority packets will ever come
our way.
Another problem is that we don’t have any way of finding out if
the packets are high or low priority, and which VL the packets
are sent on before the switch has finished processing them.
IBASwitch.VLstate[][] states = source.getStates();
// Loop through all high priority VLs and find out if
// we have data in the coming on any of them.
ListEntry entry;
boolean dataIsOnItsWay = false;
for (int i=0; i < this.highPriority.length; i++){
entry = highPriority[i];
// {{{ Kommentert ut
/*
// {{{ DEBUG
Reporter.debug("Checking high priority entry "+i);
if (entry == null){
// {{{
Reporter.println("...empty.");
}else{
220
Reporter.println(".");
}
// }}}
*/
// }}}
if (entry != null){
// Check if any of the states of the switch has the same VL
// number as any of our high priority VLs. If it has, there’s a slight
// chance that the packet on its way in the switch is actually coming here.
for (int j=0; j < states.length; j++) {
for (int k=0; k < states[j].length; k++) {
// {{{ Kommentert ut
/*
// {{{ DEBUG
Reporter.debugln("Checking input port "+j+", VL "+k+".");
Reporter.debugln("states["+j+"]["+k+"] = "+states[j][k]);
Reporter.debugln("states["+j+"]["+k+"].outputPort = "+
states[j][k].outputPort);
Reporter.debug("states["+j+"]["+k+"].state = ");
switch(states[j][k].state){
case IBASwitch.VLstate.READY:
Reporter.println("READY");
break;
case IBASwitch.VLstate.RECEIVING_HEADER:
Reporter.println("RECEIVING_HEADER");
break;
case IBASwitch.VLstate.PROCESSING_HEADER:
Reporter.println("PROCESSING_HEADER");
break;
case IBASwitch.VLstate.VIRTUAL_CUT_THROUGH:
Reporter.println("VIRTUAL_CUT_THROUGH");
break;
case IBASwitch.VLstate.WAITING_FOR_OUTPUT_LINK:
Reporter.println("WAITING_FOR_OUTPUT_LINK");
break;
case IBASwitch.VLstate.FORWARD:
Reporter.println("FORWARD");
break;
}
// }}}
*/
// }}}
if (states[j][k] != null
&& states[j][k].state ==
IBADelayedSwitch.VLstate.PROCESSING_HEADER ){
// {{{ Kommentert ut
/*
// {{{ DEBUG
Reporter.debugln("Found incoming data on VL number "+
entry.VLNumber+".");
// }}}
*/
// }}}
dataIsOnItsWay = true;
break;
}
}
}
221
}
}
if (dataIsOnItsWay){
// {{{ DEBUG
Reporter.debugln(ID+", pausing to wait for data on hi pri.");
// }}}
le = null;
}
else{// No data on its way
// {{{ DEBUG
Reporter.debugln(ID+": Sending from lowpriority.");
// }}}
bytesSentOnHighPriority = 0;
le = findNextListEntry(lowPriority, currentLowPriority);
if (le != null){ // Packets to send on Low Priority
active = lowPriority;
bytesSentOnHighPriority = 0;
sendingState = SENDING;
}
}
}
}
// Update the current list entry.
this.current = le;
// Finished if nothing to send
if (current == null){
// Reschedule if we still have data to send
// but are not able to send right now
for (int i=0; i < numberOfVLs; i++){
if (!buffer[i].isEmpty()){
kernel.schedule(this, kernel.currentTime() + 1);
break;
}
}
}else{
// Send one block of data
sending();
}
// {{{ Kommentert ut
/*
// DEBUG
if (ID.startsWith("Switch 0")
//|| ID.startsWith("Switch 6")
//|| ID.startsWith("Switch 7")
) {
System.out.println("Time: "+kernel.currentTime()+", "
+ID+": Selected VL "+current.VLNumber+". "+
"VL 1’s buffer is "+
(buffer[1].isEmpty()?"":"NOT ")+
"empty."
);
}
//
*/
// }}}
}
/**
* The output port this output port is connected to.
222
* Used to find out how long to delay in updateCurrent.
*/
protected IBADelayedSwitch source;
/**
* The number this output port has on the switch is
* connected to.
*/
protected int portNumber;
}
223
no.uio.ifi.gruns.infiniband.IBADelayedOutputPort2
package no.uio.ifi.gruns.infiniband;
import no.uio.ifi.gruns.*;
/**
* The output ports on IBA units, delayed version 2.
*
* Waits exactly the time a switch uses to process a packet before sending
* the next packet, hoping that the next packet on high priority
* whould have arrived by then.
*
* The intention is to avoid sending a packet from the low priority queue
* when there is a packet on its way on high priority, and it is just delayed
* from the processing in the swithch.
*/
public class IBADelayedOutputPort2 extends IBAOutputPort{
// {{{ Constructor
/**
* @param numberOfVirtualLanes The number of virtual lanes
* @param bufferSize The size of the output buffers
* @param kernel The kernel to use for simulation
*/
public IBADelayedOutputPort2(int numberOfVirtualLanes,
int bufferSize,
Kernel kernel,
IBADelayedSwitch2 source,
int portNumber){
super(numberOfVirtualLanes, bufferSize, kernel);
this.source = source;
this.portNumber = portNumber;
}
// }}}
/**
* Introduces a delay between packets. See class definition
* for more information.
*/
protected void updateCurrent(){
ListEntry le;
// Reset sendingStates
lrhIsSent = false;
bytesTransferred = 0;
// Check if we have exceeded the limit of high priority
// packets. If we have, check the low priority queue first.
if (
// limit == 255 means no limit
limitOfHighPriority < 255
&&
(
// limit == 0 means we could send one packet.
(limitOfHighPriority == 0 &&
bytesSentOnHighPriority > (limitOfHighPriority * 4096))
||
(limitOfHighPriority > 0 &&
bytesSentOnHighPriority >= (limitOfHighPriority * 4096))
)
224
)
{
bytesSentOnHighPriority = 0;
le = findNextListEntry(lowPriority, currentLowPriority);
if (le != null){ // Packets to send on Low Priority
active = lowPriority;
sendingState = SENDING;
}else{
le = findNextListEntry(highPriority, currentHighPriority);
if (le != null){// Packets to send on High Priority
active = highPriority;
sendingState = SENDING;
}
}
}
// If not, check the high priority first (usual case)
else{
// Find next to send from
le = findNextListEntry(highPriority, currentHighPriority);
if (le != null){// Packets to send on High Priority
// {{{ DEBUG
Reporter.debugln(ID+": Sending from high priority.");
// }}}
active = highPriority;
sendingState = SENDING;
}
else { // No packets to send on High Priority
if (!haveWaitedForHiPri) {
// INVALID_VALUE indicates that we have not
// waited any time steps yet
if (remainingDelay == INVALID_VALUE) {
remainingDelay = Integer.
parseInt(System.getProperty("infiniband.PACKET_PROCESSING_TIME"));
// {{{ DEBUG
Reporter.debugln(ID+": Starting to wait for hi pri. "+
remainingDelay+" time units left.");
// }}}
}
// Decrease waiting timer
remainingDelay--;
// {{{ DEBUG
Reporter.debugln(ID+": Waiting for high pri. "+remainingDelay+
" time units left.");
// }}}
if (remainingDelay == 0){
haveWaitedForHiPri = true;
}
}
else{
// {{{ DEBUG
Reporter.debugln(ID+": Sending from lowpriority.");
// }}}
225
bytesSentOnHighPriority = 0;
le = findNextListEntry(lowPriority, currentLowPriority);
if (le != null){ // Packets to send on Low Priority
active = lowPriority;
bytesSentOnHighPriority = 0;
sendingState = SENDING;
}
}
}
}
// Update the current list entry.
this.current = le;
// Finished if nothing to send
if (current == null){
// Reschedule if we still have data to send
// but are not able to send right now
for (int i=0; i < numberOfVLs; i++){
if (!buffer[i].isEmpty()){
kernel.schedule(this, kernel.currentTime() + 1);
break;
}
}
}else{
// Send one block of data
sending();
}
}
/**
* Sends a block from the current VL and checks if we are finished sending
* the current packet. Reschedules if we are noe finished.
*/
protected void sending(){
// TODO: Small problem: When we are scheduled, and
// have already read all the bytes in the packet, we should
// start on the next packet, as of now, we only reset the state,
// and don’t transfer any bytes.
//
// Shouldn’t happen, really, because when we have finished reading
// all bytes, the state is reset, and we proceed to the next packet. Maybe
// it’s not happening. Find out!
sendBlockFromCurrent();
// Reschedule if not finished with current packet
if (bytesTransferred <
IBAPacketParser.packetLength(sendingLRHs[current.
VLNumber])){
kernel.schedule(this, kernel.currentTime() + 1);
}
// Clear the lrh from this VL if we are finished
// sending from it. Reset other parameters
else if (bytesTransferred ==
IBAPacketParser.packetLength(sendingLRHs[current.
VLNumber])){
sendingLRHs[current.VLNumber] = null;
sendingState = READY;
// for hi pri waiting
226
haveWaitedForHiPri = false;
remainingDelay = INVALID_VALUE;
// Logging
VLstates[current.VLNumber].totalNumberOfPacketsSent++;
//
// For SmallNetwork.gridNetwork and PriTest, we need the if test
// to avoid too much output.
if (ID.startsWith("Switch 0")
//
|| ID.startsWith("Switch 6")
//
|| ID.startsWith("Switch 7")
){
/*
// DEBUG
Reporter.print("Time "+kernel.currentTime()+", ");
Reporter.print(ID+": ");
for (int i=0; i < numberOfVLs; i++){
Reporter.print("VL "+i+": "+VLstates[i].totalNumberOfPacketsSent+", ");
}
*/
// LEAVE THIS... DON’T REMOVE!
int totLo=0, totHi=0;
double ratio;
for (int i=0; i < lowPriority.length; i++){
if (lowPriority[i] != null){
totLo += VLstates[lowPriority[i].VLNumber].totalNumberOfPacketsSent;
}
}
for (int i=0; i < highPriority.length; i++){
if (highPriority[i] != null){
totHi += VLstates[highPriority[i].VLNumber].totalNumberOfPacketsSent;
}
}
IBAStatistics.reportPriorities(this, totHi, totLo);
ratio = IBAStatistics.getPriorities(this);
//
/*
Reporter.print("Ratio Hi/Lo = "+
(ratio==-1?"INF":Utils.formatDouble(ratio)));
Reporter.println();
*/
}
// Reschedule if we still have data to send
// but are not able to send right now
for (int i=0; i < numberOfVLs; i++){
if (!buffer[i].isEmpty()){
kernel.schedule(this, kernel.currentTime() + 1);
break;
}
}
// For logging and debugging
totalNumberOfPacketsSent++;
}
// Sanity check
227
else if (bytesTransferred >
IBAPacketParser.packetLength(sendingLRHs[current.
VLNumber])){
Reporter.error("IBAOutputPort.act: Too many bytes sent! "+
bytesTransferred +" > "
+ IBAPacketParser.
packetLength(sendingLRHs[current.
VLNumber])+".");
}
// Insanity check ;)
else{
throw new java.lang.RuntimeException("Serious error! "+
"Should be "+
"impossible!");
}
}
/**
* The output port this output port is connected to.
* Used to find out how long to delay in updateCurrent.
*/
protected IBADelayedSwitch2 source;
/**
* The number this output port has on the switch is
* connected to.
*/
protected int portNumber;
/**
* The time left to wait for a packet on high priority
* before sending one on low priority.
*/
protected int remainingDelay;
/**
* Indicates whether we have waited the time it takes for the
* switch to process a packet to see if there is any data coming in
* on high priority.
*/
protected boolean haveWaitedForHiPri;
/**
* To indicate that the remaining delay time counter is invalid.
*/
protected static int INVALID_VALUE = -42;
}
228
no.uio.ifi.gruns.infiniband.IBADrainNode
package no.uio.ifi.gruns.infiniband;
import no.uio.ifi.gruns.*;
import no.uio.ifi.tools.*;
import java.util.Vector;
public class IBADrainNode extends DrainNode implements Reporting{
public IBADrainNode(Kernel kernel){
super(kernel);
}
public IBADrainNode(int numberOfInputPorts,
int numberOfVirtualLanes,
Kernel kernel){
super(kernel);
init(numberOfInputPorts, numberOfVirtualLanes, kernel);
}
public IBADrainNode(int numberOfInputPorts,
int numberOfVirtualLanes,
String ID,
Kernel kernel){
this(numberOfInputPorts, numberOfVirtualLanes, kernel);
this.ID = ID;
for (int i=0; i < numberOfInputPorts; i++){
inputPorts[i].setID(ID+", input port "+i);
}
}
private void init(int numberOfInputPorts,
int numberOfVirtualLanes,
Kernel kernel){
this.numberOfVLs = numberOfVirtualLanes;
inputPorts = new IBAInputPort[numberOfInputPorts];
for (int i=0; i < numberOfInputPorts; i++){
inputPorts[i] = new IBAInputPort(numberOfVirtualLanes, kernel);
inputPorts[i].setSink(this);
}
// Create input VL information holders
states = new State[numberOfInputPorts][numberOfVirtualLanes];
for (int i=0; i < numberOfInputPorts; i++){
for (int j=0; j < states[i].length; j++){
states[i][j] = new State();
}
}
}
/**
* Sets the address of this drain node
* @param The address as a string.
*/
public void setOwnAddress(String address){
this.address = new Address(address);
}
/**
* Sets the address of this drain node
* @param The address as an Address object.
229
*/
public void setOwnAddress(Address address){
this.address = address;
}
/**
* Gets the address of this drain node
* @return The address as an Address object.
*/
public Address getOwnAddress(){
return this.address;
}
/**
*<p>
* Tells the drain node that there are more bytes ready
* to be read from the input port.
*</p>
*<p>
* Sometimes the drain node
* could be scheduled at time N-2 to read from VL A at time N,
* then be scheduled at time N-1 to read from VL B at time N+1.
* When the drain node is run (at time N), it will read from both
* VL A and VL B, since it has no way of telling who scheduled it.
*<p>
*<p>
* When the drain node is then run at time N+1, it will try to
* read from VL B, but there are no bytes waiting to be read there,
* because they have already been read. We avoid this by keeping track
* of how many bytes that wait to be read. (By using this method)
*/
public void increaseBytesReadyToBeReceived(IBAInputPort port,
int VLNumber,
int numBytes){
int portNum = -1;
// find Port number
for (int i=0; i < inputPorts.length; i++){
if (port == inputPorts[i]){
portNum = i;
break;
}
}
if (portNum == -1){
Reporter.error(ID+": Port "+port.getID()+" is not attached to me.");
}
states[portNum][VLNumber].numBytesReadyToReceive += numBytes;
}
/**
* Stores a byte array in the right buffer.
*/
private void readBytes(int inputPortNumber,
int VLNumber,
byte[] fromBuffer){
for (int i=0; i < fromBuffer.length; i++){
// Check for consitency
if (!inputPorts[inputPortNumber].hasDataOnVL(VLNumber)){
Reporter.error("IBADrainNode.readBytes(int, int, byte[]): "+
"No data to read! Read "+i+", tried "+
fromBuffer.length);
}
states[inputPortNumber][VLNumber].buffer.put(fromBuffer[i]);
230
}
}
/**
* Receives bytes from the supplied input ports
* on the supplied VL.
*/
private void readBytes(int inputPortNumber,
int VLNumber,
int numBytes){
int VL = states[inputPortNumber][VLNumber].lrh.VL();
/*
// DEBUG
Reporter.debugln("IBAPacketParser.packetLength(lrhs["+inputPortNumber+"]["+
VLNumber+"]) = "+
IBAPacketParser.packetLength(states[inputPortNumber][VLNumber].lrh));
Reporter.debugln("numBytesReceived["+inputPortNumber+"]["+
VLNumber+"]) = "+
states[inputPortNumber][VLNumber].numBytesReceived);
Reporter.debugln("(IBAPacketParser.packetLength(lrhs["+inputPortNumber+"]["+
VLNumber+"]) = "+
(IBAPacketParser.packetLength(states[inputPortNumber][VLNumber].lrh)));
Reporter.debugln("numBytes to receive = "+numBytes);
//
*/
for (int i=0; i < numBytes; i++){
// Check for consistency
if (! inputPorts[inputPortNumber].hasDataOnVL(VLNumber)){
Reporter.error("IBADrainNode.readBytes(int, int, int): "+
"No data on port "+inputPortNumber+", VL "+VLNumber+". "+
"Read "+i+", tried "+numBytes);
}
states[inputPortNumber][VL].buffer.
put(inputPorts[inputPortNumber].receiveByte(VLNumber));
}
// Update state variables
states[inputPortNumber][VLNumber].numBytesReceived+=numBytes;
states[inputPortNumber][VLNumber].numBytesReadyToReceive-=numBytes;
}
public void act(){
int numBytes=0;
// Loop through all incoming VLs and read some data.
for (int i=0; i < inputPorts.length; i++){
for (int j=0; j < inputPorts[i].numberOfVLs(); j++){
numBytes = 0;
switch(states[i][j].state){
case State.READY:
states[i][j].reset();
if (!inputPorts[i].hasDataOnVL(j) ||
states[i][j].numBytesReadyToReceive == 0){
break;
}else{
states[i][j].state = State.RECEIVING_HEAD;
}
// fallthrough
231
case State.RECEIVING_HEAD:
// Receive head
byte [] tmpByte = new byte[IBAPacket.LRH_SIZE /
IBAPacket.BITS_PER_BYTE];
for (int k=0; k < tmpByte.length; k++) {
tmpByte[k] = inputPorts[i].receiveByte(j);
states[i][j].numBytesReceived++;
states[i][j].numBytesReadyToReceive--;
}
states[i][j].lrh = dummyPacket.new LRH(tmpByte);
// assertion
if (states[i][j].lrh.VL() != j){
Reporter.error("IBADrainNode.act: wrong VL number! "+
states[i][j].lrh.VL()+" != "+j);
}
// put the LRH in the right buffer
readBytes(i, j, tmpByte);
// Read more data from the link
// (up to Integer.parseInt(System.getProperty(
// "infiniband.BLOCK_SIZE")) bytes)
/*
numBytes = Math.min(Integer.parseInt(
System.getProperty("infiniband.BLOCK_SIZE")) IBAPacket.LRH_SIZE/IBAPacket.BITS_PER_BYTE,
IBAPacketParser.packetLength(states[i][j].lrh) states[i][j].numBytesReceived);
*/
numBytes = Math.min(Integer.parseInt(
System.getProperty("infiniband.BLOCK_SIZE")) IBAPacket.LRH_SIZE/IBAPacket.BITS_PER_BYTE,
Math.min(IBAPacketParser.packetLength(states[i][j].lrh) states[i][j].numBytesReceived,
states[i][j].numBytesReadyToReceive));
readBytes(i, j, numBytes);
/*
// DEBUG
Reporter.debugln(ID+", on port "+i+
", VL "+j+": Received "+tmpByte.length+" + "+numBytes+" bytes"+
", packet: "+states[i][j].numBytesReceived+" bytes.");
//
*/
states[i][j].state = State.RECEIVING_CONTENTS;
break;
case State.RECEIVING_CONTENTS:
// Read data from the link
//(up to Integer.parseInt(System.getProperty(
// "infiniband.BLOCK_SIZE")) bytes)
numBytes = Math.min(Integer.parseInt(
System.getProperty("infiniband.BLOCK_SIZE")),
Math.min(IBAPacketParser.packetLength(states[i][j].lrh) states[i][j].numBytesReceived,
states[i][j].numBytesReadyToReceive));
/*
// DEBUG
Reporter.debugln(ID+", port "+i+
232
", VL "+j+": Trying to receive "+numBytes+" bytes");
//
*/
readBytes(i, j, numBytes);
/*
// DEBUG
Reporter.debugln(ID+", on port "+i+
", VL "+j+": Received "+numBytes+" bytes"+
", packet: "+states[i][j].numBytesReceived+" bytes.");
//
*/
// Check if we are finished reading the packet
if (states[i][j].numBytesReceived ==
IBAPacketParser.packetLength(states[i][j].lrh)){
tmpPacket = new IBAPacket(states[i][j].buffer.toByteArray());
/*
// DEBUG
Reporter.debugln("========>Received packet from "+
new Address(tmpPacket.lrh.SLID()));
//
*/
// Store some statisics
IBAStatistics.reportReceivedPacket(this, i, j, states[i][j].lrh,
states[i][j].numBytesReceived);
// Reset status
states[i][j].state = State.READY;
}
// Internal check. If the test is true, there is
// an internal error in the simulator program.
else if (states[i][j].numBytesReceived >
IBAPacketParser.packetLength(states[i][j].lrh)){
Reporter.error(ID+" IBADrainNode.act: received "+
states[i][j].numBytesReceived+
" on port "+i+", VL "+j);
}
//
break;
default:
Reporter.error("IBADrainNode.act: Illegal state for port "+
i+", VL "+j+": "+states[i][j].state);
}
}
}
}
/**
* Attaches a link to this drain node on the
* supplied input port number
*/
public void attach(Link l, int inputPortNumber)
throws IllegalArgumentException {
if (inputPorts == null){
throw new IllegalArgumentException("This drain node has "+
"no input ports.");
}
233
if (inputPortNumber < 0 || inputPortNumber > inputPorts.length){
throw new IllegalArgumentException("Input port number out "+
"of range. Must be"+
"between 0 and "+
inputPorts.length);
}
inputPorts[inputPortNumber].attach(l);
// Update the ID to be able to distinguish input ports from each other
inputPorts[inputPortNumber].setID(ID+", port "+inputPortNumber);
}
public String report(){
int grandTotalNumberOfPackets = 0;
int grandTotalNumberOfBytes = 0;
IBAStatistics.IBADrainNodeStats stats;
stats = IBAStatistics.getReceivedPacketStats(this);
StringBuffer retVal = new StringBuffer();
retVal.append("IBADrainNode "+ID+": Total number of packets received = ");
if (stats != null){
retVal.append(Utils.formatInt(stats.getTotalNumberOfReceivedPackets())+".\n");
java.util.HashMap map = stats.getPacketsReceivedPerSource();
java.util.Set keys = map.keySet();
java.util.Iterator it = keys.iterator();
while(it.hasNext()){
String key = (String) it.next();
Received from source "+
retVal.append("
key+": "+
Utils.formatInt(((Integer) map.get(key)).intValue())+"\n");
}
}
else{
retVal.append(0);
}
retVal.append("
Total number of bytes received = ");
if (stats != null){
retVal.append(Utils.formatInt(stats.getTotalNumberOfReceivedBytes()));
}else{
retVal.append(0);
}
//
retVal.append(".\n");
//return retVal.toString();
return (stats==null) ? null : retVal.toString();
}
/** Returns the number of input ports on this drain node. */
public int getNumberOfInputPorts(){
return inputPorts.length;
}
/** Returns the number of VLs per input port on this drain node. */
234
public int getNumberOfVLs(){
return this.numberOfVLs;
}
/** Used to create stats when a packet is received.*/
private IBAPacket tmpPacket;
private IBAInputPort[] inputPorts;
private int numberOfVLs;
/** Holds the state info on all VLs.*/
private State[][] states;
private static final IBAPacket dummyPacket = new IBAPacket();
/**
* Hold information on each incoming VL on all the incoming ports.
*/
private class State{
private static final int READY = 0;
private static final int RECEIVING_HEAD = 1;
private static final int RECEIVING_CONTENTS = 2;
/** For storing incoming packets.*/
private ByteBuffer buffer;
/** The LRHs of the currently incoming packets. */
private IBAPacket.LRH lrh;
/** The number of bytes received from current packet. */
private int numBytesReceived;
/** The number of bytes ready to be received from the input port. */
private int numBytesReadyToReceive;
/** The states of the VL. */
private int state;
protected State(){
init();
}
private void init(){
buffer = new ByteBuffer(IBAPacket.MAX_SIZE);
reset();
}
private void reset(){
buffer.clear();
lrh = null;
numBytesReceived = 0;
state = READY;
}
}
}
235
no.uio.ifi.gruns.infiniband.IBASourceNode
package no.uio.ifi.gruns.infiniband;
import no.uio.ifi.gruns.*;
import no.uio.ifi.tools.*;
public class IBASourceNode extends SourceNode implements IBAPacketSender{
public IBASourceNode(int numberOfOutputPorts,
int numberOfVirtualLanes,
Kernel kernel)
{
this(numberOfOutputPorts, numberOfVirtualLanes, "", kernel);
}
public IBASourceNode(int numberOfOutputPorts,
int numberOfVirtualLanes,
String ID,
Kernel kernel){
super(numberOfOutputPorts, numberOfVirtualLanes, ID, kernel);
init(numberOfOutputPorts, numberOfVirtualLanes);
}
/**
* Common initialization
*/
private void init(int numberOfOutputPorts,
int numberOfVirtualLanes){
addresses = new AddressVector();
routingTable = new IBARoutingTable();
outputPorts = new IBAOutputPort[numberOfOutputPorts];
for (int i=0; i < numberOfOutputPorts; i++){
outputPorts[i] = new IBAOutputPort(numberOfVirtualLanes,
kernel);
outputPorts[i].setID(ID+", output port "+i);
}
//
transientThreshold = Integer.getInteger("infiniband.TRANSIENT_PERIOD", 0).intValue();
transientPeriod = true;
numberOfPacketsSent = 0;
numberOfPacketsWaiting = 0;
reportedNumberOfPacketsSent = 0;
reportedNumberOfPacketsWaiting = 0;
SL = 0;
VL = 0;
/** Filler data for data packets */
StringBuffer buf = new StringBuffer();
for (int i=0; i < FILLER_SIZE; i++) {
// Too slow
//
buf.append((char) ((int) ’A’ + random.nextInt(26)));
buf.append(’A’);
}
fillData = buf.toString();
}
236
/**
* Sets the address of this source node
* @param The address as a string.
*/
public void setOwnAddress(String address){
this.address = new Address(address);
}
/**
* Sets the address of this source node
* @param The address as an Address object.
*/
public void setOwnAddress(Address address){
this.address = address;
}
/**
* Sets the SL this source node sends packets on.
* TODO: NOW IT SETS THE VL ALSO. FIX THIS.
*/
public void setSL(int SL){
this.SL = SL;
this.VL = SL;
}
/**
* Gets the SL this source node sends packets on.
*/
public void getSL(int SL){
this.SL = SL;
}
/**
* Sets the inter-packet delay for this source node.
* Controls how often this source node transmits packets.
*/
public void setInterPacketDelay(int delay){
this.interPacketDelay = delay;
}
/**
* Sets how many percent of the bandwith in the network this source node
* should use when sending packets. A value of 50 indicates that this source node
* should try to send out packets so often that it uses about 50% of the bandwith
* resources in the network. This value is computed from the forwarding capacity
* of the units in the net, which is known a priori. The main unit of transfer in
* the network is an IBA block, and each unit can process one IBA block per time step.
*
* From this, we can compute how long the inter packet delay must be for us
* to utilize a certain percentage of the link capacity.
* E.g. given a value of 50%, we can compute the delay like this:
* <pre>
* P -> Percentage of link usage
* B -> Blocks per packet
* D -> Delay in time steps (time spent sending one block) between each packet
*
* We then have the following:
*
* P
= 100 * (B / (B + D))
* B / (B + D)
= P / 100
* B
= (P*(B + D))/100
* B - PB / 100
= PD / 100
*
237
* which gives us a delay of:
*
* D = (B * (100 - P)) / P
*
* </pre>
*/
public void setUsage(double percent){
int D;
double P; // Percentage
double B; // Time steps needed to send one packet.
P = percent;
// Floor so we don’t risk waiting too long. We need to keep the pipe full.
// Better to throw away one packet because the last one isn’t finished
// sending than not to send a packet when the link is free.
B = (int)
Math.floor((Double.
parseDouble(System.
getProperty("infiniband.EXP_PACKET_SIZE")) + 2) /
Double.parseDouble(System.getProperty("infiniband.BLOCK_SIZE")));
// Inter-packet delay is just B if we are to send 100%. Don’t have to send more
// than one packet at once. The other packets will just get thrown away.
D = (int) B + (int) Math.round((B * (100 - P)) / P);
this.interPacketDelay = D;
// {{{ DEBUG
/*
Reporter.debugln(ID+": Set usage percentage to "+
P+" percent. Inter-packet delay set to "+D);
*/
// }}}
}
/**
* Attaches a link to this source node on the
* supplied output port number
*/
public void attach(Link l, int outputPortNumber)
throws IllegalArgumentException {
if (outputPorts == null){
throw new IllegalArgumentException("This source node "+
"has no output ports.");
}
if (outputPortNumber < 0 ||
outputPortNumber > outputPorts.length){
throw new IllegalArgumentException("Output port number out "+
"of range. Must be"+
"between 0 and "+
outputPorts.length);
}
238
outputPorts[outputPortNumber].attach(l);
// Update the ID to be able to distinguish outputports
// from each other
outputPorts[outputPortNumber].setID(ID+", port "+
outputPortNumber);
}
/**
* Adds a new address that this source node can send to
* @param The address as a string.
*/
public void addDestinationAddress(String address){
this.addresses.add(new Address(address));
}
/**
* Adds an address range that this source node can send
* to. The format of the string can be one of the following,
* where aaa, bbb, ccc and ddd represents integers between 0 and 255:
* <table>
* <tr><td>aaa.bbb</td><td>Adds the specified address</tr>
* <tr><td>aaa.bbb-ccc.ddd</td><td>Adds addresses ranging from
*
aaa.bbb to ccc.ddd, inclusive.</td></tr>
* </table>
* @param range A string describing the address range.
*/
public void addDestinationAddresses(String range)
throws IllegalArgumentException{
int dashIndex = range.indexOf(’-’);
// No range specified, just add the address
if (dashIndex == -1){
addDestinationAddress(range);
}
// Fetch the addresses from the sring supplied
Address[] addrs = getAddresses(range);
// Add all the addresses
for (int i=0; i < addrs.length; i++){
addresses.add(addrs[i]);
}
}
/**
* Adds an output port to which packets addresses to the
* specified addresses can be sent.
* Same address format as addDestinationAddress.
*/
public void addRoutingInterval(String addresses,
int outputPortNumber){
Address[] addrs = getAddresses(addresses);
for (int i=0; i < addrs.length; i++){
routingTable.addRoute(addrs[i], outputPortNumber);
}
}
/**
* Deletes an output port to which packets addresses to the
* specified addresses can be sent.
* Same address format as addDestinationAddress.
239
*/
public void deleteRoutingInterval(String addresses,
int outputPortNumber){
Address[] addrs = getAddresses(addresses);
for (int i=0; i < addrs.length; i++){
routingTable.deleteRoute(addrs[i], outputPortNumber);
}
}
/**
* Sets the number of units we can send from high priority
* before letting a unit from low priority send.
* @param portNumber The port number to set the limit for
* @param limit The number of units
*/
public void setLimitOfHighPriority(int portNumber, int limit){
outputPorts[portNumber].setLimitOfHighPriority(limit);
}
/**
* Adds an entry to the high priority list of this source node.
* Means that port number <tt>portNumber</tt> is allowed to send
* <tt>weight</tt> units on virtual lane number <tt>VLNumber</tt>.
* This entry has high priority, which means that it will be selected
* before any of the entries in the low priority table.
*/
public void addHighPriority(int portNumber, int VLNumber, int weight){
outputPorts[portNumber].addHighPriority(VLNumber, weight);
}
/**
* Adds an entry to the low priority list of this source node.
* Means that port number <tt>portNumber</tt> is allowed to send
* <tt>weight</tt> units on virtual lane number <tt>VLNumber</tt>.
* This entry has low priority, which means that it will be selected
* after any of the entries in the high priority table.
*/
public void addLowPriority(int portNumber, int VLNumber, int weight){
outputPorts[portNumber].addLowPriority(VLNumber, weight);
}
/**
* Checks an address on string form for validity
*/
private void checkAddress(String address)
throws IllegalArgumentException {
int[] addr = { Integer.parseInt(address.
substring(0, address.indexOf(’.’))),
Integer.parseInt(address.
substring(address.indexOf(’.’)+1)) } ;
if (addr[0] < 0 || addr[0] > 255){
throw new IllegalArgumentException("Address parts must be "+
"in the range 0 to 255. "+
addr[0]+
" is out of range.");
}
if (addr[1] < 0 || addr[1] > 255){
throw new IllegalArgumentException("Address parts must be "+
240
"in the range 0 to 255. "+
addr[1]+
" is out of range.");
}
}
/**
* Parses a string with an address range and returns an array
* containing each address in the range.
* The format of the string can be one of the following,
* where aaa, bbb, ccc and ddd represents integers between 0 and 255:
* <table>
* <tr><td>aaa.bbb</td><td>Adds the specified address</tr>
* <tr><td>aaa.bbb-ccc.ddd</td><td>Adds addresses ranging from
*
aaa.bbb to ccc.ddd, inclusive.</td></tr>
* </table>
* @param range A string describing the address range.
*/
private Address[] getAddresses(String range){
AddressVector retVal = new AddressVector();
int dashIndex = range.indexOf(’-’);
// No range specified, just add the address
if (dashIndex == -1){
Address[] a = { new Address(range)};
return a;
}
else{
String startAddr = range.substring(0, dashIndex);
String endAddr = range.substring(dashIndex+1);
int[] startAddress = { Integer.parseInt(startAddr.
substring(0, range.indexOf(’.’))),
Integer.parseInt(startAddr.
substring(range.indexOf(’.’)+1)) } ;
int[] endAddress = { Integer.parseInt(endAddr.
substring(0, range.indexOf(’.’))),
Integer.parseInt(endAddr.
substring(range.indexOf(’.’)+1)) } ;
int[] currentAddress = new int[2];
// Check the input parameters
// Range check
checkAddress(startAddr);
checkAddress(endAddr);
// Start must be smaller than end
if (
(endAddress[0] < startAddress[0]) ||
( (endAddress[0] == startAddress[0]) &&
(endAddress[1] < startAddress[1]) ) )
{
throw new IllegalArgumentException("\nStart address "+
"must be smaller than"+
" end address. "+
startAddr+
" is larger than "+
endAddr+".");
}
// Loop through all the addresses and add them
241
int limit = 255;
currentAddress[1] = startAddress[1];
for (currentAddress[0] = startAddress[0];
currentAddress[0] <= endAddress[0];
currentAddress[0]++){
// Adjust the limit of the last part of the address if
// the last prefix is reached
if (currentAddress[0] == endAddress[0]){
limit = endAddress[1];
}
while( currentAddress[1] <= limit ){
retVal.add(new Address(currentAddress[0]+"."
+currentAddress[1]));
currentAddress[1]++;
}
// Reset last part of address for next run
currentAddress[1] = 0;
}
}
return retVal.toAddressArray();
}
public void sendIBAPacket(IBAPacket p,
int portNumber,
int VLNumber){
if (outputPorts[portNumber].
canSend(VLNumber, p.getSize())){
outputPorts[portNumber].sendIBAPacket(p, VLNumber);
// Schedule the output port so that the packet moves on
kernel.schedule(outputPorts[portNumber],
kernel.currentTime() + 1);
numberOfPacketsSent++;
numberOfPacketsWaiting--;
// Check to see if the transient period is over yet
if (transientPeriod) {
if (kernel.currentTime() > transientThreshold) {
transientPeriod = false;
}
} else {
reportedNumberOfPacketsSent++;
reportedNumberOfPacketsWaiting--;
}
//
//
//
if
For extra checking. act() fails abruptly if
the number of waiting packets is more than zero and
packet is null.
(numberOfPacketsWaiting == 0) {
this.packet = null;
}
/*
// DEBUG
242
Reporter.debugln(ID+": Sending packet on port "+portNumber+", "+
"waiting packets = "+numberOfPacketsWaiting);
//
*/
}
else{
//IBAStatistics.reportDroppedPacket(this);
/*
// DEBUG
Reporter.debugln(ID+": Can’t send packet on port "+portNumber+", "+
"waiting packets = "+numberOfPacketsWaiting);
//
*/
}
}
/**
* Makes an IBA packet
*/
protected IBAPacket makeIBAPacket(){
// Fetch a random address from our addresses
Address destination =
RandomAddress.nextAddress(addresses.toAddressArray());
// Make a packet to the specified address
IBAPacket p = new IBAPacket(destination, this.address);
// Tell that this packet is a local packet
p.lrh.setLNH(IBAPacket.LNH_IBA_local);
// Make this a "Send Only" packet.
p.bth.setOpCode(IBAPacket.RD_SEND_ONLY);
p.lrh.setVL(this.VL);
p.lrh.setSL(this.SL);
// Must know ecact payload length, so skip this message.
//StringBuffer str = new StringBuffer("Hello World! Test message "+
//
"from source node "+
//
this.ID+". ");
StringBuffer str = new StringBuffer();
// Fill up with a random number of random characters
//
int numChars = random.nextInt(2000);
// Use fixed number instead, for predicatability
int numChars = Integer.parseInt(System.getProperty("infiniband.EXP_PAYLOAD_SIZE"));
// Too slow
//for (int i=0; i < numChars; i++) {
//
str.append(’A’);
//}
// Much faster
str.append(fillData.substring(0, numChars));
p.pyld.setContent(str.toString().getBytes());
p.updatePacketLength();
243
// Update the number of packets created but not yet sent
numberOfPacketsWaiting++;
if (transientPeriod) {
if (kernel.currentTime() > transientThreshold) {
transientPeriod = false;
}
}else {
reportedNumberOfPacketsWaiting++;
}
return p;
}
public void act(){
Address a = null;
Route route = null;
int outputPort = 0;
// Make a new packet each "interPacketDelay" time steps.
if (kernel.currentTime() % this.interPacketDelay == 0) {
packet = makeIBAPacket();
}
if (numberOfPacketsWaiting > 0) {
if (packet == null) {
throw new RuntimeException("IBASourceNode.act: ERROR! "+
" packet == null!");
}
a = new Address(packet.lrh.DLID());
route = routingTable.lookUp(a);
outputPort = 0;
if (route !=null){
outputPort = route.portNumber;
}else{
Reporter.error("IBASourceNode.act(): "+
"No route found for supplied address:");
Reporter.error(a.getAddressAsString()+" "+
"("+Utils.asBitString(a.getAddress())+")");
}
sendIBAPacket(packet, outputPort, packet.lrh.VL());
}
// Reschedule in "interPacketDelay" time steps
kernel.schedule(this, kernel.currentTime() +
/*random.nextInt(2*this.interPacketDelay)+*/
this.interPacketDelay);
// Reschedule on next time step if we have more data to send.
if (this.numberOfPacketsWaiting > 0) {
kernel.schedule(this, kernel.currentTime() + 1);
}
}
/**
* Returns the number of packets sent successfully.
*/
public int getSentPackets() {
244
return reportedNumberOfPacketsSent;
}
/**
* returns the number of packets waiting to be sent.
*/
public int getWaitingPackets() {
return reportedNumberOfPacketsWaiting;
}
public String report(){
return "IBASourceNode "+this.ID+
": Packets sent = "+
Utils.formatInt(reportedNumberOfPacketsSent)+
/*
", packets dropped = "+
Utils.formatInt(IBAStatistics.getDroppedPacketStats(this)
*/
", packets waiting to be sent = "+
Utils.formatInt(reportedNumberOfPacketsWaiting)
;
}
/** A routing table to know where to send outbound packets */
protected IBARoutingTable routingTable;
/** The output ports to send to */
protected IBAOutputPort[] outputPorts;
/** Used to draw different times to reschedule */
protected java.util.Random random = new java.util.Random();
/** The delay between packets being sent out.*/
protected int interPacketDelay;
/** Number of packets send out on the network */
protected int numberOfPacketsSent;
/** Number of created packets that are waiting to be sent out on the network */
protected int numberOfPacketsWaiting;
/**
* Reported number of packets send out on the network. Not registered
* before the end of the transient period.
*/
protected int reportedNumberOfPacketsSent;
/** Reported number of created packets that are waiting to be sent out on the network.
* Not registered before the end of the transient period.
*/
protected int reportedNumberOfPacketsWaiting;
/** The SL this source node is sending packets on */
protected int SL;
/** The VL this source node is sending packets on */
protected int VL;
/** Size of filler packet */
protected static final int FILLER_SIZE = 100000;
/** The next packet to send */
245
protected IBAPacket packet;
/** Used to add stochastic filler data to packets,
and avoid creating the data on each time step. */
protected String fillData;
/**
* Indicates when the transient period is over,
* so we should start gathering data.
*/
protected int transientThreshold;
/**
* Indicates that the transient period is over
*/
protected boolean transientPeriod;
}
246
no.uio.ifi.gruns.infiniband.NotClearToSendException
package no.uio.ifi.gruns.infiniband;
/**
* Thrown when trying to send to an output port on a VL
* which the output port is currently receiving a packet on.
* Then there won’t be any mixing of the two packets.
*/
public class NotClearToSendException extends RuntimeException{
public NotClearToSendException(){
super();
}
public NotClearToSendException(String message){
super(message);
}
}
247
no.uio.ifi.tools.Comparator
package no.uio.ifi.tools;
/**
* Used to compare two objects of any type, just
* define the methods accordingly.
*/
public interface Comparator{
/**
* True if and only if <i>a</i> is less than <i>b</i>
*/
public boolean isLessThan(Object a, Object b);
/**
* True if and only if <i>a</i> is less than or equal to <i>b</i>
*/
public boolean isLessThanOrEqualTo(Object a, Object b);
/**
* True if and only if <i>a</i> and <i>b</i> are equal
*/
public boolean isEqualTo(Object a, Object b);
/**
* True if and only if <i>a</i> is greater than <i>b</i>
*/
public boolean isGreaterThan(Object a, Object b);
/**
* True if and only if <i>a</i> is greater than or equal to <i>b</i>
*/
public boolean isGreaterThanOrEqualTo(Object a, Object b);
/**
* True if and only if <i>a</i> can be compared
*/
public boolean isComparable(Object a);
}
248
no.uio.ifi.tools.Item
package no.uio.ifi.tools;
/**
* Stores a (key, value) pair
*/
public class Item {
private Object key, element;
public Item(Object key, Object element){
this.key = key;
this.element = element;
}
public Object getKey() {
return key;
}
public Object getElement(){
return element;
}
public void setKey(Object key){
this.key = key;
}
public void setElement(Object element) {
this.element = element;
}
}
249
no.uio.ifi.tools.ItemComparator
package no.uio.ifi.tools;
/**
* <p>
* Compares two {@link no.uio.ifi.gruns.Item}s.
* Uses the <tt>no.uio.ifi.tools.Item.key</tt> value to compare.
* </p>
* <p>
* It depends on that the value of the key of an
* {@link no.uio.ifi.gruns.Item} is an {@link java.lang.Integer}
*/
public class ItemComparator implements Comparator{
public boolean isLessThan(Object a, Object b){
int aVal, bVal;
aVal = ( (Integer)((Item) a).getKey() ).intValue();
bVal = ( (Integer)((Item) b).getKey() ).intValue();
return ( aVal < bVal );
}
public boolean isLessThanOrEqualTo(Object a, Object b){
int aVal, bVal;
aVal = ( (Integer)((Item) a).getKey() ).intValue();
bVal = ( (Integer)((Item) b).getKey() ).intValue();
return ( aVal <= bVal );
}
public boolean isEqualTo(Object a, Object b){
int aVal, bVal;
aVal = ( (Integer)((Item) a).getKey() ).intValue();
bVal = ( (Integer)((Item) b).getKey() ).intValue();
return ( aVal == bVal );
}
public boolean isGreaterThan(Object a, Object b){
int aVal, bVal;
aVal = ( (Integer)((Item) a).getKey() ).intValue();
bVal = ( (Integer)((Item) b).getKey() ).intValue();
return ( aVal > bVal );
}
public boolean isGreaterThanOrEqualTo(Object a, Object b){
int aVal, bVal;
aVal = ( (Integer)((Item) a).getKey() ).intValue();
bVal = ( (Integer)((Item) b).getKey() ).intValue();
return ( aVal >= bVal );
}
public boolean isComparable(Object a){
250
if (a==null) return false;
try{
Integer integer = (Integer) ( (Item) a ).getKey();
}catch (ClassCastException e) { return false; }
return true;
}
}
251
no.uio.ifi.tools.JavaPriorityQueue
package no.uio.ifi.tools;
import java.io.Serializable;
import java.util.*;
/**
* A Priority Queue based on the Java Collections Framework.
* Based on the JDC Core Java Technologies Tech Tips August 21, 2002.
*
* Extended to be dynamic, e.g. one can have a priority queue with
* the priorities 3, 40 and 500, and suddely you can add an item at
* priority 2 or 37 or 349 or 504. This fills the needs of the kernel
* in the gruns simulator.
*/
public class JavaPriorityQueue
extends AbstractList
implements Serializable {
//private final static int DEFAULT_PRIORITY_COUNT = 10;
private final static int DEFAULT_PRIORITY = 0;
//
private List queue[];
private LinkedList queue;
public JavaPriorityQueue() {
this(null);
}
public JavaPriorityQueue(Collection col) {
queue = new LinkedList();
if (col != null) {
addAll(col);
}
}
public boolean add(Object element) {
insert(element, DEFAULT_PRIORITY);
return true;
}
/**
* Inserts the object specified at the priority supplied.
* Doesn’t insert an object more than once on the same priority,
* so the second call here would have no effect:
*<pre>
* queue.insert("Joy", 8);
* queue.insert("Joy", 8);
*</pre>
* Of course, one can add the same element more than once using
* different priorities.
*/
public void insert(Object element, int priority) {
if (priority < 0) {
throw new IllegalArgumentException(
"Illegal priority: " + priority);
252
}
// Find position to insert element on.
// It’s probably the last position in the simulator kernel,
// so we traverse the queue backwards looking for the right spot
// to insert.
PriorityItem[] prios = new PriorityItem[queue.size()];
PriorityItem prio = null;
prios = (PriorityItem[]) queue.toArray(prios);
//
//
//
if
Check to see if the priority is bigger (i.e. less important)
than the last entry. If it is, just add a new item at the end.
Also if the list contains no items.
( queue.size() == 0 ||
((PriorityItem)queue.getLast()).priority < priority) {
prio = new PriorityItem(priority);
queue.add(prio);
}
// If the first item is bigger thatn this one, insert first in queue.
else if ( ((PriorityItem)queue.getFirst()).priority > priority) {
//System.err.println("first.priority = "+
//
((PriorityItem)queue.getFirst()).priority+
//
", priority = "+priority);
prio = new PriorityItem(priority);
queue.addFirst(prio);
}
// If not, find the right spot to insert the item.
else{
for (int i=prios.length-1; i >=0; i--) {
//System.err.print("prios["+i+"].priority == "+
//
prios[i].priority+", "+
//
"priority == "+priority);
if (prios[i].priority==priority) {
//System.err.println("...found priority!");
// Found the priority in the queue.
prio = prios[i];
break;
} else if (prios[i].priority < priority) {
//System.err.println("...did not find priority!");
// Priority not found in queue. Make a new
// entry below the nearest one bigger than this.
prio = new PriorityItem(priority);
queue.add(i+1, prio);
break;
}
}
}
//System.err.println("queue = "+this);
//System.out.println("prio = "+prio);
// if the item is already present at that priority, don’t add it.
if (prio.items.indexOf(element) == -1) {
prio.items.add(element);
}
//System.out.println("prio = "+prio);
//System.err.println("queue = "+this);
modCount++;
}
253
public Object getFirst() {
return iterator().next();
}
public Object get(int index) {
if (index < 0) {
throw new IllegalArgumentException(
"Illegal index: "+ index);
}
Iterator iter = iterator();
int pos = 0;
while (iter.hasNext()) {
Object obj = iter.next();
if (pos == index) {
return obj;
} else
{
pos++;
}
}
return null;
}
public void clear() {
PriorityItem pItem;
Iterator iter = queue.iterator();
// Remove all the elements on each priority
while(iter.hasNext()) {
pItem = (PriorityItem)iter.next();
if (pItem != null) {
pItem.items.clear();
}
}
// Remove the list of priorities
queue.clear();
}
public Object removeFirst() {
Iterator iter = iterator();
Object obj = iter.next();
iter.remove();
if ( ((PriorityItem)queue.getFirst()).items.size() == 0) {
queue.removeFirst();
}
return obj;
}
/**
* Returns the value of the most important (lowest priority)
* item in the queue
*/
public int minValue() {
if (queue.size() > 0) {
PriorityItem item = (PriorityItem)queue.getFirst();
return item.priority;
}
254
else return -20;
}
public int size() {
PriorityItem pItem;
int size = 0;
Iterator iter = queue.iterator();
while(iter.hasNext()) {
pItem = (PriorityItem)iter.next();
if (pItem != null) {
size += pItem.items.size();
}
}
return size;
}
/**
* The priorities are soneqhat reversed, since I want the item on the
* lowest time step to be picked first, not the one on the highest time step.
*/
public Iterator iterator() {
Iterator iter = new Iterator() {
int expectedModCount = modCount;
int priority = queue.size() - 1;
int count = 0;
int size = size();
// Used to prevent successive remove() calls
int lastRet = -1;
Iterator tempIter;
// Get iterator for highest (smallest) priority
{
if (queue.size() == 0){
tempIter = null;
} else {
tempIter = ((PriorityItem)queue.getFirst()).items.iterator();
}
/*
if (queue[priority] == null) {
tempIter = null;
} else {
tempIter = queue[priority].iterator();
}
*/
}
private final void checkForComodification() {
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}
public boolean hasNext() {
return count != size();
}
255
public Object next() {
checkForComodification();
if (tempIter == null) {
throw new NoSuchElementException();
} else {
lastRet = count++;
return tempIter.next();
}
}
public void remove() {
if (lastRet == -1) {
throw new IllegalStateException();
}
checkForComodification();
tempIter.remove();
count--;
lastRet = -1;
expectedModCount = modCount;
}
};
return iter;
}
public String toString() {
StringBuffer buffer = new StringBuffer("{");
Iterator iter = queue.iterator();
PriorityItem pItem;
int i = 0;
while (iter.hasNext()) {
pItem = (PriorityItem)iter.next();
if (i > 0){
buffer.append(",");
}
buffer.append(pItem.priority+":");
buffer.append(pItem.items.toString());
++i;
}
buffer.append("}");
return buffer.toString();
}
/**
* Holds a set of (int priority, LinkedList items).
* E. g. in the gruns simulator, we would use this to hold
* a time step and a list of units that is to act on this time step.
*/
protected class PriorityItem {
protected int priority;
protected LinkedList items;
protected PriorityItem(int priority) {
this.priority = priority;
items = new LinkedList();
}
public String toString() {
256
return priority+":"+items.toString();
}
}
}
257
no.uio.ifi.tools.PriorityQueue
package no.uio.ifi.tools;
public interface PriorityQueue{
/** Returns the number of elements in this priority queue */
public int getSize();
/** Tests whether this priority queue is empty */
public boolean isEmpty();
/**
* Inserts a new element
* @param key The key to access the element with (often an Integer)
* @param element The element to insert
*/
public void insertItem(Object key, Object element);
/**
* Returns (but does not remove) an element of this ordered
* queue with the smallest key. The element is not removed.
*/
public Object getMinElement();
/**
* Returns the smallest key in this priority queue.
*/
public Object getMinKey();
/**
* Removes an element with the smallest key.
*/
public Object removeMinElement();
/**
* States whether the element supplied is
* currently in the priority queue or not.
*/
public boolean contains(Object o);
/**
* States whether the element supplied is
* currently in the priority queue with the supplied int as a
* key, or not.
*/
public boolean contains(int key, Object o);
/**
* Returns a string representation of the priority queue
* (An ordered list of the elements in the queue)
*/
public String toString();
}
258
no.uio.ifi.tools.SimplePriorityQueue
package no.uio.ifi.tools;
import java.util.ArrayList;
import java.util.Arrays;
/**
* A very basic implementation of an priority queue, using
* an array to store the elements. Could be transformed
* later to e.g. use a heap instead, for performance reasons
*/
public class SimplePriorityQueue implements PriorityQueue {
/** A list containing all the elements */
protected ArrayList elements;
/** The object used to compare the elements in the list */
protected Comparator comparator;
public SimplePriorityQueue(Comparator comparator){
this.comparator = comparator;
this.elements = new ArrayList();
}
public int getSize(){
return elements.size();
}
public boolean isEmpty(){
return elements.isEmpty();
}
public void insertItem(Object key, Object element){
elements.add(new Item(key, element));
// Sort the list (just as fast, and more intuitive)
Item[] items = new Item[elements.size()];
elements.toArray(items);
Arrays.sort(items, new java.util.Comparator(){
public int compare(Object o1, Object o2){
int i1 = ((Integer) ((Item)o1).getKey()).intValue();
int i2 = ((Integer) ((Item)o2).getKey()).intValue();
if (i1 < i2) return -1;
if (i1 == i2) return 0;
if (i1 > i2) return 1;
return -17; // ERROR
}
public boolean equals(Object o){
return false;
}
});
for (int i=0; i < items.length; i++){
elements.set(i, items[i]);
}
259
}
public Object getMinElement(){
// Return null if no elements in the queue
if (isEmpty()){
return null;
}
// Be sure that the list is sorted if you just use this!
return ((Item) elements.get(0)).getElement();
//
//
// This works if the list is unsorted as well
Object item1 = elements.get(0);
Object item2;
//
//
//
//
//
//
//
//
// Loop through all the objects and find the smallest one
for (int i=1; i < elements.size(); i++) {
item2 = elements.get(i);
if (comparator.isLessThan(item2, item1)){
item1 = item2;
}
}
return ((Item) item1).getElement();
}
public Object getMinKey(){
// Return null if no elements in the queue
if (isEmpty()){
return null;
}
// Be sure that the list is sorted if you just use this!
return ((Item) elements.get(0)).getKey();
//
//
// This works if the list is unsorted as well
Object item1 = elements.get(0);
Object item2;
//
//
//
//
//
//
//
//
// Loop through all the objects and find the smallest one
for (int i=1; i < elements.size(); i++) {
item2 = elements.get(i);
if (comparator.isLessThan(item2, item1)){
item1 = item2;
}
}
return ((Item) item1).getKey();
}
public Object removeMinElement(){
// Return null if no elements in the queue
if (isEmpty()){
return null;
}
// Be sure that the list is sorted if you just use this!
Object item = elements.get(0);
260
elements.remove(0);
return ((Item) item).getElement();
//
//
// This works if the list is unsorted as well
Object item1 = elements.get(0);
Object item2;
//
//
//
//
//
//
//
// Loop through all the objects and find the smallest one
for (int i=1; i < elements.size(); i++) {
item2 = elements.get(i);
if (comparator.isLessThan(item2, item1)){
item1 = item2;
}
}
//
//
// remove the Item from the elements list
elements.remove(elements.indexOf(item1));
//
//
// Return the element
return ((Item) item1).getElement();
}
public boolean contains(Object o){
Item item;
for (int i=0; i < elements.size(); i++) {
item = (Item) elements.get(i);
if (((Item) item).getElement() == o){
return true;
}
}
return false;
}
public boolean contains(int key, Object o){
Item item;
for (int i=0; i < elements.size(); i++) {
item = (Item) elements.get(i);
if (item.getElement() == o &&
((Integer)item.getKey()).intValue() == key ){
return true;
}
}
return false;
}
public String toString(){
/*
Breaks generality
StringBuffer retString = new StringBuffer();
Item tmpItem;
Reporting tmpUnit;
retString.append("[\n");
for (int i=0; i < elements.size(); i++){
tmpItem = (Item) elements.get(i);
tmpUnit = (Reporting) tmpItem.getElement();
retString.append(" [Item: \""+tmpUnit.report()+
261
"\", scheduled at: "+tmpItem.getKey()+
"]\n");
}
retString.append("]");
return retString.toString();
*/
return "SimplePriorityQueue";
}
}
262
Download