<commit_before>// See copyright notice in file Copyright in the root directory of this archive.

#include "MatternGVTManager.h"
#include "SchedulingManager.h"
#include "CommunicationManager.h"
#include "TimeWarpSimulationManager.h"
#include "MatternGVTMessage.h"
#include "GVTUpdateMessage.h"
#include "LazyOutputManager.h"
#include "ObjectID.h"
#include <sstream>
using std::istringstream;
using std::ostringstream;
using std::cout;
using std::cerr;
using std::endl;

MatternGVTManager::MatternGVTManager(TimeWarpSimulationManager *simMgr,
                                     unsigned int period) :
  GVTManagerImplementationBase(simMgr, period),
  objectRecord(new MatternObjectRecord()),
  gVTTokenPending(false)
{
  ASSERT( mySimulationManager != NULL );
  ASSERT( mySimulationManager->getSchedulingManager() != NULL );
  myScheduler = mySimulationManager->getSchedulingManager();
  ASSERT( mySimulationManager->getCommunicationManager() != NULL );
  myCommunicationManager = mySimulationManager->getCommunicationManager();
}

MatternGVTManager::MatternGVTManager(TimeWarpSimulationManager *simMgr,
                                     unsigned int period, bool objectRecordDefined) :
  GVTManagerImplementationBase(simMgr, period),
  gVTTokenPending(false)
{
  ASSERT( mySimulationManager != NULL );
  ASSERT( mySimulationManager->getSchedulingManager() != NULL );
  myScheduler = mySimulationManager->getSchedulingManager();
  ASSERT( mySimulationManager->getCommunicationManager() != NULL );
  myCommunicationManager = mySimulationManager->getCommunicationManager();
}

MatternGVTManager::~MatternGVTManager() {
  delete objectRecord;
}

bool MatternGVTManager::checkGVTPeriod() {
  if (!gVTTokenPending) {
    if(++gVTPeriodCounter == gVTPeriod){
      gVTPeriodCounter = 0;
      return true;
    }
  }
  return false;
}

// This is called before sending any event to keep track of the LTSE
void MatternGVTManager::calculateGVTInfo(const VTime &receiveTime) {
  abort();
}

// This is called before sending an event to a remote simulation manager
const string MatternGVTManager::getGVTInfo(unsigned int srcSimMgr, unsigned int destSimMgr,
                                           const VTime &sendTime) {
  //The timestamp information will be sent with the event, the color
  //is the only information stored in GVTInfo
  int tokenColor = objectRecord->getColor();
  char c[2];
  sprintf(c,"%d", tokenColor);

  if(tokenColor == WHITE){
    //Keep a count of all messages sent while the GVT Token is white
    objectRecord->incrementNumberOfWhiteMessages();
  }
  else{
    //If the first round of GVT Control messages has passed our
    //color is red so we should be monitoring the LTSE
    const VTime *minimumTime = (&sendTime);
    objectRecord->setMinTimeStamp(*minimumTime);
  }
  return c;
}

//This is called when receiving a remote event
void MatternGVTManager::updateEventRecord(const string &infoStream, unsigned int receivingSimMgr){
  // for mattern only color information will be present in the
  // info stream received from the kernel
  istringstream inputStream(infoStream);
  int tokenColor;
  inputStream >> tokenColor;

  if(tokenColor == WHITE) {
    objectRecord->decrementNumberOfWhiteMessages();
  }
}

void MatternGVTManager::calculateGVT() {
  // a few assumptions to state first:
  //
  // a. SimulationManager(0) is assumed to be the initiator of the
  //    gvt estimation procedure.
  //
  // b. if numberOfSimulationManagers == 1, then the gVT is simply the
  //    last scheduled event.
  ASSERT(mySimulationManager->getSimulationManagerID() == 0 );
  if (mySimulationManager->getNumberOfSimulationManagers() > 1) {
    // Okay, time to start off the gvt token.
    if (gVTTokenPending == false) {
      zeroWhiteMessagesAtStart=false;
      // Make sure there isn't a token already out there.
      const VTime *minimumTime = (&myScheduler->getLastEventScheduledTime());
      sendGVTToken(*minimumTime, mySimulationManager->getPositiveInfinity());

      objectRecord->setColor(RED);
      objectRecord->setNumberOfWhiteMessages(0);
      objectRecord->resetMinTimeStamp(mySimulationManager->getPositiveInfinity());
      gVTTokenPending = true;
    }
  }
  else { // numberOfSimulationManagers == 1
    // okay, we dont need to launch a distributed gvt estimation step
    // gVT is simply the last scheduled event's timestamp
    const VTime *minimumTime = (&myScheduler->getLastEventScheduledTime());
    setGVT(*minimumTime);
    cout << "GVT = " << getGVT() << endl;
    mySimulationManager->fossilCollect(getGVT());
  }
}

// ----------------------------------------------------------------
// A GVTTokenMessage contains:
//   1. VTime mClock;             // minimum of the local clocks
//   2. VTime mSend;              // minimum of timestamps
//   3. unsigned int count;       // number of messages in transit
// ----------------------------------------------------------------
void MatternGVTManager::sendGVTToken(const VTime &lastScheduledEventTime,
                                     const VTime &minimumTimeStamp) {
  // My(malolan) changes here The guy, whom i am going to send to has to
  // know, how many white messages, i have sent and not the white messages
  // that, i have received so changing
  // objectRecordArray[myID].getNumberOfWhiteMessages() to
  // objectRecordArray[destination].getNumberOfWhiteMessages( send the
  // token to the next guy;
  unsigned int destination = 0;
  if (mySimulationManager->getSimulationManagerID()
      != mySimulationManager->getNumberOfSimulationManagers() - 1) {
    destination = mySimulationManager->getSimulationManagerID() + 1;
  }
  // increment the token iteration number
  objectRecord->incrementTokenIterationNumber();
  KernelMessage *messageToSend = new MatternGVTMessage(
      mySimulationManager->getSimulationManagerID(), destination,
      lastScheduledEventTime, minimumTimeStamp,
      objectRecord->getNumberOfWhiteMessages());
  ASSERT(myCommunicationManager != NULL);
  myCommunicationManager->sendMessage(messageToSend, destination);
}

// send out the latest gVT value to everyone
void MatternGVTManager::sendGVTUpdate() {
  // send everybody except ourselves the gVT update message
  for (unsigned int c = 0; c < mySimulationManager->getNumberOfSimulationManagers(); c++) {
    if (mySimulationManager->getSimulationManagerID() != c) {
      KernelMessage *messageToSend =
          new GVTUpdateMessage(mySimulationManager->getSimulationManagerID(), c, getGVT());
      ASSERT(myCommunicationManager != NULL);
      myCommunicationManager->sendMessage(messageToSend, c);
    }
  }
}

// the MatternGVTManager must register the following message types with
// the communication manager: GVTTokenMessage and GVTUpdateMessage
void MatternGVTManager::registerWithCommunicationManager() {
  ASSERT(myCommunicationManager != NULL);
  myCommunicationManager->registerMessageType(GVTUpdateMessage::getGVTUpdateMessageType(), this);
  myCommunicationManager->registerMessageType(MatternGVTMessage::getMatternGVTMessageType(), this);
}

// the communication manager will call this method to deliver a
// GVTTokenMessage or a GVTUpdateMessage.
void MatternGVTManager::receiveKernelMessage(KernelMessage *msg) {
  ASSERT(msg != NULL);
  if (dynamic_cast<MatternGVTMessage *> (msg) != 0) {
    const MatternGVTMessage *gVTMessage = dynamic_cast<MatternGVTMessage *> (msg);
    const int count = gVTMessage->getNumMessagesInTransit();

    if (mySimulationManager->getSimulationManagerID() == 0) {
      // Initiator has received the control message.
      // Check to see if the count is zero and this is at least the second
      // round of the token. Continue until the count is 0 and all messages
      // in transit are accounted for.
      if (objectRecord->getTokenIterationNumber() > 1
          && (objectRecord->getNumberOfWhiteMessages() + count == 0)){

          // Need to remember the old gvt to compare it to the new.
          const VTime &oldGVT = getGVT();

          // Determine GVT.
          setGVT(MIN_FUNC(gVTMessage->getLastScheduledEventTime(),
                 gVTMessage->getMinimumTimeStamp()));
          ASSERT(getGVT() >= oldGVT);

          // Send out the GVT update to the other simulation managers and reset to white.
          objectRecord->setTokenIterationNumber(0);
          objectRecord->setNumberOfWhiteMessages(0);
          objectRecord->setColor(WHITE);
          sendGVTUpdate();

          // End of this gvt calculation cycle.
          gVTTokenPending = false;

          // Only output the value and fossil collect when it actually changes.
          if(getGVT() > oldGVT){
            // Fossil collect now with the new GVT.
            //cout << "GVT = " << getGVT() << endl;
            mySimulationManager->fossilCollect(getGVT());
          }
      }
      else {
        // Not yet ready to calculate gvt, send the token around again.
        objectRecord->setNumberOfWhiteMessages(objectRecord->getNumberOfWhiteMessages() + count);
        const VTime *lowEventTime = (&myScheduler->getLastEventScheduledTime());
        sendGVTToken(MIN_FUNC(gVTMessage->getLastScheduledEventTime(), *lowEventTime),
               MIN_FUNC(gVTMessage->getMinimumTimeStamp(), *objectRecord->getMinTimeStamp()));

        // This is reset to record the number of messages received since the last round.
        objectRecord->setNumberOfWhiteMessages(0);
      }
    }
    else {
      // The gvt token has been received by another simulation manager.
      // [a] Set color of this sim mgr to RED; set tMin = positive infinity.
      // [b] Pass on the token to processor(i mod n) + 1.
      if (objectRecord->getColor() == WHITE) {
        objectRecord->resetMinTimeStamp(mySimulationManager->getPositiveInfinity());
        objectRecord->setColor(RED);
      }

      // Add the the local white message count to the simulation's white message total.
      objectRecord->setNumberOfWhiteMessages(objectRecord->getNumberOfWhiteMessages() + count);

      const VTime *lowEventTime = (&myScheduler->getLastEventScheduledTime());
      sendGVTToken(MIN_FUNC(gVTMessage->getLastScheduledEventTime(),*lowEventTime),
                   MIN_FUNC(gVTMessage->getMinimumTimeStamp(),*objectRecord->getMinTimeStamp()));

      // This is reset to record the number of messages received since the last round.
      objectRecord->setNumberOfWhiteMessages(0);
    }
  }
  else if (dynamic_cast<GVTUpdateMessage *> (msg) != 0) {
    const GVTUpdateMessage *gVTMessage = dynamic_cast<GVTUpdateMessage *> (msg);

    const VTime &oldGVT = getGVT();
    setGVT(gVTMessage->getNewGVT());
    ASSERT(getGVT() >= oldGVT);

    // Only fossil collect if the value has increased.
    if(getGVT() > oldGVT){
      // Fossil collect now with the new GVT.
      mySimulationManager->fossilCollect(getGVT());
    }

    // VERY IMPORTANT NOTE!!
    // The white message count is not reset here because by the time this
    // simulation manager gets the update token, it may have already received some
    // white messages from another simulation manager that already switched back
    // to white. These need to be taken into account for the next GVT calculation.
    objectRecord->setTokenIterationNumber(0);
    objectRecord->setColor(WHITE);
  }
  else {
    cerr << "MatternGVTManager::receiveKernelMessage() received"
        << " unknown (" << msg->getDataType() << ") message type"
        << endl;
    cerr << "Aborting simulation ..." << endl;
    abort();
  }
  // We are done with this kernel message.
  delete msg;
}

