<commit_before>/**
 * @file MiNiFiMain.cpp
 * MiNiFiMain implementation
 *
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 <fcntl.h>
#include <stdio.h>
#include <semaphore.h>
#include <signal.h>
#include <vector>
#include <queue>
#include <map>
#include <unistd.h>
#include <yaml-cpp/yaml.h>
#include <iostream>

#include "core/Core.h"

#include "spdlog/spdlog.h"
#include "core/FlowConfiguration.h"
#include "core/ConfigurationFactory.h"
#include "core/RepositoryFactory.h"
#include "core/logging/Logger.h"
#include "core/logging/LoggerConfiguration.h"
#include "properties/Properties.h"
#include "properties/Configure.h"
#include "utils/Id.h"
#include "FlowController.h"

//! Main thread sleep interval 1 second
#define SLEEP_INTERVAL 1
//! Main thread stop wait time
#define STOP_WAIT_TIME_MS 30*1000
//! Default YAML location
#define DEFAULT_NIFI_CONFIG_YML "./conf/config.yml"
//! Default properties file paths
#define DEFAULT_NIFI_PROPERTIES_FILE "./conf/minifi.properties"
#define DEFAULT_LOG_PROPERTIES_FILE "./conf/minifi-log.properties"
#define DEFAULT_UID_PROPERTIES_FILE "./conf/minifi-uid.properties"
//! Define home environment variable
#define MINIFI_HOME_ENV_KEY "MINIFI_HOME"

/* Define Parser Values for Configuration YAML sections */
#define CONFIG_YAML_PROCESSORS_KEY "Processors"
#define CONFIG_YAML_FLOW_CONTROLLER_KEY "Flow Controller"
#define CONFIG_YAML_CONNECTIONS_KEY "Connections"
#define CONFIG_YAML_REMOTE_PROCESSING_GROUPS_KEY "Remote Processing Groups"

// Variables that allow us to avoid a timed wait.
sem_t *running;
//! Flow Controller

/**
 * Removed the stop command from the signal handler so that we could trigger
 * unload after we exit the semaphore controlled critical section in main.
 *
 * Semaphores are a portable choice when using signal handlers. Threads,
 * mutexes, and condition variables are not guaranteed to work within
 * a signal handler. Consequently we will use the semaphore to avoid thread
 * safety issues and.
 */
void sigHandler(int signal) {

  if (signal == SIGINT || signal == SIGTERM) {
    // avoid stopping the controller here.
    sem_post(running);
  }
}

int main(int argc, char **argv) {
  std::shared_ptr<logging::Logger> logger = logging::LoggerConfiguration::getConfiguration().getLogger("main");

  uint16_t stop_wait_time = STOP_WAIT_TIME_MS;

  // initialize static functions that were defined apriori
  core::FlowConfiguration::initialize_static_functions();

  std::string graceful_shutdown_seconds = "";
  std::string prov_repo_class = "provenancerepository";
  std::string flow_repo_class = "flowfilerepository";
  std::string nifi_configuration_class_name = "yamlconfiguration";
  std::string content_repo_class = "filesystemrepository";

  running = sem_open("MiNiFiMain", O_CREAT, 0644, 0);
  if (running == SEM_FAILED || running == 0) {

    logger->log_error("could not initialize semaphore");
    perror("initialization failure");
  }
  // assumes POSIX compliant environment
  std::string minifiHome;
  if (const char* env_p = std::getenv(MINIFI_HOME_ENV_KEY)) {
    minifiHome = env_p;
    logger->log_info("MINIFI_HOME=%s", minifiHome);
  } else {
    logger->log_info("MINIFI_HOME was not found, determining based on executable path.");
    char *path = NULL;
    char full_path[PATH_MAX];
    path = realpath(argv[0], full_path);
    std::string minifiHomePath(path);
    minifiHomePath = minifiHomePath.substr(0, minifiHomePath.find_last_of("/\\"));  //Remove /minifi from path
    minifiHome = minifiHomePath.substr(0, minifiHomePath.find_last_of("/\\"));	//Remove /bin from path
  }

  if (signal(SIGINT, sigHandler) == SIG_ERR || signal(SIGTERM, sigHandler) == SIG_ERR || signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
    logger->log_error("Can not install signal handler");
    return -1;
  }

  std::shared_ptr<logging::LoggerProperties> log_properties = std::make_shared<logging::LoggerProperties>();
  log_properties->setHome(minifiHome);
  log_properties->loadConfigureFile(DEFAULT_LOG_PROPERTIES_FILE);
  logging::LoggerConfiguration::getConfiguration().initialize(log_properties);

  std::shared_ptr<minifi::Properties> uid_properties = std::make_shared<minifi::Properties>();
  uid_properties->setHome(minifiHome);
  uid_properties->loadConfigureFile(DEFAULT_UID_PROPERTIES_FILE);
  utils::IdGenerator::getIdGenerator()->initialize(uid_properties);

  // Make a record of minifi home in the configured log file.
  logger->log_info("MINIFI_HOME=%s", minifiHome);

  std::shared_ptr<minifi::Configure> configure = std::make_shared<minifi::Configure>();
  configure->setHome(minifiHome);
  configure->loadConfigureFile(DEFAULT_NIFI_PROPERTIES_FILE);

  if (configure->get(minifi::Configure::nifi_graceful_shutdown_seconds, graceful_shutdown_seconds)) {
    try {
      stop_wait_time = std::stoi(graceful_shutdown_seconds);
    } catch (const std::out_of_range &e) {
      logger->log_error("%s is out of range. %s", minifi::Configure::nifi_graceful_shutdown_seconds, e.what());
    } catch (const std::invalid_argument &e) {
      logger->log_error("%s contains an invalid argument set. %s", minifi::Configure::nifi_graceful_shutdown_seconds, e.what());
    }
  } else {
    logger->log_debug("%s not set, defaulting to %d", minifi::Configure::nifi_graceful_shutdown_seconds,
    STOP_WAIT_TIME_MS);
  }

  configure->get(minifi::Configure::nifi_provenance_repository_class_name, prov_repo_class);
  // Create repos for flow record and provenance
  std::shared_ptr<core::Repository> prov_repo = core::createRepository(prov_repo_class, true, "provenance");
  prov_repo->initialize(configure);

  configure->get(minifi::Configure::nifi_flow_repository_class_name, flow_repo_class);

  std::shared_ptr<core::Repository> flow_repo = core::createRepository(flow_repo_class, true, "flowfile");

  flow_repo->initialize(configure);

  configure->get(minifi::Configure::nifi_content_repository_class_name, content_repo_class);

  std::shared_ptr<core::ContentRepository> content_repo = core::createContentRepository(content_repo_class, true, "content");

  content_repo->initialize(configure);

  configure->get(minifi::Configure::nifi_configuration_class_name, nifi_configuration_class_name);

  std::shared_ptr<minifi::io::StreamFactory> stream_factory = std::make_shared<minifi::io::StreamFactory>(configure);

  std::unique_ptr<core::FlowConfiguration> flow_configuration = std::move(core::createFlowConfiguration(prov_repo, flow_repo, content_repo, configure, stream_factory, nifi_configuration_class_name));

  std::shared_ptr<minifi::FlowController> controller = std::unique_ptr<minifi::FlowController>(
      new minifi::FlowController(prov_repo, flow_repo, configure, std::move(flow_configuration), content_repo));

  logger->log_info("Loading FlowController");
  // Load flow from specified configuration file
  controller->load();
  // Start Processing the flow

  controller->start();
  logger->log_info("MiNiFi started");

  /**
   * Sem wait provides us the ability to have a controlled
   * yield without the need for a more complex construct and
   * a spin lock
   */
  if (sem_wait(running) != -1)
    perror("sem_wait");

  sem_unlink("MiNiFiMain");

  /**
   * Trigger unload -- wait stop_wait_time
   */
  controller->waitUnload(stop_wait_time);

  flow_repo = nullptr;

  prov_repo = nullptr;

  logger->log_info("MiNiFi exit");

  return 0;
}
<commit_msg>MINIFICPP-267 Make inference of MINIFI_HOME more resilient, and gracefully exit if home value is not valid.<commit_after>/**
 * @file MiNiFiMain.cpp
 * MiNiFiMain implementation
 *
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 <fcntl.h>
#include <stdio.h>
#include <semaphore.h>
#include <signal.h>
#include <vector>
#include <queue>
#include <map>
#include <unistd.h>
#include <yaml-cpp/yaml.h>
#include <iostream>

#include "core/Core.h"

#include "spdlog/spdlog.h"
#include "core/FlowConfiguration.h"
#include "core/ConfigurationFactory.h"
#include "core/RepositoryFactory.h"
#include "core/logging/Logger.h"
#include "core/logging/LoggerConfiguration.h"
#include "properties/Properties.h"
#include "properties/Configure.h"
#include "utils/Id.h"
#include "FlowController.h"

//! Main thread sleep interval 1 second
#define SLEEP_INTERVAL 1
//! Main thread stop wait time
#define STOP_WAIT_TIME_MS 30*1000
//! Default YAML location
#define DEFAULT_NIFI_CONFIG_YML "./conf/config.yml"
//! Default properties file paths
#define DEFAULT_NIFI_PROPERTIES_FILE "./conf/minifi.properties"
#define DEFAULT_LOG_PROPERTIES_FILE "./conf/minifi-log.properties"
#define DEFAULT_UID_PROPERTIES_FILE "./conf/minifi-uid.properties"
//! Define home environment variable
#define MINIFI_HOME_ENV_KEY "MINIFI_HOME"

/* Define Parser Values for Configuration YAML sections */
#define CONFIG_YAML_PROCESSORS_KEY "Processors"
#define CONFIG_YAML_FLOW_CONTROLLER_KEY "Flow Controller"
#define CONFIG_YAML_CONNECTIONS_KEY "Connections"
#define CONFIG_YAML_REMOTE_PROCESSING_GROUPS_KEY "Remote Processing Groups"

// Variables that allow us to avoid a timed wait.
sem_t *running;
//! Flow Controller

/**
 * Removed the stop command from the signal handler so that we could trigger
 * unload after we exit the semaphore controlled critical section in main.
 *
 * Semaphores are a portable choice when using signal handlers. Threads,
 * mutexes, and condition variables are not guaranteed to work within
 * a signal handler. Consequently we will use the semaphore to avoid thread
 * safety issues and.
 */
void sigHandler(int signal) {

  if (signal == SIGINT || signal == SIGTERM) {
    // avoid stopping the controller here.
    sem_post(running);
  }
}

/**
 * Validates a MINIFI_HOME value.
 * @param home_path
 * @return true if home_path represents a valid MINIFI_HOME
 */
bool validHome(const std::string &home_path) {
  struct stat stat_result{};
  auto properties_file_path = home_path + "/" + DEFAULT_NIFI_PROPERTIES_FILE;
  return (stat(properties_file_path.c_str(), &stat_result) == 0);
}

