It is not anything API related in this program. All it does is finding the
numerical results, but it had many classes which I would be interested to
look into when the program is running.
I tried step into and step over... but you are right. After I press servral
times of F10 (step into F11), I see a bunch of machine code.
that will show you the assembler code that implements your source code.
May i show you how it is like? you do not need to look what this program
does. I would like to know if VC++ debugger will allow me to see through
the program statement by statement in this program.
Thank you
#include <stdlib.h> //directives needed for this program
#include <limits.h>
#include <math.h>
#include <iostream.h>
#include <iomanip.h>
#include <assert.h>
#define DATA_UNIT 53 // data length unit
#define FRAME_LENGTH 32*24 // bytes/frame, 768 bytes
// [bitrate=2Mbps;frame period = 3msec
#define FRAME_TIME 3 // [msec]
#define OVER_HEAD 6 // mini slot size
#define NUM_OF_MINISLOT 3
#define MAX_TRANS_QUEUE 1000 //default
#define ALL_TERMINAL_QUEUE 32768L //default maximum for random
////////////////////////////////////////////////////////////////////////////
///////////////////////////
////////////////////////////////////////////////////////////
// Random Generator Class
//
// This class is for generation of random numbers
..
////////////////////////////////////////////////////////////
class CRandom {
unsigned long Seed;
public:
CRandom(unsigned long x=1L) : Seed(x) {}
unsigned long IRand(void); // long interger random
double RRand(void); // 0.0-1.0 random
double ExpRand(void); // 0.0-1.0 exponentail distribution
random
};
inline unsigned long CRandom::IRand(void) // use inline for small but
{ //frequently used function
Seed = Seed * 1566083941UL + 1;
return(Seed);
}
inline double CRandom::ExpRand(void)
{
return(-log(1.0 - RRand()));
}
inline double CRandom::RRand(void)
{
return((1.0 / (ULONG_MAX + 1.0)) * IRand());
}
////////////////////////////////////////////////////////////////////////////
/////////////////////////////
////////////////////////////////////////////////////////////
// Performance Monitor Class
//
// This class is for monitor of the number of transmitted
// packets and their delay.
////////////////////////////////////////////////////////////
class CMonitor {
double TotalPacket;
double TotalDelay;
double TotalDelaySqr;
public:
CMonitor() :
TotalPacket(0), TotalDelay(0), TotalDelaySqr(0) {} //public that can
be accessed from other functions
void Initialize(void);
void CheckPerformance(double);
double GetNumOfTotalPacket(void) const;
double GetDelay(void) const;
double GetDelayVariance(void) const;
};
inline double CMonitor::GetNumOfTotalPacket(void) const
{
return(TotalPacket);
}
inline double CMonitor::GetDelay(void) const
{
return (TotalPacket > 0) ? TotalDelay/TotalPacket : 0;
}
inline double CMonitor::GetDelayVariance(void) const
{
return (TotalPacket > 0) ?
sqrt(TotalDelaySqr/TotalPacket -
TotalDelay*TotalDelay/TotalPacket/TotalPacket) : 0;
}
void CMonitor::Initialize(void) //recursion call #1
{
TotalPacket = 0;
TotalDelaySqr = 0;
TotalDelay = 0;
}
void CMonitor::CheckPerformance(double Delay) //call #2
{
TotalPacket += 1;
Delay += DATA_UNIT; // Add Transmission Delay
TotalDelay += Delay;
TotalDelaySqr += Delay * Delay;
}
////////////////////////////////////////////////////////////
// Packet Structure Definition, reference from p.347 of
// h.m. deitel/p.j deitel "How to program in C++"
//
struct CPacket {
int Size; //member types
double Time;
CPacket() : Size(0), Time(0) {}
};
////////////////////////////////////////////////////////////////////////////
/////////////
////////////////////////////////////////////////////////////
// Terminal Class
//
// This class discribes the behavior of each terminal,
// such as queuing and transmission of packets.
//
////////////////////////////////////////////////////////////////////////////
/////////////
class CTerminal {
int QueueSize;
CPacket* Queue;
int wp; //dummy variable wp, rp
int rp;
int NumOfPacket;
int NumOfReserved;
public:
CTerminal():
Queue(NULL), QueueSize(0), wp(0), rp(0),
NumOfPacket(0), NumOfReserved(0) {}
~CTerminal() {delete [] Queue;}
void Initialize(int queue_size);
int CheckBuffer(void) const;
int PacketArrival(const CPacket&);
void ChannelReserve(void);
void ChannelAllocate(double Time, CMonitor* Monitor=NULL);
private:
CTerminal(const CTerminal&);
CTerminal& operator = (const CTerminal&);
};
inline int CTerminal::CheckBuffer(void) const
{
return (NumOfPacket > NumOfReserved) ?
(NumOfPacket - NumOfReserved) : 0; //checking the buffer
size, if needed
}
inline void CTerminal::ChannelReserve(void)
{
NumOfReserved++;
}
void CTerminal::Initialize(int queue_size)
{
assert(queue_size > 0);
QueueSize = queue_size;
wp = 0;
rp = 0;
NumOfPacket = 0;
NumOfReserved = 0;
delete [] Queue;
if (NULL == (Queue = new CPacket[QueueSize])) {
cerr << "Memory Allocation Error in CTerminal" << endl;
exit(-1);
}
}
int CTerminal:
acketArrival(const CPacket& Packet) //this describes the
packet arriving
{ //to one terminal and check for overflow
if (Packet.Size > 0) {
if ((rp - wp - 1 + QueueSize) % QueueSize != 0) {
Queue[wp] = Packet;
NumOfPacket += Queue[wp].Size;
wp = (wp + 1) % QueueSize;
return(1); //hang the program
} else {
cerr << "Packet User Queue Over Flow!!!" << endl;
}
}
return(0);
}
void CTerminal::ChannelAllocate(double Time, CMonitor* Monitor)
{
if (--NumOfReserved < 0) {
cerr << "reservation error in Terminal" << endl;
exit(-1);
}
if (rp != wp) {
const double Delay = Time - Queue[rp].Time;
Queue[rp].Size -= 1;
NumOfPacket -= 1;
if (Monitor) {
Monitor->CheckPerformance(Delay);
}
if (Queue[rp].Size == 0) {
rp = (rp + 1) % QueueSize;
}
}
}
////////////////////////////////////////////////////////////////////////////
/////////////////
////////////////////////////////////////////////////////////
// Traffic Source Class
//
// This class discribes the behavior of traffic source.
// Call GenerateTraffic function to generate packets
// and set them to each terminal.
/////////////////////////////////////////////////////////////
class CSource {
int NumOfTerminal;
CTerminal* Terminal;
double NextEventTime;
double AveArrivalTime;
double AveServiceTime;
CRandom NodeRand;
CRandom ArrivalRand;
CRandom ServiceRand;
public:
CSource():
NumOfTerminal(0), Terminal(NULL),
NextEventTime(0), AveArrivalTime(0), AveServiceTime(0),
NodeRand(rand()), ArrivalRand(rand()), ServiceRand(rand()) {}
void Association(int, CTerminal[]);
void SetParameter(double, double);
int GenerateTraffic(double);
};
void CSource::Association(int n, CTerminal terminal[])
{
assert(n > 0);
NumOfTerminal = n;
Terminal = terminal;
}
void CSource::SetParameter(double arrival, double service)
{
assert(arrival > 0 && service > 0);
AveArrivalTime = arrival;
AveServiceTime = service;
NextEventTime += AveArrivalTime * ArrivalRand.ExpRand(); //packet
arrival
}
int CSource::GenerateTraffic(double Time)
{
int n=0;
while (NextEventTime < Time) {
CPacket Packet;
Packet.Size = ceil(AveServiceTime * ServiceRand.ExpRand());
Packet.Time = NextEventTime;
NextEventTime += AveArrivalTime * ArrivalRand.ExpRand();
int No = NodeRand.IRand() % NumOfTerminal;
if (No < 0) {
No = 0;
} else if (No >= NumOfTerminal) {
No = NumOfTerminal - 1;
}
Terminal[No].PacketArrival(Packet);
n++;
}
return(n);
}
////////////////////////////////////////////////////////////////////////
// Reservation Queue Class
//
// This class discribes the behavior of Reservation Queue.
// Call SetLeaf and MakeTree functions to make up a contention tree.
// Then, call Pop function to get a contention result of each mini slot.
//
// Reference class with some modifications
// Still need time to modify this class, Collision at a junction point?
//
////////////////////////////////////////////////////////////////////////
class CReservationQueue {
enum {IDLE=0, BUSY=1, COLLISION=2};
typedef unsigned char NodeData;
struct Position {int x, y;};
private:
int Height;
NodeData** Node;
int Depth;
int Ptr;
Position* Stack;
public:
CReservationQueue():
Height(0), Node(NULL), Depth(0), Ptr(0), Stack(NULL) {}
~CReservationQueue();
void Initialize(int);
void SetLeaf(int i, int n);
void MakeTree(void);
int Pop(int&);
protected:
int PushBranch(int, int);
int PopBranch(int&, int&);
private:
CReservationQueue(const CReservationQueue&);
CReservationQueue& operator = (const CReservationQueue&);
};
inline void CReservationQueue::SetLeaf(int i, int n)
{
Node[Height]
= (n > 0) ? BUSY : IDLE;
}
CReservationQueue::~CReservationQueue()
{
if (Node) {
for (int i=0;i<=Height;i++) {
delete [] Node;
}
}
delete [] Node;
delete [] Stack;
}
void CReservationQueue::Initialize(int n)
{
assert(n > 0);
if (Node) {
for (int i=0;i<=Height;i++) {
delete [] Node;
}
}
delete [] Node;
delete [] Stack;
Height = n;
Depth = n + 1;
Ptr = 0;
if (NULL == (Stack = new Position[Depth]) || NULL == (Node = new
NodeData*[Height+1])) {
cerr << "Memory Allocation Error in CReservationQueue" << endl;
exit(-1);
}
int NumOfNode = 1;
for (int i=0;i<=Height;i++) {
if (NULL == (Node = new NodeData[NumOfNode])) {
cerr << "Memory Allocation Error in CReservationQueue" << endl;
exit(-1);
}
for (int j=0;j<NumOfNode;j++) Node[j] = IDLE;
NumOfNode *= 2;
}
}
void CReservationQueue::MakeTree(void)
{
static const NodeData TABLE[3][3] // status of the three minislot
= { {IDLE, BUSY, COLLISION},
{BUSY, COLLISION, COLLISION},
{COLLISION, COLLISION, COLLISION} };
int NumOfNode = 1;
for (int i=0;i<Height-1;i++) NumOfNode *= 2;
for (i=Height-1;i>=0;i--) {
for (int j=0;j<NumOfNode;j++) { //with help of a freind
NodeData Left = Node[i+1][j*2];
NodeData Right = Node[i+1][j*2+1];
Node[j] = TABLE;
}
NumOfNode /= 2;
}
Ptr = 0;
if (Node[0][0] != IDLE) {
PushBranch(0, 0);
}
}
int CReservationQueue:
ushBranch(int x, int y)
{
if (Ptr < Depth) {
Stack[Ptr].x = x;
Stack[Ptr].y = y;
Ptr++;
return(1);
} else {
cerr << "Reservation Queue Over Flow!!!" << endl;
return(0);
}
}
int CReservationQueue:
opBranch(int& x, int& y)
{
if (Ptr > 0) {
Ptr--;
x = Stack[Ptr].x;
y = Stack[Ptr].y;
return(1);
} else {
return(0);
}
}
int CReservationQueue:
op(int& adr)
{
int x, y;
if (PopBranch(x, y)) {
if (Node[x][y] == COLLISION) {
PushBranch(x+1, 2*y+1);
PushBranch(x+1, 2*y);
adr = -1;
} else if (Node[x][y] == BUSY) {
while (x < Height) {
x++;
y*=2;
if (Node[x][y] == IDLE) y++;
}
if (Node[x][y] != BUSY) {
cerr << "Reservation Queue Pop Error!!!" << endl;
}
adr = y;
} else {
adr = -2;
}
} else {
adr = -3;
}
return (Ptr > 0);
}
////////////////////////////////////////////////////////////////////////////
///////////////////////
///////////////////////////////////////////////////////////////
// Transmission Queue Class
//
// This class discribes the behavior of Transmission Queue.
// This is a simple FIFO queue.
// Call Push function to push a node number which succeeds in
// mini slot access.
// Call Pop function to get a node number which can send data
// in each data slot.
//
////////////////////////////////////////////////////////////////
class CTransmissionQueue {
int* Queue;
int MaxQueue;
int wp, rp;
public:
CTransmissionQueue():Queue(NULL), MaxQueue(0), wp(0), rp(0) {}
~CTransmissionQueue() {delete [] Queue;}
void Initialize(int);
int IsFull(void) const;
int Push(int);
int Pop(int&);
private:
CTransmissionQueue(const CTransmissionQueue&);
CTransmissionQueue& operator = (const CTransmissionQueue&);
};
inline int CTransmissionQueue::IsFull(void) const //Call IsFull function to
check whether queue
{
return ((rp-wp-1+MaxQueue) % MaxQueue == 0); //is full or not.
}
void CTransmissionQueue::Initialize(int n)
{
assert(n > 0);
MaxQueue = n;
wp = rp = 0;
delete [] Queue;
if (NULL == (Queue = new int[MaxQueue])) {
cerr << "Memory Allocation Error in CTransmissionQueue" << endl;
exit(-1);
}
}
int CTransmissionQueue:
ush(int n)
{
if ((rp - wp - 1 + MaxQueue) % MaxQueue != 0) {
Queue[wp] = n;
wp = (wp + 1) % MaxQueue;
return(1);
} else {
cerr << "Transmission Queue Over Flow!!!" << endl;
return(0);
}
}
int CTransmissionQueue:
op(int& n)
{
if (wp != rp) {
n = Queue[rp];
rp = (rp + 1) % MaxQueue;
return(1);
} else {
return(0);
}
}
////////////////////////////////////////////////////////////
// Controller Class
//
// This class discribes the behavior of controller.
// Call Schedule function for each slot access.
//
/////////////////////////////////////////////////////////////
class CController {
CSource* Source;
int NumOfTerminal;
CTerminal* Terminal;
int MiniSlot;
CReservationQueue RsrvQueue;
CTransmissionQueue TrnsQueue;
public:
CController(int mini_slot):
Source(NULL), NumOfTerminal(0), Terminal(NULL), MiniSlot(mini_slot)
{}
~CController() {}
void Association(CSource&, int, CTerminal[]);
int Schedule(double Time, CMonitor* Monitor=NULL);
private:
CController(const CController&);
CController& operator = (const CController&);
};
void CController::Association(CSource& source, int n, CTerminal terminal[])
{
assert(n > 0 && n < 15);
Source = &source;
NumOfTerminal = 1;
for (int i=0;i<n;i++) NumOfTerminal *= 2;
Terminal = terminal;
RsrvQueue.Initialize(n);
TrnsQueue.Initialize(MAX_TRANS_QUEUE);
}
int CController::Schedule(double Time, CMonitor* Monitor) //modified by
KinHo Wong
{
static int IsNextPacket=1;
int No;
if (TrnsQueue.Pop(No)) {
Terminal[No].ChannelAllocate(Time, Monitor);
}
for (int i=0;i<MiniSlot;i++) {
if (!TrnsQueue.IsFull()) {
int next = RsrvQueue.Pop(No);
if (No >= 0) {
Terminal[No].ChannelReserve();
TrnsQueue.Push(No);
}
if (next == 0)
{
int IsNewPacket =
Source->GenerateTraffic(Time+DATA_UNIT+i*OVER_HEAD);
if (IsNextPacket || IsNewPacket) {
IsNextPacket = 0;
for (int j=0;j<NumOfTerminal;j++) {
int k = Terminal[j].CheckBuffer();
RsrvQueue.SetLeaf(j, k);
if (!IsNextPacket && k > 1) IsNextPacket = 1;
}
RsrvQueue.MakeTree();
}
}
}
}
return (MiniSlot * OVER_HEAD + DATA_UNIT);
}
////////////////////////////////////////////////////////////////////////////
//////////////////////////////
////////////////////////////////////////////////////////////////////////
// CSimulation Class
//
// This class discriber the behavior of all simulation.
// CSource, CTerminal, and CController class are associated
// and Simulation is executed.(Still working on this as on 5/8/2003
****************************
//
////////////////////////////////////////////////////////////////////////
class CSimulation {
long FrameLength;
CSource Source;
int NumOfTerminal;
CTerminal* Terminal;
CController Controller;
CMonitor Monitor;
public:
CSimulation() :
FrameLength(0), NumOfTerminal(0), Terminal(NULL),
Controller(NUM_OF_MINISLOT) {}
~CSimulation() {delete [] Terminal;}
void Initialize(int, long);
void Run(long, int, double, double);
private:
CSimulation(const CSimulation&);
CSimulation& operator = (const CSimulation&);
};
void CSimulation::Initialize(int n, long frame_length)
{
assert(n > 0 && n < 15);
FrameLength = frame_length;
NumOfTerminal = 1;
for (int i=0;i<n;i++) NumOfTerminal *= 2;
delete [] Terminal;
if (NULL == (Terminal = new CTerminal[NumOfTerminal])) {
cerr << "Memory Allocation Error in CSimulation" << endl;
exit(-1);
}
int QueueSize = ALL_TERMINAL_QUEUE / NumOfTerminal;
for (i=0;i<NumOfTerminal;i++) {
Terminal
.Initialize(QueueSize);
}
Source.Association(NumOfTerminal, Terminal);
Controller.Association(Source, n, Terminal);
}
void CSimulation::Run(long MaxFrame, int Interval,
double PacketAveArvlTime, double PacketAveSize)
{
double Time;
long Frame;
long UsedBandWidth;
long n;
Source.SetParameter(PacketAveArvlTime, PacketAveSize);
cout << "F\tS\tD1\tD2\tDV1\tDV2\n";
Time = 0;
n = 0L;
for (Frame=0L;Frame<MaxFrame;Frame++) {
n += FrameLength;
while (n > 0) {
UsedBandWidth = Controller.Schedule(Time, &Monitor);
Time += UsedBandWidth;
n -= UsedBandWidth;
}
if (Frame % Interval == 0)
{
cout << Frame;
cout << "\t" << (Monitor.GetNumOfTotalPacket()*DATA_UNIT/Time);
cout << "\t" << Monitor.GetDelay()/DATA_UNIT;
cout << "\t" << Monitor.GetDelay()/FrameLength*FRAME_TIME;
cout << "\t" << Monitor.GetDelayVariance()/DATA_UNIT;
cout << "\t" <<
Monitor.GetDelayVariance()/FrameLength*FRAME_TIME;
cout << endl;
}
}
cout << setiosflags(ios::fixed) << setprecision(3);
cout << Frame;
cout << "\t" << (Monitor.GetNumOfTotalPacket()*DATA_UNIT/Time);
cout << "\t" << Monitor.GetDelay()/DATA_UNIT;
cout << "\t" << Monitor.GetDelay()/FrameLength*FRAME_TIME;
cout << "\t" << Monitor.GetDelayVariance()/DATA_UNIT;
cout << "\t" << Monitor.GetDelayVariance()/FrameLength*FRAME_TIME;
cout << endl;
cout << "%\tF=Frame\n";
cout << "%\tS=Throughput\n";
cout << "%\tD1=Delay[cells] D2=Delay[ms]\n";
cout << "%\tDV1=Delay Variance[cells] DV2=Delay Variance[ms]\n";
cout << flush;
}
////////////////////////////////////////////////////////////////////////////
////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////
//
// main(void)
//
//
////////////////////////////////////////////////////////////////////////////
////////////////////
int main(void)
{
int n;
double MaxFrame;
double PacketAveSize;
double TrafficLoad;
int Interval;
MaxFrame = 10;
n = 4;
PacketAveSize = 3;
TrafficLoad = 0.6;
Interval = 2;
if (MaxFrame <= 0 || n <= 0 || n >= 15 || PacketAveSize <= 0 ||
TrafficLoad <= 0 || TrafficLoad >= 1) {
cerr << "Parameter Error" << endl;
return(-1);
}
int NumOfTerminal = 1;
for (int i=0;i<n;i++) NumOfTerminal*=2;
double PacketAveArvlTime = PacketAveSize * DATA_UNIT / TrafficLoad;
cout << "% DQRAP Simulation\n";
cout << setiosflags(ios::fixed) << setprecision(4);
cout << "% Num.of.Terminals:" << setw(20);
cout << NumOfTerminal << endl;
cout << "% Max.Sim.Frames: " << setw(20);
cout << MaxFrame << endl;
cout << "% Num.of.Ave.Cells:" << setw(20);
cout << PacketAveSize << endl;
cout << "% Data.Arrvl.Intvl:" << setw(20);
cout << (PacketAveArvlTime/DATA_UNIT) <<endl;
CSimulation Sim;
Sim.Initialize(n, FRAME_LENGTH);
Sim.Run(MaxFrame, Interval, PacketAveArvlTime, PacketAveSize);
return(0);
}