1 #ifndef Platoon_H 2 #define Platoon_H 3 #include "robouser.h" 4 #include <list> 5 #include <cstring> 6 7 /* FIXME: 'reasonable' upper bound on number of users CPU can handle */ 8 #define Platoon_MAXUSERS (1 << 16) 9 10 /**---------------------------------------------------------------------- 11 Platoon of robousers. 12 ----------------------------------------------------------------------*/ 13 class Platoon : public SkedClient { 14 public: 15 /**---------------------------------------------------------------------- 16 Set up parameters common to all instances of this class, 17 and initialize the container for all instances. 18 sked is a pointer to the Sked object to use to schedule delayed actions, 19 and whose runAll() method should be called periodically by main(). 20 21 filename is what file to fetch from the remote server (will be a template 22 later). 23 maxBytesPerSec sets how much bandwidth each client tries to use. 24 minBytesPerSec is the lowest bandwidth per client we accept (else abort). 25 bytesPerRead sets how many bytes to read each time. 26 servername and port specify the server and port the user will connect to. 27 username and passwd are the user's username and password. 28 @param local_addrs 0, or array of local addresses to assign to users 29 @param n_local_addrs number of elements in local_addrs 30 ----------------------------------------------------------------------*/ 31 void init(Poller *poller, Sked *sked, const char *filename, 32 int maxBytesPerSec, int minBytesPerSec, int bytesPerRead, 33 const char *servername, int port, 34 const char *username, const char *passwd, 35 struct sockaddr_in *local_addrs, int n_local_addrs); 36 37 /**---------------------------------------------------------------------- 38 Stops any activity. After this call, you may call init again. 39 ----------------------------------------------------------------------*/ 40 void reset(); 41 42 /**---------------------------------------------------------------------- 43 Set desired number of simulated users. Platoon will ramp up to this. 44 ----------------------------------------------------------------------*/ set_nuserTarget(int utarget)45 void set_nuserTarget(int utarget) { 46 m_nuserTarget = utarget; 47 wakeUp(); 48 } 49 50 /**---------------------------------------------------------------------- 51 How many simulated users should try to connect at once? 52 Default is 1. Higher values make Platoon ramp up more quickly. 53 ----------------------------------------------------------------------*/ set_nconnectingTarget(int ctarget)54 void set_nconnectingTarget(int ctarget) { 55 m_nconnectingTarget = ctarget; 56 wakeUp(); 57 } 58 59 /**---------------------------------------------------------------------- 60 What's the last state in which a robouser is considered to be connecting? 61 Default value is robouser_t::CONNECTING (after tcp connection complete). 62 Other possible value is robouser_t::CONNECT (when tcp connection starts). 63 Lower numerical values make Platoon ramp up more quickly. 64 ----------------------------------------------------------------------*/ set_lastConnectingState(robouser_t::state_t s)65 void set_lastConnectingState(robouser_t::state_t s) { 66 m_lastConnectingState = s; 67 wakeUp(); 68 } 69 70 /**---------------------------------------------------------------------- 71 Call this periodically to check on status of the clients. 72 *nconnecting = # of robousers still trying to connect 73 *nalive = # of robousers who connected ok and are in good shape 74 *ndead = # of robousers who have failed, and are out of action 75 76 Returns total number of bytes transferred so far. 77 ----------------------------------------------------------------------*/ 78 long getStatus(int *nconnecting, int *nalive, int *ndead); 79 80 /**---------------------------------------------------------------------- 81 Reap any dead users. Call this after each call to Sked->runAll(). 82 ----------------------------------------------------------------------*/ 83 void reap(); 84 ~Platoon()85 virtual ~Platoon() {} 86 87 // Private methods 88 private: 89 /** Schedule a wake-up call to check if we should start a new connection. */ wakeUp()90 void wakeUp() { 91 m_sked->delClient(this); /* just in case some event is pending */ 92 m_sked->addClient(this, eclock()); /* Prepare check */ 93 } 94 95 /// Return the sum of m_numInState[first ... last] 96 int sumInState(robouser_t::state_t first, robouser_t::state_t last); 97 98 /**---------------------------------------------------------------------- 99 Start another one of the robousers. 100 getStatus() should be called periodically to check on their status. 101 ----------------------------------------------------------------------*/ 102 int startUser(); 103 104 private: 105 106 /// How we get network events from the operating system 107 Poller *m_poller; 108 109 /// The server part of the URL to fetch 110 char m_servername[128]; 111 /// The port number part of the URL to fetch 112 int m_port; 113 /// The user name part of the URL to fetch 114 char m_username[128]; 115 /// The password part of the URL to fetch 116 char m_passwd[128]; 117 /// Requested Lower bound on bytes each user should read per second 118 int m_minBytesPerSec; 119 /// Requested Upper bound on bytes each user should read per second 120 int m_maxBytesPerSec; 121 /// Requested number of bytes each user should read at a time 122 int m_bytesPerRead; 123 /// Filename part of the URL to fetch 124 const char *m_filename; 125 126 /// whether to print stuff out 127 int m_verbosity; 128 129 /** How we schedule timeouts */ 130 Sked *m_sked; 131 132 /// How we deterimine whether a session is still connecting 133 robouser_t::state_t m_lastConnectingState; 134 135 /** Desired number of sessions in process of connecting. 136 sum(m_nInState[CONNECT,CONNECTING]) aspires to reach this goal. 137 */ 138 int m_nconnectingTarget; 139 140 /** Desired number of users. 141 sum(m_nInState[CONNECT,CONNECTING,GET,GETTING]) aspires to reach this goal. 142 */ 143 int m_nuserTarget; 144 145 /// Count of users in each state 146 int m_nInState[robouser_t::NUMSTATES]; 147 148 /* Each element is NULL or a nondead user */ 149 robouser_t *m_users[Platoon_MAXUSERS]; 150 151 /** List of dead robousers waiting to be reaped */ 152 std::list<robouser_t *> m_deadlist; 153 154 /** Health: count of bytes fetched so far from all files */ 155 size_t m_bytesFetched; 156 157 /** Health: count of reads performed so far from all files */ 158 int m_nreads; 159 160 /** pool of local addresses, or NULL */ 161 struct sockaddr_in *m_local_addrs; 162 163 /** size of pool */ 164 int m_n_local_addrs; 165 166 // Accessors for robouser use 167 public: getLocalAddrs()168 struct sockaddr_in *getLocalAddrs() { return m_local_addrs; } getNLocalAddrs()169 int getNLocalAddrs() { return m_n_local_addrs; } getSked()170 Sked *getSked() { return m_sked; } getMaxBytesPerSec()171 int getMaxBytesPerSec() { return m_maxBytesPerSec; } getPoller()172 Poller *getPoller() { return m_poller; } getBytesPerRead()173 int getBytesPerRead() { return m_bytesPerRead; } getFilename()174 const char *getFilename() { return m_filename; } getMinBytesPerSec()175 int getMinBytesPerSec() { return m_minBytesPerSec; } getServername()176 const char *getServername() { return m_servername; } getPort()177 int getPort() { return m_port; } getUsername()178 const char *getUsername() { return m_username; } getPasswd()179 const char *getPasswd() { return m_passwd; } setVerbosity(int v)180 void setVerbosity(int v) { m_verbosity = v; } getVerbosity()181 int getVerbosity() { return m_verbosity; } 182 183 /**---------------------------------------------------------------------- 184 Update counts on state change. For robouser use only. 185 ----------------------------------------------------------------------*/ 186 void countStateChange(int user, robouser_t::state_t oldstate, robouser_t::state_t newstate); 187 188 // Mutators addToDeadlist(robouser_t * corpse)189 void addToDeadlist(robouser_t *corpse) { m_deadlist.push_back(corpse); } incBytesFetched(int nread)190 void incBytesFetched(int nread) { m_bytesFetched += nread; } incNReads()191 void incNReads() { m_nreads++; } 192 193 /* Callback functions - called by Sked only */ 194 195 /**---------------------------------------------------------------------- 196 When the time specified by addClient() has elapsed, Sked calls this method. 197 ----------------------------------------------------------------------*/ 198 void skedCallback(clock_t now); 199 }; 200 #endif 201