const VTime *MatternGVTManager::getEarliestEventTime(const VTime *lowEventTime) {
  if (mySimulationManager->getOutputMgrType() == LAZYMGR ||
      mySimulationManager->getOutputMgrType() == ADAPTIVEMGR) {
    LazyOutputManager *lmgr = static_cast<LazyOutputManager*>(mySimulationManager->getOutputManager());
    const VTime *lazyMinTime = &lmgr->getLazyQMinTime();
    lowEventTime = &MIN_FUNC(*lazyMinTime, *lowEventTime);
  }
  return lowEventTime;
}

void
MatternGVTManager::ofcReset(){
  gVTTokenPending = false;
  gVTPeriodCounter = 0;
  objectRecord->setNumberOfWhiteMessages(0);
  objectRecord->setTokenIterationNumber(0);
  objectRecord->setColor(WHITE);
}
<commit_msg>similar optimization to a342b3a85a6ac396639feb7010904adcdd237e58 for receiving end, ~2% savings<commit_after>// See copyright notice in file Copyright in the root directory of this archive.

#include "MatternGVTManager.h"
#include "SchedulingManager.h"
#include "CommunicationManager.h"
#include "TimeWarpSimulationManager.h"
#include "MatternGVTMessage.h"
#include "GVTUpdateMessage.h"
#include "LazyOutputManager.h"
#include "ObjectID.h"
#include <sstream>
using std::istringstream;
using std::ostringstream;
using std::cout;
using std::cerr;
using std::endl;

MatternGVTManager::MatternGVTManager(TimeWarpSimulationManager *simMgr,
                                     unsigned int period) :
  GVTManagerImplementationBase(simMgr, period),
  objectRecord(new MatternObjectRecord()),
  gVTTokenPending(false)
{
  ASSERT( mySimulationManager != NULL );
  ASSERT( mySimulationManager->getSchedulingManager() != NULL );
  myScheduler = mySimulationManager->getSchedulingManager();
  ASSERT( mySimulationManager->getCommunicationManager() != NULL );
  myCommunicationManager = mySimulationManager->getCommunicationManager();
}

MatternGVTManager::MatternGVTManager(TimeWarpSimulationManager *simMgr,
                                     unsigned int period, bool objectRecordDefined) :
  GVTManagerImplementationBase(simMgr, period),
  gVTTokenPending(false)
{
  ASSERT( mySimulationManager != NULL );
  ASSERT( mySimulationManager->getSchedulingManager() != NULL );
  myScheduler = mySimulationManager->getSchedulingManager();
  ASSERT( mySimulationManager->getCommunicationManager() != NULL );
  myCommunicationManager = mySimulationManager->getCommunicationManager();
}

MatternGVTManager::~MatternGVTManager() {
  delete objectRecord;
}

bool MatternGVTManager::checkGVTPeriod() {
  if (!gVTTokenPending) {
    if(++gVTPeriodCounter == gVTPeriod){
      gVTPeriodCounter = 0;
      return true;
    }
  }
  return false;
}

// This is called before sending any event to keep track of the LTSE
void MatternGVTManager::calculateGVTInfo(const VTime &receiveTime) {
  abort();
}

// This is called before sending an event to a remote simulation manager
const string MatternGVTManager::getGVTInfo(unsigned int srcSimMgr, unsigned int destSimMgr,
                                           const VTime &sendTime) {
  //The timestamp information will be sent with the event, the color
  //is the only information stored in GVTInfo
  int tokenColor = objectRecord->getColor();
  char c[2];
  sprintf(c,"%d", tokenColor);

  if(tokenColor == WHITE){
    //Keep a count of all messages sent while the GVT Token is white
    objectRecord->incrementNumberOfWhiteMessages();
  }
  else{
    //If the first round of GVT Control messages has passed our
    //color is red so we should be monitoring the LTSE
    const VTime *minimumTime = (&sendTime);
    objectRecord->setMinTimeStamp(*minimumTime);
  }
  return c;
}

//This is called when receiving a remote event
void MatternGVTManager::updateEventRecord(const string &infoStream, unsigned int receivingSimMgr){
  // for mattern only color information will be present in the
  // info stream received from the kernel
  int tokenColor = atoi(infoStream.c_str());

  if(tokenColor == WHITE) {
    objectRecord->decrementNumberOfWhiteMessages();
  }
}

void MatternGVTManager::calculateGVT() {
  // a few assumptions to state first:
  //
  // a. SimulationManager(0) is assumed to be the initiator of the
  //    gvt estimation procedure.
  //
  // b. if numberOfSimulationManagers == 1, then the gVT is simply the
  //    last scheduled event.
  ASSERT(mySimulationManager->getSimulationManagerID() == 0 );
  if (mySimulationManager->getNumberOfSimulationManagers() > 1) {
    // Okay, time to start off the gvt token.
    if (gVTTokenPending == false) {
      zeroWhiteMessagesAtStart=false;
      // Make sure there isn't a token already out there.
      const VTime *minimumTime = (&myScheduler->getLastEventScheduledTime());
      sendGVTToken(*minimumTime, mySimulationManager->getPositiveInfinity());

      objectRecord->setColor(RED);
      objectRecord->setNumberOfWhiteMessages(0);
      objectRecord->resetMinTimeStamp(mySimulationManager->getPositiveInfinity());
      gVTTokenPending = true;
    }
  }
  else { // numberOfSimulationManagers == 1
    // okay, we dont need to launch a distributed gvt estimation step
    // gVT is simply the last scheduled event's timestamp
    const VTime *minimumTime = (&myScheduler->getLastEventScheduledTime());
    setGVT(*minimumTime);
    cout << "GVT = " << getGVT() << endl;
    mySimulationManager->fossilCollect(getGVT());
  }
}

// ----------------------------------------------------------------
// A GVTTokenMessage contains:
//   1. VTime mClock;             // minimum of the local clocks
//   2. VTime mSend;              // minimum of timestamps
//   3. unsigned int count;       // number of messages in transit
// ----------------------------------------------------------------
void MatternGVTManager::sendGVTToken(const VTime &lastScheduledEventTime,
                                     const VTime &minimumTimeStamp) {
  // My(malolan) changes here The guy, whom i am going to send to has to
  // know, how many white messages, i have sent and not the white messages
  // that, i have received so changing
  // objectRecordArray[myID].getNumberOfWhiteMessages() to
  // objectRecordArray[destination].getNumberOfWhiteMessages( send the
  // token to the next guy;
  unsigned int destination = 0;
  if (mySimulationManager->getSimulationManagerID()
      != mySimulationManager->getNumberOfSimulationManagers() - 1) {
    destination = mySimulationManager->getSimulationManagerID() + 1;
  }
  // increment the token iteration number
  objectRecord->incrementTokenIterationNumber();
  KernelMessage *messageToSend = new MatternGVTMessage(
      mySimulationManager->getSimulationManagerID(), destination,
      lastScheduledEventTime, minimumTimeStamp,
      objectRecord->getNumberOfWhiteMessages());
  ASSERT(myCommunicationManager != NULL);
  myCommunicationManager->sendMessage(messageToSend, destination);
}

// send out the latest gVT value to everyone
void MatternGVTManager::sendGVTUpdate() {
  // send everybody except ourselves the gVT update message
  for (unsigned int c = 0; c < mySimulationManager->getNumberOfSimulationManagers(); c++) {
    if (mySimulationManager->getSimulationManagerID() != c) {
      KernelMessage *messageToSend =
          new GVTUpdateMessage(mySimulationManager->getSimulationManagerID(), c, getGVT());
      ASSERT(myCommunicationManager != NULL);
      myCommunicationManager->sendMessage(messageToSend, c);
    }
  }
}

// the MatternGVTManager must register the following message types with
// the communication manager: GVTTokenMessage and GVTUpdateMessage
void MatternGVTManager::registerWithCommunicationManager() {
  ASSERT(myCommunicationManager != NULL);
  myCommunicationManager->registerMessageType(GVTUpdateMessage::getGVTUpdateMessageType(), this);
  myCommunicationManager->registerMessageType(MatternGVTMessage::getMatternGVTMessageType(), this);
}

// the communication manager will call this method to deliver a
// GVTTokenMessage or a GVTUpdateMessage.
void MatternGVTManager::receiveKernelMessage(KernelMessage *msg) {
  ASSERT(msg != NULL);
  if (dynamic_cast<MatternGVTMessage *> (msg) != 0) {
    const MatternGVTMessage *gVTMessage = dynamic_cast<MatternGVTMessage *> (msg);
    const int count = gVTMessage->getNumMessagesInTransit();

    if (mySimulationManager->getSimulationManagerID() == 0) {
      // Initiator has received the control message.
      // Check to see if the count is zero and this is at least the second
      // round of the token. Continue until the count is 0 and all messages
      // in transit are accounted for.
      if (objectRecord->getTokenIterationNumber() > 1
          && (objectRecord->getNumberOfWhiteMessages() + count == 0)){

          // Need to remember the old gvt to compare it to the new.
          const VTime &oldGVT = getGVT();

          // Determine GVT.
          setGVT(MIN_FUNC(gVTMessage->getLastScheduledEventTime(),
                 gVTMessage->getMinimumTimeStamp()));
          ASSERT(getGVT() >= oldGVT);

          // Send out the GVT update to the other simulation managers and reset to white.
          objectRecord->setTokenIterationNumber(0);
          objectRecord->setNumberOfWhiteMessages(0);
          objectRecord->setColor(WHITE);
          sendGVTUpdate();

          // End of this gvt calculation cycle.
          gVTTokenPending = false;

          // Only output the value and fossil collect when it actually changes.
          if(getGVT() > oldGVT){
            // Fossil collect now with the new GVT.
            //cout << "GVT = " << getGVT() << endl;
            mySimulationManager->fossilCollect(getGVT());
          }
      }
      else {
        // Not yet ready to calculate gvt, send the token around again.
        objectRecord->setNumberOfWhiteMessages(objectRecord->getNumberOfWhiteMessages() + count);
        const VTime *lowEventTime = (&myScheduler->getLastEventScheduledTime());
        sendGVTToken(MIN_FUNC(gVTMessage->getLastScheduledEventTime(), *lowEventTime),
               MIN_FUNC(gVTMessage->getMinimumTimeStamp(), *objectRecord->getMinTimeStamp()));

        // This is reset to record the number of messages received since the last round.
        objectRecord->setNumberOfWhiteMessages(0);
      }
    }
    else {
      // The gvt token has been received by another simulation manager.
      // [a] Set color of this sim mgr to RED; set tMin = positive infinity.
      // [b] Pass on the token to processor(i mod n) + 1.
      if (objectRecord->getColor() == WHITE) {
        objectRecord->resetMinTimeStamp(mySimulationManager->getPositiveInfinity());
        objectRecord->setColor(RED);
      }

      // Add the the local white message count to the simulation's white message total.
      objectRecord->setNumberOfWhiteMessages(objectRecord->getNumberOfWhiteMessages() + count);

      const VTime *lowEventTime = (&myScheduler->getLastEventScheduledTime());
      sendGVTToken(MIN_FUNC(gVTMessage->getLastScheduledEventTime(),*lowEventTime),
                   MIN_FUNC(gVTMessage->getMinimumTimeStamp(),*objectRecord->getMinTimeStamp()));

      // This is reset to record the number of messages received since the last round.
      objectRecord->setNumberOfWhiteMessages(0);
    }
  }
  else if (dynamic_cast<GVTUpdateMessage *> (msg) != 0) {
    const GVTUpdateMessage *gVTMessage = dynamic_cast<GVTUpdateMessage *> (msg);

    const VTime &oldGVT = getGVT();
    setGVT(gVTMessage->getNewGVT());
    ASSERT(getGVT() >= oldGVT);

    // Only fossil collect if the value has increased.
    if(getGVT() > oldGVT){
      // Fossil collect now with the new GVT.
      mySimulationManager->fossilCollect(getGVT());
    }

    // VERY IMPORTANT NOTE!!
    // The white message count is not reset here because by the time this
    // simulation manager gets the update token, it may have already received some
    // white messages from another simulation manager that already switched back
    // to white. These need to be taken into account for the next GVT calculation.
    objectRecord->setTokenIterationNumber(0);
    objectRecord->setColor(WHITE);
  }
  else {
    cerr << "MatternGVTManager::receiveKernelMessage() received"
        << " unknown (" << msg->getDataType() << ") message type"
        << endl;
    cerr << "Aborting simulation ..." << endl;
    abort();
  }
  // We are done with this kernel message.
  delete msg;
}

