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

通讯编程

开发平台:

Visual C++

  1. /* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
  2. /*
  3.  * Copyright (c) 1997 Regents of the University of California.
  4.  * All rights reserved.
  5.  * 
  6.  * Redistribution and use in source and binary forms, with or without
  7.  * modification, are permitted provided that the following conditions
  8.  * are met:
  9.  * 1. Redistributions of source code must retain the above copyright
  10.  *    notice, this list of conditions and the following disclaimer.
  11.  * 2. Redistributions in binary form must reproduce the above copyright
  12.  *    notice, this list of conditions and the following disclaimer in the
  13.  *    documentation and/or other materials provided with the distribution.
  14.  * 3. All advertising materials mentioning features or use of this software
  15.  *    must display the following acknowledgement:
  16.  *      This product includes software developed by the MASH Research
  17.  *      Group at the University of California Berkeley.
  18.  * 4. Neither the name of the University nor of the Research Group may be
  19.  *    used to endorse or promote products derived from this software without
  20.  *    specific prior written permission.
  21.  * 
  22.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  23.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  24.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  25.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  26.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  27.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  28.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  29.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  31.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  32.  * SUCH DAMAGE.
  33.  */
  34. #ifndef lint
  35. static const char rcsid[] =
  36.     "@(#) $Header: /cvsroot/nsnam/ns-2/tools/queue-monitor.cc,v 1.29 2004/10/28 01:21:41 sfloyd Exp $";
  37. #endif
  38. #include "queue-monitor.h"
  39. #include "trace.h"
  40. #include <math.h>
  41. int QueueMonitor::command(int argc, const char*const* argv)
  42. {
  43. Tcl& tcl = Tcl::instance();
  44. if (argc == 2) {
  45. if (strcmp(argv[1], "get-bytes-integrator") == 0) {
  46. if (bytesInt_)
  47. tcl.resultf("%s", bytesInt_->name());
  48. else
  49. tcl.resultf("");
  50. return (TCL_OK);
  51. }
  52. if (strcmp(argv[1], "get-pkts-integrator") == 0) {
  53. if (pktsInt_)
  54. tcl.resultf("%s", pktsInt_->name());
  55. else
  56. tcl.resultf("");
  57. return (TCL_OK);
  58. }
  59. if (strcmp(argv[1], "get-delay-samples") == 0) {
  60. if (delaySamp_)
  61. tcl.resultf("%s", delaySamp_->name());
  62. else
  63. tcl.resultf("");
  64. return (TCL_OK);
  65. }
  66. if (strcmp(argv[1], "printRTTs") == 0) {
  67. if (keepRTTstats_ && channel1_) {
  68. printRTTs();
  69. return (TCL_OK);
  70. }
  71. if (strcmp(argv[1], "printSeqnos") == 0) {
  72. if (keepSeqnoStats_ && channel1_) {
  73. printSeqnos();
  74. return (TCL_OK);
  75. }
  76. }
  77. if (argc == 3) {
  78. if (strcmp(argv[1], "set-bytes-integrator") == 0) {
  79. bytesInt_ = (Integrator *)
  80. TclObject::lookup(argv[2]);
  81. if (bytesInt_ == NULL)
  82. return (TCL_ERROR);
  83. return (TCL_OK);
  84. }
  85. if (strcmp(argv[1], "set-pkts-integrator") == 0) {
  86. pktsInt_ = (Integrator *)
  87. TclObject::lookup(argv[2]);
  88. if (pktsInt_ == NULL)
  89. return (TCL_ERROR);
  90. return (TCL_OK);
  91. }
  92. if (strcmp(argv[1], "set-delay-samples") == 0) {
  93. delaySamp_ = (Samples*)
  94. TclObject::lookup(argv[2]);
  95. if (delaySamp_ == NULL)
  96. return (TCL_ERROR);
  97. return (TCL_OK);
  98. }
  99. if (strcmp(argv[1], "trace") == 0) {
  100. // for printStats
  101. int mode;
  102. const char* id = argv[2];
  103. channel_ = Tcl_GetChannel(tcl.interp(), (char*)id, &mode);
  104. if (channel_ == 0) {
  105. tcl.resultf("trace: can't attach %s for writing", id);
  106. return (TCL_ERROR);
  107. }
  108. return (TCL_OK);
  109. }
  110. if (strcmp(argv[1], "traceDist") == 0) {
  111. // for printRTTs and printSeqnos distributions
  112. int mode;
  113. const char* id = argv[2];
  114. channel1_ = Tcl_GetChannel(tcl.interp(), (char*)id, &mode);
  115. if (channel1_ == 0) {
  116. tcl.resultf("trace: can't attach %s for writing", id);
  117. return (TCL_ERROR);
  118. }
  119. return (TCL_OK);
  120. }
  121. }
  122. if (argc == 4) {
  123. if (strcmp(argv[1], "set-src-dst") == 0) {
  124. srcId_ = atoi(argv[2]);
  125. dstId_ = atoi(argv[3]);
  126. return (TCL_OK);
  127. }
  128. }
  129. return TclObject::command(argc, argv); // else control reaches end of
  130. // non-void function, see? :-)
  131. }
  132. static class QueueMonitorClass : public TclClass {
  133.  public:
  134. QueueMonitorClass() : TclClass("QueueMonitor") {}
  135. TclObject* create(int, const char*const*) {
  136. return (new QueueMonitor());
  137. }
  138. } queue_monitor_class;
  139. void
  140. QueueMonitor::printRTTs() {
  141. int i, n, topBin, MsPerBin;
  142. char wrk[500];
  143. topBin = maxRTT_ * binsPerSec_;
  144. MsPerBin = int(1000/binsPerSec_);
  145. double now = Scheduler::instance().clock();
  146. sprintf(wrk, "Distribution of RTTs, %d ms bins, time %4.2fn", MsPerBin, now);
  147. n = strlen(wrk); wrk[n] = 0;
  148. (void)Tcl_Write(channel1_, wrk, n);
  149. for (i = 0; i < topBin; i++) {
  150. if (RTTbins_[i] > 0) {
  151.     sprintf(wrk, "%d to %d ms: frac %5.3f num %d time %4.2fn", 
  152.       i*MsPerBin, (i+1)*MsPerBin, 
  153.   (double)RTTbins_[i]/numRTTs_,
  154.       RTTbins_[i], now); 
  155. n = strlen(wrk); wrk[n] = 0; 
  156. (void)Tcl_Write(channel1_, wrk, n);
  157. }
  158. }
  159. i = topBin - 1;
  160. if (RTTbins_[i] > 0) {
  161. sprintf(wrk, "The last bin might also contain RTTs >= %d ms.n",
  162. (i+1)*MsPerBin);
  163. n = strlen(wrk); wrk[n] = 0;
  164. (void)Tcl_Write(channel1_, wrk, n);
  165. }
  166. }
  167. void
  168. QueueMonitor::printSeqnos() {
  169. int i, n, topBin; 
  170. char wrk[500];
  171. topBin = int(maxSeqno_ / SeqnoBinSize_);
  172. double now = Scheduler::instance().clock();
  173. sprintf(wrk, "Distribution of Seqnos, %d seqnos per bin, time %4.2fn", 
  174.    SeqnoBinSize_, now);
  175.   n = strlen(wrk); wrk[n] = 0;
  176. (void)Tcl_Write(channel1_, wrk, n);
  177. for (i = 0; i < topBin; i++) {
  178. if (SeqnoBins_[i] > 0) {
  179.     sprintf(wrk, "%d to %d seqnos: frac %5.3f num %d time %4.2fn", 
  180.       i*SeqnoBinSize_, (i+1)*SeqnoBinSize_ - 1, 
  181.   (double)SeqnoBins_[i]/numSeqnos_,
  182.       SeqnoBins_[i], now); 
  183. n = strlen(wrk); wrk[n] = 0;
  184. (void)Tcl_Write(channel1_, wrk, n);
  185. }
  186. }
  187. i = topBin - 1;
  188. if (SeqnoBins_[i] > 0) {
  189. sprintf(wrk, "The last bin might also contain Seqnos >= %d. n",
  190. (i+1)*SeqnoBinSize_);
  191. n = strlen(wrk); wrk[n] = 0;
  192. (void)Tcl_Write(channel1_, wrk, n);
  193. }
  194. }
  195. void
  196. QueueMonitor::printStats() {
  197. char wrk[500];
  198. int n;
  199. double now = Scheduler::instance().clock();
  200. sprintf(wrk, "q -t "TIME_FORMAT" -s %d -d %d -l %d -p %d", now, srcId_, dstId_, size_, pkts_);
  201. n = strlen(wrk);
  202. wrk[n] = 'n';
  203. wrk[n+1] = 0;
  204. (void)Tcl_Write(channel_, wrk, n+1);
  205. wrk[n] = 0;
  206. }
  207. // packet arrival to a queue
  208. void QueueMonitor::in(Packet* p)
  209. {
  210. hdr_cmn* hdr = hdr_cmn::access(p);
  211. double now = Scheduler::instance().clock();
  212. int pktsz = hdr->size();
  213. hdr_flags* pf = hdr_flags::access(p);
  214. last_pkt_ = Scheduler::instance().clock();
  215. if (parrivals_ == 0) {
  216. first_pkt_ = last_pkt_;
  217. }
  218. if (pf->qs()) {
  219. qs_pkts_++;
  220. qs_bytes_ += pktsz;
  221. }
  222.         //if enabled estimate rate now
  223. if (estimate_rate_) {
  224. estimateRate(p);
  225. }
  226. else {
  227. prevTime_ = now;
  228. }
  229. barrivals_ += pktsz;
  230. parrivals_++;
  231. size_ += pktsz;
  232. pkts_++;
  233. if (bytesInt_)
  234. bytesInt_->newPoint(now, double(size_));
  235. if (pktsInt_)
  236. pktsInt_->newPoint(now, double(pkts_));
  237. if (delaySamp_)
  238. hdr->timestamp() = now;
  239. if (channel_)
  240. printStats();
  241. }
  242. void QueueMonitor::out(Packet* p)
  243. {
  244. hdr_cmn* hdr = hdr_cmn::access(p);
  245. hdr_flags* pf = hdr_flags::access(p);
  246. double now = Scheduler::instance().clock();
  247. int pktsz = hdr->size();
  248. if (pf->ce() && pf->ect()) 
  249. pmarks_++;
  250. size_ -= pktsz;
  251. pkts_--;
  252. bdepartures_ += pktsz;
  253. pdepartures_++;
  254. if (bytesInt_)
  255. bytesInt_->newPoint(now, double(size_));
  256. if (pktsInt_)
  257. pktsInt_->newPoint(now, double(pkts_));
  258. if (delaySamp_)
  259. delaySamp_->newPoint(now - hdr->timestamp());
  260.         if (keepRTTstats_) {
  261. keepRTTstats(p);
  262. }
  263.         if (keepSeqnoStats_) {
  264. keepSeqnoStats(p);
  265. }
  266. if (channel_)
  267. printStats();
  268. }
  269. void QueueMonitor::drop(Packet* p)
  270. {
  271. hdr_cmn* hdr = hdr_cmn::access(p);
  272. double now = Scheduler::instance().clock();
  273. int pktsz = hdr->size();
  274. hdr_flags* pf = hdr_flags::access(p);
  275. size_ -= pktsz;
  276. pkts_--;
  277. bdrops_ += pktsz;
  278. pdrops_++;
  279. if (pf->qs())
  280. qs_drops_++;
  281. if (bytesInt_)
  282. bytesInt_->newPoint(now, double(size_));
  283. if (pktsInt_)
  284. pktsInt_->newPoint(now, double(pkts_));
  285. if (channel_)
  286. printStats();
  287. }
  288. // The procedure to estimate the rate of the incoming traffic
  289. void QueueMonitor::estimateRate(Packet *pkt) {
  290. hdr_cmn* hdr  = hdr_cmn::access(pkt);
  291. int pktSize   = hdr->size() << 3; /* length of the packet in bits */
  292. double now = Scheduler::instance().clock();
  293. double timeGap = ( now - prevTime_);
  294. if (timeGap == 0) {
  295. temp_size_ += pktSize;
  296. return;
  297. }
  298. else {
  299. pktSize+= temp_size_;
  300. temp_size_ = 0;
  301. }
  302. prevTime_ = now;
  303. estRate_ = (1 - exp(-timeGap/k_))*((double)pktSize)/timeGap + exp(-timeGap/k_)*estRate_;
  304. }
  305. //The procedure to keep RTT statistics.
  306. void QueueMonitor::keepRTTstats(Packet *pkt) {
  307.         int i, j, topBin, rttInMs, MsPerBin;
  308. hdr_cmn* hdr  = hdr_cmn::access(pkt);
  309. packet_t t = hdr->ptype();
  310. if (t == PT_TCP || t == PT_HTTP || t == PT_FTP || t == PT_TELNET) {
  311. hdr_tcp *tcph = hdr_tcp::access(pkt);
  312. rttInMs = tcph->last_rtt(); 
  313. if (rttInMs < 0) rttInMs = 0;
  314. topBin = maxRTT_ * binsPerSec_;
  315. if (numRTTs_ == 0) {
  316. RTTbins_ = (int *)malloc(sizeof(int)*topBin);
  317. for (i = 0; i < topBin; i++) {
  318. RTTbins_[i] = 0;
  319. }
  320. }
  321. MsPerBin = int(1000/binsPerSec_);
  322. j = (int)(rttInMs/MsPerBin);
  323. if (j < 0) j = 0;
  324. if (j >= topBin) j = topBin - 1;
  325. ++ RTTbins_[j];
  326. ++ numRTTs_;
  327. }
  328. }
  329. //The procedure to keep Seqno (sequence number) statistics.
  330. void QueueMonitor::keepSeqnoStats(Packet *pkt) {
  331.         int i, j, topBin, seqno; 
  332. hdr_cmn* hdr  = hdr_cmn::access(pkt);
  333. packet_t t = hdr->ptype();
  334. if (t == PT_TCP || t == PT_HTTP || t == PT_FTP || t == PT_TELNET) {
  335. hdr_tcp *tcph = hdr_tcp::access(pkt);
  336. seqno = tcph->seqno(); 
  337. if (seqno < 0) seqno = 0;
  338. topBin = int(maxSeqno_ / SeqnoBinSize_);
  339. if (numSeqnos_ == 0) {
  340. SeqnoBins_ = (int *)malloc(sizeof(int)*topBin);
  341. for (i = 0; i < topBin; i++) {
  342. SeqnoBins_[i] = 0;
  343. }
  344. }
  345. j = (int)(seqno/SeqnoBinSize_);
  346. if (j < 0) j = 0;
  347. if (j >= topBin) j = topBin - 1;
  348. ++ SeqnoBins_[j];
  349. ++ numSeqnos_;
  350. }
  351. }
  352. /* ##############
  353.  * Tcl Stuff
  354.  * ##############
  355.  */
  356. static class SnoopQueueInClass : public TclClass {
  357. public:
  358. SnoopQueueInClass() : TclClass("SnoopQueue/In") {}
  359. TclObject* create(int, const char*const*) {
  360. return (new SnoopQueueIn());
  361. }
  362. } snoopq_in_class;
  363. static class SnoopQueueOutClass : public TclClass {
  364. public:
  365. SnoopQueueOutClass() : TclClass("SnoopQueue/Out") {}
  366. TclObject* create(int, const char*const*) {
  367. return (new SnoopQueueOut());
  368. }
  369. } snoopq_out_class;
  370. static class SnoopQueueDropClass : public TclClass {
  371. public:
  372. SnoopQueueDropClass() : TclClass("SnoopQueue/Drop") {}
  373. TclObject* create(int, const char*const*) {
  374. return (new SnoopQueueDrop());
  375. }
  376. } snoopq_drop_class;
  377. static class SnoopQueueEDropClass : public TclClass {
  378. public:
  379. SnoopQueueEDropClass() : TclClass("SnoopQueue/EDrop") {}
  380. TclObject* create(int, const char*const*) {
  381. return (new SnoopQueueEDrop);
  382. }
  383. } snoopq_edrop_class;
  384. /* Added by Yun Wang, for use of In/Out tagger */
  385. static class SnoopQueueTaggerClass : public TclClass {
  386. public:
  387.         SnoopQueueTaggerClass() : TclClass("SnoopQueue/Tagger") {}
  388.         TclObject* create(int, const char*const*) {
  389.                 return (new SnoopQueueTagger);
  390.         }
  391. } snoopq_tagger_class;
  392. static class QueueMonitorEDClass : public TclClass {
  393. public: 
  394. QueueMonitorEDClass() : TclClass("QueueMonitor/ED") {}
  395. TclObject* create(int, const char*const*) { 
  396. return (new EDQueueMonitor);
  397. }
  398. } queue_monitor_ed_class;
  399. /* ############################################################
  400.  * a 'QueueMonitorCompat', which is used by the compat
  401.  * code to produce the link statistics used available in ns-1
  402.  *
  403.  * in ns-1, the counters are the number of departures
  404.  * ############################################################
  405.  */
  406. #include "ip.h"
  407. QueueMonitorCompat::QueueMonitorCompat()
  408. {
  409. memset(pkts_, 0, sizeof(pkts_));
  410. memset(bytes_, 0, sizeof(bytes_));
  411. memset(drops_, 0, sizeof(drops_));
  412. memset(flowstats_, 0, sizeof(flowstats_));
  413. }
  414. /*
  415.  * create an entry in the flowstats_ array.
  416.  */
  417. void
  418. QueueMonitorCompat::flowstats(int flowid)
  419. {
  420. Tcl& tcl = Tcl::instance();
  421. /*
  422.  * here is the deal.  we are in C code.  we'd like to do
  423.  *     flowstats_[flowid] = new Samples;
  424.  * but, we want to create an object that can be
  425.  * referenced via tcl.  (in particular, we want ->name_
  426.  * to be valid.)
  427.  *
  428.  * so, how do we do this?
  429.  *
  430.  * well, the answer is, call tcl to create it.  then,
  431.  * do a lookup on the result from tcl!
  432.  */
  433. tcl.evalf("new Samples");
  434. flowstats_[flowid] = (Samples*)TclObject::lookup(tcl.result());
  435. if (flowstats_[flowid] == 0) {
  436. abort();
  437. /*NOTREACHED*/
  438. }
  439. }
  440. void QueueMonitorCompat::out(Packet* pkt)
  441. {
  442. hdr_cmn* hdr = hdr_cmn::access(pkt);
  443. hdr_ip* iph = hdr_ip::access(pkt);
  444. double now = Scheduler::instance().clock();
  445. int fid = iph->flowid();
  446. if (fid >= MAXFLOW) {
  447. abort();
  448. /*NOTREACHED*/
  449. }
  450. // printf("QueueMonitorCompat::out(), fid=%dn", fid);
  451. bytes_[fid] += hdr_cmn::access(pkt)->size();
  452. pkts_[fid]++;
  453. if (flowstats_[fid] == 0) {
  454. flowstats(fid);
  455. }
  456. flowstats_[fid]->newPoint(now - hdr->timestamp());
  457. QueueMonitor::out(pkt);
  458. }
  459. void QueueMonitorCompat::in(Packet* pkt)
  460. {
  461. hdr_cmn* hdr = hdr_cmn::access(pkt);
  462. double now = Scheduler::instance().clock();
  463. // QueueMonitor::in() *may* do this, but we always need it...
  464. hdr->timestamp() = now;
  465. QueueMonitor::in(pkt);
  466. }
  467. void QueueMonitorCompat::drop(Packet* pkt)
  468. {
  469. hdr_ip* iph = hdr_ip::access(pkt);
  470. int fid = iph->flowid();
  471. if (fid >= MAXFLOW) {
  472. abort();
  473. /*NOTREACHED*/
  474. }
  475. ++drops_[fid];
  476. QueueMonitor::drop(pkt);
  477. }
  478. int QueueMonitorCompat::command(int argc, const char*const* argv)
  479. {
  480. Tcl& tcl = Tcl::instance();
  481. int fid;
  482. if (argc == 3) {
  483. fid = atoi(argv[2]);
  484. if (strcmp(argv[1], "bytes") == 0) {
  485. if (fid >= MAXFLOW) {
  486. abort();
  487. /*NOTREACHED*/
  488. }
  489. tcl.resultf("%d", bytes_[fid]);
  490. return TCL_OK;
  491. } else if (strcmp(argv[1], "pkts") == 0) {
  492. if (fid >= MAXFLOW) {
  493. abort();
  494. /*NOTREACHED*/
  495. }
  496. tcl.resultf("%d", pkts_[fid]);
  497. return TCL_OK;
  498. } else if (strcmp(argv[1], "drops") == 0) {
  499. if (fid >= MAXFLOW) {
  500. abort();
  501. /*NOTREACHED*/
  502. }
  503. tcl.resultf("%d", drops_[fid]);
  504. return TCL_OK;
  505. } else if (strcmp(argv[1], "get-class-delay-samples") == 0) {
  506. if (fid >= MAXFLOW) {
  507. abort();
  508. /*NOTREACHED*/
  509. }
  510. if (flowstats_[fid] == 0) {
  511. /*
  512.  * instantiate one if user actually
  513.  * cares enough to ask for it!
  514.  *
  515.  * (otherwise, need to return "",
  516.  * and then special-case caller to
  517.  * handle this null return.)
  518.  */
  519. flowstats(fid);
  520. }
  521. tcl.resultf("%s", flowstats_[fid]->name());
  522. return TCL_OK;
  523. }
  524. }
  525. return (QueueMonitor::command(argc, argv));
  526. }
  527. static class QueueMonitorCompatClass : public TclClass {
  528.  public: 
  529. QueueMonitorCompatClass() : TclClass("QueueMonitor/Compat") {}
  530. TclObject* create(int, const char*const*) { 
  531. return (new QueueMonitorCompat);
  532. }
  533. } queue_monitor_compat_class;