OpenCores
URL https://opencores.org/ocsvn/an-fpga-implementation-of-low-latency-noc-based-mpsoc/an-fpga-implementation-of-low-latency-noc-based-mpsoc/trunk

Subversion Repositories an-fpga-implementation-of-low-latency-noc-based-mpsoc

[/] [an-fpga-implementation-of-low-latency-noc-based-mpsoc/] [trunk/] [mpsoc/] [src_c/] [synfull/] [traffic-generator/] [src/] [TrafficGenerator.cpp] - Rev 54

Compare with Previous | Blame | View Log

/* 
Copyright (c) 2014, Mario Badr
All rights reserved.
 
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
 
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
 
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
 * TrafficGenerator.cpp
 *
 *  Created on: 2013-01-13
 *      Author: mario
 */
 
#include <iostream>
#include <list>
#include <math.h>
 
#include "assert.h"
#include <map>
#include <list>
#include <set>
 
#include "socketstream.h"
#include "messages.h"
#include "Global.h"
 
#include "PacketQueue.h"
 
using namespace std;
 
//Set this to 0 to debug without connecting to booksim
#define CONNECT 1
 
SocketStream m_channel;
 
static unsigned long long next_interval;
static unsigned long long next_hinterval;
 
static unsigned long long cycle;
 
static unsigned long int total_pck_queud=0;
 
int state = 1;
int lastState = 1;
int lastHState = 1;
 
int messageId = 0;
 
int allPacketsEjected=0;
 
//Steady state
map<int, map<int, int> > steadyState;
map<int, int> hSteadyState;
map<int, double> acceptable_mse;
double acceptable_hmse;
 
struct transaction_t {
    int source;
    int dest;
    int invs_sent;
    int acks_received;
    bool data_received;
    bool unblock_received;
 
    bool Completed() {
        return (invs_sent == acks_received) && data_received && unblock_received;
    }
 
    transaction_t() : source(-1), dest(-1), invs_sent(0), acks_received(0),
            data_received(false), unblock_received(false) {}
};
 
map<int, InjectReqMsg> inTransitPackets;
map<int, transaction_t> inTransitTransactions;
PacketQueue packet_queue;
 
void TranslateIndex(int index, int& source, int& destination) {
    source = (int) index / 32; //Truncate remainder
    destination = index - (source * 32);
}
 
void printPacket(InjectReqMsg msg) {
    cout << msg.id << " ";
    cout << cycle << " ";
    cout << msg.source << " ";
    cout << msg.dest << " ";
    cout << msg.packetSize << " ";
    cout << msg.msgType << " ";
    cout << msg.coType << " ";
    cout << msg.address << " ";
    cout << state;
    cout << endl;
}
 
void connect() {
#if CONNECT
    // connect to network simulator
    assert(m_channel.connect(NS_HOST, NS_PORT) == 0);
 
    // send request to initialize
    InitializeReqMsg req;
    InitializeResMsg res;
    m_channel << req >> res;
#endif
}
 
void exit() {
	cout << "Total packet sent to queue: " << total_pck_queud << endl;
#if CONNECT
    // Notify network we are quitting
    QuitReqMsg req;
    QuitResMsg res;
    m_channel << req >> res;
#endif
}
 
void sendPacket(InjectReqMsg& req) {
    req.id = messageId;
 
    if((int) req.address == -1) {
        req.address = messageId;
        inTransitTransactions[req.address].source = req.source;
        inTransitTransactions[req.address].dest = req.dest;
        inTransitTransactions[req.address].invs_sent = 0;
        inTransitTransactions[req.address].acks_received = 0;
    }
    messageId++;
 
    inTransitPackets[req.id] = req;
 
#if CONNECT
    InjectResMsg res;
 
    m_channel << req >> res;
#endif
}
 
double calculate_mse(vector<double> predict, vector<double> actual) {
    if(predict.size() != actual.size()) {
        return -1;
    }
 
    double sum = 0;
    for(unsigned int i = 0; i < predict.size(); i++) {
        sum += (predict[i] - actual[i]) * (predict[i] - actual[i]);
    }
 
    return ((double) sum / predict.size());
}
 
bool InHSteadyState(int numCycles) {
    vector<double> predict;
    int sum = 0;
    for (map<int, int>::iterator it=hSteadyState.begin();
            it!=hSteadyState.end(); ++it) {
        double value =  it->second;
        sum+= value;
        predict.push_back(value);
    }
 
    for(unsigned int i = 0; i < predict.size(); i++) {
        predict[i] = ((double) predict[i] / sum);
    }
 
    double mse = calculate_mse(predict, g_hierSState);
    if(mse >= 0 && mse < acceptable_hmse && cycle > numCycles*0.3) {
        return true;
    }
 
    if(cycle > numCycles*0.7) {
        return true;
    }
 
    return false;
}
 
 
 
void QueuePacket(int source, int destination, int msgType, int coType,
        int packetSize, int time, int address) {
    InjectReqMsg packet;
    packet.source = source;
    packet.dest = destination;
    packet.cl = 0;
    packet.network = 0;
    packet.packetSize = packetSize;
    packet.msgType = msgType;
    packet.coType = coType;
    packet.address = address;
 
    packet_queue.Enqueue(packet, time);
    total_pck_queud++;
}
 
