Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Try to improve getline portability...
[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 DEBUG0
12         #undef DEBUG0
13 #endif
14 #include "xbt/log.h"
15 #include "xbt/asserts.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 // Constructor.
31 // TODO: check the default values.
32 GTSim::GTSim(){
33   int wsize = 20000;
34   is_topology_ = 0;
35   nflow_ = 0;
36   sim_ = new Simulator();
37   topo_ = new GTNETS_Topology();
38   jitter_ = 0;
39   jitter_seed_ = 10;
40
41   sim_->verbose=false;
42   // Set default values.
43   TCP::DefaultAdvWin(wsize);
44   TCP::DefaultSegSize(1000);
45   TCP::DefaultTxBuffer(128000);
46   TCP::DefaultRxBuffer(128000);
47
48   // Manual routing
49   rm_ = new RoutingManual();
50   Routing::SetRouting(rm_);
51 }
52
53 GTSim::~GTSim(){
54
55   map<int, Linkp2p*>::iterator it;
56   for (it = gtnets_links_.begin(); it != gtnets_links_.end(); it++){
57     delete it->second;
58   }
59   while (!gtnets_links_.empty())
60     gtnets_links_.erase(gtnets_links_.begin());
61
62   map<int, Uniform*>::iterator it2;
63   for (it2 = uniform_jitter_generator_.begin(); it2 != uniform_jitter_generator_.end(); it2++){
64     delete it2->second;
65   }
66   while (!uniform_jitter_generator_.empty())
67     uniform_jitter_generator_.erase(uniform_jitter_generator_.begin());
68
69   map<int, Node*>::iterator it3;
70   for (it3 = gtnets_nodes_.begin(); it3 != gtnets_nodes_.end(); it3++){
71     delete it3->second;
72   }
73   while (!gtnets_nodes_.empty())
74     gtnets_nodes_.erase(gtnets_nodes_.begin());
75
76   map<int, TCPServer*>::iterator it4;
77   for (it4 = gtnets_servers_.begin(); it4 != gtnets_servers_.end(); it4++){
78     delete it4->second;
79   }
80   while (!gtnets_servers_.empty())
81     gtnets_servers_.erase(gtnets_servers_.begin());
82
83   map<int, TCPSend*>::iterator it5;
84   for (it5 = gtnets_clients_.begin(); it5 != gtnets_clients_.end(); it5++){
85     delete it5->second;
86   }
87   while (!gtnets_clients_.empty())
88     gtnets_clients_.erase(gtnets_clients_.begin());
89
90   is_topology_ = 0;
91   delete sim_;
92   delete topo_;
93   delete rm_;
94   sim_ = 0;
95   topo_ = 0;
96   rm_ = 0;
97 }
98
99 int GTSim::add_router(int id){
100   xbt_assert1(!(topo_->add_router(id) < 0), "can't add router %d. already exists", id);
101 }
102
103 //bandwidth: in bytes.
104 //latency: in seconds.
105 int GTSim::add_link(int id, double bandwidth, double latency){
106   double bw = bandwidth * 8; //Bandwidth in bits (used in GTNETS).
107   xbt_assert1(!(topo_->add_link(id) < 0),"Can't add link %d. already exists", id);
108   DEBUG3("Creating a new P2P, linkid %d, bandwidth %gl, latency %gl", id, bandwidth, latency);
109   gtnets_links_[id] = new Linkp2p(bw, latency);
110   if(jitter_ > 0){
111         DEBUG2("Using jitter %f, and seed %u", jitter_, jitter_seed_);
112         double min = -1*jitter_*latency;
113         double max = jitter_*latency;
114         //initialize the random seed only once, when adding the first link
115         if(uniform_jitter_generator_.empty()){
116                 Random::GlobalSeed(jitter_seed_  , jitter_seed_+1, jitter_seed_+2,
117                                                jitter_seed_+3, jitter_seed_+4, jitter_seed_+5);
118         }
119         uniform_jitter_generator_[id] = new Uniform(min,max);
120         gtnets_links_[id]->Jitter((const Random &) *(uniform_jitter_generator_[id]));
121   }
122   return 0;
123 }
124
125 // if gtnets_nodes_ includes id, return true, otherwise return false.
126 bool GTSim::node_include(int id){
127   if (gtnets_nodes_.find(id) != gtnets_nodes_.end()) return true;
128   else return false;
129 }
130
131 // if gtnets_link_ includes id, return true, otherwise return false.
132 bool GTSim::link_include(int id){
133   if (gtnets_links_.find(id) != gtnets_links_.end()) return true;
134   else return false;
135 }
136
137 int GTSim::add_onehop_route(int src, int dst, int link){
138   xbt_assert3(!(topo_->add_onehop_route(src, dst, link) < 0), "Cannot add a route, src: %d, dst: %d, link: %d", src, dst, link);
139   return 0;
140 }
141
142 // Generate the gtnets nodes according to topo_.
143 void GTSim::add_nodes(){
144   static unsigned int address = IPAddr("192.168.0.1");
145   IPAddr helper = IPAddr();
146   vector<GTNETS_Node*> nodes = topo_->nodes();
147   vector<GTNETS_Node*>::iterator it;
148   int id;
149   for (it = nodes.begin(); it != nodes.end(); it++){
150     id = (*it)->id();
151     gtnets_nodes_[id] = new Node();
152     gtnets_nodes_[id]->SetIPAddr(address++);
153     DEBUG2("In GTSim, add_node: %d, with IPAddr %s", id, helper.ToDotted(address-1));
154
155   }
156 }
157
158 void GTSim::node_connect(){
159
160   map<int, GTNETS_Link*> links = topo_->links();
161   map<int, GTNETS_Link*>::iterator it;
162   int linkid, srcid, dstid;
163   for (it = links.begin(); it != links.end(); it++){
164     linkid = it->second->id();
165     //if link is used in a route, connect the two nodes.
166     if (it->second->src_node() && it->second->dst_node()){
167
168       srcid = it->second->src_node()->id();
169       dstid = it->second->dst_node()->id();
170
171       gtnets_nodes_[srcid]->
172         AddDuplexLink(gtnets_nodes_[dstid], *(gtnets_links_[linkid]));
173     DEBUG3("Setting DuplexLink, src %d, dst %d, linkid %d", srcid, dstid, linkid);
174     }
175   }
176 }
177
178 // Create nodes and routes from the temporary topology, GTNETS_Topolgy.
179 void GTSim::create_gtnets_topology(){
180   add_nodes();
181   node_connect();
182 }
183
184 void GTSim::print_topology(){
185   topo_->print_topology();
186 }
187
188 // Add a route that includes more than one hop. All one hop
189 // routes must have been added. When this function is called
190 // for the first time, all gtnets nodes are generated.
191 int GTSim::add_route(int src, int dst, int* links, int nlink){
192   if (is_topology_ == 0){
193     create_gtnets_topology();
194     is_topology_ = 1;
195   }  
196
197   IPAddr_t mymask = IPAddr("255.255.255.255");
198
199   int src_node = topo_->nodeid_from_hostid(src);
200   int dst_node = topo_->nodeid_from_hostid(dst);
201
202   xbt_assert1(!(gtnets_nodes_.find(src_node) == gtnets_nodes_.end()), "Node %d not found", src_node);
203   xbt_assert1(!(gtnets_nodes_.find(dst_node) == gtnets_nodes_.end()), "Node %d not found", dst_node);
204
205   Node* tmpsrc = gtnets_nodes_[src_node];
206   Node* tmpdst = gtnets_nodes_[dst_node];
207
208   int next_node, cur_node;
209   
210   cur_node = src_node;
211   for (int i = 0; i < nlink; i++){
212         xbt_assert1(!(gtnets_nodes_.find(cur_node) == gtnets_nodes_.end()), "Node %d not found", cur_node);
213     next_node = topo_->peer_node_id(links[i], cur_node);
214     xbt_assert0(!(next_node < 0), "Peer node not found");
215     xbt_assert1(!(gtnets_nodes_.find(next_node) == gtnets_nodes_.end()), "Node %d not found", next_node);
216     
217     //add route
218     Node* tmpcur = gtnets_nodes_[cur_node];
219     Node* tmpnext = gtnets_nodes_[next_node];
220
221     tmpcur->AddRoute(tmpdst->GetIPAddr(),
222                      mymask,
223                      tmpcur->GetIfByNode(tmpnext),
224                      tmpnext->GetIPAddr());
225
226     tmpnext->AddRoute(tmpsrc->GetIPAddr(),
227                       mymask,
228                       tmpnext->GetIfByNode(tmpcur),
229                       tmpcur->GetIPAddr());
230     
231     cur_node = next_node;
232   }
233
234   xbt_assert2(!(cur_node != dst_node), "Route inconsistency, last: %d, dst: %d",cur_node, dst_node);
235
236   return 0;
237 }
238
239
240
241 int GTSim::create_flow(int src, int dst, long datasize, void* metadata){
242   //if no route with more than one links, topology has not been generated.
243   //generate it here.
244   if (is_topology_ == 0){
245     create_gtnets_topology();
246     is_topology_ = 1;
247   }
248
249   int src_node = topo_->nodeid_from_hostid(src);
250   xbt_assert1(!(src_node < 0), "Src %d not found", src_node);
251
252   int dst_node = topo_->nodeid_from_hostid(dst);
253   xbt_assert1(!(dst_node < 0), "Dst %d not found", dst_node);
254
255   gtnets_servers_[nflow_] = (TCPServer*) gtnets_nodes_[dst_node]->
256        AddApplication(TCPServer(TCPReno()));
257   gtnets_servers_[nflow_]->BindAndListen(1000+nflow_);
258
259   gtnets_clients_[nflow_] = (TCPSend*)gtnets_nodes_[src_node]->
260     AddApplication(TCPSend(metadata, gtnets_nodes_[dst_node]->GetIPAddr(), 
261                            1000+nflow_, Constant(datasize), TCPReno()));
262   gtnets_clients_[nflow_]->SetSendCallBack(tcp_sent_callback);
263   gtnets_clients_[nflow_]->Start(0);
264
265   gtnets_action_to_flow_[metadata] = nflow_;
266   nflow_++;
267
268   return 0;
269 }
270
271 Time_t GTSim::get_time_to_next_flow_completion(){
272   int status;
273   Time_t t1;
274   int pfds[2];
275   int soon_pid=-1;
276   meta_flg=0;
277
278   //remain needs to be updated in the future
279   Count_t remain;
280   
281   pipe(pfds);
282   
283   t1 = 0;
284
285   if ( (soon_pid=fork()) != 0){
286     read(pfds[0], &t1, sizeof(Time_t));
287     waitpid(soon_pid, &status, 0);      
288   }else{
289     Time_t t;
290     t = sim_->RunUntilNextCompletion();
291     write(pfds[1], (const void*)&t, sizeof(Time_t));
292     exit(0);
293   }
294
295   return t1;
296 }
297
298 double GTSim::gtnets_get_flow_rx(void *metadata){
299   int flow_id = gtnets_action_to_flow_[metadata];
300   return gtnets_servers_[flow_id]->GetTotRx(); 
301 }
302
303 int GTSim::run_until_next_flow_completion(void ***metadata, int *number_of_flows){
304
305   meta_flows.clear();
306   meta_nflow = number_of_flows;
307   meta_flg = 1;
308
309   Time_t t1 = sim_->RunUntilNextCompletion();
310
311   *metadata = (meta_flows.empty() ? NULL : &meta_flows[0]);
312   return 0;
313 }
314
315 int GTSim::run(double delta){
316   meta_flg=0;
317   sim_->Run(delta);
318   return 0;
319 }
320
321 void GTSim::set_jitter(double d){
322   xbt_assert1(((0 <= d)&&(d <= 1)), "The jitter value must be within interval [0.0;1.0], got %f", d);
323   jitter_ = d;
324 }
325
326 void GTSim::set_jitter_seed(int s){
327   jitter_seed_ = s;
328 }
329
330 void static tcp_sent_callback(void* action, double completion_time){
331   // Schedule the flow complete event.
332   SimulatorEvent* e =
333     new SimulatorEvent(SimulatorEvent::FLOW_COMPLETE);
334   Simulator::instance->Schedule(e, 0, Simulator::instance);
335
336   if (meta_flg){
337     meta_flows.push_back(action);
338     (*meta_nflow)++;
339   }
340 }
341
342