<commit_before>/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "src/profiling/memory/shared_ring_buffer.h"

#include <atomic>
#include <type_traits>

#include <errno.h>
#include <inttypes.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>

#include "perfetto/base/build_config.h"
#include "perfetto/ext/base/scoped_file.h"
#include "perfetto/ext/base/temp_file.h"
#include "src/profiling/memory/scoped_spinlock.h"

#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
#include <linux/memfd.h>
#include <sys/syscall.h>
#endif

namespace perfetto {
namespace profiling {

namespace {

constexpr auto kMetaPageSize = base::kPageSize;
constexpr auto kAlignment = 8;  // 64 bits to use aligned memcpy().
constexpr auto kHeaderSize = kAlignment;
constexpr auto kGuardSize = base::kPageSize * 1024 * 16;  // 64 MB.
#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
constexpr auto kFDSeals = F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_SEAL;
#endif

}  // namespace

SharedRingBuffer::SharedRingBuffer(CreateFlag, size_t size) {
  size_t size_with_meta = size + kMetaPageSize;
  base::ScopedFile fd;
#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
  bool is_memfd = false;
  fd.reset(static_cast<int>(syscall(__NR_memfd_create, "heapprofd_ringbuf",
                                    MFD_CLOEXEC | MFD_ALLOW_SEALING)));
  is_memfd = !!fd;

  if (!fd) {
#if PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
    // In-tree builds should only allow mem_fd, so we can inspect the seals
    // to verify the fd is appropriately sealed.
    PERFETTO_ELOG("memfd_create() failed");
    return;
#else
    PERFETTO_DPLOG("memfd_create() failed");
#endif
  }
#endif

  if (!fd)
    fd = base::TempFile::CreateUnlinked().ReleaseFD();

  PERFETTO_CHECK(fd);
  int res = ftruncate(fd.get(), static_cast<off_t>(size_with_meta));
  PERFETTO_CHECK(res == 0);
#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
  if (is_memfd) {
    res = fcntl(*fd, F_ADD_SEALS, kFDSeals);
    if (res != 0) {
      PERFETTO_PLOG("Failed to seal FD.");
      return;
    }
  }
#endif
  Initialize(std::move(fd));
  if (!is_valid())
    return;

  new (meta_) MetadataPage();
}

SharedRingBuffer::~SharedRingBuffer() {
  static_assert(std::is_trivially_constructible<MetadataPage>::value,
                "MetadataPage must be trivially constructible");
  static_assert(std::is_trivially_destructible<MetadataPage>::value,
                "MetadataPage must be trivially destructible");

  if (is_valid()) {
    size_t outer_size = kMetaPageSize + size_ * 2 + kGuardSize;
    munmap(meta_, outer_size);
  }
}

void SharedRingBuffer::Initialize(base::ScopedFile mem_fd) {
#if PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
  int seals = fcntl(*mem_fd, F_GET_SEALS);
  if (seals == -1) {
    PERFETTO_PLOG("Failed to get seals of FD.");
    return;
  }
  if ((seals & kFDSeals) != kFDSeals) {
    PERFETTO_ELOG("FD not properly sealed. Expected %x, got %x", kFDSeals,
                  seals);
    return;
  }
#endif

  struct stat stat_buf = {};
  int res = fstat(*mem_fd, &stat_buf);
  if (res != 0 || stat_buf.st_size == 0) {
    PERFETTO_PLOG("Could not attach to fd.");
    return;
  }
  auto size_with_meta = static_cast<size_t>(stat_buf.st_size);
  auto size = size_with_meta - kMetaPageSize;

  // |size_with_meta| must be a power of two number of pages + 1 page (for
  // metadata).
  if (size_with_meta < 2 * base::kPageSize || size % base::kPageSize ||
      (size & (size - 1))) {
    PERFETTO_ELOG("SharedRingBuffer size is invalid (%zu)", size_with_meta);
    return;
  }

  // First of all reserve the whole virtual region to fit the buffer twice
  // + metadata page + red zone at the end.
  size_t outer_size = kMetaPageSize + size * 2 + kGuardSize;
  uint8_t* region = reinterpret_cast<uint8_t*>(
      mmap(nullptr, outer_size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
  if (region == MAP_FAILED) {
    PERFETTO_PLOG("mmap(PROT_NONE) failed");
    return;
  }

  // Map first the whole buffer (including the initial metadata page) @ off=0.
  void* reg1 = mmap(region, size_with_meta, PROT_READ | PROT_WRITE,
                    MAP_SHARED | MAP_FIXED, *mem_fd, 0);

  // Then map again the buffer, skipping the metadata page. The final result is:
  // [ METADATA ] [ RING BUFFER SHMEM ] [ RING BUFFER SHMEM ]
  void* reg2 = mmap(region + size_with_meta, size, PROT_READ | PROT_WRITE,
                    MAP_SHARED | MAP_FIXED, *mem_fd,
                    /*offset=*/kMetaPageSize);

  if (reg1 != region || reg2 != region + size_with_meta) {
    PERFETTO_PLOG("mmap(MAP_SHARED) failed");
    munmap(region, outer_size);
    return;
  }
  size_ = size;
  meta_ = reinterpret_cast<MetadataPage*>(region);
  mem_ = region + kMetaPageSize;
  mem_fd_ = std::move(mem_fd);
}

SharedRingBuffer::Buffer SharedRingBuffer::BeginWrite(
    const ScopedSpinlock& spinlock,
    size_t size) {
  PERFETTO_DCHECK(spinlock.locked());
  Buffer result;

  base::Optional<PointerPositions> opt_pos = GetPointerPositions();
  if (!opt_pos) {
    meta_->stats.num_writes_corrupt++;
    errno = EBADF;
    return result;
  }
  auto pos = opt_pos.value();

  const uint64_t size_with_header =
      base::AlignUp<kAlignment>(size + kHeaderSize);

  // size_with_header < size is for catching overflow of size_with_header.
  if (PERFETTO_UNLIKELY(size_with_header < size)) {
    errno = EINVAL;
    return result;
  }

  if (size_with_header > write_avail(pos)) {
    meta_->stats.num_writes_overflow++;
    errno = EAGAIN;
    return result;
  }

  uint8_t* wr_ptr = at(pos.write_pos);

  result.size = size;
  result.data = wr_ptr + kHeaderSize;
  meta_->stats.bytes_written += size;
  meta_->stats.num_writes_succeeded++;

  // We can make this a relaxed store, as this gets picked up by the acquire
  // load in GetPointerPositions (and the release store below).
  reinterpret_cast<std::atomic<uint32_t>*>(wr_ptr)->store(
      0, std::memory_order_relaxed);

  // This needs to happen after the store above, so the reader never observes an
  // incorrect byte count. This is matched by the acquire load in
  // GetPointerPositions.
  meta_->write_pos.fetch_add(size_with_header, std::memory_order_release);
  return result;
}

void SharedRingBuffer::EndWrite(Buffer buf) {
  if (!buf)
    return;
  uint8_t* wr_ptr = buf.data - kHeaderSize;
  PERFETTO_DCHECK(reinterpret_cast<uintptr_t>(wr_ptr) % kAlignment == 0);

  // This needs to release to make sure the reader sees the payload written
  // between the BeginWrite and EndWrite calls.
  //
  // This is matched by the acquire load in BeginRead where it reads the
  // record's size.
  reinterpret_cast<std::atomic<uint32_t>*>(wr_ptr)->store(
      static_cast<uint32_t>(buf.size), std::memory_order_release);
}

SharedRingBuffer::Buffer SharedRingBuffer::BeginRead() {
  base::Optional<PointerPositions> opt_pos = GetPointerPositions();
  if (!opt_pos) {
    meta_->stats.num_reads_corrupt++;
    errno = EBADF;
    return Buffer();
  }
  auto pos = opt_pos.value();

  size_t avail_read = read_avail(pos);

  if (avail_read < kHeaderSize) {
    meta_->stats.num_reads_nodata++;
    errno = EAGAIN;
    return Buffer();  // No data
  }

  uint8_t* rd_ptr = at(pos.read_pos);
  PERFETTO_DCHECK(reinterpret_cast<uintptr_t>(rd_ptr) % kAlignment == 0);
  const size_t size = reinterpret_cast<std::atomic<uint32_t>*>(rd_ptr)->load(
      std::memory_order_acquire);
  if (size == 0) {
    meta_->stats.num_reads_nodata++;
    errno = EAGAIN;
    return Buffer();
  }
  const size_t size_with_header = base::AlignUp<kAlignment>(size + kHeaderSize);

  if (size_with_header > avail_read) {
    PERFETTO_ELOG(
        "Corrupted header detected, size=%zu"
        ", read_avail=%zu, rd=%" PRIu64 ", wr=%" PRIu64,
        size, avail_read, pos.read_pos, pos.write_pos);
    meta_->stats.num_reads_corrupt++;
    errno = EBADF;
    return Buffer();
  }

  rd_ptr += kHeaderSize;
  PERFETTO_DCHECK(reinterpret_cast<uintptr_t>(rd_ptr) % kAlignment == 0);
  return Buffer(rd_ptr, size);
}

void SharedRingBuffer::EndRead(Buffer buf) {
  if (!buf)
    return;
  size_t size_with_header = base::AlignUp<kAlignment>(buf.size + kHeaderSize);
  meta_->read_pos.fetch_add(size_with_header, std::memory_order_relaxed);
  meta_->stats.num_reads_succeeded++;
}

bool SharedRingBuffer::IsCorrupt(const PointerPositions& pos) {
  if (pos.write_pos < pos.read_pos || pos.write_pos - pos.read_pos > size_ ||
      pos.write_pos % kAlignment || pos.read_pos % kAlignment) {
    PERFETTO_ELOG("Ring buffer corrupted, rd=%" PRIu64 ", wr=%" PRIu64
                  ", size=%zu",
                  pos.read_pos, pos.write_pos, size_);
    return true;
  }
  return false;
}

SharedRingBuffer::SharedRingBuffer(SharedRingBuffer&& other) noexcept {
  *this = std::move(other);
}

SharedRingBuffer& SharedRingBuffer::operator=(SharedRingBuffer&& other) {
  mem_fd_ = std::move(other.mem_fd_);
  std::tie(meta_, mem_, size_) = std::tie(other.meta_, other.mem_, other.size_);
  std::tie(other.meta_, other.mem_, other.size_) =
      std::make_tuple(nullptr, nullptr, 0);
  return *this;
}

// static
base::Optional<SharedRingBuffer> SharedRingBuffer::Create(size_t size) {
  auto buf = SharedRingBuffer(CreateFlag(), size);
  if (!buf.is_valid())
    return base::nullopt;
  return base::make_optional(std::move(buf));
}

// static
base::Optional<SharedRingBuffer> SharedRingBuffer::Attach(
    base::ScopedFile mem_fd) {
  auto buf = SharedRingBuffer(AttachFlag(), std::move(mem_fd));
  if (!buf.is_valid())
    return base::nullopt;
  return base::make_optional(std::move(buf));
}

}  // namespace profiling
}  // namespace perfetto
<commit_msg>Work around double-closing memfd.<commit_after>/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "src/profiling/memory/shared_ring_buffer.h"

#include <atomic>
#include <type_traits>

#include <errno.h>
#include <inttypes.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>

#include "perfetto/base/build_config.h"
#include "perfetto/ext/base/scoped_file.h"
#include "perfetto/ext/base/temp_file.h"
#include "src/profiling/memory/scoped_spinlock.h"

#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
#include <linux/memfd.h>
#include <sys/syscall.h>
#endif

namespace perfetto {
namespace profiling {

namespace {

constexpr auto kMetaPageSize = base::kPageSize;
constexpr auto kAlignment = 8;  // 64 bits to use aligned memcpy().
constexpr auto kHeaderSize = kAlignment;
constexpr auto kGuardSize = base::kPageSize * 1024 * 16;  // 64 MB.
#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
constexpr auto kFDSeals = F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_SEAL;
#endif

}  // namespace

SharedRingBuffer::SharedRingBuffer(CreateFlag, size_t size) {
  size_t size_with_meta = size + kMetaPageSize;
  base::ScopedFile fd;
#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
  bool is_memfd = false;
  fd.reset(static_cast<int>(syscall(__NR_memfd_create, "heapprofd_ringbuf",
                                    MFD_CLOEXEC | MFD_ALLOW_SEALING)));
  is_memfd = !!fd;

  if (!fd) {
#if PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
    // In-tree builds should only allow mem_fd, so we can inspect the seals
    // to verify the fd is appropriately sealed.
    PERFETTO_ELOG("memfd_create() failed");
    return;
#else
    PERFETTO_DPLOG("memfd_create() failed");
#endif
  }
#endif

  if (!fd)
    fd = base::TempFile::CreateUnlinked().ReleaseFD();

  PERFETTO_CHECK(fd);
  int res = ftruncate(fd.get(), static_cast<off_t>(size_with_meta));
  PERFETTO_CHECK(res == 0);
#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
  if (is_memfd) {
    res = fcntl(*fd, F_ADD_SEALS, kFDSeals);
    if (res != 0) {
      PERFETTO_PLOG("Failed to seal FD.");
      return;
    }
  }
#endif
  Initialize(std::move(fd));
  if (!is_valid())
    return;

  new (meta_) MetadataPage();
}

SharedRingBuffer::~SharedRingBuffer() {
  static_assert(std::is_trivially_constructible<MetadataPage>::value,
                "MetadataPage must be trivially constructible");
  static_assert(std::is_trivially_destructible<MetadataPage>::value,
                "MetadataPage must be trivially destructible");

  if (is_valid()) {
    size_t outer_size = kMetaPageSize + size_ * 2 + kGuardSize;
    munmap(meta_, outer_size);
  }

  // This is work-around for code like the following:
  // https://android.googlesource.com/platform/libcore/+/4ecb71f94378716f88703b9f7548b5d24839262f/ojluni/src/main/native/UNIXProcess_md.c#427
  // They fork, close all fds by iterating over /proc/self/fd using opendir.
  // Unfortunately closedir calls free, which detects the fork, and then tries
  // to destruct the Client that holds this SharedRingBuffer.
  //
  // ScopedResource crashes on failure to close, so we explicitly ignore
  // failures here.
  int fd = mem_fd_.release();
  if (fd != -1)
    close(fd);
}

void SharedRingBuffer::Initialize(base::ScopedFile mem_fd) {
#if PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
  int seals = fcntl(*mem_fd, F_GET_SEALS);
  if (seals == -1) {
    PERFETTO_PLOG("Failed to get seals of FD.");
    return;
  }
  if ((seals & kFDSeals) != kFDSeals) {
    PERFETTO_ELOG("FD not properly sealed. Expected %x, got %x", kFDSeals,
                  seals);
    return;
  }
#endif

  struct stat stat_buf = {};
  int res = fstat(*mem_fd, &stat_buf);
  if (res != 0 || stat_buf.st_size == 0) {
    PERFETTO_PLOG("Could not attach to fd.");
    return;
  }
  auto size_with_meta = static_cast<size_t>(stat_buf.st_size);
  auto size = size_with_meta - kMetaPageSize;

  // |size_with_meta| must be a power of two number of pages + 1 page (for
  // metadata).
  if (size_with_meta < 2 * base::kPageSize || size % base::kPageSize ||
      (size & (size - 1))) {
    PERFETTO_ELOG("SharedRingBuffer size is invalid (%zu)", size_with_meta);
    return;
  }

  // First of all reserve the whole virtual region to fit the buffer twice
  // + metadata page + red zone at the end.
  size_t outer_size = kMetaPageSize + size * 2 + kGuardSize;
  uint8_t* region = reinterpret_cast<uint8_t*>(
      mmap(nullptr, outer_size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
  if (region == MAP_FAILED) {
    PERFETTO_PLOG("mmap(PROT_NONE) failed");
    return;
  }

  // Map first the whole buffer (including the initial metadata page) @ off=0.
  void* reg1 = mmap(region, size_with_meta, PROT_READ | PROT_WRITE,
                    MAP_SHARED | MAP_FIXED, *mem_fd, 0);

  // Then map again the buffer, skipping the metadata page. The final result is:
  // [ METADATA ] [ RING BUFFER SHMEM ] [ RING BUFFER SHMEM ]
  void* reg2 = mmap(region + size_with_meta, size, PROT_READ | PROT_WRITE,
                    MAP_SHARED | MAP_FIXED, *mem_fd,
                    /*offset=*/kMetaPageSize);

  if (reg1 != region || reg2 != region + size_with_meta) {
    PERFETTO_PLOG("mmap(MAP_SHARED) failed");
    munmap(region, outer_size);
    return;
  }
  size_ = size;
  meta_ = reinterpret_cast<MetadataPage*>(region);
  mem_ = region + kMetaPageSize;
  mem_fd_ = std::move(mem_fd);
}

SharedRingBuffer::Buffer SharedRingBuffer::BeginWrite(
    const ScopedSpinlock& spinlock,
    size_t size) {
  PERFETTO_DCHECK(spinlock.locked());
  Buffer result;

  base::Optional<PointerPositions> opt_pos = GetPointerPositions();
  if (!opt_pos) {
    meta_->stats.num_writes_corrupt++;
    errno = EBADF;
    return result;
  }
  auto pos = opt_pos.value();

  const uint64_t size_with_header =
      base::AlignUp<kAlignment>(size + kHeaderSize);

  // size_with_header < size is for catching overflow of size_with_header.
  if (PERFETTO_UNLIKELY(size_with_header < size)) {
    errno = EINVAL;
    return result;
  }

  if (size_with_header > write_avail(pos)) {
    meta_->stats.num_writes_overflow++;
    errno = EAGAIN;
    return result;
  }

  uint8_t* wr_ptr = at(pos.write_pos);

  result.size = size;
  result.data = wr_ptr + kHeaderSize;
  meta_->stats.bytes_written += size;
  meta_->stats.num_writes_succeeded++;

  // We can make this a relaxed store, as this gets picked up by the acquire
  // load in GetPointerPositions (and the release store below).
  reinterpret_cast<std::atomic<uint32_t>*>(wr_ptr)->store(
      0, std::memory_order_relaxed);

  // This needs to happen after the store above, so the reader never observes an
  // incorrect byte count. This is matched by the acquire load in
  // GetPointerPositions.
  meta_->write_pos.fetch_add(size_with_header, std::memory_order_release);
  return result;
}

void SharedRingBuffer::EndWrite(Buffer buf) {
  if (!buf)
    return;
  uint8_t* wr_ptr = buf.data - kHeaderSize;
  PERFETTO_DCHECK(reinterpret_cast<uintptr_t>(wr_ptr) % kAlignment == 0);

  // This needs to release to make sure the reader sees the payload written
  // between the BeginWrite and EndWrite calls.
  //
  // This is matched by the acquire load in BeginRead where it reads the
  // record's size.
  reinterpret_cast<std::atomic<uint32_t>*>(wr_ptr)->store(
      static_cast<uint32_t>(buf.size), std::memory_order_release);
}

SharedRingBuffer::Buffer SharedRingBuffer::BeginRead() {
  base::Optional<PointerPositions> opt_pos = GetPointerPositions();
  if (!opt_pos) {
    meta_->stats.num_reads_corrupt++;
    errno = EBADF;
    return Buffer();
  }
  auto pos = opt_pos.value();

  size_t avail_read = read_avail(pos);

  if (avail_read < kHeaderSize) {
    meta_->stats.num_reads_nodata++;
    errno = EAGAIN;
    return Buffer();  // No data
  }

  uint8_t* rd_ptr = at(pos.read_pos);
  PERFETTO_DCHECK(reinterpret_cast<uintptr_t>(rd_ptr) % kAlignment == 0);
  const size_t size = reinterpret_cast<std::atomic<uint32_t>*>(rd_ptr)->load(
      std::memory_order_acquire);
  if (size == 0) {
    meta_->stats.num_reads_nodata++;
    errno = EAGAIN;
    return Buffer();
  }
  const size_t size_with_header = base::AlignUp<kAlignment>(size + kHeaderSize);

  if (size_with_header > avail_read) {
    PERFETTO_ELOG(
        "Corrupted header detected, size=%zu"
        ", read_avail=%zu, rd=%" PRIu64 ", wr=%" PRIu64,
        size, avail_read, pos.read_pos, pos.write_pos);
    meta_->stats.num_reads_corrupt++;
    errno = EBADF;
    return Buffer();
  }

  rd_ptr += kHeaderSize;
  PERFETTO_DCHECK(reinterpret_cast<uintptr_t>(rd_ptr) % kAlignment == 0);
  return Buffer(rd_ptr, size);
}

void SharedRingBuffer::EndRead(Buffer buf) {
  if (!buf)
    return;
  size_t size_with_header = base::AlignUp<kAlignment>(buf.size + kHeaderSize);
  meta_->read_pos.fetch_add(size_with_header, std::memory_order_relaxed);
  meta_->stats.num_reads_succeeded++;
}

bool SharedRingBuffer::IsCorrupt(const PointerPositions& pos) {
  if (pos.write_pos < pos.read_pos || pos.write_pos - pos.read_pos > size_ ||
      pos.write_pos % kAlignment || pos.read_pos % kAlignment) {
    PERFETTO_ELOG("Ring buffer corrupted, rd=%" PRIu64 ", wr=%" PRIu64
                  ", size=%zu",
                  pos.read_pos, pos.write_pos, size_);
    return true;
  }
  return false;
}

SharedRingBuffer::SharedRingBuffer(SharedRingBuffer&& other) noexcept {
  *this = std::move(other);
}

SharedRingBuffer& SharedRingBuffer::operator=(SharedRingBuffer&& other) {
  mem_fd_ = std::move(other.mem_fd_);
  std::tie(meta_, mem_, size_) = std::tie(other.meta_, other.mem_, other.size_);
  std::tie(other.meta_, other.mem_, other.size_) =
      std::make_tuple(nullptr, nullptr, 0);
  return *this;
}

// static
base::Optional<SharedRingBuffer> SharedRingBuffer::Create(size_t size) {
  auto buf = SharedRingBuffer(CreateFlag(), size);
  if (!buf.is_valid())
    return base::nullopt;
  return base::make_optional(std::move(buf));
}

// static
base::Optional<SharedRingBuffer> SharedRingBuffer::Attach(
    base::ScopedFile mem_fd) {
  auto buf = SharedRingBuffer(AttachFlag(), std::move(mem_fd));
  if (!buf.is_valid())
    return base::nullopt;
  return base::make_optional(std::move(buf));
}

}  // namespace profiling
}  // namespace perfetto
<|endoftext|>


<commit_before>#include "doofit/Builder/numerobis/blueprint/elements/registrar.h"

// from STL
#include <string>
#include <map>

// from BOOST
#include <boost/foreach.hpp>

// from RooFit
#include "RooArgList.h"

// from project
#include "doofit/utils//MsgStream.h"
#include "doofit/Builder/numerobis/blueprint/elements/element.h"

// forward decalaration
class RooWorkspace;

namespace doofit {
namespace builder {
namespace numerobis {
namespace blueprint {
namespace elements {

Registrar::Registrar()
    : elements_()
{

}

Registrar::~Registrar() {

}

void Registrar::Declare(Element* const element) {
  std::string temp_key = element->id_abs();
  elements_.insert(temp_key,  element);
}

void Registrar::Print() const {
  namespace du = doofit::utils;
  du::sinfo.Ruler();
  du::sinfo << "Registrar contents:" << du::endmsg;
  du::sinfo.increment_indent(2);
  for (boost::ptr_map<std::string, Element>::const_iterator it=elements_.begin();
       it!=elements_.end(); ++it) {
    du::sinfo << *(*it).second << du::endmsg;
  }
  du::sinfo.increment_indent(-2);
}

bool Registrar::CheckReady(const std::string& element_name) {
  boost::ptr_map<std::string, Element>::iterator it_element = elements_.find(element_name);
  if (it_element == elements_.end()) return false;

  Element* element = *it_element->second();

  namespace du = doofit::utils;
  //du::sdebug << "Checking ready for: " << element.id_abs() << du::endmsg;

  // Check if element is ready, if not, check if dependants are ready.
  if (!element.ready()) {
    const std::vector<std::string>& dep = element.dependants();
    bool allready = true;

    std::map<std::string, Element*>::iterator it_el;
    BOOST_FOREACH (std::string it_dep, dep) {
      it_el = elements_.find(it_dep);
      if (it_el == elements_.end()) {
        allready = false;
      } else {
        allready &= CheckReady(*it_el->second);
      }
    }
    if (allready) element.set_ready(true);
  }

  return element.ready();
}

RooAbsArg* Registrar::Register(RooWorkspace* ws, Element &element) {
  if (CheckReady(element)) {
    const std::vector<std::string>& dep_ids = element.dependants();

    // Iterate ove dependants and check if dependants exist in elements_.
    // If not, throw exception.
    // If yes, register them and invoke AddToWorkspace
    std::vector<RooAbsArg*> dep_elements;
    std::map<std::string, Element*>::iterator it_el;
    BOOST_FOREACH(std::string it_dep, dep_ids) {
      it_el = elements_.find(it_dep);
      if (it_el == elements_.end()) {
        throw UnexpectedException();
      } else {
        Element& dep_element = *it_el->second;
        dep_elements.push_back(Register(ws, dep_element));
      }
    }
    return element.AddToWorkspace(ws, dep_elements);
  }
  return NULL;
}

RooArgList VectorToArgList(std::vector<RooAbsArg*> vec) {
  RooArgList list;
  for (std::vector<RooAbsArg*>::const_iterator it=vec.begin();
       it!=vec.end(); ++it) {
    list.add(**it, true);
  }
  return list;
}

} // namespace elements
} // namespace blueprint
} // namespace numerobis
} // namespace builder
} // namespace doofit
<commit_msg>Blubbsel.<commit_after>#include "doofit/Builder/numerobis/blueprint/elements/registrar.h"

// from STL
#include <string>
#include <map>

// from BOOST
#include <boost/foreach.hpp>

// from RooFit
#include "RooArgList.h"

// from project
#include "doofit/utils//MsgStream.h"
#include "doofit/Builder/numerobis/blueprint/elements/element.h"

// forward decalaration
class RooWorkspace;

namespace doofit {
namespace builder {
namespace numerobis {
namespace blueprint {
namespace elements {

Registrar::Registrar()
    : elements_()
{

}

Registrar::~Registrar() {

}

void Registrar::Declare(Element* const element) {
  std::string temp_key = element->id_abs();
  elements_.insert(temp_key,  element);
}

void Registrar::Print() const {
  namespace du = doofit::utils;
  du::sinfo.Ruler();
  du::sinfo << "Registrar contents:" << du::endmsg;
  du::sinfo.increment_indent(2);
  for (boost::ptr_map<std::string, Element>::const_iterator it=elements_.begin();
       it!=elements_.end(); ++it) {
    du::sinfo << *(*it).second << du::endmsg;
  }
  du::sinfo.increment_indent(-2);
}

bool Registrar::CheckReady(const std::string& element_name) {
  boost::ptr_map<std::string, Element>::iterator it_element = elements_.find(element_name);
  if (it_element == elements_.end()) return false;

  Element* element = it_element->second;

  namespace du = doofit::utils;
  //du::sdebug << "Checking ready for: " << element.id_abs() << du::endmsg;

  // Check if element is ready, if not, check if dependants are ready.
  if (!element->ready()) {
    const std::vector<std::string>& dep = element->dependants();
    bool allready = true;

    boost::ptr_map<std::string, Element>::iterator it_el;
    BOOST_FOREACH (std::string it_dep, dep) {
      it_el = elements_.find(it_dep);
      if (it_el == elements_.end()) {
        allready = false;
      } else {
        allready &= CheckReady(it_el->second->id_abs());
      }
    }
    if (allready) element->set_ready(true);
  }

  return element->ready();
}

RooAbsArg* Registrar::Register(RooWorkspace* ws, const std::string& element_name) {
  if (CheckReady(element_name)) {
    Element* element = elements_.find(element_name)->second;

    const std::vector<std::string>& dep_ids = element->dependants();

    // Iterate over dependants and check if dependants exist in elements_.
    // If not, throw exception.
    // If yes, register them and invoke AddToWorkspace
    std::vector<RooAbsArg*> dep_elements;
    boost::ptr_map<std::string, Element>::iterator it_el;
    BOOST_FOREACH(std::string it_dep, dep_ids) {
      it_el = elements_.find(it_dep);
      if (it_el == elements_.end()) {
        throw UnexpectedException();
      } else {
        Element* dep_element = it_el->second;
        dep_elements.push_back(Register(ws, dep_element->id_abs()));
      }
    }
    return element->AddToWorkspace(ws, dep_elements);
  }
  return NULL;
}

RooArgList VectorToArgList(std::vector<RooAbsArg*> vec) {
  RooArgList list;
  for (std::vector<RooAbsArg*>::const_iterator it=vec.begin();
       it!=vec.end(); ++it) {
    list.add(**it, true);
  }
  return list;
}

} // namespace elements
} // namespace blueprint
} // namespace numerobis
} // namespace builder
} // namespace doofit
<|endoftext|>


<commit_before>/**************************************************************************
 * Copyright(c) 1998-2007, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

/* $Id$ */

//-------------------------------------------------------------------------
//     Offline Analysis Database Container and Service Class
//     Author: Andreas Morsch, CERN
//-------------------------------------------------------------------------

#include "AliOADBContainer.h"
#include "AliLog.h"
#include <TObjArray.h>
#include <TArrayI.h>
#include <TFile.h>
#include <TList.h>
#include <TBrowser.h>
#include <TSystem.h>
#include <TError.h>

ClassImp(AliOADBContainer);

//______________________________________________________________________________
AliOADBContainer::AliOADBContainer() :
  TNamed(),
  fArray(0),
  fDefaultList(0),
  fLowerLimits(),
  fUpperLimits(),
  fEntries(0)
{
  // Default constructor
}

AliOADBContainer::AliOADBContainer(const char* name) :
  TNamed(name, "OADBContainer"),
  fArray(new TObjArray(100)),
  fDefaultList(new TList()),
  fLowerLimits(),
  fUpperLimits(),
  fEntries(0)
{
  // Constructor
}

//______________________________________________________________________________
AliOADBContainer::~AliOADBContainer()
{
  // destructor
}

//______________________________________________________________________________
AliOADBContainer::AliOADBContainer(const AliOADBContainer& cont) :
  TNamed(cont),
  fArray(cont.fArray),
  fDefaultList(cont.fDefaultList),
  fLowerLimits(cont.fLowerLimits),
  fUpperLimits(cont.fUpperLimits),
  fEntries(cont.fEntries)
{
  // Copy constructor.
}

//______________________________________________________________________________
AliOADBContainer& AliOADBContainer::operator=(const AliOADBContainer& cont)
{
  //
  // Assignment operator
  // Copy objects related to run ranges
  if(this!=&cont) {
    TNamed::operator=(cont);
    fEntries = cont.fEntries;
    fLowerLimits.Set(fEntries);
    fUpperLimits.Set(fEntries);
    for (Int_t i = 0; i < fEntries; i++) {
	fLowerLimits[i] = cont.fLowerLimits[i];
	fUpperLimits[i] = cont.fUpperLimits[i];
	fArray->AddAt(cont.fArray->At(i), i);
    }
  }
  //
  // Copy default objects
  TList* list = cont.GetDefaultList();
  TIter next(list);
  TObject* obj;
  while((obj = next())) fDefaultList->Add(obj);
  //
  return *this;
}

void AliOADBContainer::AppendObject(TObject* obj, Int_t lower, Int_t upper)
{
  //
  // Append a new object to the list
  //
  // Check that there is no overlap with existing run ranges
  Int_t index = HasOverlap(lower, upper);

  if (index != -1) {
    AliFatal(Form("Ambiguos validity range (%5d, %5.5d-%5.5d) !\n", index,lower,upper));
    return;
  }
  //
  // Adjust arrays
  fEntries++;
  fLowerLimits.Set(fEntries);
  fUpperLimits.Set(fEntries);

  // Add the object
  fLowerLimits[fEntries - 1] = lower;
  fUpperLimits[fEntries - 1] = upper;
  fArray->Add(obj);
}

void AliOADBContainer::RemoveObject(Int_t idx)
{
  //
  // Remove object from the list

  //
  // Check that index is inside range
  if (idx < 0 || idx >= fEntries)
    {
      AliError(Form("Index out of Range %5d >= %5d", idx, fEntries));
      return;
    }
  //
  // Remove the object
  TObject* obj = fArray->RemoveAt(idx);
  delete obj;
  //
  // Adjust the run ranges and shrink the array
  for (Int_t i = idx; i < (fEntries-1); i++) {
    fLowerLimits[i] = fLowerLimits[i + 1];
    fUpperLimits[i] = fUpperLimits[i + 1];
    fArray->AddAt(fArray->At(i+1), i);
  }
  fArray->RemoveAt(fEntries - 1);
  fEntries--;
}

void AliOADBContainer::UpdateObject(Int_t idx, TObject* obj, Int_t lower, Int_t upper)
{
  //
  // Update an existing object, at a given position

  // Check that index is inside range
  if (idx < 0 || idx >= fEntries)
    {
      AliError(Form("Index out of Range %5d >= %5d", idx, fEntries));
      return;
    }
  //
  // Remove the old object and reset the range
  //  TObject* obj2 =
  fArray->RemoveAt(idx);
  // don't delete it: if you are updating it may be pointing to the same location of obj...
  //  delete obj2;
  fLowerLimits[idx] = -1;
  fUpperLimits[idx] = -1;
  // Check that there is no overlap with existing run ranges
  Int_t index = HasOverlap(lower, upper);
  if (index != -1) {
    AliFatal(Form("Ambiguos validity range (%5d, %5.5d-%5.5d) !\n", index,lower,upper));
    return;
  }
  //
  // Add object at the same position
  //printf("idx %d obj %llx\n", idx, obj);
  fLowerLimits[idx] = lower;
  fUpperLimits[idx] = upper;
  fArray->AddAt(obj, idx);

}

void  AliOADBContainer::AddDefaultObject(TObject* obj)
{
  // Add a default object
  fDefaultList->Add(obj);
}

void  AliOADBContainer::CleanDefaultList()
{
  // Clean default list
  fDefaultList->Delete();
}

Int_t AliOADBContainer::GetIndexForRun(Int_t run) const
{
  //
  // Find the index for a given run

  Int_t found = 0;
  Int_t index = -1;
  for (Int_t i = 0; i < fEntries; i++)
    {
      if (run >= fLowerLimits[i] && run <= fUpperLimits[i])
	{
	  found++;
	  index = i;
	}
    }

  if (found > 1) {
    AliError(Form("More than one (%5d) object found; return last (%5d) !\n", found, index));
  } else if (index == -1) {
    AliWarning(Form("No object (%s) found for run %5d !\n", GetName(), run));
  }

  return index;
}

TObject* AliOADBContainer::GetObject(Int_t run, const char* def) const
{
  // Return object for given run or default if not found
  TObject* obj = 0;
  Int_t idx = GetIndexForRun(run);
  if (idx == -1) {
    // no object found, try default
    obj = fDefaultList->FindObject(def);
    if (!obj) {
      AliError(Form("Default Object (%s) not found !\n", GetName()));
      return (0);
    } else {
      return (obj);
    }
  } else {
    return (fArray->At(idx));
  }
}

TObject* AliOADBContainer::GetObjectByIndex(Int_t run) const
{
  // Return object for given index
  return (fArray->At(run));
}

void AliOADBContainer::WriteToFile(const char* fname) const
{
  //
  // Write object to file
  TFile* f = new TFile(fname, "update");
  Write();
  f->Purge();
  f->Close();
}

Int_t AliOADBContainer::InitFromFile(const char* fname, const char* key)
{
    //
    // Initialize object from file
    TFile* file = TFile::Open(fname);
    if (!file) return (1);
    AliOADBContainer* cont  = 0;
    file->GetObject(key, cont);
    if (!cont)
    {
      AliError(Form("Object (%s) not found in file \n", GetName()));
	return 1;
    }

    SetName(cont->GetName());
    SetTitle(cont->GetTitle());

    fEntries = cont->GetNumberOfEntries();
    fLowerLimits.Set(fEntries);
    fUpperLimits.Set(fEntries);
    if(fEntries > fArray->GetSize()) fArray->Expand(fEntries);

    for (Int_t i = 0; i < fEntries; i++) {
	fLowerLimits[i] = cont->LowerLimit(i);
	fUpperLimits[i] = cont->UpperLimit(i);
	fArray->AddAt(cont->GetObjectByIndex(i), i);
    }
    if (!fDefaultList) fDefaultList = new TList();
    TIter next(cont->GetDefaultList());
    TObject* obj;
    while((obj = next())) fDefaultList->Add(obj);

    return 0;

}

void AliOADBContainer::List()
{
  //
  // List Objects
  printf("Entries %d\n", fEntries);

  for (Int_t i = 0; i < fEntries; i++) {
    printf("Lower %5d Upper %5d \n", fLowerLimits[i], fUpperLimits[i]);
    (fArray->At(i))->Dump();
  }
  TIter next(fDefaultList);
  TObject* obj;
  while((obj = next())) obj->Dump();

}

Int_t AliOADBContainer::HasOverlap(Int_t lower, Int_t upper) const
{
  //
  // Checks for overlpapping validity regions
  for (Int_t i = 0; i < fEntries; i++) {
    if ((lower >= fLowerLimits[i] && lower <= fUpperLimits[i]) ||
	(upper >= fLowerLimits[i] && upper <= fUpperLimits[i]))
      {
	return (i);
      }
  }
  return (-1);
}

void AliOADBContainer::Browse(TBrowser *b)
{
   // Browse this object.
   // If b=0, there is no Browse call TObject::Browse(0) instead.
   //         This means TObject::Inspect() will be invoked indirectly

  if (b) {
    for (Int_t i = 0; i < fEntries; i++) {
      b->Add(fArray->At(i),Form("%9.9d - %9.9d", fLowerLimits[i], fUpperLimits[i]));
    }
    TIter next(fDefaultList);
    TObject* obj;
    while((obj = next())) b->Add(obj);

  }
   else
      TObject::Browse(b);
}

//______________________________________________________________________________
const char* AliOADBContainer::GetOADBPath()
{
// returns the path of the OADB
// this static function just depends on environment variables

   static TString oadbPath;

   if (gSystem->Getenv("OADB_PATH"))
      oadbPath = gSystem->Getenv("OADB_PATH");
   else if (gSystem->Getenv("ALICE_ROOT"))
      oadbPath.Form("%s/OADB", gSystem->Getenv("ALICE_ROOT"));
   else
   ::Fatal("AliAnalysisManager::GetOADBPath", "Cannot figure out AODB path. Define ALICE_ROOT or OADB_PATH!");
   return oadbPath;
}
<commit_msg>Destructor<commit_after>/**************************************************************************
 * Copyright(c) 1998-2007, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

/* $Id$ */

//-------------------------------------------------------------------------
//     Offline Analysis Database Container and Service Class
//     Author: Andreas Morsch, CERN
//-------------------------------------------------------------------------

#include "AliOADBContainer.h"
#include "AliLog.h"
#include <TObjArray.h>
#include <TArrayI.h>
#include <TFile.h>
#include <TList.h>
#include <TBrowser.h>
#include <TSystem.h>
#include <TError.h>

ClassImp(AliOADBContainer);

//______________________________________________________________________________
AliOADBContainer::AliOADBContainer() :
  TNamed(),
  fArray(0),
  fDefaultList(0),
  fLowerLimits(),
  fUpperLimits(),
  fEntries(0)
{
  // Default constructor
}

AliOADBContainer::AliOADBContainer(const char* name) :
  TNamed(name, "OADBContainer"),
  fArray(new TObjArray(100)),
  fDefaultList(new TList()),
  fLowerLimits(),
  fUpperLimits(),
  fEntries(0)
{
  // Constructor
  if (fArray)       delete fArray;
  if (fDefaultList) delete fDefaultList;
}

//______________________________________________________________________________
AliOADBContainer::~AliOADBContainer()
{
  // destructor
}

//______________________________________________________________________________
AliOADBContainer::AliOADBContainer(const AliOADBContainer& cont) :
  TNamed(cont),
  fArray(cont.fArray),
  fDefaultList(cont.fDefaultList),
  fLowerLimits(cont.fLowerLimits),
  fUpperLimits(cont.fUpperLimits),
  fEntries(cont.fEntries)
{
  // Copy constructor.
}

//______________________________________________________________________________
AliOADBContainer& AliOADBContainer::operator=(const AliOADBContainer& cont)
{
  //
  // Assignment operator
  // Copy objects related to run ranges
  if(this!=&cont) {
    TNamed::operator=(cont);
    fEntries = cont.fEntries;
    fLowerLimits.Set(fEntries);
    fUpperLimits.Set(fEntries);
    for (Int_t i = 0; i < fEntries; i++) {
	fLowerLimits[i] = cont.fLowerLimits[i];
	fUpperLimits[i] = cont.fUpperLimits[i];
	fArray->AddAt(cont.fArray->At(i), i);
    }
  }
  //
  // Copy default objects
  TList* list = cont.GetDefaultList();
  TIter next(list);
  TObject* obj;
  while((obj = next())) fDefaultList->Add(obj);
  //
  return *this;
}

void AliOADBContainer::AppendObject(TObject* obj, Int_t lower, Int_t upper)
{
  //
  // Append a new object to the list
  //
  // Check that there is no overlap with existing run ranges
  Int_t index = HasOverlap(lower, upper);

  if (index != -1) {
    AliFatal(Form("Ambiguos validity range (%5d, %5.5d-%5.5d) !\n", index,lower,upper));
    return;
  }
  //
  // Adjust arrays
  fEntries++;
  fLowerLimits.Set(fEntries);
  fUpperLimits.Set(fEntries);

  // Add the object
  fLowerLimits[fEntries - 1] = lower;
  fUpperLimits[fEntries - 1] = upper;
  fArray->Add(obj);
}

void AliOADBContainer::RemoveObject(Int_t idx)
{
  //
  // Remove object from the list

  //
  // Check that index is inside range
  if (idx < 0 || idx >= fEntries)
    {
      AliError(Form("Index out of Range %5d >= %5d", idx, fEntries));
      return;
    }
  //
  // Remove the object
  TObject* obj = fArray->RemoveAt(idx);
  delete obj;
  //
  // Adjust the run ranges and shrink the array
  for (Int_t i = idx; i < (fEntries-1); i++) {
    fLowerLimits[i] = fLowerLimits[i + 1];
    fUpperLimits[i] = fUpperLimits[i + 1];
    fArray->AddAt(fArray->At(i+1), i);
  }
  fArray->RemoveAt(fEntries - 1);
  fEntries--;
}

void AliOADBContainer::UpdateObject(Int_t idx, TObject* obj, Int_t lower, Int_t upper)
{
  //
  // Update an existing object, at a given position

  // Check that index is inside range
  if (idx < 0 || idx >= fEntries)
    {
      AliError(Form("Index out of Range %5d >= %5d", idx, fEntries));
      return;
    }
  //
  // Remove the old object and reset the range
  //  TObject* obj2 =
  fArray->RemoveAt(idx);
  // don't delete it: if you are updating it may be pointing to the same location of obj...
  //  delete obj2;
  fLowerLimits[idx] = -1;
  fUpperLimits[idx] = -1;
  // Check that there is no overlap with existing run ranges
  Int_t index = HasOverlap(lower, upper);
  if (index != -1) {
    AliFatal(Form("Ambiguos validity range (%5d, %5.5d-%5.5d) !\n", index,lower,upper));
    return;
  }
  //
  // Add object at the same position
  //printf("idx %d obj %llx\n", idx, obj);
  fLowerLimits[idx] = lower;
  fUpperLimits[idx] = upper;
  fArray->AddAt(obj, idx);

}

void  AliOADBContainer::AddDefaultObject(TObject* obj)
{
  // Add a default object
  fDefaultList->Add(obj);
}

void  AliOADBContainer::CleanDefaultList()
{
  // Clean default list
  fDefaultList->Delete();
}

Int_t AliOADBContainer::GetIndexForRun(Int_t run) const
{
  //
  // Find the index for a given run

  Int_t found = 0;
  Int_t index = -1;
  for (Int_t i = 0; i < fEntries; i++)
    {
      if (run >= fLowerLimits[i] && run <= fUpperLimits[i])
	{
	  found++;
	  index = i;
	}
    }

  if (found > 1) {
    AliError(Form("More than one (%5d) object found; return last (%5d) !\n", found, index));
  } else if (index == -1) {
    AliWarning(Form("No object (%s) found for run %5d !\n", GetName(), run));
  }

  return index;
}

TObject* AliOADBContainer::GetObject(Int_t run, const char* def) const
{
  // Return object for given run or default if not found
  TObject* obj = 0;
  Int_t idx = GetIndexForRun(run);
  if (idx == -1) {
    // no object found, try default
    obj = fDefaultList->FindObject(def);
    if (!obj) {
      AliError(Form("Default Object (%s) not found !\n", GetName()));
      return (0);
    } else {
      return (obj);
    }
  } else {
    return (fArray->At(idx));
  }
}

TObject* AliOADBContainer::GetObjectByIndex(Int_t run) const
{
  // Return object for given index
  return (fArray->At(run));
}

void AliOADBContainer::WriteToFile(const char* fname) const
{
  //
  // Write object to file
  TFile* f = new TFile(fname, "update");
  Write();
  f->Purge();
  f->Close();
}

Int_t AliOADBContainer::InitFromFile(const char* fname, const char* key)
{
    //
    // Initialize object from file
    TFile* file = TFile::Open(fname);
    if (!file) return (1);
    AliOADBContainer* cont  = 0;
    file->GetObject(key, cont);
    if (!cont)
    {
      AliError(Form("Object (%s) not found in file \n", GetName()));
	return 1;
    }

    SetName(cont->GetName());
    SetTitle(cont->GetTitle());

    fEntries = cont->GetNumberOfEntries();
    fLowerLimits.Set(fEntries);
    fUpperLimits.Set(fEntries);
    if(fEntries > fArray->GetSize()) fArray->Expand(fEntries);

    for (Int_t i = 0; i < fEntries; i++) {
	fLowerLimits[i] = cont->LowerLimit(i);
	fUpperLimits[i] = cont->UpperLimit(i);
	fArray->AddAt(cont->GetObjectByIndex(i), i);
    }
    if (!fDefaultList) fDefaultList = new TList();
    TIter next(cont->GetDefaultList());
    TObject* obj;
    while((obj = next())) fDefaultList->Add(obj);

    return 0;

}

void AliOADBContainer::List()
{
  //
  // List Objects
  printf("Entries %d\n", fEntries);

  for (Int_t i = 0; i < fEntries; i++) {
    printf("Lower %5d Upper %5d \n", fLowerLimits[i], fUpperLimits[i]);
    (fArray->At(i))->Dump();
  }
  TIter next(fDefaultList);
  TObject* obj;
  while((obj = next())) obj->Dump();

}

Int_t AliOADBContainer::HasOverlap(Int_t lower, Int_t upper) const
{
  //
  // Checks for overlpapping validity regions
  for (Int_t i = 0; i < fEntries; i++) {
    if ((lower >= fLowerLimits[i] && lower <= fUpperLimits[i]) ||
	(upper >= fLowerLimits[i] && upper <= fUpperLimits[i]))
      {
	return (i);
      }
  }
  return (-1);
}

void AliOADBContainer::Browse(TBrowser *b)
{
   // Browse this object.
   // If b=0, there is no Browse call TObject::Browse(0) instead.
   //         This means TObject::Inspect() will be invoked indirectly

  if (b) {
    for (Int_t i = 0; i < fEntries; i++) {
      b->Add(fArray->At(i),Form("%9.9d - %9.9d", fLowerLimits[i], fUpperLimits[i]));
    }
    TIter next(fDefaultList);
    TObject* obj;
    while((obj = next())) b->Add(obj);

  }
   else
      TObject::Browse(b);
}

//______________________________________________________________________________
const char* AliOADBContainer::GetOADBPath()
{
// returns the path of the OADB
// this static function just depends on environment variables

   static TString oadbPath;

   if (gSystem->Getenv("OADB_PATH"))
      oadbPath = gSystem->Getenv("OADB_PATH");
   else if (gSystem->Getenv("ALICE_ROOT"))
      oadbPath.Form("%s/OADB", gSystem->Getenv("ALICE_ROOT"));
   else
   ::Fatal("AliAnalysisManager::GetOADBPath", "Cannot figure out AODB path. Define ALICE_ROOT or OADB_PATH!");
   return oadbPath;
}
<|endoftext|>


<commit_before>// Copyright 2010-2012 RethinkDB, all rights reserved.
#ifndef RDB_PROTOCOL_SERIALIZABLE_ENVIRONMENT_HPP_
#define RDB_PROTOCOL_SERIALIZABLE_ENVIRONMENT_HPP_

#include "rdb_protocol/scope.hpp"

namespace query_language {

enum term_type_t {
    TERM_TYPE_JSON,
    TERM_TYPE_STREAM,
    TERM_TYPE_VIEW,

