/*
http://t...content-available-to-author-only...h.net/test/read.cgi/tech/1342966104/12
課題1 サーバにアクセスが集中する場合のシミュレーション
ここではVirtual Output Queuing構成のハブをシミュレーションする。設定は
以下のようにする:
●ポート数は4.ポート0にはサーバが,残りのポート1〜ポート3にはクライアン
トが接続されている.
●パケットの入出力やスイッチにおけるパケット転送はクロック単位で同期し
ている.
●入力ポートからスイッチへの,またスイッチから出力ポートへの転送は1クロッ
クにつきPパケット.
●サーバが接続するポート0にパケットが到着する平均時間間隔はTa,その他の
ポートに到着する平均時間間隔は3Taでいずれも指数分布に従う.
●ポート0に到着するパケットの宛先ポートはポート1〜ポート3まで等確率でラ
ンダムに選ぶ. その他のポートから来るパケットの宛先は,確率1/2でポート0,
残りは他のポートに等確率(つまり他のクライアントポートに1/4ずつの確率)
であるとする.
●Tクロックの間動作をさせる.
Ta=1,T=1000,P=1として実行し,全てのパケットに対する転送遅延(入力ポート
に入ってから出力ポートに出ていくまでの時間)の最大値と平均値を求めよ.
課題2 帯域幅の増加ポート数やサーバ配置,パケット数などは課題1と同等とす
る. ただし,ポート0を流れるパケット数が多いことは容易に想像できるため,こ
こだけ帯域幅を2とする(つまり,入力ポート0は1クロックに2個のパケットを受
けとることができ,また出力ポート0は1クロックに2個のパケットを送り出すこ
とができるものとする).
Ta=1,T=1000,P=1として実行し,全てのパケットに対する転送遅延(入力ポート
に入ってから出力ポートに出ていくまでの時間)の最大値と平均値を求めよ.
参考プログラム: http://i...content-available-to-author-only...e.com/T3e0j
*/
#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<vector>
#include<deque>
using namespace std;
typedef vector< vector<double> > Matrix;
//隣接行列がgraphであるようなグラフにおいて、startからgoalまで幅優先探索を行う。
//goalまでたどりつけばtrue、たどりつけなければfalseを返す。
//trueが返るときには、prevに「直前の頂点」の情報が入っている。
bool bfs(const vector<vector<int> > &graph, int start, int goal, vector<int> &prev)
{
const int n = graph.size(); //n:グラフの頂点数
//「直前の頂点」の情報をクリア
for(int i = 0; i < n; ++i){
prev[i] = -1;
}
//アルゴリズムの都合上、出発点の「直前」は出発点自身とする:
prev[start] = start;
//「まだたどってない頂点」をキューで管理する。最初は出発点だけ。
deque<int> frontier;
frontier.push_back(start);
//キューに頂点が残っていたらループ
while(! frontier.empty()){
int vertex = frontier[0];
frontier.pop_front();
//目的地に到達していれば終わり
if(vertex == goal){
return true;
}
//「次にたどるべき頂点」をキューに追加する
for(int next = 0; next < n; ++next){
//はじめて見る頂点で今の頂点から行けるものをキューに追加
if(prev[next] == -1 && graph[vertex][next] > 0){
prev[next] = vertex;
frontier.push_back(next);
}
}
}
//目的地にたどりつかなかったのでfalse.
return false;
}
//辺(i,j)の容量がgraph[i][j]であるようなグラフにおけるsourceからsinkへの最大フローを求める。
//求めた最大フローはflowに入る。
//最大フローの値を返す。
int maxFlow(vector<vector<int> > graph, int source, int sink, vector<vector<int> > &flow)
{
const int n = graph.size(); //n:グラフの頂点数
//フローflowと値valueを初期化
for(int i = 0; i < n; ++i){
for(int j = 0; j < n; ++j){
flow[i][j] = 0;
}
}
int value = 0;
//幅優先探索の準備
vector<int> prev(n);
//経路が見付かる限りフローを更新
while(bfs(graph,source,sink,prev)){
//prevに従って,見付けた経路の容量の最小値を求める.
int capacity = graph[prev[sink]][sink];
for(int v = sink; v != source; v = prev[v]){
if(capacity > graph[prev[v]][v]){
capacity = graph[prev[v]][v];
}
}
//フローと残余ネットワークを更新
for(int v = sink; v != source; v = prev[v]){
int pv = prev[v];
flow[pv][v] += capacity;
graph[pv][v] -= capacity;
graph[v][pv] += capacity;
}
value += capacity;
}
return value;
}
double exprand(double average)
{
double r = rand() / (RAND_MAX + 1.0);
return -log(1-r) * average;
}
struct Packet {
int source; //入力ポート
int dest; //出力ポート
int arriveTime; //ハブへの到着時刻
int deliverTime; //ハブからの排出時刻
};
typedef deque<Packet> PacketQueue;
//ハブに届いたパケットを生成する.
Packet makePacket(int in_port, int current, int ports, const Matrix& m)
{
Packet packet;
packet.source = in_port;
int sum = 0;
for (int i = 0; i < ports; ++i)
sum += m[in_port][i];
int n = int(rand() / (RAND_MAX + 1.0) * sum);
for (int i = 0; i < 0; i++) {
if (m[in_port][i] == 0)
continue;
n -= m[in_port][i];
if (n < 0)
break;
}
packet.dest = n;
packet.arriveTime = current;
packet.deliverTime = -1;
return packet;
}
//ポート数Ports,スイッチ転送量xppcパケット/クロックのハブのシミュレーションを行う.
//パケットの平均到着時間間隔はTa,シミュレーション時間はdurationとする.
void runSimulation(int Ports, const int *xppc, const double *Ta, int duration,
const Matrix& packet_info)
{
//入力バッファは入力ポートごとかつ出力ポートごと
vector<vector<PacketQueue> > inputBuffer(Ports, vector<PacketQueue>(Ports));
//次に各入力ポートにパケットがくるタイミング
vector<int> nextPacketTime(Ports);
//最初のパケットのタイミングを設定して....
for(int in_port = 0; in_port < Ports; ++in_port){
nextPacketTime[in_port] = int(exprand(Ta[in_port]));
}
int count = 0, sum = 0, max = 0;
//シミュレーション開始
printf("Simulation start\n");
for(int current = 0; current < duration; ++current){
// debug("T% 4d", current);
//まず入力パケットをもらう
for(int in_port = 0; in_port < Ports; ++in_port){
while(current == nextPacketTime[in_port]){
Packet packet = makePacket(in_port, current, Ports, packet_info);
inputBuffer[in_port][packet.dest].push_back(packet);
nextPacketTime[in_port] += int(exprand(Ta[in_port]));
// debug(" (in%d,to%d)", in_port, packet.dest);
}
}
//グラフを作って
const int Vertices = 2*Ports+2;
const int Source = 2*Ports;
const int Sink = 2*Ports+1;
vector<vector<int> > graph(Vertices, vector<int>(Vertices));
for(int in_port = 0; in_port < Ports; ++in_port){
for(int out_port = 0; out_port < Ports; ++out_port){
graph[in_port][Ports+out_port] = inputBuffer[in_port][out_port].size();
}
}
for(int in_port = 0; in_port < Ports; ++in_port){
graph[Source][in_port] = xppc[in_port];
}
for(int out_port = 0; out_port < Ports; ++out_port){
graph[Ports+out_port][Sink] = xppc[out_port];
}
//最大フローを求め
vector<vector<int> > flow(Vertices, vector<int>(Vertices));
maxFlow(graph, Source, Sink, flow);
//それに従ってパケットを送り出す
for(int in_port = 0; in_port < Ports; ++in_port){
for(int out_port = 0; out_port < Ports; ++out_port){
for(int p = 0; p < flow[in_port][Ports+out_port]; ++p){
inputBuffer[in_port][out_port][0].deliverTime = current;
// debug(" (from%d, out%d)", in_port, out_port);
Packet& x = inputBuffer[in_port][out_port][0];
int time = x.deliverTime - x.arriveTime;
if (max < time)
max = time;
sum += time;
++count;
inputBuffer[in_port][out_port].pop_front();
}
}
}
// debug("\n");
}
//時間がきたのでシミュレーション終了
printf("Simulation finished\n");
printf("max %d, average %f\n", max, (double) sum / count);
}
//テスト用のmain
int main()
{
const int Ports = 4; //ポート数
const double Ta = 1; //平均到着時間間隔
double Ta_port[Ports] = {Ta, 3 * Ta, 3 * Ta, 3 * Ta};
// 各ポートの平均到着間隔
const int T = 1000; //シミュレートする時間数
// 各ポートの1クロックあたりの転送パケット数
// 課題1
const int P[] = {1, 1, 1, 1};
// 課題2
// const int P[] = {2, 1, 1, 1};
double packet_info_data[Ports*Ports] = {
0, 1, 1, 1, // ポート0から届いたパケットの宛先ポートが0~3の各割合
2, 0, 1, 1, // ポート1から
2, 1, 0, 1, // ポート2から
2, 1, 1, 0, // ポート3から
};
Matrix packet_info(Ports);
double *p = packet_info_data;
for (int i = 0; i < Ports; ++i)
for (int j = 0; j < Ports; ++j, ++p)
packet_info[i].push_back(*p);
srand(time(NULL));
runSimulation(Ports, P, Ta_port, T, packet_info);
return 0;
}