<commit_before>//===-- PPCBranchSelector.cpp - Emit long conditional branches-----*- C++ -*-=//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by Nate Baegeman and is distributed under the
// University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains a pass that scans a machine function to determine which
// conditional branches need more than 16 bits of displacement to reach their
// target basic block.  It does this in two passes; a calculation of basic block
// positions pass, and a branch psuedo op to machine branch opcode pass.  This
// pass should be run last, just before the assembly printer.
//
//===----------------------------------------------------------------------===//

#include "PPC.h"
#include "PPCInstrBuilder.h"
#include "PPCInstrInfo.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetAsmInfo.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/Compiler.h"
#include <map>
using namespace llvm;

static Statistic<> NumExpanded("ppc-branch-select",
                               "Num branches expanded to long format");

namespace {
  struct VISIBILITY_HIDDEN PPCBSel : public MachineFunctionPass {
    /// OffsetMap - Mapping between BB and byte offset from start of function.
    /// TODO: replace this with a vector, using the MBB idx as the key.
    std::map<MachineBasicBlock*, unsigned> OffsetMap;

    virtual bool runOnMachineFunction(MachineFunction &Fn);

    virtual const char *getPassName() const {
      return "PowerPC Branch Selection";
    }
  };
}

/// createPPCBranchSelectionPass - returns an instance of the Branch Selection
/// Pass
///
FunctionPass *llvm::createPPCBranchSelectionPass() {
  return new PPCBSel();
}

/// getNumBytesForInstruction - Return the number of bytes of code the specified
/// instruction may be.  This returns the maximum number of bytes.
///
static unsigned getNumBytesForInstruction(MachineInstr *MI) {
  switch (MI->getOpcode()) {
  case PPC::COND_BRANCH:
    // while this will be 4 most of the time, if we emit 8 it is just a
    // minor pessimization that saves us from having to worry about
    // keeping the offsets up to date later when we emit long branch glue.
    return 8;
  case PPC::IMPLICIT_DEF_GPRC: // no asm emitted
  case PPC::IMPLICIT_DEF_G8RC: // no asm emitted
  case PPC::IMPLICIT_DEF_F4:   // no asm emitted
  case PPC::IMPLICIT_DEF_F8:   // no asm emitted
  case PPC::IMPLICIT_DEF_VRRC: // no asm emitted
    return 0;
  case PPC::INLINEASM: {       // Inline Asm: Variable size.
    MachineFunction *MF = MI->getParent()->getParent();
    const char *AsmStr = MI->getOperand(0).getSymbolName();
    return MF->getTarget().getTargetAsmInfo()->getInlineAsmLength(AsmStr);
  }
  default:
    return 4; // PowerPC instructions are all 4 bytes
  }
}

bool PPCBSel::runOnMachineFunction(MachineFunction &Fn) {
  // Running total of instructions encountered since beginning of function
  unsigned ByteCount = 0;

  // For each MBB, add its offset to the offset map, and count up its
  // instructions
  for (MachineFunction::iterator MFI = Fn.begin(), E = Fn.end(); MFI != E;
       ++MFI) {
    MachineBasicBlock *MBB = MFI;
    OffsetMap[MBB] = ByteCount;

    for (MachineBasicBlock::iterator MBBI = MBB->begin(), EE = MBB->end();
         MBBI != EE; ++MBBI)
      ByteCount += getNumBytesForInstruction(MBBI);
  }

  // We're about to run over the MBB's again, so reset the ByteCount
  ByteCount = 0;

  // For each MBB, find the conditional branch pseudo instructions, and
  // calculate the difference between the target MBB and the current ICount
  // to decide whether or not to emit a short or long branch.
  //
  // short branch:
  // bCC .L_TARGET_MBB
  //
  // long branch:
  // bInverseCC $PC+8
  // b .L_TARGET_MBB
  for (MachineFunction::iterator MFI = Fn.begin(), E = Fn.end(); MFI != E;
       ++MFI) {
    MachineBasicBlock *MBB = MFI;

    for (MachineBasicBlock::iterator MBBI = MBB->begin(), EE = MBB->end();
         MBBI != EE; ++MBBI) {
      // We may end up deleting the MachineInstr that MBBI points to, so
      // remember its opcode now so we can refer to it after calling erase()
      unsigned ByteSize = getNumBytesForInstruction(MBBI);
      if (MBBI->getOpcode() != PPC::COND_BRANCH) {
        ByteCount += ByteSize;
        continue;
      }

      // condbranch operands:
      // 0. CR register
      // 1. PPC branch opcode
      // 2. Target MBB
      MachineBasicBlock *DestMBB = MBBI->getOperand(2).getMachineBasicBlock();
      unsigned Opcode = MBBI->getOperand(1).getImmedValue();
      unsigned CRReg = MBBI->getOperand(0).getReg();

      int Displacement = OffsetMap[DestMBB] - ByteCount;
      unsigned Inverted = PPCInstrInfo::invertPPCBranchOpcode(Opcode);

      MachineBasicBlock::iterator MBBJ;
      if (Displacement >= -32768 && Displacement <= 32767) {
        MBBJ = BuildMI(*MBB, MBBJ, Opcode, 2).addReg(CRReg).addMBB(DestMBB);
      } else {
        // Long branch, skip next branch instruction (i.e. $PC+8).
        ++NumExpanded;
        BuildMI(*MBB, MBBJ, Inverted, 2).addReg(CRReg).addImm(2);
        MBBJ = BuildMI(*MBB, MBBJ, PPC::B, 1).addMBB(DestMBB);
      }

      // Erase the psuedo COND_BRANCH instruction, and then back up the
      // iterator so that when the for loop increments it, we end up in
      // the correct place rather than iterating off the end.
      MBB->erase(MBBI);
      MBBI = MBBJ;
      ByteCount += ByteSize;
    }
  }

  OffsetMap.clear();
  return true;
}

<commit_msg>fix typo<commit_after>//===-- PPCBranchSelector.cpp - Emit long conditional branches-----*- C++ -*-=//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by Nate Baegeman and is distributed under the
// University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains a pass that scans a machine function to determine which
// conditional branches need more than 16 bits of displacement to reach their
// target basic block.  It does this in two passes; a calculation of basic block
// positions pass, and a branch psuedo op to machine branch opcode pass.  This
// pass should be run last, just before the assembly printer.
//
//===----------------------------------------------------------------------===//

#include "PPC.h"
#include "PPCInstrBuilder.h"
#include "PPCInstrInfo.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetAsmInfo.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/Compiler.h"
#include <map>
using namespace llvm;

static Statistic<> NumExpanded("ppc-branch-select",
                               "Num branches expanded to long format");

namespace {
  struct VISIBILITY_HIDDEN PPCBSel : public MachineFunctionPass {
    /// OffsetMap - Mapping between BB and byte offset from start of function.
    /// TODO: replace this with a vector, using the MBB idx as the key.
    std::map<MachineBasicBlock*, unsigned> OffsetMap;

    virtual bool runOnMachineFunction(MachineFunction &Fn);

    virtual const char *getPassName() const {
      return "PowerPC Branch Selection";
    }
  };
}

/// createPPCBranchSelectionPass - returns an instance of the Branch Selection
/// Pass
///
FunctionPass *llvm::createPPCBranchSelectionPass() {
  return new PPCBSel();
}

/// getNumBytesForInstruction - Return the number of bytes of code the specified
/// instruction may be.  This returns the maximum number of bytes.
///
static unsigned getNumBytesForInstruction(MachineInstr *MI) {
  switch (MI->getOpcode()) {
  case PPC::COND_BRANCH:
    // while this will be 4 most of the time, if we emit 8 it is just a
    // minor pessimization that saves us from having to worry about
    // keeping the offsets up to date later when we emit long branch glue.
    return 8;
  case PPC::IMPLICIT_DEF_GPRC: // no asm emitted
  case PPC::IMPLICIT_DEF_G8RC: // no asm emitted
  case PPC::IMPLICIT_DEF_F4:   // no asm emitted
  case PPC::IMPLICIT_DEF_F8:   // no asm emitted
  case PPC::IMPLICIT_DEF_VRRC: // no asm emitted
    return 0;
  case PPC::INLINEASM: {       // Inline Asm: Variable size.
    MachineFunction *MF = MI->getParent()->getParent();
    const char *AsmStr = MI->getOperand(0).getSymbolName();
    return MF->getTarget().getTargetAsmInfo()->getInlineAsmLength(AsmStr);
  }
  default:
    return 4; // PowerPC instructions are all 4 bytes
  }
}

bool PPCBSel::runOnMachineFunction(MachineFunction &Fn) {
  // Running total of instructions encountered since beginning of function
  unsigned ByteCount = 0;

  // For each MBB, add its offset to the offset map, and count up its
  // instructions
  for (MachineFunction::iterator MFI = Fn.begin(), E = Fn.end(); MFI != E;
       ++MFI) {
    MachineBasicBlock *MBB = MFI;
    OffsetMap[MBB] = ByteCount;

    for (MachineBasicBlock::iterator MBBI = MBB->begin(), EE = MBB->end();
         MBBI != EE; ++MBBI)
      ByteCount += getNumBytesForInstruction(MBBI);
  }

  // We're about to run over the MBB's again, so reset the ByteCount
  ByteCount = 0;

  // For each MBB, find the conditional branch pseudo instructions, and
  // calculate the difference between the target MBB and the current ICount
  // to decide whether or not to emit a short or long branch.
  //
  // short branch:
  // bCC .L_TARGET_MBB
  //
  // long branch:
  // bInverseCC $PC+8
  // b .L_TARGET_MBB
  for (MachineFunction::iterator MFI = Fn.begin(), E = Fn.end(); MFI != E;
       ++MFI) {
    MachineBasicBlock *MBB = MFI;

    for (MachineBasicBlock::iterator MBBI = MBB->begin(), EE = MBB->end();
         MBBI != EE; ++MBBI) {
      // We may end up deleting the MachineInstr that MBBI points to, so
      // remember its opcode now so we can refer to it after calling erase()
      unsigned ByteSize = getNumBytesForInstruction(MBBI);
      if (MBBI->getOpcode() != PPC::COND_BRANCH) {
        ByteCount += ByteSize;
        continue;
      }

      // condbranch operands:
      // 0. CR register
      // 1. PPC branch opcode
      // 2. Target MBB
      MachineBasicBlock *DestMBB = MBBI->getOperand(2).getMachineBasicBlock();
      unsigned Opcode = MBBI->getOperand(1).getImmedValue();
      unsigned CRReg = MBBI->getOperand(0).getReg();

      int Displacement = OffsetMap[DestMBB] - ByteCount;
      unsigned Inverted = PPCInstrInfo::invertPPCBranchOpcode(Opcode);

      MachineBasicBlock::iterator MBBJ;
      if (Displacement >= -32768 && Displacement <= 32767) {
        MBBJ = BuildMI(*MBB, MBBI, Opcode, 2).addReg(CRReg).addMBB(DestMBB);
      } else {
        // Long branch, skip next branch instruction (i.e. $PC+8).
        ++NumExpanded;
        BuildMI(*MBB, MBBJ, Inverted, 2).addReg(CRReg).addImm(2);
        MBBJ = BuildMI(*MBB, MBBI, PPC::B, 1).addMBB(DestMBB);
      }

      // Erase the psuedo COND_BRANCH instruction, and then back up the
      // iterator so that when the for loop increments it, we end up in
      // the correct place rather than iterating off the end.
      MBB->erase(MBBI);
      MBBI = MBBJ;
      ByteCount += ByteSize;
    }
  }

  OffsetMap.clear();
  return true;
}

