Logo AND Algorithmique Numérique Distribuée

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