empweb.cc
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:18k
- /* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
- /*
- * empweb.cc
- * Copyright (C) 2001 by the University of Southern California
- * $Id: empweb.cc,v 1.20 2005/09/18 23:33:32 tomh Exp $
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
- *
- *
- * The copyright of this module includes the following
- * linking-with-specific-other-licenses addition:
- *
- * In addition, as a special exception, the copyright holders of
- * this module give you permission to combine (via static or
- * dynamic linking) this module with free software programs or
- * libraries that are released under the GNU LGPL and with code
- * included in the standard release of ns-2 under the Apache 2.0
- * license or under otherwise-compatible licenses with advertising
- * requirements (or modified versions of such code, with unchanged
- * license). You may copy and distribute such a system following the
- * terms of the GNU GPL for this module and the licenses of the
- * other code concerned, provided that you include the source code of
- * that other code when and as the GNU GPL requires distribution of
- * source code.
- *
- * Note that people who make modified versions of this module
- * are not obligated to grant this special exception for their
- * modified versions; it is their choice whether to do so. The GNU
- * General Public License gives permission to release a modified
- * version without this exception; this exception also makes it
- * possible to release a modified version which carries forward this
- * exception.
- *
- */
- //
- // Empirical Web traffic model that simulates Web traffic based on a set of
- // CDF (Cumulative Distribution Function) data derived from live tcpdump trace
- // The structure of this file is largely borrowed from webtraf.cc
- //
- // $Header: /cvsroot/nsnam/ns-2/empweb/empweb.cc,v 1.20 2005/09/18 23:33:32 tomh Exp $
- #include <tclcl.h>
- #include "empweb.h"
- // Data structures that are specific to this web traffic model and
- // should not be used outside this file.
- //
- // - EmpWebTrafPage
- // - EmpWebTrafObject
- class EmpWebPage : public TimerHandler {
- public:
- EmpWebPage(int id, EmpWebTrafSession* sess, int nObj, Node* dst, int svrId) :
- persistOption_(0), id_(id), sess_(sess), nObj_(nObj), curObj_(0), doneObj_(0), dst_(dst), svrId_(svrId) {}
- virtual ~EmpWebPage() {}
- inline void start() {
- // Call expire() and schedule the next one if needed
- status_ = TIMER_PENDING;
- handle(&event_);
- }
- inline int id() const { return id_; }
- inline int svrId() const { return svrId_; }
- Node* dst() { return dst_; }
- void doneObject() {
- if (sess_->mgr()->isdebug())
- printf("doneObject: %g done=%d total=%d n", Scheduler::instance().clock(), doneObj_, nObj_);
- if (++doneObj_ >= nObj_) {
- printf("doneObject: %g %d %d n", Scheduler::instance().clock(), doneObj_, nObj_);
- sess_->donePage((void*)this);
- // }
- // sched(sess_->interObj()->value());
- } else if (persistOption_) {
- sched(sess_->interObj()->value());
- }
-
- }
- inline int curObj() const { return curObj_; }
- inline int doneObj() const { return doneObj_; }
-
- inline void set_persistOption(int opt) { persistOption_ = opt; }
- int persistOption_ ; //0: http1.0 1: http1.1 ; use http1.0 as default
- private:
- virtual void expire(Event* = 0) {
- // Launch a request. Make sure size is not 0!
- if (curObj_ >= nObj_)
- return;
- sess_->launchReq(this, LASTOBJ_++,
- (int)ceil(sess_->objSize()->value()),
- (int)ceil(sess_->reqSize()->value()), sess_->id(), persistOption_);
- if (sess_->mgr()->isdebug())
- printf("expire: Session %d launched page %d obj %d nObj %d n",
- sess_->id(), id_, curObj_, nObj_);
- }
- virtual void handle(Event *e) {
- if (sess_->mgr()->isdebug())
- printf("handle: Session %d launched page %d obj %dn",
- sess_->id(), id_, curObj_);
- TimerHandler::handle(e);
- curObj_++;
- if (!persistOption_) {
- if (curObj_ < nObj_) sched(sess_->interObj()->value());
- }
- }
- int id_;
- EmpWebTrafSession* sess_;
- int nObj_, curObj_;
- int doneObj_;
- Node* dst_;
- int svrId_ ;
- static int LASTOBJ_;
- };
- int EmpWebPage::LASTOBJ_ = 1;
- int EmpWebTrafSession::LASTPAGE_ = 1;
- int EmpWebTrafPool::LASTFLOW_ = 1;
- // XXX Must delete this after all pages are done!!
- EmpWebTrafSession::~EmpWebTrafSession()
- {
- if (donePage_ != curPage_) {
- fprintf(stderr, "done pages %d != all pages %dn",
- donePage_, curPage_);
- abort();
- }
- if (status_ != TIMER_IDLE) {
- fprintf(stderr, "EmpWebTrafSession must be idle when deleted.n");
- abort();
- }
- /*
- if (rvInterPage_ != NULL)
- Tcl::instance().evalf("delete %s", rvInterPage_->name());
- if (rvPageSize_ != NULL)
- Tcl::instance().evalf("delete %s", rvPageSize_->name());
- if (rvInterObj_ != NULL)
- Tcl::instance().evalf("delete %s", rvInterObj_->name());
- if (rvObjSize_ != NULL)
- Tcl::instance().evalf("delete %s", rvObjSize_->name());
- if (rvReqSize_ != NULL)
- Tcl::instance().evalf("delete %s", rvReqSize_->name());
- if (rvPersistSel_ != NULL)
- Tcl::instance().evalf("delete %s", rvPersistSel_->name());
- if (rvServerSel_ != NULL)
- Tcl::instance().evalf("delete %s", rvServerSel_->name());
- */
- }
- void EmpWebTrafSession::donePage(void* ClntData)
- {
- EmpWebPage* pg = (EmpWebPage*)ClntData;
- if (mgr_->isdebug())
- printf("Session %d done page %dn", id_, pg->id());
-
- if (pg->doneObj() != pg->curObj()) {
- fprintf(stderr, "done objects %d != all objects %dn",
- pg->doneObj(), pg->curObj());
- abort();
- }
-
- //for HTTP1.1 persistent-connection
- if (pg->persistOption_) {
- if (!fulltcp_) {
- //recycle TCP connection
- mgr_->recycleTcp(ctcp_);
- mgr_->recycleTcp(stcp_);
- mgr_->recycleSink(csnk_);
- mgr_->recycleSink(ssnk_);
- } else {
- Tcl::instance().evalf("%s disconnect-full %s %s %s %s",
- mgr_->name(),
- src_->name(), pg->dst()->name(),
- ctcp_->name(), stcp_->name());
- }
- }
- delete pg;
- // If all pages are done, tell my parent to delete myself
- if (++donePage_ >= nPage_) {
- mgr_->doneSession(id_);
- } else if (interPageOption_) {
- sched(rvInterPage_->value());
- // printf("donePage: %g %d %dn", Scheduler::instance().clock(), donePage_, curPage_);
- }
- }
- // Launch the current page
- void EmpWebTrafSession::expire(Event *)
- {
- // Pick destination for this page
- //temporary hack for isi traffic
- int n;
- if (clientIdx_ < mgr()->nClientL_) n = 0 ; //ISI server
- else
- n = int(ceil(serverSel()->value()));
- assert((n >= 0) && (n < mgr()->nSrc_));
- Node* dst = mgr()->server_[n];
- // Make sure page size is not 0!
- EmpWebPage* pg = new EmpWebPage(LASTPAGE_++, this,
- (int)ceil(rvPageSize_->value()), dst, n);
- //each page either use persistent or non-persistent connection
- int opt = (int)ceil(this->persistSel()->value());
- pg->set_persistOption(opt);
- if (mgr_->isdebug())
- printf("Session %d starting page %d, curpage %d n",
- id_, LASTPAGE_-1, curPage_);
- if (pg->persistOption_) { //for HTTP1.1 persistent-connection
- mgr_->LASTFLOW_++;
- int wins = int(ceil(serverWin()->value()));
- int winc = int(ceil(clientWin()->value()));
- int window = (wins >= winc) ? wins : winc;
- int m = int(ceil(mtu()->value()));
- // Choose source and dest TCP agents for both source and destination
- if (fulltcp_) {
- ctcp_ = mgr_->picktcp(window,m);
- stcp_ = mgr_->picktcp(window,m);
- Tcl::instance().evalf("%s connect-full %s %s %s %s",
- mgr_->name(),
- src_->name(), pg->dst()->name(),
- ctcp_->name(), stcp_->name());
- } else {
- ctcp_ = mgr_->picktcp(window,m);
- stcp_ = mgr_->picktcp(window,m);
- csnk_ = mgr_->picksink();
- ssnk_ = mgr_->picksink();
- }
- // Tcl::instance().evalf("%s set-fid %d %s %s", mgr_->name(), mgr_->LASTFLOW_-1, ctcp_->name(), stcp_->name());
- Tcl::instance().evalf("%s set-fid %d %s %s", mgr_->name(), mgr_->color_, ctcp_->name(), stcp_->name());
- }
- pg->start();
- }
- void EmpWebTrafSession::handle(Event *e)
- {
- // If I haven't scheduled all my pages, do the next one
- TimerHandler::handle(e);
- ++curPage_;
- // XXX Notice before each page is done, it will schedule itself
- // one more time, this makes sure that this session will not be
- // deleted after the above call. Thus the following code will not
- // be executed in the context of a deleted object.
- if (!interPageOption_) {
- if (curPage_ < nPage_) {
- sched(rvInterPage_->value());
- // printf("schedule: %g %d %dn", Scheduler::instance().clock(), donePage_, curPage_);
- }
- }
- }
- // Launch a request for a particular object
- void EmpWebTrafSession::launchReq(void* ClntData, int obj, int size, int reqSize, int sid, int persist)
- {
- TcpAgent* ctcp;
- TcpAgent* stcp;
- TcpSink* csnk;
- TcpSink* ssnk;
- EmpWebPage* pg = (EmpWebPage*)ClntData;
- if (persist) { //for HTTP1.1 persistent-connection
- if (mgr_->isdebug()) {
- printf("HTTP1.1n");
- }
- // use the same connection
- ctcp = ctcp_;
- stcp = stcp_;
- if (fulltcp_) {
- csnk = 0;
- ssnk = 0;
- } else {
- csnk = csnk_;
- ssnk = ssnk_;
- }
- } else { //for HTTP1.0 non-consistent connection
- if (mgr_->isdebug()) {
- printf("HTTP1.0n");
- }
-
- mgr_->LASTFLOW_++;
- int wins = int(ceil(serverWin()->value()));
- int winc = int(ceil(clientWin()->value()));
- int window = (wins >= winc) ? wins : winc;
- int m = int(ceil(mtu()->value()));
- // Choose source and dest TCP agents for both source and destination
- ctcp = mgr_->picktcp(window,m);
- stcp = mgr_->picktcp(window,m);
- Tcl::instance().evalf("%s set-fid %d %s %s",
- mgr_->name(), mgr_->color_, ctcp->name(), stcp->name());
- if (fulltcp_) {
- csnk = 0;
- ssnk = 0;
- } else {
- csnk = mgr_->picksink();
- ssnk = mgr_->picksink();
- }
- }
- // Setup new TCP connection and launch request
- // size and reqSize are in the unit of bytes in fulltcp mode
- // but in the unit of packet in halftcp mode
- if (fulltcp_) {
- Tcl::instance().evalf("%s launch-req-full %d %d %s %s %s %s %d %d %d %d",
- mgr_->name(), obj, pg->id(),
- src_->name(), pg->dst()->name(),
- ctcp->name(),
- stcp->name(),
- size, reqSize, ClntData,persist);
- } else {
- assert (csnk != 0 && ssnk != 0);
- Tcl::instance().evalf("%s launch-req %d %d %s %s %s %s %s %s %d %d %d %d",
- mgr_->name(), obj, pg->id(),
- src_->name(), pg->dst()->name(),
- ctcp->name(), csnk->name(),
- stcp->name(), ssnk->name(),
- size, reqSize, ClntData,
- persist);
- }
- if (mgr_->isdebug()) {
- printf("size=%d obj=%d page=%d sess=%d %g src=%d dst=%dn", size, obj, pg->id(), id_, Scheduler::instance().clock(), src_->address(), pg->dst()->address());
- }
- }
- static class EmpWebTrafPoolClass : public TclClass {
- public:
- EmpWebTrafPoolClass() : TclClass("PagePool/EmpWebTraf") {}
- TclObject* create(int, const char*const*) {
- return (new EmpWebTrafPool());
- }
- } class_empwebtrafpool;
- EmpWebTrafPool::~EmpWebTrafPool()
- {
- if (session_ != NULL) {
- for (int i = 0; i < nSession_; i++)
- delete session_[i];
- delete []session_;
- }
- if (server_ != NULL)
- delete []server_;
- if (client_ != NULL)
- delete []client_;
- // XXX Destroy tcpPool_ and sinkPool_ ?
- }
- void EmpWebTrafPool::delay_bind_init_all()
- {
- delay_bind_init_one("debug_");
- PagePool::delay_bind_init_all();
- }
- int EmpWebTrafPool::delay_bind_dispatch(const char *varName,const char *localName,
- TclObject *tracer)
- {
- if (delay_bind_bool(varName, localName, "debug_", &debug_, tracer))
- return TCL_OK;
- return PagePool::delay_bind_dispatch(varName, localName, tracer);
- }
- EmpWebTrafPool::EmpWebTrafPool() :
- concurrentSess_(0), nSrc_(0), server_(NULL), session_(NULL), nClient_(0), client_(NULL), nTcp_(0), nSink_(0), fulltcp_(0)
- {
- bind("fulltcp_", &fulltcp_);
- LIST_INIT(&tcpPool_);
- LIST_INIT(&sinkPool_);
- }
- TcpAgent* EmpWebTrafPool::picktcp(int win, int mtu)
- {
- TcpAgent* a = (TcpAgent*)detachHead(&tcpPool_);
- if (a == NULL) {
- Tcl& tcl = Tcl::instance();
- tcl.evalf("%s alloc-tcp %d %d", name(), win, mtu);
- a = (TcpAgent*)lookup_obj(tcl.result());
- if (a == NULL) {
- fprintf(stderr, "Failed to allocate a TCP agentn");
- abort();
- }
- } else
- nTcp_--;
- return a;
- }
- TcpSink* EmpWebTrafPool::picksink()
- {
- TcpSink* a = (TcpSink*)detachHead(&sinkPool_);
- if (a == NULL) {
- Tcl& tcl = Tcl::instance();
- tcl.evalf("%s alloc-tcp-sink", name());
- a = (TcpSink*)lookup_obj(tcl.result());
- if (a == NULL) {
- fprintf(stderr, "Failed to allocate a TCP sinkn");
- abort();
- }
- } else
- nSink_--;
- return a;
- }
- void EmpWebTrafPool::recycleTcp(Agent* a)
- {
- if (fulltcp_) {
- delete a;
- } else {
- if (a == NULL) {
- fprintf(stderr, "Failed to recycle TCP agentn");
- abort();
- }
- nTcp_++;
- insertAgent(&tcpPool_, a);
- }
- }
- void EmpWebTrafPool::recycleSink(Agent* a)
- {
- if (fulltcp_) {
- delete a;
- } else {
- if (a == NULL) {
- fprintf(stderr, "Failed to recycle Sink agentn");
- abort();
- }
- nSink_++;
- insertAgent(&sinkPool_, a);
- }
- }
- int EmpWebTrafPool::command(int argc, const char*const* argv)
- {
- if (argc == 3) {
- if (strcmp(argv[1], "set-num-session") == 0) {
- if (session_ != NULL) {
- for (int i = 0; i < nSession_; i++)
- delete session_[i];
- delete []session_;
- }
- nSession_ = atoi(argv[2]);
- session_ = new EmpWebTrafSession*[nSession_];
- memset(session_, 0, sizeof(EmpWebTrafSession*)*nSession_);
- return (TCL_OK);
- } else if (strcmp(argv[1], "set-num-server-lan") == 0) {
- nSrcL_ = atoi(argv[2]);
- if (nSrcL_ > nSrc_) {
- fprintf(stderr, "Wrong server index %dn", nSrcL_);
- return TCL_ERROR;
- }
- return (TCL_OK);
- } else if (strcmp(argv[1], "set-num-remote-client") == 0) {
- nClientL_ = atoi(argv[2]);
- if (nClientL_ > nClient_) {
- fprintf(stderr, "Wrong client index %dn", nClientL_);
- return TCL_ERROR;
- }
- return (TCL_OK);
- } else if (strcmp(argv[1], "set-num-server") == 0) {
- nSrc_ = atoi(argv[2]);
- if (server_ != NULL)
- delete []server_;
- server_ = new Node*[nSrc_];
- return (TCL_OK);
- } else if (strcmp(argv[1], "set-num-client") == 0) {
- nClient_ = atoi(argv[2]);
- if (client_ != NULL)
- delete []client_;
- client_ = new Node*[nClient_];
- return (TCL_OK);
- } else if (strcmp(argv[1], "set-interPageOption") == 0) {
- int option = atoi(argv[2]);
- if (session_ != NULL) {
- for (int i = 0; i < nSession_; i++) {
- EmpWebTrafSession* p = session_[i];
- p->set_interPageOption(option);
- }
- }
- return (TCL_OK);
- } else if (strcmp(argv[1], "doneObj") == 0) {
- EmpWebPage* p = (EmpWebPage*)atol(argv[2]);
-
- p->doneObject();
-
- return (TCL_OK);
- }
- } else if (argc == 4) {
- if (strcmp(argv[1], "set-server") == 0) {
- Node* cli = (Node*)lookup_obj(argv[3]);
- if (cli == NULL)
- return (TCL_ERROR);
- int nc = atoi(argv[2]);
- if (nc >= nSrc_) {
- fprintf(stderr, "Wrong server index %dn", nc);
- return TCL_ERROR;
- }
- server_[nc] = cli;
- return (TCL_OK);
- } else if (strcmp(argv[1], "set-client") == 0) {
- Node* s = (Node*)lookup_obj(argv[3]);
- if (s == NULL)
- return (TCL_ERROR);
- int n = atoi(argv[2]);
- if (n >= nClient_) {
- fprintf(stderr, "Wrong client index %dn", n);
- return TCL_ERROR;
- }
- client_[n] = s;
- return (TCL_OK);
- } else if (strcmp(argv[1], "recycle") == 0) {
- // <obj> recycle <tcp> <sink>
- //
- // Recycle a TCP source/sink pair
- Agent* tcp = (Agent*)lookup_obj(argv[2]);
- Agent* snk = (Agent*)lookup_obj(argv[3]);
- if ((tcp == NULL) || (snk == NULL))
- return (TCL_ERROR);
- // XXX TBA: recycle tcp agents
- if (fulltcp_) {
- delete tcp;
- delete snk;
- } else {
- nTcp_++, nSink_++;
- insertAgent(&tcpPool_, tcp);
- insertAgent(&sinkPool_, snk);
- }
- return (TCL_OK);
- }
- } else if (argc == 17) {
- if (strcmp(argv[1], "create-session") == 0) {
- // <obj> create-session <session_index>
- // <pages_per_sess> <launch_time>
- // <inter_page_rv> <page_size_rv>
- // <inter_obj_rv> <obj_size_rv>
- // <req_size_rv> <persist_sel_rv> <server_sel_rv>
- // <client_win_rv> <server_win_rv> <mtu_rv>
- // <inbound/outbound flag> <color>
- int n = atoi(argv[2]);
- if ((n < 0)||(n >= nSession_)||(session_[n] != NULL)) {
- fprintf(stderr,"Invalid session index %dn",n);
- return (TCL_ERROR);
- }
- int npg = (int)strtod(argv[3], NULL);
- double lt = strtod(argv[4], NULL);
- int flip = atoi(argv[15]);
- if ((flip < 0)||(flip > 1)) {
- fprintf(stderr,"Invalid I/O flag %dn",flip);
- return (TCL_ERROR);
- }
- //for SPAWAR demo
- color_ = atoi(argv[16]);
- int cl;
- if (flip == 1)
- cl = int(floor(Random::uniform(0, nClientL_)));
- else
- cl = int(floor(Random::uniform(nClientL_, nClient_)));
- assert((cl >= 0) && (cl < nClient_));
- Node* c=client_[cl];
- EmpWebTrafSession* p =
- new EmpWebTrafSession(this, c, npg, n, nSrc_, cl,fulltcp_);
- int res = lookup_rv(p->interPage(), argv[5]);
- res = (res == TCL_OK) ?
- lookup_rv(p->pageSize(), argv[6]) : TCL_ERROR;
- res = (res == TCL_OK) ?
- lookup_rv(p->interObj(), argv[7]) : TCL_ERROR;
- res = (res == TCL_OK) ?
- lookup_rv(p->objSize(), argv[8]) : TCL_ERROR;
- res = (res == TCL_OK) ?
- lookup_rv(p->reqSize(), argv[9]) : TCL_ERROR;
- res = (res == TCL_OK) ?
- lookup_rv(p->persistSel(), argv[10]) : TCL_ERROR;
- res = (res == TCL_OK) ?
- lookup_rv(p->serverSel(), argv[11]) : TCL_ERROR;
- res = (res == TCL_OK) ?
- lookup_rv(p->serverWin(), argv[12]) : TCL_ERROR;
- res = (res == TCL_OK) ?
- lookup_rv(p->clientWin(), argv[13]) : TCL_ERROR;
- res = (res == TCL_OK) ?
- lookup_rv(p->mtu(), argv[14]) : TCL_ERROR;
- if (res == TCL_ERROR) {
- delete p;
- fprintf(stderr, "Invalid random variablen");
- return (TCL_ERROR);
- }
- p->sched(lt);
- session_[n] = p;
-
- return (TCL_OK);
- }
- }
- return PagePool::command(argc, argv);
- }