const VTime *MatternGVTManager::getEarliestEventTime(const VTime *lowEventTime) {
  if (mySimulationManager->getOutputMgrType() == LAZYMGR ||
      mySimulationManager->getOutputMgrType() == ADAPTIVEMGR) {
    LazyOutputManager *lmgr = static_cast<LazyOutputManager*>(mySimulationManager->getOutputManager());
    const VTime *lazyMinTime = &lmgr->getLazyQMinTime();
    lowEventTime = &MIN_FUNC(*lazyMinTime, *lowEventTime);
  }
  return lowEventTime;
}

void
MatternGVTManager::ofcReset(){
  gVTTokenPending = false;
  gVTPeriodCounter = 0;
  objectRecord->setNumberOfWhiteMessages(0);
  objectRecord->setTokenIterationNumber(0);
  objectRecord->setColor(WHITE);
}
<|endoftext|>


<commit_before>#include "FWCore/Framework/interface/Frameworkfwd.h"
#include "FWCore/Framework/interface/EDAnalyzer.h"
#include "FWCore/Framework/interface/Event.h"
#include "FWCore/Framework/interface/Run.h"
#include "FWCore/Framework/interface/MakerMacros.h"
#include "FWCore/Utilities/interface/InputTag.h"
#include "FWCore/Common/interface/TriggerNames.h"
#include "DataFormats/Common/interface/TriggerResults.h"
#include "DataFormats/Common/interface/Handle.h"
#include "DataFormats/PatCandidates/interface/TriggerObjectStandAlone.h"

#include "PandaTree/Objects/interface/Event.h"

#include "../interface/FillerBase.h"
#include "../interface/ObjectMap.h"

#include "TFile.h"
#include "TTree.h"
#include "TH1D.h"
#include <vector>
#include <utility>
#include <chrono>

typedef std::chrono::steady_clock SClock;
double toMS(SClock::duration const& interval)
{
  return std::chrono::duration_cast<std::chrono::nanoseconds>(interval).count() * 1.e-6;
}

class PandaProducer : public edm::EDAnalyzer {
public:
  explicit PandaProducer(edm::ParameterSet const&);
  ~PandaProducer();

private:
  typedef edm::View<pat::TriggerObjectStandAlone> TriggerObjectView;

  void analyze(edm::Event const&, edm::EventSetup const&) override;
  void beginRun(edm::Run const&, edm::EventSetup const&) override;
  void endRun(edm::Run const&, edm::EventSetup const&) override;
  void beginJob() override;
  void endJob() override;

  std::vector<FillerBase*> fillers_;
  ObjectMapStore objectMaps_;

  VString selectEvents_;
  edm::EDGetTokenT<edm::TriggerResults> skimResultsToken_;
  edm::EDGetTokenT<edm::TriggerResults> hltResultsToken_;
  edm::EDGetTokenT<TriggerObjectView> triggerObjectsToken_;

  TFile* outputFile_{0};
  TTree* eventTree_{0};
  TTree* runTree_{0};
  TH1D* eventCounter_{0};
  panda::Event outEvent_;

  std::string outputName_;
  bool useTrigger_;
  // [[filter0, filter1, ...], ...] outer index runs over trigger objects
  std::vector<VString> triggerObjectNames_;
  unsigned printLevel_;

  std::vector<SClock::duration> timers_;
  SClock::time_point lastAnalyze_; //! Time point of last return from analyze()
  unsigned long long nEvents_;
};

PandaProducer::PandaProducer(edm::ParameterSet const& _cfg) :
  selectEvents_(_cfg.getUntrackedParameter<VString>("SelectEvents")),
  skimResultsToken_(consumes<edm::TriggerResults>(edm::InputTag("TriggerResults"))), // no process name -> pick up the trigger results from the current process
  outputName_(_cfg.getUntrackedParameter<std::string>("outputFile", "panda.root")),
  useTrigger_(_cfg.getUntrackedParameter<bool>("useTrigger", true)),
  printLevel_(_cfg.getUntrackedParameter<unsigned>("printLevel", 0)),
  timers_(),
  lastAnalyze_(),
  nEvents_(0)
{
  auto&& coll(consumesCollector());

  auto& fillersCfg(_cfg.getUntrackedParameterSet("fillers"));

  SClock::time_point start;

  for (auto& fillerName : fillersCfg.getParameterNames()) {
    if (fillerName == "common")
      continue;

    auto& fillerPSet(fillersCfg.getUntrackedParameterSet(fillerName));
    try {
      auto className(fillerPSet.getUntrackedParameter<std::string>("filler") + "Filler");

      if (printLevel_ >= 1) {
        std::cout << "[PandaProducer::PandaProducer] "
          << "Constructing " << className << "::" << fillerName << std::endl;

        if (printLevel_ >= 3)
          start = SClock::now();
      }

      auto* filler(FillerFactoryStore::singleton()->makeFiller(className, fillerName, _cfg, coll));
      fillers_.push_back(filler);

      if (filler->enabled())
        filler->setObjectMap(objectMaps_[fillerName]);

      if (printLevel_ >= 1) {
        timers_.push_back(SClock::duration::zero());

        if (printLevel_ >= 3)
          std::cout << "Initializing " << fillerName << " took " << toMS(SClock::now() - start) << " ms." << std::endl;
      }
    }
    catch (std::exception& ex) {
      std::cerr << "[PandaProducer::PandaProducer] "
        << "Configuration error in " << fillerName << ":"
                                     << ex.what() << std::endl;
      throw;
    }
  }

  if (useTrigger_) {
    hltResultsToken_ = consumes<edm::TriggerResults>(edm::InputTag("TriggerResults", "", "HLT"));
    triggerObjectsToken_ = consumes<TriggerObjectView>(edm::InputTag(fillersCfg.getUntrackedParameterSet("common").getUntrackedParameter<std::string>("triggerObjects")));
  }

  if (printLevel_ >= 1) {
    // timer for the CMSSW execution outside of this module
    timers_.push_back(SClock::duration::zero());
  }
}

PandaProducer::~PandaProducer()
{
  for (auto* filler : fillers_)
    delete filler;
}

void
PandaProducer::analyze(edm::Event const& _event, edm::EventSetup const& _setup)
{
  eventCounter_->Fill(0.5);

  if (printLevel_ >= 1) {
    if (nEvents_ == 0) {
      if (printLevel_ >= 3)
        std::cout << "[PandaProducer::analyze] "
                  << "First event; CMSSW step time unknown" << std::endl;

    }
    else {
      auto dt(SClock::now() - lastAnalyze_);
      if (printLevel_ >= 3)
        std::cout << "[PandaProducer::analyze] "
                  << "Previous (CMSSW) step took " << toMS(dt) << " ms" << std::endl;

      timers_.back() += dt;
    }
  }

  ++nEvents_;

  SClock::time_point start;

  // Fill "all events" information
  for (unsigned iF(0); iF != fillers_.size(); ++iF) {
    auto* filler(fillers_[iF]);

    if (!filler->enabled())
      continue;

    try {
      if (printLevel_ >= 1) {
        start = SClock::now();

        if (printLevel_ >= 2)
          std::cout << "[PandaProducer::analyze] "
                    << "Calling " << filler->getName() << "->fillAll()" << std::endl;
      }

      filler->fillAll(_event, _setup);

      if (printLevel_ >= 1) {
        auto dt(SClock::now() - start);

        if (printLevel_ >= 3) {
          std::cout << "[PandaProducer::analyze] "
                    << "Step " << filler->getName() << "->fillAll() took " << toMS(dt) << " ms" << std::endl;
        }

        timers_[iF] += dt;
      }
    }
    catch (std::exception& ex) {
      std::cerr << "[PandaProducer::analyze] "
        << "Error in " << filler->getName() << "::fillAll()" << std::endl;
      throw;
    }
  }

  // If path names are given, check if at least one succeeded
  if (selectEvents_.size() != 0) {
    edm::Handle<edm::TriggerResults> triggerResults;
    if(_event.getByToken(skimResultsToken_, triggerResults)){
      auto& pathNames(_event.triggerNames(*triggerResults));
      unsigned iS(0);
      for (; iS != selectEvents_.size(); ++iS) {
        unsigned iP(pathNames.triggerIndex(selectEvents_[iS]));
        if (iP != pathNames.size() && triggerResults->accept(iP))
          break;
      }
      if (iS == selectEvents_.size())
        return;
    }
  }

  eventCounter_->Fill(1.5);

  // Now fill the event
  outEvent_.init();

  for (auto& mm : objectMaps_)
    mm.second.clearMaps();

  if (useTrigger_) {
    // Unpack trigger object names
    edm::Handle<edm::TriggerResults> triggerResultsHandle;
    _event.getByToken(hltResultsToken_, triggerResultsHandle);
    auto& triggerNames(_event.triggerNames(*triggerResultsHandle));

    edm::Handle<TriggerObjectView> triggerObjectsHandle;
    _event.getByToken(triggerObjectsToken_, triggerObjectsHandle);
    auto& triggerObjects(*triggerObjectsHandle);

    auto& objMap(objectMaps_["global"].get<pat::TriggerObjectStandAlone, VString>());
    triggerObjectNames_.assign(triggerObjects.size(), VString());

    unsigned iObj(0);
    for (auto& obj : triggerObjects) {
      // need to create a copy to perform the non-const action of unpacking
      pat::TriggerObjectStandAlone copy(obj);
      copy.unpackPathNames(triggerNames);

      for (auto& label : obj.filterLabels())
        triggerObjectNames_[iObj].push_back(label);

      // link the pat trigger object to the list of labels
      objMap.add(triggerObjects.ptrAt(iObj), triggerObjectNames_[iObj]);
      ++iObj;
    }
  }

  outEvent_.runNumber = _event.id().run();
  outEvent_.lumiNumber = _event.luminosityBlock();
  outEvent_.eventNumber = _event.id().event();
  outEvent_.isData = _event.isRealData();

  for (unsigned iF(0); iF != fillers_.size(); ++iF) {
    auto* filler(fillers_[iF]);

    if (!filler->enabled())
      continue;

    try {
      if (printLevel_ >= 1) {
        if (printLevel_ >= 2)
          std::cout << "[PandaProducer::fill] "
                    << "Calling " << filler->getName() << "->fill()" << std::endl;

        start = SClock::now();
      }

      filler->fill(outEvent_, _event, _setup);

      if (printLevel_ >= 1) {
        auto dt(SClock::now() - start);

        if (printLevel_ >= 3)
          std::cout << "[PandaProducer::analyze] "
                    << "Step " << filler->getName() << "->fill() took " << toMS(dt) << " ms" << std::endl;

        timers_[iF] += dt;
      }
    }
    catch (std::exception& ex) {
      std::cerr << "[PandaProducer::fill] "
        << "Error in " << filler->getName() << "::fill()" << std::endl;
      throw;
    }
  }

  // Set inter-branch references
  for (unsigned iF(0); iF != fillers_.size(); ++iF) {
    auto* filler(fillers_[iF]);

    if (!filler->enabled())
      continue;

    try {
      if (printLevel_ >= 1) {
        if (printLevel_ >= 2)
          std::cout << "[PandaProducer:fill] "
                    << "Calling " << filler->getName() << "->setRefs()" << std::endl;

        start = SClock::now();
      }

      filler->setRefs(objectMaps_);

      if (printLevel_ >= 1) {
        auto dt(SClock::now() - start);

        if (printLevel_ >= 3)
          std::cout << "[PandaProducer::analyze] "
                    << "Step " << filler->getName() << "->setRefs() took " << toMS(dt) << " ms" << std::endl;

        timers_[iF] += dt;
      }
    }
    catch (std::exception& ex) {
      std::cerr << "[PandaProducer:fill] "
        << "Error in " << filler->getName() << "::setRefs()" << std::endl;
      throw;
    }
  }

  outEvent_.fill(*eventTree_);

  lastAnalyze_ = SClock::now();
}