    // TODO: in the clients errors are just JSON for simplicity.  Maybe we should do that here too?
    /* This is the type of `Error` terms. It's called "arbitrary" because an
    `Error` term can be either a stream or an object. It is a subtype of every
    type. */
    TERM_TYPE_ARBITRARY
};

ARCHIVE_PRIM_MAKE_RANGED_SERIALIZABLE(term_type_t, int8_t, TERM_TYPE_JSON, TERM_TYPE_ARBITRARY);

class term_info_t {
public:
    term_info_t() { }
    term_info_t(term_type_t _type, bool _deterministic)
        : type(_type), deterministic(_deterministic)
    { }

    term_type_t type;
    bool deterministic;

    RDB_DECLARE_ME_SERIALIZABLE;
};

typedef variable_scope_t<term_info_t> variable_type_scope_t;

typedef variable_type_scope_t::new_scope_t new_scope_t;

typedef implicit_value_t<term_info_t> implicit_type_t;

struct type_checking_environment_t {
    variable_type_scope_t scope;
    implicit_type_t implicit_type;

    RDB_DECLARE_ME_SERIALIZABLE;
};

//Implicit value typedef
typedef implicit_value_t<boost::shared_ptr<scoped_cJSON_t> >::impliciter_t implicit_value_setter_t;

/* Wrapper for the scopes in the runtime environment. Makes it convenient to
 * serialize all the in scope variables. */
struct scopes_t {
    type_checking_environment_t type_env;