int main(int argc, char **argv) {
  std::shared_ptr<logging::Logger> logger = logging::LoggerConfiguration::getConfiguration().getLogger("main");

  uint16_t stop_wait_time = STOP_WAIT_TIME_MS;

  // initialize static functions that were defined apriori
  core::FlowConfiguration::initialize_static_functions();

  std::string graceful_shutdown_seconds = "";
  std::string prov_repo_class = "provenancerepository";
  std::string flow_repo_class = "flowfilerepository";
  std::string nifi_configuration_class_name = "yamlconfiguration";
  std::string content_repo_class = "filesystemrepository";

  running = sem_open("MiNiFiMain", O_CREAT, 0644, 0);
  if (running == SEM_FAILED || running == 0) {

    logger->log_error("could not initialize semaphore");
    perror("initialization failure");
  }
  // assumes POSIX compliant environment
  std::string minifiHome;
  if (const char *env_p = std::getenv(MINIFI_HOME_ENV_KEY)) {
    minifiHome = env_p;
    logger->log_info("Using MINIFI_HOME=%s from environment.", minifiHome);
  } else {
    logger->log_info("MINIFI_HOME is not set; determining based on environment.");
    char *path = nullptr;
    char full_path[PATH_MAX];
    path = realpath(argv[0], full_path);

    if (path != nullptr) {
      std::string minifiHomePath(path);
      if (minifiHomePath.find_last_of("/\\") != std::string::npos) {
        minifiHomePath = minifiHomePath.substr(0, minifiHomePath.find_last_of("/\\"));  //Remove /minifi from path
        minifiHome = minifiHomePath.substr(0, minifiHomePath.find_last_of("/\\"));    //Remove /bin from path
      }
    }

    // attempt to use cwd as MINIFI_HOME
    if (minifiHome.empty() || !validHome(minifiHome)) {
      char cwd[PATH_MAX];
      getcwd(cwd, PATH_MAX);
      minifiHome = cwd;
    }
  }

  if (!validHome(minifiHome)) {
    logger->log_error("No valid MINIFI_HOME could be inferred. "
                          "Please set MINIFI_HOME or run minifi from a valid location.");
    return -1;
  }

  if (signal(SIGINT, sigHandler) == SIG_ERR || signal(SIGTERM, sigHandler) == SIG_ERR
      || signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
    logger->log_error("Can not install signal handler");
    return -1;
  }

  std::shared_ptr<logging::LoggerProperties> log_properties = std::make_shared<logging::LoggerProperties>();
  log_properties->setHome(minifiHome);
  log_properties->loadConfigureFile(DEFAULT_LOG_PROPERTIES_FILE);
  logging::LoggerConfiguration::getConfiguration().initialize(log_properties);

  std::shared_ptr<minifi::Properties> uid_properties = std::make_shared<minifi::Properties>();
  uid_properties->setHome(minifiHome);
  uid_properties->loadConfigureFile(DEFAULT_UID_PROPERTIES_FILE);
  utils::IdGenerator::getIdGenerator()->initialize(uid_properties);

  // Make a record of minifi home in the configured log file.
  logger->log_info("MINIFI_HOME=%s", minifiHome);

  std::shared_ptr<minifi::Configure> configure = std::make_shared<minifi::Configure>();
  configure->setHome(minifiHome);
  configure->loadConfigureFile(DEFAULT_NIFI_PROPERTIES_FILE);

  if (configure->get(minifi::Configure::nifi_graceful_shutdown_seconds, graceful_shutdown_seconds)) {
    try {
      stop_wait_time = std::stoi(graceful_shutdown_seconds);
    } catch (const std::out_of_range &e) {
      logger->log_error("%s is out of range. %s", minifi::Configure::nifi_graceful_shutdown_seconds, e.what());
    } catch (const std::invalid_argument &e) {
      logger->log_error("%s contains an invalid argument set. %s",
                        minifi::Configure::nifi_graceful_shutdown_seconds,
                        e.what());
    }
  } else {
    logger->log_debug("%s not set, defaulting to %d", minifi::Configure::nifi_graceful_shutdown_seconds,
                      STOP_WAIT_TIME_MS);
  }

  configure->get(minifi::Configure::nifi_provenance_repository_class_name, prov_repo_class);
  // Create repos for flow record and provenance
  std::shared_ptr<core::Repository> prov_repo = core::createRepository(prov_repo_class, true, "provenance");
  prov_repo->initialize(configure);

  configure->get(minifi::Configure::nifi_flow_repository_class_name, flow_repo_class);

  std::shared_ptr<core::Repository> flow_repo = core::createRepository(flow_repo_class, true, "flowfile");

  flow_repo->initialize(configure);

  configure->get(minifi::Configure::nifi_content_repository_class_name, content_repo_class);

  std::shared_ptr<core::ContentRepository>
      content_repo = core::createContentRepository(content_repo_class, true, "content");

  content_repo->initialize(configure);

  configure->get(minifi::Configure::nifi_configuration_class_name, nifi_configuration_class_name);

  std::shared_ptr<minifi::io::StreamFactory> stream_factory = std::make_shared<minifi::io::StreamFactory>(configure);

  std::unique_ptr<core::FlowConfiguration> flow_configuration = std::move(core::createFlowConfiguration(prov_repo,
                                                                                flow_repo,
                                                                                content_repo,
                                                                                configure,
                                                                                stream_factory,
                                                                                nifi_configuration_class_name));

  std::shared_ptr<minifi::FlowController> controller = std::unique_ptr<minifi::FlowController>(
      new minifi::FlowController(prov_repo, flow_repo, configure, std::move(flow_configuration), content_repo));

  logger->log_info("Loading FlowController");
  // Load flow from specified configuration file
  controller->load();
  // Start Processing the flow

  controller->start();
  logger->log_info("MiNiFi started");

  /**
   * Sem wait provides us the ability to have a controlled
   * yield without the need for a more complex construct and
   * a spin lock
   */
  if (sem_wait(running) != -1)
    perror("sem_wait");

  sem_unlink("MiNiFiMain");

  /**
   * Trigger unload -- wait stop_wait_time
   */
  controller->waitUnload(stop_wait_time);

  flow_repo = nullptr;

  prov_repo = nullptr;

  logger->log_info("MiNiFi exit");

  return 0;
}
<|endoftext|>


<commit_before>#include "../../testing/testing.hpp"

#include "../file_container.hpp"
#include "../varint.hpp"

#include "../../base/logging.hpp"
#include "../../base/string_utils.hpp"
#include "../../base/scope_guard.hpp"

UNIT_TEST(FilesContainer_Smoke)
{
  string const fName = "file_container.tmp";
  FileWriter::DeleteFileX(fName);
  size_t const count = 10;

  // fill container one by one
  {
    FilesContainerW writer(fName);

    for (size_t i = 0; i < count; ++i)
    {
      FileWriter w = writer.GetWriter(strings::to_string(i));

      for (uint32_t j = 0; j < i; ++j)
        WriteVarUint(w, j);
    }
  }

  // read container one by one
  {
    FilesContainerR reader(fName);

    for (size_t i = 0; i < count; ++i)
    {
      FilesContainerR::ReaderT r = reader.GetReader(strings::to_string(i));
      ReaderSource<FilesContainerR::ReaderT> src(r);

      for (uint32_t j = 0; j < i; ++j)
      {
        uint32_t const test = ReadVarUint<uint32_t>(src);
        TEST_EQUAL(j, test, ());
      }
    }
  }

  // append to container
  uint32_t const arrAppend[] = { 888, 777, 666 };
  for (size_t i = 0; i < ARRAY_SIZE(arrAppend); ++i)
  {
    {
      FilesContainerW writer(fName, FileWriter::OP_WRITE_EXISTING);

      FileWriter w = writer.GetWriter(strings::to_string(arrAppend[i]));
      WriteVarUint(w, arrAppend[i]);
    }

    // read appended
    {
      FilesContainerR reader(fName);

      FilesContainerR::ReaderT r = reader.GetReader(strings::to_string(arrAppend[i]));
      ReaderSource<FilesContainerR::ReaderT> src(r);

      uint32_t const test = ReadVarUint<uint32_t>(src);
      TEST_EQUAL(arrAppend[i], test, ());
    }
  }
  FileWriter::DeleteFileX(fName);
}

namespace
{
  void CheckInvariant(FilesContainerR & reader, string const & tag, int64_t test)
  {
    FilesContainerR::ReaderT r = reader.GetReader(tag);
    TEST_EQUAL(test, ReadPrimitiveFromPos<int64_t>(r, 0), ());
  }
}

UNIT_TEST(FilesContainer_Shared)
{
  string const fName = "file_container.tmp";
  FileWriter::DeleteFileX(fName);

  uint32_t const count = 10;
  int64_t const test64 = 908175281437210836LL;

  {
    // shared container fill

    FilesContainerW writer(fName);

    FileWriter w1 = writer.GetWriter("5");
    WriteToSink(w1, uint32_t(0));

    for (uint32_t i = 0; i < count; ++i)
      WriteVarUint(w1, i);
    w1.Flush();

    FileWriter w2 = writer.GetWriter("2");
    WriteToSink(w2, test64);
    w2.Flush();
  }

  {
    // shared container read and fill

    FilesContainerR reader(fName);
    FilesContainerR::ReaderT r1 = reader.GetReader("5");
    uint64_t const offset = sizeof(uint32_t);
    r1 = r1.SubReader(offset, r1.Size() - offset);

    CheckInvariant(reader, "2", test64);

    FilesContainerW writer(fName, FileWriter::OP_WRITE_EXISTING);
    FileWriter w = writer.GetWriter("3");

    ReaderSource<FilesContainerR::ReaderT> src(r1);
    for (uint32_t i = 0; i < count; ++i)
    {
      uint32_t test = ReadVarUint<uint32_t>(src);
      TEST_EQUAL(test, i, ());
      WriteVarUint(w, i);
    }
  }

  {
    // check invariant
    FilesContainerR reader(fName);
    CheckInvariant(reader, "2", test64);
  }

  FileWriter::DeleteFileX(fName);
}

namespace
{
  void ReplaceInContainer(string const & fName,
                          char const * key, char const * value)
  {
    FilesContainerW writer(fName, FileWriter::OP_WRITE_EXISTING);
    FileWriter w = writer.GetWriter(key);
    w.Write(value, strlen(value));
  }

  void CheckContainer(string const & fName,
                      char const * key[], char const * value[], size_t count)
  {
    FilesContainerR reader(fName);
    LOG(LINFO, ("Size=", reader.GetFileSize()));

    for (size_t i = 0; i < count; ++i)
    {
      FilesContainerR::ReaderT r = reader.GetReader(key[i]);

      size_t const szBuffer = 100;
      size_t const szS = strlen(value[i]);

      char s[szBuffer] = { 0 };
      ASSERT_LESS ( szS, szBuffer, () );
      r.Read(0, s, szS);

      TEST(strcmp(value[i], s) == 0, (s));
    }
  }
}

UNIT_TEST(FilesContainer_RewriteExisting)
{
  string const fName = "file_container.tmp";
  FileWriter::DeleteFileX(fName);

  char const * key[] = { "3", "2", "1" };
  char const * value[] = { "prolog", "data", "epilog" };

  // fill container
  {
    FilesContainerW writer(fName);

    for (size_t i = 0; i < ARRAY_SIZE(key); ++i)
    {
      FileWriter w = writer.GetWriter(key[i]);
      w.Write(value[i], strlen(value[i]));
    }
  }

  // re-write middle file in container
  char const * buffer1 = "xxxxxxx";
  ReplaceInContainer(fName, key[1], buffer1);
  char const * value1[] = { value[0], buffer1, value[2] };
  CheckContainer(fName, key, value1, 3);

  // re-write end file in container
  char const * buffer2 = "yyyyyyyyyyyyyy";
  ReplaceInContainer(fName, key[2], buffer2);
  char const * value2[] = { value[0], buffer1, buffer2 };
  CheckContainer(fName, key, value2, 3);

  // re-write end file in container once again
  char const * buffer3 = "zzz";
  ReplaceInContainer(fName, key[2], buffer3);
  char const * value3[] = { value[0], buffer1, buffer3 };
  CheckContainer(fName, key, value3, 3);

  FileWriter::DeleteFileX(fName);
}

UNIT_TEST(FilesMappingContainer_Handle)
{
  string const fName = "file_container.tmp";
  string const tag = "dummy";

  {
    FilesContainerW writer(fName);
    FileWriter w = writer.GetWriter(tag);
    w.Write(tag.c_str(), tag.size());
  }

  {
    FilesMappingContainer cont(fName);

    FilesMappingContainer::Handle h1 = cont.Map(tag);
    TEST(h1.IsValid(), ());

    FilesMappingContainer::Handle h2;
    TEST(!h2.IsValid(), ());

    h2.Assign(std::move(h1));
    TEST(!h1.IsValid(), ());
    TEST(h2.IsValid(), ());
  }

  FileWriter::DeleteFileX(fName);
}

UNIT_TEST(FilesMappingContainer_MoveHandle)
{
  static uint8_t const kNumMapTests = 200;
  class HandleWrapper
  {
  public:
    HandleWrapper(FilesMappingContainer::Handle&& handle) : m_handle(move(handle))
    {
      TEST(m_handle.IsValid(), ());
    }

  private:
    FilesMappingContainer::Handle m_handle;
  };

  string const containerPath = "file_container.tmp";
  string const tagName = "dummy";

  MY_SCOPE_GUARD(deleteContainerFileGuard, bind(&FileWriter::DeleteFileX, cref(containerPath)));

  {
    FilesContainerW writer(containerPath);
    FileWriter w = writer.GetWriter(tagName);
    w.Write(tagName.c_str(), tagName.size());
  }

  {
    FilesMappingContainer cont(containerPath);

    FilesMappingContainer::Handle h1 = cont.Map(tagName);
    TEST(h1.IsValid(), ());

    FilesMappingContainer::Handle h2(move(h1));
    TEST(h2.IsValid(), ());
    TEST(!h1.IsValid(), ());

    for (int i = 0; i < kNumMapTests; ++i)
    {
      FilesMappingContainer::Handle parent_handle = cont.Map(tagName);
      HandleWrapper tmp(move(parent_handle));
    }

  }
}