<|endoftext|>


<commit_before>#include <stdint.h>
#include <ncurses.h>

#include "display/Screen.h"

Screen::Screen()
{
	initscr();
	clear();
	noecho();

	getmaxyx(stdscr, _height, _width);
}

Screen::~Screen()
{
	endwin();
}
<commit_msg>Make cursor invisible.<commit_after>#include <stdint.h>
#include <ncurses.h>

#include "display/Screen.h"

Screen::Screen()
{
	//Initialized the screen
	initscr();
	//Start with a clean slate
	clear();
	//Don't echo entered characters on the screen
	noecho();

	//Hide the cursor
	curs_set(false);

	//Get our height and width for later
	getmaxyx(stdscr, _height, _width);
}

Screen::~Screen()
{
	endwin();
}
<|endoftext|>


<commit_before>/* ---------------------------------------------------------------------
 * Numenta Platform for Intelligent Computing (NuPIC)
 * Copyright (C) 2013, Numenta, Inc.  Unless you have an agreement
 * with Numenta, Inc., for a separate license for this software code, the
 * following terms and conditions apply:
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see http://www.gnu.org/licenses.
 *
 * http://numenta.org/licenses/
 * ---------------------------------------------------------------------
 */

/** @file
 * Interface for the Network class
 */

#ifndef NTA_NETWORK_HPP
#define NTA_NETWORK_HPP

#include <map>
#include <string>
#include <vector>
#include <set>
#include <nta/types/types.hpp>
#include <nta/ntypes/Collection.hpp>

namespace nta
{

  class Region;
  class Dimensions;

  /**
   * A Network represents an HTM network. A network is a collection of regions.
   */
  class Network
  {
  public:

    /**
     * @name Construction and destruction
     * @{
     */

    /**
     *
     * Create an new Network and register it to NuPIC.
     *
     * @note Creating a Network will auto-initialize NuPIC.
     */
    Network();

    /**
     * Create a Network by loading previously saved bundle,
     * and register it to NuPIC.
     *
     * @param path The path to the previously saved bundle file, currently only
     * support files with `.nta` extension.
     *
     * @note Creating a Network will auto-initialize NuPIC.
     */
    Network(const std::string& path);

    /**
     * Destructor.
     *
     * Destruct the network and unregister it from NuPIC:
     *
     * - Uninitialize all regions
     * - Remove all links
     * - Delete the regions themselves
     *
     * @todo Should we document the tear down steps above?
     */
    ~Network();

    /**
     * Initialize all elements of a network so that it can run.
     *
     * @note This can be called after the Network structure has been set and
     * before Network.run(). However, if you don't call it, Network.run() will
     * call it for you. Also sets up various memory buffers etc. once the Network
     *  structure has been finalized.
     */
    void
    initialize();

    /**
     * @}
     *
     * @name Serialization
     *
     * @{
     */

    /**
     * Save the network to a network bundle (extension `.nta`).
     *
     * @param name
     *        Name of the bundle
     */
    void save(const std::string& name);

    /**
     * @}
     *
     * @name Region and Link operations
     *
     * @{
     */

    /**
     * Create a new region in a network.
     *
     * @param name
     *        Name of the region, Must be unique in the network
     * @param nodeType
     *        Type of node in the region, e.g. "FDRNode"
     * @param nodeParams
     *        A JSON-encoded string specifying writable params
     *
     * @returns A pointer to the newly created Region
     */
    Region*
    addRegion(const std::string& name,
              const std::string& nodeType,
              const std::string& nodeParams);

    /**
     * Create a new region from saved state.
     *
     * @param name
     *        Name of the region, Must be unique in the network
     * @param nodeType
     *        Type of node in the region, e.g. "FDRNode"
     * @param dimensions
     *        Dimensions of the region
     * @param bundlePath
     *        The path to the bundle
     * @param label
     *        The label of the bundle
     *
     * @todo @a label is the prefix of filename of the saved bundle, should this
     * be documented?
     *
     * @returns A pointer to the newly created Region
     */
    Region*
    addRegionFromBundle(const std::string& name,
                        const std::string& nodeType,
                        const Dimensions& dimensions,
                        const std::string& bundlePath,
                        const std::string& label);

    /**
     * Removes a new region from the network.
     *
     * @param name
     *        Name of the Region
     */
    void
    removeRegion(const std::string& name);

    /**
     * Create a link and add it to the network.
     *
     * @param srcName
     *        Name of the source region
     * @param destName
     *        Name of the destination region
     * @param linkType
     *        Type of the link
     * @param linkParams
     *        Parameters of the link
     * @param srcOutput
     *        Name of the source output
     * @param destInput
     *        Name of the destination input
     */
    void
    link(const std::string& srcName, const std::string& destName,
         const std::string& linkType, const std::string& linkParams,
         const std::string& srcOutput="", const std::string& destInput="");

    /**
     * Removes a link.
     *
     * @param srcName
     *        Name of the source region
     * @param destName
     *        Name of the destination region
     * @param srcOutputName
     *        Name of the source output
     * @param destInputName
     *        Name of the destination input
     */
    void
    removeLink(const std::string& srcName, const std::string& destName,
               const std::string& srcOutputName="", const std::string& destInputName="");

    /**
     * @}
     *
     * @name Access to components
     *
     * @{
     */

    /**
     * Get all regions.
     *
     * @returns A Collection of Region objects in the network
     */
    const Collection<Region*>&
    getRegions() const;

    /**
     * Set phases for a region.
     *
     * @param name
     *        Name of the region
     * @param phases
     *        A tuple of phases (must be positive integers)
     */
    void
    setPhases(const std::string& name, std::set<UInt32>& phases);

    /**
     * Get phases for a region.
     *
     * @param name
     *        Name of the region
     *
     * @returns Set of phases for the region
     */
    std::set<UInt32>
    getPhases(const std::string& name) const;

    /**
     * Get minimum phase for regions in this network. If no regions, then min = 0.
     *
     * @returns Minimum phase
     */
    UInt32 getMinPhase() const;

    /**
     * Get maximum phase for regions in this network. If no regions, then max = 0.
     *
     * @returns Maximum phase
     */
    UInt32 getMaxPhase() const;

    /**
     * Set the minimum enabled phase for this network.
     *
     * @param minPhase Minimum enabled phase
     */
    void
    setMinEnabledPhase(UInt32 minPhase);

    /**
     * Set the maximum enabled phase for this network.
     *
     * @param minPhase Maximum enabled phase
     */
    void
    setMaxEnabledPhase(UInt32 minPhase);

    /**
     * Get the minimum enabled phase for this network.
     *
     * @returns Minimum enabled phase for this network
     */
    UInt32
    getMinEnabledPhase() const;

    /**
     * Get the maximum enabled phase for this network.
     *
     * @returns Maximum enabled phase for this network
     */
    UInt32
    getMaxEnabledPhase() const;

    /**
     * @}
     *
     * @name Running
     *
     * @{
     */

    /**
     * Run the network for the given number of iterations of compute for each
     * Region in the correct order.
     *
     * For each iteration, Region.compute() is called.
     *
     * @param n Number of iterations
     */
    void
    run(int n);

    /**
     * The type of run callback function.
     *
     * You can attach a callback function to a network, and the callback function
     *  is called after every iteration of run().
     *
     * To attach a callback, just get a reference to the callback
     * collection with getCallbacks() , and add a callback.
     */
    typedef void (*runCallbackFunction)(Network*, UInt64 iteration, void*);

    /**
     * @todo document
     */
    typedef std::pair<runCallbackFunction, void*> callbackItem;

    /**
     * Get reference to callback Collection.
     *
     * @returns Reference to callback Collection
     */
    Collection<callbackItem>& getCallbacks();

    /**
     * Start profiling for all regions of this network.
     */
    void
    enableProfiling();

    /**
     * Stop profiling for all regions of this network.
     */
    void
    disableProfiling();

    /**
     * Reset profiling timers for all regions of this network.
     */
    void
    resetProfiling();

    /**
     * @}
     */

  private:

    // Both constructors use this common initialization method
    void commonInit();

    // Used by the path-based constructor
    void load(const std::string& path);

    void loadFromBundle(const std::string& path);

    // save() always calls this internal method, which creates
    // a .nta bundle
    void saveToBundle(const std::string& bundleName);

    // internal method using region pointer instead of name
    void
    setPhases_(Region *r, std::set<UInt32>& phases);

    // default phase assignment for a new region
    void setDefaultPhase_(Region* region);

    // whenever we modify a network or change phase
    // information, we set enabled phases to min/max for
    // the network
    void resetEnabledPhases_();

    bool initialized_;
    Collection<Region*> regions_;

    UInt32 minEnabledPhase_;
    UInt32 maxEnabledPhase_;

    // This is main data structure used to choreograph
    // network computation
    std::vector< std::set<Region*> > phaseInfo_;

    // we invoke these callbacks at every iteration
    Collection<callbackItem> callbacks_;

    //number of elapsed iterations
    UInt64 iteration_;
  };

} // namespace nta

#endif // NTA_NETWORK_HPP
<commit_msg>Prevent subgrouping<commit_after>/* ---------------------------------------------------------------------
 * Numenta Platform for Intelligent Computing (NuPIC)
 * Copyright (C) 2013, Numenta, Inc.  Unless you have an agreement
 * with Numenta, Inc., for a separate license for this software code, the
 * following terms and conditions apply:
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see http://www.gnu.org/licenses.
 *
 * http://numenta.org/licenses/
 * ---------------------------------------------------------------------
 */

/** @file
 * Interface for the Network class
 */

#ifndef NTA_NETWORK_HPP
#define NTA_NETWORK_HPP

#include <map>
#include <string>
#include <vector>
#include <set>
#include <nta/types/types.hpp>
#include <nta/ntypes/Collection.hpp>

namespace nta
{

  class Region;
  class Dimensions;

  /**
   * A Network represents an HTM network. A network is a collection of regions.
   *
   * @nosubgrouping
   */
  class Network
  {
  public:

    /**
     * @name Construction and destruction
     * @{
     */

    /**
     *
     * Create an new Network and register it to NuPIC.
     *
     * @note Creating a Network will auto-initialize NuPIC.
     */
    Network();

    /**
     * Create a Network by loading previously saved bundle,
     * and register it to NuPIC.
     *
     * @param path The path to the previously saved bundle file, currently only
     * support files with `.nta` extension.
     *
     * @note Creating a Network will auto-initialize NuPIC.
     */
    Network(const std::string& path);

    /**
     * Destructor.
     *
     * Destruct the network and unregister it from NuPIC:
     *
     * - Uninitialize all regions
     * - Remove all links
     * - Delete the regions themselves
     *
     * @todo Should we document the tear down steps above?
     */
    ~Network();

    /**
     * Initialize all elements of a network so that it can run.
     *
     * @note This can be called after the Network structure has been set and
     * before Network.run(). However, if you don't call it, Network.run() will
     * call it for you. Also sets up various memory buffers etc. once the Network
     *  structure has been finalized.
     */
    void
    initialize();

    /**
     * @}
     *
     * @name Serialization
     *
     * @{
     */

    /**
     * Save the network to a network bundle (extension `.nta`).
     *
     * @param name
     *        Name of the bundle
     */
    void save(const std::string& name);

    /**
     * @}
     *
     * @name Region and Link operations
     *
     * @{
     */