    implicit_value_t<boost::shared_ptr<scoped_cJSON_t> > implicit_attribute_value;

    RDB_DECLARE_ME_SERIALIZABLE;
};

} //namespace query_language

#endif  // RDB_PROTOCOL_SERIALIZABLE_ENVIRONMENT_HPP_
<commit_msg>Removed unused typedef new_scope_t.<commit_after>// Copyright 2010-2012 RethinkDB, all rights reserved.
#ifndef RDB_PROTOCOL_SERIALIZABLE_ENVIRONMENT_HPP_
#define RDB_PROTOCOL_SERIALIZABLE_ENVIRONMENT_HPP_

#include "rdb_protocol/scope.hpp"

namespace query_language {

enum term_type_t {
    TERM_TYPE_JSON,
    TERM_TYPE_STREAM,
    TERM_TYPE_VIEW,

    // TODO: in the clients errors are just JSON for simplicity.  Maybe we should do that here too?
    /* This is the type of `Error` terms. It's called "arbitrary" because an
    `Error` term can be either a stream or an object. It is a subtype of every
    type. */
    TERM_TYPE_ARBITRARY
};

ARCHIVE_PRIM_MAKE_RANGED_SERIALIZABLE(term_type_t, int8_t, TERM_TYPE_JSON, TERM_TYPE_ARBITRARY);

class term_info_t {
public:
    term_info_t() { }
    term_info_t(term_type_t _type, bool _deterministic)
        : type(_type), deterministic(_deterministic)
    { }