void
PandaProducer::beginRun(edm::Run const& _run, edm::EventSetup const& _setup)
{
  outEvent_.run.init();

  outEvent_.run.runNumber = _run.run();

  for (auto* filler : fillers_) {
    if (!filler->enabled())
      continue;

    try {
      if (printLevel_ >= 2)
        std::cout << "[PandaProducer::beginRun] "
          << "Calling " << filler->getName() << "->fillBeginRun()" << std::endl;

      filler->fillBeginRun(outEvent_.run, _run, _setup);
    }
    catch (std::exception& ex) {
      std::cerr << "[PandaProducer::beginRun] "
        << "Error in " << filler->getName() << "::fillBeginRun()" << std::endl;
      throw;
    }
  }
}

void
PandaProducer::endRun(edm::Run const& _run, edm::EventSetup const& _setup)
{
  for (auto* filler : fillers_) {
    if (!filler->enabled())
      continue;

    try {
      if (printLevel_ >= 2)
        std::cout << "[PandaProducer::endRun] "
          << "Calling " << filler->getName() << "->fillEndRun()" << std::endl;

      filler->fillEndRun(outEvent_.run, _run, _setup);
    }
    catch (std::exception& ex) {
      std::cerr << "[PandaProducer::endRun] "
        << "Error in " << filler->getName() << "::fillEndRun()" << std::endl;
      throw;
    }
  }

  outEvent_.run.fill(*runTree_);
}

void
PandaProducer::beginJob()
{
  outputFile_ = TFile::Open(outputName_.c_str(), "recreate");
  eventTree_ = new TTree("events", "");
  runTree_ = new TTree("runs", "");

  panda::utils::BranchList eventBranches = {"runNumber", "lumiNumber", "eventNumber", "isData"};
  panda::utils::BranchList runBranches = {"runNumber"};
  for (auto* filler : fillers_) {
    if (filler->enabled())
      filler->branchNames(eventBranches, runBranches);
  }

  outEvent_.book(*eventTree_, eventBranches);
  outEvent_.run.book(*runTree_, runBranches);

  for (auto* filler : fillers_) {
    filler->addOutput(*outputFile_);
  }

  if (useTrigger_ && outputFile_->Get("hlt")) {
    outEvent_.run.hlt.create();
    auto& hltTree(*static_cast<TTree*>(outputFile_->Get("hlt")));
    hltTree.Branch("menu", "TString", &outEvent_.run.hlt.menu);
    hltTree.Branch("paths", "std::vector<TString>", &outEvent_.run.hlt.paths, 32000, 0);
  }

  eventCounter_ = new TH1D("eventcounter", "", 2, 0., 2.);
  eventCounter_->SetDirectory(outputFile_);
  eventCounter_->GetXaxis()->SetBinLabel(1, "all");
  eventCounter_->GetXaxis()->SetBinLabel(2, "selected");
}

void
PandaProducer::endJob()
{
  // writes out all outputs that are still hanging in the directory
  outputFile_->cd();
  outputFile_->Write();
  delete outputFile_;

  if (printLevel_ >= 1) {
    std::cout << "[PandaProducer::endJob] Timer summary" << std::endl;
    for (unsigned iF(0); iF != fillers_.size(); ++iF) {
      std::cout << " " << fillers_[iF]->getName() << "  ";
      double time(toMS(timers_[iF]));
      if (time > 10000.)
        std::cout << std::fixed << std::setprecision(5) << time / nEvents_ / 1000. << " s/evt";
      else
        std::cout << time / nEvents_ << " ms/evt";
      std::cout << std::endl;
    }
    std::cout << " Other CMSSW  ";
    double time(toMS(timers_.back()));
    if (time > 10000.)
      std::cout << std::fixed << std::setprecision(5) << time / nEvents_ / 1000. << " s/evt";
    else
      std::cout << time / nEvents_ << " ms/evt";
    std::cout << std::endl;
  }
}

DEFINE_FWK_MODULE(PandaProducer);
<commit_msg>switching s and ms was a bad idea<commit_after>#include "FWCore/Framework/interface/Frameworkfwd.h"
#include "FWCore/Framework/interface/EDAnalyzer.h"
#include "FWCore/Framework/interface/Event.h"
#include "FWCore/Framework/interface/Run.h"
#include "FWCore/Framework/interface/MakerMacros.h"
#include "FWCore/Utilities/interface/InputTag.h"
#include "FWCore/Common/interface/TriggerNames.h"
#include "DataFormats/Common/interface/TriggerResults.h"
#include "DataFormats/Common/interface/Handle.h"
#include "DataFormats/PatCandidates/interface/TriggerObjectStandAlone.h"

#include "PandaTree/Objects/interface/Event.h"

#include "../interface/FillerBase.h"
#include "../interface/ObjectMap.h"

#include "TFile.h"
#include "TTree.h"
#include "TH1D.h"
#include <vector>
#include <utility>
#include <chrono>

typedef std::chrono::steady_clock SClock;
double toMS(SClock::duration const& interval)
{
  return std::chrono::duration_cast<std::chrono::nanoseconds>(interval).count() * 1.e-6;
}

class PandaProducer : public edm::EDAnalyzer {
public:
  explicit PandaProducer(edm::ParameterSet const&);
  ~PandaProducer();

private:
  typedef edm::View<pat::TriggerObjectStandAlone> TriggerObjectView;

  void analyze(edm::Event const&, edm::EventSetup const&) override;
  void beginRun(edm::Run const&, edm::EventSetup const&) override;
  void endRun(edm::Run const&, edm::EventSetup const&) override;
  void beginJob() override;
  void endJob() override;

  std::vector<FillerBase*> fillers_;
  ObjectMapStore objectMaps_;

  VString selectEvents_;
  edm::EDGetTokenT<edm::TriggerResults> skimResultsToken_;
  edm::EDGetTokenT<edm::TriggerResults> hltResultsToken_;
  edm::EDGetTokenT<TriggerObjectView> triggerObjectsToken_;

  TFile* outputFile_{0};
  TTree* eventTree_{0};
  TTree* runTree_{0};
  TH1D* eventCounter_{0};
  panda::Event outEvent_;

  std::string outputName_;
  bool useTrigger_;
  // [[filter0, filter1, ...], ...] outer index runs over trigger objects
  std::vector<VString> triggerObjectNames_;
  unsigned printLevel_;

  std::vector<SClock::duration> timers_;
  SClock::time_point lastAnalyze_; //! Time point of last return from analyze()
  unsigned long long nEvents_;
};

PandaProducer::PandaProducer(edm::ParameterSet const& _cfg) :
  selectEvents_(_cfg.getUntrackedParameter<VString>("SelectEvents")),
  skimResultsToken_(consumes<edm::TriggerResults>(edm::InputTag("TriggerResults"))), // no process name -> pick up the trigger results from the current process
  outputName_(_cfg.getUntrackedParameter<std::string>("outputFile", "panda.root")),
  useTrigger_(_cfg.getUntrackedParameter<bool>("useTrigger", true)),
  printLevel_(_cfg.getUntrackedParameter<unsigned>("printLevel", 0)),
  timers_(),
  lastAnalyze_(),
  nEvents_(0)
{
  auto&& coll(consumesCollector());

  auto& fillersCfg(_cfg.getUntrackedParameterSet("fillers"));

  SClock::time_point start;

  for (auto& fillerName : fillersCfg.getParameterNames()) {
    if (fillerName == "common")
      continue;

    auto& fillerPSet(fillersCfg.getUntrackedParameterSet(fillerName));
    try {
      auto className(fillerPSet.getUntrackedParameter<std::string>("filler") + "Filler");

      if (printLevel_ >= 1) {
        std::cout << "[PandaProducer::PandaProducer] "
          << "Constructing " << className << "::" << fillerName << std::endl;

        if (printLevel_ >= 3)
          start = SClock::now();
      }

      auto* filler(FillerFactoryStore::singleton()->makeFiller(className, fillerName, _cfg, coll));
      fillers_.push_back(filler);

      if (filler->enabled())
        filler->setObjectMap(objectMaps_[fillerName]);

      if (printLevel_ >= 1) {
        timers_.push_back(SClock::duration::zero());

        if (printLevel_ >= 3)
          std::cout << "Initializing " << fillerName << " took " << toMS(SClock::now() - start) << " ms." << std::endl;
      }
    }
    catch (std::exception& ex) {
      std::cerr << "[PandaProducer::PandaProducer] "
        << "Configuration error in " << fillerName << ":"
                                     << ex.what() << std::endl;
      throw;
    }
  }

  if (useTrigger_) {
    hltResultsToken_ = consumes<edm::TriggerResults>(edm::InputTag("TriggerResults", "", "HLT"));
    triggerObjectsToken_ = consumes<TriggerObjectView>(edm::InputTag(fillersCfg.getUntrackedParameterSet("common").getUntrackedParameter<std::string>("triggerObjects")));
  }

  if (printLevel_ >= 1) {
    // timer for the CMSSW execution outside of this module
    timers_.push_back(SClock::duration::zero());
  }
}