    /**
     * Create a new region in a network.
     *
     * @param name
     *        Name of the region, Must be unique in the network
     * @param nodeType
     *        Type of node in the region, e.g. "FDRNode"
     * @param nodeParams
     *        A JSON-encoded string specifying writable params
     *
     * @returns A pointer to the newly created Region
     */
    Region*
    addRegion(const std::string& name,
              const std::string& nodeType,
              const std::string& nodeParams);

    /**
     * Create a new region from saved state.
     *
     * @param name
     *        Name of the region, Must be unique in the network
     * @param nodeType
     *        Type of node in the region, e.g. "FDRNode"
     * @param dimensions
     *        Dimensions of the region
     * @param bundlePath
     *        The path to the bundle
     * @param label
     *        The label of the bundle
     *
     * @todo @a label is the prefix of filename of the saved bundle, should this
     * be documented?
     *
     * @returns A pointer to the newly created Region
     */
    Region*
    addRegionFromBundle(const std::string& name,
                        const std::string& nodeType,
                        const Dimensions& dimensions,
                        const std::string& bundlePath,
                        const std::string& label);

    /**
     * Removes a new region from the network.
     *
     * @param name
     *        Name of the Region
     */
    void
    removeRegion(const std::string& name);

    /**
     * Create a link and add it to the network.
     *
     * @param srcName
     *        Name of the source region
     * @param destName
     *        Name of the destination region
     * @param linkType
     *        Type of the link
     * @param linkParams
     *        Parameters of the link
     * @param srcOutput
     *        Name of the source output
     * @param destInput
     *        Name of the destination input
     */
    void
    link(const std::string& srcName, const std::string& destName,
         const std::string& linkType, const std::string& linkParams,
         const std::string& srcOutput="", const std::string& destInput="");

    /**
     * Removes a link.
     *
     * @param srcName
     *        Name of the source region
     * @param destName
     *        Name of the destination region
     * @param srcOutputName
     *        Name of the source output
     * @param destInputName
     *        Name of the destination input
     */
    void
    removeLink(const std::string& srcName, const std::string& destName,
               const std::string& srcOutputName="", const std::string& destInputName="");

    /**
     * @}
     *
     * @name Access to components
     *
     * @{
     */

    /**
     * Get all regions.
     *
     * @returns A Collection of Region objects in the network
     */
    const Collection<Region*>&
    getRegions() const;

    /**
     * Set phases for a region.
     *
     * @param name
     *        Name of the region
     * @param phases
     *        A tuple of phases (must be positive integers)
     */
    void
    setPhases(const std::string& name, std::set<UInt32>& phases);

    /**
     * Get phases for a region.
     *
     * @param name
     *        Name of the region
     *
     * @returns Set of phases for the region
     */
    std::set<UInt32>
    getPhases(const std::string& name) const;

    /**
     * Get minimum phase for regions in this network. If no regions, then min = 0.
     *
     * @returns Minimum phase
     */
    UInt32 getMinPhase() const;

    /**
     * Get maximum phase for regions in this network. If no regions, then max = 0.
     *
     * @returns Maximum phase
     */
    UInt32 getMaxPhase() const;

    /**
     * Set the minimum enabled phase for this network.
     *
     * @param minPhase Minimum enabled phase
     */
    void
    setMinEnabledPhase(UInt32 minPhase);

    /**
     * Set the maximum enabled phase for this network.
     *
     * @param minPhase Maximum enabled phase
     */
    void
    setMaxEnabledPhase(UInt32 minPhase);

    /**
     * Get the minimum enabled phase for this network.
     *
     * @returns Minimum enabled phase for this network
     */
    UInt32
    getMinEnabledPhase() const;

    /**
     * Get the maximum enabled phase for this network.
     *
     * @returns Maximum enabled phase for this network
     */
    UInt32
    getMaxEnabledPhase() const;

    /**
     * @}
     *
     * @name Running
     *
     * @{
     */

    /**
     * Run the network for the given number of iterations of compute for each
     * Region in the correct order.
     *
     * For each iteration, Region.compute() is called.
     *
     * @param n Number of iterations
     */
    void
    run(int n);

    /**
     * The type of run callback function.
     *
     * You can attach a callback function to a network, and the callback function
     *  is called after every iteration of run().
     *
     * To attach a callback, just get a reference to the callback
     * collection with getCallbacks() , and add a callback.
     */
    typedef void (*runCallbackFunction)(Network*, UInt64 iteration, void*);

    /**
     * @todo document
     */
    typedef std::pair<runCallbackFunction, void*> callbackItem;

    /**
     * Get reference to callback Collection.
     *
     * @returns Reference to callback Collection
     */
    Collection<callbackItem>& getCallbacks();

    /**
     * Start profiling for all regions of this network.
     */
    void
    enableProfiling();

    /**
     * Stop profiling for all regions of this network.
     */
    void
    disableProfiling();

    /**
     * Reset profiling timers for all regions of this network.
     */
    void
    resetProfiling();

    /**
     * @}
     */

  private:

    // Both constructors use this common initialization method
    void commonInit();

    // Used by the path-based constructor
    void load(const std::string& path);

    void loadFromBundle(const std::string& path);

    // save() always calls this internal method, which creates
    // a .nta bundle
    void saveToBundle(const std::string& bundleName);

    // internal method using region pointer instead of name
    void
    setPhases_(Region *r, std::set<UInt32>& phases);

    // default phase assignment for a new region
    void setDefaultPhase_(Region* region);

    // whenever we modify a network or change phase
    // information, we set enabled phases to min/max for
    // the network
    void resetEnabledPhases_();

    bool initialized_;
    Collection<Region*> regions_;

    UInt32 minEnabledPhase_;
    UInt32 maxEnabledPhase_;

    // This is main data structure used to choreograph
    // network computation
    std::vector< std::set<Region*> > phaseInfo_;

    // we invoke these callbacks at every iteration
    Collection<callbackItem> callbacks_;

    //number of elapsed iterations
    UInt64 iteration_;
  };

} // namespace nta

#endif // NTA_NETWORK_HPP
<|endoftext|>


<commit_before>#include "nan.h"
#include "marker-index.h"

using namespace std;
using namespace v8;

class MarkerIndexWrapper : public Nan::ObjectWrap {
public:
  static void Init(Local<Object> exports, Local<Object> module) {
    Local<FunctionTemplate> constructorTemplate =
        Nan::New<FunctionTemplate>(New);
    constructorTemplate->SetClassName(
        Nan::New<String>("MarkerIndex").ToLocalChecked());
    constructorTemplate->InstanceTemplate()->SetInternalFieldCount(1);
    constructorTemplate->PrototypeTemplate()->Set(Nan::New<String>("generateRandomNumber").ToLocalChecked(), Nan::New<FunctionTemplate>(GenerateRandomNumber)->GetFunction());
    module->Set(Nan::New("exports").ToLocalChecked(),
                constructorTemplate->GetFunction());
  }

private:
  static NAN_METHOD(New) {
    MarkerIndexWrapper *marker_index = new MarkerIndexWrapper(Local<Number>::Cast(info[0]));
    marker_index->Wrap(info.This());
  }

  static NAN_METHOD(GenerateRandomNumber) {
    MarkerIndexWrapper *wrapper = Nan::ObjectWrap::Unwrap<MarkerIndexWrapper>(info.This());
    int random = wrapper->marker_index.GenerateRandomNumber();
    info.GetReturnValue().Set(Nan::New<v8::Number>(random));
  }

  MarkerIndexWrapper(v8::Local<v8::Number> seed) :
    marker_index{static_cast<unsigned>(seed->Int32Value())} {}

  MarkerIndex marker_index;
};

NODE_MODULE(marker_index, MarkerIndexWrapper::Init)
<commit_msg>Expose insert function to JS that takes an id and 4 numbers<commit_after>#include "nan.h"
#include "marker-index.h"

using namespace std;
using namespace v8;

class MarkerIndexWrapper : public Nan::ObjectWrap {
public:
  static void Init(Local<Object> exports, Local<Object> module) {
    Local<FunctionTemplate> constructorTemplate =
        Nan::New<FunctionTemplate>(New);
    constructorTemplate->SetClassName(
        Nan::New<String>("MarkerIndex").ToLocalChecked());
    constructorTemplate->InstanceTemplate()->SetInternalFieldCount(1);
    constructorTemplate->PrototypeTemplate()->Set(Nan::New<String>("generateRandomNumber").ToLocalChecked(), Nan::New<FunctionTemplate>(GenerateRandomNumber)->GetFunction());
    constructorTemplate->PrototypeTemplate()->Set(Nan::New<String>("insert").ToLocalChecked(), Nan::New<FunctionTemplate>(Insert)->GetFunction());
    module->Set(Nan::New("exports").ToLocalChecked(),
                constructorTemplate->GetFunction());
  }

private:
  static NAN_METHOD(New) {
    MarkerIndexWrapper *marker_index = new MarkerIndexWrapper(Local<Number>::Cast(info[0]));
    marker_index->Wrap(info.This());
  }

  static NAN_METHOD(GenerateRandomNumber) {
    MarkerIndexWrapper *wrapper = Nan::ObjectWrap::Unwrap<MarkerIndexWrapper>(info.This());
    int random = wrapper->marker_index.GenerateRandomNumber();
    info.GetReturnValue().Set(Nan::New<v8::Number>(random));
  }

  static NAN_METHOD(Insert) {
    MarkerIndexWrapper *wrapper = Nan::ObjectWrap::Unwrap<MarkerIndexWrapper>(info.This());

    String::Utf8Value id_utf_8_value {info[0]};
    string id {*id_utf_8_value};

    Local<Number> start_row = Local<Number>::Cast(info[1]);
    Local<Number> start_column = Local<Number>::Cast(info[2]);
    Local<Number> end_row = Local<Number>::Cast(info[3]);
    Local<Number> end_column = Local<Number>::Cast(info[4]);
    Point start_point {static_cast<unsigned>(start_row->Int32Value()), static_cast<unsigned>(start_column->Int32Value())};
    Point end_point {static_cast<unsigned>(end_row->Int32Value()), static_cast<unsigned>(end_column->Int32Value())};

    wrapper->marker_index.Insert(id, start_point, end_point);
  }

  MarkerIndexWrapper(v8::Local<v8::Number> seed) :
    marker_index{static_cast<unsigned>(seed->Int32Value())} {}

  MarkerIndex marker_index;
};

NODE_MODULE(marker_index, MarkerIndexWrapper::Init)
<|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 "mfem.hpp"
#include "catch.hpp"

using namespace mfem;