UNIT_TEST(FilesMappingContainer_Smoke)
{
  string const fName = "file_container.tmp";
  char const * key[] = { "3", "2", "1" };
  uint32_t const count = 1000000;

  // fill container
  {
    FilesContainerW writer(fName);

    for (size_t i = 0; i < ARRAY_SIZE(key); ++i)
    {
      FileWriter w = writer.GetWriter(key[i]);
      for (uint32_t j = 0; j < count; ++j)
      {
        uint32_t v = j + i;
        w.Write(&v, sizeof(v));
      }
    }
  }

  {
    FilesMappingContainer reader(fName);

    for (size_t i = 0; i < ARRAY_SIZE(key); ++i)
    {
      FilesMappingContainer::Handle h = reader.Map(key[i]);
      uint32_t const * data = h.GetData<uint32_t>();

      for (uint32_t j = 0; j < count; ++j)
      {
        TEST_EQUAL(j + i, *data, ());
        ++data;
      }

      h.Unmap();
    }
  }

  FileWriter::DeleteFileX(fName);
}

UNIT_TEST(FilesMappingContainer_PageSize)
{
  string const fName = "file_container.tmp";

  size_t const pageSize =
#ifndef OMIM_OS_WINDOWS
      sysconf(_SC_PAGE_SIZE);
#else
      4096;
#endif
  LOG(LINFO, ("Page size:", pageSize));

  char const * key[] = { "3", "2", "1" };
  char const byte[] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g' };
  size_t count[] = { pageSize-1, pageSize, pageSize+1 };
  size_t const sz = ARRAY_SIZE(key);

  {
    FilesContainerW writer(fName);

    for (size_t i = 0; i < sz; ++i)
    {
      FileWriter w = writer.GetWriter(key[i]);
      for (size_t j = 0; j < count[i]; ++j)
        w.Write(&byte[j % ARRAY_SIZE(byte)], 1);
    }
  }

  {
    FilesMappingContainer reader(fName);
    FilesMappingContainer::Handle handle[sz];

    for (size_t i = 0; i < sz; ++i)
    {
      handle[i].Assign(reader.Map(key[i]));
      TEST_EQUAL(handle[i].GetSize(), count[i], ());
    }

    for (size_t i = 0; i < sz; ++i)
    {
      char const * data = handle[i].GetData<char>();
      for (size_t j = 0; j < count[i]; ++j)
        TEST_EQUAL(*data++, byte[j % ARRAY_SIZE(byte)], ());
    }
  }

  FileWriter::DeleteFileX(fName);
}
<commit_msg>File container handle moving constructor bugfix<commit_after>#include "../../testing/testing.hpp"

#include "../file_container.hpp"
#include "../varint.hpp"

#include "../../base/logging.hpp"
#include "../../base/string_utils.hpp"
#include "../../base/scope_guard.hpp"

UNIT_TEST(FilesContainer_Smoke)
{
  string const fName = "file_container.tmp";
  FileWriter::DeleteFileX(fName);
  size_t const count = 10;

  // fill container one by one
  {
    FilesContainerW writer(fName);

    for (size_t i = 0; i < count; ++i)
    {
      FileWriter w = writer.GetWriter(strings::to_string(i));

      for (uint32_t j = 0; j < i; ++j)
        WriteVarUint(w, j);
    }
  }

  // read container one by one
  {
    FilesContainerR reader(fName);

    for (size_t i = 0; i < count; ++i)
    {
      FilesContainerR::ReaderT r = reader.GetReader(strings::to_string(i));
      ReaderSource<FilesContainerR::ReaderT> src(r);

      for (uint32_t j = 0; j < i; ++j)
      {
        uint32_t const test = ReadVarUint<uint32_t>(src);
        TEST_EQUAL(j, test, ());
      }
    }
  }

  // append to container
  uint32_t const arrAppend[] = { 888, 777, 666 };
  for (size_t i = 0; i < ARRAY_SIZE(arrAppend); ++i)
  {
    {
      FilesContainerW writer(fName, FileWriter::OP_WRITE_EXISTING);

      FileWriter w = writer.GetWriter(strings::to_string(arrAppend[i]));
      WriteVarUint(w, arrAppend[i]);
    }

    // read appended
    {
      FilesContainerR reader(fName);

      FilesContainerR::ReaderT r = reader.GetReader(strings::to_string(arrAppend[i]));
      ReaderSource<FilesContainerR::ReaderT> src(r);

      uint32_t const test = ReadVarUint<uint32_t>(src);
      TEST_EQUAL(arrAppend[i], test, ());
    }
  }
  FileWriter::DeleteFileX(fName);
}

namespace
{
  void CheckInvariant(FilesContainerR & reader, string const & tag, int64_t test)
  {
    FilesContainerR::ReaderT r = reader.GetReader(tag);
    TEST_EQUAL(test, ReadPrimitiveFromPos<int64_t>(r, 0), ());
  }
}

UNIT_TEST(FilesContainer_Shared)
{
  string const fName = "file_container.tmp";
  FileWriter::DeleteFileX(fName);

  uint32_t const count = 10;
  int64_t const test64 = 908175281437210836LL;

  {
    // shared container fill

    FilesContainerW writer(fName);

    FileWriter w1 = writer.GetWriter("5");
    WriteToSink(w1, uint32_t(0));

    for (uint32_t i = 0; i < count; ++i)
      WriteVarUint(w1, i);
    w1.Flush();

    FileWriter w2 = writer.GetWriter("2");
    WriteToSink(w2, test64);
    w2.Flush();
  }

  {
    // shared container read and fill

    FilesContainerR reader(fName);
    FilesContainerR::ReaderT r1 = reader.GetReader("5");
    uint64_t const offset = sizeof(uint32_t);
    r1 = r1.SubReader(offset, r1.Size() - offset);

    CheckInvariant(reader, "2", test64);

    FilesContainerW writer(fName, FileWriter::OP_WRITE_EXISTING);
    FileWriter w = writer.GetWriter("3");

    ReaderSource<FilesContainerR::ReaderT> src(r1);
    for (uint32_t i = 0; i < count; ++i)
    {
      uint32_t test = ReadVarUint<uint32_t>(src);
      TEST_EQUAL(test, i, ());
      WriteVarUint(w, i);
    }
  }

  {
    // check invariant
    FilesContainerR reader(fName);
    CheckInvariant(reader, "2", test64);
  }

  FileWriter::DeleteFileX(fName);
}

namespace
{
  void ReplaceInContainer(string const & fName,
                          char const * key, char const * value)
  {
    FilesContainerW writer(fName, FileWriter::OP_WRITE_EXISTING);
    FileWriter w = writer.GetWriter(key);
    w.Write(value, strlen(value));
  }

  void CheckContainer(string const & fName,
                      char const * key[], char const * value[], size_t count)
  {
    FilesContainerR reader(fName);
    LOG(LINFO, ("Size=", reader.GetFileSize()));

    for (size_t i = 0; i < count; ++i)
    {
      FilesContainerR::ReaderT r = reader.GetReader(key[i]);

      size_t const szBuffer = 100;
      size_t const szS = strlen(value[i]);

      char s[szBuffer] = { 0 };
      ASSERT_LESS ( szS, szBuffer, () );
      r.Read(0, s, szS);

      TEST(strcmp(value[i], s) == 0, (s));
    }
  }
}

UNIT_TEST(FilesContainer_RewriteExisting)
{
  string const fName = "file_container.tmp";
  FileWriter::DeleteFileX(fName);

  char const * key[] = { "3", "2", "1" };
  char const * value[] = { "prolog", "data", "epilog" };

  // fill container
  {
    FilesContainerW writer(fName);

    for (size_t i = 0; i < ARRAY_SIZE(key); ++i)
    {
      FileWriter w = writer.GetWriter(key[i]);
      w.Write(value[i], strlen(value[i]));
    }
  }

  // re-write middle file in container
  char const * buffer1 = "xxxxxxx";
  ReplaceInContainer(fName, key[1], buffer1);
  char const * value1[] = { value[0], buffer1, value[2] };
  CheckContainer(fName, key, value1, 3);

  // re-write end file in container
  char const * buffer2 = "yyyyyyyyyyyyyy";
  ReplaceInContainer(fName, key[2], buffer2);
  char const * value2[] = { value[0], buffer1, buffer2 };
  CheckContainer(fName, key, value2, 3);

  // re-write end file in container once again
  char const * buffer3 = "zzz";
  ReplaceInContainer(fName, key[2], buffer3);
  char const * value3[] = { value[0], buffer1, buffer3 };
  CheckContainer(fName, key, value3, 3);

  FileWriter::DeleteFileX(fName);
}

UNIT_TEST(FilesMappingContainer_Handle)
{
  string const fName = "file_container.tmp";
  string const tag = "dummy";

  {
    FilesContainerW writer(fName);
    FileWriter w = writer.GetWriter(tag);
    w.Write(tag.c_str(), tag.size());
  }

  {
    FilesMappingContainer cont(fName);

    FilesMappingContainer::Handle h1 = cont.Map(tag);
    TEST(h1.IsValid(), ());

    FilesMappingContainer::Handle h2;
    TEST(!h2.IsValid(), ());

    h2.Assign(std::move(h1));
    TEST(!h1.IsValid(), ());
    TEST(h2.IsValid(), ());
  }

  FileWriter::DeleteFileX(fName);
}

UNIT_TEST(FilesMappingContainer_MoveHandle)
{
  static uint8_t const kNumMapTests = 200;
  class HandleWrapper
  {
  public:
    HandleWrapper(FilesMappingContainer::Handle&& handle) : m_handle(move(handle))
    {
      TEST(m_handle.IsValid(), ());
    }

  private:
    FilesMappingContainer::Handle m_handle;
  };

  string const containerPath = "file_container.tmp";
  string const tagName = "dummy";

  MY_SCOPE_GUARD(deleteContainerFileGuard, bind(&FileWriter::DeleteFileX, cref(containerPath)));

  {
    FilesContainerW writer(containerPath);
    FileWriter w = writer.GetWriter(tagName);
    w.Write(tagName.c_str(), tagName.size());
  }

  {
    FilesMappingContainer cont(containerPath);

    FilesMappingContainer::Handle h1 = cont.Map(tagName);
    TEST(h1.IsValid(), ());

    FilesMappingContainer::Handle h2(move(h1));
    TEST(h2.IsValid(), ());
    TEST(!h1.IsValid(), ());

    for (int i = 0; i < kNumMapTests; ++i)
    {
      FilesMappingContainer::Handle parent_handle = cont.Map(tagName);
      HandleWrapper tmp(move(parent_handle));
    }

  }
  FileWriter::DeleteFileX(containerPath);
}

UNIT_TEST(FilesMappingContainer_Smoke)
{
  string const fName = "file_container.tmp";
  char const * key[] = { "3", "2", "1" };
  uint32_t const count = 1000000;

  // fill container
  {
    FilesContainerW writer(fName);

    for (size_t i = 0; i < ARRAY_SIZE(key); ++i)
    {
      FileWriter w = writer.GetWriter(key[i]);
      for (uint32_t j = 0; j < count; ++j)
      {
        uint32_t v = j + i;
        w.Write(&v, sizeof(v));
      }
    }
  }

  {
    FilesMappingContainer reader(fName);

    for (size_t i = 0; i < ARRAY_SIZE(key); ++i)
    {
      FilesMappingContainer::Handle h = reader.Map(key[i]);
      uint32_t const * data = h.GetData<uint32_t>();

      for (uint32_t j = 0; j < count; ++j)
      {
        TEST_EQUAL(j + i, *data, ());
        ++data;
      }

      h.Unmap();
    }
  }

  FileWriter::DeleteFileX(fName);
}