PandaProducer::~PandaProducer()
{
  for (auto* filler : fillers_)
    delete filler;
}

void
PandaProducer::analyze(edm::Event const& _event, edm::EventSetup const& _setup)
{
  eventCounter_->Fill(0.5);

  if (printLevel_ >= 1) {
    if (nEvents_ == 0) {
      if (printLevel_ >= 3)
        std::cout << "[PandaProducer::analyze] "
                  << "First event; CMSSW step time unknown" << std::endl;

    }
    else {
      auto dt(SClock::now() - lastAnalyze_);
      if (printLevel_ >= 3)
        std::cout << "[PandaProducer::analyze] "
                  << "Previous (CMSSW) step took " << toMS(dt) << " ms" << std::endl;

      timers_.back() += dt;
    }
  }

  ++nEvents_;

  SClock::time_point start;

  // Fill "all events" information
  for (unsigned iF(0); iF != fillers_.size(); ++iF) {
    auto* filler(fillers_[iF]);

    if (!filler->enabled())
      continue;

    try {
      if (printLevel_ >= 1) {
        start = SClock::now();

        if (printLevel_ >= 2)
          std::cout << "[PandaProducer::analyze] "
                    << "Calling " << filler->getName() << "->fillAll()" << std::endl;
      }

      filler->fillAll(_event, _setup);

      if (printLevel_ >= 1) {
        auto dt(SClock::now() - start);

        if (printLevel_ >= 3) {
          std::cout << "[PandaProducer::analyze] "
                    << "Step " << filler->getName() << "->fillAll() took " << toMS(dt) << " ms" << std::endl;
        }

        timers_[iF] += dt;
      }
    }
    catch (std::exception& ex) {
      std::cerr << "[PandaProducer::analyze] "
        << "Error in " << filler->getName() << "::fillAll()" << std::endl;
      throw;
    }
  }

  // If path names are given, check if at least one succeeded
  if (selectEvents_.size() != 0) {
    edm::Handle<edm::TriggerResults> triggerResults;
    if(_event.getByToken(skimResultsToken_, triggerResults)){
      auto& pathNames(_event.triggerNames(*triggerResults));
      unsigned iS(0);
      for (; iS != selectEvents_.size(); ++iS) {
        unsigned iP(pathNames.triggerIndex(selectEvents_[iS]));
        if (iP != pathNames.size() && triggerResults->accept(iP))
          break;
      }
      if (iS == selectEvents_.size())
        return;
    }
  }

  eventCounter_->Fill(1.5);

  // Now fill the event
  outEvent_.init();

  for (auto& mm : objectMaps_)
    mm.second.clearMaps();

  if (useTrigger_) {
    // Unpack trigger object names
    edm::Handle<edm::TriggerResults> triggerResultsHandle;
    _event.getByToken(hltResultsToken_, triggerResultsHandle);
    auto& triggerNames(_event.triggerNames(*triggerResultsHandle));

    edm::Handle<TriggerObjectView> triggerObjectsHandle;
    _event.getByToken(triggerObjectsToken_, triggerObjectsHandle);
    auto& triggerObjects(*triggerObjectsHandle);

    auto& objMap(objectMaps_["global"].get<pat::TriggerObjectStandAlone, VString>());
    triggerObjectNames_.assign(triggerObjects.size(), VString());

    unsigned iObj(0);
    for (auto& obj : triggerObjects) {
      // need to create a copy to perform the non-const action of unpacking
      pat::TriggerObjectStandAlone copy(obj);
      copy.unpackPathNames(triggerNames);

      for (auto& label : obj.filterLabels())
        triggerObjectNames_[iObj].push_back(label);

      // link the pat trigger object to the list of labels
      objMap.add(triggerObjects.ptrAt(iObj), triggerObjectNames_[iObj]);
      ++iObj;
    }
  }

  outEvent_.runNumber = _event.id().run();
  outEvent_.lumiNumber = _event.luminosityBlock();
  outEvent_.eventNumber = _event.id().event();
  outEvent_.isData = _event.isRealData();

  for (unsigned iF(0); iF != fillers_.size(); ++iF) {
    auto* filler(fillers_[iF]);

    if (!filler->enabled())
      continue;

    try {
      if (printLevel_ >= 1) {
        if (printLevel_ >= 2)
          std::cout << "[PandaProducer::fill] "
                    << "Calling " << filler->getName() << "->fill()" << std::endl;

        start = SClock::now();
      }

      filler->fill(outEvent_, _event, _setup);

      if (printLevel_ >= 1) {
        auto dt(SClock::now() - start);

        if (printLevel_ >= 3)
          std::cout << "[PandaProducer::analyze] "
                    << "Step " << filler->getName() << "->fill() took " << toMS(dt) << " ms" << std::endl;

        timers_[iF] += dt;
      }
    }
    catch (std::exception& ex) {
      std::cerr << "[PandaProducer::fill] "
        << "Error in " << filler->getName() << "::fill()" << std::endl;
      throw;
    }
  }

  // Set inter-branch references
  for (unsigned iF(0); iF != fillers_.size(); ++iF) {
    auto* filler(fillers_[iF]);

    if (!filler->enabled())
      continue;

    try {
      if (printLevel_ >= 1) {
        if (printLevel_ >= 2)
          std::cout << "[PandaProducer:fill] "
                    << "Calling " << filler->getName() << "->setRefs()" << std::endl;

        start = SClock::now();
      }

      filler->setRefs(objectMaps_);

      if (printLevel_ >= 1) {
        auto dt(SClock::now() - start);

        if (printLevel_ >= 3)
          std::cout << "[PandaProducer::analyze] "
                    << "Step " << filler->getName() << "->setRefs() took " << toMS(dt) << " ms" << std::endl;

        timers_[iF] += dt;
      }
    }
    catch (std::exception& ex) {
      std::cerr << "[PandaProducer:fill] "
        << "Error in " << filler->getName() << "::setRefs()" << std::endl;
      throw;
    }
  }

  outEvent_.fill(*eventTree_);

  lastAnalyze_ = SClock::now();
}

void
PandaProducer::beginRun(edm::Run const& _run, edm::EventSetup const& _setup)
{
  outEvent_.run.init();

  outEvent_.run.runNumber = _run.run();

  for (auto* filler : fillers_) {
    if (!filler->enabled())
      continue;

    try {
      if (printLevel_ >= 2)
        std::cout << "[PandaProducer::beginRun] "
          << "Calling " << filler->getName() << "->fillBeginRun()" << std::endl;

      filler->fillBeginRun(outEvent_.run, _run, _setup);
    }
    catch (std::exception& ex) {
      std::cerr << "[PandaProducer::beginRun] "
        << "Error in " << filler->getName() << "::fillBeginRun()" << std::endl;
      throw;
    }
  }
}

void
PandaProducer::endRun(edm::Run const& _run, edm::EventSetup const& _setup)
{
  for (auto* filler : fillers_) {
    if (!filler->enabled())
      continue;

    try {
      if (printLevel_ >= 2)
        std::cout << "[PandaProducer::endRun] "
          << "Calling " << filler->getName() << "->fillEndRun()" << std::endl;

      filler->fillEndRun(outEvent_.run, _run, _setup);
    }
    catch (std::exception& ex) {
      std::cerr << "[PandaProducer::endRun] "
        << "Error in " << filler->getName() << "::fillEndRun()" << std::endl;
      throw;
    }
  }

  outEvent_.run.fill(*runTree_);
}

void
PandaProducer::beginJob()
{
  outputFile_ = TFile::Open(outputName_.c_str(), "recreate");
  eventTree_ = new TTree("events", "");
  runTree_ = new TTree("runs", "");

  panda::utils::BranchList eventBranches = {"runNumber", "lumiNumber", "eventNumber", "isData"};
  panda::utils::BranchList runBranches = {"runNumber"};
  for (auto* filler : fillers_) {
    if (filler->enabled())
      filler->branchNames(eventBranches, runBranches);
  }

  outEvent_.book(*eventTree_, eventBranches);
  outEvent_.run.book(*runTree_, runBranches);

  for (auto* filler : fillers_) {
    filler->addOutput(*outputFile_);
  }

  if (useTrigger_ && outputFile_->Get("hlt")) {
    outEvent_.run.hlt.create();
    auto& hltTree(*static_cast<TTree*>(outputFile_->Get("hlt")));
    hltTree.Branch("menu", "TString", &outEvent_.run.hlt.menu);
    hltTree.Branch("paths", "std::vector<TString>", &outEvent_.run.hlt.paths, 32000, 0);
  }

  eventCounter_ = new TH1D("eventcounter", "", 2, 0., 2.);
  eventCounter_->SetDirectory(outputFile_);
  eventCounter_->GetXaxis()->SetBinLabel(1, "all");
  eventCounter_->GetXaxis()->SetBinLabel(2, "selected");
}

void
PandaProducer::endJob()
{
  // writes out all outputs that are still hanging in the directory
  outputFile_->cd();
  outputFile_->Write();
  delete outputFile_;

  if (printLevel_ >= 1) {
    std::cout << "[PandaProducer::endJob] Timer summary" << std::endl;
    for (unsigned iF(0); iF != fillers_.size(); ++iF) {
      std::cout << " " << fillers_[iF]->getName() << "  "
                << std::fixed << std::setprecision(3) << toMS(timers_[iF]) / nEvents_ << " ms/evt"
                << std::endl;
    }
    std::cout << " Other CMSSW  "
              << std::fixed << std::setprecision(3) << toMS(timers_.back()) / nEvents_ << " ms/evt"
              << std::endl;
  }
}

DEFINE_FWK_MODULE(PandaProducer);
<|endoftext|>


<commit_before>// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.

#include "catch.hpp"
#include "mfem.hpp"
#include <fstream>
#include <iostream>

using namespace mfem;