namespace pa_coeff
{

int dimension;

double coeffFunction(const Vector& x)
{
   if (dimension == 2)
   {
      return sin(8.0 * M_PI * x[0]) * cos(6.0 * M_PI * x[1]) + 2.0;
   }
   else
   {
      return sin(8.0 * M_PI * x[0]) * cos(6.0 * M_PI * x[1]) *
             sin(4.0 * M_PI * x[2]) +
             2.0;
   }
}

double linearFunction(const Vector & x)
{
   if (dimension == 3)
   {
      return (10.0 * x(0)) + (5.0 * x(1)) + x(2);
   }
   else
   {
      return (10.0 * x(0)) + (5.0 * x(1));
   }
}

TEST_CASE("H1 pa_coeff")
{
   for (dimension = 2; dimension < 4; ++dimension)
   {
      for (int coeffType = 0; coeffType < 3; ++coeffType)
      {
         for (int integrator = 0; integrator < 2; ++integrator)
         {
            const int ne = 2;
            std::cout << "Testing " << dimension << "D partial assembly with "
                      << "coeffType " << coeffType << " and "
                      << "integrator " << integrator << std::endl;
            for (int order = 1; order < 5; ++order)
            {
               Mesh* mesh;
               if (dimension == 2)
               {
                  mesh = new Mesh(ne, ne, Element::QUADRILATERAL, 1, 1.0, 1.0);
               }
               else
               {
                  mesh = new Mesh(ne, ne, ne, Element::HEXAHEDRON, 1, 1.0, 1.0,
                                  1.0);
               }
               FiniteElementCollection* h1_fec =
                  new H1_FECollection(order, dimension);
               FiniteElementSpace h1_fespace(mesh, h1_fec);
               Array<int> ess_tdof_list;

               BilinearForm paform(&h1_fespace);
               GridFunction* coeffGridFunction = nullptr;
               Coefficient* coeff = nullptr;
               if (coeffType == 0)
               {
                  coeff = new ConstantCoefficient(1.0);
               }
               else if (coeffType == 1)
               {
                  coeff = new FunctionCoefficient(&coeffFunction);
               }
               else if (coeffType == 2)
               {
                  FunctionCoefficient tmpCoeff(&coeffFunction);
                  coeffGridFunction = new GridFunction(&h1_fespace);
                  coeffGridFunction->ProjectCoefficient(tmpCoeff);
                  coeff = new GridFunctionCoefficient(coeffGridFunction);
               }
               paform.SetAssemblyLevel(AssemblyLevel::PARTIAL);
               if (integrator < 2)
               {
                  paform.AddDomainIntegrator(new DiffusionIntegrator(*coeff));
               }
               if (integrator > 0)
               {
                  paform.AddDomainIntegrator(new MassIntegrator(*coeff));
               }
               paform.Assemble();
               OperatorHandle paopr;
               paform.FormSystemMatrix(ess_tdof_list, paopr);

               BilinearForm assemblyform(&h1_fespace);
               if (integrator < 2)
               {
                  assemblyform.AddDomainIntegrator(
                     new DiffusionIntegrator(*coeff));
               }
               if (integrator > 0)
               {
                  assemblyform.AddDomainIntegrator(new MassIntegrator(*coeff));
               }
               assemblyform.SetDiagonalPolicy(Matrix::DIAG_ONE);
               assemblyform.Assemble();
               assemblyform.Finalize();
               const SparseMatrix& A_explicit = assemblyform.SpMat();

               Vector xin(h1_fespace.GetTrueVSize());
               xin.Randomize();
               Vector y_mat(xin);
               y_mat = 0.0;
               Vector y_assembly(xin);
               y_assembly = 0.0;
               Vector y_pa(xin);
               y_pa = 0.0;

               paopr->Mult(xin, y_pa);
               assemblyform.Mult(xin, y_assembly);
               A_explicit.Mult(xin, y_mat);

               y_pa -= y_mat;
               double pa_error = y_pa.Norml2();
               std::cout << "  order: " << order
                         << ", pa error norm: " << pa_error << std::endl;
               REQUIRE(pa_error < 1.e-12);

               y_assembly -= y_mat;
               double assembly_error = y_assembly.Norml2();
               std::cout << "  order: " << order
                         << ", assembly error norm: " << assembly_error
                         << std::endl;
               REQUIRE(assembly_error < 1.e-12);

               delete coeff;
               delete coeffGridFunction;
               delete mesh;
               delete h1_fec;
            }
         }
      }
   }
}

TEST_CASE("Hcurl pa_coeff")
{
   for (dimension = 2; dimension < 4; ++dimension)
   {
      Mesh* mesh;
      const int ne = 3;
      if (dimension == 2)
      {
         mesh = new Mesh(ne, ne, Element::QUADRILATERAL, 1, 1.0, 1.0);
      }
      else
      {
         mesh = new Mesh(ne, ne, ne, Element::HEXAHEDRON, 1, 1.0, 1.0, 1.0);
      }

      for (int coeffType = 0; coeffType < 2; ++coeffType)
      {
         Coefficient* coeff = nullptr;
         Coefficient* curlCoeff = nullptr;
         if (coeffType == 0)
         {
            coeff = new ConstantCoefficient(12.34);
            curlCoeff = new ConstantCoefficient(12.34);
         }
         else if (coeffType == 1)
         {
            coeff = new FunctionCoefficient(&coeffFunction);
            curlCoeff = new FunctionCoefficient(&linearFunction);
         }

         for (int integrator = 0; integrator < 3; ++integrator)
         {
            std::cout << "Testing " << dimension << "D ND partial assembly with "
                      << "coeffType " << coeffType << " and "
                      << "integrator " << integrator << std::endl;
            for (int order = 1; order < 5; ++order)
            {
               FiniteElementCollection* ND_fec =
                  new ND_FECollection(order, dimension);
               FiniteElementSpace ND_fespace(mesh, ND_fec);

               // Set essential boundary conditions on the entire boundary.
               Array<int> tdof_ess(ND_fespace.GetVSize());
               for (int i=0; i<ND_fespace.GetVSize(); ++i)
               {
                  tdof_ess[i] = 0;
               }

               for (int i=0; i<mesh->GetNBE(); ++i)
               {
                  Array<int> dofs;
                  ND_fespace.GetBdrElementDofs(i, dofs);
                  for (int j=0; j<dofs.Size(); ++j)
                  {
                     const int dof_j = (dofs[j] >= 0) ? dofs[j] : -1 - dofs[j];
                     tdof_ess[dof_j] = 1;
                  }
               }

               int num_ess = 0;
               for (int i=0; i<ND_fespace.GetVSize(); ++i)
               {
                  if (tdof_ess[i] == 1)
                  {
                     num_ess++;
                  }
               }

               Array<int> ess_tdof_list(num_ess);
               num_ess = 0;
               for (int i=0; i<ND_fespace.GetVSize(); ++i)
               {
                  if (tdof_ess[i] == 1)
                  {
                     ess_tdof_list[num_ess] = i;
                     num_ess++;
                  }
               }

               BilinearForm paform(&ND_fespace);
               paform.SetAssemblyLevel(AssemblyLevel::PARTIAL);
               if (integrator < 2)
               {
                  paform.AddDomainIntegrator(new VectorFEMassIntegrator(*coeff));
               }
               if (integrator > 0)
               {
                  paform.AddDomainIntegrator(new CurlCurlIntegrator(*curlCoeff));
               }
               paform.Assemble();
               OperatorHandle paopr;
               paform.FormSystemMatrix(ess_tdof_list, paopr);

               BilinearForm assemblyform(&ND_fespace);
               if (integrator < 2)
               {
                  assemblyform.AddDomainIntegrator(
                     new VectorFEMassIntegrator(*coeff));
               }
               if (integrator > 0)
               {
                  assemblyform.AddDomainIntegrator(new CurlCurlIntegrator(*curlCoeff));
               }
               assemblyform.SetDiagonalPolicy(Matrix::DIAG_ONE);
               assemblyform.Assemble();
               assemblyform.Finalize();
               SparseMatrix A_explicit;
               assemblyform.FormSystemMatrix(ess_tdof_list, A_explicit);

               Vector xin(ND_fespace.GetTrueVSize());
               xin.Randomize();
               Vector y_mat(xin);
               y_mat = 0.0;
               Vector y_assembly(xin);
               y_assembly = 0.0;
               Vector y_pa(xin);
               y_pa = 0.0;

               paopr->Mult(xin, y_pa);
               assemblyform.Mult(xin, y_assembly);
               A_explicit.Mult(xin, y_mat);

               y_pa -= y_mat;
               double pa_error = y_pa.Norml2();
               std::cout << "  order: " << order
                         << ", pa error norm: " << pa_error << std::endl;
               REQUIRE(pa_error < 1.e-11);

               y_assembly -= y_mat;
               double assembly_error = y_assembly.Norml2();
               std::cout << "  order: " << order
                         << ", assembly error norm: " << assembly_error
                         << std::endl;
               REQUIRE(assembly_error < 1.e-12);

               delete ND_fec;
            }
         }

         delete coeff;
         delete curlCoeff;
      }

      delete mesh;
   }
}

TEST_CASE("Hcurl H1 mixed pa_coeff")
{
   for (dimension = 2; dimension < 4; ++dimension)
   {
      Mesh* mesh;
      const int ne = 2;
      if (dimension == 2)
      {
         mesh = new Mesh(ne, ne, Element::QUADRILATERAL, 1, 1.0, 1.0);
      }
      else
      {
         mesh = new Mesh(ne, ne, ne, Element::HEXAHEDRON, 1, 1.0, 1.0, 1.0);
      }

      for (int coeffType = 0; coeffType < 2; ++coeffType)
      {
         Coefficient* coeff = nullptr;
         if (coeffType == 0)
         {
            coeff = new ConstantCoefficient(12.34);
         }
         else if (coeffType == 1)
         {
            coeff = new FunctionCoefficient(&coeffFunction);
         }

         // Currently, we test only one integrator. More could be tested here
         // when they are implemented, using different test spaces (e.g. vector L2, H(div)).
         for (int integrator = 0; integrator < 1; ++integrator)
         {
            std::cout << "Testing " << dimension << "D ND H1 mixed partial assembly with "
                      << "coeffType " << coeffType << " and "
                      << "integrator " << integrator << std::endl;
            for (int order = 1; order < 5; ++order)
            {
               FiniteElementCollection* ND_fec =
                  new ND_FECollection(order, dimension);
               FiniteElementSpace ND_fespace(mesh, ND_fec);

               FiniteElementCollection* h1_fec =
                  new H1_FECollection(order, dimension);
               FiniteElementSpace h1_fespace(mesh, h1_fec);

               Array<int> ess_tdof_list;

               MixedBilinearForm paform(&h1_fespace, &ND_fespace);
               paform.SetAssemblyLevel(AssemblyLevel::PARTIAL);
               paform.AddDomainIntegrator(new MixedVectorGradientIntegrator(*coeff));
               paform.Assemble();

               MixedBilinearForm assemblyform(&h1_fespace, &ND_fespace);
               assemblyform.AddDomainIntegrator(new MixedVectorGradientIntegrator(*coeff));
               assemblyform.Assemble();
               assemblyform.Finalize();
               const SparseMatrix& A_explicit = assemblyform.SpMat();

               Vector xin(h1_fespace.GetTrueVSize());
               xin.Randomize();
               Vector y_mat(ND_fespace.GetTrueVSize());
               y_mat = 0.0;
               Vector y_assembly(ND_fespace.GetTrueVSize());
               y_assembly = 0.0;
               Vector y_pa(ND_fespace.GetTrueVSize());
               y_pa = 0.0;

               paform.Mult(xin, y_pa);
               assemblyform.Mult(xin, y_assembly);
               A_explicit.Mult(xin, y_mat);

               y_pa -= y_mat;
               double pa_error = y_pa.Norml2();
               std::cout << "  order: " << order
                         << ", pa error norm: " << pa_error << std::endl;
               REQUIRE(pa_error < 1.e-12);

               y_assembly -= y_mat;
               double assembly_error = y_assembly.Norml2();
               std::cout << "  order: " << order
                         << ", assembly error norm: " << assembly_error
                         << std::endl;
               REQUIRE(assembly_error < 1.e-12);

               delete ND_fec;
               delete h1_fec;
            }
         }

         delete coeff;
      }

      delete mesh;
   }
}

} // namespace pa_coeff
<commit_msg>Adding H(div) PA unit tests.<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 "mfem.hpp"
#include "catch.hpp"

using namespace mfem;

