MessageObserver.cc

Go to the documentation of this file.
00001 //
00002 // This program is free software; you can redistribute it and/or
00003 // modify it under the terms of the GNU General Public License
00004 // as published by the Free Software Foundation; either version 2
00005 // of the License, or (at your option) any later version.
00006 //
00007 // This program is distributed in the hope that it will be useful,
00008 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00009 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00010 // GNU General Public License for more details.
00011 //
00012 // You should have received a copy of the GNU General Public License
00013 // along with this program; if not, write to the Free Software
00014 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00015 //
00016 
00022 #include <assert.h>
00023 #include <sstream>
00024 #include <omnetpp.h>
00025 #include <GlobalStatisticsAccess.h>
00026 #include "MessageObserver.h"
00027 #include "ALMTestTracedMessage_m.h"
00028 
00029 Define_Module(MessageObserver);
00030 
00031 MessageObserver::MessageObserver() {
00032     gcTimer = new cMessage("garbage_collection");
00033     gcInterval = 1.0;
00034     cacheMaxAge = 10.0;
00035     numLooped = 0;
00036 }
00037 
00038 MessageObserver::~MessageObserver() {
00039     cancelAndDelete(gcTimer);
00040 }
00041 
00042 void MessageObserver::initialize() {
00043     WATCH_MAP(groups);
00044     WATCH_MAP(joinedAt);
00045     WATCH_MAP(receivedAt);
00046     WATCH(numLooped);
00047 
00048     numLooped = 0;
00049     gcInterval = par("gcInterval");
00050     cacheMaxAge = par("cacheMaxAge");
00051 
00052     if (gcInterval > 0.0)
00053         scheduleAt(OPP::simTime() + gcInterval, gcTimer);
00054 
00055     creationTime = OPP::simTime();
00056     globalStatistics = GlobalStatisticsAccess().get();
00057 }
00058 
00059 void MessageObserver::finish() {
00060     uint64_t totalSent = 0;
00061     uint64_t totalReceived = 0;
00062     for (std::map<OverlayKey, MulticastGroup>::iterator i = groups.begin(); i != groups.end(); ++i) {
00063         std::stringstream message;
00064         message << "MessageObserver: Group " << i->first;
00065         std::string name;
00066 
00067         name = message.str() + " Sent Messages";
00068         recordScalar(name.c_str(), (double)i->second.sent);
00069 
00070         name = message.str() + " Received Messages";
00071         recordScalar(name.c_str(), (double)i->second.received);
00072 
00073         name = message.str() + " Delivered Percentage";
00074         recordScalar(name.c_str(), ((double)i->second.received * 100.0) / (double)i->second.sent);
00075 
00076         totalSent += i->second.sent;
00077         totalReceived += i->second.received;
00078     }
00079 
00080     recordScalar("MessageObserver: Total Sent Messages", (double)totalSent);
00081     recordScalar("MessageObserver: Total Received Messages", (double)totalReceived);
00082     recordScalar("MessageObserver: Total Delivered Percentage", ((double)totalReceived * 100.0) / (double)totalSent);
00083     
00084     simtime_t time = globalStatistics->calcMeasuredLifetime(creationTime);
00085     if ( time >= GlobalStatistics::MIN_MEASURED ) {
00086         globalStatistics->addStdDev("MessageObserver: Looped messages/s", (double)numLooped / time);
00087     }
00088 }
00089 
00090 void MessageObserver::handleMessage(cMessage* msg) {
00091     if (msg == gcTimer) {
00092         simtime_t now = OPP::simTime();
00093         std::map<NodeMessagePair, simtime_t>::iterator i, iPrev;
00094         i = receivedAt.begin();
00095         while (i != receivedAt.end()) {
00096             if (now - i->second >= cacheMaxAge) {
00097                 iPrev = i;
00098                 ++i;
00099                 receivedAt.erase(iPrev);
00100             }
00101             else {
00102                 ++i;
00103             }
00104         }
00105         scheduleAt(OPP::simTime() + gcInterval, gcTimer);
00106     }
00107 }
00108 
00112 void MessageObserver::joinedGroup(int moduleId, OverlayKey groupId) {
00113     groups[groupId].size += 1;
00114     joinedAt[NodeGroupPair(moduleId, groupId)] = OPP::simTime();
00115 }
00116 
00120 void MessageObserver::leftGroup(int moduleId, OverlayKey groupId) {
00121     std::map<OverlayKey, MulticastGroup>::iterator iter = groups.find(groupId);
00122     if (iter == groups.end()) {
00123         EV << "Warning: MessageObserver asked to remove node from nonexistent group " << groupId.toString();
00124     }
00125     else if (iter->second.size == 0) {
00126         EV << "Warning: MessageObserver asked to remove node from empty group " << groupId.toString();
00127     }
00128     else {
00129         iter->second.size -= 1;
00130     }
00131     joinedAt.erase(NodeGroupPair(moduleId, groupId));
00132 }
00133 
00138 void MessageObserver::sentMessage(ALMTestTracedMessage* msg) {
00139     if (msg == NULL) {
00140         error("%s called with null message.", __PRETTY_FUNCTION__);
00141     }
00142 
00143     std::map<OverlayKey, MulticastGroup>::iterator iter;
00144     iter = groups.find(msg->getGroupId());
00145     if (iter == groups.end()) {
00146         EV << "Warning: MessageObserver notified of sent message for nonexistent group " << msg->getGroupId().toString();
00147     }
00148     else if (iter->second.size == 0) {
00149         EV << "Warning: MessageObserver notified of sent message for empty group " << msg->getGroupId().toString();
00150     }
00151     else {
00152         iter->second.sent += iter->second.size - 1;
00153     }
00154 }
00155 
00159 void MessageObserver::receivedMessage(ALMTestTracedMessage* msg) {
00160     if (msg == NULL) {
00161         error("%s called with null message.", __PRETTY_FUNCTION__);
00162     }
00163 
00164     std::map<OverlayKey, MulticastGroup>::iterator iGroup;
00165     iGroup = groups.find(msg->getGroupId());
00166     if (iGroup == groups.end()) {
00167         EV << "Warning: MessageObserver notified of received message for nonexistent group " << msg->getGroupId().toString();
00168     }
00169     else if (iGroup->second.size == 0) {
00170         EV << "Warning: MessageObserver notified of received message for empty group " << msg->getGroupId().toString();
00171     }
00172     else if (msg->getSenderId() != msg->getReceiverId()) {
00173 
00174         // Only count if message was received after joining
00175         std::map<NodeGroupPair, simtime_t>::iterator iJoinInfo;
00176         iJoinInfo = joinedAt.find(NodeGroupPair(msg->getReceiverId(), msg->getGroupId()));
00177 
00178         if (iJoinInfo != joinedAt.end() && iJoinInfo->second < msg->getTimestamp()) {
00179             
00180             // Check if this message has not already been received
00181             NodeMessagePair nmp = NodeMessagePair(msg->getReceiverId(), msg->getMcastId());
00182             if (receivedAt.find(nmp) == receivedAt.end()) {
00183                 iGroup->second.received += 1;
00184                 receivedAt[nmp] = msg->getTimestamp();
00185             }
00186         }
00187     }
00188     else {
00189         RECORD_STATS(++numLooped);
00190     }
00191 }
00192 
00196 void MessageObserver::nodeDead(int moduleId) {
00197     // For each group, if node has joined group, decrease group member count by one
00198     // and clear joined info.
00199     for (std::map<OverlayKey, MulticastGroup>::iterator ig = groups.begin(); ig != groups.end(); ++ig) {
00200         NodeGroupPair ngp = NodeGroupPair(moduleId, ig->first);
00201         if (joinedAt.find(ngp) != joinedAt.end()) {
00202             ig->second.size--;
00203             joinedAt.erase(ngp);
00204         }
00205     }
00206 }
00207 
00208 std::ostream& operator<< (std::ostream& os, MessageObserver::MulticastGroup const & mg) {
00209     return os << "Nodes: " << mg.size << "; Messages Sent: " << mg.sent
00210         << ", Received: " << mg.received << ", Dropped: " << (mg.sent - mg.received);
00211 }
00212 
00213 std::ostream& operator<< (std::ostream& os, MessageObserver::NodeGroupPair const & ngp) {
00214     cModule* module = OPP::cSimulation::getActiveSimulation()->getModule(ngp.first);
00215     return os << "(" << (module != NULL ? module->getFullPath() : "Deleted node")
00216         << ", " << ngp.second << ")";
00217 }
00218