Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
cbb3434fe6f0ec1c96fa6ec5efd23a8ab6f9288a
[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 #ifdef XBT_DEBUG
12         #undef XBT_DEBUG
13 #endif
14 #include "xbt/log.h"
15 #include "xbt/asserts.h"
16 #include "RngStream.h"
17
18 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(surf_network_gtnets_simulator, surf_network_gtnets,
19                                 "Logging specific to the SURF network GTNetS simulator");
20
21
22 using namespace std;
23
24 static vector<void*> meta_flows;
25 static int* meta_nflow;
26 static int meta_flg = 0;
27
28
29 void static tcp_sent_callback(void* action, double completion_time);
30
31
32 // Constructor.
33 // TODO: check the default values.
34 GTSim::GTSim(int WindowSize){
35   int wsize = WindowSize;
36   is_topology_ = 0;
37   nflow_ = 0;
38   jitter_ = 0;
39   jitter_seed_ = 10;
40
41   // EXTRACTED FROM GTNETS SOURCE CODE COMMENTS
42   //  REDQueue::REDQueue(
43   //     DCount_t in_w_q, Count_t in_min_th, Count_t in_max_th,
44   //     Count_t in_limit, DCount_t in_max_p, Count_t in_mean_pktsize) : iface(nil)
45   // Set default values.
46   //Doc:Desc This constructor the critical RED parameters and builds a
47   //Doc:Desc correspoding RED queue
48   //Doc:Arg1 weight of the queue
49   //Doc:Arg2 minimum threshold
50   //Doc:Arg3 maximum threshold
51   //Doc:Arg4 Limit/max size for the queue
52   //Doc:Arg5 maximum value for mark/drop probability
53   //Doc:Arg6 Average packet size
54
55   //Default Parameters
56   //REDQueue *default_red_queue_ = new REDQueue(0.002, 2500, 7500, 30000, 0.10, 500);
57   //Same as above
58   //REDQueue *default_red_queue_ = new REDQueue();
59
60   //See for details of how those values are calucated below
61   //[1] Sally Floyd and Van Jacobson, "Random Early Detection Gateways with Congestion Avoidance",
62   //    IEEE/ACM Transactions on Networking, vol. 1, n. 4, august 1993.
63   //
64   //[2] Kostas Pentikousis, "Active Queue Management", ACM Crossroads, vol. 7, n. 5,
65   //    mid-summer 2001
66   //
67   //[3] Stefann De Cnodder, Omar Ecoumi, Kenny Paulwels, "RED behavior with different packet sizes",
68   //    5th IEEE Symposium on Computers and Communication, (ISCC 2000)
69   //
70   //[4] http://www.opalsoft.net/qos/DS-26.htm
71   //
72   //short explanation:
73   // q_weight = fixed to 0.002 in most literature
74   // min_bytes = max / 3 = 16,666,666
75   // max_bytes = mean_bw * max_tolerable_latency, set to 1e8 * 0.5 = 50,000,000
76   // limit_bytes = 8 * max = 400,000,000
77   // prob = follow most literature 0.02
78   // avgpkt = fixed to the same TCP segment size, 1000 Bytes
79   //
80   // burst = (2*(min+max))/(3*avgpkt) ***DON'T USED BY GTNetS***
81   REDQueue *default_red_queue_ = new REDQueue(0.002, 16666666, 50000000, 400000000, 0.02, 1000);
82
83   Queue::Default(*default_red_queue_);
84   delete default_red_queue_;
85
86   TCP::DefaultAdvWin(wsize);
87   TCP::DefaultSegSize(1000);
88   TCP::DefaultTxBuffer(128000);
89   TCP::DefaultRxBuffer(128000);
90
91   sim_ = new Simulator();
92   sim_->verbose=false;
93   topo_ = new GTNETS_Topology();
94
95   // Manual routing
96   rm_ = new RoutingManual();
97   Routing::SetRouting(rm_);
98 }
99
100 // Constructor.
101 // TODO: check the default values.
102 GTSim::GTSim(){
103   int wsize = 20000;
104   is_topology_ = 0;
105   nflow_ = 0;
106   jitter_ = 0;
107   jitter_seed_ = 10;
108
109   // EXTRACTED FROM GTNETS SOURCE CODE COMMENTS
110   //  REDQueue::REDQueue(
111   //     DCount_t in_w_q, Count_t in_min_th, Count_t in_max_th,
112   //     Count_t in_limit, DCount_t in_max_p, Count_t in_mean_pktsize) : iface(nil)
113   // Set default values.
114   //Doc:Desc This constructor the critical RED parameters and builds a
115   //Doc:Desc correspoding RED queue
116   //Doc:Arg1 weight of the queue
117   //Doc:Arg2 minimum threshold
118   //Doc:Arg3 maximum threshold
119   //Doc:Arg4 Limit/max size for the queue
120   //Doc:Arg5 maximum value for mark/drop probability
121   //Doc:Arg6 Average packet size
122
123   //Default Parameters
124   //REDQueue *default_red_queue_ = new REDQueue(0.002, 2500, 7500, 30000, 0.10, 500);
125   //Same as above
126   //REDQueue *default_red_queue_ = new REDQueue();
127
128   //See for details of how those values are calucated below
129   //[1] Sally Floyd and Van Jacobson, "Random Early Detection Gateways with Congestion Avoidance",
130   //    IEEE/ACM Transactions on Networking, vol. 1, n. 4, august 1993.
131   //
132   //[2] Kostas Pentikousis, "Active Queue Management", ACM Crossroads, vol. 7, n. 5,
133   //    mid-summer 2001
134   //
135   //[3] Stefann De Cnodder, Omar Ecoumi, Kenny Paulwels, "RED behavior with different packet sizes",
136   //    5th IEEE Symposium on Computers and Communication, (ISCC 2000)
137   //
138   //[4] http://www.opalsoft.net/qos/DS-26.htm
139   //
140   //short explanation:
141   // q_weight = fixed to 0.002 in most literature
142   // min_bytes = max / 3 = 16,666,666
143   // max_bytes = mean_bw * max_tolerable_latency, set to 1e8 * 0.5 = 50,000,000
144   // limit_bytes = 8 * max = 400,000,000
145   // prob = follow most literature 0.02
146   // avgpkt = fixed to the same TCP segment size, 1000 Bytes
147   //
148   // burst = (2*(min+max))/(3*avgpkt) ***DON'T USED BY GTNetS***
149   REDQueue *default_red_queue_ = new REDQueue(0.002, 16666666, 50000000, 400000000, 0.02, 1000);
150
151   Queue::Default(*default_red_queue_);
152   delete default_red_queue_;
153
154   TCP::DefaultAdvWin(wsize);
155   TCP::DefaultSegSize(1000);
156   TCP::DefaultTxBuffer(128000);
157   TCP::DefaultRxBuffer(128000);
158
159   sim_ = new Simulator();
160   sim_->verbose=false;
161   topo_ = new GTNETS_Topology();
162
163   // Manual routing
164   rm_ = new RoutingManual();
165   Routing::SetRouting(rm_);
166 }
167
168 GTSim::~GTSim(){
169
170   map<int, Linkp2p*>::iterator it;
171   for (it = gtnets_links_.begin(); it != gtnets_links_.end(); it++){
172     delete it->second;
173   }
174   while (!gtnets_links_.empty())
175     gtnets_links_.erase(gtnets_links_.begin());
176
177   map<int, Uniform*>::iterator it2;
178   for (it2 = uniform_jitter_generator_.begin(); it2 != uniform_jitter_generator_.end(); it2++){
179     delete it2->second;
180   }
181   while (!uniform_jitter_generator_.empty())
182     uniform_jitter_generator_.erase(uniform_jitter_generator_.begin());
183
184   map<int, Node*>::iterator it3;
185   for (it3 = gtnets_nodes_.begin(); it3 != gtnets_nodes_.end(); it3++){
186     delete it3->second;
187   }
188   while (!gtnets_nodes_.empty())
189     gtnets_nodes_.erase(gtnets_nodes_.begin());
190
191   map<int, TCPServer*>::iterator it4;
192   for (it4 = gtnets_servers_.begin(); it4 != gtnets_servers_.end(); it4++){
193     delete it4->second;
194   }
195   while (!gtnets_servers_.empty())
196     gtnets_servers_.erase(gtnets_servers_.begin());
197
198   map<int, TCPSend*>::iterator it5;
199   for (it5 = gtnets_clients_.begin(); it5 != gtnets_clients_.end(); it5++){
200     delete it5->second;
201   }
202   while (!gtnets_clients_.empty())
203     gtnets_clients_.erase(gtnets_clients_.begin());
204
205   is_topology_ = 0;
206   delete sim_;
207   delete topo_;
208   delete rm_;
209   sim_ = 0;
210   topo_ = 0;
211   rm_ = 0;
212 }
213
214 int GTSim::add_router(int id){
215   xbt_assert1(!(topo_->add_router(id) < 0), "can't add router %d. already exists", id);
216 }
217
218 //bandwidth: in bytes.
219 //latency: in seconds.
220 int GTSim::add_link(int id, double bandwidth, double latency){
221   double bw = bandwidth * 8; //Bandwidth in bits (used in GTNETS).
222   xbt_assert1(!(topo_->add_link(id) < 0),"Can't add link %d. already exists", id);
223   XBT_DEBUG("Creating a new P2P, linkid %d, bandwidth %gl, latency %gl", id, bandwidth, latency);
224   gtnets_links_[id] = new Linkp2p(bw, latency);
225   if(jitter_ > 0){
226         XBT_DEBUG("Using jitter %f, and seed %u", jitter_, jitter_seed_);
227         double min = -1*jitter_*latency;
228         double max = jitter_*latency;
229         uniform_jitter_generator_[id] = new Uniform(min,max);
230         gtnets_links_[id]->Jitter((const Random &) *(uniform_jitter_generator_[id]));
231   }
232   return 0;
233 }
234
235 // if gtnets_nodes_ includes id, return true, otherwise return false.
236 bool GTSim::node_include(int id){
237   if (gtnets_nodes_.find(id) != gtnets_nodes_.end()) return true;
238   else return false;
239 }
240
241 // if gtnets_link_ includes id, return true, otherwise return false.
242 bool GTSim::link_include(int id){
243   if (gtnets_links_.find(id) != gtnets_links_.end()) return true;
244   else return false;
245 }
246
247 int GTSim::add_onehop_route(int src, int dst, int link){
248   xbt_assert3(!(topo_->add_onehop_route(src, dst, link) < 0), "Cannot add a route, src: %d, dst: %d, link: %d", src, dst, link);
249   return 0;
250 }
251
252 // Generate the gtnets nodes according to topo_.
253 void GTSim::add_nodes(){
254   static unsigned int address = IPAddr("192.168.0.1");
255   IPAddr helper = IPAddr();
256   vector<GTNETS_Node*> nodes = topo_->nodes();
257   vector<GTNETS_Node*>::iterator it;
258   int id;
259   for (it = nodes.begin(); it != nodes.end(); it++){
260     id = (*it)->id();
261     gtnets_nodes_[id] = new Node();
262     gtnets_nodes_[id]->SetIPAddr(address++);
263     XBT_DEBUG("In GTSim, add_node: %d, with IPAddr %s", id, helper.ToDotted(address-1));
264
265   }
266 }
267
268 void GTSim::node_connect(){
269
270   map<int, GTNETS_Link*> links = topo_->links();
271   map<int, GTNETS_Link*>::iterator it;
272   int linkid, srcid, dstid;
273   for (it = links.begin(); it != links.end(); it++){
274     linkid = it->second->id();
275     //if link is used in a route, connect the two nodes.
276     if (it->second->src_node() && it->second->dst_node()){
277
278       srcid = it->second->src_node()->id();
279       dstid = it->second->dst_node()->id();
280
281       gtnets_nodes_[srcid]->
282         AddDuplexLink(gtnets_nodes_[dstid], *(gtnets_links_[linkid]));
283     XBT_DEBUG("Setting DuplexLink, src %d, dst %d, linkid %d", srcid, dstid, linkid);
284     }
285   }
286 }
287
288 // Create nodes and routes from the temporary topology, GTNETS_Topolgy.
289 void GTSim::create_gtnets_topology(){
290   add_nodes();
291   node_connect();
292 }
293
294 void GTSim::print_topology(){
295   topo_->print_topology();
296 }
297
298 // Add a route that includes more than one hop. All one hop
299 // routes must have been added. When this function is called
300 // for the first time, all gtnets nodes are generated.
301 int GTSim::add_route(int src, int dst, int* links, int nlink){
302   if (is_topology_ == 0){
303     create_gtnets_topology();
304     is_topology_ = 1;
305   }  
306
307   IPAddr_t mymask = IPAddr("255.255.255.255");
308
309   int src_node = topo_->nodeid_from_hostid(src);
310   int dst_node = topo_->nodeid_from_hostid(dst);
311
312   xbt_assert1(!(gtnets_nodes_.find(src_node) == gtnets_nodes_.end()), "Node %d not found", src_node);
313   xbt_assert1(!(gtnets_nodes_.find(dst_node) == gtnets_nodes_.end()), "Node %d not found", dst_node);
314
315   Node* tmpsrc = gtnets_nodes_[src_node];
316   Node* tmpdst = gtnets_nodes_[dst_node];
317
318   int next_node, cur_node;
319   
320   cur_node = src_node;
321   for (int i = 0; i < nlink; i++){
322         xbt_assert1(!(gtnets_nodes_.find(cur_node) == gtnets_nodes_.end()), "Node %d not found", cur_node);
323     next_node = topo_->peer_node_id(links[i], cur_node);
324     xbt_assert0(!(next_node < 0), "Peer node not found");
325     xbt_assert1(!(gtnets_nodes_.find(next_node) == gtnets_nodes_.end()), "Node %d not found", next_node);
326     
327     //add route
328     Node* tmpcur = gtnets_nodes_[cur_node];
329     Node* tmpnext = gtnets_nodes_[next_node];
330
331     tmpcur->AddRoute(tmpdst->GetIPAddr(),
332                      mymask,
333                      tmpcur->GetIfByNode(tmpnext),
334                      tmpnext->GetIPAddr());
335
336     tmpnext->AddRoute(tmpsrc->GetIPAddr(),
337                       mymask,
338                       tmpnext->GetIfByNode(tmpcur),
339                       tmpcur->GetIPAddr());
340     
341     cur_node = next_node;
342   }
343
344   xbt_assert2(!(cur_node != dst_node), "Route inconsistency, last: %d, dst: %d",cur_node, dst_node);
345
346   return 0;
347 }
348
349
350
351 int GTSim::create_flow(int src, int dst, long datasize, void* metadata){
352   //if no route with more than one links, topology has not been generated.
353   //generate it here.
354   if (is_topology_ == 0){
355     create_gtnets_topology();
356     is_topology_ = 1;
357   }
358
359   int src_node = topo_->nodeid_from_hostid(src);
360   xbt_assert1(!(src_node < 0), "Src %d not found", src_node);
361
362   int dst_node = topo_->nodeid_from_hostid(dst);
363   xbt_assert1(!(dst_node < 0), "Dst %d not found", dst_node);
364
365   gtnets_servers_[nflow_] = (TCPServer*) gtnets_nodes_[dst_node]->
366        AddApplication(TCPServer(TCPReno()));
367   gtnets_servers_[nflow_]->BindAndListen(1000+nflow_);
368
369   gtnets_clients_[nflow_] = (TCPSend*)gtnets_nodes_[src_node]->
370     AddApplication(TCPSend(metadata, gtnets_nodes_[dst_node]->GetIPAddr(), 
371                            1000+nflow_, Constant(datasize), TCPReno()));
372   gtnets_clients_[nflow_]->SetSendCallBack(tcp_sent_callback);
373   gtnets_clients_[nflow_]->Start(0);
374
375   gtnets_action_to_flow_[metadata] = nflow_;
376   nflow_++;
377
378   return 0;
379 }
380
381 Time_t GTSim::get_time_to_next_flow_completion(){
382   int status;
383   Time_t t1;
384   int pfds[2];
385   int soon_pid=-1;
386   meta_flg=0;
387
388   //remain needs to be updated in the future
389   Count_t remain;
390   
391   pipe(pfds);
392   
393   t1 = 0;
394   fflush (NULL);
395   if( (soon_pid=fork()) != 0){
396     read(pfds[0], &t1, sizeof(Time_t));
397     waitpid(soon_pid, &status, 0);      
398   }else{
399     Time_t t;
400     t = sim_->RunUntilNextCompletion();
401     write(pfds[1], (const void*)&t, sizeof(Time_t));
402     exit(0);
403   }
404
405   return t1;
406 }
407
408 double GTSim::gtnets_get_flow_rx(void *metadata){
409   int flow_id = gtnets_action_to_flow_[metadata];
410   return gtnets_servers_[flow_id]->GetTotRx(); 
411 }
412
413
414 int GTSim::run_until_next_flow_completion(void ***metadata, int *number_of_flows){
415
416   meta_flows.clear();
417   meta_nflow = number_of_flows;
418   meta_flg = 1;
419
420   Time_t t1 = sim_->RunUntilNextCompletion();
421
422   *metadata = (meta_flows.empty() ? NULL : &meta_flows[0]);
423   return 0;
424 }
425
426 int GTSim::run(double delta){
427   meta_flg=0;
428   sim_->Run(delta);
429   return 0;
430 }
431
432 void GTSim::set_jitter(double d){
433   xbt_assert1(((0 <= d)&&(d <= 1)), "The jitter value must be within interval [0.0;1.0), got %f", d);
434   jitter_ = d;
435 }
436
437 void GTSim::set_jitter_seed(int s){
438   jitter_seed_ = s;
439
440   if(jitter_seed_ > 0.0){
441     XBT_INFO("Setting the jitter_seed with %d", jitter_seed_ );
442     Random::GlobalSeed(jitter_seed_  , jitter_seed_  , jitter_seed_  ,jitter_seed_  ,jitter_seed_  ,jitter_seed_);
443   }
444 }
445
446 void static tcp_sent_callback(void* action, double completion_time){
447   // Schedule the flow complete event.
448   SimulatorEvent* e =
449     new SimulatorEvent(SimulatorEvent::FLOW_COMPLETE);
450   Simulator::instance->Schedule(e, 0, Simulator::instance);
451
452   if (meta_flg){
453     meta_flows.push_back(action);
454     (*meta_nflow)++;
455   }
456 }
457
458