namespace pa_coeff
{

int dimension;

double coeffFunction(const Vector& x)
{
   if (dimension == 2)
   {
      return sin(8.0 * M_PI * x[0]) * cos(6.0 * M_PI * x[1]) + 2.0;
   }
   else
   {
      return sin(8.0 * M_PI * x[0]) * cos(6.0 * M_PI * x[1]) *
             sin(4.0 * M_PI * x[2]) +
             2.0;
   }
}

double linearFunction(const Vector & x)
{
   if (dimension == 3)
   {
      return (10.0 * x(0)) + (5.0 * x(1)) + x(2);
   }
   else
   {
      return (10.0 * x(0)) + (5.0 * x(1));
   }
}

TEST_CASE("H1 pa_coeff")
{
   for (dimension = 2; dimension < 4; ++dimension)
   {
      for (int coeffType = 0; coeffType < 3; ++coeffType)
      {
         for (int integrator = 0; integrator < 2; ++integrator)
         {
            const int ne = 2;
            std::cout << "Testing " << dimension << "D partial assembly with "
                      << "coeffType " << coeffType << " and "
                      << "integrator " << integrator << std::endl;
            for (int order = 1; order < 5; ++order)
            {
               Mesh* mesh;
               if (dimension == 2)
               {
                  mesh = new Mesh(ne, ne, Element::QUADRILATERAL, 1, 1.0, 1.0);
               }
               else
               {
                  mesh = new Mesh(ne, ne, ne, Element::HEXAHEDRON, 1, 1.0, 1.0,
                                  1.0);
               }
               FiniteElementCollection* h1_fec =
                  new H1_FECollection(order, dimension);
               FiniteElementSpace h1_fespace(mesh, h1_fec);
               Array<int> ess_tdof_list;

               BilinearForm paform(&h1_fespace);
               GridFunction* coeffGridFunction = nullptr;
               Coefficient* coeff = nullptr;
               if (coeffType == 0)
               {
                  coeff = new ConstantCoefficient(1.0);
               }
               else if (coeffType == 1)
               {
                  coeff = new FunctionCoefficient(&coeffFunction);
               }
               else if (coeffType == 2)
               {
                  FunctionCoefficient tmpCoeff(&coeffFunction);
                  coeffGridFunction = new GridFunction(&h1_fespace);
                  coeffGridFunction->ProjectCoefficient(tmpCoeff);
                  coeff = new GridFunctionCoefficient(coeffGridFunction);
               }
               paform.SetAssemblyLevel(AssemblyLevel::PARTIAL);
               if (integrator < 2)
               {
                  paform.AddDomainIntegrator(new DiffusionIntegrator(*coeff));
               }
               if (integrator > 0)
               {
                  paform.AddDomainIntegrator(new MassIntegrator(*coeff));
               }
               paform.Assemble();
               OperatorHandle paopr;
               paform.FormSystemMatrix(ess_tdof_list, paopr);

               BilinearForm assemblyform(&h1_fespace);
               if (integrator < 2)
               {
                  assemblyform.AddDomainIntegrator(
                     new DiffusionIntegrator(*coeff));
               }
               if (integrator > 0)
               {
                  assemblyform.AddDomainIntegrator(new MassIntegrator(*coeff));
               }
               assemblyform.SetDiagonalPolicy(Matrix::DIAG_ONE);
               assemblyform.Assemble();
               assemblyform.Finalize();
               const SparseMatrix& A_explicit = assemblyform.SpMat();

               Vector xin(h1_fespace.GetTrueVSize());
               xin.Randomize();
               Vector y_mat(xin);
               y_mat = 0.0;
               Vector y_assembly(xin);
               y_assembly = 0.0;
               Vector y_pa(xin);
               y_pa = 0.0;

               paopr->Mult(xin, y_pa);
               assemblyform.Mult(xin, y_assembly);
               A_explicit.Mult(xin, y_mat);

               y_pa -= y_mat;
               double pa_error = y_pa.Norml2();
               std::cout << "  order: " << order
                         << ", pa error norm: " << pa_error << std::endl;
               REQUIRE(pa_error < 1.e-12);

               y_assembly -= y_mat;
               double assembly_error = y_assembly.Norml2();
               std::cout << "  order: " << order
                         << ", assembly error norm: " << assembly_error
                         << std::endl;
               REQUIRE(assembly_error < 1.e-12);

               delete coeff;
               delete coeffGridFunction;
               delete mesh;
               delete h1_fec;
            }
         }
      }
   }
}

TEST_CASE("Hcurl/Hdiv pa_coeff")
{
   for (dimension = 2; dimension < 4; ++dimension)
   {
      Mesh* mesh;
      const int ne = 3;
      if (dimension == 2)
      {
         mesh = new Mesh(ne, ne, Element::QUADRILATERAL, 1, 1.0, 1.0);
      }
      else
      {
         mesh = new Mesh(ne, ne, ne, Element::HEXAHEDRON, 1, 1.0, 1.0, 1.0);
      }

      for (int coeffType = 0; coeffType < 2; ++coeffType)
      {
         Coefficient* coeff = nullptr;
         Coefficient* coeff2 = nullptr;
         if (coeffType == 0)
         {
            coeff = new ConstantCoefficient(12.34);
            coeff2 = new ConstantCoefficient(12.34);
         }
         else if (coeffType == 1)
         {
            coeff = new FunctionCoefficient(&coeffFunction);
            coeff2 = new FunctionCoefficient(&linearFunction);
         }

	 for (int spaceType = 0; spaceType < 2; ++spaceType)
	   {
	     for (int integrator = 0; integrator < 3; ++integrator)
	       {
		 if (spaceType == 0)
		   std::cout << "Testing " << dimension
			     << "D ND partial assembly with " << "coeffType "
			     << coeffType << " and " << "integrator "
			     << integrator << std::endl;
		 else
		   std::cout << "Testing " << dimension
			     << "D RT partial assembly with " << "coeffType "
			     << coeffType << " and " << "integrator "
			     << integrator << std::endl;

		 for (int order = 1; order < 4; ++order)
		   {
		     FiniteElementCollection* fec = (spaceType == 0) ?
		       (FiniteElementCollection*) new ND_FECollection(order, dimension) :
		       (FiniteElementCollection*) new RT_FECollection(order, dimension);

		     FiniteElementSpace fespace(mesh, fec);

		     // Set essential boundary conditions on the entire boundary.
		     Array<int> tdof_ess(fespace.GetVSize());
		     for (int i=0; i<fespace.GetVSize(); ++i)
		       {
			 tdof_ess[i] = 0;
		       }

		     for (int i=0; i<mesh->GetNBE(); ++i)
		       {
			 Array<int> dofs;
			 fespace.GetBdrElementDofs(i, dofs);
			 for (int j=0; j<dofs.Size(); ++j)
			   {
			     const int dof_j = (dofs[j] >= 0) ? dofs[j] : -1 - dofs[j];
			     tdof_ess[dof_j] = 1;
			   }
		       }

		     int num_ess = 0;
		     for (int i=0; i<fespace.GetVSize(); ++i)
		       {
			 if (tdof_ess[i] == 1)
			   {
			     num_ess++;
			   }
		       }

		     Array<int> ess_tdof_list(num_ess);
		     num_ess = 0;
		     for (int i=0; i<fespace.GetVSize(); ++i)
		       {
			 if (tdof_ess[i] == 1)
			   {
			     ess_tdof_list[num_ess] = i;
			     num_ess++;
			   }
		       }

		     BilinearForm paform(&fespace);
		     paform.SetAssemblyLevel(AssemblyLevel::PARTIAL);
		     if (integrator < 2)
		       {
			 paform.AddDomainIntegrator(new VectorFEMassIntegrator(*coeff));
		       }
		     if (integrator > 0)
		       {
			 if (spaceType == 0)
			   paform.AddDomainIntegrator(new CurlCurlIntegrator(*coeff2));
			 else
			   paform.AddDomainIntegrator(new DivDivIntegrator(*coeff2));
		       }
		     paform.Assemble();
		     OperatorHandle paopr;
		     paform.FormSystemMatrix(ess_tdof_list, paopr);

		     BilinearForm assemblyform(&fespace);
		     if (integrator < 2)
		       {
			 assemblyform.AddDomainIntegrator(
							  new VectorFEMassIntegrator(*coeff));
		       }
		     if (integrator > 0)
		       {
			 if (spaceType == 0)
			   assemblyform.AddDomainIntegrator(new CurlCurlIntegrator(*coeff2));
			 else
			   assemblyform.AddDomainIntegrator(new DivDivIntegrator(*coeff2));
		       }
		     assemblyform.SetDiagonalPolicy(Matrix::DIAG_ONE);
		     assemblyform.Assemble();
		     assemblyform.Finalize();
		     SparseMatrix A_explicit;
		     assemblyform.FormSystemMatrix(ess_tdof_list, A_explicit);

		     Vector xin(fespace.GetTrueVSize());
		     xin.Randomize();
		     Vector y_mat(xin);
		     y_mat = 0.0;
		     Vector y_assembly(xin);
		     y_assembly = 0.0;
		     Vector y_pa(xin);
		     y_pa = 0.0;

		     paopr->Mult(xin, y_pa);
		     assemblyform.Mult(xin, y_assembly);
		     A_explicit.Mult(xin, y_mat);

		     y_pa -= y_mat;
		     double pa_error = y_pa.Norml2();
		     std::cout << "  order: " << order
			       << ", pa error norm: " << pa_error << std::endl;
		     REQUIRE(pa_error < 1.e-10);

		     y_assembly -= y_mat;
		     double assembly_error = y_assembly.Norml2();
		     std::cout << "  order: " << order
			       << ", assembly error norm: " << assembly_error
			       << std::endl;
		     REQUIRE(assembly_error < 1.e-12);

		     delete fec;
		   }
	       }
	   }

         delete coeff;
         delete coeff2;
      }

      delete mesh;
   }
}

TEST_CASE("Hcurl H1 mixed pa_coeff")
{
   for (dimension = 2; dimension < 4; ++dimension)
   {
      Mesh* mesh;
      const int ne = 2;
      if (dimension == 2)
      {
         mesh = new Mesh(ne, ne, Element::QUADRILATERAL, 1, 1.0, 1.0);
      }
      else
      {
         mesh = new Mesh(ne, ne, ne, Element::HEXAHEDRON, 1, 1.0, 1.0, 1.0);
      }

      for (int coeffType = 0; coeffType < 2; ++coeffType)
      {
         Coefficient* coeff = nullptr;
         if (coeffType == 0)
         {
            coeff = new ConstantCoefficient(12.34);
         }
         else if (coeffType == 1)
         {
            coeff = new FunctionCoefficient(&coeffFunction);
         }

         // Currently, we test only one integrator. More could be tested here
         // when they are implemented, using different test spaces (e.g. vector L2, H(div)).
         for (int integrator = 0; integrator < 1; ++integrator)
         {
            std::cout << "Testing " << dimension << "D ND H1 mixed partial assembly with "
                      << "coeffType " << coeffType << " and "
                      << "integrator " << integrator << std::endl;
            for (int order = 1; order < 5; ++order)
            {
               FiniteElementCollection* ND_fec =
                  new ND_FECollection(order, dimension);
               FiniteElementSpace ND_fespace(mesh, ND_fec);

               FiniteElementCollection* h1_fec =
                  new H1_FECollection(order, dimension);
               FiniteElementSpace h1_fespace(mesh, h1_fec);

               Array<int> ess_tdof_list;

               MixedBilinearForm paform(&h1_fespace, &ND_fespace);
               paform.SetAssemblyLevel(AssemblyLevel::PARTIAL);
               paform.AddDomainIntegrator(new MixedVectorGradientIntegrator(*coeff));
               paform.Assemble();

               MixedBilinearForm assemblyform(&h1_fespace, &ND_fespace);
               assemblyform.AddDomainIntegrator(new MixedVectorGradientIntegrator(*coeff));
               assemblyform.Assemble();
               assemblyform.Finalize();
               const SparseMatrix& A_explicit = assemblyform.SpMat();

               Vector xin(h1_fespace.GetTrueVSize());
               xin.Randomize();
               Vector y_mat(ND_fespace.GetTrueVSize());
               y_mat = 0.0;
               Vector y_assembly(ND_fespace.GetTrueVSize());
               y_assembly = 0.0;
               Vector y_pa(ND_fespace.GetTrueVSize());
               y_pa = 0.0;

               paform.Mult(xin, y_pa);
               assemblyform.Mult(xin, y_assembly);
               A_explicit.Mult(xin, y_mat);

               y_pa -= y_mat;
               double pa_error = y_pa.Norml2();
               std::cout << "  order: " << order
                         << ", pa error norm: " << pa_error << std::endl;
               REQUIRE(pa_error < 1.e-12);

               y_assembly -= y_mat;
               double assembly_error = y_assembly.Norml2();
               std::cout << "  order: " << order
                         << ", assembly error norm: " << assembly_error
                         << std::endl;
               REQUIRE(assembly_error < 1.e-12);

               delete ND_fec;
               delete h1_fec;
            }
         }

         delete coeff;
      }

      delete mesh;
   }
}

} // namespace pa_coeff
<|endoftext|>