    term_type_t type;
    bool deterministic;

    RDB_DECLARE_ME_SERIALIZABLE;
};

typedef variable_scope_t<term_info_t> variable_type_scope_t;

typedef implicit_value_t<term_info_t> implicit_type_t;

struct type_checking_environment_t {
    variable_type_scope_t scope;
    implicit_type_t implicit_type;

    RDB_DECLARE_ME_SERIALIZABLE;
};

//Implicit value typedef
typedef implicit_value_t<boost::shared_ptr<scoped_cJSON_t> >::impliciter_t implicit_value_setter_t;

/* Wrapper for the scopes in the runtime environment. Makes it convenient to
 * serialize all the in scope variables. */
struct scopes_t {
    type_checking_environment_t type_env;

    implicit_value_t<boost::shared_ptr<scoped_cJSON_t> > implicit_attribute_value;

    RDB_DECLARE_ME_SERIALIZABLE;
};

} //namespace query_language

#endif  // RDB_PROTOCOL_SERIALIZABLE_ENVIRONMENT_HPP_
<|endoftext|>


<commit_before>//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

#include "ForcingFunctionAux.h"
// #include "Function.h" //don't think this is needed but check

registerMooseObject("MooseApp", ForcingFunctionAux);

defineLegacyParams(ForcingFunctionAux); //?

InputParameters
ForcingFunctionAux::validParams()
{
  InputParameters params = FunctionAux::validParams();
  params.addClassDescription("Auxiliary Kernel that adds a forcing function to the value of an "
                             "AuxVariable from the previous time step.");
  return params;
}

ForcingFunctionAux::ForcingFunctionAux(const InputParameters & parameters)
  : FunctionAux(parameters), _u_old(uOld())
{
}

Real
ForcingFunctionAux::computeValue()
{
  if (isNodal())
    mooseError("Must use an elemental AuxVariable for ForcingFunctionAux.");
  else
    return _u_old[_qp] + _dt * _func.value(_t, _q_point[_qp]);
}
<commit_msg>Address PR comments and fix non-unity build failure for ForcingFunctionAux #20065<commit_after>//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

#include "ForcingFunctionAux.h"
#include "Function.h"

registerMooseObject("MooseApp", ForcingFunctionAux);

defineLegacyParams(ForcingFunctionAux); //?

InputParameters
ForcingFunctionAux::validParams()
{
  InputParameters params = FunctionAux::validParams();
  params.addClassDescription("Auxiliary Kernel that adds a forcing function to the value of an "
                             "AuxVariable from the previous time step.");
  return params;
}

ForcingFunctionAux::ForcingFunctionAux(const InputParameters & parameters)
  : FunctionAux(parameters), _u_old(uOld())
{
  if (isNodal())
    paramError("variable", "The variable must be elemental");
}

Real
ForcingFunctionAux::computeValue()
{
  return _u_old[_qp] + _dt * _func.value(_t, _q_point[_qp]);
}
<|endoftext|>


<commit_before>//Compile with:
//gcc -g box_example_02.c -o box_example_02 `pkg-config --cflags --libs elementary`

#ifdef HAVE_CONFIG_H
# include <elementary_config.h>
#endif

#define ELM_INTERNAL_API_ARGESFSDFEFC
#define ELM_INTERFACE_ATSPI_ACCESSIBLE_PROTECTED
#define ELM_INTERFACE_ATSPI_COMPONENT_PROTECTED
#define ELM_INTERFACE_ATSPI_ACTION_PROTECTED
#define ELM_INTERFACE_ATSPI_VALUE_PROTECTED
#define ELM_INTERFACE_ATSPI_EDITABLE_TEXT_PROTECTED
#define ELM_INTERFACE_ATSPI_TEXT_PROTECTED
#define ELM_INTERFACE_ATSPI_SELECTION_PROTECTED
#define ELM_INTERFACE_ATSPI_IMAGE_PROTECTED
#define ELM_INTERFACE_ATSPI_WIDGET_ACTION_PROTECTED

#include <iostream>

#include <Elementary.h>

#include <Eo.h>
#include <Evas.h>
#include <Elementary.h>
#include <elm_widget.h>
#include <elm_interface_atspi_accessible.h>

#include <elm_win.eo.hh>
#include <elm_box.eo.hh>
#include <elm_button.eo.hh>

#include <Eina.hh>

#include <deque>

struct Transitions_Data
{
   efl::eo::wref<elm_box> box;
   std::deque<Evas_Object_Box_Layout> transitions;
   Evas_Object_Box_Layout last_layout;
};

static void
_test_box_transition_change(void *data)
{
   Transitions_Data *tdata = static_cast<Transitions_Data*>(data);
   Elm_Box_Transition *layout_data;
   Evas_Object_Box_Layout next_layout;

   assert (!!data);
   assert (!tdata->transitions.empty());

   if(efl::eina::optional<elm_box> box = tdata->box.lock())
     {
        next_layout = tdata->transitions.front();
        layout_data = elm_box_transition_new(2.0, tdata->transitions.back(),
                                             nullptr, nullptr, next_layout, nullptr, nullptr,
                                             _test_box_transition_change, tdata);
        box->layout_set(elm_box_layout_transition, layout_data,
                        elm_box_transition_free);
        tdata->last_layout = next_layout;

        tdata->transitions.push_back(tdata->transitions[0]);
        tdata->transitions.pop_front();
     }
}

EAPI_MAIN int
elm_main(int argc, char *argv[])
{
   elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED);