namespace ea_kernels
{

void velocity_function(const Vector &x, Vector &v)
{
   int dim = x.Size();
   switch (dim)
   {
      case 1: v(0) = 1.0; break;
      case 2: v(0) = x(1); v(1) = -x(0); break;
      case 3: v(0) = x(1); v(1) = -x(0); v(2) = x(0); break;
   }
}

void AddConvectionIntegrators(BilinearForm &k, VectorCoefficient &velocity,
                              bool dg)
{
   k.AddDomainIntegrator(new ConvectionIntegrator(velocity, -1.0));

   if (dg)
   {
      k.AddInteriorFaceIntegrator(
         new TransposeIntegrator(new DGTraceIntegrator(velocity, 1.0, -0.5)));
      k.AddBdrFaceIntegrator(
         new TransposeIntegrator(new DGTraceIntegrator(velocity, 1.0, -0.5)));
   }
}

void test_assembly_level(Mesh &&mesh, int order, bool dg, const int pb,
                         const AssemblyLevel assembly)
{
   mesh.EnsureNodes();
   mesh.SetCurvature(mesh.GetNodalFESpace()->GetOrder(0));
   int dim = mesh.Dimension();

   FiniteElementCollection *fec;
   if (dg)
   {
      fec = new L2_FECollection(order, dim, BasisType::GaussLobatto);
   }
   else
   {
      fec = new H1_FECollection(order, dim);
   }

   FiniteElementSpace fespace(&mesh, fec);

   BilinearForm k_test(&fespace);
   BilinearForm k_ref(&fespace);

   ConstantCoefficient one(1.0);
   VectorFunctionCoefficient vel_coeff(dim, velocity_function);

   if (pb==0) // Mass
   {
      k_ref.AddDomainIntegrator(new MassIntegrator(one));
      k_test.AddDomainIntegrator(new MassIntegrator(one));
   }
   else if (pb==1) // Convection
   {
      AddConvectionIntegrators(k_ref, vel_coeff, dg);
      AddConvectionIntegrators(k_test, vel_coeff, dg);
   }
   else if (pb==2) // Diffusion
   {
      k_ref.AddDomainIntegrator(new DiffusionIntegrator(one));
      k_test.AddDomainIntegrator(new DiffusionIntegrator(one));
   }

   k_ref.Assemble();
   k_ref.Finalize();

   k_test.SetAssemblyLevel(assembly);
   k_test.Assemble();

   GridFunction x(&fespace), y_ref(&fespace), y_test(&fespace);

   x.Randomize(1);

   k_ref.Mult(x,y_ref);
   k_test.Mult(x,y_test);

   y_test -= y_ref;

   REQUIRE(y_test.Norml2() < 1.e-12);

   delete fec;
}

TEST_CASE("Assembly Levels", "[AssemblyLevel]")
{
   for (AssemblyLevel assembly : {AssemblyLevel::PARTIAL,AssemblyLevel::ELEMENT,AssemblyLevel::FULL})
   {
      for (int pb : {0, 1, 2})
      {
         for (bool dg : {true, false})
         {
            SECTION("2D")
            {
               for (int order : {2, 3, 4})
               {
                  test_assembly_level(Mesh("../../data/periodic-square.mesh", 1, 1),
                                      order, dg, pb, assembly);
                  test_assembly_level(Mesh("../../data/periodic-hexagon.mesh", 1, 1),
                                      order, dg, pb, assembly);
                  test_assembly_level(Mesh("../../data/star-q3.mesh", 1, 1),
                                      order, dg, pb, assembly);
               }
            }

            SECTION("3D")
            {
               int order = 2;
               test_assembly_level(Mesh("../../data/periodic-cube.mesh", 1, 1),
                                   order, dg, pb, assembly);
               test_assembly_level(Mesh("../../data/fichera-q3.mesh", 1, 1),
                                   order, dg, pb, assembly);
            }
         }

         // Test AMR cases (DG not implemented)
         SECTION("AMR 2D")
         {
            for (int order : {2, 3, 4})
            {
               test_assembly_level(Mesh("../../data/amr-quad.mesh", 1, 1),
                                   order, false, 0, assembly);
            }
         }
         SECTION("AMR 3D")
         {
            int order = 2;
            test_assembly_level(Mesh("../../data/fichera-amr.mesh", 1, 1),
                                order, false, 0, assembly);
         }
      }
   }
} // test case

} // namespace pa_kernels
<commit_msg>Fix testing of assembly levels.<commit_after>// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.

#include "catch.hpp"
#include "mfem.hpp"
#include <fstream>
#include <iostream>

using namespace mfem;

namespace ea_kernels
{

void velocity_function(const Vector &x, Vector &v)
{
   int dim = x.Size();
   switch (dim)
   {
      case 1: v(0) = 1.0; break;
      case 2: v(0) = x(1); v(1) = -x(0); break;
      case 3: v(0) = x(1); v(1) = -x(0); v(2) = x(0); break;
   }
}

void AddConvectionIntegrators(BilinearForm &k, VectorCoefficient &velocity,
                              bool dg)
{
   k.AddDomainIntegrator(new ConvectionIntegrator(velocity, -1.0));

   if (dg)
   {
      k.AddInteriorFaceIntegrator(
         new TransposeIntegrator(new DGTraceIntegrator(velocity, 1.0, -0.5)));
      k.AddBdrFaceIntegrator(
         new TransposeIntegrator(new DGTraceIntegrator(velocity, 1.0, -0.5)));
   }
}

void test_assembly_level(Mesh &&mesh, int order, bool dg, const int pb,
                         const AssemblyLevel assembly)
{
   mesh.EnsureNodes();
   mesh.SetCurvature(mesh.GetNodalFESpace()->GetOrder(0),
                     mesh.GetNodalFESpace()->IsDGSpace());
   int dim = mesh.Dimension();

   FiniteElementCollection *fec;
   if (dg)
   {
      fec = new L2_FECollection(order, dim, BasisType::GaussLobatto);
   }
   else
   {
      fec = new H1_FECollection(order, dim);
   }

   FiniteElementSpace fespace(&mesh, fec);

   BilinearForm k_test(&fespace);
   BilinearForm k_ref(&fespace);

   ConstantCoefficient one(1.0);
   VectorFunctionCoefficient vel_coeff(dim, velocity_function);

   if (pb==0) // Mass
   {
      k_ref.AddDomainIntegrator(new MassIntegrator(one));
      k_test.AddDomainIntegrator(new MassIntegrator(one));
   }
   else if (pb==1) // Convection
   {
      AddConvectionIntegrators(k_ref, vel_coeff, dg);
      AddConvectionIntegrators(k_test, vel_coeff, dg);
   }
   else if (pb==2) // Diffusion
   {
      k_ref.AddDomainIntegrator(new DiffusionIntegrator(one));
      k_test.AddDomainIntegrator(new DiffusionIntegrator(one));
   }

   k_ref.Assemble();
   k_ref.Finalize();

   k_test.SetAssemblyLevel(assembly);
   k_test.Assemble();

   GridFunction x(&fespace), y_ref(&fespace), y_test(&fespace);

   x.Randomize(1);

   k_ref.Mult(x,y_ref);
   k_test.Mult(x,y_test);

   y_test -= y_ref;

   REQUIRE(y_test.Norml2() < 1.e-12);

   delete fec;
}

TEST_CASE("Assembly Levels", "[AssemblyLevel]")
{
   SECTION("Continuous Galerkin")
   {
      const bool dg = false;
      SECTION("2D")
      {
         for (AssemblyLevel assembly : {AssemblyLevel::PARTIAL,AssemblyLevel::ELEMENT,AssemblyLevel::FULL})
         {
            for (int pb : {0, 1, 2})
            {
               for (int order : {2, 3, 4})
               {
                  test_assembly_level(Mesh("../../data/inline-quad.mesh", 1, 1),
                                       order, dg, pb, assembly);
                  test_assembly_level(Mesh("../../data/periodic-hexagon.mesh", 1, 1),
                                       order, dg, pb, assembly);
                  test_assembly_level(Mesh("../../data/star-q3.mesh", 1, 1),
                                       order, dg, pb, assembly);
               }
            }
         }
      }
      SECTION("3D")
      {
         for (AssemblyLevel assembly : {AssemblyLevel::PARTIAL,AssemblyLevel::ELEMENT,AssemblyLevel::FULL})
         {
            for (int pb : {0, 1, 2})
            {
               int order = 2;
               test_assembly_level(Mesh("../../data/inline-hex.mesh", 1, 1),
                                    order, dg, pb, assembly);
               test_assembly_level(Mesh("../../data/fichera-q3.mesh", 1, 1),
                                    order, dg, pb, assembly);
            }
         }
      }
      SECTION("AMR 2D")
      {
         for (AssemblyLevel assembly : {AssemblyLevel::PARTIAL,AssemblyLevel::ELEMENT,AssemblyLevel::FULL})
         {
            for (int pb : {0, 1, 2})
            {
               for (int order : {2, 3, 4})
               {
                  test_assembly_level(Mesh("../../data/amr-quad.mesh", 1, 1),
                                       order, false, 0, assembly);
               }
            }
         }
      }
      SECTION("AMR 3D")
      {
         for (AssemblyLevel assembly : {AssemblyLevel::PARTIAL,AssemblyLevel::ELEMENT,AssemblyLevel::FULL})
         {
            for (int pb : {0, 1, 2})
            {
               int order = 2;
               test_assembly_level(Mesh("../../data/fichera-amr.mesh", 1, 1),
                                    order, false, 0, assembly);
            }
         }
      }
   }

   SECTION("Discontinuous Galerkin")
   {
      const bool dg = true;
      SECTION("2D")
      {
         for (AssemblyLevel assembly : {AssemblyLevel::PARTIAL,AssemblyLevel::ELEMENT,AssemblyLevel::FULL})
         {
            for (int pb : {0, 1})
            {
               for (int order : {2, 3, 4})
               {
                  test_assembly_level(Mesh("../../data/periodic-square.mesh", 1, 1),
                                       order, dg, pb, assembly);
                  test_assembly_level(Mesh("../../data/periodic-hexagon.mesh", 1, 1),
                                       order, dg, pb, assembly);
                  test_assembly_level(Mesh("../../data/star-q3.mesh", 1, 1),
                                       order, dg, pb, assembly);
               }
            }
         }
      }
      SECTION("3D")
      {
         for (AssemblyLevel assembly : {AssemblyLevel::PARTIAL,AssemblyLevel::ELEMENT,AssemblyLevel::FULL})
         {
            for (int pb : {0, 1})
            {
               for (bool dg : {true, false})
               {
                  int order = 2;
                  test_assembly_level(Mesh("../../data/periodic-cube.mesh", 1, 1),
                                       order, dg, pb, assembly);
                  test_assembly_level(Mesh("../../data/fichera-q3.mesh", 1, 1),
                                       order, dg, pb, assembly);
               }
            }
         }
      }
   }
} // test case

} // namespace pa_kernels
<|endoftext|>


<commit_before>/****************************************************************/
/*               DO NOT MODIFY THIS HEADER                      */
/* MOOSE - Multiphysics Object Oriented Simulation Environment  */
/*                                                              */
/*           (c) 2010 Battelle Energy Alliance, LLC             */
/*                   ALL RIGHTS RESERVED                        */
/*                                                              */
/*          Prepared by Battelle Energy Alliance, LLC           */
/*            Under Contract No. DE-AC07-05ID14517              */
/*            With the U. S. Department of Energy               */
/*                                                              */
/*            See COPYRIGHT for full restrictions               */
/****************************************************************/

#include "ReportableData.h"
#include "FEProblem.h"

ReportableData::ReportableData(FEProblem & fe_problem) :
    Restartable("values", "ReportableData", fe_problem),
    _names(declareRestartableData<std::vector<std::set<std::string> > >("reportable_names", std::vector<std::set<std::string> >(libMesh::n_threads(), std::set<std::string>()))),
    _output(declareRestartableData<std::map<std::string, bool> >("reportable_output"))
{
}

void
ReportableData::init(const std::string & name, Real value, THREAD_ID tid, bool output)
{
  // Check that the name was not already used
  if (hasReportableValue(name, tid))
    mooseError("A reportable value with the name " << name << " already exists");

  // Declare the data as restartable
  if (_values.find(name) == _values.end())
  {
    _values[name] = &declareRestartableDataWithObjectName<ReportableValue>(name, "reportable_values");
    _values_old[name] = &declareRestartableDataWithObjectName<ReportableValue>(name, "reportable_values_old");
  }

  // Set the values
  getReportableValue(name) = value;
  getReportableValueOld(name) = value;

  // Output the output flag
  _output.insert(std::pair<std::string, bool>(name, output));

  // Update the name storage
  _names[tid].insert(name);
}