<commit_before>#include <Core/Utils/IndexMap.hpp>
#include <catch2/catch.hpp>
#include <unittestUtils.hpp>

// Just a standard test structure
struct Foo {
    explicit Foo( int x ) : value( x ) {}
    int value;
};

TEST_CASE( "Core/Utils/IndexMap", "[Core][Core/Utils][IndexMap]" ) {
    using Ra::Core::Utils::Index;
    using Ra::Core::Utils::IndexMap;

    SECTION( "Sanity checks" ) {
        IndexMap<Foo> map1;
        // New map should be empty
        REQUIRE( map1.empty() );
        // New map should be empty (size)
        REQUIRE( map1.size() == 0 );
        // New map should not be full
        REQUIRE( !map1.full() );
    }

    SECTION( "Test Copyable" ) {
        IndexMap<Foo> map1;
        Index i1, i2;
        i1 = map1.insert( Foo( 12 ) );
        REQUIRE( i1.isValid() );

        // We expect to have one element now.
        REQUIRE( !map1.empty() );
        REQUIRE( map1.size() == 1 );

        // Test value read and write
        REQUIRE( map1.at( i1 ).value == 12 );
        REQUIRE( map1[i1].value == 12 );

        map1.access( i1 ).value = 24;
        REQUIRE( map1.at( i1 ).value == 24 );

        map1[i1].value = 32;
        REQUIRE( map1.at( i1 ).value == 32 );

        i2 = map1.insert( Foo( 42 ) );
        REQUIRE( map1.at( i2 ).value == 42 );
        REQUIRE( map1.size() == 2 );

        //////////////////////////////////////////////////
        // Test range-based for loop (relies on iterators)
        uint counter = 0;
        for ( const Foo& f : map1 )
        {
            REQUIRE( ( f.value == 32 || f.value == 42 ) );
            ++counter;
        }
        REQUIRE( counter == 2 );

        // Test non-const loop
        counter = 0;
        for ( Foo& f : map1 )
        {
            f.value = 2 * f.value;
            REQUIRE( ( f.value == 2 * 32 || f.value == 2 * 42 ) );
            ++counter;
        }
        REQUIRE( counter == 2 );

        // Test index iterators
        counter = 0;
        for ( auto it = map1.cbegin_index(); it != map1.cend_index(); ++it )
        {
            REQUIRE( ( *it == i1 || *it == i2 ) );
            ++counter;
        }

        ///////////////////////////////////
        // Test methods contains and remove

        REQUIRE( map1.contains( i1 ) );
        REQUIRE( map1.contains( i2 ) );
        REQUIRE( !map1.contains( Index( 12000 ) ) );

        // Remove an item once.
        bool result = map1.remove( i1 );
        REQUIRE( result );
        REQUIRE( map1.size() == 1 );

        // Removing it twice should not work.
        result = map1.remove( i1 );
        REQUIRE( !result );

        // Remove the other item
        result = map1.remove( Index( 1000 ) );
        REQUIRE( !result );

        result = map1.remove( i2 );
        REQUIRE( result );

        REQUIRE( map1.size() == 0 );
        REQUIRE( map1.empty() );
    }

    SECTION( "Test Non-Copyable" ) {
        using Ra::Core::Utils::Index;
        using Ra::Core::Utils::IndexMap;
        // Now try to insert non-copyable elements

        IndexMap<NonCopy> map2;
        Index i1 = map2.emplace( std::move( 12 ) );
        // map insert (inplace)
        REQUIRE( i1.isValid() );

        Index i2 = map2.emplace( std::move( 42 ) );
        // map insert (inplace)
        REQUIRE( i2.isValid() );

        // map access (inplace)
        REQUIRE( map2[i1].value == 12 );
        REQUIRE( map2[i2].value == 42 );

        // Test the clear function
        map2.clear();
        REQUIRE( map2.size() == 0 );
        REQUIRE( map2.empty() );
    }
}
<commit_msg>[tests] Add some index tests regarding new ctor.<commit_after>#include <Core/Utils/IndexMap.hpp>
#include <catch2/catch.hpp>
#include <unittestUtils.hpp>

using Ra::Core::Utils::Index;
using Ra::Core::Utils::IndexMap;

// Just a standard test structure
struct Foo {
    explicit Foo( int x ) : value( x ) {}
    int value;
};

TEST_CASE( "Core/Utils/IndexMap", "[Core][Core/Utils][IndexMap]" ) {

    SECTION( "Sanity checks" ) {
        IndexMap<Foo> map1;
        // New map should be empty
        REQUIRE( map1.empty() );
        // New map should be empty (size)
        REQUIRE( map1.size() == 0 );
        // New map should not be full
        REQUIRE( !map1.full() );
    }

    SECTION( "Test Copyable" ) {
        IndexMap<Foo> map1;
        Index i1, i2;
        i1 = map1.insert( Foo( 12 ) );
        REQUIRE( i1.isValid() );

        // We expect to have one element now.
        REQUIRE( !map1.empty() );
        REQUIRE( map1.size() == 1 );

        // Test value read and write
        REQUIRE( map1.at( i1 ).value == 12 );
        REQUIRE( map1[i1].value == 12 );

        map1.access( i1 ).value = 24;
        REQUIRE( map1.at( i1 ).value == 24 );

        map1[i1].value = 32;
        REQUIRE( map1.at( i1 ).value == 32 );

        i2 = map1.insert( Foo( 42 ) );
        REQUIRE( map1.at( i2 ).value == 42 );
        REQUIRE( map1.size() == 2 );

        //////////////////////////////////////////////////
        // Test range-based for loop (relies on iterators)
        uint counter = 0;
        for ( const Foo& f : map1 )
        {
            REQUIRE( ( f.value == 32 || f.value == 42 ) );
            ++counter;
        }
        REQUIRE( counter == 2 );

        // Test non-const loop
        counter = 0;
        for ( Foo& f : map1 )
        {
            f.value = 2 * f.value;
            REQUIRE( ( f.value == 2 * 32 || f.value == 2 * 42 ) );
            ++counter;
        }
        REQUIRE( counter == 2 );

        // Test index iterators
        counter = 0;
        for ( auto it = map1.cbegin_index(); it != map1.cend_index(); ++it )
        {
            REQUIRE( ( *it == i1 || *it == i2 ) );
            ++counter;
        }

        ///////////////////////////////////
        // Test methods contains and remove

        REQUIRE( map1.contains( i1 ) );
        REQUIRE( map1.contains( i2 ) );
        REQUIRE( !map1.contains( Index( 12000 ) ) );

        // Remove an item once.
        bool result = map1.remove( i1 );
        REQUIRE( result );
        REQUIRE( map1.size() == 1 );

        // Removing it twice should not work.
        result = map1.remove( i1 );
        REQUIRE( !result );

        // Remove the other item
        result = map1.remove( Index( 1000 ) );
        REQUIRE( !result );

        result = map1.remove( i2 );
        REQUIRE( result );

        REQUIRE( map1.size() == 0 );
        REQUIRE( map1.empty() );
    }

    SECTION( "Test Non-Copyable" ) {
        using Ra::Core::Utils::Index;
        using Ra::Core::Utils::IndexMap;
        // Now try to insert non-copyable elements

        IndexMap<NonCopy> map2;
        Index i1 = map2.emplace( std::move( 12 ) );
        // map insert (inplace)
        REQUIRE( i1.isValid() );

        Index i2 = map2.emplace( std::move( 42 ) );
        // map insert (inplace)
        REQUIRE( i2.isValid() );

        // map access (inplace)
        REQUIRE( map2[i1].value == 12 );
        REQUIRE( map2[i2].value == 42 );

        // Test the clear function
        map2.clear();
        REQUIRE( map2.size() == 0 );
        REQUIRE( map2.empty() );
    }
}

template <typename T>
void testType() {
    T step = std::numeric_limits<T>::max() / T {1000};
    for ( T i = static_cast<T>( std::numeric_limits<Index::IntegerType>::max() ) + 1;
          i < static_cast<T>( std::numeric_limits<T>::max() - 2 * step );
          i += step )
    {
        // Index is more than max, so it is invalid
        Index idx {i};
        REQUIRE( idx.isInvalid() );
    }
}

TEST_CASE( "Core/Utils/Index/Ctor", "[Core][Core/Utils][Index]" ) {

    Index idxInvalid;
    REQUIRE( idxInvalid.isInvalid() );
    // testing everything is too long
    const int step = std::numeric_limits<Index::IntegerType>::max() / 1000;
    for ( Index::IntegerType i = 0; i < std::numeric_limits<Index::IntegerType>::max() - 2 * step;
          i += step )
    {
        Index idx {i};
        REQUIRE( idx.isValid() );
        auto idxUl = Index {static_cast<unsigned long int>( i )};
        auto idxL  = Index {static_cast<long int>( i )};
        auto idxU  = Index {static_cast<unsigned int>( i )};
        REQUIRE( idxUl.isValid() );
        REQUIRE( idxU.isValid() );
        REQUIRE( idxL.isValid() );
        REQUIRE( idx == idxUl );
        REQUIRE( idx == idxU );
        REQUIRE( idx == idxL );
    }

    testType<unsigned long int>();
    testType<long int>();
    testType<unsigned int>();
    testType<size_t>();
}
<|endoftext|>


