Commit cf78ba83 authored by Nguyen, Thien Minh's avatar Nguyen, Thien Minh
Browse files

Work on NISQ anc. buffer allocator



Signed-off-by: default avatarThien Nguyen <nguyentm@ornl.gov>
parent 23f5532c
Loading
Loading
Loading
Loading
+65 −0
Original line number Diff line number Diff line
@@ -17,6 +17,71 @@
using namespace cppmicroservices;
using namespace xacc;

namespace {
class NisqQubitAllocator : public AllocEventListener, public QubitAllocator {
public:
  static inline const std::string ANC_BUFFER_NAME = "nisq_temp_buffer";
  virtual void onAllocate(qubit *in_qubit) override {}

  // On deallocate: don't try to deref the qubit since it may have been gone.
  virtual void onDealloc(qubit *in_qubit) override {
    // If this qubit was allocated from this pool:
    if (xacc::container::contains(m_allocatedQubits, in_qubit)) {
      const auto qIndex = std::find(m_allocatedQubits.begin(),
                                    m_allocatedQubits.end(), in_qubit) -
                          m_allocatedQubits.begin();
      // Strategy: create a storage copy of the returned qubit:
      // i.e. with the same index w.r.t. this global anc. buffer
      // but store it in the pool vector -> will stay alive
      // until giving out at the next allocate()
      qubit archive_qubit(ANC_BUFFER_NAME, qIndex, m_buffer.get());
      m_allocatedQubits[qIndex] = &archive_qubit;
      m_qubitPool.emplace_back(archive_qubit);
    }
  }

  virtual qubit allocate() override {
    if (!m_qubitPool.empty()) {
      auto recycled_qubit = m_qubitPool.back();
      m_qubitPool.pop_back();
      return recycled_qubit;
    }

    if (!m_buffer) {
      // This must be the first call.
      assert(m_allocatedQubits.empty());
      m_buffer = xacc::qalloc(1);
    }

    // Need to allocate new qubit:
    // Each new qubit will have an incrementing index.
    const auto newIdx = m_allocatedQubits.size();
    qubit new_qubit(ANC_BUFFER_NAME, newIdx, m_buffer.get());
    // Just track that we allocated this qubit
    m_allocatedQubits.emplace_back(&new_qubit);
    m_buffer->setSize(m_allocatedQubits.size());
    return new_qubit;
  }

  static NisqQubitAllocator *getInstance() {
    if (!g_instance) {
      g_instance = new NisqQubitAllocator();
    }
    return g_instance;
  }
  static NisqQubitAllocator *g_instance;

private:
  std::vector<qubit> m_qubitPool;
  // Track the list of qubit pointers for those
  // that was allocated by this Allocator.
  std::vector<qubit *> m_allocatedQubits;
  std::shared_ptr<xacc::AcceleratorBuffer> m_buffer;
};

NisqQubitAllocator *NisqQubitAllocator::g_instance = nullptr;
} // namespace

namespace qcor {
template <typename T>
bool ptr_is_a(std::shared_ptr<Observable> ptr) {
+22 −6
Original line number Diff line number Diff line
@@ -173,20 +173,36 @@ void setGlobalQubitManager(AllocEventListener *in_listener) {

// Dummy one:
struct DummyListener : AllocEventListener {
  static std::string address_to_string(qubit *qubit) {
    std::ostringstream address;
    address << (void const *)qubit;
    return address.str();
  }

  virtual void onAllocate(qubit *qubit) override {
    xacc::debug("Allocate: " + qubit->first + "[" +
                std::to_string(qubit->second) + "]");
    xacc::debug("Allocate qubit: " + qubit->first + "[" +
                std::to_string(qubit->second) +
                "] at: " + address_to_string(qubit));
  }

  // On deallocate: don't try to deref the qubit since it may have been gone.
  virtual void onDealloc(qubit *qubit) override {
    xacc::debug("Deallocate: " + qubit->first + "[" +
                std::to_string(qubit->second) + "]");
    xacc::debug("Deallocate qubit at address: " + address_to_string(qubit));
  }

  // Note: AllocEventListener global instances must
  // be heap-allocated to be alive until all qubits have been deallocated.
  static AllocEventListener *getInstance() {
    static DummyListener dummy;
    return &dummy;
    if (!g_instance) {
      g_instance = new DummyListener();
    }
    return g_instance;
  }
  static DummyListener *g_instance;
};

DummyListener *DummyListener::g_instance = nullptr;

AllocEventListener *getGlobalQubitManager() {
  return global_alloc_tracker ? global_alloc_tracker
                              : DummyListener::getInstance();
+2 −2
Original line number Diff line number Diff line
@@ -64,13 +64,13 @@ struct qubit {
  qubit(const std::string &reg_name, size_t idx,
        xacc::AcceleratorBuffer *in_buffer = nullptr)
      : first(reg_name), second(idx), buffer(in_buffer) {
    // tracker = std::make_shared<AllocTracker>(this);
    tracker = std::make_shared<AllocTracker>(this);
  }
  qubit() = default;
  // Having this tracker as a shared_ptr so that we can follow the qubit
  // even if it is copied, e.g. via slicing.
  // Default copy and copy assign should just copy this tracker across.
  // std::shared_ptr<AllocTracker> tracker;
  std::shared_ptr<AllocTracker> tracker;
};

class qreg;