UNIT_TEST(FilesMappingContainer_PageSize)
{
  string const fName = "file_container.tmp";

  size_t const pageSize =
#ifndef OMIM_OS_WINDOWS
      sysconf(_SC_PAGE_SIZE);
#else
      4096;
#endif
  LOG(LINFO, ("Page size:", pageSize));

  char const * key[] = { "3", "2", "1" };
  char const byte[] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g' };
  size_t count[] = { pageSize-1, pageSize, pageSize+1 };
  size_t const sz = ARRAY_SIZE(key);

  {
    FilesContainerW writer(fName);

    for (size_t i = 0; i < sz; ++i)
    {
      FileWriter w = writer.GetWriter(key[i]);
      for (size_t j = 0; j < count[i]; ++j)
        w.Write(&byte[j % ARRAY_SIZE(byte)], 1);
    }
  }

  {
    FilesMappingContainer reader(fName);
    FilesMappingContainer::Handle handle[sz];

    for (size_t i = 0; i < sz; ++i)
    {
      handle[i].Assign(reader.Map(key[i]));
      TEST_EQUAL(handle[i].GetSize(), count[i], ());
    }

    for (size_t i = 0; i < sz; ++i)
    {
      char const * data = handle[i].GetData<char>();
      for (size_t j = 0; j < count[i]; ++j)
        TEST_EQUAL(*data++, byte[j % ARRAY_SIZE(byte)], ());
    }
  }

  FileWriter::DeleteFileX(fName);
}
<|endoftext|>


<commit_before>//===- LiveValues.cpp - Liveness information for LLVM IR Values. ----------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the implementation for the LLVM IR Value liveness
// analysis pass.
//
//===----------------------------------------------------------------------===//

#include "llvm/Analysis/LiveValues.h"
#include "llvm/Analysis/Dominators.h"
#include "llvm/Analysis/LoopInfo.h"
using namespace llvm;

FunctionPass *llvm::createLiveValuesPass() { return new LiveValues(); }

char LiveValues::ID = 0;
static RegisterPass<LiveValues>
X("live-values", "Value Liveness Analysis", false, true);

LiveValues::LiveValues() : FunctionPass(&ID) {}

void LiveValues::getAnalysisUsage(AnalysisUsage &AU) const {
  AU.addRequired<DominatorTree>();
  AU.addRequired<LoopInfo>();
  AU.setPreservesAll();
}

bool LiveValues::runOnFunction(Function &F) {
  DT = &getAnalysis<DominatorTree>();
  LI = &getAnalysis<LoopInfo>();

  // This pass' values are computed lazily, so there's nothing to do here.

  return false;
}

void LiveValues::releaseMemory() {
  Memos.clear();
}

/// isUsedInBlock - Test if the given value is used in the given block.
///
bool LiveValues::isUsedInBlock(const Value *V, const BasicBlock *BB) {
  Memo &M = getMemo(V);
  return M.Used.count(BB);
}

/// isLiveThroughBlock - Test if the given value is known to be
/// live-through the given block, meaning that the block is properly
/// dominated by the value's definition, and there exists a block
/// reachable from it that contains a use. This uses a conservative
/// approximation that errs on the side of returning false.
///
bool LiveValues::isLiveThroughBlock(const Value *V,
                                    const BasicBlock *BB) {
  Memo &M = getMemo(V);
  return M.LiveThrough.count(BB);
}

/// isKilledInBlock - Test if the given value is known to be killed in
/// the given block, meaning that the block contains a use of the value,
/// and no blocks reachable from the block contain a use. This uses a
/// conservative approximation that errs on the side of returning false.
///
bool LiveValues::isKilledInBlock(const Value *V, const BasicBlock *BB) {
  Memo &M = getMemo(V);
  return M.Killed.count(BB);
}

/// getMemo - Retrieve an existing Memo for the given value if one
/// is available, otherwise compute a new one.
///
LiveValues::Memo &LiveValues::getMemo(const Value *V) {
  DenseMap<const Value *, Memo>::iterator I = Memos.find(V);
  if (I != Memos.end())
    return I->second;
  return compute(V);
}

/// getImmediateDominator - A handy utility for the specific DominatorTree
/// query that we need here.
///
static const BasicBlock *getImmediateDominator(const BasicBlock *BB,
                                               const DominatorTree *DT) {
  DomTreeNode *Node = DT->getNode(const_cast<BasicBlock *>(BB))->getIDom();
  return Node ? Node->getBlock() : 0;
}

/// compute - Compute a new Memo for the given value.
///
LiveValues::Memo &LiveValues::compute(const Value *V) {
  Memo &M = Memos[V];

  // Determine the block containing the definition.
  const BasicBlock *DefBB;
  // Instructions define values with meaningful live ranges.
  if (const Instruction *I = dyn_cast<Instruction>(V))
    DefBB = I->getParent();
  // Arguments can be analyzed as values defined in the entry block.
  else if (const Argument *A = dyn_cast<Argument>(V))
    DefBB = &A->getParent()->getEntryBlock();
  // Constants and other things aren't meaningful here, so just
  // return having computed an empty Memo so that we don't come
  // here again. The assumption here is that client code won't
  // be asking about such values very often.
  else
    return M;

  // Determine if the value is defined inside a loop. This is used
  // to track whether the value is ever used outside the loop, so
  // it'll be set to null if the value is either not defined in a
  // loop or used outside the loop in which it is defined.
  const Loop *L = LI->getLoopFor(DefBB);

  // Track whether the value is used anywhere outside of the block
  // in which it is defined.
  bool LiveOutOfDefBB = false;

  // Examine each use of the value.
  for (Value::use_const_iterator I = V->use_begin(), E = V->use_end();
       I != E; ++I) {
    const User *U = *I;
    const BasicBlock *UseBB = cast<Instruction>(U)->getParent();

    // Note the block in which this use occurs.
    M.Used.insert(UseBB);

    // Observe whether the value is used outside of the loop in which
    // it is defined. Switch to an enclosing loop if necessary.
    for (; L; L = L->getParentLoop())
      if (L->contains(UseBB))
        break;

    if (isa<PHINode>(U)) {
      // The value is used by a PHI, so it is live-out of the defining block.
      LiveOutOfDefBB = true;
    } else if (UseBB != DefBB) {
      // A use outside the defining block has been found.
      LiveOutOfDefBB = true;

      // Climb the immediate dominator tree from the use to the definition
      // and mark all intermediate blocks as live-through. Don't do this if
      // the user is a PHI because such users may not be dominated by the
      // definition.
      for (const BasicBlock *BB = getImmediateDominator(UseBB, DT);
           BB != DefBB; BB = getImmediateDominator(BB, DT))
        if (!M.LiveThrough.insert(BB))
          break;
    }
  }

  // If the value is defined inside a loop and is not live outside
  // the loop, then each exit block of the loop in which the value
  // is used is a kill block.
  if (L) {
    SmallVector<BasicBlock *, 4> ExitingBlocks;
    L->getExitingBlocks(ExitingBlocks);
    for (unsigned i = 0, e = ExitingBlocks.size(); i != e; ++i) {
      const BasicBlock *ExitingBlock = ExitingBlocks[i];
      if (M.Used.count(ExitingBlock))
        M.Killed.insert(ExitingBlock);
    }
  }

  // If the value was never used outside the the block in which it was
  // defined, it's killed in that block.
  if (!LiveOutOfDefBB)
    M.Killed.insert(DefBB);

  return M;
}
<commit_msg>The last use in a block that doesn't have successors (return or unreachable) is a kill.<commit_after>//===- LiveValues.cpp - Liveness information for LLVM IR Values. ----------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the implementation for the LLVM IR Value liveness
// analysis pass.
//
//===----------------------------------------------------------------------===//

#include "llvm/Analysis/LiveValues.h"
#include "llvm/Analysis/Dominators.h"
#include "llvm/Analysis/LoopInfo.h"
using namespace llvm;

FunctionPass *llvm::createLiveValuesPass() { return new LiveValues(); }

char LiveValues::ID = 0;
static RegisterPass<LiveValues>
X("live-values", "Value Liveness Analysis", false, true);

LiveValues::LiveValues() : FunctionPass(&ID) {}

void LiveValues::getAnalysisUsage(AnalysisUsage &AU) const {
  AU.addRequired<DominatorTree>();
  AU.addRequired<LoopInfo>();
  AU.setPreservesAll();
}

bool LiveValues::runOnFunction(Function &F) {
  DT = &getAnalysis<DominatorTree>();
  LI = &getAnalysis<LoopInfo>();

  // This pass' values are computed lazily, so there's nothing to do here.

  return false;
}

void LiveValues::releaseMemory() {
  Memos.clear();
}

/// isUsedInBlock - Test if the given value is used in the given block.
///
bool LiveValues::isUsedInBlock(const Value *V, const BasicBlock *BB) {
  Memo &M = getMemo(V);
  return M.Used.count(BB);
}

/// isLiveThroughBlock - Test if the given value is known to be
/// live-through the given block, meaning that the block is properly
/// dominated by the value's definition, and there exists a block
/// reachable from it that contains a use. This uses a conservative
/// approximation that errs on the side of returning false.
///
bool LiveValues::isLiveThroughBlock(const Value *V,
                                    const BasicBlock *BB) {
  Memo &M = getMemo(V);
  return M.LiveThrough.count(BB);
}

/// isKilledInBlock - Test if the given value is known to be killed in
/// the given block, meaning that the block contains a use of the value,
/// and no blocks reachable from the block contain a use. This uses a
/// conservative approximation that errs on the side of returning false.
///
bool LiveValues::isKilledInBlock(const Value *V, const BasicBlock *BB) {
  Memo &M = getMemo(V);
  return M.Killed.count(BB);
}

/// getMemo - Retrieve an existing Memo for the given value if one
/// is available, otherwise compute a new one.
///
LiveValues::Memo &LiveValues::getMemo(const Value *V) {
  DenseMap<const Value *, Memo>::iterator I = Memos.find(V);
  if (I != Memos.end())
    return I->second;
  return compute(V);
}

/// getImmediateDominator - A handy utility for the specific DominatorTree
/// query that we need here.
///
static const BasicBlock *getImmediateDominator(const BasicBlock *BB,
                                               const DominatorTree *DT) {
  DomTreeNode *Node = DT->getNode(const_cast<BasicBlock *>(BB))->getIDom();
  return Node ? Node->getBlock() : 0;
}

/// compute - Compute a new Memo for the given value.
///
LiveValues::Memo &LiveValues::compute(const Value *V) {
  Memo &M = Memos[V];

  // Determine the block containing the definition.
  const BasicBlock *DefBB;
  // Instructions define values with meaningful live ranges.
  if (const Instruction *I = dyn_cast<Instruction>(V))
    DefBB = I->getParent();
  // Arguments can be analyzed as values defined in the entry block.
  else if (const Argument *A = dyn_cast<Argument>(V))
    DefBB = &A->getParent()->getEntryBlock();
  // Constants and other things aren't meaningful here, so just
  // return having computed an empty Memo so that we don't come
  // here again. The assumption here is that client code won't
  // be asking about such values very often.
  else
    return M;

  // Determine if the value is defined inside a loop. This is used
  // to track whether the value is ever used outside the loop, so
  // it'll be set to null if the value is either not defined in a
  // loop or used outside the loop in which it is defined.
  const Loop *L = LI->getLoopFor(DefBB);

  // Track whether the value is used anywhere outside of the block
  // in which it is defined.
  bool LiveOutOfDefBB = false;

  // Examine each use of the value.
  for (Value::use_const_iterator I = V->use_begin(), E = V->use_end();
       I != E; ++I) {
    const User *U = *I;
    const BasicBlock *UseBB = cast<Instruction>(U)->getParent();

    // Note the block in which this use occurs.
    M.Used.insert(UseBB);

    // If the use block doesn't have successors, the value can be
    // considered killed.
    if (succ_begin(UseBB) == succ_end(UseBB))
      M.Killed.insert(UseBB);

    // Observe whether the value is used outside of the loop in which
    // it is defined. Switch to an enclosing loop if necessary.
    for (; L; L = L->getParentLoop())
      if (L->contains(UseBB))
        break;

    if (isa<PHINode>(U)) {
      // The value is used by a PHI, so it is live-out of the defining block.
      LiveOutOfDefBB = true;
    } else if (UseBB != DefBB) {
      // A use outside the defining block has been found.
      LiveOutOfDefBB = true;

      // Climb the immediate dominator tree from the use to the definition
      // and mark all intermediate blocks as live-through. Don't do this if
      // the user is a PHI because such users may not be dominated by the
      // definition.
      for (const BasicBlock *BB = getImmediateDominator(UseBB, DT);
           BB != DefBB; BB = getImmediateDominator(BB, DT))
        if (!M.LiveThrough.insert(BB))
          break;
    }
  }

  // If the value is defined inside a loop and is not live outside
  // the loop, then each exit block of the loop in which the value
  // is used is a kill block.
  if (L) {
    SmallVector<BasicBlock *, 4> ExitingBlocks;
    L->getExitingBlocks(ExitingBlocks);
    for (unsigned i = 0, e = ExitingBlocks.size(); i != e; ++i) {
      const BasicBlock *ExitingBlock = ExitingBlocks[i];
      if (M.Used.count(ExitingBlock))
        M.Killed.insert(ExitingBlock);
    }
  }

  // If the value was never used outside the the block in which it was
  // defined, it's killed in that block.
  if (!LiveOutOfDefBB)
    M.Killed.insert(DefBB);

  return M;
}
<|endoftext|>