bool
ReportableData::hasReportableValue(const std::string & name, THREAD_ID tid)
{
  // Return true if the supplied name was already defined on the thread
  return _names[tid].find(name) != _names[tid].end();
}

ReportableValue &
ReportableData::getReportableValue(const std::string & name)
{
  // If the stored value does not exists; create it, this allows getReportableValue to be called
  // without calling init
  if (_values.find(name) == _values.end())
    _values[name] = &declareRestartableDataWithObjectName<ReportableValue>(name, "reportable_values");

  return *_values[name];
}

ReportableValue &
ReportableData::getReportableValueOld(const std::string & name)
{
  if (_values.find(name) == _values.end())
    _values_old[name] = &declareRestartableDataWithObjectName<ReportableValue>(name, "reportable_values_old");

  return *_values_old[name];
}

void
ReportableData::storeValue(const std::string & name, Real value)
{
  if (hasReportableValue(name))
    getReportableValue(name) = value;
  else
    mooseError("A ReportableValue with the name " << name << " does not exist, must initialize first");
}

const std::map<std::string, ReportableValue*> &
ReportableData::values() const
{
  return _values;
}

void
ReportableData::copyValuesBack()
{
  _values_old = _values;
}

bool
ReportableData::valueOutput(std::string name)
{
  return _output[name];
}
<commit_msg>Fix ReportableData bug. Refs #2241<commit_after>/****************************************************************/
/*               DO NOT MODIFY THIS HEADER                      */
/* MOOSE - Multiphysics Object Oriented Simulation Environment  */
/*                                                              */
/*           (c) 2010 Battelle Energy Alliance, LLC             */
/*                   ALL RIGHTS RESERVED                        */
/*                                                              */
/*          Prepared by Battelle Energy Alliance, LLC           */
/*            Under Contract No. DE-AC07-05ID14517              */
/*            With the U. S. Department of Energy               */
/*                                                              */
/*            See COPYRIGHT for full restrictions               */
/****************************************************************/

#include "ReportableData.h"
#include "FEProblem.h"

ReportableData::ReportableData(FEProblem & fe_problem) :
    Restartable("values", "ReportableData", fe_problem),
    _names(declareRestartableData<std::vector<std::set<std::string> > >("reportable_names", std::vector<std::set<std::string> >(libMesh::n_threads(), std::set<std::string>()))),
    _output(declareRestartableData<std::map<std::string, bool> >("reportable_output"))
{
}

void
ReportableData::init(const std::string & name, Real value, THREAD_ID tid, bool output)
{
  // Check that the name was not already used
  if (hasReportableValue(name, tid))
    mooseError("A reportable value with the name " << name << " already exists");

  // Declare the data as restartable
  if (_values.find(name) == _values.end())
  {
    _values[name] = &declareRestartableDataWithObjectName<ReportableValue>(name, "reportable_values");
  }
  if (_values_old.find(name) == _values_old.end())
  {
    _values_old[name] = &declareRestartableDataWithObjectName<ReportableValue>(name, "reportable_values_old");
  }

  // Set the values
  getReportableValue(name) = value;
  getReportableValueOld(name) = value;

  // Output the output flag
  _output.insert(std::pair<std::string, bool>(name, output));

  // Update the name storage
  _names[tid].insert(name);
}

bool
ReportableData::hasReportableValue(const std::string & name, THREAD_ID tid)
{
  // Return true if the supplied name was already defined on the thread
  return _names[tid].find(name) != _names[tid].end();
}

ReportableValue &
ReportableData::getReportableValue(const std::string & name)
{
  // If the stored value does not exists; create it, this allows getReportableValue to be called
  // without calling init
  if (_values.find(name) == _values.end())
    _values[name] = &declareRestartableDataWithObjectName<ReportableValue>(name, "reportable_values");

  return *_values[name];
}

ReportableValue &
ReportableData::getReportableValueOld(const std::string & name)
{
  if (_values_old.find(name) == _values_old.end())
    _values_old[name] = &declareRestartableDataWithObjectName<ReportableValue>(name, "reportable_values_old");

  return *_values_old[name];
}

void
ReportableData::storeValue(const std::string & name, Real value)
{
  if (hasReportableValue(name))
    getReportableValue(name) = value;
  else
    mooseError("A ReportableValue with the name " << name << " does not exist, must initialize first");
}

const std::map<std::string, ReportableValue*> &
ReportableData::values() const
{
  return _values;
}

void
ReportableData::copyValuesBack()
{
  _values_old = _values;
}

