jobs.cc
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:35k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /*
  2.  * Copyright (c) 2000-2002, by the Rector and Board of Visitors of the 
  3.  * University of Virginia.
  4.  * All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms, 
  7.  * with or without modification, are permitted provided 
  8.  * that the following conditions are met:
  9.  *
  10.  * Redistributions of source code must retain the above 
  11.  * copyright notice, this list of conditions and the following 
  12.  * disclaimer. 
  13.  *
  14.  * Redistributions in binary form must reproduce the above 
  15.  * copyright notice, this list of conditions and the following 
  16.  * disclaimer in the documentation and/or other materials provided 
  17.  * with the distribution. 
  18.  *
  19.  * Neither the name of the University of Virginia nor the names 
  20.  * of its contributors may be used to endorse or promote products 
  21.  * derived from this software without specific prior written 
  22.  * permission. 
  23.  *
  24.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 
  25.  * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 
  26.  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
  27.  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
  28.  * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE 
  29.  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 
  30.  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
  31.  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
  32.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 
  33.  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
  34.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
  35.  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 
  36.  * THE POSSIBILITY OF SUCH DAMAGE.
  37.  */
  38. /*
  39.  *                                                                     
  40.  * JoBS - ns-2 prototype implementation                                
  41.  *                                                                     
  42.  * Author: Nicolas Christin <nicolas@cs.virginia.edu>, 2000-2002       
  43.  *       
  44.  * JoBS algorithms originally devised and proposed by       
  45.  * Nicolas Christin and Jorg Liebeherr                                 
  46.  * Grateful acknowledgments to Tarek Abdelzaher for his help and       
  47.  * comments.                                                           
  48.  *                                                                     
  49.  * $Id: jobs.cc,v 1.3 2005/07/27 01:13:44 tomh Exp $                   
  50.  *                
  51.  */
  52. #include "jobs.h"
  53. static class JoBSClass : public TclClass {
  54. public:
  55.   JoBSClass() : TclClass("Queue/JoBS") {}
  56.   TclObject* create(int, const char*const*) {
  57.     return (new JoBS);
  58.   }
  59. } class_jobs;
  60. JoBS::JoBS() : link_(NULL) {
  61. for (int i=1; i<=NO_CLASSES; i++) 
  62. cls_[i] = new PacketQueue;
  63. bind_bool("drop_front_", &drop_front_);
  64. bind_bool("trace_hop_", &trace_hop_);
  65. bind("mean_pkt_size_", &mean_pkt_size_);  // avg pkt size
  66. bind("adc_resolution_type_", &adc_resolution_type_);
  67. bind_bool("shared_buffer_", &shared_buffer_);
  68. total_backlog_Pkts_  = 0;
  69. total_backlog_Bits_  = 0;
  70. pkt_count_ = 0;
  71. idle_ = 1;
  72. ABS_present_ = FALSE;
  73. monitoring_window_ = 0;
  74. last_arrival_ = 0;
  75. last_monitor_update_ = 0;
  76. sliding_arv_pkts_=0;
  77. util_ = 0;
  78. for (int i=1; i<=NO_CLASSES; i++) {
  79. RDC_[i] = (double)i; 
  80. RLC_[i] = (double)i;
  81. ADC_[i] = INFINITY;
  82. ALC_[i] = INFINITY;
  83. sliding_serviced_pkts_[i] = 0;
  84. sliding_serviced_bits_[i] = 0;
  85. sliding_arv_pkts_c[i] = 0;
  86. sliding_class_delay_[i] = 0;
  87. sliding_class_service_rate_[i] = 0;
  88. last_xmit_[i] = 0;
  89. avg_elapsed_[i] = 0.0;
  90. excess_drops_[i] = 0.0;
  91. Rout_last_up_[i] = 0.0;
  92. min_drop_[i] = 0.0;
  93. max_drop_[i] = 1.0;
  94. error_[i] = 0.0;
  95. min_rate_[i] = 0.0;
  96. backlog_Pkts_[i] = 0;
  97. backlog_Bits_[i] = 0;
  98. service_rate_[i] = 0;
  99. current_loss_[i] = 0;
  100. Rout_[i] = 0;
  101. Rin_[i] = 0;
  102. Rout_th_[i] = 0;
  103. last_rate_update_[i] = 0;
  104. }  
  105. }
  106. int JoBS::command(int argc, const char*const* argv) {
  107. Tcl& tcl = Tcl::instance();
  108. double tmp[NO_CLASSES+1];
  109. if (argc >= NO_CLASSES+2) { /* input RDCs/RLCs/ADCs/ALCs */
  110. if (strcmp(argv[1], "init-rdcs") == 0) {
  111. RDC_[0] = -1;
  112. for (int i=1; i<=NO_CLASSES; i++) {
  113. RDC_[i] = atof(argv[i+1]);
  114. if (RDC_[i] == -1)
  115. concerned_RDC_[i] = FALSE;
  116. else
  117.   concerned_RDC_[i] = TRUE;
  118. }
  119. for (int i=1; i<=NO_CLASSES;i++) {
  120. tmp[i] = 1.0;
  121. for (int j = 1; j <= i-1; j++) 
  122.   if (concerned_RDC_[j]) tmp[i] *= RDC_[j];
  123. }
  124. for (int i=1; i<=NO_CLASSES; i++) {
  125. prod_others_[i] = 1.0;
  126. for (int j = 1; j <= NO_CLASSES; j++) 
  127. if ((j != i)&&(concerned_RDC_[j]))
  128.   prod_others_[i] *= tmp[j];
  129. }
  130. if (argc == NO_CLASSES+2) {
  131. fprintf(stdout, "nConfigured RDC, with:n");
  132. for (int i=1; i<=NO_CLASSES; i++) {
  133. fprintf(stdout, "tClass %d: ",i);
  134. if (concerned_RDC_[i]) 
  135. fprintf(stdout, "t%ft(%f)n", (double)RDC_[i], (double) prod_others_[i]);
  136. else 
  137. fprintf(stdout, "tNot concernedn");
  138. }
  139. }
  140. return (TCL_OK);
  141. }
  142. if (strcmp(argv[1], "init-rlcs") == 0) {
  143. RLC_[0] = -1;
  144. for (int i=1; i<=NO_CLASSES; i++) {
  145. RLC_[i] = atof(argv[i+1]);
  146. if (RLC_[i] == -1)
  147. concerned_RLC_[i] = FALSE;
  148. else
  149. concerned_RLC_[i] = TRUE;
  150. }
  151. for (int i=1; i<=NO_CLASSES;i++) {
  152. tmp[i] = 1.0;
  153. for (int j = 1; j <= i-1; j++) 
  154. if (concerned_RLC_[j]) 
  155. tmp[i] *= RLC_[j];
  156. }
  157. for (int i=1; i<=NO_CLASSES; i++) {
  158. loss_prod_others_[i] = 1.0;
  159. for (int j = 1; j <= NO_CLASSES; j++) 
  160. if ((j != i)&&(concerned_RLC_[j]))
  161. loss_prod_others_[i] *= tmp[j];
  162. }
  163. if (argc == NO_CLASSES+2) {
  164. fprintf(stdout, "nConfigured RLC, with:n");
  165. for (int i=1; i<=NO_CLASSES; i++) {
  166. fprintf(stdout, "tClass %d: ",i);
  167. if (concerned_RLC_[i]) 
  168. fprintf(stdout, "t%ft(%f)n", (double)RLC_[i], (double)loss_prod_others_[i]);
  169. else 
  170. fprintf(stdout, "tNot concernedn");
  171. }
  172. }
  173. return (TCL_OK);
  174. }
  175. if (strcmp(argv[1], "init-adcs") == 0) {
  176. ADC_[0] = -1;
  177. for (int i=1; i<=NO_CLASSES; i++) {
  178. ADC_[i] = atof(argv[i+1]);
  179. if (ADC_[i] == -1) {
  180. concerned_ADC_[i] = FALSE;
  181. ADC_[i] = INFINITY;
  182. } else {
  183. concerned_ADC_[i] = TRUE;
  184. ABS_present_ = TRUE;
  185. }
  186. }
  187. if (argc == NO_CLASSES+2) {
  188. fprintf(stdout, "nConfigured ADC, with:n");
  189. for (int i=1; i<=NO_CLASSES; i++) {
  190. fprintf(stdout, "tClass %d: ", i);
  191. if (concerned_ADC_[i]) 
  192. fprintf(stdout, "t%f secsn", (double)ADC_[i]);
  193. else 
  194. fprintf(stdout, "tNot concernedn");
  195. }
  196. }
  197. return (TCL_OK);
  198. }
  199. if (strcmp(argv[1], "init-alcs") == 0) {
  200. ALC_[0] = -1;
  201. for (int i=1; i<=NO_CLASSES; i++) {
  202. ALC_[i] = atof(argv[i+1]);
  203. if (ALC_[i] == -1) {
  204. concerned_ALC_[i] = FALSE;
  205. ALC_[i] = INFINITY;
  206. } else
  207. concerned_ALC_[i] = TRUE;
  208. }
  209. if (argc == NO_CLASSES+2) {
  210. fprintf(stdout, "nConfigured ALC, with:n");
  211. for (int i=1; i<=NO_CLASSES; i++) {
  212. fprintf(stdout, "tClass %d: ",i);
  213. if (concerned_ALC_[i])  
  214. fprintf(stdout, "t%fn", (double)ALC_[i]);
  215. else 
  216. fprintf(stdout, "tNot concernedn");
  217. }
  218. }
  219. return (TCL_OK);
  220. }
  221. if (strcmp(argv[1], "init-arcs") == 0) {
  222. ARC_[0] = -1;
  223. for (int i=1; i<=NO_CLASSES; i++) {
  224. ARC_[i] = atof(argv[i+1]);
  225. if (ARC_[i] == -1) {
  226. concerned_ARC_[i] = FALSE;
  227. ARC_[i] = 0;
  228. } else {
  229. concerned_ARC_[i] = TRUE;
  230. ABS_present_ = TRUE;
  231. }
  232. }
  233. if (argc == NO_CLASSES+2) {
  234. fprintf(stdout, "nConfigured ARC, with:n");
  235. for (int i=1; i<=NO_CLASSES; i++) {
  236. fprintf(stdout, "tClass %d: ",i);
  237. if (concerned_ARC_[i])  
  238. fprintf(stdout, "t%fn", (double)ARC_[i]);
  239. else 
  240. fprintf(stdout, "tNot concernedn");
  241. }
  242. }
  243. return (TCL_OK);
  244. }
  245. } else if (argc == 3) {
  246. if (strcmp(argv[1], "link") == 0) {
  247. LinkDelay* del = (LinkDelay*)TclObject::lookup(argv[2]);
  248. if (del == 0) {
  249. tcl.resultf("JoBS: no LinkDelay object %s",
  250.     argv[2]);
  251. return(TCL_ERROR);
  252. }
  253. link_ = del;
  254. for (int i=1; i <= NO_CLASSES; i++)
  255. service_rate_[i] = 0;
  256. return (TCL_OK);
  257. }
  258. if (strcmp(argv[1], "sampling-period") == 0) {
  259. sampling_period_ = atoi(argv[2]);
  260. if (sampling_period_ < 0) {
  261. fprintf(stderr, "JoBS: sampling period must be positive!!n");
  262. abort();
  263. return (TCL_ERROR); // __NOT REACHED__
  264. } else 
  265. return (TCL_OK);      
  266. }
  267. if (strcmp(argv[1], "id") == 0) {
  268. link_id_ = (int)atof(argv[2]);
  269. return (TCL_OK);
  270. }
  271. if (strcmp(argv[1], "trace-file") == 0) {
  272. file_name_ = new(char[500]);
  273. strcpy(file_name_, argv[2]);
  274. if (strcmp(file_name_, "null")) {
  275. trace_hop_ = true;
  276. } else {
  277. trace_hop_ = false;
  278. }
  279. return (TCL_OK);
  280. }
  281. } else if (argc == 2) {
  282. if (strcmp(argv[1], "initialize") == 0) {
  283. double myMaxPi=0;
  284. for (int i = 1; i <= NO_CLASSES; i++) 
  285. if (prod_others_[i] > myMaxPi) 
  286. myMaxPi = prod_others_[i];
  287. Kp_static_ = -2/(double)(myMaxPi*mean_pkt_size_*sampling_period_);
  288.       // Open files
  289. if (trace_hop_) {
  290. if ((hop_trace_ = fopen(file_name_, "w"))==NULL) {
  291. fprintf(stderr, "Problem with opening the per-hop trace file: %sn", file_name_);
  292. abort();   
  293. }
  294. }    
  295. return (TCL_OK);
  296. }
  297. if (strcmp(argv[1], "copyright-info") == 0) {
  298. fprintf(stdout, "n----------------------------------------------------------nn");
  299. fprintf(stdout, "JoBS scheduler/dropper [prototype ns-2 implementation]n");
  300. fprintf(stdout, "Version 1.0 (CVS Revision: $Id: jobs.cc,v 1.3 2005/07/27 01:13:44 tomh Exp $)nn");
  301. fprintf(stdout, "ns-2 implementation by Nicolas Christin <nicolas@cs.virginia.edu>n");
  302. fprintf(stdout, "JoBS algorithms proposed by Nicolas Christin and Jorg Liebeherr.n");
  303. fprintf(stdout, "Grateful acknowledgments to Tarek Abdelzaher for his help and comments.n");
  304. fprintf(stdout, "Visit http://qosbox.cs.virginia.edu for moren");
  305. fprintf(stdout, "information.nn");
  306. fprintf(stdout, "Copyright (c) 2000-2002 by the Rector and Board of Visitors of then");
  307. fprintf(stdout, "University of Virginia.n");
  308. fprintf(stdout, "All Rights Reserved.n");
  309. fprintf(stdout, "----------------------------------------------------------nn");
  310. return (TCL_OK);
  311. }
  312. }
  313. return (Queue::command(argc, argv));
  314. }
  315. // *******************************************************************
  316. // JoBS: Simplified Packetization of the Fluid Flow Model.
  317. // *******************************************************************
  318. Packet* JoBS::deque() { // Lower classes are better. 
  319. double  cur_time  = Scheduler::instance().clock(); 
  320. double error;
  321. double maxError;
  322. int svc_class = 0;
  323.   
  324. error = 0;
  325. // Fast translation of service rates into packet forwarding decisions
  326. maxError = -INFINITY;
  327. for (int i=1; i<=NO_CLASSES; i++) {
  328. if (cls_[i]->head()) {
  329. error = (double)Rout_th_[i] - Rout_[i];
  330. if (error > maxError) {
  331. maxError = error;
  332. svc_class = i;
  333. }
  334. }
  335. }
  336. if (svc_class == 0) {
  337. idle_ = 1;
  338. if (&Scheduler::instance() != NULL)
  339. idletime_ = cur_time;
  340. else
  341. idletime_ = 0.0;
  342. return NULL; /* Idle system */
  343. } else {
  344. idle_ = 0;
  345. Packet* p = cls_[svc_class]->deque();
  346. hdr_cmn* cm_h = hdr_cmn::access(p);
  347.     
  348. total_backlog_Pkts_--;
  349. total_backlog_Bits_ -= 8*cm_h->size();
  350. backlog_Pkts_[svc_class]--;
  351. backlog_Bits_[svc_class] -= 8*cm_h->size();
  352. Rout_[svc_class] += 8*cm_h->size();
  353. Rout_last_up_[svc_class] = cur_time;
  354. sliding_serviced_pkts_[svc_class] ++;
  355. sliding_serviced_bits_[svc_class] += 8*cm_h->size();
  356. sliding_class_delay_[svc_class] 
  357.   = ((sliding_serviced_pkts_[svc_class]-1)*(sliding_class_delay_[svc_class])
  358.      +(cur_time-cm_h->ts_))/(sliding_serviced_pkts_[svc_class]);
  359. last_xmit_[svc_class] = cur_time+(8.*cm_h->size()/(double)link_->bandwidth());
  360. return(p);
  361. }
  362. }
  363. // *******************************************************************
  364. // JoBS: Enqueue packet 
  365. // *******************************************************************
  366. void JoBS::enque(Packet* pkt) {
  367. double* DeltaR;
  368. int i;
  369. hdr_ip*  ip_h = hdr_ip::access(pkt);
  370. hdr_cmn* cm_h = hdr_cmn::access(pkt);
  371. int prio = ip_h->prio_;
  372. if ((prio < 1) || (prio > NO_CLASSES)) {
  373. printf("Bad priority valuen");
  374. abort();
  375. }
  376.   
  377. double cur_time = Scheduler::instance().clock(); 
  378. cm_h->ts_ = cur_time; // timestamp the packet
  379. cls_[prio]->enque(pkt);
  380. monitoring_window_ -= cur_time-last_monitor_update_;
  381. last_monitor_update_ = cur_time;
  382. if (monitoring_window_ <= 0) {
  383. updateStats(pkt, RESET_STATS);
  384. monitoring_window_ = MON_WINDOW_SIZE;
  385. } else {
  386. updateStats(pkt, UPDATE_STATS);
  387. }
  388. // Reset arrival, input, and service curves if the scheduler is 
  389. // not busy
  390. if (idle_) {
  391. for (i=1; i<= NO_CLASSES; i++) {
  392.   Arrival_[i]=0.0;
  393.   Rin_[i]=0.0;
  394.   Rout_[i]=0.0;
  395.   Rout_th_[i]=0.0;
  396.   last_rate_update_[i] = 0;
  397.   Rout_last_up_[i] = cur_time;
  398.   idle_ = 0;
  399. }
  400. }
  401. arvAccounting(pkt);
  402. /* Is the buffer full? */  
  403. if (!shared_buffer_ && backlog_Pkts_[prio] > qlim_/NO_CLASSES) {
  404. /* separate buffers: no guarantees on packet drops 
  405.  * can be offered
  406.  * thus we drop the incoming packet
  407.  */
  408. if (drop_front_)
  409. dropFront(prio, WITH_UPDATE);
  410. else
  411. dropTail(prio, WITH_UPDATE);    
  412. } else {
  413.   /* shared buffer */
  414. if (total_backlog_Pkts_ > qlim_) {
  415. if (!concerned_RLC_[prio]) {
  416. if (!concerned_ALC_[prio]) {
  417. // No ALC, no RLC on that class. Drop the incoming packet.
  418. if (drop_front_)
  419. dropFront(prio, WITH_UPDATE);
  420. else
  421. dropTail(prio, WITH_UPDATE);
  422. } else {
  423. // No RLC on that class. Drop the incoming packet if you can...
  424. if (current_loss_[prio]+(double)8*cm_h -> size()/(double)Arrival_[prio] <= ALC_[prio]) {
  425. if (drop_front_)
  426. dropFront(prio, WITH_UPDATE);
  427. else     
  428. dropTail(prio, WITH_UPDATE);
  429. } else {
  430. // If it doesn't work, pick another class
  431. if (drop_front_)
  432. dropFront(pickDroppedRLC(RESOLVE_OVERFLOW), WITH_UPDATE);
  433. else     
  434. dropTail(pickDroppedRLC(RESOLVE_OVERFLOW), WITH_UPDATE);
  435. }
  436. }
  437. } else {
  438. // RLC on that class (w/ or w/o ALC), pick a class according to the RLC
  439.   if (drop_front_)
  440. dropFront(pickDroppedRLC(RESOLVE_OVERFLOW), WITH_UPDATE);
  441.   else     
  442. dropTail(pickDroppedRLC(RESOLVE_OVERFLOW), WITH_UPDATE);
  443. }
  444. }
  445. }
  446. pkt_count_ ++;
  447. enforceWC(); // Change rates if some classes have entered/left the system
  448. // since the last update
  449. if ((ABS_present_)&&(!minRatesNeeded(ip_h -> prio()))) {
  450. DeltaR = assignRateDropsADC();   
  451. if (DeltaR != NULL) {
  452. for (i = 1; i <= NO_CLASSES; i++) 
  453. service_rate_[i] += DeltaR[i];
  454. delete []DeltaR; 
  455. }
  456. DeltaR = adjustRatesRDC();
  457. if (DeltaR) {
  458. for (i = 1; i <= NO_CLASSES; i++) 
  459. service_rate_[i] += DeltaR[i];
  460. delete []DeltaR;   
  461. }
  462. pkt_count_ = 0;
  463. } else if (pkt_count_ >= sampling_period_) {
  464. /* Is it time for a new evaluation of the system? */
  465. DeltaR = adjustRatesRDC();
  466. if (DeltaR != NULL) {
  467. for (i = 1; i <= NO_CLASSES; i++)
  468. service_rate_[i] += DeltaR[i];
  469. delete []DeltaR;
  470. pkt_count_ = 0;
  471. }
  472. return;
  473. }
  474. // *******************************************************************
  475. // Auxiliary functions (helpers) follow
  476. // *******************************************************************
  477. // 1) Scheduling Primitives
  478. // *******************************************************************
  479. // JoBS: Enforce Work-Conserving Property
  480. // *******************************************************************
  481. int JoBS::enforceWC() {
  482. int i;
  483. int activeClasses;
  484. int updated;
  485. updated = FALSE;
  486. activeClasses = 0;
  487. for (i = 1; i <= NO_CLASSES; i++) {
  488. if (cls_[i]->head()) 
  489. activeClasses++;
  490. if ((cls_[i] -> head() && service_rate_[i] <= PRECISION_ERROR)
  491.     ||(cls_[i] -> head() == NULL && service_rate_[i] > 0)) 
  492.   updated = TRUE;
  493. }
  494. if (updated) {
  495. for (i = 1; i <= NO_CLASSES; i++) {
  496. if (cls_[i]->head() == NULL) {
  497. service_rate_[i] = 0;
  498. } else {
  499. if (activeClasses > 0)
  500. service_rate_[i] = link_->bandwidth()/(double)activeClasses;
  501. else 
  502. service_rate_[i] = 0 ;
  503. }
  504. }
  505. }
  506. return (updated);
  507. }
  508. // *******************************************************************
  509. // JoBS: Adjusts the rates for meeting the RDCs
  510. // *******************************************************************
  511. double* JoBS::adjustRatesRDC() {
  512. int i, j;
  513. int RDC_Classes, activeClasses;
  514. double* result;
  515. double credit, available, lower_bound, upper_bound;
  516. double bk;
  517. double cur_time;
  518. cur_time = Scheduler::instance().clock(); 
  519.   
  520. activeClasses = 0;
  521. RDC_Classes = 0;
  522. upper_bound = link_ -> bandwidth();
  523. for (i = 1; i <= NO_CLASSES; i++)
  524. if (cls_[i]->head() != NULL) {
  525. activeClasses++;
  526. if (concerned_RDC_[i]) 
  527. RDC_Classes++;
  528. else 
  529. upper_bound -= service_rate_[i];
  530. }
  531. result = new double[NO_CLASSES+1];
  532. if (result == NULL) 
  533. return NULL;
  534. for (i = 0; i <= NO_CLASSES; i++) 
  535. result[i] = 0;
  536. if (upper_bound < PRECISION_ERROR || activeClasses == 0) return result;
  537. credit = 0;
  538. lower_bound = 0;
  539. updateError();
  540. min_share_ = 1.0;
  541. bk = 0;
  542. for (i = 1; i <= NO_CLASSES; i++) 
  543. if (concerned_RDC_[i])
  544. bk += Rin_[i];
  545. for (i = 1; i <= NO_CLASSES; i++) 
  546. if ((double)Rin_[i]/(double)bk < min_share_)
  547. min_share_ = (double)Rin_[i]/(double)bk;
  548.   
  549. /*
  550.  * note that the formula for Kp is slightly different 
  551.  * from the formula derived in CS-2001-21. 
  552.  * the formula used here provides better results 
  553.  * at the expense of more complicated computations.
  554.  */
  555. Kp_dynamic_ = Kp_static_*pow(upper_bound, 2.)*min_share_*util_*max(util_, 1.0);
  556. credit = 0;
  557. for (i = 1; i <= NO_CLASSES; i++) {
  558. if ((cls_[i]->head() != NULL)&&(concerned_RDC_[i])) {
  559. result[i] = Kp_dynamic_*(error_[i]); 
  560. }
  561. }
  562. // saturation 
  563. for (i = 1; i <= NO_CLASSES; i++) 
  564. if (cls_[i]->head() != NULL) {
  565. if (concerned_RDC_[i]) {
  566. lower_bound += max(0, min_rate_[i]);
  567. }
  568. for (i = 1; i <= NO_CLASSES; i++) {
  569. if ((concerned_RDC_[i])&&(result[i] + service_rate_[i] > upper_bound)) {
  570. for (j = 0; j <= NO_CLASSES; j++) {
  571. if (concerned_RDC_[j]) {
  572. if (j == i) 
  573. result[j] = (upper_bound-service_rate_[j])  
  574.     + min_rate_[j] - lower_bound;
  575. else
  576. result[j] = -service_rate_[j]+min_rate_[j];
  577. }
  578. }
  579. return result;
  580. }
  581. if (concerned_RDC_[i] && result[i] + service_rate_[i] < min_rate_[i]) {
  582. credit += service_rate_[i]+result[i]-min_rate_[i]; 
  583. // "credit" is in fact a negative number
  584. result[i] = -service_rate_[i]+min_rate_[i];
  585. }
  586. }
  587. for (i = NO_CLASSES; (i > 0)&&(credit < 0); i--) {
  588. if ((cls_[i]->head() != NULL)&&(concerned_RDC_[i])) {
  589. available = result[i] + service_rate_[i]-min_rate_[i];
  590. if (available >= -credit) {
  591. result[i] += credit;
  592. credit = 0;
  593. } else {
  594. result[i] -= available;
  595. credit += available;
  596. }      
  597. }
  598. }
  599. return result;
  600. }
  601. // *******************************************************************
  602. // JoBS: Assigns the rates (and possibly drops some traffic) 
  603. // needed for meeting the ADCs
  604. // *******************************************************************
  605. double* JoBS::assignRateDropsADC() {
  606. double* x;
  607. //double myRatios[NO_CLASSES+1];
  608. double c[NO_CLASSES+1], n[NO_CLASSES+1];
  609. double k[NO_CLASSES+1], target[NO_CLASSES+1];
  610. double available[NO_CLASSES+1];
  611. double toDrop;
  612. int lowest, highest;
  613. int victim_class, keep_going;
  614. int i;
  615. Packet* p; 
  616. hdr_cmn* cm_h; 
  617. double cur_time = Scheduler::instance().clock(); 
  618. x = new double[NO_CLASSES+1];
  619. if (x == NULL) return NULL;
  620. for (i = 0;i <= NO_CLASSES; i++) 
  621. x[i] = 0;
  622. keep_going = TRUE;
  623. for (i = 1; i <= NO_CLASSES; i++) {
  624. if (cls_[i]->head() != NULL) {
  625. p = cls_[i]->head();
  626. cm_h = hdr_cmn::access(p);
  627. n[i] = (double)service_rate_[i];
  628. k[i] = (double)backlog_Bits_[i];
  629. available[i] = service_rate_[i];
  630. if (concerned_ADC_[i]) { 
  631. c[i] = (double)max((double)ADC_[i]-(cur_time-cm_h->ts_),1e-10);
  632. target[i] = (double)k[i]/(double)c[i];
  633. available[i] = -(target[i] - n[i]); 
  634. if (concerned_ARC_[i]) { 
  635. if (n[i] - ARC_[i] < available[i])
  636. available[i] = n[i] - ARC_[i];
  637. }
  638. } else {
  639. available[i] = service_rate_[i];
  640. n[i] = 0;
  641. k[i] = 0;
  642. c[i] = 0;
  643. }
  644. }
  645. // Step 1: Adjust rates 
  646. highest = 1;
  647. lowest  = NO_CLASSES;
  648. while ((highest < NO_CLASSES+1)&&(available[highest] >= 0))
  649. highest++; // which is the highest class that needs more service? 
  650. while ((lowest > 0)&&(available[lowest] <= 0))
  651. lowest--;  // which is the lowest class that needs less service? 
  652. while ((highest != NO_CLASSES+1)&&(lowest != 0)) {
  653. // give the excess service from lowest to highest 
  654. if (available[lowest]+available[highest] > 0) {
  655. // Still some "credit" left 
  656. // Give all that is needed by "highest" 
  657. n[lowest]  -= -available[highest];
  658. n[highest] += -available[highest];
  659. available[lowest]  -= -available[highest];
  660. available[highest] = 0;
  661. while ((highest < NO_CLASSES+1)&&(available[highest] >= 0))
  662. highest++;  // which is the highest class that needs more service? 
  663. } else if (available[lowest]+available[highest] == 0) {
  664. // No more credit left but it's fine 
  665. n[lowest]  -= -available[highest];
  666. n[highest] += -available[highest];
  667. available[highest] = 0;
  668. available[lowest]  = 0;
  669. while ((highest < NO_CLASSES+1)&&(available[highest] >= 0))
  670. highest++;  // which is the highest class that needs more service? 
  671. while ((lowest > 0)&&(available[lowest] <= 0))
  672. lowest--;   // which is the lowest class that needs less service? 
  673. } else if (available[lowest]+available[highest] < 0) {
  674. // No more credit left and we need to switch to another class 
  675. n[lowest]  -= available[lowest];
  676. n[highest] += available[lowest];
  677. available[highest] += available[lowest];
  678. available[lowest]  = 0;
  679. while ((lowest > 0)&&(available[lowest] <= 0))
  680. lowest--;  // which is the lowest class that needs less service? 
  681. }
  682. }
  683. for (i = 1; i <= NO_CLASSES; i++) {
  684. if (cls_[i]->head() != NULL)
  685. x[i] = n[i] - (double)service_rate_[i];
  686. else 
  687. x[i] = - (double)service_rate_[i] ;
  688. }
  689. // Step 2: Adjust drops 
  690. if (highest != NO_CLASSES+1) {
  691. // Some class still needs additional service 
  692. if (adc_resolution_type_ == SHARED_PAIN) {
  693. // Drop from all classes
  694. toDrop = 0;
  695. for (i = 1; i <= NO_CLASSES; i++) 
  696. if (available[i] < 0 && concerned_ADC_[i] && cls_[i]->head()) 
  697. toDrop += k[i] - c[i]*n[i];
  698. while ((toDrop > 0)&&(keep_going)) {
  699. victim_class = pickDroppedRLC(RESOLVE_ADC);
  700. if (drop_front_) 
  701. p = cls_[victim_class] -> head();
  702. else
  703. p = cls_[victim_class] -> tail();
  704.       
  705. cm_h = hdr_cmn::access(p);
  706. if (current_loss_[victim_class]+(double)8*cm_h -> size()/(double)Arrival_[victim_class] > ALC_[victim_class]) {
  707. keep_going = FALSE;
  708. } else {
  709. toDrop -= (double)8*cm_h -> size();
  710. if (drop_front_) 
  711. dropFront(victim_class, WITH_UPDATE);
  712. else
  713. dropTail(victim_class, WITH_UPDATE);
  714. }
  715. }
  716. } else {
  717. // Drop solely from the class(es) that need(s) more service
  718. for (i = 1; i <= NO_CLASSES; i++) {
  719. if (available[i] < 0 && cls_[i] -> head()) {
  720. k[i] = c[i]*n[i];
  721. while ((backlog_Bits_[i] > k[i])&&(keep_going)) {
  722. if (drop_front_) {
  723. p = cls_[i] -> head();
  724. cm_h = hdr_cmn::access(p);
  725. if (current_loss_[i]+(double)8*cm_h -> size()/(double)Arrival_[i] > ALC_[i]) {
  726. keep_going = FALSE;
  727. } else 
  728. dropFront(i, WITH_UPDATE);
  729. } else {
  730. p = cls_[i] -> tail();
  731. cm_h = hdr_cmn::access(p);
  732. if (current_loss_[i]+(double)8*cm_h -> size()/(double)Arrival_[i] > ALC_[i]) {
  733. keep_going = FALSE;
  734. } else 
  735. dropTail(i, WITH_UPDATE);
  736. }
  737. }
  738. k[i] = backlog_Bits_[i];
  739. }
  740. }      
  741. }
  742. for (i = 1; i <= NO_CLASSES; i++) 
  743. if (cls_[i]->head() && concerned_ADC_[i]) {
  744. if (c[i] > 0) {
  745. if (concerned_ADC_[i] && !concerned_ARC_[i]) {
  746. min_rate_[i] = (double)k[i]/(double)c[i];
  747. } else 
  748. min_rate_[i] = (double)n[i];
  749. } else {
  750. min_rate_[i] = INFINITY;
  751. }
  752. } else  if (cls_[i]->head() && concerned_ARC_[i]) {
  753. min_rate_[i] = n[i];
  754. } else {
  755.   min_rate_[i] = 0.0;    
  756. }
  757. return (x);
  758. }
  759. // 1bis) Scheduling Helpers
  760. // *******************************************************************
  761. // JoBS: Update Error - used by the RDC feedback loop controller
  762. // *******************************************************************
  763. void JoBS::updateError() {
  764. int i;
  765. int activeClasses, backloggedClasses;
  766. double meanWeightedDelay;
  767. meanWeightedDelay = 0;
  768. activeClasses = 0 ; 
  769. backloggedClasses = 0;
  770. for (i = 1; i <= NO_CLASSES; i++) 
  771. if (cls_[i]->head() != NULL) {
  772. backloggedClasses++;
  773. if (concerned_RDC_[i]) {
  774. meanWeightedDelay += prod_others_[i]*projDelay(i);
  775. activeClasses ++;
  776. }    
  777. }
  778. if (activeClasses > 0) 
  779. meanWeightedDelay /= (double)activeClasses;
  780. else if (backloggedClasses == 0) {
  781. fprintf(stderr, "JoBS::updateError() called but there's no backlog!n");
  782. abort();
  783. }
  784. for (i = 1; i <= NO_CLASSES; i++) 
  785. if ((cls_[i]->head() != NULL)&&(concerned_RDC_[i])) {
  786. error_[i] = meanWeightedDelay-prod_others_[i]*projDelay(i);
  787. } else {
  788. error_[i] = 0.0; // either the class isn't concerned, or it's not backlogged
  789. // in any case, the rate shouldn't be adjusted.
  790. }
  791. return;
  792. }
  793. // *******************************************************************
  794. // JoBS: Derives the rates needed for meeting the ADC.
  795. // Returns true if the sum of the rates needed for meeting the ADC
  796. // is less than the link's bandwidth, false otherwise.
  797. // It's also the place where the "RED" algorithm is triggered.
  798. // Side effect (desired): assigns a value to min_rate_[i]
  799. // *******************************************************************
  800. int JoBS::minRatesNeeded(int priority) {
  801. int result;
  802. int i;
  803. double cur_time;
  804. Packet* p;
  805. hdr_cmn* cm_h; 
  806. cur_time = Scheduler::instance().clock();
  807. result = TRUE;
  808.   
  809. for (i = 1; i <= NO_CLASSES; i++) {
  810. if (cls_[i]->head() != 0 && (concerned_ADC_[i] || concerned_ARC_[i])) {
  811. p = cls_[i]->head();
  812. cm_h = hdr_cmn::access(p);
  813. if (concerned_ADC_[i]) { 
  814. if ((ADC_[i] - (cur_time-cm_h->ts_)) > 0 ) {
  815. // min rate needed for ADC
  816. min_rate_[i] = (double)(backlog_Bits_[i])
  817.     /(double)(ADC_[i] - (cur_time-cm_h->ts_));
  818. if (concerned_ARC_[i] && ARC_[i] > min_rate_[i]) {
  819. // min rate needed for ADC+ARC
  820. min_rate_[i] = ARC_[i];
  821. }
  822. } else 
  823. min_rate_[i] = INFINITY; 
  824. } else if (concerned_ARC_[i]) {
  825. // no ADC, an ARC
  826. min_rate_[i] = ARC_[i];
  827. }
  828. if (min_rate_[i] > service_rate_[i]) 
  829. result = FALSE;
  830. } else 
  831. min_rate_[i] = 0.0;
  832. }
  833. return result;
  834. }
  835. // *******************************************************************
  836. // JoBS: Returns the value of the delay metric for class i
  837. // *******************************************************************
  838. double JoBS::projDelay(int i) {
  839. double cur_time  = Scheduler::instance().clock(); 
  840. if (cls_[i]->head() != NULL) {
  841. Packet* p = cls_[i]->head();
  842. hdr_cmn* cm_h = hdr_cmn::access(p);
  843. return (cur_time - cm_h -> ts_);
  844. } else return 0.0; // __NOT REACHED__
  845. }
  846. // 2) Dropping Primitives
  847. // *******************************************************************
  848. // JoBS: Choose which class to drop from in case of a buffer overflow
  849. // *******************************************************************
  850. int JoBS::pickDroppedRLC(int mode) {
  851. double Mean;
  852. double loss_error[NO_CLASSES+1];
  853. int i, activeClasses, backloggedClasses;
  854. int class_dropped;
  855. double maxError;
  856. double maxALC;
  857. double cur_time  = Scheduler::instance().clock(); 
  858. hdr_cmn* cm_h; 
  859. class_dropped = -1;
  860. maxError = 0;
  861. Mean = 0;
  862. activeClasses = 0;
  863. backloggedClasses = 0;
  864. for (i = 1; i <= NO_CLASSES; i++) 
  865. if (cls_[i]->head() != NULL) {
  866. backloggedClasses ++;
  867. if (concerned_RLC_[i]) {
  868. Mean += loss_prod_others_[i]*current_loss_[i];
  869. activeClasses ++;
  870. }    
  871. }
  872. if (activeClasses > 0) 
  873. Mean /= (double)activeClasses;
  874. else if (backloggedClasses == 0) {
  875. fprintf(stderr, "JoBS::pickDroppedRLC() called but there's no backlog!n");
  876. abort();
  877. }
  878. if (activeClasses == 0) 
  879. class_dropped = NO_CLASSES+1; // no classes are concerned by RLCs (NO_CLASSES+1 means "ignore RLC")
  880. else {
  881. for (i = 1; i <= NO_CLASSES; i++) 
  882. if ((cls_[i]->head() != NULL)&&(concerned_RLC_[i])) 
  883. loss_error[i]=loss_prod_others_[i]*current_loss_[i]-Mean;
  884. else 
  885. loss_error[i] = INFINITY; 
  886.     
  887. for (i = 1; i <= NO_CLASSES; i++)
  888. if ((cls_[i]->head() != NULL)&&(loss_error[i] <= maxError)) {
  889. maxError = loss_error[i]; // Find out which class is the most below the mean
  890. class_dropped = i;   // It's the one that needs to be dropped
  891. // Ties are broken in favor of the higher priority classes (i.e., if
  892. // two classes present the same deviation, the lower priority class 
  893. // will get dropped).
  894. if (class_dropped != -1) {
  895. if (drop_front_)
  896. cm_h = hdr_cmn::access(cls_[class_dropped] -> head());
  897. else
  898. cm_h = hdr_cmn::access(cls_[class_dropped] -> tail());
  899. if (current_loss_[class_dropped]+(double)8*cm_h -> size()/(double)Arrival_[class_dropped] > ALC_[class_dropped])
  900. class_dropped = NO_CLASSES+1; // the class to drop for meeting the RLC will defeat the ALC: ignore RLC.
  901. } else 
  902. class_dropped = NO_CLASSES+1;
  903. }
  904. if (class_dropped != -1) { // this test is here only for "safety purposes" 
  905. // it should always return true at this point.
  906. if (class_dropped == NO_CLASSES+1) {
  907. maxALC = -INFINITY;
  908. for (i = 1; i <= NO_CLASSES; i++) {
  909. if (cls_[i] -> tail() != NULL) {
  910. if (ALC_[i]-current_loss_[i] > maxALC);
  911. maxALC = ALC_[i]-current_loss_[i]; // pick the class which is the furthest from its ALC
  912. class_dropped = i;
  913. }
  914. }
  915. if (drop_front_)
  916.   cm_h = hdr_cmn::access(cls_[class_dropped]->head());
  917. else
  918.   cm_h = hdr_cmn::access(cls_[class_dropped]->tail());
  919. if ((mode == RESOLVE_OVERFLOW)
  920.     &&(current_loss_[class_dropped]+(double)8*cm_h -> size()/(double)Arrival_[class_dropped] > ALC_[class_dropped])) {
  921. fprintf(stderr, "*** Warning at time t=%f: ALC violated in class %d on link %dn(reason: buffer overflow impossible to resolve otherwise)nPkt size=%d bitstold_loss[%d]=%ftnew_loss[%d]=%ftArrival_[%d]=%ftALC[%d]=%fn",
  922. cur_time, link_id_,
  923. class_dropped, 8*cm_h -> size(),
  924. class_dropped, current_loss_[class_dropped],
  925. class_dropped, current_loss_[class_dropped]+(double)8*cm_h -> size()/(double)Arrival_[class_dropped],
  926. class_dropped, (double)Arrival_[class_dropped],
  927. class_dropped, ALC_[class_dropped]);
  928. }
  929. }
  930. } else {
  931. fprintf(stderr, "Trying to drop a packet, but there's nothing in any queue!n");
  932. abort();
  933. }
  934. return class_dropped;
  935. }
  936. // *******************************************************************
  937. // JoBS: Drops traffic from the tail of the specified class, and 
  938. // update the statistics.
  939. // *******************************************************************
  940. void JoBS::dropTail(int prio, int strategy) {
  941. Packet *p;
  942. hdr_cmn *cm_h;
  943. p = cls_[prio] -> tail();
  944. cm_h = hdr_cmn::access(p);
  945. total_backlog_Pkts_ --;
  946. total_backlog_Bits_ -= 8*cm_h->size();
  947. backlog_Pkts_[prio] --;
  948. backlog_Bits_[prio] -= 8*cm_h->size();
  949. Rin_[prio] -= 8*cm_h->size();
  950. if (strategy == WITH_UPDATE) {
  951. for (int i = 1; i <= NO_CLASSES; i++) 
  952. current_loss_[i] = min_drop_[i];
  953. current_loss_[prio] += (double)8*cm_h -> size()
  954.     /(double)Arrival_[prio];
  955. }
  956. cls_[prio] -> remove(p);
  957. drop(p);
  958. return;
  959. }
  960. // *******************************************************************
  961. // JoBS: Drops traffic from the head of the specified class, and 
  962. // update the statistics.
  963. // *******************************************************************
  964. void JoBS::dropFront(int prio, int strategy) {
  965. Packet *p;
  966. hdr_cmn *cm_h;
  967. p = cls_[prio] -> head();
  968. cm_h = hdr_cmn::access(p);
  969. total_backlog_Pkts_ --;
  970. total_backlog_Bits_ -= 8*cm_h->size();
  971. backlog_Pkts_[prio] --;
  972. backlog_Bits_[prio] -= 8*cm_h->size();
  973. Rin_[prio] -= 8*cm_h->size();
  974. if (strategy == WITH_UPDATE) {
  975. for (int i = 1; i <= NO_CLASSES; i++) 
  976. current_loss_[i] = min_drop_[i];
  977. current_loss_[prio] += (double)8*cm_h -> size()
  978.   /(double)Arrival_[prio];
  979. }
  980. cls_[prio] -> remove(p);
  981. drop(p);
  982. return;
  983. }  
  984. // 3) Other Helpers
  985. // *******************************************************************
  986. // JoBS: Update internal variables upon a packet arrival.
  987. // *******************************************************************
  988. void JoBS::arvAccounting(Packet* thePacket) {
  989. int i;
  990. double cur_time;
  991. hdr_cmn* cm_h;
  992. hdr_cmn* cm_h1;
  993. hdr_cmn* cm_h2; 
  994. hdr_ip*  ip_h; 
  995. cur_time = Scheduler::instance().clock();
  996. cm_h = hdr_cmn::access(thePacket);
  997. ip_h = hdr_ip::access(thePacket);
  998. /* Update curves */
  999. Arrival_[ip_h -> prio()]      += 8*cm_h -> size();
  1000. Rin_    [ip_h -> prio()]      += 8*cm_h -> size();
  1001. if (last_rate_update_[ip_h -> prio()] == 0) {
  1002. last_rate_update_[ip_h -> prio()] = cur_time;
  1003. } else {
  1004. Rout_th_ [ip_h -> prio()]      += (cur_time-last_rate_update_[ip_h -> prio()])*service_rate_[ip_h -> prio()];
  1005. last_rate_update_[ip_h -> prio()] = cur_time;
  1006. }
  1007. backlog_Pkts_[ip_h -> prio()] ++;
  1008. backlog_Bits_[ip_h -> prio()] += 8*cm_h -> size();
  1009. total_backlog_Bits_ += 8*cm_h -> size();
  1010. total_backlog_Pkts_ ++;
  1011. for (i = 1; i <= NO_CLASSES; i++) {
  1012. if (Arrival_[i] > 0) {
  1013. current_loss_[i] = (double)(Arrival_[i] - Rin_[i])/(double)(Arrival_[i]);
  1014. min_drop_[i] = (double)(max(0.0, (1.0-(double)(Rin_[i])/(double)Arrival_[i])));
  1015. max_drop_[i] = (double)(min(1.0, (1.0-(double)((double)Rout_[i]/(double)Arrival_[i]))));
  1016. } else {
  1017. current_loss_[i] = 0;
  1018. min_drop_[i] = 0.0;
  1019. max_drop_[i] = 0.0;
  1020. }
  1021. if (cls_[i]->head() != NULL) {
  1022. cm_h1 = hdr_cmn::access(cls_[i]->head());
  1023. cm_h2 = hdr_cmn::access(cls_[i]->tail());
  1024. avg_elapsed_[i] = (2*cur_time - cm_h1 -> ts_ - cm_h2 -> ts_)/((backlog_Pkts_[i]>1)? 2.0 :1.0);
  1025. }
  1026. }
  1027. return;
  1028. }
  1029. // 4) Debugging Tools
  1030. void JoBS::updateStats(Packet* p, int action) {
  1031. double cur_time = Scheduler::instance().clock();
  1032. hdr_cmn* cm_h;
  1033. hdr_ip* ip_h;
  1034. cm_h = hdr_cmn::access(p);
  1035. ip_h = hdr_ip::access(p);
  1036. if (action == UPDATE_STATS) {
  1037. sliding_arv_pkts_++;
  1038. sliding_arv_pkts_c[ip_h->prio()]++;
  1039. sliding_inter_ = (cur_time - last_arrival_ + sliding_inter_ * (sliding_arv_pkts_-1))
  1040.     /(double)sliding_arv_pkts_;
  1041. sliding_avg_pkt_size_ = (sliding_avg_pkt_size_*(sliding_arv_pkts_ - 1) + 8*cm_h->size())
  1042.     /(double)sliding_arv_pkts_; 
  1043. last_arrival_ = cur_time;
  1044. } else if (action == RESET_STATS) {
  1045. if (trace_hop_) {
  1046. fprintf(hop_trace_, "%ft", cur_time);
  1047. for (int i=1;i<=NO_CLASSES;i++) {
  1048. fprintf(hop_trace_, "%.8ft", max(current_loss_[i],0.00000001));
  1049. }
  1050. for (int i=1;i<=NO_CLASSES;i++) {
  1051. fprintf(hop_trace_, "%.8ft", max(sliding_class_delay_[i],0.00000001));
  1052. }
  1053. for (int i=1;i<=NO_CLASSES;i++) {
  1054. sliding_class_service_rate_[i] = sliding_serviced_bits_[i]/(double)MON_WINDOW_SIZE;
  1055. fprintf(hop_trace_, "%.0ft", max(sliding_class_service_rate_[i], 1));
  1056. sliding_serviced_pkts_[i] = 0;
  1057. sliding_serviced_bits_[i] = 0;
  1058. sliding_class_delay_[i] = 0;
  1059. sliding_class_service_rate_[i] = 0;
  1060. }
  1061. for (int i=1;i<=NO_CLASSES;i++) {
  1062. fprintf(hop_trace_, "%.0ft", (double)cls_[i]->length());
  1063. }
  1064. fprintf(hop_trace_, "n");
  1065. }
  1066. sliding_arv_pkts_ = 1;
  1067. sliding_arv_pkts_c[ip_h->prio()] = 1;
  1068. sliding_inter_ = cur_time - last_arrival_;
  1069. sliding_avg_pkt_size_ = 8*cm_h->size();
  1070. last_arrival_ = cur_time;
  1071. }
  1072. util_ = sliding_avg_pkt_size_ / (sliding_inter_*link_->bandwidth());
  1073. return;
  1074. }