<commit_before>/*
 * This file is part of the CN24 semantic segmentation software,
 * copyright (C) 2015 Clemens-Alexander Brust (ikosa dot de at gmail dot com).
 *
 * For licensing information, see the LICENSE file included with this project.
 */

#include <cmath>

#include "CombinedTensor.h"

#include "HMaxActivationFunction.h"

namespace Conv {
bool HMaxActivationFunction::CreateOutputs (
                                       const std::vector< CombinedTensor* >& inputs,
                                       std::vector< CombinedTensor* >& outputs) {
  // This is a simple layer, only one input
  if (inputs.size() != 1) {
    LOGERROR << "Only one input supported!";
    return false;
  }

  // Save input node pointer
  CombinedTensor* input = inputs[0];

  // Check if input node pointer is null
  if (input == nullptr) {
    LOGERROR << "Null pointer input node!";
    return false;
  }

  // Create output
  CombinedTensor* output = new CombinedTensor (input->data.samples(),
                                               input->data.width(),
                                               input->data.height(),
                                               input->data.maps());
  // Tell network about the output
  outputs.push_back (output);

  return true;
}

bool HMaxActivationFunction::Connect (const CombinedTensor* input,
                                 CombinedTensor* output) {
  // Check dimensions for equality
  bool valid = input->data.samples() == output->data.samples() &&
  input->data.width() == output->data.width() &&
  input->data.height() == output->data.height() &&
  input->data.maps() == output->data.maps();

  if(!valid)
    return false;

  weights_ = new CombinedTensor(1, 2, 1, 1);
  weights_->data.Clear(1.0);
  weights_->delta.Clear();

  parameters_.push_back(weights_);

  return true;
}

void HMaxActivationFunction::FeedForward() {
  const datum a = *(weights_->data.data_ptr(0));
  const datum b = *(weights_->data.data_ptr(1));

  LOGDEBUG << "a: " << a << ", b:" << b;

  total_activations_ = (datum)(input_->data.elements());
  sum_of_activations_ = 0;

#pragma omp parallel for default(shared)
  for (std::size_t element = 0; element < input_->data.elements(); element++) {
    const datum input_data = input_->data.data_ptr_const() [element];

    // Calculate sigmoid function
    const datum output_data = 1.0 / (1.0 + exp(-(a * input_data + b)));
    sum_of_activations_ += output_data;
    output_->data.data_ptr() [element] = output_data;
  }
}

void HMaxActivationFunction::BackPropagate() {
  // Calculate gradient w.r.t. input
  const datum a = weights_->data.data_ptr_const()[0];
  const datum b = weights_->data.data_ptr_const()[1];

  // weights the regularization term
  const datum lambda_sparse_regularization = 0.1;

  // TODO: This layer needs to produce a loss (aka regularizer) as well
  // that is added directly to the objective

  // calculate part of the derivative of the KL criterion
  // which is constant for all dimensions
  // https://figss.uni-frankfurt.de/~triesch/publications/Triesch-ICANN2005.pdf
  datum delta_a = -((datum)(input_->data.elements()))/a * lambda_sparse_regularization;
  datum delta_b = -(datum)(input_->data.elements()) * lambda_sparse_regularization;
#pragma omp parallel for default(shared)
  for (std::size_t element = 0; element < input_->data.elements(); element++) {
    const datum input_data = input_->data.data_ptr_const() [element];
    const datum output_data = output_->data.data_ptr_const() [element];
    const datum output_delta = output_->delta.data_ptr_const ()[element];
    const datum output_mix = (1-output_data) * output_data;

    // Calculate derivative
    // o = (1 + exp(-ax - b))^{-1}
    // https://en.wikipedia.org/wiki/Logistic_function
    // do/dx = o (1-o) * a
    // do/da = o (1-o) * x
    // do/db = o (1-o)
    datum input_delta = output_delta * a * output_mix;

    // Calculate gradient of the output w.r.t. to weights
    delta_a += output_mix * input_data;
    delta_b += output_mix;

    // handle the KL divergence regularization;
    // We need to add the derivative of eq. (4) w.r.t. x here to input_delta
    // weighted by lambda_sparse_regularization
    // d/(dx) o log o = do/dx * log o + o * do/dx * o^-1
    //                = do/dx ( log o + 1 )
    input_delta += lambda_sparse_regularization * ( output_mix * (log(output_data) + 1) );
    input_delta += lambda_sparse_regularization * output_mix / mu_;

    input_->delta.data_ptr() [element] = input_delta;

    // Calculate gradient of KL-divergence w.r.t. weights
    delta_a += (-input_data + (2.0 + 1.0/mu_) * input_data * output_data - input_data * output_data * output_data / mu_)
        * lambda_sparse_regularization;
    delta_b += ((2.0 + 1.0/mu_) * output_data - output_data * output_data / mu_)
        * lambda_sparse_regularization;
  }

  weights_->delta.data_ptr()[0] = local_lr_ * delta_a;
  weights_->delta.data_ptr()[1] = local_lr_ * delta_b;
  LOGDEBUG << "delta a: " << delta_a << ", delta b:" << delta_b;
}

datum HMaxActivationFunction::CalculateLossFunction() {
  datum total_loss = logf(mu_) + (sum_of_activations_/(total_activations_ * mu_)); // - H(y)
  return total_loss;
}

}
<commit_msg>HMaxActivationFunction: Removed actual calculation of loss<commit_after>/*
 * This file is part of the CN24 semantic segmentation software,
 * copyright (C) 2015 Clemens-Alexander Brust (ikosa dot de at gmail dot com).
 *
 * For licensing information, see the LICENSE file included with this project.
 */

#include <cmath>

#include "CombinedTensor.h"

#include "HMaxActivationFunction.h"

namespace Conv {
bool HMaxActivationFunction::CreateOutputs (
                                       const std::vector< CombinedTensor* >& inputs,
                                       std::vector< CombinedTensor* >& outputs) {
  // This is a simple layer, only one input
  if (inputs.size() != 1) {
    LOGERROR << "Only one input supported!";
    return false;
  }

  // Save input node pointer
  CombinedTensor* input = inputs[0];

  // Check if input node pointer is null
  if (input == nullptr) {
    LOGERROR << "Null pointer input node!";
    return false;
  }

  // Create output
  CombinedTensor* output = new CombinedTensor (input->data.samples(),
                                               input->data.width(),
                                               input->data.height(),
                                               input->data.maps());
  // Tell network about the output
  outputs.push_back (output);

  return true;
}

bool HMaxActivationFunction::Connect (const CombinedTensor* input,
                                 CombinedTensor* output) {
  // Check dimensions for equality
  bool valid = input->data.samples() == output->data.samples() &&
  input->data.width() == output->data.width() &&
  input->data.height() == output->data.height() &&
  input->data.maps() == output->data.maps();

  if(!valid)
    return false;

  weights_ = new CombinedTensor(1, 2, 1, 1);
  weights_->data.Clear(1.0);
  weights_->delta.Clear();

  parameters_.push_back(weights_);

  return true;
}

void HMaxActivationFunction::FeedForward() {
  const datum a = *(weights_->data.data_ptr(0));
  const datum b = *(weights_->data.data_ptr(1));

  LOGDEBUG << "a: " << a << ", b:" << b;

  total_activations_ = (datum)(input_->data.elements());
  sum_of_activations_ = 0;

#pragma omp parallel for default(shared)
  for (std::size_t element = 0; element < input_->data.elements(); element++) {
    const datum input_data = input_->data.data_ptr_const() [element];

    // Calculate sigmoid function
    const datum output_data = 1.0 / (1.0 + exp(-(a * input_data + b)));
    sum_of_activations_ += output_data;
    output_->data.data_ptr() [element] = output_data;
  }
}

void HMaxActivationFunction::BackPropagate() {
  // Calculate gradient w.r.t. input
  const datum a = weights_->data.data_ptr_const()[0];
  const datum b = weights_->data.data_ptr_const()[1];

  // weights the regularization term
  const datum lambda_sparse_regularization = 0.2;

  // TODO: This layer needs to produce a loss (aka regularizer) as well
  // that is added directly to the objective

  // calculate part of the derivative of the KL criterion
  // which is constant for all dimensions
  // https://figss.uni-frankfurt.de/~triesch/publications/Triesch-ICANN2005.pdf
  datum delta_a = -((datum)(input_->data.elements()))/a * lambda_sparse_regularization;
  datum delta_b = -(datum)(input_->data.elements()) * lambda_sparse_regularization;
#pragma omp parallel for default(shared)
  for (std::size_t element = 0; element < input_->data.elements(); element++) {
    const datum input_data = input_->data.data_ptr_const() [element];
    const datum output_data = output_->data.data_ptr_const() [element];
    const datum output_delta = output_->delta.data_ptr_const ()[element];
    const datum output_mix = (1-output_data) * output_data;

    // Calculate derivative
    // o = (1 + exp(-ax - b))^{-1}
    // https://en.wikipedia.org/wiki/Logistic_function
    // do/dx = o (1-o) * a
    // do/da = o (1-o) * x
    // do/db = o (1-o)
    datum input_delta = output_delta * a * output_mix;

    // Calculate gradient of the output w.r.t. to weights
    delta_a += output_mix * input_data;
    delta_b += output_mix;

    // handle the KL divergence regularization;
    // We need to add the derivative of eq. (4) w.r.t. x here to input_delta
    // weighted by lambda_sparse_regularization
    // d/(dx) o log o = do/dx * log o + o * do/dx * o^-1
    //                = do/dx ( log o + 1 )
    input_delta += lambda_sparse_regularization * ( output_mix * (log(output_data) + 1) );
    input_delta += lambda_sparse_regularization * output_mix / mu_;

    input_->delta.data_ptr() [element] = input_delta;

    // Calculate gradient of KL-divergence w.r.t. weights
    delta_a += (-input_data + (2.0 + 1.0/mu_) * input_data * output_data - input_data * output_data * output_data / mu_)
        * lambda_sparse_regularization;
    delta_b += ((2.0 + 1.0/mu_) * output_data - output_data * output_data / mu_)
        * lambda_sparse_regularization;
  }

  weights_->delta.data_ptr()[0] = local_lr_ * delta_a;
  weights_->delta.data_ptr()[1] = local_lr_ * delta_b;
  LOGDEBUG << "delta a: " << delta_a << ", delta b:" << delta_b;
}

datum HMaxActivationFunction::CalculateLossFunction() {
  //datum total_loss = logf(mu_) + (sum_of_activations_/(total_activations_ * mu_)); // - H(y)
  //return total_loss;
  return 0;
}

}
<|endoftext|>


<commit_before>#include <muduo/net/TcpClient.h>

#include <muduo/base/Logging.h>
#include <muduo/base/Thread.h>
#include <muduo/net/EventLoop.h>
#include <muduo/net/EventLoopThreadPool.h>
#include <muduo/net/InetAddress.h>

#include <boost/bind.hpp>
#include <boost/ptr_container/ptr_vector.hpp>

#include <utility>

#include <mcheck.h>
#include <stdio.h>
#include <unistd.h>

using namespace muduo;
using namespace muduo::net;

class Client;

class Session : boost::noncopyable
{
 public:
  Session(EventLoop* loop,
          const InetAddress& serverAddr,
          const string& name,
          Client* owner)
    : client_(loop, serverAddr, name),
      owner_(owner),
      bytesRead_(0),
      bytesWritten_(0),
      messagesRead_(0)
  {
    client_.setConnectionCallback(
        boost::bind(&Session::onConnection, this, _1));
    client_.setMessageCallback(
        boost::bind(&Session::onMessage, this, _1, _2, _3));
  }

  void start()
  {
    client_.connect();
  }

  void stop()
  {
    client_.disconnect();
  }

  int64_t bytesRead() const
  {
     return bytesRead_;
  }

  int64_t messagesRead() const
  {
     return messagesRead_;
  }

 private:

  void onConnection(const TcpConnectionPtr& conn);

