Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
4b3032426a5ecf30f44454e4880df31c33ce94a5
[simgrid.git] / src / surf / gtnets / gtnets_simulator.cc
1 /*      $Id$     */
2 /* Copyright (c) 2007 Kayo Fujiwara. All rights reserved.                  */
3
4 /* This program is free software; you can redistribute it and/or modify it
5  * under the terms of the license (GNU LGPL) which comes with this package. */
6
7 #include "gtnets_simulator.h"
8 #include "gtnets_topology.h"
9 #include <map>
10 #include <vector>
11
12 using namespace std;
13
14 static vector<void*> meta_flows;
15 static int* meta_nflow;
16 static int meta_flg = 0;
17
18 void static tcp_sent_callback(void* action, double completion_time);
19
20 // Constructor.
21 // TODO: check the default values.
22 GTSim::GTSim(){
23   int wsize = 20000;
24   is_topology_ = 0;
25   nflow_ = 0;
26   sim_ = new Simulator();
27   topo_ = new GTNETS_Topology();
28
29   sim_->verbose=false;
30   // Set default values.
31   TCP::DefaultAdvWin(wsize);
32   TCP::DefaultSegSize(1000);
33   TCP::DefaultTxBuffer(128000);
34   TCP::DefaultRxBuffer(128000);
35
36   // Manual routing
37   rm_ = new RoutingManual();
38   Routing::SetRouting(rm_);
39 }
40
41 GTSim::~GTSim(){
42
43   map<int, Linkp2p*>::iterator it;
44   for (it = gtnets_links_.begin(); it != gtnets_links_.end(); it++){
45     delete it->second;
46   }
47   while (!gtnets_links_.empty())
48     gtnets_links_.erase(gtnets_links_.begin());
49
50   map<int, Node*>::iterator it3;
51   for (it3 = gtnets_nodes_.begin(); it3 != gtnets_nodes_.end(); it3++){
52     delete it3->second;
53   }
54   while (!gtnets_nodes_.empty())
55     gtnets_nodes_.erase(gtnets_nodes_.begin());
56
57   map<int, TCPServer*>::iterator it4;
58   for (it4 = gtnets_servers_.begin(); it4 != gtnets_servers_.end(); it4++){
59     delete it4->second;
60   }
61   while (!gtnets_servers_.empty())
62     gtnets_servers_.erase(gtnets_servers_.begin());
63
64   map<int, TCPSend*>::iterator it5;
65   for (it5 = gtnets_clients_.begin(); it5 != gtnets_clients_.end(); it5++){
66     delete it5->second;
67   }
68   while (!gtnets_clients_.empty())
69     gtnets_clients_.erase(gtnets_clients_.begin());
70
71   is_topology_ = 0;
72   delete sim_;
73   delete topo_;
74   delete rm_;
75   sim_ = 0;
76   topo_ = 0;
77   rm_ = 0;
78 }
79
80 int GTSim::add_router(int id){
81   if (topo_->add_router(id) < 0){
82     fprintf(stderr, "can't add router %d. already exists.\n", id);
83     return -1;
84   }
85 }
86
87 //bandwidth: in bytes.
88 //latency: in seconds.
89 int GTSim::add_link(int id, double bandwidth, double latency){
90   double bw = bandwidth * 8; //Bandwidth in bits (used in GTNETS).
91   if (topo_->add_link(id) < 0){
92     fprintf(stderr, "can't add link %d. already exists.\n", id);
93     return -1;
94   }
95   gtnets_links_[id] = new Linkp2p(bw, latency);
96   return 0;
97 }
98
99 // if gtnets_nodes_ includes id, return true, otherwise return false.
100 bool GTSim::node_include(int id){
101   if (gtnets_nodes_.find(id) != gtnets_nodes_.end()) return true;
102   else return false;
103 }
104
105 // if gtnets_link_ includes id, return true, otherwise return false.
106 bool GTSim::link_include(int id){
107   if (gtnets_links_.find(id) != gtnets_links_.end()) return true;
108   else return false;
109 }
110
111 int GTSim::add_onehop_route(int src, int dst, int link){
112   if (topo_->add_onehop_route(src, dst, link) < 0){
113     fprintf(stderr, "Cannot add a route, src: %d, dst: %d, link: %d\n",
114             src, dst, link);
115     return -1;
116   }
117   return 0;
118 }
119
120 // Generate the gtnets nodes according to topo_.
121 void GTSim::add_nodes(){
122   static unsigned int address = IPAddr("192.168.0.1");
123   vector<GTNETS_Node*> nodes = topo_->nodes();
124   vector<GTNETS_Node*>::iterator it;
125   int id;
126   for (it = nodes.begin(); it != nodes.end(); it++){
127     id = (*it)->id();
128     gtnets_nodes_[id] = new Node();
129     gtnets_nodes_[id]->SetIPAddr(address++);
130     //    printf("In GTSim, add_node: %d\n", id);
131   }
132 }
133
134 void GTSim::node_connect(){
135
136   map<int, GTNETS_Link*> links = topo_->links();
137   map<int, GTNETS_Link*>::iterator it;
138   int linkid, srcid, dstid;
139   for (it = links.begin(); it != links.end(); it++){
140     linkid = it->second->id();
141     //if link is used in a route, connect the two nodes.
142     if (it->second->src_node() && it->second->dst_node()){
143
144       srcid = it->second->src_node()->id();
145       dstid = it->second->dst_node()->id();
146
147       gtnets_nodes_[srcid]->
148         AddDuplexLink(gtnets_nodes_[dstid], *(gtnets_links_[linkid]));
149     }
150   }
151 }
152
153 // Create nodes and routes from the temporary topology, GTNETS_Topolgy.
154 void GTSim::create_gtnets_topology(){
155   add_nodes();
156   node_connect();
157 }
158
159 // Add a route that includes more than one hop. All one hop
160 // routes must have been added. When this function is called
161 // for the first time, all gtnets nodes are generated.
162 int GTSim::add_route(int src, int dst, int* links, int nlink){
163   if (is_topology_ == 0){
164     create_gtnets_topology();
165     //    topo_->print_topology();
166     is_topology_ = 1;
167   }  
168
169   IPAddr_t mymask = IPAddr("255.255.255.255");
170
171   int src_node = topo_->nodeid_from_hostid(src);
172   int dst_node = topo_->nodeid_from_hostid(dst);
173
174   if (gtnets_nodes_.find(src_node) == gtnets_nodes_.end()){
175     fprintf(stderr, "node %d not found\n", src_node);
176     return -1;
177   }
178   if (gtnets_nodes_.find(dst_node) == gtnets_nodes_.end()){
179     fprintf(stderr, "node %d not found\n", dst_node);
180     return -1;
181   }
182
183   Node* tmpsrc = gtnets_nodes_[src_node];
184   Node* tmpdst = gtnets_nodes_[dst_node];
185
186   int next_node, cur_node;
187   
188   cur_node = src_node;
189   for (int i = 0; i < nlink; i++){
190     if (gtnets_nodes_.find(cur_node) == gtnets_nodes_.end()){
191       fprintf(stderr, "node %d not found\n", cur_node);
192       return -1;
193     }
194     next_node = topo_->peer_node_id(links[i], cur_node);
195     if (next_node < 0){
196       fprintf(stderr, "peer node not found\n");
197       return -1;
198     }
199     if (gtnets_nodes_.find(next_node) == gtnets_nodes_.end()){
200       fprintf(stderr, "node %d not found\n", next_node);
201       return -1;
202     }
203     
204     //add route
205     Node* tmpcur = gtnets_nodes_[cur_node];
206     Node* tmpnext = gtnets_nodes_[next_node];
207
208     tmpcur->AddRoute(tmpdst->GetIPAddr(),
209                      mymask,
210                      tmpcur->GetIfByNode(tmpnext),
211                      tmpnext->GetIPAddr());
212
213     tmpnext->AddRoute(tmpsrc->GetIPAddr(),
214                       mymask,
215                       tmpnext->GetIfByNode(tmpcur),
216                       tmpcur->GetIPAddr());
217     
218     cur_node = next_node;
219   }
220
221   if (cur_node != dst_node){
222     fprintf(stderr, "Route inconsistency, last: %d, dst: %d\n",
223             cur_node, dst_node);
224     return -1;
225   }
226
227   return 0;
228 }
229
230
231
232 int GTSim::create_flow(int src, int dst, long datasize, void* metadata){
233   //if no route with more than one links, topology has not been generated.
234   //generate it here.
235   if (is_topology_ == 0){
236     create_gtnets_topology();
237     //    topo_->print_topology();
238     is_topology_ = 1;
239   }
240
241   int src_node = topo_->nodeid_from_hostid(src);
242   if (src_node < 0){
243     fprintf(stderr, "src %d not found\n");
244     return -1;
245   }
246   int dst_node = topo_->nodeid_from_hostid(dst);
247   if (dst_node < 0){
248     fprintf(stderr, "dst %d not found\n");
249     return -1;
250   }
251
252   gtnets_servers_[nflow_] = (TCPServer*)gtnets_nodes_[dst_node]->
253        AddApplication(TCPServer(TCPReno()));
254   //added by arnaud in order to avoid TCPServer duplicates.
255   //It is not needed since we create a new TCPServer for
256   //each flow. Also we need to control this variable
257   //to proper set the value of remaining communication amount.
258   //See functions:
259   gtnets_servers_[nflow_]->copyOnConnect=false;
260   gtnets_servers_[nflow_]->BindAndListen(80);
261
262   gtnets_clients_[nflow_] = (TCPSend*)gtnets_nodes_[src_node]->
263     AddApplication(TCPSend(metadata, gtnets_nodes_[dst_node]->GetIPAddr(), 
264                            80, Constant(datasize), TCPReno()));
265   gtnets_clients_[nflow_]->copyOnConnect=false;
266   gtnets_clients_[nflow_]->SetSendCallBack(tcp_sent_callback);
267   gtnets_clients_[nflow_]->Start(0);
268
269   //added by pedro in order to get statistics
270   //map an action from a gtnets flow id
271   //metadata is the action and flow is the id to gtnets
272   gtnets_action_to_flow_[metadata] = nflow_;
273   nflow_++;
274
275   return 0;
276 }
277
278 Time_t GTSim::get_time_to_next_flow_completion(){
279   int status;
280   Time_t t1;
281   int pfds[2];
282   meta_flg=0;
283  
284   //remain needs to be updated in the future
285   Count_t remain;
286   
287   pipe(pfds);
288   
289   t1 = 0;
290   if (fork() != 0){
291     read(pfds[0], &t1, sizeof(Time_t));
292     waitpid(-1, &status, 0);      
293   }else{
294     Time_t t;
295     t = sim_->RunUntilNextCompletion();
296     write(pfds[1], (const void*)&t, sizeof(Time_t));
297     exit(0);
298   }
299
300   return t1;
301 }
302
303 double GTSim::gtnets_get_flow_rx(void *metadata){
304   int flow = gtnets_action_to_flow_[metadata];
305   return ((TCPServer *)gtnets_servers_[flow])->totRx;//action_remain[flow]; 
306 }
307
308 int GTSim::run_until_next_flow_completion(void ***metadata, int *number_of_flows){
309   meta_flows.clear();
310   meta_nflow = number_of_flows;
311   meta_flg = 1;
312
313   Time_t t1 = sim_->RunUntilNextCompletion();
314
315   *metadata = (meta_flows.empty() ? NULL : &meta_flows[0]);
316   return 0;
317 }
318
319 int GTSim::run(double delta){
320   meta_flg=0;
321   sim_->Run(delta);
322   return 0;
323 }
324
325
326 void static tcp_sent_callback(void* action, double completion_time){
327   // Schedule the flow complete event.
328   SimulatorEvent* e =
329     new SimulatorEvent(SimulatorEvent::FLOW_COMPLETE);
330   Simulator::instance->Schedule(e, 0, Simulator::instance);
331
332   if (meta_flg){
333     meta_flows.push_back(action);
334     (*meta_nflow)++;
335   }
336 }
337