<commit_before>
/*
 * MIT License
 *
 * Copyright (c) 2017 Hiroki SHIROKURA
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include <assert.h>
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#include <slankdev/string.h>
#include <slankdev/exception.h>

#include <ssn_thread.h>
#include <ssn_cpu.h>
#include <ssn_port.h>
#include <ssn_common.h>
#include <ssn_log.h>
#include <ssn_vnf.h>
#include <dpdk/dpdk.h>

ssn_vnf_port* port[2];

struct access_ids {
  size_t rx_aid;
  size_t tx_aid;
};
access_ids aids[RTE_MAX_LCORE];

size_t get_oportid_from_iportid(size_t in_port_id) { return in_port_id^1; }

class vnf_impl {
 public:
  uint32_t coremask;
  size_t rx_aid;
  size_t tx_aid;
  void configure(uint32_t coremask_)
  {
    coremask = coremask_;
  }
  virtual void deploy_impl(void*) = 0;
  virtual void undeploy_impl() = 0;
};
class vnf_impl_port0 : public vnf_impl {
 public:
  const size_t n_ports = 2;
  bool running;
  virtual void undeploy_impl() override { running = false; }
  virtual void deploy_impl(void*) override
  {
    constexpr size_t iport_id = 0;
    size_t rxaid = this->rx_aid;
    size_t txaid = this->tx_aid;
    printf("running impl_port0\n");
    running = true;
    while (running) {
      rte_mbuf* mbufs[32];
      size_t n_recv = port[iport_id]->rx_burst(rxaid, mbufs, 32);
      if (n_recv == 0) continue;

      for (size_t i=0; i<n_recv; i++) {

        /* Delay Block begin */
        size_t n=10;
        for (size_t j=0; j<100; j++) n++;

        size_t oport_id = get_oportid_from_iportid(iport_id);
        port[oport_id]->tx_burst(txaid, &mbufs[i], 1);
      }
    }
    printf("finnish impl_port0\n");
  }
};
class vnf_impl_port1 : public vnf_impl {
 public:
  const size_t n_ports = 2;
  bool running;
  virtual void undeploy_impl() override { running = false; }
  virtual void deploy_impl(void*) override
  {
    constexpr size_t iport_id = 1;
    size_t rxaid = this->rx_aid;
    size_t txaid = this->tx_aid;
    printf("running impl_port1\n");
    running = true;
    while (running) {
      rte_mbuf* mbufs[32];
      size_t n_recv = port[iport_id]->rx_burst(rxaid, mbufs, 32);
      if (n_recv == 0) continue;

      for (size_t i=0; i<n_recv; i++) {

        /* Delay Block begin */
        size_t n=10;
        for (size_t j=0; j<100; j++) n++;

        size_t oport_id = get_oportid_from_iportid(iport_id);
        port[oport_id]->tx_burst(txaid, &mbufs[i], 1);
      }
    }
    printf("finnish impl_port1\n");
  }
};
void _vnf_imple_spawner(void* instance_)
{
  vnf_impl* vi = reinterpret_cast<vnf_impl*>(instance_);
  vi->deploy_impl(nullptr);
}
class vnf {
 protected:
  std::vector<size_t> tids;
  std::vector<vnf_impl*> impls;
  ssn_vnf_port* ports[2];
 public:
  vnf()
  {
    vnf_impl* vnf_impl0 = new vnf_impl_port0;
    vnf_impl* vnf_impl1 = new vnf_impl_port1;
    vnf_impl0->rx_aid = 0; vnf_impl0->tx_aid = 0;
    vnf_impl1->rx_aid = 0; vnf_impl1->tx_aid = 1;
    impls.push_back(vnf_impl0);
    impls.push_back(vnf_impl1);
  }
  void deploy(size_t coremask0, size_t coremask1)
  {
    tids.resize(2);
    assert(impls.size() == 2);
    assert(tids.size() == 2);

    size_t n_impls = impls.size();
    for (size_t i=0; i<n_impls; i++) {
      tids[i] = ssn_thread_launch(_vnf_imple_spawner, impls[i], i+1);
    }
  }
  void undeploy()
  {
    assert(impls.size() == tids.size());
    size_t n_impls = impls.size();
    for (size_t i=0; i<n_impls; i++) {
      impls[i]->undeploy_impl();
    }
    size_t n_tids = tids.size();
    for (size_t i=0; i<n_tids; i++) {
      ssn_thread_join(tids[i]);
    }
  }
  void attach_port(size_t pid, ssn_vnf_port* port)
  {
    if (pid >= 2)
      throw slankdev::exception("invalid port_id");
    ports[pid] = port;
  }
};

/*---------------------------------------------------------------------------*/

char waitmsg(const char* msg)
{
  printf(msg);
  return getchar();
}

int main(int argc, char** argv)
{
  ssn_init(argc, argv);
  size_t n_ports = ssn_dev_count();
  if (n_ports != 2) {
    std::string err = slankdev::format("n_ports is not 2 (current %zd)",
        ssn_dev_count());
    throw slankdev::exception(err.c_str());
  }

  printf("\n");
  port[0] = new ssn_vnf_port(0, 2, 4); // dpdk0
  port[1] = new ssn_vnf_port(1, 2, 4); // dpdk1
  printf("\n");
  port[0]->debug_dump(stdout); printf("\n");
  port[1]->debug_dump(stdout); printf("\n");

  /*--------deploy-field-begin----------------------------------------------*/
  uint32_t tid0,tid1,tid2,tid3;

#if 0
  /* configuration 1 */
  port[0]->configure(1, 2);
  port[1]->configure(1, 2);
  vnf_impl* vnf_impl0 = new vnf_impl_port0;
  vnf_impl* vnf_impl1 = new vnf_impl_port1;
  vnf_impl0->rx_aid = 0; vnf_impl0->tx_aid = 0;
  vnf_impl1->rx_aid = 0; vnf_impl1->tx_aid = 1;
  tid0 = ssn_thread_launch(_vnf_imple_spawner, vnf_impl0, 1);
  tid1 = ssn_thread_launch(_vnf_imple_spawner, vnf_impl1, 2);
  getchar();
  vnf_impl0->undeploy_impl();
  vnf_impl1->undeploy_impl();
  ssn_thread_join(tid0);
  ssn_thread_join(tid1);
  delete vnf_impl0;
  delete vnf_impl1;

  /* configuration 2 */
  port[0]->configure(2, 4);
  port[1]->configure(2, 4);
  vnf_impl* vnf_impl0_0 = new vnf_impl_port0;
  vnf_impl* vnf_impl0_1 = new vnf_impl_port0;
  vnf_impl* vnf_impl1_0 = new vnf_impl_port1;
  vnf_impl* vnf_impl1_1 = new vnf_impl_port1;
  vnf_impl0_0->rx_aid = 0; vnf_impl0_0->tx_aid = 0;
  vnf_impl0_1->rx_aid = 1; vnf_impl0_1->tx_aid = 1;
  vnf_impl1_0->rx_aid = 0; vnf_impl1_0->tx_aid = 2;
  vnf_impl1_1->rx_aid = 1; vnf_impl1_1->tx_aid = 3;
  tid0 = ssn_thread_launch(_vnf_imple_spawner, vnf_impl0_0, 1);
  tid1 = ssn_thread_launch(_vnf_imple_spawner, vnf_impl0_1, 2);
  tid2 = ssn_thread_launch(_vnf_imple_spawner, vnf_impl1_0, 3);
  tid3 = ssn_thread_launch(_vnf_imple_spawner, vnf_impl1_1, 4);
  getchar();
  vnf_impl0_0->undeploy_impl();
  vnf_impl0_1->undeploy_impl();
  vnf_impl1_0->undeploy_impl();
  vnf_impl1_1->undeploy_impl();
  ssn_thread_join(tid0);
  ssn_thread_join(tid1);
  ssn_thread_join(tid2);
  ssn_thread_join(tid3);
  delete vnf_impl0_0;
  delete vnf_impl0_1;
  delete vnf_impl1_0;
  delete vnf_impl1_1;
#else
  vnf v0;
  v0.attach_port(0, port[0]);
  v0.attach_port(1, port[1]);

  /* configuration 2 */
  port[0]->configure(1, 2);
  port[1]->configure(1, 2);
  v0.deploy(0x02, 0x04);
  // v0.impl[0].deploy(0x02);
  // v0.impl[1].deploy(0x04);
  getchar();
  v0.undeploy();

  // #<{(| configuration 2 |)}>#
  // port[0]->configure(1, 2);
  // port[1]->configure(1, 2);
  // v0.impl[0].deploy(0x06);
  // v0.impl[1].deploy(0x24);
  // getchar();
  // v0.undeploy();
#endif

  /*--------deploy-field-end------------------------------------------------*/

  delete port[0];
  delete port[1];
  ssn_fin();
}

<commit_msg>WIP test<commit_after>
/*
 * MIT License
 *
 * Copyright (c) 2017 Hiroki SHIROKURA
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include <assert.h>
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#include <slankdev/string.h>
#include <slankdev/exception.h>

#include <ssn_thread.h>
#include <ssn_cpu.h>
#include <ssn_port.h>
#include <ssn_common.h>
#include <ssn_log.h>
#include <ssn_vnf.h>
#include <dpdk/dpdk.h>

#define NOTIMPL(str) slankdev::exception("NOT IMPLEMENT " #str)

struct access_ids {
  size_t rx_aid;
  size_t tx_aid;
};
access_ids aids[RTE_MAX_LCORE];

size_t popcnt(uint32_t n)
{
  size_t cnt = 0;
  for (size_t i=0; i<32; i++) {
    if ((0x01&n) != 0) cnt ++;
    n >>= 1;
  }
  return cnt;
}

size_t get_oportid_from_iportid(size_t in_port_id) { return in_port_id^1; }

class ssn_vnf_port_neo : public ssn_vnf_port {
  const size_t port_id;
  size_t n_rxacc;
  size_t n_txacc;
 public:
  ssn_vnf_port_neo(size_t pid, size_t nrxq, size_t ntxq)
    : ssn_vnf_port(pid, nrxq, ntxq), port_id(pid), n_rxacc(0), n_txacc(0) {}
  void reset_acc() { n_rxacc = 0; n_txacc = 0; }
  void request_rx_access(size_t n) { n_rxacc += n; }
  void request_tx_access(size_t n) { n_txacc += n; }
  void config_acc()
  {
    printf("SSN_VNF_PORT_CONF(pid:%zd, n_rxac:%zd, n_txacc:%zd)\n", port_id, n_rxacc, n_txacc);
    this->configure(n_rxacc, n_txacc);
  }
};
ssn_vnf_port_neo* port[2];

struct vnf_lcore {
  size_t lcore_id;
  ssize_t rx_acc;
  ssize_t tx_acc;
};

class vnf_impl {
 private:
  static void _vnf_imple_spawner(void* instance_)
  {
    vnf_impl* vi = reinterpret_cast<vnf_impl*>(instance_);
    vi->deploy_impl(nullptr);
  }
  std::vector<uint32_t> tids;
  std::vector<vnf_lcore> lcores;
  uint32_t coremask;

 protected:
  virtual void deploy_impl(void*) = 0;
  virtual void undeploy_impl() = 0;
  virtual void set_coremask_impl(uint32_t coremask) = 0;

  size_t tx_burst(size_t pid, size_t aid, rte_mbuf** mbufs, size_t n_mbufs)
  { return ports[pid]->tx_burst(aid, mbufs, n_mbufs); }
  size_t rx_burst(size_t pid, size_t aid, rte_mbuf** mbufs, size_t n_mbufs)
  { return ports[pid]->rx_burst(aid, mbufs, n_mbufs); }

 public:
  std::vector<ssn_vnf_port_neo*> ports;
  void attach_port(size_t pid, ssn_vnf_port_neo* p) { ports.at(pid) = p; }
  void set_coremask(uint32_t lcore_mask)
  {
    this->coremask = lcore_mask;
    set_coremask_impl(coremask);
  }
  void deploy()
  {
    lcores.clear();
    for (size_t i=0; i<32; i++) {
      if ((coremask & (0x1<<i)) != 0)
        lcores.push_back({i,-1,-1});
    }
    tids.resize(lcores.size());

    for (size_t i=0; i<lcores.size(); i++) {
      tids[i] = ssn_thread_launch(_vnf_imple_spawner, this, lcores[i].lcore_id);
    }
  }
  void undeploy()
  {
    assert(tids.size() == lcores.size());

    undeploy_impl();
    for (size_t i=0; i<lcores.size(); i++) {
      ssn_thread_join(tids[i]);
    }
    printf("undeploy succes\n");
  }
  vnf_impl() { ports.resize(2); } // TODO

  size_t get_rxaid_from_lcoreid(size_t lcore_id) const
  {
    for (size_t i=0; i<lcores.size(); i++) {
      if (lcores[i].lcore_id == lcore_id)
        return lcores[i].rx_acc;
    }
    std::string err = "vnf_impl::get_rxaid_from_lcoreid";
    err += slankdev::format("(%zd): ", lcore_id);
    err += "not found aid (lcoreid is invalid?)";
    throw slankdev::exception(err.c_str());
  }
  size_t get_txaid_from_lcoreid(size_t lcore_id) const
  {
    for (size_t i=0; i<lcores.size(); i++) {
      if (lcores[i].lcore_id == lcore_id)
        return lcores[i].rx_acc;
    }
    std::string err = "vnf_impl::get_rxaid_from_lcoreid";
    err += slankdev::format("(%zd): ", lcore_id);
    err += "not found aid (lcoreid is invalid?)";
    throw slankdev::exception(err.c_str());
  }
  size_t get_rxaid() const
  {
    size_t lcore_id = ssn_lcore_id();
    get_rxaid_from_lcoreid(lcore_id);
  }
  size_t get_txaid() const
  {
    size_t lcore_id = ssn_lcore_id();
    get_txaid_from_lcoreid(lcore_id);
  }

  /* To Be Implement */
  // virtual bool is_running();
  // void debug_dump(FILE* fp) const;
};
class vnf_impl_port : public vnf_impl {
 public:
  const size_t port_id;
  const size_t n_ports = 2;
  bool running;