void UniformInject(int writes, int reads, int ccrs, int dcrs) {
    int source, destination;
    UniformDistribution uni_dist(0, g_resolution/2 -1);
 
    int delta = 0;
 
    for(int i = 0; i < writes; i++) {
        delta = uni_dist.Generate(0) * 2;
        source = g_writeSpat[g_hierClass][state].Generate(0);
        source = source * 2;
 
        destination = g_writeDest[g_hierClass][state][source].Generate(0);
        destination = destination * 2 + 1;
 
        QueuePacket(source, destination, REQUEST, WRITE, CONTROL_SIZE,
                cycle + delta, -1);
    }
 
    for(int i = 0; i < reads; i++) {
        delta = uni_dist.Generate(0) * 2;
        source = g_readSpat[g_hierClass][state].Generate(0);
        source = source * 2;
 
        destination = g_readDest[g_hierClass][state][source].Generate(0);
        destination = destination * 2 + 1;
 
        QueuePacket(source, destination, REQUEST, READ, CONTROL_SIZE,
                cycle + delta, -1);
    }
 
    for(int i = 0; i < ccrs; i++) {
        delta = uni_dist.Generate(0) * 2;
        source = g_ccrSpat[g_hierClass][state].Generate(0);
        source = source * 2;
 
        destination = g_ccrDest[g_hierClass][state][source].Generate(0);
        destination = destination * 2 + 1;
 
        QueuePacket(source, destination, REQUEST, PUTC, CONTROL_SIZE,
                cycle + delta, -1);
    }
 
    for(int i = 0; i < dcrs; i++) {
        delta = uni_dist.Generate(0) * 2;
        source = g_dcrSpat[g_hierClass][state].Generate(0);
        source = source * 2;
 
        destination = g_dcrDest[g_hierClass][state][source].Generate(0);
        destination = destination * 2 + 1;
 
        QueuePacket(source, destination, REQUEST, PUTD, DATA_SIZE,
                cycle + delta, -1);
    }
}
 
//Volumes
void InitiateMessages() {
    int writes = g_writes[g_hierClass][state].Generate(0);
    int reads = g_reads[g_hierClass][state].Generate(0);
    int ccrs = g_ccrs[g_hierClass][state].Generate(0);
    int dcrs = g_dcrs[g_hierClass][state].Generate(0);
 
    //cout << "synfull: writes " << writes << " reads " << reads << " ccrs " << ccrs << " dcrs " << dcrs  << endl;
    UniformInject(writes, reads, ccrs, dcrs);
}
 
void Inject() {
    list<InjectReqMsg> packets = packet_queue.DeQueue(cycle);
    list<InjectReqMsg>::iterator it;
 
    for(it = packets.begin(); it != packets.end(); ++it) {
        sendPacket(*it);
    }
 
    packet_queue.CleanUp(cycle);
}
 
