[Avida-SVN] r3438 - in development/source: cpu main

dk at myxo.css.msu.edu dk at myxo.css.msu.edu
Fri Oct 2 08:55:44 PDT 2009


Author: dk
Date: 2009-10-02 11:55:44 -0400 (Fri, 02 Oct 2009)
New Revision: 3438

Modified:
   development/source/cpu/cHardwareCPU.cc
   development/source/main/cAvidaConfig.h
   development/source/main/cOrgMessage.cc
   development/source/main/cOrgMessage.h
   development/source/main/cOrganism.cc
   development/source/main/cOrganism.h
   development/source/main/cPopulationCell.cc
   development/source/main/cPopulationInterface.cc
   development/source/main/cPopulationInterface.h
Log:
Refactored message-related code in cOrganism.  Fixed a potential dangling pointer, added send and receive-side buffer size config options, moved stat tracking code to the population interface.

Modified: development/source/cpu/cHardwareCPU.cc
===================================================================
--- development/source/cpu/cHardwareCPU.cc	2009-10-02 02:58:45 UTC (rev 3437)
+++ development/source/cpu/cHardwareCPU.cc	2009-10-02 15:55:44 UTC (rev 3438)
@@ -4819,23 +4819,22 @@
     return false;
   }
 
-  const cOrgMessage* msg = m_organism->RetrieveMessage();
-  if(msg == 0) {
-    return false;
-  }
+	std::pair<bool, cOrgMessage> retrieved = m_organism->RetrieveMessage();
+	if(!retrieved.first) {
+		return false;
+	}
   
   /* MJM - by this point, the pointer returned by GetSender() may no longer
    * be any good. Instead, we should use the cell and organism ID of the
    * message sender to get hold of the sender (if it still exists and hasn't moved)
    */
-
-  cPopulationCell senderCell = m_world->GetPopulation().GetCell(msg->GetSenderCellID());
+  cPopulationCell senderCell = m_world->GetPopulation().GetCell(retrieved.second.GetSenderCellID());
   if (!senderCell.IsOccupied()) {
 	  // the organism that made the request is gone, we can't donate...
 	  return false;
   }
   cOrganism* energyReceiver = senderCell.GetOrganism();