  vnf_impl_port(size_t polling_port_id) : port_id(polling_port_id) {}
  virtual void set_coremask_impl(uint32_t coremask) override
  {
    size_t n_lcores = popcnt(coremask);
    ports[port_id  ]->request_rx_access(n_lcores);
    ports[port_id  ]->request_tx_access(n_lcores);
    ports[port_id^1]->request_tx_access(n_lcores);
  }
  virtual void undeploy_impl() override { running = false; }
  virtual void deploy_impl(void*) override
  {
    size_t rxaid = get_rxaid();
    size_t txaid = get_txaid();
    printf("running impl_port1\n");
    running = true;
    while (running) {
      rte_mbuf* mbufs[32];
      size_t n_recv = port[port_id]->rx_burst(rxaid, mbufs, 32);
      if (n_recv == 0) continue;

      for (size_t i=0; i<n_recv; i++) {

        /* Delay Block begin */
        size_t n=10;
        for (size_t j=0; j<100; j++) n++;

        size_t oport_id = get_oportid_from_iportid(port_id);
        port[oport_id]->tx_burst(txaid, &mbufs[i], 1);
      }
    }
    printf("finnish impl_port1\n");
  }
};
class vnf {
 public:
  std::vector<vnf_impl*> impls;
  vnf()
  {
    vnf_impl* vnf_impl0 = new vnf_impl_port(0);
    vnf_impl* vnf_impl1 = new vnf_impl_port(1);
    impls.push_back(vnf_impl0);
    impls.push_back(vnf_impl1);
  }
};

/*---------------------------------------------------------------------------*/

char waitmsg(const char* msg)
{
  printf(msg);
  return getchar();
}

int main(int argc, char** argv)
{
  ssn_init(argc, argv);
  size_t n_ports = ssn_dev_count();
  if (n_ports != 2) {
    std::string err = slankdev::format("n_ports is not 2 (current %zd)",
        ssn_dev_count());
    throw slankdev::exception(err.c_str());
  }

  printf("\n");
  port[0] = new ssn_vnf_port_neo(0, 2, 4); // dpdk0
  port[1] = new ssn_vnf_port_neo(1, 2, 4); // dpdk1
  printf("\n");
  port[0]->debug_dump(stdout); printf("\n");
  port[1]->debug_dump(stdout); printf("\n");

  /*--------deploy-field-begin----------------------------------------------*/

  vnf v0;
  v0.impls[0]->attach_port(0, port[0]);
  v0.impls[0]->attach_port(1, port[1]);
  v0.impls[1]->attach_port(0, port[0]);
  v0.impls[1]->attach_port(1, port[1]);

  /* configuration 2 */
  v0.impls[0]->set_coremask(0x02);
  v0.impls[1]->set_coremask(0x04);
  port[0]->config_acc();
  port[1]->config_acc();
  v0.impls[0]->deploy();
  v0.impls[1]->deploy();
  getchar();
  v0.impls[0]->undeploy();
  v0.impls[1]->undeploy();

  // #<{(| configuration 2 |)}>#
  // port[0]->configure(1, 2);
  // port[1]->configure(1, 2);
  // v0.impl[0].deploy(0x06);
  // v0.impl[1].deploy(0x24);
  // getchar();
  // v0.undeploy();

  /*--------deploy-field-end------------------------------------------------*/

  delete port[0];
  delete port[1];
  ssn_fin();
}

<|endoftext|>


<commit_before>/*
 * Copyright 2008 The Native Client Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can
 * be found in the LICENSE file.
 */

// NaCl inter-module communication primitives.
//
// This file implements common parts of IMC for "unix like systems" (i.e. not
// used on Windows).

// TODO(shiki): Perhaps this file should go into a platform-specific directory
// (posix? unixlike?)  We have a little convention going where mac/linux stuff
// goes in the linux directory and is referenced by the mac build but that's a
// little sloppy.

#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>

#include <algorithm>

#include "native_client/src/include/atomic_ops.h"

#include "native_client/src/shared/imc/nacl_imc.h"

namespace nacl {

namespace {

// The pathname prefix for memory objects created by CreateMemoryObject().
const char kShmPrefix[] = "/google-nacl-shm-";

}  // namespace

bool WouldBlock() {
  return (errno == EAGAIN) ? true : false;
}

int GetLastErrorString(char* buffer, size_t length) {
#if NACL_LINUX
  // Note some Linux distributions provide only GNU version of strerror_r().
  if (buffer == NULL || length == 0) {
    errno = ERANGE;
    return -1;
  }
  char* message = strerror_r(errno, buffer, length);
  if (message != buffer) {
    size_t message_bytes = strlen(message) + 1;
    length = std::min(message_bytes, length);
    memmove(buffer, message, length);
    buffer[length - 1] = '\0';
  }
  return 0;
#else
  return strerror_r(errno, buffer, length);
#endif
}

Handle CreateMemoryObject(size_t length) {
  static AtomicWord memory_object_count;
  if (0 == length) {
    return -1;
  }

  char name[PATH_MAX];
  for (;;) {
    snprintf(name, sizeof name, "%s-%u.%u", kShmPrefix,
             getpid(),
             static_cast<uint32_t>(AtomicIncrement(&memory_object_count, 1)));
    int m = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0666);
    if (0 <= m) {
      if (ftruncate(m, length) == -1) {
        close(m);
        m = -1;
      }
      shm_unlink(name);
      return m;
    }
    if (errno != EEXIST) {
      return -1;
    }
  }
}

void* Map(void* start, size_t length, int prot, int flags,
          Handle memory, off_t offset) {
  static const int kPosixProt[] = {
    PROT_NONE,
    PROT_READ,
    PROT_WRITE,
    PROT_READ | PROT_WRITE,
    PROT_EXEC,
    PROT_READ | PROT_EXEC,
    PROT_WRITE | PROT_EXEC,
    PROT_READ | PROT_WRITE | PROT_EXEC
  };

  int adjusted = 0;
  if (flags & kMapShared) {
    adjusted |= MAP_SHARED;
  }
  if (flags & kMapPrivate) {
    adjusted |= MAP_PRIVATE;
  }
  if (flags & kMapFixed) {
    adjusted |= MAP_FIXED;
  }
  return mmap(start, length, kPosixProt[prot & 7], adjusted, memory, offset);
}

int Unmap(void* start, size_t length) {
  return munmap(start, length);
}

}  // namespace nacl
<commit_msg>make linux/osx shared memory safer.<commit_after>/*
 * Copyright 2008 The Native Client Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can
 * be found in the LICENSE file.
 */

// NaCl inter-module communication primitives.
//
// This file implements common parts of IMC for "unix like systems" (i.e. not
// used on Windows).

// TODO(shiki): Perhaps this file should go into a platform-specific directory
// (posix? unixlike?)  We have a little convention going where mac/linux stuff
// goes in the linux directory and is referenced by the mac build but that's a
// little sloppy.

#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>

#include <algorithm>

#include "native_client/src/include/atomic_ops.h"

#include "native_client/src/shared/imc/nacl_imc.h"

namespace nacl {

namespace {

// The pathname prefix for memory objects created by CreateMemoryObject().
const char kShmPrefix[] = "/google-nacl-shm-";

}  // namespace

bool WouldBlock() {
  return (errno == EAGAIN) ? true : false;
}

int GetLastErrorString(char* buffer, size_t length) {
#if NACL_LINUX
  // Note some Linux distributions provide only GNU version of strerror_r().
  if (buffer == NULL || length == 0) {
    errno = ERANGE;
    return -1;
  }
  char* message = strerror_r(errno, buffer, length);
  if (message != buffer) {
    size_t message_bytes = strlen(message) + 1;
    length = std::min(message_bytes, length);
    memmove(buffer, message, length);
    buffer[length - 1] = '\0';
  }
  return 0;
#else
  return strerror_r(errno, buffer, length);
#endif
}

Handle CreateMemoryObject(size_t length) {
  static AtomicWord memory_object_count;
  if (0 == length) {
    return -1;
  }

  char name[PATH_MAX];
  for (;;) {
    snprintf(name, sizeof name, "%s-%u.%u", kShmPrefix,
             getpid(),
             static_cast<uint32_t>(AtomicIncrement(&memory_object_count, 1)));
    int m = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
    if (0 <= m) {
      if (ftruncate(m, length) == -1) {
        close(m);
        m = -1;
      }
      shm_unlink(name);
      return m;
    }
    if (errno != EEXIST) {
      return -1;
    }
  }
}

void* Map(void* start, size_t length, int prot, int flags,
          Handle memory, off_t offset) {
  static const int kPosixProt[] = {
    PROT_NONE,
    PROT_READ,
    PROT_WRITE,
    PROT_READ | PROT_WRITE,
    PROT_EXEC,
    PROT_READ | PROT_EXEC,
    PROT_WRITE | PROT_EXEC,
    PROT_READ | PROT_WRITE | PROT_EXEC
  };

  int adjusted = 0;
  if (flags & kMapShared) {
    adjusted |= MAP_SHARED;
  }
  if (flags & kMapPrivate) {
    adjusted |= MAP_PRIVATE;
  }
  if (flags & kMapFixed) {
    adjusted |= MAP_FIXED;
  }
  return mmap(start, length, kPosixProt[prot & 7], adjusted, memory, offset);
}

int Unmap(void* start, size_t length) {
  return munmap(start, length);
}

}  // namespace nacl
<|endoftext|>