bool
ReportableData::valueOutput(std::string name)
{
  return _output[name];
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014-2015 Advanced Micro Devices, Inc.
 * All rights reserved.
 *
 * For use for simulation and test purposes only
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its
 * contributors may be used to endorse or promote products derived from this
 * software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#define __STDC_FORMAT_MACROS
#include <cinttypes>
#include "debug/GPUCoalescer.hh"
#include "debug/GPUMem.hh"
#include "debug/GPUReg.hh"
#include "gpu-compute/compute_unit.hh"
#include "gpu-compute/global_memory_pipeline.hh"
#include "gpu-compute/gpu_dyn_inst.hh"
#include "gpu-compute/shader.hh"
#include "gpu-compute/vector_register_file.hh"
#include "gpu-compute/wavefront.hh"

GlobalMemPipeline::GlobalMemPipeline(const ComputeUnitParams* p) :
    computeUnit(nullptr), gmQueueSize(p->global_mem_queue_size),
    maxWaveRequests(p->max_wave_requests), inflightStores(0),
    inflightLoads(0)
{
}

void
GlobalMemPipeline::init(ComputeUnit *cu)
{
    computeUnit = cu;
    globalMemSize = computeUnit->shader->globalMemSize;
    _name = computeUnit->name() + ".GlobalMemPipeline";
}

bool
GlobalMemPipeline::coalescerReady(GPUDynInstPtr mp) const
{
    // We require one token from the coalescer's uncoalesced table to
    // proceed
    int token_count = 1;

    // Make sure the vector port has tokens. There is a single pool
    // of tokens so only one port in the vector port needs to be checked.
    // Lane 0 is chosen arbirarily.
    DPRINTF(GPUCoalescer, "Checking for %d tokens\n", token_count);
    if (!mp->computeUnit()->getTokenManager()->haveTokens(token_count)) {
        DPRINTF(GPUCoalescer, "Stalling inst because coalsr is busy!\n");
        return false;
    }

    return true;
}

void
GlobalMemPipeline::acqCoalescerToken(GPUDynInstPtr mp)
{
    // We require one token from the coalescer's uncoalesced table to
    // proceed
    int token_count = 1;

    DPRINTF(GPUCoalescer, "Acquiring %d token(s)\n", token_count);
    assert(mp->computeUnit()->getTokenManager()->haveTokens(token_count));
    mp->computeUnit()->getTokenManager()->acquireTokens(token_count);
}

bool
GlobalMemPipeline::outstandingReqsCheck(GPUDynInstPtr mp) const
{
    // Ensure we haven't exceeded the maximum number of vmem requests
    // for this wavefront
    if ((mp->wavefront()->outstandingReqsRdGm
         + mp->wavefront()->outstandingReqsWrGm) >= maxWaveRequests) {
        return false;
    }

    return true;
}

void
GlobalMemPipeline::exec()
{
    // apply any returned global memory operations
    GPUDynInstPtr m = getNextReadyResp();

    bool accessVrf = true;
    Wavefront *w = nullptr;

    // check the VRF to see if the operands of a load (or load component
    // of an atomic) are accessible
    if (m && (m->isLoad() || m->isAtomicRet())) {
        w = m->wavefront();

        accessVrf = w->computeUnit->vrf[w->simdId]->
            canScheduleWriteOperandsFromLoad(w, m);

    }

    if (m && m->latency.rdy() && computeUnit->glbMemToVrfBus.rdy() &&
        accessVrf && (computeUnit->shader->coissue_return ||
        computeUnit->vectorGlobalMemUnit.rdy())) {

        w = m->wavefront();

        DPRINTF(GPUMem, "CU%d: WF[%d][%d]: Completing global mem instr %s\n",
                m->cu_id, m->simdId, m->wfSlotId, m->disassemble());
        m->completeAcc(m);

        if (m->isLoad() || m->isAtomicRet()) {
            w->computeUnit->vrf[w->simdId]->
            scheduleWriteOperandsFromLoad(w, m);
        }

        completeRequest(m);

        Tick accessTime = curTick() - m->getAccessTime();

        // Decrement outstanding requests count
        computeUnit->shader->ScheduleAdd(&w->outstandingReqs, m->time, -1);
        if (m->isStore() || m->isAtomic() || m->isMemSync()) {
            computeUnit->shader->sampleStore(accessTime);
            computeUnit->shader->ScheduleAdd(&w->outstandingReqsWrGm,
                                             m->time, -1);
        }

        if (m->isLoad() || m->isAtomic() || m->isMemSync()) {
            computeUnit->shader->sampleLoad(accessTime);
            computeUnit->shader->ScheduleAdd(&w->outstandingReqsRdGm,
                                             m->time, -1);
        }

        w->validateRequestCounters();

        // Generate stats for round-trip time for vectory memory insts
        // going all the way to memory and stats for individual cache
        // blocks generated by the instruction.
        m->profileRoundTripTime(curTick(), InstMemoryHop::Complete);
        computeUnit->shader->sampleInstRoundTrip(m->getRoundTripTime());
        computeUnit->shader->sampleLineRoundTrip(m->getLineAddressTime());

        // Mark write bus busy for appropriate amount of time
        computeUnit->glbMemToVrfBus.set(m->time);
        if (!computeUnit->shader->coissue_return)
            w->computeUnit->vectorGlobalMemUnit.set(m->time);
    }

    // If pipeline has executed a global memory instruction
    // execute global memory packets and issue global
    // memory packets to DTLB
    if (!gmIssuedRequests.empty()) {
        GPUDynInstPtr mp = gmIssuedRequests.front();
        if (mp->isLoad() || mp->isAtomic()) {
            if (inflightLoads >= gmQueueSize) {
                return;
            } else {
                ++inflightLoads;
            }
        } else if (mp->isStore()) {
            if (inflightStores >= gmQueueSize) {
                return;
            } else {
                ++inflightStores;
            }
        }

        DPRINTF(GPUCoalescer, "initiateAcc for %s seqNum %d\n",
                mp->disassemble(), mp->seqNum());
        // Memfences will not return tokens and must be issued so we should
        // not request one as this will deplete the token count until deadlock
        if (!mp->isMemSync()) {
            assert(mp->computeUnit()->getTokenManager()->haveTokens(1));
            mp->computeUnit()->getTokenManager()->acquireTokens(1);
        }
        mp->initiateAcc(mp);

        if (((mp->isMemSync() && !mp->isEndOfKernel()) || !mp->isMemSync())) {
            /**
             * if we are not in out-of-order data delivery mode
             * then we keep the responses sorted in program order.
             * in order to do so we must reserve an entry in the
             * resp buffer before we issue the request to the mem
             * system. mem fence requests will not be stored here
             * because once they are issued from the GM pipeline,
             * they do not send any response back to it.
             */
            gmOrderedRespBuffer.insert(std::make_pair(mp->seqNum(),
                std::make_pair(mp, false)));
        }

        gmIssuedRequests.pop();

        DPRINTF(GPUMem, "CU%d: WF[%d][%d] Popping 0 mem_op = \n",
                computeUnit->cu_id, mp->simdId, mp->wfSlotId);
    }
}

GPUDynInstPtr
GlobalMemPipeline::getNextReadyResp()
{
    if (!gmOrderedRespBuffer.empty()) {
        auto mem_req = gmOrderedRespBuffer.begin();

        if (mem_req->second.second) {
            return mem_req->second.first;
        }
    }

    return nullptr;
}

void
GlobalMemPipeline::completeRequest(GPUDynInstPtr gpuDynInst)
{
    if (gpuDynInst->isLoad() || gpuDynInst->isAtomic()) {
        assert(inflightLoads > 0);
        --inflightLoads;
    } else if (gpuDynInst->isStore()) {
        assert(inflightStores > 0);
        --inflightStores;
    }

    // we should only pop the oldest requst, and it
    // should be marked as done if we are here
    assert(gmOrderedRespBuffer.begin()->first == gpuDynInst->seqNum());
    assert(gmOrderedRespBuffer.begin()->second.first == gpuDynInst);
    assert(gmOrderedRespBuffer.begin()->second.second);
    // remove this instruction from the buffer by its
    // unique seq ID
    gmOrderedRespBuffer.erase(gpuDynInst->seqNum());
}

void
GlobalMemPipeline::issueRequest(GPUDynInstPtr gpuDynInst)
{
    gpuDynInst->setAccessTime(curTick());
    gpuDynInst->profileRoundTripTime(curTick(), InstMemoryHop::Initiate);
    gmIssuedRequests.push(gpuDynInst);
}

void
GlobalMemPipeline::handleResponse(GPUDynInstPtr gpuDynInst)
{
    auto mem_req = gmOrderedRespBuffer.find(gpuDynInst->seqNum());
    // if we are getting a response for this mem request,
    // then it ought to already be in the ordered response
    // buffer
    assert(mem_req != gmOrderedRespBuffer.end());
    mem_req->second.second = true;
}

void
GlobalMemPipeline::regStats()
{
    loadVrfBankConflictCycles
        .name(name() + ".load_vrf_bank_conflict_cycles")
        .desc("total number of cycles GM data are delayed before updating "
              "the VRF")
        ;
}
<commit_msg>gpu-compute: remove recvToken from GM pipe exec<commit_after>/*
 * Copyright (c) 2014-2015 Advanced Micro Devices, Inc.
 * All rights reserved.
 *
 * For use for simulation and test purposes only
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its
 * contributors may be used to endorse or promote products derived from this
 * software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#define __STDC_FORMAT_MACROS
#include <cinttypes>
#include "debug/GPUCoalescer.hh"
#include "debug/GPUMem.hh"
#include "debug/GPUReg.hh"
#include "gpu-compute/compute_unit.hh"
#include "gpu-compute/global_memory_pipeline.hh"
#include "gpu-compute/gpu_dyn_inst.hh"
#include "gpu-compute/shader.hh"
#include "gpu-compute/vector_register_file.hh"
#include "gpu-compute/wavefront.hh"

GlobalMemPipeline::GlobalMemPipeline(const ComputeUnitParams* p) :
    computeUnit(nullptr), gmQueueSize(p->global_mem_queue_size),
    maxWaveRequests(p->max_wave_requests), inflightStores(0),
    inflightLoads(0)
{
}

void
GlobalMemPipeline::init(ComputeUnit *cu)
{
    computeUnit = cu;
    globalMemSize = computeUnit->shader->globalMemSize;
    _name = computeUnit->name() + ".GlobalMemPipeline";
}

bool
GlobalMemPipeline::coalescerReady(GPUDynInstPtr mp) const
{
    // We require one token from the coalescer's uncoalesced table to
    // proceed
    int token_count = 1;

    // Make sure the vector port has tokens. There is a single pool
    // of tokens so only one port in the vector port needs to be checked.
    // Lane 0 is chosen arbirarily.
    DPRINTF(GPUCoalescer, "Checking for %d tokens\n", token_count);
    if (!mp->computeUnit()->getTokenManager()->haveTokens(token_count)) {
        DPRINTF(GPUCoalescer, "Stalling inst because coalsr is busy!\n");
        return false;
    }

    return true;
}

void
GlobalMemPipeline::acqCoalescerToken(GPUDynInstPtr mp)
{
    // We require one token from the coalescer's uncoalesced table to
    // proceed
    int token_count = 1;

    DPRINTF(GPUCoalescer, "Acquiring %d token(s)\n", token_count);
    assert(mp->computeUnit()->getTokenManager()->haveTokens(token_count));
    mp->computeUnit()->getTokenManager()->acquireTokens(token_count);
}

bool
GlobalMemPipeline::outstandingReqsCheck(GPUDynInstPtr mp) const
{
    // Ensure we haven't exceeded the maximum number of vmem requests
    // for this wavefront
    if ((mp->wavefront()->outstandingReqsRdGm
         + mp->wavefront()->outstandingReqsWrGm) >= maxWaveRequests) {
        return false;
    }

    return true;
}

void
GlobalMemPipeline::exec()
{
    // apply any returned global memory operations
    GPUDynInstPtr m = getNextReadyResp();

    bool accessVrf = true;
    Wavefront *w = nullptr;

    // check the VRF to see if the operands of a load (or load component
    // of an atomic) are accessible
    if (m && (m->isLoad() || m->isAtomicRet())) {
        w = m->wavefront();

        accessVrf = w->computeUnit->vrf[w->simdId]->
            canScheduleWriteOperandsFromLoad(w, m);

    }

    if (m && m->latency.rdy() && computeUnit->glbMemToVrfBus.rdy() &&
        accessVrf && (computeUnit->shader->coissue_return ||
        computeUnit->vectorGlobalMemUnit.rdy())) {

        w = m->wavefront();

        DPRINTF(GPUMem, "CU%d: WF[%d][%d]: Completing global mem instr %s\n",
                m->cu_id, m->simdId, m->wfSlotId, m->disassemble());
        m->completeAcc(m);

        if (m->isLoad() || m->isAtomicRet()) {
            w->computeUnit->vrf[w->simdId]->
            scheduleWriteOperandsFromLoad(w, m);
        }

        completeRequest(m);

        Tick accessTime = curTick() - m->getAccessTime();

        // Decrement outstanding requests count
        computeUnit->shader->ScheduleAdd(&w->outstandingReqs, m->time, -1);
        if (m->isStore() || m->isAtomic() || m->isMemSync()) {
            computeUnit->shader->sampleStore(accessTime);
            computeUnit->shader->ScheduleAdd(&w->outstandingReqsWrGm,
                                             m->time, -1);
        }

        if (m->isLoad() || m->isAtomic() || m->isMemSync()) {
            computeUnit->shader->sampleLoad(accessTime);
            computeUnit->shader->ScheduleAdd(&w->outstandingReqsRdGm,
                                             m->time, -1);
        }

        w->validateRequestCounters();

        // Generate stats for round-trip time for vectory memory insts
        // going all the way to memory and stats for individual cache
        // blocks generated by the instruction.
        m->profileRoundTripTime(curTick(), InstMemoryHop::Complete);
        computeUnit->shader->sampleInstRoundTrip(m->getRoundTripTime());
        computeUnit->shader->sampleLineRoundTrip(m->getLineAddressTime());

        // Mark write bus busy for appropriate amount of time
        computeUnit->glbMemToVrfBus.set(m->time);
        if (!computeUnit->shader->coissue_return)
            w->computeUnit->vectorGlobalMemUnit.set(m->time);
    }

    // If pipeline has executed a global memory instruction
    // execute global memory packets and issue global
    // memory packets to DTLB
    if (!gmIssuedRequests.empty()) {
        GPUDynInstPtr mp = gmIssuedRequests.front();
        if (mp->isLoad() || mp->isAtomic()) {
            if (inflightLoads >= gmQueueSize) {
                return;
            } else {
                ++inflightLoads;
            }
        } else if (mp->isStore()) {
            if (inflightStores >= gmQueueSize) {
                return;
            } else {
                ++inflightStores;
            }
        }

        DPRINTF(GPUCoalescer, "initiateAcc for %s seqNum %d\n",
                mp->disassemble(), mp->seqNum());
        mp->initiateAcc(mp);

        if (((mp->isMemSync() && !mp->isEndOfKernel()) || !mp->isMemSync())) {
            /**
             * if we are not in out-of-order data delivery mode
             * then we keep the responses sorted in program order.
             * in order to do so we must reserve an entry in the
             * resp buffer before we issue the request to the mem
             * system. mem fence requests will not be stored here
             * because once they are issued from the GM pipeline,
             * they do not send any response back to it.
             */
            gmOrderedRespBuffer.insert(std::make_pair(mp->seqNum(),
                std::make_pair(mp, false)));
        }

        gmIssuedRequests.pop();

        DPRINTF(GPUMem, "CU%d: WF[%d][%d] Popping 0 mem_op = \n",
                computeUnit->cu_id, mp->simdId, mp->wfSlotId);
    }
}

GPUDynInstPtr
GlobalMemPipeline::getNextReadyResp()
{
    if (!gmOrderedRespBuffer.empty()) {
        auto mem_req = gmOrderedRespBuffer.begin();

        if (mem_req->second.second) {
            return mem_req->second.first;
        }
    }

    return nullptr;
}

void
GlobalMemPipeline::completeRequest(GPUDynInstPtr gpuDynInst)
{
    if (gpuDynInst->isLoad() || gpuDynInst->isAtomic()) {
        assert(inflightLoads > 0);
        --inflightLoads;
    } else if (gpuDynInst->isStore()) {
        assert(inflightStores > 0);
        --inflightStores;
    }

    // we should only pop the oldest requst, and it
    // should be marked as done if we are here
    assert(gmOrderedRespBuffer.begin()->first == gpuDynInst->seqNum());
    assert(gmOrderedRespBuffer.begin()->second.first == gpuDynInst);
    assert(gmOrderedRespBuffer.begin()->second.second);
    // remove this instruction from the buffer by its
    // unique seq ID
    gmOrderedRespBuffer.erase(gpuDynInst->seqNum());
}

void
GlobalMemPipeline::issueRequest(GPUDynInstPtr gpuDynInst)
{
    gpuDynInst->setAccessTime(curTick());
    gpuDynInst->profileRoundTripTime(curTick(), InstMemoryHop::Initiate);
    gmIssuedRequests.push(gpuDynInst);
}

void
GlobalMemPipeline::handleResponse(GPUDynInstPtr gpuDynInst)
{
    auto mem_req = gmOrderedRespBuffer.find(gpuDynInst->seqNum());
    // if we are getting a response for this mem request,
    // then it ought to already be in the ordered response
    // buffer
    assert(mem_req != gmOrderedRespBuffer.end());
    mem_req->second.second = true;
}

void
GlobalMemPipeline::regStats()
{
    loadVrfBankConflictCycles
        .name(name() + ".load_vrf_bank_conflict_cycles")
        .desc("total number of cycles GM data are delayed before updating "
              "the VRF")
        ;
}
<|endoftext|>