void react(EjectResMsg ePacket) {
    map<int, InjectReqMsg>::iterator it = inTransitPackets.find(ePacket.id);
    if(it == inTransitPackets.end()) {
        cerr << "Error: couldn't find in transit packet " << ePacket.id << endl;
        exit(-1);
    }
 
    InjectReqMsg request = it->second;
    InjectReqMsg response;
    inTransitPackets.erase(it);
 
    //cout << "synfull received packet id: " << request.id << " " << cycle  << endl;
 
 
    map<int, transaction_t>::iterator trans = inTransitTransactions.find(request.address);
 
    if(request.msgType == REQUEST &&
            (request.coType == WRITE || request.coType == READ)) {
        //Handle Read/Write Requests
        if((int) request.address == request.id) {
            //This is an initiating request. Should we forward it or go to
            //memory?
            bool isForwarded = g_toForward[g_hierClass][request.dest][request.coType].Generate(0) == 0;
 
            if(isForwarded) {
                int destination = g_forwardDest[g_hierClass][state][request.dest].Generate(0);
                destination = destination*2;
                if(destination % 2 != 0) {
                    cerr << "Error: Invalid destination for forwarded request." << endl;
                    exit();
                }
 
                QueuePacket(request.dest, destination, REQUEST, request.coType,
                        CONTROL_SIZE, cycle + 1, request.address);
 
                if(request.coType == WRITE) {
                    //How many invalidates to send
                    int numInv = g_numInv[g_hierClass][state][request.dest].Generate(0);
                    int s = state;
 
                    if(numInv <= 0) {
                        return;
                    }
 
                    //Ensure invalidate destinations are unique (i.e. no two
                    //invalidate messages to the same destination)
                    set<int> destinations;
                    destinations.insert(destination); //Request already forwarded here
                    while(destinations.size() != (unsigned int) numInv) {
                        int dest = g_invDest[g_hierClass][s][request.dest].Generate(0);
                        dest = dest*2;
                        destinations.insert(dest);
                    }
 
                    for(set<int>::iterator it = destinations.begin();
                            it != destinations.end(); ++it) {
                        QueuePacket(request.dest, *it, REQUEST, INV,
                                CONTROL_SIZE, cycle + 1, request.address);
                        trans->second.invs_sent++;
                    }
                }
 
            } else {
                //Access memory, queue up a data response for the future
                    //cout << "synfull mem access  id: " << request.id << " src:"<< request.source 
                    //    << " dst:" << request.dest << " addr:" << request.address 
                    //    << " " << cycle  << endl;
                QueuePacket(request.dest, request.source, RESPONSE, DATA,
                        DATA_SIZE, cycle + 80, request.address);
            }
 
            return;
        } else {
            //This is not an initiating request, so it's a forwarded request
            //if(request.id==52)
            //{
            //    cout << "synfull packet debug  id: " << request.id << " src:"<< request.dest 
            //        << " dst:" << trans->second.source << 
            //           " addr:" << request.address << " " << cycle  << endl;
            //}
 
            //Respond with Data
            QueuePacket(request.dest,
                    trans->second.source, RESPONSE,
                    DATA, DATA_SIZE, cycle + 1, request.address);
        }
    } 
    else if(request.msgType == REQUEST &&
            (request.coType == PUTC || request.coType == PUTD)) {
        //Respond with WB_ACK
        QueuePacket(request.dest, request.source, RESPONSE, WB_ACK,
                CONTROL_SIZE, cycle + 1, request.address);
 
    }
    else if(request.msgType == REQUEST && request.coType == INV) {
        //Respond with Ack
        QueuePacket(request.dest, trans->second.source,
                RESPONSE, ACK, CONTROL_SIZE, cycle + 1, request.address);
    } else if(request.msgType == RESPONSE && request.coType == DATA) {
        trans->second.data_received = true;
        //Send unblock
        QueuePacket(inTransitTransactions[request.address].source,
                inTransitTransactions[request.address].dest, RESPONSE, UNBLOCK,
                CONTROL_SIZE, cycle + 1, request.address);
    } else if(request.msgType == RESPONSE && request.coType == ACK) {
        trans->second.acks_received++;
    } else if(request.msgType == RESPONSE && request.coType == UNBLOCK) {
                trans->second.unblock_received = true;
        }
 
    if(trans->second.Completed()) {
        inTransitTransactions.erase(trans);
    }
}
 
unsigned long long int cntPackets = 0;
 
void Eject(unsigned int numPackets) {
#if CONNECT
    EjectReqMsg req; //The request to the network
    EjectResMsg res; //The response from the network
    bool hasRequests = true; //Whether there are more requests from the network
 
    //Loop through all the network's messages
    while(hasRequests) {
        m_channel << req >> res;
 
        if(res.id >= 0) {
            //Add responses to list
            if(res.id > -1) {
                cntPackets++;
                react(res);
            }
        }
        //Check if there are more messages from the network
        hasRequests = res.remainingRequests;
 
    }
 
        if (cntPackets == numPackets) 
        {
            allPacketsEjected=1;
        }
#endif
}
 
void reset_ss() {
    for (std::map<int,int>::iterator it=steadyState[g_hierClass].begin();
            it!=steadyState[g_hierClass].end(); ++it) {
        it->second = 0;
    }
    state = 1;
}
 
void Run(unsigned int numCycles, bool ssExit, unsigned int numPackets) {
    next_interval = 0;
    next_hinterval = 0;
 
    //Calculate an acceptable MSE for the Markovian Steady-State
    double sensitivity = 1.04;
    vector<double> predict;
    for (unsigned int i = 0; i < g_hierSState.size(); i++) {
        predict.push_back(((double) g_hierSState[i] * sensitivity));
    }
    acceptable_hmse = calculate_mse(predict, g_hierSState);
 
    //Connect to network simulator
    connect();
 
        //Iterate through each cycle and inject packets
        for(cycle = 0; cycle < numCycles; ++cycle) {
            if(cycle >= next_hinterval) {
                next_hinterval += g_timeSpan;
 
                hSteadyState[g_hierClass]++;
 
                if(cycle != 0) {
                    lastHState = g_hierClass;
                    g_hierClass = g_hierState[g_hierClass].Generate(0) + 1;
                    reset_ss();
                }
 
                if(InHSteadyState(numCycles) && ssExit) {
                    cout << "Ending simulation at steady state: " << cycle << endl;
                    break;
                }
 
                cout << "Current hierarchical state: " << g_hierClass << endl;
            }
 
            if(cycle >= next_interval) {
                next_interval += g_resolution;
 
                //Track state history for markovian steady state
                steadyState[g_hierClass][state]++;
 
                if(cycle != 0) {
                    //Update state
                    lastState = state;
                    state = g_states1[g_hierClass][state].Generate(0) + 1;
                }
 
                //Queue up initiating messages for injection
                InitiateMessages();
            }
 
            //Inject all of this cycles' messages into the network
            Inject();
 
            //Eject from network
            Eject(numPackets);
 
            if (allPacketsEjected) 
            {
                cycle = numCycles; 
            }
            //Step the network
#if CONNECT
            StepReqMsg req;
            StepResMsg res;
            m_channel << req >> res;
#endif
        }
 
    //Close the connection
    exit();
}
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.