  void onMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp)
  {
    ++messagesRead_;
    bytesRead_ += buf->readableBytes();
    bytesWritten_ += buf->readableBytes();
    conn->send(buf);
  }

  TcpClient client_;
  Client* owner_;
  int64_t bytesRead_;
  int64_t bytesWritten_;
  int64_t messagesRead_;
};

class Client : boost::noncopyable
{
 public:
  Client(EventLoop* loop,
         const InetAddress& serverAddr,
         int blockSize,
         int sessionCount,
         int timeout,
         int threadCount)
    : loop_(loop),
      threadPool_(loop),
      sessionCount_(sessionCount),
      timeout_(timeout)
  {
    loop->runAfter(timeout, boost::bind(&Client::handleTimeout, this));
    if (threadCount > 1)
    {
      threadPool_.setThreadNum(threadCount);
    }
    threadPool_.start();

    for (int i = 0; i < blockSize; ++i)
    {
      message_.push_back(static_cast<char>(i % 128));
    }

    for (int i = 0; i < sessionCount; ++i)
    {
      char buf[32];
      snprintf(buf, sizeof buf, "C%05d", i);
      Session* session = new Session(threadPool_.getNextLoop(), serverAddr, buf, this);
      session->start();
      sessions_.push_back(session);
    }
  }

  const string& message() const
  {
    return message_;
  }

  void onConnect()
  {
    if (numConnected_.incrementAndGet() == sessionCount_)
    {
      LOG_WARN << "all connected";
    }
  }

  void onDisconnect()
  {
    if (numConnected_.decrementAndGet() == 0)
    {
      LOG_WARN << "all disconnected";

      int64_t totalBytesRead = 0;
      int64_t totalMessagesRead = 0;
      for (boost::ptr_vector<Session>::iterator it = sessions_.begin();
          it != sessions_.end(); ++it)
      {
        totalBytesRead += it->bytesRead();
        totalMessagesRead += it->messagesRead();
      }
      LOG_WARN << totalBytesRead << " total bytes read";
      LOG_WARN << totalMessagesRead << " total messages read";
      LOG_WARN << static_cast<double>(totalBytesRead) / static_cast<double>(totalMessagesRead)
               << " average message size";
      LOG_WARN << static_cast<double>(totalBytesRead) / (timeout_ * 1024 * 1024)
               << " MiB/s throughput";
      loop_->queueInLoop(boost::bind(&EventLoop::quit, loop_));
    }
  }

 private:

  void handleTimeout()
  {
    LOG_WARN << "stop";
    std::for_each(sessions_.begin(), sessions_.end(),
                  boost::mem_fn(&Session::stop));
  }

  EventLoop* loop_;
  EventLoopThreadPool threadPool_;
  int sessionCount_;
  int timeout_;
  boost::ptr_vector<Session> sessions_;
  string message_;
  AtomicInt32 numConnected_;
};

void Session::onConnection(const TcpConnectionPtr& conn)
{
  if (conn->connected())
  {
    conn->setTcpNoDelay(true);
    conn->send(owner_->message());
    owner_->onConnect();
  }
  else
  {
    owner_->onDisconnect();
  }
}

int main(int argc, char* argv[])
{
  if (argc != 7)
  {
    fprintf(stderr, "Usage: client <host_ip> <port> <threads> <blocksize> ");
    fprintf(stderr, "<sessions> <time>\n");
  }
  else
  {
    LOG_INFO << "pid = " << getpid() << ", tid = " << CurrentThread::tid();
    Logger::setLogLevel(Logger::WARN);

    const char* ip = argv[1];
    uint16_t port = static_cast<uint16_t>(atoi(argv[2]));
    int threadCount = atoi(argv[3]);
    int blockSize = atoi(argv[4]);
    int sessionCount = atoi(argv[5]);
    int timeout = atoi(argv[6]);

    EventLoop loop;
    InetAddress serverAddr(ip, port);

    Client client(&loop, serverAddr, blockSize, sessionCount, timeout, threadCount);
    loop.loop();
  }
}

<commit_msg>Defer the quit() of main loop.<commit_after>#include <muduo/net/TcpClient.h>

#include <muduo/base/Logging.h>
#include <muduo/base/Thread.h>
#include <muduo/net/EventLoop.h>
#include <muduo/net/EventLoopThreadPool.h>
#include <muduo/net/InetAddress.h>

#include <boost/bind.hpp>
#include <boost/ptr_container/ptr_vector.hpp>

#include <utility>

#include <mcheck.h>
#include <stdio.h>
#include <unistd.h>

using namespace muduo;
using namespace muduo::net;

class Client;

class Session : boost::noncopyable
{
 public:
  Session(EventLoop* loop,
          const InetAddress& serverAddr,
          const string& name,
          Client* owner)
    : client_(loop, serverAddr, name),
      owner_(owner),
      bytesRead_(0),
      bytesWritten_(0),
      messagesRead_(0)
  {
    client_.setConnectionCallback(
        boost::bind(&Session::onConnection, this, _1));
    client_.setMessageCallback(
        boost::bind(&Session::onMessage, this, _1, _2, _3));
  }

  void start()
  {
    client_.connect();
  }

  void stop()
  {
    client_.disconnect();
  }

  int64_t bytesRead() const
  {
     return bytesRead_;
  }

  int64_t messagesRead() const
  {
     return messagesRead_;
  }

 private:

  void onConnection(const TcpConnectionPtr& conn);

  void onMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp)
  {
    ++messagesRead_;
    bytesRead_ += buf->readableBytes();
    bytesWritten_ += buf->readableBytes();
    conn->send(buf);
  }

  TcpClient client_;
  Client* owner_;
  int64_t bytesRead_;
  int64_t bytesWritten_;
  int64_t messagesRead_;
};

class Client : boost::noncopyable
{
 public:
  Client(EventLoop* loop,
         const InetAddress& serverAddr,
         int blockSize,
         int sessionCount,
         int timeout,
         int threadCount)
    : loop_(loop),
      threadPool_(loop),
      sessionCount_(sessionCount),
      timeout_(timeout)
  {
    loop->runAfter(timeout, boost::bind(&Client::handleTimeout, this));
    if (threadCount > 1)
    {
      threadPool_.setThreadNum(threadCount);
    }
    threadPool_.start();

    for (int i = 0; i < blockSize; ++i)
    {
      message_.push_back(static_cast<char>(i % 128));
    }

    for (int i = 0; i < sessionCount; ++i)
    {
      char buf[32];
      snprintf(buf, sizeof buf, "C%05d", i);
      Session* session = new Session(threadPool_.getNextLoop(), serverAddr, buf, this);
      session->start();
      sessions_.push_back(session);
    }
  }

  const string& message() const
  {
    return message_;
  }

  void onConnect()
  {
    if (numConnected_.incrementAndGet() == sessionCount_)
    {
      LOG_WARN << "all connected";
    }
  }

  void onDisconnect(const TcpConnectionPtr& conn)
  {
    if (numConnected_.decrementAndGet() == 0)
    {
      LOG_WARN << "all disconnected";

      int64_t totalBytesRead = 0;
      int64_t totalMessagesRead = 0;
      for (boost::ptr_vector<Session>::iterator it = sessions_.begin();
          it != sessions_.end(); ++it)
      {
        totalBytesRead += it->bytesRead();
        totalMessagesRead += it->messagesRead();
      }
      LOG_WARN << totalBytesRead << " total bytes read";
      LOG_WARN << totalMessagesRead << " total messages read";
      LOG_WARN << static_cast<double>(totalBytesRead) / static_cast<double>(totalMessagesRead)
               << " average message size";
      LOG_WARN << static_cast<double>(totalBytesRead) / (timeout_ * 1024 * 1024)
               << " MiB/s throughput";
      conn->getLoop()->queueInLoop(boost::bind(&Client::quit, this));
    }
  }

 private:

  void quit()
  {
    loop_->queueInLoop(boost::bind(&EventLoop::quit, loop_));
  }

  void handleTimeout()
  {
    LOG_WARN << "stop";
    std::for_each(sessions_.begin(), sessions_.end(),
                  boost::mem_fn(&Session::stop));
  }

  EventLoop* loop_;
  EventLoopThreadPool threadPool_;
  int sessionCount_;
  int timeout_;
  boost::ptr_vector<Session> sessions_;
  string message_;
  AtomicInt32 numConnected_;
};

void Session::onConnection(const TcpConnectionPtr& conn)
{
  if (conn->connected())
  {
    conn->setTcpNoDelay(true);
    conn->send(owner_->message());
    owner_->onConnect();
  }
  else
  {
    owner_->onDisconnect(conn);
  }
}

int main(int argc, char* argv[])
{
  if (argc != 7)
  {
    fprintf(stderr, "Usage: client <host_ip> <port> <threads> <blocksize> ");
    fprintf(stderr, "<sessions> <time>\n");
  }
  else
  {
    LOG_INFO << "pid = " << getpid() << ", tid = " << CurrentThread::tid();
    Logger::setLogLevel(Logger::WARN);

    const char* ip = argv[1];
    uint16_t port = static_cast<uint16_t>(atoi(argv[2]));
    int threadCount = atoi(argv[3]);
    int blockSize = atoi(argv[4]);
    int sessionCount = atoi(argv[5]);
    int timeout = atoi(argv[6]);

    EventLoop loop;
    InetAddress serverAddr(ip, port);

    Client client(&loop, serverAddr, blockSize, sessionCount, timeout, threadCount);
    loop.loop();
  }
}

<|endoftext|>


<commit_before>//
// Copyright © 2017 Arm Ltd. All rights reserved.
// SPDX-License-Identifier: MIT
//

#include "NeonInterceptorScheduler.hpp"

#include <boost/assert.hpp>

namespace armnn{

NeonInterceptorScheduler::NeonInterceptorScheduler(arm_compute::IScheduler &realScheduler)
        : m_RealScheduler(realScheduler)
{
}

void NeonInterceptorScheduler::set_num_threads(unsigned int numThreads)
{
    m_RealScheduler.set_num_threads(numThreads);
}

unsigned int NeonInterceptorScheduler::num_threads() const
{
    return m_RealScheduler.num_threads();
}

void NeonInterceptorScheduler::schedule(arm_compute::ICPPKernel* kernel, const Hints& hints)
{
    WallClockTimer::clock::time_point startTime = WallClockTimer::clock::now();
    m_RealScheduler.schedule(kernel, hints.split_dimension());
    WallClockTimer::clock::time_point stopTime = WallClockTimer::clock::now();

    const auto delta       = std::chrono::duration<double, std::micro>(stopTime - startTime);
    m_Kernels->emplace_back(kernel->name(), delta.count(), Measurement::Unit::TIME_US);
}

void NeonInterceptorScheduler::run_workloads(std::vector <Workload>& workloads)
{
    WallClockTimer::clock::time_point startTime = WallClockTimer::clock::now();
    m_RealScheduler.run_tagged_workloads(workloads, nullptr);
    WallClockTimer::clock::time_point stopTime = WallClockTimer::clock::now();

    const auto delta       = std::chrono::duration<double, std::micro>(stopTime - startTime);
    m_Kernels->emplace_back(std::string("Workload"), delta.count(), Measurement::Unit::TIME_US);
}

} // namespace armnn<commit_msg>IVGCVSW-1823 Fix uninitialised member<commit_after>//
// Copyright © 2017 Arm Ltd. All rights reserved.
// SPDX-License-Identifier: MIT
//

#include "NeonInterceptorScheduler.hpp"

#include <boost/assert.hpp>

namespace armnn{

NeonInterceptorScheduler::NeonInterceptorScheduler(arm_compute::IScheduler &realScheduler)
        : m_Kernels(nullptr), m_RealScheduler(realScheduler)
{
}

void NeonInterceptorScheduler::set_num_threads(unsigned int numThreads)
{
    m_RealScheduler.set_num_threads(numThreads);
}

unsigned int NeonInterceptorScheduler::num_threads() const
{
    return m_RealScheduler.num_threads();
}

void NeonInterceptorScheduler::schedule(arm_compute::ICPPKernel* kernel, const Hints& hints)
{
    WallClockTimer::clock::time_point startTime = WallClockTimer::clock::now();
    m_RealScheduler.schedule(kernel, hints.split_dimension());
    WallClockTimer::clock::time_point stopTime = WallClockTimer::clock::now();

    const auto delta       = std::chrono::duration<double, std::micro>(stopTime - startTime);
    m_Kernels->emplace_back(kernel->name(), delta.count(), Measurement::Unit::TIME_US);
}

void NeonInterceptorScheduler::run_workloads(std::vector <Workload>& workloads)
{
    WallClockTimer::clock::time_point startTime = WallClockTimer::clock::now();
    m_RealScheduler.run_tagged_workloads(workloads, nullptr);
    WallClockTimer::clock::time_point stopTime = WallClockTimer::clock::now();

    const auto delta       = std::chrono::duration<double, std::micro>(stopTime - startTime);
    m_Kernels->emplace_back(std::string("Workload"), delta.count(), Measurement::Unit::TIME_US);
}

} // namespace armnn<|endoftext|>