   Transitions_Data tdata;
   Eo* test;

   {
     ::elm_win win (elm_win_util_standard_add("box-transition", "Box Transition"));
     win.autodel_set(true);

     elm_box bigbox ( efl::eo::parent = win );
     bigbox.size_hint_weight_set(EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
     win.resize_object_add(bigbox);
     bigbox.visibility_set(true);

     elm_box buttons ( efl::eo::parent = win );
     buttons.horizontal_set(EINA_TRUE);
     bigbox.pack_end(buttons);
     buttons.visibility_set(true);

     elm_button add ( efl::eo::parent = win );
     add.text_set("Add");
     buttons.pack_end(add);
     add.visibility_set(true);
     add.event_clicked_callback_add
       (std::bind([&tdata]
        {
          if(efl::eina::optional<elm_box> box = tdata.box.lock())
          {
            elm_button btn ( efl::eo::parent = *box );
            btn.text_set("I do nothing");
            efl::eina::list<evas::object> childrens = box->children_get();
            if (!childrens.empty())
              {
                box->pack_after(btn, childrens.front());
              }
            else
              box->pack_end(btn);
            btn.visibility_set(true);
          }
        }));

     elm_button clear ( efl::eo::parent = win );
     clear.text_set("Clear");
     buttons.pack_end(clear);
     clear.visibility_set(true);
     clear.event_clicked_callback_add(std::bind([&tdata] { tdata.box.lock()->clear(); }));

     elm_box dynamic ( efl::eo::parent = win );
     dynamic.size_hint_weight_set(EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
     dynamic.size_hint_align_set(EVAS_HINT_FILL, EVAS_HINT_FILL);
     bigbox.pack_end(dynamic);
     dynamic.visibility_set(true);

     auto unpack = std::bind([&tdata] (evas::clickable_interface obj)
       {
         elm_button btn = efl::eo::downcast<elm_button>(obj);
         tdata.box.lock()->unpack(btn);
         btn.position_set(0, 50);
         btn.color_set(128, 64, 0, 128);
       }, std::placeholders::_1)
     ;

     elm_button bt1 ( efl::eo::parent = win );
     bt1.text_set("Button 1");
     bt1.event_clicked_callback_add(unpack);
     bt1.size_hint_weight_set(EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
     bt1.size_hint_align_set(EVAS_HINT_FILL, EVAS_HINT_FILL);
     dynamic.pack_end(bt1);
     bt1.visibility_set(true);

     elm_button bt2 ( efl::eo::parent = win );
     bt2.text_set("Button 2");
     bt2.size_hint_weight_set(EVAS_HINT_EXPAND, 0.0);
     bt2.size_hint_align_set(1.0, 0.5);
     bt2.event_clicked_callback_add(unpack);
     dynamic.pack_end(bt2);
     bt2.visibility_set(true);

     elm_button bt3 ( efl::eo::parent = win );
     bt3.text_set("Button 3");
     bt3.event_clicked_callback_add(unpack);
     dynamic.pack_end(bt3);
     bt3.visibility_set(true);

     tdata.box = dynamic;
     tdata.last_layout = evas_object_box_layout_horizontal;
     tdata.transitions.push_back(evas_object_box_layout_vertical);
     tdata.transitions.push_back(evas_object_box_layout_horizontal);
     tdata.transitions.push_back(evas_object_box_layout_stack);
     tdata.transitions.push_back(evas_object_box_layout_homogeneous_vertical);
     tdata.transitions.push_back(evas_object_box_layout_homogeneous_horizontal);
     tdata.transitions.push_back(evas_object_box_layout_flow_vertical);
     tdata.transitions.push_back(evas_object_box_layout_flow_horizontal);
     tdata.transitions.push_back(evas_object_box_layout_stack);

     dynamic.layout_set(evas_object_box_layout_horizontal, nullptr, nullptr);
     _test_box_transition_change(&tdata);

     win.size_set(300, 320);
     win.visibility_set(true);

     // bigbox._release();
     // buttons._release();
     // add._release();
     // clear._release();
     // dynamic._release();
     // bt1._release();
     // bt2._release();
     // bt3._release();

     std::cout << "references to win " << win.ref_get() << std::endl;
     test = win._eo_ptr();
     //win._release();
   }
   std::cout << "references to win " << ::eo_ref_get(test) << std::endl;

   elm_run();
   elm_shutdown();

   return 0;
}
ELM_MAIN()
<commit_msg>c++: Added workaround for correct unref times<commit_after>//Compile with:
//gcc -g box_example_02.c -o box_example_02 `pkg-config --cflags --libs elementary`

#ifdef HAVE_CONFIG_H
# include <elementary_config.h>
#endif

#define ELM_INTERNAL_API_ARGESFSDFEFC
#define ELM_INTERFACE_ATSPI_ACCESSIBLE_PROTECTED
#define ELM_INTERFACE_ATSPI_COMPONENT_PROTECTED
#define ELM_INTERFACE_ATSPI_ACTION_PROTECTED
#define ELM_INTERFACE_ATSPI_VALUE_PROTECTED
#define ELM_INTERFACE_ATSPI_EDITABLE_TEXT_PROTECTED
#define ELM_INTERFACE_ATSPI_TEXT_PROTECTED
#define ELM_INTERFACE_ATSPI_SELECTION_PROTECTED
#define ELM_INTERFACE_ATSPI_IMAGE_PROTECTED
#define ELM_INTERFACE_ATSPI_WIDGET_ACTION_PROTECTED

#include <iostream>

#include <Elementary.h>

#include <Eo.h>
#include <Evas.h>
#include <Elementary.h>
#include <elm_widget.h>
#include <elm_interface_atspi_accessible.h>

#include <elm_win.eo.hh>
#include <elm_box.eo.hh>
#include <elm_button.eo.hh>

#include <Eina.hh>

#include <deque>

struct Transitions_Data
{
   efl::eo::wref<elm_box> box;
   std::deque<Evas_Object_Box_Layout> transitions;
   Evas_Object_Box_Layout last_layout;
};

static void
_test_box_transition_change(void *data)
{
   Transitions_Data *tdata = static_cast<Transitions_Data*>(data);
   Elm_Box_Transition *layout_data;
   Evas_Object_Box_Layout next_layout;

   assert (!!data);
   assert (!tdata->transitions.empty());

   if(efl::eina::optional<elm_box> box = tdata->box.lock())
     {
        next_layout = tdata->transitions.front();
        layout_data = elm_box_transition_new(2.0, tdata->transitions.back(),
                                             nullptr, nullptr, next_layout, nullptr, nullptr,
                                             _test_box_transition_change, tdata);
        box->layout_set(elm_box_layout_transition, layout_data,
                        elm_box_transition_free);
        tdata->last_layout = next_layout;

        tdata->transitions.push_back(tdata->transitions[0]);
        tdata->transitions.pop_front();
     }
}

EAPI_MAIN int
elm_main(int argc, char *argv[])
{
   elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED);

   Transitions_Data tdata;
   Eo* test;

   {
     ::elm_win win (elm_win_util_standard_add("box-transition", "Box Transition"));
     win.autodel_set(true);

     elm_box bigbox ( efl::eo::parent = win );
     ::eo_unref(bigbox._eo_ptr());
     bigbox.size_hint_weight_set(EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
     win.resize_object_add(bigbox);
     bigbox.visibility_set(true);

     elm_box buttons ( efl::eo::parent = win );
     ::eo_unref(buttons._eo_ptr());
     buttons.horizontal_set(EINA_TRUE);
     bigbox.pack_end(buttons);
     buttons.visibility_set(true);

     elm_button add ( efl::eo::parent = win );
     ::eo_unref(add._eo_ptr());
     add.text_set("Add");
     buttons.pack_end(add);
     add.visibility_set(true);
     add.event_clicked_callback_add
       (std::bind([&tdata]
        {
          if(efl::eina::optional<elm_box> box = tdata.box.lock())
          {
            elm_button btn ( efl::eo::parent = *box );
            btn.text_set("I do nothing");
            efl::eina::list<evas::object> childrens = box->children_get();
            if (!childrens.empty())
              {
                box->pack_after(btn, childrens.front());
              }
            else
              box->pack_end(btn);
            btn.visibility_set(true);
          }
        }));

     elm_button clear ( efl::eo::parent = win );
     ::eo_unref(clear._eo_ptr());
     clear.text_set("Clear");
     buttons.pack_end(clear);
     clear.visibility_set(true);
     clear.event_clicked_callback_add(std::bind([&tdata] { tdata.box.lock()->clear(); }));

     elm_box dynamic ( efl::eo::parent = win );
     ::eo_unref(dynamic._eo_ptr());
     dynamic.size_hint_weight_set(EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
     dynamic.size_hint_align_set(EVAS_HINT_FILL, EVAS_HINT_FILL);
     bigbox.pack_end(dynamic);
     dynamic.visibility_set(true);

     auto unpack = std::bind([&tdata] (evas::clickable_interface obj)
       {
         elm_button btn = efl::eo::downcast<elm_button>(obj);
         tdata.box.lock()->unpack(btn);
         btn.position_set(0, 50);
         btn.color_set(128, 64, 0, 128);
       }, std::placeholders::_1)
     ;

     elm_button bt1 ( efl::eo::parent = win );
     ::eo_unref(bt1._eo_ptr());
     bt1.text_set("Button 1");
     bt1.event_clicked_callback_add(unpack);
     bt1.size_hint_weight_set(EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
     bt1.size_hint_align_set(EVAS_HINT_FILL, EVAS_HINT_FILL);
     dynamic.pack_end(bt1);
     bt1.visibility_set(true);

     elm_button bt2 ( efl::eo::parent = win );
     ::eo_unref(bt2._eo_ptr());
     bt2.text_set("Button 2");
     bt2.size_hint_weight_set(EVAS_HINT_EXPAND, 0.0);
     bt2.size_hint_align_set(1.0, 0.5);
     bt2.event_clicked_callback_add(unpack);
     dynamic.pack_end(bt2);
     bt2.visibility_set(true);

     elm_button bt3 ( efl::eo::parent = win );
     ::eo_unref(bt3._eo_ptr());
     bt3.text_set("Button 3");
     bt3.event_clicked_callback_add(unpack);
     dynamic.pack_end(bt3);
     bt3.visibility_set(true);

     tdata.box = dynamic;
     tdata.last_layout = evas_object_box_layout_horizontal;
     tdata.transitions.push_back(evas_object_box_layout_vertical);
     tdata.transitions.push_back(evas_object_box_layout_horizontal);
     tdata.transitions.push_back(evas_object_box_layout_stack);
     tdata.transitions.push_back(evas_object_box_layout_homogeneous_vertical);
     tdata.transitions.push_back(evas_object_box_layout_homogeneous_horizontal);
     tdata.transitions.push_back(evas_object_box_layout_flow_vertical);
     tdata.transitions.push_back(evas_object_box_layout_flow_horizontal);
     tdata.transitions.push_back(evas_object_box_layout_stack);

     dynamic.layout_set(evas_object_box_layout_horizontal, nullptr, nullptr);
     _test_box_transition_change(&tdata);

     win.size_set(300, 320);
     win.visibility_set(true);

     std::cout << "references to win " << win.ref_get() << std::endl;
     test = win._eo_ptr();
     win._release();
   }
   std::cout << "references to win " << ::eo_ref_get(test) << std::endl;

   elm_run();
   elm_shutdown();

   return 0;
}
ELM_MAIN()
<|endoftext|>


<commit_before>//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

#include "StackGenerator.h"
#include "CastUniquePointer.h"

#include "libmesh/replicated_mesh.h"
#include "libmesh/distributed_mesh.h"
#include "libmesh/boundary_info.h"
#include "libmesh/mesh_modification.h"
#include "libmesh/bounding_box.h"
#include "libmesh/mesh_tools.h"
#include "libmesh/point.h"

#include <typeinfo>

registerMooseObject("MooseApp", StackGenerator);

template <>
InputParameters
validParams<StackGenerator>()
{
  InputParameters params = validParams<MeshGenerator>();

  MooseEnum dims("2=2 3=3");
  params.addRequiredParam<MooseEnum>("dim", dims, "The dimension of the mesh to be generated");

  params.addRequiredParam<std::vector<MeshGeneratorName>>("inputs",
                                                          "The meshes we want to stitch together");

  params.addParam<Real>("bottom_height", 0, "The height of the bottom of the final mesh");

  // y boundary names (2D case)
  params.addParam<BoundaryName>("top_boundary", "top", "name of the top (y) boundary");
  params.addParam<BoundaryName>("bottom_boundary", "bottom", "name of the bottom (y) boundary");

  // z boundary names (3D case)
  params.addParam<BoundaryName>("front_boundary", "front", "name of the front (z) boundary");
  params.addParam<BoundaryName>("back_boundary", "back", "name of the back (z) boundary");

  params.addClassDescription("Use the supplied meshes and stitch them on top of each other");

  return params;
}

StackGenerator::StackGenerator(const InputParameters & parameters)
  : MeshGenerator(parameters),
    _dim(getParam<MooseEnum>("dim")),
    _input_names(getParam<std::vector<MeshGeneratorName>>("inputs")),
    _bottom_height(getParam<Real>("bottom_height"))
{
  // Grab the input meshes
  _mesh_ptrs.reserve(_input_names.size());
  for (auto i = beginIndex(_input_names); i < _input_names.size(); ++i)
    _mesh_ptrs.push_back(&getMeshByName(_input_names[i]));
}

std::unique_ptr<MeshBase>
StackGenerator::generate()
{
  std::unique_ptr<ReplicatedMesh> mesh = dynamic_pointer_cast<ReplicatedMesh>(*_mesh_ptrs[0]);
  if (mesh == nullptr)
    mooseError("StackGenerator only works with ReplicatedMesh : mesh from Meshgenerator ",
               _input_names[0],
               "is not a ReplicatedMesh.");

  int dim = static_cast<int>(_dim);

  if (dim != int(mesh->mesh_dimension()))
    mooseError("The first mesh's dimension and the dimension provided don't match !");

  // Reserve spaces for the other meshes (no need to store the first one another time)
  _meshes.reserve(_input_names.size() - 1);

  // Read in all of the other meshes
  for (auto i = beginIndex(_input_names, 1); i < _input_names.size(); ++i)
    _meshes.push_back(dynamic_pointer_cast<ReplicatedMesh>(*_mesh_ptrs[i]));

  // Check that the casts didn't fail, and that the dimensions match
  for (auto i = beginIndex(_meshes); i < _meshes.size(); ++i)
  {
    if (_meshes[i] == nullptr)
      mooseError("StackGenerator only works with ReplicatedMesh : mesh from Meshgenerator ",
                 _input_names[i + 1],
                 "is not a ReplicatedMesh.");
    if (int(_meshes[i]->mesh_dimension()) != dim)
      mooseError("Mesh from MeshGenerator : ", _input_names[i + 1], " is not in ", _dim, "D.");
  }

  boundary_id_type first, second;

  switch (_dim)
  {
    case 2:
    {
      first = mesh->get_boundary_info().get_id_by_name(getParam<BoundaryName>("top_boundary"));
      second = mesh->get_boundary_info().get_id_by_name(getParam<BoundaryName>("bottom_boundary"));
      break;
    }
    case 3:
    {
      first = mesh->get_boundary_info().get_id_by_name(getParam<BoundaryName>("front_boundary"));
      second = mesh->get_boundary_info().get_id_by_name(getParam<BoundaryName>("back_boundary"));
      break;
    }
  }

  // Getting the z width of each mesh
  std::vector<Real> heights;
  heights.push_back(computeWidth(*mesh, _dim) + _bottom_height);
  for (auto i = beginIndex(_meshes); i < _meshes.size(); ++i)
    heights.push_back(computeWidth(*_meshes[i], _dim) + *heights.rbegin());

  switch (_dim)
  {
    case 2:
      MeshTools::Modification::translate(*mesh, 0, _bottom_height, 0);
      break;
    case 3:
      MeshTools::Modification::translate(*mesh, 0, 0, _bottom_height);
      break;
  }

  for (auto i = beginIndex(_meshes); i < _meshes.size(); ++i)
  {
    switch (_dim)
    {
      case 2:
        MeshTools::Modification::translate(*_meshes[i], 0, heights[i], 0);
        break;
      case 3:
        MeshTools::Modification::translate(*_meshes[i], 0, 0, heights[i]);
        break;
    }
    mesh->stitch_meshes(
        *_meshes[i], first, second, TOLERANCE, /*clear_stitched_boundary_ids=*/true);
  }

  return dynamic_pointer_cast<MeshBase>(mesh);
}

Real
StackGenerator::computeWidth(const MeshBase & mesh, const int & dim)
{
  std::set<subdomain_id_type> sub_ids;
  mesh.subdomain_ids(sub_ids);
  BoundingBox bbox(Point(std::numeric_limits<Real>::max(),
                         std::numeric_limits<Real>::max(),
                         std::numeric_limits<Real>::max()),
                   Point(std::numeric_limits<Real>::lowest(),
                         std::numeric_limits<Real>::lowest(),
                         std::numeric_limits<Real>::lowest()));
  for (auto id : sub_ids)
  {
    BoundingBox sub_bbox = MeshTools::create_subdomain_bounding_box(mesh, id);
    bbox.union_with(sub_bbox);
  }

  return bbox.max()(dim - 1) - bbox.min()(dim - 1);
}
<commit_msg>Change the boundary ids initialization.<commit_after>//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

#include "StackGenerator.h"
#include "CastUniquePointer.h"

#include "libmesh/replicated_mesh.h"
#include "libmesh/distributed_mesh.h"
#include "libmesh/boundary_info.h"
#include "libmesh/mesh_modification.h"
#include "libmesh/bounding_box.h"
#include "libmesh/mesh_tools.h"
#include "libmesh/point.h"

#include <typeinfo>

registerMooseObject("MooseApp", StackGenerator);

template <>
InputParameters
validParams<StackGenerator>()
{
  InputParameters params = validParams<MeshGenerator>();

  MooseEnum dims("2=2 3=3");
  params.addRequiredParam<MooseEnum>("dim", dims, "The dimension of the mesh to be generated");

  params.addRequiredParam<std::vector<MeshGeneratorName>>("inputs",
                                                          "The meshes we want to stitch together");

  params.addParam<Real>("bottom_height", 0, "The height of the bottom of the final mesh");

  // y boundary names (2D case)
  params.addParam<BoundaryName>("top_boundary", "top", "name of the top (y) boundary");
  params.addParam<BoundaryName>("bottom_boundary", "bottom", "name of the bottom (y) boundary");

  // z boundary names (3D case)
  params.addParam<BoundaryName>("front_boundary", "front", "name of the front (z) boundary");
  params.addParam<BoundaryName>("back_boundary", "back", "name of the back (z) boundary");

  params.addClassDescription("Use the supplied meshes and stitch them on top of each other");

  return params;
}

StackGenerator::StackGenerator(const InputParameters & parameters)
  : MeshGenerator(parameters),
    _dim(getParam<MooseEnum>("dim")),
    _input_names(getParam<std::vector<MeshGeneratorName>>("inputs")),
    _bottom_height(getParam<Real>("bottom_height"))
{
  // Grab the input meshes
  _mesh_ptrs.reserve(_input_names.size());
  for (auto i = beginIndex(_input_names); i < _input_names.size(); ++i)
    _mesh_ptrs.push_back(&getMeshByName(_input_names[i]));
}

std::unique_ptr<MeshBase>
StackGenerator::generate()
{
  std::unique_ptr<ReplicatedMesh> mesh = dynamic_pointer_cast<ReplicatedMesh>(*_mesh_ptrs[0]);
  if (mesh == nullptr)
    mooseError("StackGenerator only works with ReplicatedMesh : mesh from Meshgenerator ",
               _input_names[0],
               "is not a ReplicatedMesh.");

  int dim = static_cast<int>(_dim);

  if (dim != int(mesh->mesh_dimension()))
    mooseError("The first mesh's dimension and the dimension provided don't match !");

  // Reserve spaces for the other meshes (no need to store the first one another time)
  _meshes.reserve(_input_names.size() - 1);

  // Read in all of the other meshes
  for (auto i = beginIndex(_input_names, 1); i < _input_names.size(); ++i)
    _meshes.push_back(dynamic_pointer_cast<ReplicatedMesh>(*_mesh_ptrs[i]));

  // Check that the casts didn't fail, and that the dimensions match
  for (auto i = beginIndex(_meshes); i < _meshes.size(); ++i)
  {
    if (_meshes[i] == nullptr)
      mooseError("StackGenerator only works with ReplicatedMesh : mesh from Meshgenerator ",
                 _input_names[i + 1],
                 "is not a ReplicatedMesh.");
    if (int(_meshes[i]->mesh_dimension()) != dim)
      mooseError("Mesh from MeshGenerator : ", _input_names[i + 1], " is not in ", _dim, "D.");
  }

  boundary_id_type first =
      mesh->get_boundary_info().get_id_by_name(getParam<BoundaryName>("top_boundary"));
  boundary_id_type second =
      mesh->get_boundary_info().get_id_by_name(getParam<BoundaryName>("bottom_boundary"));

  if (dim == 3)
  {
    first = mesh->get_boundary_info().get_id_by_name(getParam<BoundaryName>("front_boundary"));
    second = mesh->get_boundary_info().get_id_by_name(getParam<BoundaryName>("back_boundary"));
  }

  // Getting the width of each mesh
  std::vector<Real> heights;
  heights.push_back(computeWidth(*mesh, _dim) + _bottom_height);
  for (auto i = beginIndex(_meshes); i < _meshes.size(); ++i)
    heights.push_back(computeWidth(*_meshes[i], _dim) + *heights.rbegin());

  // Move the first mesh at the provided height
  switch (_dim)
  {
    case 2:
      MeshTools::Modification::translate(*mesh, 0, _bottom_height, 0);
      break;
    case 3:
      MeshTools::Modification::translate(*mesh, 0, 0, _bottom_height);
      break;
  }

  // Move all of the other meshes in the right spots then stitch them one by one to the first one
  for (auto i = beginIndex(_meshes); i < _meshes.size(); ++i)
  {
    switch (_dim)
    {
      case 2:
        MeshTools::Modification::translate(*_meshes[i], 0, heights[i], 0);
        break;
      case 3:
        MeshTools::Modification::translate(*_meshes[i], 0, 0, heights[i]);
        break;
    }
    mesh->stitch_meshes(
        *_meshes[i], first, second, TOLERANCE, /*clear_stitched_boundary_ids=*/true);
  }

  return dynamic_pointer_cast<MeshBase>(mesh);
}

Real
StackGenerator::computeWidth(const MeshBase & mesh, const int & dim)
{
  std::set<subdomain_id_type> sub_ids;
  mesh.subdomain_ids(sub_ids);
  BoundingBox bbox(Point(std::numeric_limits<Real>::max(),
                         std::numeric_limits<Real>::max(),
                         std::numeric_limits<Real>::max()),
                   Point(std::numeric_limits<Real>::lowest(),
                         std::numeric_limits<Real>::lowest(),
                         std::numeric_limits<Real>::lowest()));
  for (auto id : sub_ids)
  {
    BoundingBox sub_bbox = MeshTools::create_subdomain_bounding_box(mesh, id);
    bbox.union_with(sub_bbox);
  }

  return bbox.max()(dim - 1) - bbox.min()(dim - 1);
}
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/phy/phy_cntrl.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file phy_cntrl.C
/// @brief Subroutines for the PHY PC registers
///
// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 2
// *HWP Consumed by: FSP:HB

#include <fapi2.H>
#include <lib/phy/phy_cntrl.H>
#include <lib/utils/scom.H>
#include <lib/utils/c_str.H>
#include <lib/utils/index.H>

#include <lib/mss_attribute_accessors.H>

using fapi2::TARGET_TYPE_MCA;

namespace mss
{

namespace pc
{

///
/// @brief Reset the PC CONFIG0 register
/// @param[in] i_target the target (MCA or MBA?)
/// @return FAPI2_RC_SUCCESS if and only if ok
///
template<>
fapi2::ReturnCode reset_config0(const fapi2::Target<TARGET_TYPE_MCA>& i_target)
{
    typedef pcTraits<TARGET_TYPE_MCA> TT;

    fapi2::buffer<uint64_t> l_data;

    l_data.setBit<TT::DDR4_CMD_SIG_REDUCTION>();
    l_data.setBit<TT::DDR4_VLEVEL_BANK_GROUP>();

    FAPI_TRY( write_config0(i_target, l_data) );

fapi_try_exit:
    return fapi2::current_err;
}

///
/// @brief Reset the PC CONFIG1 register
/// @param[in] i_target <the target (MCA or MBA?)
/// @return FAPI2_RC_SUCCESS if and only if ok
///
template<>
fapi2::ReturnCode reset_config1(const fapi2::Target<TARGET_TYPE_MCA>& i_target)
{
    typedef pcTraits<TARGET_TYPE_MCA> TT;

    // Static table of PHY config values for MEMORY_TYPE.
    // [EMPTY, RDIMM, CDIMM, or LRDIMM][EMPTY, DDR3 or DDR4]
    constexpr uint64_t memory_type[4][3] =
    {
        { 0, 0,     0     },  // Empty, never really used.
        { 0, 0b001, 0b101 },  // RDIMM
        { 0, 0b000, 0b000 },  // CDIMM bits, UDIMM enum (placeholder, never used on Nimbus)
        { 0, 0b011, 0b111 },  // LRDIMM
    };

    fapi2::buffer<uint64_t> l_data;

    uint8_t l_rlo = 0;
    uint8_t l_wlo = 0;
    uint8_t l_dram_gen[MAX_DIMM_PER_PORT]    = {0};
    uint8_t l_dimm_type[MAX_DIMM_PER_PORT]   = {0};
    uint8_t l_type_index = 0;
    uint8_t l_gen_index = 0;

    FAPI_TRY( mss::vpd_mr_dphy_rlo(i_target, l_rlo) );
    FAPI_TRY( mss::vpd_mr_dphy_wlo(i_target, l_wlo) );
    FAPI_TRY( mss::eff_dram_gen(i_target, &(l_dram_gen[0])) );
    FAPI_TRY( mss::eff_dimm_type(i_target, &(l_dimm_type[0])) );

    // There's no way to configure the PHY for more than one value. However, we don't know if there's
    // a DIMM in one slot, the other or double drop. So we do a little gyration here to make sure
    // we have one of the two values (and assume effective config caught a bad config)
    l_type_index = l_dimm_type[0] | l_dimm_type[1];
    l_gen_index = l_dram_gen[0] | l_dram_gen[1];

    // FOR NIMBUS PHY (as the protocol choice above is) BRS
    FAPI_TRY( mss::getScom(i_target, MCA_DDRPHY_PC_CONFIG1_P0, l_data) );

    l_data.insertFromRight<TT::MEMORY_TYPE, TT::MEMORY_TYPE_LEN>(memory_type[l_type_index][l_gen_index]);
    l_data.insertFromRight<TT::READ_LATENCY_OFFSET, TT::READ_LATENCY_OFFSET_LEN>(l_rlo);
    l_data.insertFromRight<TT::WRITE_LATENCY_OFFSET, TT::WRITE_LATENCY_OFFSET_LEN>(l_wlo);

    // Always set this bit. It forces the PHY to use A12 when figuring out latency. This makes sense in
    // all cases as A12 is 0 for non-3DS in MR0.
    l_data.setBit<TT::DDR4_LATENCY_SW>();

    FAPI_TRY( write_config1(i_target, l_data) );

fapi_try_exit:
    return fapi2::current_err;
}

} // close namespace pc
} // close namespace mss
<commit_msg>Update mss_decode_shadow_regs to use library MRS decoders<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/phy/phy_cntrl.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file phy_cntrl.C
/// @brief Subroutines for the PHY PC registers
///
// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 2
// *HWP Consumed by: FSP:HB

#include <fapi2.H>
#include <lib/phy/phy_cntrl.H>
#include <lib/utils/scom.H>
#include <lib/utils/c_str.H>
#include <lib/utils/index.H>

#include <lib/mss_attribute_accessors.H>

using fapi2::TARGET_TYPE_MCA;

namespace mss
{

// Definition of the PHY PC MR shadow registers
// indexed by [rank_pair][MR index]
const std::vector< std::vector<uint64_t> > pcTraits<TARGET_TYPE_MCA>::PC_MR_SHADOW_REGS =
{
    {
        MCA_DDRPHY_PC_MR0_PRI_RP0_P0,
        MCA_DDRPHY_PC_MR1_PRI_RP0_P0,
        MCA_DDRPHY_PC_MR2_PRI_RP0_P0,
        MCA_DDRPHY_PC_MR3_PRI_RP0_P0,
        MCA_DDRPHY_PC_MR0_SEC_RP0_P0,
        MCA_DDRPHY_PC_MR1_SEC_RP0_P0,
        MCA_DDRPHY_PC_MR2_SEC_RP0_P0,
    },
    {
        MCA_DDRPHY_PC_MR0_PRI_RP1_P0,
        MCA_DDRPHY_PC_MR1_PRI_RP1_P0,
        MCA_DDRPHY_PC_MR2_PRI_RP1_P0,
        MCA_DDRPHY_PC_MR3_PRI_RP1_P0,
        MCA_DDRPHY_PC_MR0_SEC_RP1_P0,
        MCA_DDRPHY_PC_MR1_SEC_RP1_P0,
        MCA_DDRPHY_PC_MR2_SEC_RP1_P0,
    },
    {
        MCA_DDRPHY_PC_MR0_PRI_RP2_P0,
        MCA_DDRPHY_PC_MR1_PRI_RP2_P0,
        MCA_DDRPHY_PC_MR2_PRI_RP2_P0,
        MCA_DDRPHY_PC_MR3_PRI_RP2_P0,
        MCA_DDRPHY_PC_MR0_SEC_RP2_P0,
        MCA_DDRPHY_PC_MR1_SEC_RP2_P0,
        MCA_DDRPHY_PC_MR2_SEC_RP2_P0,
    },
    {
        MCA_DDRPHY_PC_MR0_PRI_RP3_P0,
        MCA_DDRPHY_PC_MR1_PRI_RP3_P0,
        MCA_DDRPHY_PC_MR2_PRI_RP3_P0,
        MCA_DDRPHY_PC_MR3_PRI_RP3_P0,
        MCA_DDRPHY_PC_MR0_SEC_RP3_P0,
        MCA_DDRPHY_PC_MR1_SEC_RP3_P0,
        MCA_DDRPHY_PC_MR2_SEC_RP3_P0,
    },
};

namespace pc
{

///
/// @brief Reset the PC CONFIG0 register
/// @param[in] i_target the target (MCA or MBA?)
/// @return FAPI2_RC_SUCCESS if and only if ok
///
template<>
fapi2::ReturnCode reset_config0(const fapi2::Target<TARGET_TYPE_MCA>& i_target)
{
    typedef pcTraits<TARGET_TYPE_MCA> TT;

    fapi2::buffer<uint64_t> l_data;

    l_data.setBit<TT::DDR4_CMD_SIG_REDUCTION>();
    l_data.setBit<TT::DDR4_VLEVEL_BANK_GROUP>();

    FAPI_TRY( write_config0(i_target, l_data) );

fapi_try_exit:
    return fapi2::current_err;
}

///
/// @brief Reset the PC CONFIG1 register
/// @param[in] i_target <the target (MCA or MBA?)
/// @return FAPI2_RC_SUCCESS if and only if ok
///
template<>
fapi2::ReturnCode reset_config1(const fapi2::Target<TARGET_TYPE_MCA>& i_target)
{
    typedef pcTraits<TARGET_TYPE_MCA> TT;

    // Static table of PHY config values for MEMORY_TYPE.
    // [EMPTY, RDIMM, CDIMM, or LRDIMM][EMPTY, DDR3 or DDR4]
    constexpr uint64_t memory_type[4][3] =
    {
        { 0, 0,     0     },  // Empty, never really used.
        { 0, 0b001, 0b101 },  // RDIMM
        { 0, 0b000, 0b000 },  // CDIMM bits, UDIMM enum (placeholder, never used on Nimbus)
        { 0, 0b011, 0b111 },  // LRDIMM
    };

    fapi2::buffer<uint64_t> l_data;

    uint8_t l_rlo = 0;
    uint8_t l_wlo = 0;
    uint8_t l_dram_gen[MAX_DIMM_PER_PORT]    = {0};
    uint8_t l_dimm_type[MAX_DIMM_PER_PORT]   = {0};
    uint8_t l_type_index = 0;
    uint8_t l_gen_index = 0;

    FAPI_TRY( mss::vpd_mr_dphy_rlo(i_target, l_rlo) );
    FAPI_TRY( mss::vpd_mr_dphy_wlo(i_target, l_wlo) );
    FAPI_TRY( mss::eff_dram_gen(i_target, &(l_dram_gen[0])) );
    FAPI_TRY( mss::eff_dimm_type(i_target, &(l_dimm_type[0])) );

    // There's no way to configure the PHY for more than one value. However, we don't know if there's
    // a DIMM in one slot, the other or double drop. So we do a little gyration here to make sure
    // we have one of the two values (and assume effective config caught a bad config)
    l_type_index = l_dimm_type[0] | l_dimm_type[1];
    l_gen_index = l_dram_gen[0] | l_dram_gen[1];

    // FOR NIMBUS PHY (as the protocol choice above is) BRS
    FAPI_TRY( mss::getScom(i_target, MCA_DDRPHY_PC_CONFIG1_P0, l_data) );

    l_data.insertFromRight<TT::MEMORY_TYPE, TT::MEMORY_TYPE_LEN>(memory_type[l_type_index][l_gen_index]);
    l_data.insertFromRight<TT::READ_LATENCY_OFFSET, TT::READ_LATENCY_OFFSET_LEN>(l_rlo);
    l_data.insertFromRight<TT::WRITE_LATENCY_OFFSET, TT::WRITE_LATENCY_OFFSET_LEN>(l_wlo);

    // Always set this bit. It forces the PHY to use A12 when figuring out latency. This makes sense in
    // all cases as A12 is 0 for non-3DS in MR0.
    l_data.setBit<TT::DDR4_LATENCY_SW>();

    FAPI_TRY( write_config1(i_target, l_data) );

fapi_try_exit:
    return fapi2::current_err;
}

} // close namespace pc
} // close namespace mss
<|endoftext|>


<commit_before>/*
 * Simple cache model for predicting miss rates.
 *
 * By Eric Anger <eanger@lanl.gov>
 */

#include <algorithm>
#include <iterator>

#include "byfl.h"

namespace bytesflops {}
using namespace bytesflops;
using namespace std;

class Cache {
  public:
    void access(uint64_t baseaddr, uint64_t numaddrs);
    Cache(uint64_t line_size) : line_size_{line_size}, accesses_{0} {}
    uint64_t getAccesses() const { return accesses_; }
    vector<uint64_t> getHits() const { return hits_; }

  private:
    vector<uint64_t> lines_; // back is mru, front is lru
    uint64_t line_size_;
    uint64_t accesses_;
    vector<uint64_t> hits_;  // back is lru, front is mru
};

void Cache::access(uint64_t baseaddr, uint64_t numaddrs){
  uint64_t num_accesses = 0; // running total of number of lines accessed
  for(uint64_t addr = baseaddr / line_size_ * line_size_;
      addr <= (baseaddr + numaddrs ) / line_size_ * line_size_;
      addr += line_size_){
    ++num_accesses;
    auto line = lines_.rbegin();
    auto hit = begin(hits_);
    bool found = false;
    for(; line != lines_.rend(); ++line, ++hit){
      if(addr == *line){
        found = true;
        ++(*hit);
        // erase the line pointed to by this reverse iterator. see
        // stackoverflow.com/questions/1830158/how-to-call-erase-with-a-reverse-iterator
        lines_.erase((line + 1).base());
        break;
      }
    }

    if(!found){
      // make a new entry containing all previous hits plus any that occur
      // this time
      hits_.push_back(1); ////TODO I think this is the broke part. Should just be one?
    }

    // move up this address to mru position
    lines_.push_back(addr);
  }

  // we've made all our accesses
  accesses_ += num_accesses;
}

static Cache* cache = NULL;

namespace bytesflops{

void initialize_cache(void){
  cache = new Cache(bf_line_size);
}

// Access the cache model with this address.
void bf_touch_cache(uint64_t baseaddr, uint64_t numaddrs){
  cache->access(baseaddr, numaddrs);
}

// Get cache accesses
uint64_t bf_get_cache_accesses(void){
  return cache->getAccesses();
}

// Get cache hits
vector<uint64_t> bf_get_cache_hits(void){
  // The total hits to a cache size N is equal to the sum of unique hits to
  // all caches sized N or smaller.
  auto hits = cache->getHits();
  vector<uint64_t> tot_hits(hits.size());
  uint64_t prev_hits = 0;
  for(uint64_t i = 0; i < hits.size(); ++i){
    tot_hits[i] = hits[i] + prev_hits;
    prev_hits = tot_hits[i];
  }
  return tot_hits;
}

} // namespace bytesflops
<commit_msg>Deduct cold misses from reported total hits.<commit_after>/*
 * Simple cache model for predicting miss rates.
 *
 * By Eric Anger <eanger@lanl.gov>
 */

#include <algorithm>
#include <iterator>

#include "byfl.h"

namespace bytesflops {}
using namespace bytesflops;
using namespace std;

class Cache {
  public:
    void access(uint64_t baseaddr, uint64_t numaddrs);
    Cache(uint64_t line_size) : line_size_{line_size}, accesses_{0},
      cold_misses_{0} {}
    uint64_t getAccesses() const { return accesses_; }
    vector<uint64_t> getHits() const { return hits_; }
    uint64_t getColdMisses() const { return cold_misses_; }

  private:
    vector<uint64_t> lines_; // back is mru, front is lru
    uint64_t line_size_;
    uint64_t accesses_;
    uint64_t cold_misses_;
    vector<uint64_t> hits_;  // back is lru, front is mru
};

void Cache::access(uint64_t baseaddr, uint64_t numaddrs){
  uint64_t num_accesses = 0; // running total of number of lines accessed
  for(uint64_t addr = baseaddr / line_size_ * line_size_;
      addr <= (baseaddr + numaddrs ) / line_size_ * line_size_;
      addr += line_size_){
    ++num_accesses;
    auto line = lines_.rbegin();
    auto hit = begin(hits_);
    bool found = false;
    for(; line != lines_.rend(); ++line, ++hit){
      if(addr == *line){
        found = true;
        ++(*hit);
        // erase the line pointed to by this reverse iterator. see
        // stackoverflow.com/questions/1830158/how-to-call-erase-with-a-reverse-iterator
        lines_.erase((line + 1).base());
        break;
      }
    }

    if(!found){
      // add a new hit entry with this hit
      hits_.push_back(1);
      // this is a cold miss since we've never seen the line before.
      ++cold_misses_;
    }

    // move up this address to mru position
    lines_.push_back(addr);
  }

  // we've made all our accesses
  accesses_ += num_accesses;
}

static Cache* cache = NULL;

namespace bytesflops{

void initialize_cache(void){
  cache = new Cache(bf_line_size);
}

// Access the cache model with this address.
void bf_touch_cache(uint64_t baseaddr, uint64_t numaddrs){
  cache->access(baseaddr, numaddrs);
}

// Get cache accesses
uint64_t bf_get_cache_accesses(void){
  return cache->getAccesses();
}

// Get cache hits
vector<uint64_t> bf_get_cache_hits(void){
  // The total hits to a cache size N is equal to the sum of unique hits to
  // all caches sized N or smaller.
  auto hits = cache->getHits();
  auto cold_misses = cache->getColdMisses();
  vector<uint64_t> tot_hits(hits.size());
  uint64_t prev_hits = 0;
  for(uint64_t i = 0; i < hits.size(); ++i){
    tot_hits[i] = hits[i] + prev_hits;
    if(i == 0){
      // remove cold misses from all cache sizes
      tot_hits[i] -= cold_misses;
    }
    prev_hits = tot_hits[i];
  }
  return tot_hits;
}

} // namespace bytesflops
<|endoftext|>