[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