<commit_before>// Copyright (C) 2012-2015 Leap Motion, Inc. All rights reserved.
#include "stdafx.h"
#include <autowiring/observable.h>

class ObservableTest:
  public testing::Test
{};

TEST_F(ObservableTest, SimpleAssignmentCheck) {
  autowiring::observable<int> ob;

  bool hit = false;
  ob.onChanged += [&hit] { hit = true; };
  ob = 2;
  ASSERT_TRUE(hit) << "OnChanged handler not hit when the observable value was modified";
}

TEST_F(ObservableTest, BeforeAndAfter) {
  autowiring::observable<int> ob;
  ob = 8;

  bool hit = false;
  ob.onChanged += [&hit] { hit = true; };

  int obBefore = 0;
  int obAfter = 0;
  ob.onBeforeChanged += [&] (const int& before, const int& after) {
    obBefore = before;
    obAfter = after;
  };

  ob = 9;

  ASSERT_TRUE(hit) << "Change notification not raised";
  ASSERT_EQ(8, obBefore) << "\"Before\" value in onBeforeChanged was not correct";
  ASSERT_EQ(9, obAfter) << "\"AfFter\" value in onBeforeChanged was not correct";
}
<commit_msg>Add a test case for operator *<commit_after>// Copyright (C) 2012-2015 Leap Motion, Inc. All rights reserved.
#include "stdafx.h"
#include <autowiring/observable.h>

class ObservableTest:
  public testing::Test
{};

TEST_F(ObservableTest, SimpleAssignmentCheck) {
  autowiring::observable<int> ob;

  bool hit = false;
  ob.onChanged += [&hit] { hit = true; };
  ob = 2;
  ASSERT_TRUE(hit) << "OnChanged handler not hit when the observable value was modified";
  ASSERT_EQ(2, *ob) << "operator * gives an incorrect value";
}

TEST_F(ObservableTest, BeforeAndAfter) {
  autowiring::observable<int> ob;
  ob = 8;

  bool hit = false;
  ob.onChanged += [&hit] { hit = true; };

  int obBefore = 0;
  int obAfter = 0;
  ob.onBeforeChanged += [&] (const int& before, const int& after) {
    obBefore = before;
    obAfter = after;
  };

  ob = 9;

  ASSERT_TRUE(hit) << "Change notification not raised";
  ASSERT_EQ(8, obBefore) << "\"Before\" value in onBeforeChanged was not correct";
  ASSERT_EQ(9, obAfter) << "\"AfFter\" value in onBeforeChanged was not correct";
}
<|endoftext|>


<commit_before>/*
* BCJR Decoding, Memoryless Modulation, and Filtering come from Tarik BENADDI (Toulouse INP)
*/
#include <cassert>
#include <cstdlib>
#include <cstdio>
#include <cmath>

#include "../../../Decoder/decoder_functions.h"

#include "Modulator_GSM_BCJR.hpp"

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// BCJR tools //////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template <typename Q>
struct negative_inf
{
	static Q get() { return -std::numeric_limits<Q>::max(); }
};

template <>
struct negative_inf <short>
{
	static short get() { return -(1 << (sizeof(short) * 8 -2)); }
};

template <>
struct negative_inf <signed char>
{
	static signed char get() { return -63; }
};

template <typename Q, proto_max<Q> MAX>
struct BCJR_normalize
{
	// Adrien comment's: I think that the normalisation is useless in floating point arithmetic
	static void apply(Q *metrics, const int &i, const int &n_states)
	{
		// normalization
		auto norm_val = negative_inf<Q>::get();
		for (auto j = 0; j < n_states; j++)
			norm_val = MAX(norm_val, metrics[j]);

		for (auto j = 0; j < n_states; j++)
			metrics[j] -= norm_val;
	}
};

template <proto_max<signed char> MAX>
struct BCJR_normalize <signed char,MAX>
{
	static void apply(signed char *metrics, const int &i, const int &n_states)
	{
		// normalization & saturation
		auto norm_val = negative_inf<signed char>::get();
		for (auto j = 0; j < n_states; j++)
			norm_val = MAX(norm_val, metrics[j]);

		for (auto j = 0; j < n_states; j++)
			metrics[j] = saturate<signed char>(metrics[j] - norm_val, -63, +63);
	}
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

template <typename Q, proto_max<Q> MAX>
Modulator_GSM_BCJR<Q,MAX>
::Modulator_GSM_BCJR(const int frame_size,
	                 const int n_states,
	                 const int m_order,
	                 const int n_bits_per_symb,
	                 const int n_prev_branches,
	                 const std::vector<int> binary_symbols,
	                 const std::vector<int> trellis,
	                 const std::vector<int> anti_trellis)
: frame_size     (frame_size     ),
  n_states       (n_states       ),
  m_order        (m_order        ),
  n_bits_per_symb(n_bits_per_symb),
  n_prev_branches(n_prev_branches),

  binary_symbols(binary_symbols),
  trellis       (trellis       ),
  anti_trellis  (anti_trellis  ),

  symb_apriori_prob(frame_size            * m_order   ),
  gamma            (frame_size * n_states * m_order   ),
  alpha            (frame_size * n_states             ),
  beta             (frame_size * n_states             ),
  proba_msg_symb   (frame_size            * m_order, 0),
  proba_msg_bits   (frame_size            * 2      , 0)
{
}

template <typename Q, proto_max<Q> MAX>
Modulator_GSM_BCJR<Q,MAX>
::~Modulator_GSM_BCJR()
{
}

template <typename Q, proto_max<Q> MAX>
void Modulator_GSM_BCJR<Q,MAX>
::decode(const mipp::vector<Q> &Lch_N, mipp::vector<Q> &Le_N)
{
	std::fill(this->symb_apriori_prob.begin(), this->symb_apriori_prob.end(), 0);

	compute_alpha_beta_gamma(Lch_N);
	symboles_probas         (     );
	bits_probas             (     );
	compute_ext             (Le_N );
}

template <typename Q, proto_max<Q> MAX>
void Modulator_GSM_BCJR<Q,MAX>
::decode(const mipp::vector<Q> &Lch_N, const mipp::vector<Q> &Ldec_N, mipp::vector<Q> &Le_N)
{
	LLR_to_logsymb_proba    (Ldec_N      );
	compute_alpha_beta_gamma(Lch_N       );
	symboles_probas         (            );
	bits_probas             (            );
	compute_ext             (Ldec_N, Le_N);
}

// retrieve log symbols probability from LLR
template <typename Q, proto_max<Q> MAX>
void Modulator_GSM_BCJR<Q,MAX>
::LLR_to_logsymb_proba(const mipp::vector<Q> &Ldec_N)
{
	std::fill(this->symb_apriori_prob.begin(), this->symb_apriori_prob.end(), 0);

	for (auto i = 0; i < (int) this->symb_apriori_prob.size() / m_order; i++)
		for (auto j = 0; j < this->m_order; j++)
			for (auto k = 0; k < this->n_bits_per_symb; k++)
			{
				const auto symbol = this->binary_symbols[k * this->m_order +j];
				const auto sign   = 1 - (symbol + symbol);
				this->symb_apriori_prob[i * this->m_order +j] += (Q)sign * Ldec_N[i * this->n_bits_per_symb +k] * 0.5;
			}
}

// compute gamma, alpha and beta, heart of the processing
template <typename Q, proto_max<Q> MAX>
void Modulator_GSM_BCJR<Q,MAX>
::compute_alpha_beta_gamma(const mipp::vector<Q> &Lch_N)
{
	// alpha and beta initialization
	std::fill(this->alpha.begin(), this->alpha.end(), negative_inf<Q>::get());
	std::fill(this->beta .begin(), this->beta .end(), negative_inf<Q>::get());
	this->alpha[0                                     ] = 0;
	this->beta [(this->frame_size -1) * this->n_states] = 0;

	// other way to initialize beta: does not support the fixed point mode because of the log function call
	// this is usefull when we don't use the tail bits in the turbo demodulation
	// auto beta_final_equi_proba = 1.0 / this->n_states;
	for (auto i = 0; i < this->n_states; i++)
		// this->beta[(this->frame_size -1) * n_states +i] = std::log(beta_final_equi_proba);
		this->beta[(this->frame_size -1) * n_states +i] = 0;

	// compute gamma
	for (auto i = 0; i < this->frame_size; i++)
		for (auto j = 0; j < this->n_states; j++)
			for (auto k = 0; k < this->m_order; k++)
				this->gamma[(k * n_states +j) * this->frame_size +i] =
					Lch_N[this->trellis[(k + this->m_order) * this->n_states +j] * this->frame_size +i] + // info from the channel
					this->symb_apriori_prob[i * this->m_order +k];                                        // info from the decoder

	// compute alpha and beta
	for (auto i = 1; i < this->frame_size; i++)
	{
		for (auto j = 0; j < this->n_states; j++)
		{
			const auto original_state = this->anti_trellis.data() +                  j  * this->n_prev_branches;
			const auto input_symb     = this->anti_trellis.data() + (this->n_states +j) * this->n_prev_branches;

			// compute the alpha nodes
			for (auto k = 0; k < this->n_prev_branches; k++)
				this->alpha        [(i -0) * this->n_states                  +j] =
				    MAX(this->alpha[(i -0) * this->n_states                  +j],
				        this->alpha[(i -1) * this->n_states + original_state[k]] +
				        this->gamma[(input_symb[k] * this->n_states + original_state[k]) * this->frame_size +i -1]);

			// compute the beta nodes
			for (auto k = 0; k < this->m_order; k++)
				this->beta         [(this->frame_size - (i +1)) * this->n_states                                     +j] =
				    MAX(this->beta [(this->frame_size - (i +1)) * this->n_states                                     +j],
				        this->beta [(this->frame_size - (i +0)) * this->n_states + this->trellis[k * this->n_states +j]] +
				        this->gamma[(k * this->n_states +j) * this->frame_size + this->frame_size -i]);
		}

		// normalize alpha and beta vectors (not impact on the decoding performances)
		BCJR_normalize<Q,MAX>::apply(&this->alpha[                    (i +0)  * this->n_states], i, this->n_states);
		BCJR_normalize<Q,MAX>::apply(&this->beta [(this->frame_size - (i +1)) * this->n_states], i, this->n_states);
	}
}

// from alpha, beta, and gamma computes new symbol probability
template <typename Q, proto_max<Q> MAX>
void Modulator_GSM_BCJR<Q,MAX>
::symboles_probas()
{
	// initialize proba_msg_symb
	for (auto i = 0; i < this->frame_size; i++)
		for (auto j = 0; j < this->m_order; j++)
			proba_msg_symb[i * this->m_order +j] = negative_inf<Q>::get();

	for (auto i = 0; i < this->frame_size; i++)
		for (auto j = 0; j < this->m_order; j++)
			for (auto k = 0; k < this->n_states; k++)
				proba_msg_symb        [ i * this->m_order                                      +j] =
				    MAX(proba_msg_symb[ i * this->m_order                                      +j],
				        this->alpha   [ i * this->n_states                                     +k] +
				        this->beta    [ i * this->n_states + this->trellis[j * this->n_states +k]] +
				        this->gamma   [(j * this->n_states +k) * this->frame_size              +i]);
}

// from symbol probabilities, computes bit probabilities
template <typename Q, proto_max<Q> MAX>
void Modulator_GSM_BCJR<Q,MAX>
::bits_probas()
{
	// initialize proba_msg_bits
	std::fill(proba_msg_bits.begin(), proba_msg_bits.end(), negative_inf<Q>::get());

	for (auto i = 0; i < this->frame_size; i++)
	{
		const auto ii = i * this->n_bits_per_symb;
		for (auto j = 0; j < n_bits_per_symb; j++)
			for (auto k = 0; k < this->m_order; k++)
			{
				const auto symbol = binary_symbols[j * this->m_order +k];

				// bit 0
				if (symbol == 0)
					proba_msg_bits[(ii +j) * 2 +0] = MAX(proba_msg_bits[(ii +j) * 2 +0],
					                                     proba_msg_symb[i * this->m_order +k]);
				// bit 1
				else if (symbol == 1)
					proba_msg_bits[(ii +j) * 2 +1] = MAX(proba_msg_bits[(ii +j) * 2 +1],
					                                     proba_msg_symb[i * this->m_order +k]);
			}
	}
}

// extrinsic information processing from bit probabilities
template <typename Q, proto_max<Q> MAX>
void Modulator_GSM_BCJR<Q,MAX>
::compute_ext(mipp::vector<Q> &Le_N)
{
	const auto loop_size = (int)Le_N.size() * 2;
	for (auto i = 0; i < loop_size; i += 2)
		// processing aposteriori and substracting a priori to directly obtain extrinsic
		Le_N[i / 2] = proba_msg_bits[i] - proba_msg_bits[i +1];
}

// extrinsic information processing from bit probabilities and CPM a priori LLR
template <typename Q, proto_max<Q> MAX>
void Modulator_GSM_BCJR<Q,MAX>
::compute_ext(const mipp::vector<Q> &Ldec_N,
                    mipp::vector<Q> &Le_N)
{
	const auto loop_size = (int)Le_N.size() * 2;
	for (auto i = 0; i < loop_size; i += 2)
		// processing aposteriori and substracting a priori to directly obtain extrinsic
		Le_N[i / 2] = proba_msg_bits[i] - (proba_msg_bits[i +1] + Ldec_N[i / 2]);
}<commit_msg>Fix a memory leak in the GSM modulator.<commit_after>/*
* BCJR Decoding, Memoryless Modulation, and Filtering come from Tarik BENADDI (Toulouse INP)
*/
#include <cassert>
#include <cstdlib>
#include <cstdio>
#include <cmath>

#include "../../../Decoder/decoder_functions.h"

#include "Modulator_GSM_BCJR.hpp"

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// BCJR tools //////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template <typename Q>
struct negative_inf
{
	static Q get() { return -std::numeric_limits<Q>::max(); }
};

template <>
struct negative_inf <short>
{
	static short get() { return -(1 << (sizeof(short) * 8 -2)); }
};

template <>
struct negative_inf <signed char>
{
	static signed char get() { return -63; }
};

template <typename Q, proto_max<Q> MAX>
struct BCJR_normalize
{
	// Adrien comment's: I think that the normalisation is useless in floating point arithmetic
	static void apply(Q *metrics, const int &i, const int &n_states)
	{
		// normalization
		auto norm_val = negative_inf<Q>::get();
		for (auto j = 0; j < n_states; j++)
			norm_val = MAX(norm_val, metrics[j]);

		for (auto j = 0; j < n_states; j++)
			metrics[j] -= norm_val;
	}
};

template <proto_max<signed char> MAX>
struct BCJR_normalize <signed char,MAX>
{
	static void apply(signed char *metrics, const int &i, const int &n_states)
	{
		// normalization & saturation
		auto norm_val = negative_inf<signed char>::get();
		for (auto j = 0; j < n_states; j++)
			norm_val = MAX(norm_val, metrics[j]);

		for (auto j = 0; j < n_states; j++)
			metrics[j] = saturate<signed char>(metrics[j] - norm_val, -63, +63);
	}
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

template <typename Q, proto_max<Q> MAX>
Modulator_GSM_BCJR<Q,MAX>
::Modulator_GSM_BCJR(const int frame_size,
	                 const int n_states,
	                 const int m_order,
	                 const int n_bits_per_symb,
	                 const int n_prev_branches,
	                 const std::vector<int> binary_symbols,
	                 const std::vector<int> trellis,
	                 const std::vector<int> anti_trellis)
: frame_size     (frame_size     ),
  n_states       (n_states       ),
  m_order        (m_order        ),
  n_bits_per_symb(n_bits_per_symb),
  n_prev_branches(n_prev_branches),

