00001 /*!@file Neuro/SingleChannelBeo.C wrapper class to run a SingleChannel on a 00002 distant CPU */ 00003 00004 // //////////////////////////////////////////////////////////////////// // 00005 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2003 // 00006 // by the University of Southern California (USC) and the iLab at USC. // 00007 // See http://iLab.usc.edu for information about this project. // 00008 // //////////////////////////////////////////////////////////////////// // 00009 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00010 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00011 // in Visual Environments, and Applications'' by Christof Koch and // 00012 // Laurent Itti, California Institute of Technology, 2001 (patent // 00013 // pending; application number 09/912,225 filed July 23, 2001; see // 00014 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00015 // //////////////////////////////////////////////////////////////////// // 00016 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00017 // // 00018 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00019 // redistribute it and/or modify it under the terms of the GNU General // 00020 // Public License as published by the Free Software Foundation; either // 00021 // version 2 of the License, or (at your option) any later version. // 00022 // // 00023 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00024 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00025 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00026 // PURPOSE. See the GNU General Public License for more details. // 00027 // // 00028 // You should have received a copy of the GNU General Public License // 00029 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00030 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00031 // Boston, MA 02111-1307 USA. // 00032 // //////////////////////////////////////////////////////////////////// // 00033 // 00034 // Primary maintainer for this file: Laurent Itti <itti@usc.edu> 00035 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Neuro/SingleChannelBeo.C $ 00036 // $Id: SingleChannelBeo.C 8195 2007-03-30 04:34:07Z rjpeters $ 00037 // 00038 00039 #include "Neuro/SingleChannelBeo.H" 00040 00041 #include "Beowulf/Beowulf.H" 00042 #include "Beowulf/TCPmessage.H" 00043 #include "Component/ParamMap.H" 00044 #include "Util/Assert.H" 00045 00046 #include <sstream> 00047 00048 // ###################################################################### 00049 SingleChannelBeo::SingleChannelBeo(const nub::ref<Beowulf>& beow) : 00050 itsBeo(beow), itsNode(-2), itsFrame(-1) 00051 { } 00052 00053 // ###################################################################### 00054 SingleChannelBeo::~SingleChannelBeo() 00055 { 00056 if (itsNode >= 0) 00057 itsBeo->releaseNode(itsNode); 00058 } 00059 00060 // ###################################################################### 00061 void SingleChannelBeo::handleInput(SingleChannel& chan, 00062 const Image<float>& bwimg, 00063 const SimTime& t, 00064 const Image<byte>& clipMask, 00065 const rutz::shared_ptr<PyramidCache<float> >& cache) 00066 { 00067 // if we haven't allocated a Beowulf node yet, then let's do so now: 00068 if (itsNode == -2) 00069 { 00070 if (itsBeo->getNodeNumber() != -1) 00071 LFATAL("I need to be Beowulf master"); 00072 00073 // ask the Beowulf for a node number: 00074 itsNode = itsBeo->requestNode(); 00075 if (itsNode == -2) 00076 LFATAL("No more available nodes - You need a bigger Beowulf"); 00077 00078 LINFO("Delegating '%s' [%s] to Beowulf node %d", 00079 chan.descriptiveName().c_str(), chan.tagName().c_str(), 00080 itsNode); 00081 } 00082 00083 // if this is the first time we are called, let's start by sending 00084 // off a configuration message to our processing node, so that it 00085 // can create a channel for us: 00086 if (itsFrame == -1) { 00087 // we have two types of config data: our ModelParam values, and our 00088 // map weights. We put each into a ParamMap: 00089 ParamMap param; chan.writeParamsTo(param); 00090 ParamMap weight; chan.writeTo(weight); 00091 00092 // let's convert both ParamMaps to string: 00093 std::stringstream sparam, sweight; 00094 param.format(sparam); weight.format(sweight); 00095 00096 // let's put our descriptive name, our tag name and both parameter 00097 // strings into a TCPmessage, and let's put our VisualFeature in 00098 // the 'frame' field, and let's send it off (NOTE: VisualFeature 00099 // also is in param, but having it here will make decoding of the 00100 // message easier). 00101 int32 vs = static_cast<int32>(chan.visualFeature()); 00102 TCPmessage msg(vs, BEO_SCHANCONF); 00103 msg.addString(chan.descriptiveName().c_str()); 00104 msg.addString(chan.tagName().c_str()); 00105 msg.addString(sparam.str().c_str()); 00106 msg.addString(sweight.str().c_str()); 00107 00108 itsBeo->send(itsNode, msg); 00109 } 00110 00111 // increment our unofficial frame number; we have this counter just 00112 // because we have a frame field in TCPmessage, so we may as well 00113 // use it: 00114 itsFrame ++; 00115 00116 // send t, bwimg and clipMask to processor node: 00117 TCPmessage msg(itsFrame, BEO_SCHANINPUT); 00118 msg.addDouble(t.secs()); msg.addImage(bwimg); msg.addImage(clipMask); 00119 itsBeo->send(itsNode, msg); 00120 00121 // anybody needing our results will need to wait until they have 00122 // come back from the processor node: 00123 chan.killCaches(); 00124 } 00125 00126 // ###################################################################### 00127 void SingleChannelBeo::waitForOutput(SingleChannel& chan) 00128 { 00129 // nothing to wait for if we haven't allocated a Beowulf node yet: 00130 if (itsNode == -2) return; 00131 00132 // nothing to wait for if we have nothing in progress 00133 if (chan.hasOutputCache()) return; 00134 00135 // See if we have a new message on our Beowulf: 00136 TCPmessage rmsg; bool gotnothing = true; int err = 0; 00137 int32 rframe, raction, rnode = itsNode; // receive only from our server 00138 while(gotnothing) { 00139 err = 0; 00140 // wait up to 50ms 00141 if (itsBeo->receive(rnode, rmsg, rframe, raction, 50, &err)) { 00142 // message is supposed to contain: pyramid, submaps, possibly clipPyr: 00143 if (raction != BEO_SCHANOUTPUT && raction != BEO_SCHANALLOUT) 00144 LERROR("IGNORING message of wrong type from node %d", rnode); 00145 else { 00146 if (rframe != itsFrame) 00147 LERROR("Received results for frame %d while at frame %d??", 00148 rframe, itsFrame); 00149 // the time: 00150 const double t = rmsg.getElementDouble(); 00151 00152 // the output map (always valid, but possibly blank): 00153 chan.storeOutputCache(rmsg.getElementFloatIma()); 00154 00155 // additional results? 00156 if (raction == BEO_SCHANALLOUT) { 00157 // the pyramid: 00158 ImageSet<float> pyr = rmsg.getElementFloatImaSet(); 00159 // if the SingleChannel on the remote node had no output 00160 // available yet, we have an empty pyramid, which we don't 00161 // want to push into our pyramid queue; this way, we will also 00162 // have no pyramid available if the remote had none: 00163 if (pyr.size()) 00164 chan.storePyramid(pyr, SimTime::SECS(t)); 00165 00166 // the submaps: 00167 pyr = rmsg.getElementFloatImaSet(); 00168 if (pyr.size()) 00169 chan.storeSubmapCache(pyr); 00170 00171 // clip pyramid (if any): 00172 pyr = rmsg.getElementFloatImaSet(); 00173 if (pyr.size()) 00174 chan.storeClipPyramid(pyr); 00175 } 00176 00177 // ok, we got our results, let's return: 00178 gotnothing = false; 00179 } 00180 } 00181 00182 if (err != 0) 00183 LFATAL("error during Beowulf::receive()"); 00184 } 00185 } 00186 00187 // ###################################################################### 00188 rutz::shared_ptr<InputHandler> SingleChannelBeo::makeClone() const 00189 { 00190 return rutz::make_shared(new SingleChannelBeo(itsBeo)); 00191 } 00192 00193 // ###################################################################### 00194 /* So things look consistent in everyone's emacs... */ 00195 /* Local Variables: */ 00196 /* indent-tabs-mode: nil */ 00197 /* End: */