-  if (energyReceiver->GetID() != msg->GetSenderOrgID()) {
+  if (energyReceiver->GetID() != retrieved.second.GetSenderOrgID()) {
 	  // some other organism has occupied this cell since the msg was sent,
 	  // we can't donate...
 	  return false;
@@ -7165,15 +7164,16 @@
 */
 bool cHardwareCPU::Inst_RetrieveMessage(cAvidaContext& ctx) 
 {
-  const cOrgMessage* msg = m_organism->RetrieveMessage();
-  if(msg == 0)
-    return false;
+	std::pair<bool, cOrgMessage> retrieved = m_organism->RetrieveMessage();
+	if(!retrieved.first) {
+		return false;
+	}
   
   const int label_reg = FindModifiedRegister(REG_BX);
   const int data_reg = FindNextRegister(label_reg);
   
-  GetRegister(label_reg) = msg->GetLabel();
-  GetRegister(data_reg) = msg->GetData();
+  GetRegister(label_reg) = retrieved.second.GetLabel();
+  GetRegister(data_reg) = retrieved.second.GetData();
   return true;
 }
 

Modified: development/source/main/cAvidaConfig.h
===================================================================
--- development/source/main/cAvidaConfig.h	2009-10-02 02:58:45 UTC (rev 3437)
+++ development/source/main/cAvidaConfig.h	2009-10-02 15:55:44 UTC (rev 3438)
@@ -485,7 +485,6 @@
   CONFIG_ADD_VAR(TEST_CPU_TIME_MOD, int, 20, "Time allocated in test CPUs (multiple of length)");
   CONFIG_ADD_VAR(TRACK_PARENT_DIST, bool, 0, "Track parent distance during run. This is unnecessary when track main lineage is on.");
   
-  
   CONFIG_ADD_GROUP(LOG_GROUP, "Log Files");
   CONFIG_ADD_VAR(LOG_CREATURES, bool, 0, "0/1 (off/on) toggle to print file.");
   CONFIG_ADD_VAR(LOG_GENOTYPES, int, 0, "0 = off, 1 = print ALL, 2 = print threshold ONLY.");
@@ -506,9 +505,9 @@
   CONFIG_ADD_GROUP(ORGANISM_MESSAGING_GROUP, "Organism Message-Based Communication");
   CONFIG_ADD_VAR(MESSAGE_TYPE, int, 0, "Messaging Style. 0=Receiver Facing, 1=Broadcast");
   CONFIG_ADD_VAR(MESSAGE_BCAST_RADIUS, int, 1, "Broadcast message radius (cells)");
-  CONFIG_ADD_VAR(ORGANISMS_REMEMBER_MESSAGES, bool, 1, "Does an organism remember all messages it has sent or received? 0=false, 1=true (default)");
-  CONFIG_ADD_VAR(MESSAGE_QUEUE_SIZE, int, -1, "Maximum number of unretrieved messages an organism can store (-1 for no limit is the default)");
-  CONFIG_ADD_VAR(MESSAGE_QUEUE_BEHAVIOR_WHEN_FULL, int, 0, "0 = Drop incoming message (default), 1 = Drop oldest unretrieved message");
+  CONFIG_ADD_VAR(MESSAGE_SEND_BUFFER_SIZE, bool, -1, "Size of message send buffer (stores messages that were sent)\nTASKS NOT CHECKED ON 0!\n-1=inf (default)");
+  CONFIG_ADD_VAR(MESSAGE_RECV_BUFFER_SIZE, bool, -1, "Size of message receive buffer (stores messages that are received); -1=inf (default)");
+	CONFIG_ADD_VAR(MESSAGE_RECV_BUFFER_BEHAVIOR, bool, 0, "Behavior of message receive buffer; 0=drop oldest (default), 1=drop incoming");
 
   CONFIG_ADD_GROUP(BUY_SELL_GROUP, "Buying and Selling Parameters");
   CONFIG_ADD_VAR(SAVE_RECEIVED, bool, 0, "Enable storage of all inputs bought from other orgs");

Modified: development/source/main/cOrgMessage.cc
===================================================================
--- development/source/main/cOrgMessage.cc	2009-10-02 02:58:45 UTC (rev 3437)
+++ development/source/main/cOrgMessage.cc	2009-10-02 15:55:44 UTC (rev 3438)
@@ -25,15 +25,23 @@
 #include "cOrgMessage.h"
 #include "cOrganism.h"
 
-cOrgMessage::cOrgMessage(cOrganism* sender) 
-	: m_pSender(sender), m_pReceiver(0), m_data(0), m_label(0),
-	m_receiverOrgID(0), m_receiverCellID(0)
-{
-    assert(m_pSender);
+
+cOrgMessage::cOrgMessage()
+: m_pSender(0), m_pReceiver(0), m_data(0)
+, m_label(0), m_senderOrgID(0), m_senderCellID(0)
+, m_receiverOrgID(0), m_receiverCellID(0) {
+}
+
+
+cOrgMessage::cOrgMessage(cOrganism* sender)
+: m_pSender(sender), m_pReceiver(0), m_data(0)
+, m_label(0), m_receiverOrgID(0), m_receiverCellID(0) {
+	assert(m_pSender);
 	m_senderCellID = sender->GetCellID();
 	m_senderOrgID = sender->GetID();
 }
 
+
 void cOrgMessage::SetReceiver(cOrganism *recvr)
 {
 	m_pReceiver = recvr;

Modified: development/source/main/cOrgMessage.h
===================================================================
--- development/source/main/cOrgMessage.h	2009-10-02 02:58:45 UTC (rev 3437)
+++ development/source/main/cOrgMessage.h	2009-10-02 15:55:44 UTC (rev 3438)
@@ -37,6 +37,9 @@
 class cOrgMessage
 {
 public:
+  //! Default constructor.
+  cOrgMessage();
+	
   //! Constructor that takes a pointer to the sending organism.
   cOrgMessage(cOrganism* sender);
   
@@ -57,12 +60,6 @@
   int GetReceiverOrgID() const { return m_receiverOrgID; }
 
 private:
-  //! Default constructor is only used internally, to support message predicates.
-  cOrgMessage() : m_pSender(0), m_pReceiver(0), m_data(0), m_label(0), m_senderOrgID(0),
-	  m_senderCellID(0), m_receiverOrgID(0), m_receiverCellID(0)
-  {
-  }
-  
   cOrganism* m_pSender;
   cOrganism* m_pReceiver;
   unsigned int m_data;

Modified: development/source/main/cOrganism.cc
===================================================================
--- development/source/main/cOrganism.cc	2009-10-02 02:58:45 UTC (rev 3437)
+++ development/source/main/cOrganism.cc	2009-10-02 15:55:44 UTC (rev 3438)
@@ -813,131 +813,107 @@
   m_output_buf.Clear();
 }
 
+//! Called as the bottom-half of a successfully sent message.
+void cOrganism::MessageSent(cAvidaContext& ctx, cOrgMessage& msg) {
+	// check to see if we should store it:
+	const int bsize = m_world->GetConfig().MESSAGE_SEND_BUFFER_SIZE.Get();
 
-bool cOrganism::SendMessage(cAvidaContext& ctx, cOrgMessage& msg)
-{
+	if((bsize > 0) || (bsize == -1)) {
+		// yep; store it:
+		m_msg->sent.push_back(msg);
+		// and set the receiver-pointer of this message to NULL.  We don't want to
+		// walk this list later thinking that the receivers are still around.
+		m_msg->sent.back().SetReceiver(0);
+		// now, if our buffer is too large, chop off old messages:
+		if((bsize != -1) && (static_cast<int>(m_msg->sent.size()) > bsize)) {
+			while(static_cast<int>(m_msg->sent.size()) > bsize) { m_msg->sent.pop_front(); }
+		}
+
+		// check to see if we've performed any tasks:
+		DoOutput(ctx);
+	}	
+}
+
+
+/*! Send a message to the currently faced organism.  Stat-tracking is done over
+ in cPopulationInterface.  Remember that this code WILL be called from within the
+ test CPU!  (Also, BroadcastMessage funnels down to code in the population interface
+ too, so this way all the message sending code is in the same place.)
+ */
+bool cOrganism::SendMessage(cAvidaContext& ctx, cOrgMessage& msg) {
   assert(m_interface);
   InitMessaging();
 
-	cDeme* deme = m_interface->GetDeme();
-	if(deme) {
-		deme->IncMessageSent();
-	}
-	
-  // If we're able to succesfully send the message...
+  // if we sent the message:
   if(m_interface->SendMessage(msg)) {
-    // If we're remembering messages
-    if (m_world->GetConfig().ORGANISMS_REMEMBER_MESSAGES.Get()) {
-      // save it...
-      m_msg->sent.push_back(msg);
-      // and set the receiver-pointer of this message to NULL.  We don't want to
-      // walk this list later thinking that the receivers are still around.
-      m_msg->sent.back().SetReceiver(0);
-    }
-    // stat-tracking...
-    m_world->GetStats().SentMessage(msg);
-		m_interface->GetDeme()->MessageSuccessfullySent();
-    // check to see if we've performed any tasks...
-    DoOutput(ctx);
+		MessageSent(ctx, msg);
     return true;
-  } else {
-		// couldn't send the message
-		if(deme) {
-			deme->messageSendFailed();
-		}
-		return false;
-	}
+  }
+	
+	// importantly, m_interface->SendMessage() fails if we're running in the test CPU.
+	return false;
 }
 
 
-/*! Broadcast a message to all organisms out to the given depth. */
+/*! Broadcast a message to all organisms out to the given depth.
+ */
 bool cOrganism::BroadcastMessage(cAvidaContext& ctx, cOrgMessage& msg, int depth) {
   assert(m_interface);
   InitMessaging();
 	
+	// if we broadcasted the message:
 	if(m_interface->BroadcastMessage(msg, depth)) {
-		// If we're remembering messages
-    if (m_world->GetConfig().ORGANISMS_REMEMBER_MESSAGES.Get()) {
-      // save it...
-      m_msg->sent.push_back(msg);
-      // and set the receiver-pointer of this message to NULL.  We don't want to
-      // walk this list later thinking that the receivers are still around.
-      m_msg->sent.back().SetReceiver(0);
-    }		
-		// stat-tracking...  NOTE: this has receiver not specified, so may be a problem for predicates
-    m_world->GetStats().SentMessage(msg);
-    // check to see if we've performed any tasks...NOTE: this has receiver not specified, so may be a problem for tasks that care
-    DoOutput(ctx);
+		MessageSent(ctx, msg);
     return true;
   }
 	
+	// Again, m_interface->BroadcastMessage() fails if we're running in the test CPU.
 	return false;
 }
 
 
-void cOrganism::ReceiveMessage(cOrgMessage& msg)
-{
+/*! Called when this organism receives a message from another.
+ */
+void cOrganism::ReceiveMessage(cOrgMessage& msg) {
   InitMessaging();
-  msg.SetReceiver(this);
-  int msg_queue_size = m_world->GetConfig().MESSAGE_QUEUE_SIZE.Get();
-  // are message queues unbounded?
-  if (msg_queue_size >= 0) {
-    // if the message queue size is zero, the incoming message is always dropped
-    if (msg_queue_size == 0) {
-      return;
-    }
+	
+	// don't store more messages than we're configured to.
+	const int bsize = m_world->GetConfig().MESSAGE_RECV_BUFFER_SIZE.Get();
+	if((bsize != -1) && (bsize <= static_cast<int>(m_msg->received.size()))) {
+		switch(m_world->GetConfig().MESSAGE_RECV_BUFFER_BEHAVIOR.Get()) {
+			case 0: // drop oldest message
+				m_msg->received.pop_front();
+				break;
+			case 1: // drop this message
+				return;
+			default: // error
+				m_world->GetDriver().RaiseFatalException(-1, "MESSAGE_RECV_BUFFER_BEHAVIOR is set to an invalid value.");
+				assert(false);
+		}
+	}
 
-    // how many messages in the queue?
-    int num_unretrieved_msgs = m_msg->received.size()-m_msg->retrieve_index;
-    if (num_unretrieved_msgs == msg_queue_size) {
-      // look up message queue behavior
-      int bhvr = m_world->GetConfig().MESSAGE_QUEUE_BEHAVIOR_WHEN_FULL.Get();
-      if (bhvr == 0) {
-        // drop incoming message
-        return;
-      } else if (bhvr == 1 ) {
-        // drop the oldest unretrieved message
-        m_msg->received.erase(m_msg->received.begin()+m_msg->retrieve_index);
-      } else {
-        assert(false);
-        cerr << "ERROR: MESSAGE_QUEUE_BEHAVIOR_WHEN_FULL was set to " << bhvr << "," << endl;
-        cerr << "legal values are:" << endl;
-        cerr << "\t0: drop incoming message if message queue is full (default)" << endl;
-        cerr << "\t1: drop oldest unretrieved message if message queue is full" << endl;
-
-        // TODO: is there a more gracefull way to fail?
-        exit(1);
-      }
-    } // end if message queue is full
-    m_msg->received.push_back(msg);
-  } else {
-    // unbounded message queues
-    m_msg->received.push_back(msg);
-  }
+	msg.SetReceiver(this);
+	m_msg->received.push_back(msg);
 }
 
 
-const cOrgMessage* cOrganism::RetrieveMessage()
-{
+/*! Called to when this organism tries to load its CPU with the contents of a
+ previously-received message.  In a change from previous versions, pop the message
+ off the front.
+ 
+ \return A pair (b, msg): if b is true, then msg was received; if b is false, then msg was not received.
+ */
+std::pair<bool, cOrgMessage> cOrganism::RetrieveMessage() {
   InitMessaging();
-
-  assert(m_msg->retrieve_index <= m_msg->received.size());
-
-  // Return null if no new messages have been received
-  if (m_msg->retrieve_index == m_msg->received.size())
-    return 0;
-
-  if (m_world->GetConfig().ORGANISMS_REMEMBER_MESSAGES.Get()) {
-    // Return the next unretrieved message and incrememt retrieve_index
-    return &m_msg->received.at(m_msg->retrieve_index++);
-  } else {
-    // Not remembering messages, return the front of the message queue.
-    // Notice that retrieve_index will always equal 0 if
-    // ORGANISMS_REMEMBER_MESSAGES is false.
-    const cOrgMessage* msg = &m_msg->received.front();
-    m_msg->received.pop_front();
-    return msg;
-  }
+	std::pair<bool, cOrgMessage> ret = std::make_pair(false, cOrgMessage());	
+	
+	if(m_msg->received.size() > 0) {
+		ret.second = m_msg->received.front();
+		ret.first = true;
+		m_msg->received.pop_front();
+	}
+	
+	return ret;
 }
 
 

Modified: development/source/main/cOrganism.h
===================================================================
--- development/source/main/cOrganism.h	2009-10-02 02:58:45 UTC (rev 3437)
+++ development/source/main/cOrganism.h	2009-10-02 15:55:44 UTC (rev 3438)
@@ -31,6 +31,7 @@
 #include <set>
 #include <string>
 #include <vector>
+#include <utility>
 #include <map>
 
 #ifndef cCPUMemory_h
@@ -387,9 +388,6 @@
 
   
   // -------- Messaging support --------
-  // Use a deque instead of vector for amortized constant-time removal
-  // from the front of the list, to efficiently support message list
-  // size caps
 public:
   typedef std::deque<cOrgMessage> message_list_type; //!< Container-type for cOrgMessages.
   
@@ -400,7 +398,7 @@
   //! Called when this organism has been sent a message.
   void ReceiveMessage(cOrgMessage& msg);
   //! Called when this organism attempts to move a received message into its CPU.
-  const cOrgMessage* RetrieveMessage();
+	std::pair<bool, cOrgMessage> RetrieveMessage();
   //! Returns the list of all messsages received by this organism.
   const message_list_type& GetReceivedMessages() { InitMessaging(); return m_msg->received; }
   //! Returns the list of all messages sent by this organism.
@@ -426,7 +424,9 @@
   cMessagingSupport* m_msg;
   
   //! Called to check for (and initialize) messaging support within this organism.
-  inline void InitMessaging() { if(!m_msg) m_msg = new cMessagingSupport(); }
+  inline void InitMessaging() { if(!m_msg) m_msg = new cMessagingSupport(); }	
+	//! Called as the bottom-half of a successfully sent message.
+	void MessageSent(cAvidaContext& ctx, cOrgMessage& msg);
   // -------- End of messaging support --------
 
   // -------- Movement TEMP --------

Modified: development/source/main/cPopulationCell.cc
===================================================================
--- development/source/main/cPopulationCell.cc	2009-10-02 02:58:45 UTC (rev 3437)
+++ development/source/main/cPopulationCell.cc	2009-10-02 15:55:44 UTC (rev 3438)
@@ -149,6 +149,7 @@
   while(!i.AtEnd()) {
 		// store the cell pointer, and check to see if we've already visited that cell...
     cPopulationCell* cell = i.Next();
+		assert(cell != 0); // cells should never be null.
 		std::pair<cell_set_t::iterator, bool> ins = cell_set.insert(cell);
 		// and if so, recurse to it...
 		if(ins.second && (depth > 1)) {

Modified: development/source/main/cPopulationInterface.cc
===================================================================
--- development/source/main/cPopulationInterface.cc	2009-10-02 02:58:45 UTC (rev 3437)
+++ development/source/main/cPopulationInterface.cc	2009-10-02 15:55:44 UTC (rev 3438)
@@ -284,31 +284,47 @@
 }
 
 
-/*! Send a message to the faced organism, failing if this cell does not have 
-neighbors or if the cell currently faced is not occupied. */
-bool cPopulationInterface::SendMessage(cOrgMessage& msg) {
+/*! Internal-use method to consolidate message-sending code.
+ */
+bool cPopulationInterface::SendMessage(cOrgMessage& msg, cPopulationCell& rcell) {
 	static const double drop_prob = m_world->GetConfig().NET_DROP_PROB.Get();
-  if (drop_prob > 0.0 && m_world->GetRandom().P(drop_prob)) {
+  if((drop_prob > 0.0) && m_world->GetRandom().P(drop_prob)) {
+		// message dropped
 		GetDeme()->messageDropped();
-		return false; // message dropped
+		GetDeme()->messageSendFailed();
+		return false;
 	}
 	
-  cPopulationCell& cell = m_world->GetPopulation().GetCell(m_cell_id);
-  assert(cell.IsOccupied()); // This organism; sanity.
-  cPopulationCell* rcell = cell.ConnectionList().GetFirst();
-  assert(rcell != NULL); // Cells should never be null.
-
   // Fail if the cell we're facing is not occupied.
-  if(!rcell->IsOccupied())
+  if(!rcell.IsOccupied()) {
+		GetDeme()->messageSendFailed();
     return false;
-  cOrganism* recvr = rcell->GetOrganism();
-  assert(recvr != NULL);
+	}
+	
+	cOrganism* recvr = rcell.GetOrganism();
+  assert(recvr != 0);
   recvr->ReceiveMessage(msg);
+	m_world->GetStats().SentMessage(msg);
+	GetDeme()->IncMessageSent();
+	GetDeme()->MessageSuccessfullySent(); // No idea what the difference is here...
   return true;
 }
 
 
 /*! Send a message to the faced organism, failing if this cell does not have 
+ neighbors or if the cell currently faced is not occupied.
+ */
+bool cPopulationInterface::SendMessage(cOrgMessage& msg) {
+	cPopulationCell& cell = m_world->GetPopulation().GetCell(m_cell_id);
+	assert(cell.IsOccupied()); // This organism; sanity.
+
+  cPopulationCell* rcell = cell.ConnectionList().GetFirst();
+  assert(rcell != 0); // Cells should never be null.	
+	return SendMessage(msg, *rcell);
+}
+
+
+/*! Send a message to the faced organism, failing if this cell does not have 
  neighbors or if the cell currently faced is not occupied. */
 bool cPopulationInterface::BroadcastMessage(cOrgMessage& msg, int depth) {
   cPopulationCell& cell = m_world->GetPopulation().GetCell(m_cell_id);
@@ -321,11 +337,9 @@
 	// Remove this cell from the set!
 	cell_set.erase(&cell);
 	
-	// Now, send a message to each organism living in that set of cells.
+	// Now, send a message towards each cell:
 	for(std::set<cPopulationCell*>::iterator i=cell_set.begin(); i!=cell_set.end(); ++i) {
-		if((*i)->IsOccupied()) {
-			(*i)->GetOrganism()->ReceiveMessage(msg);
-		}
+		SendMessage(msg, **i);
 	}
 	return true;
 }

Modified: development/source/main/cPopulationInterface.h
===================================================================
--- development/source/main/cPopulationInterface.h	2009-10-02 02:58:45 UTC (rev 3437)
+++ development/source/main/cPopulationInterface.h	2009-10-02 15:55:44 UTC (rev 3438)
@@ -113,7 +113,6 @@
   bool TestOnDivide();
   //! Send a message to the faced organism.
   bool SendMessage(cOrgMessage& msg);
-  bool SendMessage(cOrganism* recvr, cOrgMessage& msg);
   bool BroadcastMessage(cOrgMessage& msg, int depth);
   bool BcastAlarm(int jump_label, int bcast_range);  
   void DivideOrgTestamentAmongDeme(double value);
@@ -133,7 +132,11 @@
 	//! Link this organism's cell to the cell with coordinates (x,y).
 	void CreateLinkByXY(int x, int y, double weight=1.0);
 	//! Link this organism's cell to the cell with index idx.
-	void CreateLinkByIndex(int idx, double weight=1.0);	
+	void CreateLinkByIndex(int idx, double weight=1.0);
+
+protected:
+	//! Internal-use method to consolidate message-sending code.
+	bool SendMessage(cOrgMessage& msg, cPopulationCell& rcell);
 };
 
 




More information about the Avida-cvs mailing list