  binary_symbols(binary_symbols),
  trellis       (trellis       ),
  anti_trellis  (anti_trellis  ),

  symb_apriori_prob(frame_size            * m_order   ),
  gamma            (frame_size * n_states * m_order   ),
  alpha            (frame_size * n_states             ),
  beta             (frame_size * n_states             ),
  proba_msg_symb   (frame_size            * m_order, 0),
  proba_msg_bits   (frame_size            * 2      , 0)
{
}

template <typename Q, proto_max<Q> MAX>
Modulator_GSM_BCJR<Q,MAX>
::~Modulator_GSM_BCJR()
{
}

template <typename Q, proto_max<Q> MAX>
void Modulator_GSM_BCJR<Q,MAX>
::decode(const mipp::vector<Q> &Lch_N, mipp::vector<Q> &Le_N)
{
	std::fill(this->symb_apriori_prob.begin(), this->symb_apriori_prob.end(), 0);

	compute_alpha_beta_gamma(Lch_N);
	symboles_probas         (     );
	bits_probas             (     );
	compute_ext             (Le_N );
}

template <typename Q, proto_max<Q> MAX>
void Modulator_GSM_BCJR<Q,MAX>
::decode(const mipp::vector<Q> &Lch_N, const mipp::vector<Q> &Ldec_N, mipp::vector<Q> &Le_N)
{
	LLR_to_logsymb_proba    (Ldec_N      );
	compute_alpha_beta_gamma(Lch_N       );
	symboles_probas         (            );
	bits_probas             (            );
	compute_ext             (Ldec_N, Le_N);
}

// retrieve log symbols probability from LLR
template <typename Q, proto_max<Q> MAX>
void Modulator_GSM_BCJR<Q,MAX>
::LLR_to_logsymb_proba(const mipp::vector<Q> &Ldec_N)
{
	assert(Ldec_N.size() <= this->symb_apriori_prob.size() / m_order);

	std::fill(this->symb_apriori_prob.begin(), this->symb_apriori_prob.end(), 0);

	for (auto i = 0; i < (int)Ldec_N.size(); i++)
		for (auto j = 0; j < this->m_order; j++)
			for (auto k = 0; k < this->n_bits_per_symb; k++)
			{
				const auto symbol = this->binary_symbols[k * this->m_order +j];
				const auto sign   = 1 - (symbol + symbol);
				this->symb_apriori_prob[i * this->m_order +j] += (Q)sign * Ldec_N[i * this->n_bits_per_symb +k] * 0.5;
			}
}

// compute gamma, alpha and beta, heart of the processing
template <typename Q, proto_max<Q> MAX>
void Modulator_GSM_BCJR<Q,MAX>
::compute_alpha_beta_gamma(const mipp::vector<Q> &Lch_N)
{
	// alpha and beta initialization
	std::fill(this->alpha.begin(), this->alpha.end(), negative_inf<Q>::get());
	std::fill(this->beta .begin(), this->beta .end(), negative_inf<Q>::get());
	this->alpha[0                                     ] = 0;
	this->beta [(this->frame_size -1) * this->n_states] = 0;

	// other way to initialize beta: does not support the fixed point mode because of the log function call
	// this is usefull when we don't use the tail bits in the turbo demodulation
	// auto beta_final_equi_proba = 1.0 / this->n_states;
	for (auto i = 0; i < this->n_states; i++)
		// this->beta[(this->frame_size -1) * n_states +i] = std::log(beta_final_equi_proba);
		this->beta[(this->frame_size -1) * n_states +i] = 0;

	// compute gamma
	for (auto i = 0; i < this->frame_size; i++)
		for (auto j = 0; j < this->n_states; j++)
			for (auto k = 0; k < this->m_order; k++)
				this->gamma[(k * n_states +j) * this->frame_size +i] =
					Lch_N[this->trellis[(k + this->m_order) * this->n_states +j] * this->frame_size +i] + // info from the channel
					this->symb_apriori_prob[i * this->m_order +k];                                        // info from the decoder

	// compute alpha and beta
	for (auto i = 1; i < this->frame_size; i++)
	{
		for (auto j = 0; j < this->n_states; j++)
		{
			const auto original_state = this->anti_trellis.data() +                  j  * this->n_prev_branches;
			const auto input_symb     = this->anti_trellis.data() + (this->n_states +j) * this->n_prev_branches;

			// compute the alpha nodes
			for (auto k = 0; k < this->n_prev_branches; k++)
				this->alpha        [(i -0) * this->n_states                  +j] =
				    MAX(this->alpha[(i -0) * this->n_states                  +j],
				        this->alpha[(i -1) * this->n_states + original_state[k]] +
				        this->gamma[(input_symb[k] * this->n_states + original_state[k]) * this->frame_size +i -1]);

			// compute the beta nodes
			for (auto k = 0; k < this->m_order; k++)
				this->beta         [(this->frame_size - (i +1)) * this->n_states                                     +j] =
				    MAX(this->beta [(this->frame_size - (i +1)) * this->n_states                                     +j],
				        this->beta [(this->frame_size - (i +0)) * this->n_states + this->trellis[k * this->n_states +j]] +
				        this->gamma[(k * this->n_states +j) * this->frame_size + this->frame_size -i]);
		}

		// normalize alpha and beta vectors (not impact on the decoding performances)
		BCJR_normalize<Q,MAX>::apply(&this->alpha[                    (i +0)  * this->n_states], i, this->n_states);
		BCJR_normalize<Q,MAX>::apply(&this->beta [(this->frame_size - (i +1)) * this->n_states], i, this->n_states);
	}
}

// from alpha, beta, and gamma computes new symbol probability
template <typename Q, proto_max<Q> MAX>
void Modulator_GSM_BCJR<Q,MAX>
::symboles_probas()
{
	// initialize proba_msg_symb
	for (auto i = 0; i < this->frame_size; i++)
		for (auto j = 0; j < this->m_order; j++)
			proba_msg_symb[i * this->m_order +j] = negative_inf<Q>::get();

	for (auto i = 0; i < this->frame_size; i++)
		for (auto j = 0; j < this->m_order; j++)
			for (auto k = 0; k < this->n_states; k++)
				proba_msg_symb        [ i * this->m_order                                      +j] =
				    MAX(proba_msg_symb[ i * this->m_order                                      +j],
				        this->alpha   [ i * this->n_states                                     +k] +
				        this->beta    [ i * this->n_states + this->trellis[j * this->n_states +k]] +
				        this->gamma   [(j * this->n_states +k) * this->frame_size              +i]);
}

// from symbol probabilities, computes bit probabilities
template <typename Q, proto_max<Q> MAX>
void Modulator_GSM_BCJR<Q,MAX>
::bits_probas()
{
	// initialize proba_msg_bits
	std::fill(proba_msg_bits.begin(), proba_msg_bits.end(), negative_inf<Q>::get());

	for (auto i = 0; i < this->frame_size; i++)
	{
		const auto ii = i * this->n_bits_per_symb;
		for (auto j = 0; j < n_bits_per_symb; j++)
			for (auto k = 0; k < this->m_order; k++)
			{
				const auto symbol = binary_symbols[j * this->m_order +k];

				// bit 0
				if (symbol == 0)
					proba_msg_bits[(ii +j) * 2 +0] = MAX(proba_msg_bits[(ii +j) * 2 +0],
					                                     proba_msg_symb[i * this->m_order +k]);
				// bit 1
				else if (symbol == 1)
					proba_msg_bits[(ii +j) * 2 +1] = MAX(proba_msg_bits[(ii +j) * 2 +1],
					                                     proba_msg_symb[i * this->m_order +k]);
			}
	}
}

// extrinsic information processing from bit probabilities
template <typename Q, proto_max<Q> MAX>
void Modulator_GSM_BCJR<Q,MAX>
::compute_ext(mipp::vector<Q> &Le_N)
{
	const auto loop_size = (int)Le_N.size() * 2;
	for (auto i = 0; i < loop_size; i += 2)
		// processing aposteriori and substracting a priori to directly obtain extrinsic
		Le_N[i / 2] = proba_msg_bits[i] - proba_msg_bits[i +1];
}

// extrinsic information processing from bit probabilities and CPM a priori LLR
template <typename Q, proto_max<Q> MAX>
void Modulator_GSM_BCJR<Q,MAX>
::compute_ext(const mipp::vector<Q> &Ldec_N,
                    mipp::vector<Q> &Le_N)
{
	const auto loop_size = (int)Le_N.size() * 2;
	for (auto i = 0; i < loop_size; i += 2)
		// processing aposteriori and substracting a priori to directly obtain extrinsic
		Le_N[i / 2] = proba_msg_bits[i] - (proba_msg_bits[i +1] + Ldec_N[i / 2]);
}<|endoftext|>