<commit_before>/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

// Usage: replay_computation some_binary_snapshot_proto*
//
// Replays computations and shows the results on the command line.
//
// some_binary_snapshot_proto is obtained by serializing the HloSnapshot from
// ServiceInterface::SnapshotComputation to disk.
//
// Computations that require arguments can be replayed using fake data by
// passing --use_fake_data on the command line.  If the real data is available
// in the proto and --use_fake_data is false, the real data is used.
//
// Input can be a binary HloSnapshot proto, a binary HloProto proto, or a
// textual HLO string.
//
// The output format is:
//
// file_path: computation_name :: type:literal_str

#include <stdio.h>
#include <memory>
#include <string>
#include <utility>
#include <vector>

#include "tensorflow/compiler/xla/client/client.h"
#include "tensorflow/compiler/xla/client/client_library.h"
#include "tensorflow/compiler/xla/client/global_data.h"
#include "tensorflow/compiler/xla/client/lib/testing.h"
#include "tensorflow/compiler/xla/client/local_client.h"
#include "tensorflow/compiler/xla/client/xla_computation.h"
#include "tensorflow/compiler/xla/execution_options_util.h"
#include "tensorflow/compiler/xla/legacy_flags/debug_options_flags.h"
#include "tensorflow/compiler/xla/literal.h"
#include "tensorflow/compiler/xla/service/gpu/infeed_manager.h"
#include "tensorflow/compiler/xla/service/hlo.pb.h"
#include "tensorflow/compiler/xla/service/hlo_parser.h"
#include "tensorflow/compiler/xla/shape_util.h"
#include "tensorflow/compiler/xla/status_macros.h"
#include "tensorflow/compiler/xla/statusor.h"
#include "tensorflow/compiler/xla/tests/test_utils.h"
#include "tensorflow/compiler/xla/types.h"
#include "tensorflow/compiler/xla/xla_data.pb.h"
#include "tensorflow/core/lib/core/threadpool.h"
#include "tensorflow/core/lib/gtl/array_slice.h"
#include "tensorflow/core/platform/env.h"
#include "tensorflow/core/platform/init_main.h"
#include "tensorflow/core/platform/logging.h"
#include "tensorflow/core/util/command_line_flags.h"

namespace xla {
namespace tools {
namespace {

// Command-line opts to this tool.  See main() for descriptions of these
// fields.
struct Options {
  string fake_infeed_shape;
  bool generate_fake_infeed = false;
  bool use_fake_data = false;
  bool print_result = true;
  int num_runs = 1;
};

// Invokes the given computation passing arbitrary data for every (unbound)
// parameter if use_fake_data, Otherwise use recorded data if available.
//
// Similarly, infeeds fake data of shape fake_infeed_shape if it is provided.
// If generate_fake_infeed is true, the required infeed shape is derived from
// the computation and then used to provide a fake infeed shape.
//
// If neither generate_fake_infeed is true nor a fake_infeed_shape is provided,
// no infeed is performed.
StatusOr<Literal> ReplayComputation(const HloSnapshot& module,
                                    LocalClient* client, const Options& opts) {
  XlaComputation computation(module.hlo().hlo_module());

  // Build the `argument_ptrs` vector, which contains ShapedBuffer*s to our
  // arguments.  This is a bit involved, because we may have to convert from
  // GlobalData to ShapedBuffer*, and we have to manage the lifetime of all our
  // objects.
  std::vector<ScopedShapedBuffer> scoped_shaped_buffer_arguments;
  std::vector<std::unique_ptr<GlobalData>> global_data_arguments;
  std::vector<const ShapedBuffer*> argument_ptrs;
  if (opts.use_fake_data) {
    global_data_arguments = MakeFakeArgumentsOrDie(computation, client);
    for (const auto& data : global_data_arguments) {
      argument_ptrs.push_back(
          client->GlobalDataToShapedBuffer(data->handle(), /*device_ordinal=*/0)
              .ValueOrDie());
    }
  } else {  // use recorded data if available
    for (const auto& proto : module.arguments()) {
      TF_ASSIGN_OR_RETURN(std::unique_ptr<xla::Literal> literal,
                          Literal::CreateFromProto(proto));
      TF_ASSIGN_OR_RETURN(
          ScopedShapedBuffer data,
          client->LiteralToShapedBuffer(*literal, /*device_ordinal=*/0));
      scoped_shaped_buffer_arguments.push_back(std::move(data));
    }
    for (const auto& argument : scoped_shaped_buffer_arguments) {
      argument_ptrs.push_back(&argument);
    }
  }

  bool provide_infeed = false;
  Shape infeed_shape;
  if (!opts.fake_infeed_shape.empty()) {
    StatusOr<Shape> shape_status =
        ShapeUtil::ParseShapeString(opts.fake_infeed_shape);
    TF_CHECK_OK(shape_status.status());
    infeed_shape = std::move(shape_status).ValueOrDie();
    provide_infeed = true;
  } else if (opts.generate_fake_infeed) {
    for (const auto& comp : computation.proto().computations()) {
      for (const auto& instruction : comp.instructions()) {
        if (instruction.opcode() == HloOpcodeString(HloOpcode::kInfeed)) {
          CHECK(!provide_infeed)
              << "--generate_fake_infeed only works if the model has 0 or 1 "
                 "infeed ops, but this one has >= 2.";
          provide_infeed = true;
          infeed_shape = instruction.shape();
          LOG(INFO) << "Generating fake infeed shape for inferred shape: "
                    << ShapeUtil::HumanString(infeed_shape);
        }
      }
    }
  }
  // We only instantiate the thread pool if the user has requested that a
  // concurrent infeed occur via the fake_infeed_shape, or when
  // --generate_fake_infeed is passed and there exists an infeed operation in
  // the HloSnapshot.
  tensorflow::gtl::optional<tensorflow::thread::ThreadPool> pool;
  std::unique_ptr<Literal> data;
  if (provide_infeed) {
    data = std::move(MakeFakeLiteral(infeed_shape)).ValueOrDie();
  }
  auto transfer_infeed = [&data, client]() {
    TF_CHECK_OK(client->TransferToInfeed(*data));
  };
  if (provide_infeed) {
    pool.emplace(tensorflow::Env::Default(), "infeed",
                 /*num_threads=*/1);
    pool->Schedule([transfer_infeed]() {
      // There may be several infeed buffers needed, however we don't know how
      // many. If we proactively transfer too many infeed buffers, we may run
      // out of memory. If we transfer too few infeed buffers, the program will
      // hang. Therefore, we register a callback that is called when the infeed
      // becomes empty, and in this callback we will transfer another fake
      // infeed.
      auto infeed_manager = xla::gpu::GetOrCreateInfeedManager();
      infeed_manager->RegisterOnEmptyCallback(transfer_infeed);
      transfer_infeed();
    });
  }

  std::vector<const Shape*> argument_layouts;
  for (const auto& param : computation.proto().program_shape().parameters()) {
    argument_layouts.push_back(&param);
  }
  std::unique_ptr<LocalExecutable> executable =
      client->Compile(computation, argument_layouts, ExecutableBuildOptions())
          .ValueOrDie();

  // Do not attmept to run the executable, if num_runs is less than 1.
  if (opts.num_runs < 1) {
    return Cancelled("Cancelled after compilation since --num_runs < 1.");
  }

  // Run the computation num_runs times, and return the result from the last
  // execution.
  const bool xla_hlo_profile =
      legacy_flags::GetDebugOptionsFromFlags().xla_hlo_profile();
  StreamExecutorMemoryAllocator allocator(
      client->platform(),
      {client->platform()->ExecutorForDevice(0).ValueOrDie()});
  tensorflow::gtl::optional<ScopedShapedBuffer> result;
  for (int i = 0; i < opts.num_runs; ++i) {
    // If xla_hlo_profile is enabled, print a noisy message before the last run,
    // making it easier to separate this profile from the others in the logspam.
    if (xla_hlo_profile && i == opts.num_runs - 1) {
      LOG(INFO) << "\n\n***** Final run below ******";
    }
    ExecutionProfile profile;
    ExecutableRunOptions run_options;
    run_options.set_execution_profile(&profile);
    run_options.set_allocator(&allocator);

    TF_ASSIGN_OR_RETURN(result, executable->Run(argument_ptrs, run_options));
    LOG(INFO) << "Execution took "
              << static_cast<double>(profile.compute_time_ns()) / 1e9 << "s";
  }

  TF_ASSIGN_OR_RETURN(std::unique_ptr<Literal> result_literal,
                      client->ShapedBufferToLiteral(*result));
  return std::move(*result_literal);
}

StatusOr<HloSnapshot> ParseInputFile(const string& filename,
                                     const Options& opts) {
  tensorflow::Env* env = tensorflow::Env::Default();
  HloSnapshot snapshot;
  if (tensorflow::ReadBinaryProto(env, filename, &snapshot).ok()) {
    return snapshot;
  }
  CHECK(opts.use_fake_data)
      << "Without --use_fake_data, you must pass an HloSnapshot -- HloProto "
         "and textual HLO don't carry real data.";
  fprintf(stderr, "%s: is not HloSnapshot. Trying HloProto.\n",
          filename.c_str());

  if (tensorflow::ReadBinaryProto(env, filename, snapshot.mutable_hlo()).ok()) {
    return snapshot;
  }
  fprintf(stderr, "%s: is not HloProto. Trying HLO text.\n", filename.c_str());
  string contents;
  TF_RETURN_IF_ERROR(tensorflow::ReadFileToString(env, filename, &contents));
  StatusOr<std::unique_ptr<HloModule>> module = ParseHloString(contents);
  if (module.ok()) {
    *snapshot.mutable_hlo()->mutable_hlo_module() =
        module.ValueOrDie()->ToProto();
    return snapshot;
  }
  fprintf(stderr, "%s: is not HLO text.  Nothing left to try.\n",
          filename.c_str());
  return InvalidArgument("Could not parse %s.", filename.c_str());
}

int RealMain(tensorflow::gtl::ArraySlice<char*> args, const Options& opts) {
  LocalClient* client = ClientLibrary::LocalClientOrDie();
  int exit_status = EXIT_SUCCESS;
  for (char* arg : args) {
    StatusOr<HloSnapshot> maybe_snapshot = ParseInputFile(arg, opts);
    if (!maybe_snapshot.ok()) {
      continue;
    }
    HloSnapshot snapshot = std::move(maybe_snapshot).ValueOrDie();
    StatusOr<Literal> result_status = ReplayComputation(snapshot, client, opts);
    if (!result_status.ok()) {
      fprintf(stderr, "%s: error: %s\n", arg,
              result_status.status().ToString().c_str());
      exit_status = EXIT_FAILURE;
      continue;
    }

    if (opts.print_result) {
      Literal result = std::move(result_status).ValueOrDie();
      fprintf(stdout, "%s: %s :: %s:%s\n", arg,
              snapshot.hlo().hlo_module().name().c_str(),
              ShapeUtil::HumanString(result.shape()).c_str(),
              result.ToString().c_str());
      if (snapshot.has_result()) {
        std::unique_ptr<Literal> literal =
            Literal::CreateFromProto(snapshot.result()).ConsumeValueOrDie();
        fprintf(stdout, "was %s:%s\n",
                ShapeUtil::HumanString(snapshot.result().shape()).c_str(),
                literal->ToString().c_str());
      }
    }
  }

  ClientLibrary::DestroyLocalInstances();
  return exit_status;
}

}  // namespace
}  // namespace tools
}  // namespace xla

int main(int argc, char** argv) {
  xla::tools::Options opts;
  const std::vector<tensorflow::Flag> flag_list = {
      tensorflow::Flag("use_fake_data", &opts.use_fake_data,
                       "Replay computation using fake data"),
      tensorflow::Flag("print_result", &opts.print_result,
                       "Print the result of the computation to stdout"),
      tensorflow::Flag("num_runs", &opts.num_runs,
                       "Number of times to run each computation"),
      tensorflow::Flag("fake_infeed_shape", &opts.fake_infeed_shape,
                       "Shape of fake data to construct for (infinite) infeed"),
      tensorflow::Flag("generate_fake_infeed", &opts.generate_fake_infeed,
                       "Whether a fake infeed shape should be generated "
                       "derived from the computation"),
  };
  xla::string usage = tensorflow::Flags::Usage(argv[0], flag_list);
  bool parse_ok = tensorflow::Flags::Parse(&argc, argv, flag_list);
  tensorflow::port::InitMain(argv[0], &argc, &argv);
  if (argc < 2 || !parse_ok) {
    LOG(QFATAL) << usage;
  }

  tensorflow::gtl::ArraySlice<char*> args(argv, argc);
  args.pop_front();  // Pop off the binary name, argv[0]
  return xla::tools::RealMain(args, opts);
}
<commit_msg>[XLA] Compile in parallel within replay_computation.<commit_after>/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

// Usage: replay_computation some_binary_snapshot_proto*
//
// Replays computations and shows the results on the command line.
//
// some_binary_snapshot_proto is obtained by serializing the HloSnapshot from
// ServiceInterface::SnapshotComputation to disk.
//
// Computations that require arguments can be replayed using fake data by
// passing --use_fake_data on the command line.  If the real data is available
// in the proto and --use_fake_data is false, the real data is used.
//
// Input can be a binary HloSnapshot proto, a binary HloProto proto, or a
// textual HLO string.
//
// The output format is:
//
// file_path: computation_name :: type:literal_str
//
// Note: If you pass multiple modules, they will be compiled in parallel but run
// in series.

#include <stdio.h>
#include <memory>
#include <string>
#include <utility>
#include <vector>

#include "tensorflow/compiler/xla/client/client.h"
#include "tensorflow/compiler/xla/client/client_library.h"
#include "tensorflow/compiler/xla/client/global_data.h"
#include "tensorflow/compiler/xla/client/lib/testing.h"
#include "tensorflow/compiler/xla/client/local_client.h"
#include "tensorflow/compiler/xla/client/xla_computation.h"
#include "tensorflow/compiler/xla/execution_options_util.h"
#include "tensorflow/compiler/xla/legacy_flags/debug_options_flags.h"
#include "tensorflow/compiler/xla/literal.h"
#include "tensorflow/compiler/xla/service/gpu/infeed_manager.h"
#include "tensorflow/compiler/xla/service/hlo.pb.h"
#include "tensorflow/compiler/xla/service/hlo_parser.h"
#include "tensorflow/compiler/xla/shape_util.h"
#include "tensorflow/compiler/xla/status_macros.h"
#include "tensorflow/compiler/xla/statusor.h"
#include "tensorflow/compiler/xla/tests/test_utils.h"
#include "tensorflow/compiler/xla/types.h"
#include "tensorflow/compiler/xla/xla_data.pb.h"
#include "tensorflow/core/lib/core/threadpool.h"
#include "tensorflow/core/lib/gtl/array_slice.h"
#include "tensorflow/core/platform/env.h"
#include "tensorflow/core/platform/init_main.h"
#include "tensorflow/core/platform/logging.h"
#include "tensorflow/core/util/command_line_flags.h"

namespace xla {
namespace tools {
namespace {

// Command-line opts to this tool.  See main() for descriptions of these
// fields.
struct Options {
  string fake_infeed_shape;
  bool generate_fake_infeed = false;
  bool use_fake_data = false;
  bool print_result = true;
  int num_runs = 1;
};

std::unique_ptr<LocalExecutable> CompileExecutable(const HloSnapshot& module,
                                                   LocalClient* client) {
  XlaComputation computation(module.hlo().hlo_module());
  std::vector<const Shape*> argument_layouts;
  for (const auto& param : computation.proto().program_shape().parameters()) {
    argument_layouts.push_back(&param);
  }
  return client
      ->Compile(computation, argument_layouts, ExecutableBuildOptions())
      .ValueOrDie();
}

// Invokes the given computation passing arbitrary data for every (unbound)
// parameter if use_fake_data, Otherwise use recorded data if available.
//
// Similarly, infeeds fake data of shape fake_infeed_shape if it is provided.
// If generate_fake_infeed is true, the required infeed shape is derived from
// the computation and then used to provide a fake infeed shape.
//
// If neither generate_fake_infeed is true nor a fake_infeed_shape is provided,
// no infeed is performed.
StatusOr<Literal> ReplayComputation(const HloSnapshot& module,
                                    LocalExecutable* executable,
                                    LocalClient* client, const Options& opts) {
  XlaComputation computation(module.hlo().hlo_module());

  // Build the `argument_ptrs` vector, which contains ShapedBuffer*s to our
  // arguments.  This is a bit involved, because we may have to convert from
  // GlobalData to ShapedBuffer*, and we have to manage the lifetime of all our
  // objects.
  std::vector<ScopedShapedBuffer> scoped_shaped_buffer_arguments;
  std::vector<std::unique_ptr<GlobalData>> global_data_arguments;
  std::vector<const ShapedBuffer*> argument_ptrs;
  if (opts.use_fake_data) {
    global_data_arguments = MakeFakeArgumentsOrDie(computation, client);
    for (const auto& data : global_data_arguments) {
      argument_ptrs.push_back(
          client->GlobalDataToShapedBuffer(data->handle(), /*device_ordinal=*/0)
              .ValueOrDie());
    }
  } else {  // use recorded data if available
    for (const auto& proto : module.arguments()) {
      TF_ASSIGN_OR_RETURN(std::unique_ptr<xla::Literal> literal,
                          Literal::CreateFromProto(proto));
      TF_ASSIGN_OR_RETURN(
          ScopedShapedBuffer data,
          client->LiteralToShapedBuffer(*literal, /*device_ordinal=*/0));
      scoped_shaped_buffer_arguments.push_back(std::move(data));
    }
    for (const auto& argument : scoped_shaped_buffer_arguments) {
      argument_ptrs.push_back(&argument);
    }
  }

  bool provide_infeed = false;
  Shape infeed_shape;
  if (!opts.fake_infeed_shape.empty()) {
    StatusOr<Shape> shape_status =
        ShapeUtil::ParseShapeString(opts.fake_infeed_shape);
    TF_CHECK_OK(shape_status.status());
    infeed_shape = std::move(shape_status).ValueOrDie();
    provide_infeed = true;
  } else if (opts.generate_fake_infeed) {
    for (const auto& comp : computation.proto().computations()) {
      for (const auto& instruction : comp.instructions()) {
        if (instruction.opcode() == HloOpcodeString(HloOpcode::kInfeed)) {
          CHECK(!provide_infeed)
              << "--generate_fake_infeed only works if the model has 0 or 1 "
                 "infeed ops, but this one has >= 2.";
          provide_infeed = true;
          infeed_shape = instruction.shape();
          LOG(INFO) << "Generating fake infeed shape for inferred shape: "
                    << ShapeUtil::HumanString(infeed_shape);
        }
      }
    }
  }
  // We only instantiate the thread pool if the user has requested that a
  // concurrent infeed occur via the fake_infeed_shape, or when
  // --generate_fake_infeed is passed and there exists an infeed operation in
  // the HloSnapshot.
  tensorflow::gtl::optional<tensorflow::thread::ThreadPool> pool;
  std::unique_ptr<Literal> data;
  if (provide_infeed) {
    data = std::move(MakeFakeLiteral(infeed_shape)).ValueOrDie();
  }
  auto transfer_infeed = [&data, client]() {
    TF_CHECK_OK(client->TransferToInfeed(*data));
  };
  if (provide_infeed) {
    pool.emplace(tensorflow::Env::Default(), "infeed",
                 /*num_threads=*/1);
    pool->Schedule([transfer_infeed]() {
      // There may be several infeed buffers needed, however we don't know how
      // many. If we proactively transfer too many infeed buffers, we may run
      // out of memory. If we transfer too few infeed buffers, the program will
      // hang. Therefore, we register a callback that is called when the infeed
      // becomes empty, and in this callback we will transfer another fake
      // infeed.
      auto infeed_manager = xla::gpu::GetOrCreateInfeedManager();
      infeed_manager->RegisterOnEmptyCallback(transfer_infeed);
      transfer_infeed();
    });
  }

  // Do not attempt to run the executable if num_runs is less than 1.
  if (opts.num_runs < 1) {
    return Cancelled("Cancelled after compilation since --num_runs < 1.");
  }

  // Run the computation num_runs times, and return the result from the last
  // execution.
  const bool xla_hlo_profile =
      legacy_flags::GetDebugOptionsFromFlags().xla_hlo_profile();
  StreamExecutorMemoryAllocator allocator(
      client->platform(),
      {client->platform()->ExecutorForDevice(0).ValueOrDie()});
  tensorflow::gtl::optional<ScopedShapedBuffer> result;
  for (int i = 0; i < opts.num_runs; ++i) {
    // If xla_hlo_profile is enabled, print a noisy message before the last run,
    // making it easier to separate this profile from the others in the logspam.
    if (xla_hlo_profile && i == opts.num_runs - 1) {
      LOG(INFO) << "\n\n***** Final run below ******";
    }
    ExecutionProfile profile;
    ExecutableRunOptions run_options;
    run_options.set_execution_profile(&profile);
    run_options.set_allocator(&allocator);

    TF_ASSIGN_OR_RETURN(result, executable->Run(argument_ptrs, run_options));
    LOG(INFO) << "Done executing in "
              << static_cast<double>(profile.compute_time_ns()) / 1e9
              << "s: " << module.hlo().hlo_module().name();
  }

  TF_ASSIGN_OR_RETURN(std::unique_ptr<Literal> result_literal,
                      client->ShapedBufferToLiteral(*result));
  return std::move(*result_literal);
}

StatusOr<HloSnapshot> ParseInputFile(const string& filename,
                                     const Options& opts) {
  tensorflow::Env* env = tensorflow::Env::Default();
  HloSnapshot snapshot;
  if (tensorflow::ReadBinaryProto(env, filename, &snapshot).ok()) {
    return snapshot;
  }
  CHECK(opts.use_fake_data)
      << "Without --use_fake_data, you must pass an HloSnapshot -- HloProto "
         "and textual HLO don't carry real data.";
  fprintf(stderr, "%s: is not HloSnapshot. Trying HloProto.\n",
          filename.c_str());

  if (tensorflow::ReadBinaryProto(env, filename, snapshot.mutable_hlo()).ok()) {
    return snapshot;
  }
  fprintf(stderr, "%s: is not HloProto. Trying HLO text.\n", filename.c_str());
  string contents;
  TF_RETURN_IF_ERROR(tensorflow::ReadFileToString(env, filename, &contents));
  StatusOr<std::unique_ptr<HloModule>> module = ParseHloString(contents);
  if (module.ok()) {
    *snapshot.mutable_hlo()->mutable_hlo_module() =
        module.ValueOrDie()->ToProto();
    return snapshot;
  }
  fprintf(stderr, "%s: is not HLO text.  Nothing left to try.\n",
          filename.c_str());
  return InvalidArgument("Could not parse %s.", filename.c_str());
}

int RealMain(tensorflow::gtl::ArraySlice<char*> args, const Options& opts) {
  LocalClient* client = ClientLibrary::LocalClientOrDie();
  int exit_status = EXIT_SUCCESS;

  std::vector<HloSnapshot> snapshots;
  for (char* arg : args) {
    StatusOr<HloSnapshot> maybe_snapshot = ParseInputFile(arg, opts);
    if (maybe_snapshot.ok()) {
      snapshots.push_back(std::move(maybe_snapshot).ValueOrDie());
    }
  }

  // Compile all the modules in parallel.
  LOG(INFO) << "Compiling " << snapshots.size() << " modules in parallel.";
  std::vector<std::unique_ptr<LocalExecutable>> executables;
  {
    // ThreadPool CHECK-fails if we give it 0 threads.
    tensorflow::thread::ThreadPool thread_pool(
        tensorflow::Env::Default(), tensorflow::ThreadOptions(),
        "compile_modules", std::max(size_t{1}, snapshots.size()),
        /*low_latency_hint=*/false);
    executables.resize(snapshots.size());
    for (int64 i = 0; i < snapshots.size(); ++i) {
      thread_pool.Schedule([&snapshots, &executables, client, i] {
        executables[i] = CompileExecutable(snapshots[i], client);
      });
    }
  }
  LOG(INFO) << "Done compiling; now running the modules.";

  for (int64 i = 0; i < executables.size(); ++i) {
    LocalExecutable* executable = executables[i].get();
    StatusOr<Literal> result_status =
        ReplayComputation(snapshots[i], executable, client, opts);
    if (!result_status.ok()) {
      fprintf(stderr, "%s: error: %s\n", args[i],
              result_status.status().ToString().c_str());
      exit_status = EXIT_FAILURE;
      continue;
    }

    if (opts.print_result) {
      Literal result = std::move(result_status).ValueOrDie();
      fprintf(stdout, "%s: %s :: %s:%s\n", args[i],
              executable->executable()->module().name().c_str(),
              ShapeUtil::HumanString(result.shape()).c_str(),
              result.ToString().c_str());
      auto& snapshot = snapshots[i];
      if (snapshot.has_result()) {
        std::unique_ptr<Literal> literal =
            Literal::CreateFromProto(snapshot.result()).ConsumeValueOrDie();
        fprintf(stdout, "was %s:%s\n",
                ShapeUtil::HumanString(snapshot.result().shape()).c_str(),
                literal->ToString().c_str());
      }
    }
  }

  ClientLibrary::DestroyLocalInstances();
  return exit_status;
}

}  // namespace
}  // namespace tools
}  // namespace xla

int main(int argc, char** argv) {
  xla::tools::Options opts;
  const std::vector<tensorflow::Flag> flag_list = {
      tensorflow::Flag("use_fake_data", &opts.use_fake_data,
                       "Replay computation using fake data"),
      tensorflow::Flag("print_result", &opts.print_result,
                       "Print the result of the computation to stdout"),
      tensorflow::Flag("num_runs", &opts.num_runs,
                       "Number of times to run each computation"),
      tensorflow::Flag("fake_infeed_shape", &opts.fake_infeed_shape,
                       "Shape of fake data to construct for (infinite) infeed"),
      tensorflow::Flag("generate_fake_infeed", &opts.generate_fake_infeed,
                       "Whether a fake infeed shape should be generated "
                       "derived from the computation"),
  };
  xla::string usage = tensorflow::Flags::Usage(argv[0], flag_list);
  bool parse_ok = tensorflow::Flags::Parse(&argc, argv, flag_list);
  tensorflow::port::InitMain(argv[0], &argc, &argv);
  if (argc < 2 || !parse_ok) {
    LOG(QFATAL) << usage;
  }

  tensorflow::gtl::ArraySlice<char*> args(argv, argc);
  args.pop_front();  // Pop off the binary name, argv[0]
  return xla::tools::RealMain(args, opts);
}
<|endoftext|>


<commit_before>## Note that this file is not auto generated, it is what generates the
## elog-gen.hpp file
// This file was autogenerated.  Do not edit!
// See elog-gen.py for more details
#pragma once

#include <string>
#include <tuple>
#include <type_traits>
#include <sdbusplus/exception.hpp>
#include <phosphor-logging/log.hpp>
#include <phosphor-logging/elog.hpp>

<% exceptions = [] %>\
% for name in errors:
<%
    if("example.xyz.openbmc_project" not in name):
        exception = name.replace(".", "::")
        exception = "sdbusplus::" + exception
        index = exception.rfind("::")
        exception = exception[:index] + "::Error::" + exception[index+2:]
        exceptions.append(exception)
%>\
% endfor
% for exception in set(exceptions):
<%
    ns = exception.split("::")
    exception_name = ns[-1]
    ns = ns[:-1]
%>\
    % for s in ns:
namespace ${s}
{
    % endfor
    struct ${exception_name};
    % for s in reversed(ns):
} // namespace ${s}
    % endfor

% endfor

namespace phosphor
{

namespace logging
{

    % for index, name in enumerate(errors):
<%
    ## Ex: name: xyz.openbmc_project.Error.Callout.Device
    namespaces = name.split('.')
    ## classname is the last name item (Device)
    classname = namespaces[-1]
    ## namespaces are all the name items except the last one
    namespaces = namespaces[:-1]
%>\
    % for s in namespaces:
namespace ${s}
{
    % endfor
namespace _${classname}
{
<%
    meta_list = []
    if(name in meta):
        meta_list = meta[name]
%>\

    % for b in meta_list:
struct ${b}
{
    static constexpr auto str = "${meta_data[b]['str']}";
    static constexpr auto str_short = "${meta_data[b]['str_short']}";
    using type = std::tuple<std::decay_t<decltype(str)>,${meta_data[b]['type']}>;
    explicit constexpr ${b}(${meta_data[b]['type']} a) : _entry(entry(str, a)) {};
    type _entry;
};
    % endfor

}  // namespace _${classname}
<%
    example_yaml = False
    if("example.xyz.openbmc_project" in name):
        example_yaml = True
%>\
<%
    meta_string = ""
    if(meta_list):
        meta_string = ', '.join(meta_list)
    parent_meta = []

    parent = parents[name]
    while parent:
        tmpparent = parent.split('.')
        ## Name is the last item
        parent_name = tmpparent[-1]
        ## namespaces are all the name items except the last one
        parent_namespace = '::'.join(tmpparent[:-1])
        parent_meta += [parent_namespace + "::" + parent_name + "::" +
                        p for p in meta[parent]]
        parent_meta_short = ', '.join(meta[parent])
        if(meta_string):
            meta_string = meta_string + ", " + parent_meta_short
        else:
            meta_string = parent_meta_short
        parent = parents[parent]

    if example_yaml:
        error_type = classname + " : public sdbusplus::exception_t"
    else:
        error_type = classname
%>
struct ${error_type}
{
    % if example_yaml:
    static constexpr auto errName = "${name}";
    static constexpr auto errDesc = "${error_msg[name]}";
    % endif
    static constexpr auto L = level::${error_lvl[name]};
    % for b in meta_list:
    using ${b} = _${classname}::${b};
    % endfor
    % for b in parent_meta:
    using ${b.split("::").pop()} = ${b};
    % endfor
    using metadata_types = std::tuple<${meta_string}>;

    % if example_yaml:
    const char* name() const noexcept
    {
        return errName;
    }

    const char* description() const noexcept
    {
        return errDesc;
    }

    const char* what() const noexcept
    {
        return errName;
    }
    % endif
};

% for s in reversed(namespaces):
} // namespace ${s}
% endfor

<%
    sdbusplus_name = name
    if not example_yaml :
        sdbusplus_name = "sdbusplus." + sdbusplus_name
        pos = sdbusplus_name.rfind(".")
        sdbusplus_name = (sdbusplus_name[:pos] + ".Error." +
                          sdbusplus_name[pos+1:])
    sdbusplus_type = sdbusplus_name.replace(".", "::")
    phosphor_type = sdbusplus_type
    if not example_yaml :
        phosphor_type = sdbusplus_type.replace("sdbusplus::", "")
        phosphor_type = phosphor_type.replace("Error::", "")
%>\

% if sdbusplus_type != phosphor_type:
namespace details
{

template <>
struct map_exception_type<${sdbusplus_type}>
{
    using type = ${phosphor_type};
};

}
%endif

    % endfor

} // namespace logging

} // namespace phosphor
<commit_msg>templates: Allow use of -fsanitize=undefined<commit_after>## Note that this file is not auto generated, it is what generates the
## elog-gen.hpp file
// This file was autogenerated.  Do not edit!
// See elog-gen.py for more details
#pragma once

#include <string>
#include <tuple>
#include <type_traits>
#include <sdbusplus/exception.hpp>
#include <phosphor-logging/log.hpp>
#include <phosphor-logging/elog.hpp>

<% exceptions = [] %>\
% for name in errors:
<%
    if("example.xyz.openbmc_project" not in name):
        exception = name.replace(".", "::")
        exception = "sdbusplus::" + exception
        index = exception.rfind("::")
        exception = exception[:index] + "::Error::" + exception[index+2:]
        exceptions.append(exception)
%>\
% endfor
% for exception in set(exceptions):
<%
    ns = exception.split("::")
    exception_name = ns[-1]
    ns = ns[:-1]
%>\
    % for s in ns:
namespace ${s}
{
    % endfor
    struct ${exception_name};
    % for s in reversed(ns):
} // namespace ${s}
    % endfor

% endfor

namespace phosphor
{

namespace logging
{

    % for index, name in enumerate(errors):
<%
    ## Ex: name: xyz.openbmc_project.Error.Callout.Device
    namespaces = name.split('.')
    ## classname is the last name item (Device)
    classname = namespaces[-1]
    ## namespaces are all the name items except the last one
    namespaces = namespaces[:-1]
%>\
    % for s in namespaces:
namespace ${s}
{
    % endfor
namespace _${classname}
{
<%
    meta_list = []
    if(name in meta):
        meta_list = meta[name]
%>\

    % for b in meta_list:
struct ${b}
{
    /*
     * We can't use -fsanitize=undefined if we declare a
     * 'static constexpr auto str' member, so don't. Instead, open-code the
     * mako template lookups.
     */
    static constexpr auto str_short = "${meta_data[b]['str_short']}";
    using type = std::tuple<std::decay_t<decltype("${meta_data[b]['str']}")>,${meta_data[b]['type']}>;
    explicit constexpr ${b}(${meta_data[b]['type']} a) : _entry(entry("${meta_data[b]['str']}", a)) {};
    type _entry;
};
    % endfor

}  // namespace _${classname}
<%
    example_yaml = False
    if("example.xyz.openbmc_project" in name):
        example_yaml = True
%>\
<%
    meta_string = ""
    if(meta_list):
        meta_string = ', '.join(meta_list)
    parent_meta = []

    parent = parents[name]
    while parent:
        tmpparent = parent.split('.')
        ## Name is the last item
        parent_name = tmpparent[-1]
        ## namespaces are all the name items except the last one
        parent_namespace = '::'.join(tmpparent[:-1])
        parent_meta += [parent_namespace + "::" + parent_name + "::" +
                        p for p in meta[parent]]
        parent_meta_short = ', '.join(meta[parent])
        if(meta_string):
            meta_string = meta_string + ", " + parent_meta_short
        else:
            meta_string = parent_meta_short
        parent = parents[parent]

    if example_yaml:
        error_type = classname + " : public sdbusplus::exception_t"
    else:
        error_type = classname
%>
struct ${error_type}
{
    % if example_yaml:
    static constexpr auto errName = "${name}";
    static constexpr auto errDesc = "${error_msg[name]}";
    % endif
    static constexpr auto L = level::${error_lvl[name]};
    % for b in meta_list:
    using ${b} = _${classname}::${b};
    % endfor
    % for b in parent_meta:
    using ${b.split("::").pop()} = ${b};
    % endfor
    using metadata_types = std::tuple<${meta_string}>;

    % if example_yaml:
    const char* name() const noexcept
    {
        return errName;
    }

    const char* description() const noexcept
    {
        return errDesc;
    }

    const char* what() const noexcept
    {
        return errName;
    }
    % endif
};

% for s in reversed(namespaces):
} // namespace ${s}
% endfor

<%
    sdbusplus_name = name
    if not example_yaml :
        sdbusplus_name = "sdbusplus." + sdbusplus_name
        pos = sdbusplus_name.rfind(".")
        sdbusplus_name = (sdbusplus_name[:pos] + ".Error." +
                          sdbusplus_name[pos+1:])
    sdbusplus_type = sdbusplus_name.replace(".", "::")
    phosphor_type = sdbusplus_type
    if not example_yaml :
        phosphor_type = sdbusplus_type.replace("sdbusplus::", "")
        phosphor_type = phosphor_type.replace("Error::", "")
%>\

% if sdbusplus_type != phosphor_type:
namespace details
{

template <>
struct map_exception_type<${sdbusplus_type}>
{
    using type = ${phosphor_type};
};

}
%endif

    % endfor

} // namespace logging

} // namespace phosphor
<|endoftext|>


<commit_before>#include "webcam.hpp"

using namespace cv;
using namespace std;

Mat ellipticKernel(int width, int height = -1) {
 if (height==-1) {
  return getStructuringElement(MORPH_ELLIPSE,Size(width,width), Point(width/2, width/2));
 } else {
  return getStructuringElement(MORPH_ELLIPSE,Size(width,height), Point(width/2, height/2));
 }
}

void morphFast(Mat inout, int smallsize = 100, int factor = 25, int eq = 1, int diler = 0) {
 int width, height;
 width = inout.size().width;
 height = inout.size().height;
 Mat downsample;
 resize(inout, downsample, Size(smallsize,smallsize));
 Mat kernel = ellipticKernel(factor);
 if (diler) {
  erode(downsample, downsample, kernel);
 } else {
  dilate(downsample, downsample, kernel);
 }
 if (eq) {
  equalizeHist(downsample, downsample);
 }
 resize(downsample, inout, Size(width, height));
}

int main (int argc, char** argv) {

 int tracker1, tracker2, tracker3;
 namedWindow("s",1);
 createTrackbar("1","s",&tracker1,100);
 createTrackbar("2","s",&tracker2,100);
 createTrackbar("3","s",&tracker3,100);

 CvCapture* capture = 0;
 int width, height, fps;

 capture = cvCaptureFromCAM(0);

 if (!capture) {
  printf("No camera detected!");
  return -1;
 }

 ifstream configFile (".config");

 if (configFile.is_open()) {

  //probably want to support corrupted .config
  string line;
  getline(configFile, line);
  istringstream(line)>>width;
  getline(configFile, line);
  istringstream(line)>>height;
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, width);
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, height);

  configFile.close();

 } else {

  initResolutions();

  for (int i=36; i<150; i++) {
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, resolutions[i].width);
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, resolutions[i].height);
  }

  width = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH);
  height = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT);

  ofstream configFileOut(".config");
  configFileOut << width;
  configFileOut << "\n";
  configFileOut << height;
  configFileOut << "\n";
  configFileOut.close();
 }

 bool keepGoing = true;

// srand(890);//not interested in good randomness

 for (int i = 0; i < 30; i++) {
  // capture some frames so exposure correction takes place
  cvQueryFrame(capture);
 }

 Mat background = cvQueryFrame(capture);
 background = background.clone();
 blur(background, background, Size(50,50));

 Mat image;
 Mat channel[3];

 while (keepGoing) {

  image = cvQueryFrame(capture);
// preprocess by rotating according to OVR roll
//  imshow("webcam", image);

// let's make multiple masks where 0=not mouth, 1=uncertain

// then multiply them together and multiply that with image
// and run haar classifier on image

  Mat gray, blurred_img;
  cvtColor(image, gray, CV_RGB2GRAY);
  blur(image, blurred_img, Size(50,50));

// this mask filters out areas with too many edges
// removed for now; it didn't generalize well
/*
  Mat canny;
  Canny(gray, canny, 50, 50, 3);
  blur(canny, canny, Size(width/20,height/20));
  bitwise_not(canny, canny);
  threshold(canny, canny, 200, 1, THRESH_BINARY);
  blur(canny*255, canny, Size(width/10, height/10));
  threshold(canny, canny, 220, 1, THRESH_BINARY);
  imshow("canny mask", gray.mul(canny));
*/

// this mask filters out areas which have not changed much
// background needs to be updated when person is not in frame
// use OVR SDK to do this later
  Mat flow;
  absdiff(blurred_img, background, flow);
  cvtColor(flow, flow, CV_RGB2GRAY);
  morphFast(flow);
  threshold(flow, flow, 60, 1, THRESH_BINARY);
//  imshow("flow mask", gray.mul(flow));

// this mask gets anything kind of dark (DK2) and dilates
  Mat kindofdark;
  equalizeHist(gray, kindofdark);
  threshold(kindofdark, kindofdark, 100, 1, THRESH_BINARY_INV);
  morphFast(kindofdark, 100, 17, 0);
//  imshow("dark mask", gray.mul(kindofdark));

// this mask gets rid of anything far away from red stuff
// lips have a lot of red
  Mat notlips;
  Mat channels[3];
  split(image, channels);
  channels[2].convertTo(notlips, CV_32FC1);
  divide(notlips, gray, notlips, 1, CV_32FC1);
  //equalistHist is horrible for a red background
  //equalizeHist(notlips, notlips);
  threshold(notlips, notlips, 1.2, 1, THRESH_BINARY);
  imshow("lip mask", notlips*255);
  int tx = tracker1+1-(tracker1%2);
  if (tx<3) tx=3;
  if (tx>90) tx=91;
  morphFast(notlips, 100, tx, 0, 0);
  morphFast(notlips, 100, tx, 0, 1);
  imshow("lips2", notlips*255);
  waitKey(1);

  Mat mask = flow.mul(kindofdark);
// open the mask
  Mat smallMask0, smallMask1;
  resize(mask, smallMask0, Size(width/5,height/5));
  Mat erodeKernel = ellipticKernel(69,79);
  erode(smallMask0, smallMask1, erodeKernel);
  Mat dilateKernel = ellipticKernel(69,79);
  dilate(smallMask1, smallMask1, dilateKernel);
  bitwise_and(smallMask0, smallMask1, smallMask1);
  resize(smallMask1, mask, Size(width, height));
//  imshow("morph mask", gray.mul(mask));

// update background with new morph mask
// average what we know is background with prior background
// erode it first since we really want to be sure it's bg

//  Mat erodeKernel = ellipticKernel(21);
  Mat erodedMask;
  erode(mask, erodedMask, erodeKernel);
  Mat mask_;
  subtract(1,erodedMask,mask_);
  Mat mask3, mask3_;
  channel[0] = erodedMask;
  channel[1] = erodedMask;
  channel[2] = erodedMask;
  merge(channel, 3, mask3);
  channel[0] = mask_;
  channel[1] = mask_;
  channel[2] = mask_;
  merge(channel, 3, mask3_);

  background = background.mul(mask3) +
   (background.mul(mask3_) + blurred_img.mul(mask3_))/2;

  imshow("background", background);

/*
  Moments lol = moments(gray, 1);
  circle(image, Point(lol.m10/lol.m00,lol.m01/lol.m00),20,Scalar(128),30);
  imshow("leimage", image);
*/
/*
  CascadeClassifier mouth_cascade;
  mouth_cascade.load("Mouth.xml");
  vector<Rect> mouths;
  int scale = tracker1+1;
  Mat classifyThis = image.clone();
  equalizeHist(gray, gray);//ew; watch out not to use this later
  resize(gray.mul(mask), classifyThis, Size(width/scale,height/scale));
//  bilateralFilter(gray, classifyThis, 15, 10, 1);
  mouth_cascade.detectMultiScale(classifyThis, mouths, 1.1, tracker2, CV_HAAR_SCALE_IMAGE);
  for (size_t i=0; i<mouths.size(); i++) {
   Rect scaled(mouths[i].x*scale, mouths[i].y*scale, mouths[i].width*scale,mouths[i].height*scale);
   rectangle(image, scaled, Scalar(255,0,0));
  }
  imshow("MOUTH", image);
*/

  keepGoing = (waitKey(25)<0);

 }

 cvReleaseCapture(&capture);

 return 0;
}
<commit_msg>hacking<commit_after>#include "webcam.hpp"

using namespace cv;
using namespace std;

Mat ellipticKernel(int width, int height = -1) {
 if (height==-1) {
  return getStructuringElement(MORPH_ELLIPSE,Size(width,width), Point(width/2, width/2));
 } else {
  return getStructuringElement(MORPH_ELLIPSE,Size(width,height), Point(width/2, height/2));
 }
}

void morphFast(Mat inout, int smallsize = 100, int factor = 25, int eq = 1, int diler = 0) {
 int width, height;
 width = inout.size().width;
 height = inout.size().height;
 Mat downsample;
 resize(inout, downsample, Size(smallsize,smallsize));
 Mat kernel = ellipticKernel(factor);
 if (diler) {
  erode(downsample, downsample, kernel);
 } else {
  dilate(downsample, downsample, kernel);
 }
 if (eq) {
  equalizeHist(downsample, downsample);
 }
 resize(downsample, inout, Size(width, height));
}

int main (int argc, char** argv) {

 int tracker1, tracker2, tracker3;
 namedWindow("s",1);
 createTrackbar("1","s",&tracker1,100);
 createTrackbar("2","s",&tracker2,100);
 createTrackbar("3","s",&tracker3,100);

 CvCapture* capture = 0;
 int width, height, fps;

 capture = cvCaptureFromCAM(0);

 if (!capture) {
  printf("No camera detected!");
  return -1;
 }

 ifstream configFile (".config");

 if (configFile.is_open()) {

  //probably want to support corrupted .config
  string line;
  getline(configFile, line);
  istringstream(line)>>width;
  getline(configFile, line);
  istringstream(line)>>height;
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, width);
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, height);

  configFile.close();

 } else {

  initResolutions();

  for (int i=36; i<150; i++) {
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, resolutions[i].width);
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, resolutions[i].height);
  }

  width = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH);
  height = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT);

  ofstream configFileOut(".config");
  configFileOut << width;
  configFileOut << "\n";
  configFileOut << height;
  configFileOut << "\n";
  configFileOut.close();
 }

 bool keepGoing = true;

// srand(890);//not interested in good randomness

 for (int i = 0; i < 30; i++) {
  // capture some frames so exposure correction takes place
  cvQueryFrame(capture);
 }

 Mat background = cvQueryFrame(capture);
 background = background.clone();
 blur(background, background, Size(50,50));

 Mat image;
 Mat channel[3];

 while (keepGoing) {

  image = cvQueryFrame(capture);
// preprocess by rotating according to OVR roll
//  imshow("webcam", image);

// let's make multiple masks where 0=not mouth, 1=uncertain

// then multiply them together and multiply that with image
// and run haar classifier on image

  Mat gray, blurred_img;
  cvtColor(image, gray, CV_RGB2GRAY);
  blur(image, blurred_img, Size(50,50));

// this mask filters out areas with too many edges
// removed for now; it didn't generalize well
/*
  Mat canny;
  Canny(gray, canny, 50, 50, 3);
  blur(canny, canny, Size(width/20,height/20));
  bitwise_not(canny, canny);
  threshold(canny, canny, 200, 1, THRESH_BINARY);
  blur(canny*255, canny, Size(width/10, height/10));
  threshold(canny, canny, 220, 1, THRESH_BINARY);
  imshow("canny mask", gray.mul(canny));
*/

// this mask filters out areas which have not changed much
// background needs to be updated when person is not in frame
// use OVR SDK to do this later
  Mat flow;
  absdiff(blurred_img, background, flow);
  cvtColor(flow, flow, CV_RGB2GRAY);
  morphFast(flow);
  threshold(flow, flow, 60, 1, THRESH_BINARY);
//  imshow("flow mask", gray.mul(flow));

// this mask gets anything kind of dark (DK2) and dilates
  Mat kindofdark;
  equalizeHist(gray, kindofdark);
  threshold(kindofdark, kindofdark, 100, 1, THRESH_BINARY_INV);
  morphFast(kindofdark, 100, 17, 0);
//  imshow("dark mask", gray.mul(kindofdark));

// this mask gets rid of anything far away from red stuff
// lips have a lot of red
  Mat notlips;
  Mat channels[3];
  split(image, channels);
  channels[2].convertTo(notlips, CV_32FC1);
  divide(notlips, gray, notlips, 1, CV_32FC1);
  //equalistHist is horrible for a red background
  //equalizeHist(notlips, notlips);
  threshold(notlips, notlips, tracker2/30.0, 1, THRESH_BINARY);
  imshow("lip mask", notlips*255);
  int tx = tracker1+1-(tracker1%2);
  if (tx<3) tx=3;
  if (tx>90) tx=91;
  morphFast(notlips, 100, tx, 0, 1);
  morphFast(notlips, 100, tx, 0, 0);
  imshow("lips2", notlips*255);
  waitKey(1);

  Mat mask = flow.mul(kindofdark);
// open the mask
  Mat smallMask0, smallMask1;
  resize(mask, smallMask0, Size(width/5,height/5));
  Mat erodeKernel = ellipticKernel(69,79);
  erode(smallMask0, smallMask1, erodeKernel);
  Mat dilateKernel = ellipticKernel(69,79);
  dilate(smallMask1, smallMask1, dilateKernel);
  bitwise_and(smallMask0, smallMask1, smallMask1);
  resize(smallMask1, mask, Size(width, height));
//  imshow("morph mask", gray.mul(mask));

// update background with new morph mask
// average what we know is background with prior background
// erode it first since we really want to be sure it's bg

//  Mat erodeKernel = ellipticKernel(21);
  Mat erodedMask;
  erode(mask, erodedMask, erodeKernel);
  Mat mask_;
  subtract(1,erodedMask,mask_);
  Mat mask3, mask3_;
  channel[0] = erodedMask;
  channel[1] = erodedMask;
  channel[2] = erodedMask;
  merge(channel, 3, mask3);
  channel[0] = mask_;
  channel[1] = mask_;
  channel[2] = mask_;
  merge(channel, 3, mask3_);

  background = background.mul(mask3) +
   (background.mul(mask3_) + blurred_img.mul(mask3_))/2;

  imshow("background", background);

/*
  Moments lol = moments(gray, 1);
  circle(image, Point(lol.m10/lol.m00,lol.m01/lol.m00),20,Scalar(128),30);
  imshow("leimage", image);
*/
/*
  CascadeClassifier mouth_cascade;
  mouth_cascade.load("Mouth.xml");
  vector<Rect> mouths;
  int scale = tracker1+1;
  Mat classifyThis = image.clone();
  equalizeHist(gray, gray);//ew; watch out not to use this later
  resize(gray.mul(mask), classifyThis, Size(width/scale,height/scale));
//  bilateralFilter(gray, classifyThis, 15, 10, 1);
  mouth_cascade.detectMultiScale(classifyThis, mouths, 1.1, tracker2, CV_HAAR_SCALE_IMAGE);
  for (size_t i=0; i<mouths.size(); i++) {
   Rect scaled(mouths[i].x*scale, mouths[i].y*scale, mouths[i].width*scale,mouths[i].height*scale);
   rectangle(image, scaled, Scalar(255,0,0));
  }
  imshow("MOUTH", image);
*/

  keepGoing = (waitKey(25)<0);

 }

 cvReleaseCapture(&capture);

 return 0;
}
<|endoftext|>


<commit_before>/*=========================================================================
 *
 *  Copyright NumFOCUS
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 *  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.
 *
 *=========================================================================*/
/*=========================================================================
 *
 *  Portions of this file are subject to the VTK Toolkit Version 3 copyright.
 *
 *  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
 *
 *  For complete copyright, license and disclaimer of warranty information
 *  please refer to the NOTICE file at the top of the ITK source tree.
 *
 *=========================================================================*/
#include "itkPlatformMultiThreader.h"
#include "itkObjectFactory.h"
#include "itksys/SystemTools.hxx"
#include <cstdlib>

#include "itkWindows.h"
#include <process.h>

namespace itk
{
#if !defined(ITK_LEGACY_REMOVE)
void
PlatformMultiThreader::MultipleMethodExecute()
{
  ThreadIdType threadCount;

  DWORD  threadId;
  HANDLE processId[ITK_MAX_THREADS];

  // obey the global maximum number of threads limit
  if (m_NumberOfWorkUnits > MultiThreaderBase::GetGlobalMaximumNumberOfThreads())
  {
    m_NumberOfWorkUnits = MultiThreaderBase::GetGlobalMaximumNumberOfThreads();
  }
  for (threadCount = 0; threadCount < m_NumberOfWorkUnits; ++threadCount)
  {
    if (m_MultipleMethod[threadCount] == nullptr)
    {
      itkExceptionMacro(<< "No multiple method set for: " << threadCount);
    }
  }
  // Using _beginthreadex on a PC
  //
  // We want to use _beginthreadex to start m_NumberOfWorkUnits - 1
  // additional threads which will be used to call the NumberOfWorkUnits-1
  // methods defined in this->MultipleMethods[](). The parent thread
  // will call m_MultipleMethods[NumberOfWorkUnits-1]().  When it is done,
  // it will wait for all the children to finish.
  //
  // First, start up the m_NumberOfWorkUnits-1 processes.  Keep track
  // of their process ids for use later in the waitid call
  for (threadCount = 1; threadCount < m_NumberOfWorkUnits; ++threadCount)
  {
    m_ThreadInfoArray[threadCount].UserData = m_MultipleData[threadCount];
    m_ThreadInfoArray[threadCount].NumberOfWorkUnits = m_NumberOfWorkUnits;

    processId[threadCount] = (void *)_beginthreadex(
      nullptr, 0, m_MultipleMethod[threadCount], &m_ThreadInfoArray[threadCount], 0, (unsigned int *)&threadId);

    if (processId[threadCount] == nullptr)
    {
      itkExceptionMacro("Error in thread creation!");
    }
  }

  // Now, the parent thread calls the last method itself
  m_ThreadInfoArray[0].UserData = m_MultipleData[0];
  m_ThreadInfoArray[0].NumberOfWorkUnits = m_NumberOfWorkUnits;
  (m_MultipleMethod[0])((void *)(&m_ThreadInfoArray[0]));
  // The parent thread has finished its method - so now it
  // waits for each of the other processes to
  // exit
  for (threadCount = 1; threadCount < m_NumberOfWorkUnits; ++threadCount)
  {
    WaitForSingleObject(processId[threadCount], INFINITE);
  }
  // close the threads
  for (threadCount = 1; threadCount < m_NumberOfWorkUnits; ++threadCount)
  {
    CloseHandle(processId[threadCount]);
  }
}

ThreadIdType
PlatformMultiThreader::SpawnThread(ThreadFunctionType f, void * UserData)
{
  ThreadIdType id = 0;

  DWORD threadId;

  while (id < ITK_MAX_THREADS)
  {
    if (!m_SpawnedThreadActiveFlagLock[id])
    {
      m_SpawnedThreadActiveFlagLock[id] = std::make_shared<std::mutex>();
    }
    m_SpawnedThreadActiveFlagLock[id]->lock();
    if (m_SpawnedThreadActiveFlag[id] == 0)
    {
      // We've got a useable thread id, so grab it
      m_SpawnedThreadActiveFlag[id] = 1;
      m_SpawnedThreadActiveFlagLock[id]->unlock();
      break;
    }
    m_SpawnedThreadActiveFlagLock[id]->unlock();

    id++;
  }

  if (id >= ITK_MAX_THREADS)
  {
    itkExceptionMacro(<< "You have too many active threads!");
  }

  m_SpawnedThreadInfoArray[id].UserData = UserData;
  m_SpawnedThreadInfoArray[id].NumberOfWorkUnits = 1;
  m_SpawnedThreadInfoArray[id].ActiveFlag = &m_SpawnedThreadActiveFlag[id];
  m_SpawnedThreadInfoArray[id].ActiveFlagLock = m_SpawnedThreadActiveFlagLock[id];

  // Using _beginthreadex on a PC
  //
  m_SpawnedThreadProcessID[id] =
    (void *)_beginthreadex(nullptr, 0, f, &m_SpawnedThreadInfoArray[id], 0, (unsigned int *)&threadId);
  if (m_SpawnedThreadProcessID[id] == nullptr)
  {
    itkExceptionMacro("Error in thread creation !!!");
  }
  return id;
}

void
PlatformMultiThreader::TerminateThread(ThreadIdType WorkUnitID)
{
  if (!m_SpawnedThreadActiveFlag[WorkUnitID])
  {
    return;
  }

  m_SpawnedThreadActiveFlagLock[WorkUnitID]->lock();
  m_SpawnedThreadActiveFlag[WorkUnitID] = 0;
  m_SpawnedThreadActiveFlagLock[WorkUnitID]->unlock();

  WaitForSingleObject(m_SpawnedThreadProcessID[WorkUnitID], INFINITE);
  CloseHandle(m_SpawnedThreadProcessID[WorkUnitID]);
  m_SpawnedThreadActiveFlagLock[WorkUnitID] = nullptr;
}
#endif

void
PlatformMultiThreader::SpawnWaitForSingleMethodThread(ThreadProcessIdType threadHandle)
{
  // Using _beginthreadex on a PC
  WaitForSingleObject(threadHandle, INFINITE);
  CloseHandle(threadHandle);
}

ThreadProcessIdType
PlatformMultiThreader::SpawnDispatchSingleMethodThread(PlatformMultiThreader::WorkUnitInfo * threadInfo)
{
  // Using _beginthreadex on a PC
  DWORD  threadId;
  HANDLE threadHandle =
    (HANDLE)_beginthreadex(nullptr, 0, this->SingleMethodProxy, threadInfo, 0, (unsigned int *)&threadId);
  if (threadHandle == nullptr)
  {
    itkExceptionMacro("Error in thread creation !!!");
  }
  return threadHandle;
}

} // end namespace itk
<commit_msg>BUG: Replace C-style casts from `_beginthreadex` with `bit_cast<HANDLE>`<commit_after>/*=========================================================================
 *
 *  Copyright NumFOCUS
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 *  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.
 *
 *=========================================================================*/
/*=========================================================================
 *
 *  Portions of this file are subject to the VTK Toolkit Version 3 copyright.
 *
 *  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
 *
 *  For complete copyright, license and disclaimer of warranty information
 *  please refer to the NOTICE file at the top of the ITK source tree.
 *
 *=========================================================================*/
#include "itkPlatformMultiThreader.h"
#include "itkBitCast.h"
#include "itkObjectFactory.h"
#include "itksys/SystemTools.hxx"
#include <cstdlib>

#include "itkWindows.h"
#include <process.h>

namespace itk
{
#if !defined(ITK_LEGACY_REMOVE)
void
PlatformMultiThreader::MultipleMethodExecute()
{
  ThreadIdType threadCount;

  DWORD  threadId;
  HANDLE processId[ITK_MAX_THREADS];

  // obey the global maximum number of threads limit
  if (m_NumberOfWorkUnits > MultiThreaderBase::GetGlobalMaximumNumberOfThreads())
  {
    m_NumberOfWorkUnits = MultiThreaderBase::GetGlobalMaximumNumberOfThreads();
  }
  for (threadCount = 0; threadCount < m_NumberOfWorkUnits; ++threadCount)
  {
    if (m_MultipleMethod[threadCount] == nullptr)
    {
      itkExceptionMacro(<< "No multiple method set for: " << threadCount);
    }
  }
  // Using _beginthreadex on a PC
  //
  // We want to use _beginthreadex to start m_NumberOfWorkUnits - 1
  // additional threads which will be used to call the NumberOfWorkUnits-1
  // methods defined in this->MultipleMethods[](). The parent thread
  // will call m_MultipleMethods[NumberOfWorkUnits-1]().  When it is done,
  // it will wait for all the children to finish.
  //
  // First, start up the m_NumberOfWorkUnits-1 processes.  Keep track
  // of their process ids for use later in the waitid call
  for (threadCount = 1; threadCount < m_NumberOfWorkUnits; ++threadCount)
  {
    m_ThreadInfoArray[threadCount].UserData = m_MultipleData[threadCount];
    m_ThreadInfoArray[threadCount].NumberOfWorkUnits = m_NumberOfWorkUnits;

    processId[threadCount] = bit_cast<HANDLE>(_beginthreadex(
      nullptr, 0, m_MultipleMethod[threadCount], &m_ThreadInfoArray[threadCount], 0, (unsigned int *)&threadId));

    if (processId[threadCount] == nullptr)
    {
      itkExceptionMacro("Error in thread creation!");
    }
  }

  // Now, the parent thread calls the last method itself
  m_ThreadInfoArray[0].UserData = m_MultipleData[0];
  m_ThreadInfoArray[0].NumberOfWorkUnits = m_NumberOfWorkUnits;
  (m_MultipleMethod[0])((void *)(&m_ThreadInfoArray[0]));
  // The parent thread has finished its method - so now it
  // waits for each of the other processes to
  // exit
  for (threadCount = 1; threadCount < m_NumberOfWorkUnits; ++threadCount)
  {
    WaitForSingleObject(processId[threadCount], INFINITE);
  }
  // close the threads
  for (threadCount = 1; threadCount < m_NumberOfWorkUnits; ++threadCount)
  {
    CloseHandle(processId[threadCount]);
  }
}

ThreadIdType
PlatformMultiThreader::SpawnThread(ThreadFunctionType f, void * UserData)
{
  ThreadIdType id = 0;

  DWORD threadId;

  while (id < ITK_MAX_THREADS)
  {
    if (!m_SpawnedThreadActiveFlagLock[id])
    {
      m_SpawnedThreadActiveFlagLock[id] = std::make_shared<std::mutex>();
    }
    m_SpawnedThreadActiveFlagLock[id]->lock();
    if (m_SpawnedThreadActiveFlag[id] == 0)
    {
      // We've got a useable thread id, so grab it
      m_SpawnedThreadActiveFlag[id] = 1;
      m_SpawnedThreadActiveFlagLock[id]->unlock();
      break;
    }
    m_SpawnedThreadActiveFlagLock[id]->unlock();

    id++;
  }

  if (id >= ITK_MAX_THREADS)
  {
    itkExceptionMacro(<< "You have too many active threads!");
  }

  m_SpawnedThreadInfoArray[id].UserData = UserData;
  m_SpawnedThreadInfoArray[id].NumberOfWorkUnits = 1;
  m_SpawnedThreadInfoArray[id].ActiveFlag = &m_SpawnedThreadActiveFlag[id];
  m_SpawnedThreadInfoArray[id].ActiveFlagLock = m_SpawnedThreadActiveFlagLock[id];

  // Using _beginthreadex on a PC
  //
  m_SpawnedThreadProcessID[id] =
    bit_cast<HANDLE>(_beginthreadex(nullptr, 0, f, &m_SpawnedThreadInfoArray[id], 0, (unsigned int *)&threadId));
  if (m_SpawnedThreadProcessID[id] == nullptr)
  {
    itkExceptionMacro("Error in thread creation !!!");
  }
  return id;
}

void
PlatformMultiThreader::TerminateThread(ThreadIdType WorkUnitID)
{
  if (!m_SpawnedThreadActiveFlag[WorkUnitID])
  {
    return;
  }

  m_SpawnedThreadActiveFlagLock[WorkUnitID]->lock();
  m_SpawnedThreadActiveFlag[WorkUnitID] = 0;
  m_SpawnedThreadActiveFlagLock[WorkUnitID]->unlock();

  WaitForSingleObject(m_SpawnedThreadProcessID[WorkUnitID], INFINITE);
  CloseHandle(m_SpawnedThreadProcessID[WorkUnitID]);
  m_SpawnedThreadActiveFlagLock[WorkUnitID] = nullptr;
}
#endif

void
PlatformMultiThreader::SpawnWaitForSingleMethodThread(ThreadProcessIdType threadHandle)
{
  // Using _beginthreadex on a PC
  WaitForSingleObject(threadHandle, INFINITE);
  CloseHandle(threadHandle);
}

ThreadProcessIdType
PlatformMultiThreader::SpawnDispatchSingleMethodThread(PlatformMultiThreader::WorkUnitInfo * threadInfo)
{
  // Using _beginthreadex on a PC
  DWORD threadId;
  auto  threadHandle =
    bit_cast<HANDLE>(_beginthreadex(nullptr, 0, this->SingleMethodProxy, threadInfo, 0, (unsigned int *)&threadId));
  if (threadHandle == nullptr)
  {
    itkExceptionMacro("Error in thread creation !!!");
  }
  return threadHandle;
}

} // end namespace itk
<|endoftext|>


<commit_before>/*++
Copyright (c) 2012 Microsoft Corporation

Module Name:

    expr_safe_replace.cpp

Abstract:

    Version of expr_replace/expr_substitution that is safe for quantifiers.

Author:

    Nikolaj Bjorner (nbjorner) 2012-11-30

Revision History:

--*/

#include "expr_safe_replace.h"
#include "rewriter.h"

void expr_safe_replace::insert(expr* src, expr* dst) {
    m_src.push_back(src);
    m_dst.push_back(dst);
    m_subst.insert(src, dst);
}

void expr_safe_replace::operator()(expr* e, expr_ref& res) {
    m_todo.push_back(e);
    expr* a, *b, *d;

    while (!m_todo.empty()) {
        a = m_todo.back();
        if (m_cache.contains(a)) {
            m_todo.pop_back();
        }
        else if (m_subst.find(a, b)) {
            m_cache.insert(a, b);
            m_todo.pop_back();
        }
        else if (is_var(a)) {
            m_cache.insert(a, a);
            m_todo.pop_back();
        }
        else if (is_app(a)) {
            app* c = to_app(a);
            unsigned n = c->get_num_args();
            m_args.reset();
            for (unsigned i = 0; i < n; ++i) {
                if (m_cache.find(c->get_arg(i), d)) {
                    m_args.push_back(d);
                }
                else {
                    m_todo.push_back(c->get_arg(i));
                }
            }
            if (m_args.size() == n) {
                b = m.mk_app(c->get_decl(), m_args.size(), m_args.c_ptr());
                m_refs.push_back(b);
                m_cache.insert(a, b);
                m_todo.pop_back();
            }
        }
        else {
            SASSERT(is_quantifier(a));
            quantifier* q = to_quantifier(a);
            expr_safe_replace replace(m);
            var_shifter shift(m);
            expr_ref new_body(m), src(m), dst(m), tmp(m);
            expr_ref_vector pats(m), nopats(m);
            unsigned num_decls = q->get_num_decls();
            for (unsigned i = 0; i < m_src.size(); ++i) {
                shift(m_src[i].get(), num_decls, src);
                shift(m_dst[i].get(), num_decls, dst);
                replace.insert(src, dst);
            }
            unsigned np = q->get_num_patterns();
            for (unsigned i = 0; i < np; ++i) {
                replace(q->get_pattern(i), tmp);
                pats.push_back(tmp);
            }
            np = q->get_num_no_patterns();
            for (unsigned i = 0; i < np; ++i) {
                replace(q->get_no_pattern(i), tmp);
                nopats.push_back(tmp);
            }
            replace(q->get_expr(), new_body);
            b = m.update_quantifier(q, pats.size(), pats.c_ptr(), nopats.size(), nopats.c_ptr(), new_body);
            m_refs.push_back(b);
            m_cache.insert(a, b);
            m_todo.pop_back();
        }
    }
    res = m_cache.find(e);
    m_cache.reset();
    m_todo.reset();
    m_args.reset();
    m_refs.reset();
}

void expr_safe_replace::reset() {
    m_src.reset();
    m_dst.reset();
    m_subst.reset();
}

void expr_safe_replace::apply_substitution(expr* s, expr* def, expr_ref& t) {
    reset();
    insert(s, def);
    (*this)(t, t);
    reset();
}
<commit_msg>optimize expr_safe_replace for when a subexpression has no substitutions<commit_after>/*++
Copyright (c) 2012 Microsoft Corporation

Module Name:

    expr_safe_replace.cpp

Abstract:

    Version of expr_replace/expr_substitution that is safe for quantifiers.

Author:

    Nikolaj Bjorner (nbjorner) 2012-11-30

Revision History:

--*/

#include "expr_safe_replace.h"
#include "rewriter.h"

void expr_safe_replace::insert(expr* src, expr* dst) {
    m_src.push_back(src);
    m_dst.push_back(dst);
    m_subst.insert(src, dst);
}

void expr_safe_replace::operator()(expr* e, expr_ref& res) {
    m_todo.push_back(e);
    expr* a, *b, *d;

    while (!m_todo.empty()) {
        a = m_todo.back();
        if (m_cache.contains(a)) {
            m_todo.pop_back();
        }
        else if (m_subst.find(a, b)) {
            m_cache.insert(a, b);
            m_todo.pop_back();
        }
        else if (is_var(a)) {
            m_cache.insert(a, a);
            m_todo.pop_back();
        }
        else if (is_app(a)) {
            app* c = to_app(a);
            unsigned n = c->get_num_args();
            m_args.reset();
            bool arg_differs = false;
            for (unsigned i = 0; i < n; ++i) {
                if (m_cache.find(c->get_arg(i), d)) {
                    m_args.push_back(d);
                    arg_differs |= c->get_arg(i) != d;
                }
                else {
                    m_todo.push_back(c->get_arg(i));
                }
            }
            if (m_args.size() == n) {
                if (arg_differs) {
                    b = m.mk_app(c->get_decl(), m_args.size(), m_args.c_ptr());
                    m_refs.push_back(b);
                } else {
                    b = a;
                }
                m_cache.insert(a, b);
                m_todo.pop_back();
            }
        }
        else {
            SASSERT(is_quantifier(a));
            quantifier* q = to_quantifier(a);
            expr_safe_replace replace(m);
            var_shifter shift(m);
            expr_ref new_body(m), src(m), dst(m), tmp(m);
            expr_ref_vector pats(m), nopats(m);
            unsigned num_decls = q->get_num_decls();
            for (unsigned i = 0; i < m_src.size(); ++i) {
                shift(m_src[i].get(), num_decls, src);
                shift(m_dst[i].get(), num_decls, dst);
                replace.insert(src, dst);
            }
            unsigned np = q->get_num_patterns();
            for (unsigned i = 0; i < np; ++i) {
                replace(q->get_pattern(i), tmp);
                pats.push_back(tmp);
            }
            np = q->get_num_no_patterns();
            for (unsigned i = 0; i < np; ++i) {
                replace(q->get_no_pattern(i), tmp);
                nopats.push_back(tmp);
            }
            replace(q->get_expr(), new_body);
            b = m.update_quantifier(q, pats.size(), pats.c_ptr(), nopats.size(), nopats.c_ptr(), new_body);
            m_refs.push_back(b);
            m_cache.insert(a, b);
            m_todo.pop_back();
        }
    }
    res = m_cache.find(e);
    m_cache.reset();
    m_todo.reset();
    m_args.reset();
    m_refs.reset();
}

void expr_safe_replace::reset() {
    m_src.reset();
    m_dst.reset();
    m_subst.reset();
}

void expr_safe_replace::apply_substitution(expr* s, expr* def, expr_ref& t) {
    reset();
    insert(s, def);
    (*this)(t, t);
    reset();
}
<|endoftext|>


<commit_before>/******************************************************************************
The MIT License(MIT)

Embedded Template Library.
https://github.com/ETLCPP/etl
https://www.etlcpp.com

Copyright(c) 2020 jwellbelove

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files(the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions :

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/

#include "UnitTest++/UnitTest++.h"

#include <thread>
#include <vector>
#include <numeric>
#include <array>
#include <algorithm>
#include <queue>
#include <atomic>

#include "etl/atomic.h"
#include "etl/queue_spsc_atomic.h"
#include "etl/buffer_descriptors.h"

#if defined(ETL_TARGET_OS_WINDOWS)
  #include <Windows.h>
#endif

#define REALTIME_TEST 0

namespace
{
  constexpr size_t BUFFER_SIZE = 16U;
  constexpr size_t N_BUFFERS   = 4U;
  constexpr size_t DATA_COUNT  = BUFFER_SIZE / 2;

  using BD = etl::buffer_descriptors<char, BUFFER_SIZE, N_BUFFERS, std::atomic_char>;

  char buffers[N_BUFFERS][BUFFER_SIZE];

  //***********************************
  struct Receiver
  {
    void receive(BD::notification n)
    {
      pbuffer = n.get_descriptor().data();
      count   = n.get_count();
    }

    void clear()
    {
      pbuffer = nullptr;
      count   = 0U;
    }

    BD::pointer   pbuffer;
    BD::size_type count;
  };

  Receiver receiver;

  SUITE(test_buffer_descriptors)
  {
    //*************************************************************************
    TEST(test_constructor_plus_buffer)
    {
      BD bd(&buffers[0][0]);

      CHECK_EQUAL(N_BUFFERS, bd.N_BUFFERS);
      CHECK_EQUAL(BUFFER_SIZE, bd.BUFFER_SIZE);
      CHECK(!bd.is_valid());
    }

    //*************************************************************************
    TEST(test_constructor_plus_buffer_and_callback)
    {
      receiver.clear();
      BD::callback_type callback = BD::callback_type::create<Receiver, &Receiver::receive>(receiver);

      BD bd(&buffers[0][0], callback);

      CHECK_EQUAL(N_BUFFERS, bd.N_BUFFERS);
      CHECK_EQUAL(BUFFER_SIZE, bd.BUFFER_SIZE);
      CHECK(bd.is_valid());
    }

    //*************************************************************************
    TEST(test_constructor_plus_buffer_set_callback)
    {
      receiver.clear();
      BD::callback_type callback = BD::callback_type::create<Receiver, &Receiver::receive>(receiver);

      BD bd(&buffers[0][0]);
      bd.set_callback(callback);

      CHECK_EQUAL(N_BUFFERS, bd.N_BUFFERS);
      CHECK_EQUAL(BUFFER_SIZE, bd.BUFFER_SIZE);
      CHECK(bd.is_valid());
    }

    //*************************************************************************
    TEST(test_buffers)
    {
      BD bd(&buffers[0][0]);

      for (size_t i = 0U; i < N_BUFFERS - 1; ++i)
      {
        BD::descriptor desc = bd.allocate();

        //CHECK_EQUAL(BUFFER_SIZE, desc.max_size());
        //CHECK_EQUAL(uintptr_t(&buffers[i][0]), uintptr_t(desc.data()));
      }
    }

    //*************************************************************************
    TEST(test_buffers_with_allocate_fill)
    {
      std::array<char, BUFFER_SIZE> test =
      {
        char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF),
        char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF)
      };

      BD bd(&buffers[0][0]);

      for (size_t i = 0U; i < N_BUFFERS; ++i)
      {
        BD::descriptor desc = bd.allocate(char(0xFF));

        CHECK_EQUAL(BUFFER_SIZE, desc.max_size());
        CHECK_EQUAL(uintptr_t(&buffers[i][0]), uintptr_t(desc.data()));
        CHECK_ARRAY_EQUAL(test.data(), desc.data(), BUFFER_SIZE);
      }
    }

    //*************************************************************************
    TEST(test_notifications)
    {
      std::array<char, BUFFER_SIZE> test = { 0, 1, 2, 3, 4, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0 };

      std::fill(&buffers[0][0], &buffers[N_BUFFERS - 1][0] + BUFFER_SIZE , 0U);

      receiver.clear();
      BD::callback_type callback = BD::callback_type::create<Receiver, &Receiver::receive>(receiver);

      BD bd(&buffers[0][0], callback);

      for (size_t i = 0U; i < N_BUFFERS; ++i)
      {
        BD::descriptor desc = bd.allocate();

        CHECK(desc.is_valid());

        std::copy(test.begin(), test.begin() + DATA_COUNT, desc.data());
        bd.notify(BD::notification(desc, DATA_COUNT));
        desc.release();

        CHECK_EQUAL(DATA_COUNT, receiver.count);
        CHECK_EQUAL(uintptr_t(&buffers[i][0]), uintptr_t(receiver.pbuffer));
        CHECK_ARRAY_EQUAL(test.data(), desc.data(), BUFFER_SIZE);
      }
    }

    //*************************************************************************
    TEST(test_allocate_overflow)
    {
      BD bd(&buffers[0][0]);

      // Use up all of the descriptors.
      for (size_t i = 0U; i < N_BUFFERS; ++i)
      {
        BD::descriptor desc = bd.allocate();
        CHECK(desc.is_valid());
      }

      BD::descriptor desc = bd.allocate();
      CHECK(!desc.is_valid());
    }

    //*************************************************************************
    TEST(test_allocate_release_rollover)
    {
      std::queue<BD::descriptor> desc_queue;

      BD bd(&buffers[0][0]);

      // Use up all of the descriptors, then release/allocate for the rest.
      for (size_t i = 0U; i < (N_BUFFERS * 2); ++i)
      {
        BD::descriptor desc = bd.allocate();
        desc_queue.push(desc);

        CHECK(desc.is_valid());

        if (i >= (N_BUFFERS - 1))
        {
          desc_queue.front().release();
          desc_queue.pop();
        }
      }
    }

    //*************************************************************************
    TEST(test_descriptors)
    {
      BD bd(&buffers[0][0]);

      BD::descriptor desc1 = bd.allocate();
      BD::descriptor desc2 = bd.allocate();
      BD::descriptor desc3 = bd.allocate();
      BD::descriptor desc4 = bd.allocate();

      CHECK(desc1.is_allocated());
      CHECK(desc2.is_allocated());
      CHECK(desc3.is_allocated());
      CHECK(desc4.is_allocated());

      CHECK(desc1.data() == &buffers[0][0]);
      CHECK(desc2.data() == &buffers[1][0]);
      CHECK(desc3.data() == &buffers[2][0]);
      CHECK(desc4.data() == &buffers[3][0]);

      CHECK(desc1.max_size() == BUFFER_SIZE);
      CHECK(desc2.max_size() == BUFFER_SIZE);
      CHECK(desc3.max_size() == BUFFER_SIZE);
      CHECK(desc4.max_size() == BUFFER_SIZE);

      CHECK(desc1.MAX_SIZE == BUFFER_SIZE);
      CHECK(desc2.MAX_SIZE == BUFFER_SIZE);
      CHECK(desc3.MAX_SIZE == BUFFER_SIZE);
      CHECK(desc4.MAX_SIZE == BUFFER_SIZE);

      CHECK(desc1.is_valid());
      CHECK(desc2.is_valid());
      CHECK(desc3.is_valid());
      CHECK(desc4.is_valid());

      desc1.release();
      desc2.release();
      desc3.release();
      desc4.release();

      CHECK(desc1.is_released());
      CHECK(desc2.is_released());
      CHECK(desc3.is_released());
      CHECK(desc4.is_released());
    }

    //*************************************************************************
#if REALTIME_TEST

#if defined(ETL_TARGET_OS_WINDOWS) // Only Windows priority is currently supported
#define RAISE_THREAD_PRIORITY  SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST)
#define FIX_PROCESSOR_AFFINITY1 SetThreadAffinityMask(GetCurrentThread(), 1)
#define FIX_PROCESSOR_AFFINITY2 SetThreadAffinityMask(GetCurrentThread(), 2)
#else
#define RAISE_THREAD_PRIORITY
#define FIX_PROCESSOR_AFFINITY1
#define FIX_PROCESSOR_AFFINITY2
#endif

    std::atomic_bool start = false;

    //*********************************
    struct Notification
    {
      BD::descriptor    desc;
      BD::size_type count;
    };

    constexpr int N_ITERATIONS = 1000000;

    etl::queue_spsc_atomic<BD::notification, N_ITERATIONS + 100> desc_queue;

    //*********************************
    void Callback(BD::notification n)
    {
      desc_queue.push(n);
    }

    //*********************************
    void Producer()
    {
      static char buffers[N_BUFFERS][BUFFER_SIZE];

      BD bd(&buffers[0][0], BD::callback_type::create<Callback>());

      RAISE_THREAD_PRIORITY;
      FIX_PROCESSOR_AFFINITY1;

      // Wait for the start flag.
      while (!start);

      int errors = 0;

      for (int i = 0; i < N_ITERATIONS; ++i)
      {
        BD::descriptor desc;

        // Wait until we can allocate a descriptor.
        do
        {
          desc = bd.allocate();
        } while (desc.is_valid() == false);

        if (!desc.is_allocated())
        {
          ++errors;
        }

        // Send a notification to the callback function.
        bd.notify(BD::notification(desc, BUFFER_SIZE));
      }

      CHECK_EQUAL(0, errors);
    }

    //*********************************
    void Consumer()
    {
      RAISE_THREAD_PRIORITY;
      FIX_PROCESSOR_AFFINITY2;

      // Wait for the start flag.
      while (!start);

      int errors = 0;

      for (int i = 0; i < N_ITERATIONS;)
      {
        BD::notification notification;

        // Try to get a notification from the queue.
        if (desc_queue.pop(notification))
        {
          CHECK_EQUAL(BUFFER_SIZE, notification.get_count());
          CHECK(notification.get_descriptor().is_allocated());

          if (!notification.get_descriptor().is_allocated())
          {
            ++errors;
          }

          notification.get_descriptor().release();
          ++i;
        }

        CHECK_EQUAL(0, errors);
      }
    }

    //*********************************
    TEST(test_multi_thread)
    {
      std::thread t1(Producer);
      std::thread t2(Consumer);

      start = true;

      t1.join();
      t2.join();
    }
#endif
  };
}
<commit_msg>Refactor buffer_descriptors test<commit_after>/******************************************************************************
The MIT License(MIT)

Embedded Template Library.
https://github.com/ETLCPP/etl
https://www.etlcpp.com

Copyright(c) 2020 jwellbelove

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files(the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions :

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/

#include "UnitTest++/UnitTest++.h"

#include <thread>
#include <vector>
#include <numeric>
#include <array>
#include <algorithm>
#include <queue>
#include <atomic>

#include "etl/atomic.h"
#include "etl/queue_spsc_atomic.h"
#include "etl/buffer_descriptors.h"

#if defined(ETL_TARGET_OS_WINDOWS)
#include <Windows.h>
#endif

#define REALTIME_TEST 0

namespace
{
  constexpr size_t BUFFER_SIZE = 16U;
  constexpr size_t N_BUFFERS = 4U;
  constexpr size_t DATA_COUNT = BUFFER_SIZE / 2;

  using BD = etl::buffer_descriptors<char, BUFFER_SIZE, N_BUFFERS, std::atomic_char>;

  char buffers[N_BUFFERS][BUFFER_SIZE];

  //***********************************
  struct Receiver
  {
    void receive(BD::notification n)
    {
      pbuffer = n.get_descriptor().data();
      count = n.get_count();
    }

    void clear()
    {
      pbuffer = nullptr;
      count = 0U;
    }

    BD::pointer   pbuffer;
    BD::size_type count;
  };

  Receiver receiver;

  SUITE(test_buffer_descriptors)
  {
    ////*************************************************************************
    //TEST(test_constructor_plus_buffer)
    //{
    //  BD bd(&buffers[0][0]);

    //  CHECK_EQUAL(N_BUFFERS, bd.N_BUFFERS);
    //  CHECK_EQUAL(BUFFER_SIZE, bd.BUFFER_SIZE);
    //  CHECK(!bd.is_valid());
    //}

    ////*************************************************************************
    //TEST(test_constructor_plus_buffer_and_callback)
    //{
    //  receiver.clear();
    //  BD::callback_type callback = BD::callback_type::create<Receiver, &Receiver::receive>(receiver);

    //  BD bd(&buffers[0][0], callback);

    //  CHECK_EQUAL(N_BUFFERS, bd.N_BUFFERS);
    //  CHECK_EQUAL(BUFFER_SIZE, bd.BUFFER_SIZE);
    //  CHECK(bd.is_valid());
    //}

    ////*************************************************************************
    //TEST(test_constructor_plus_buffer_set_callback)
    //{
    //  receiver.clear();
    //  BD::callback_type callback = BD::callback_type::create<Receiver, &Receiver::receive>(receiver);

    //  BD bd(&buffers[0][0]);
    //  bd.set_callback(callback);

    //  CHECK_EQUAL(N_BUFFERS, bd.N_BUFFERS);
    //  CHECK_EQUAL(BUFFER_SIZE, bd.BUFFER_SIZE);
    //  CHECK(bd.is_valid());
    //}

    //*************************************************************************
    TEST(test_buffers)
    {
      BD bd(&buffers[0][0]);

      for (size_t i = 0U; i < 1; ++i)
      {
        BD::descriptor desc = bd.allocate();

        //CHECK_EQUAL(BUFFER_SIZE, desc.max_size());
        //CHECK_EQUAL(uintptr_t(&buffers[i][0]), uintptr_t(desc.data()));
      }
    }
    //
    //    //*************************************************************************
    //    TEST(test_buffers_with_allocate_fill)
    //    {
    //      std::array<char, BUFFER_SIZE> test =
    //      {
    //        char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF),
    //        char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF)
    //      };
    //
    //      BD bd(&buffers[0][0]);
    //
    //      for (size_t i = 0U; i < N_BUFFERS; ++i)
    //      {
    //        BD::descriptor desc = bd.allocate(char(0xFF));
    //
    //        CHECK_EQUAL(BUFFER_SIZE, desc.max_size());
    //        CHECK_EQUAL(uintptr_t(&buffers[i][0]), uintptr_t(desc.data()));
    //        CHECK_ARRAY_EQUAL(test.data(), desc.data(), BUFFER_SIZE);
    //      }
    //    }
    //
    //    //*************************************************************************
    //    TEST(test_notifications)
    //    {
    //      std::array<char, BUFFER_SIZE> test = { 0, 1, 2, 3, 4, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0 };
    //
    //      std::fill(&buffers[0][0], &buffers[N_BUFFERS - 1][0] + BUFFER_SIZE , 0U);
    //
    //      receiver.clear();
    //      BD::callback_type callback = BD::callback_type::create<Receiver, &Receiver::receive>(receiver);
    //
    //      BD bd(&buffers[0][0], callback);
    //
    //      for (size_t i = 0U; i < N_BUFFERS; ++i)
    //      {
    //        BD::descriptor desc = bd.allocate();
    //
    //        CHECK(desc.is_valid());
    //
    //        std::copy(test.begin(), test.begin() + DATA_COUNT, desc.data());
    //        bd.notify(BD::notification(desc, DATA_COUNT));
    //        desc.release();
    //
    //        CHECK_EQUAL(DATA_COUNT, receiver.count);
    //        CHECK_EQUAL(uintptr_t(&buffers[i][0]), uintptr_t(receiver.pbuffer));
    //        CHECK_ARRAY_EQUAL(test.data(), desc.data(), BUFFER_SIZE);
    //      }
    //    }
    //
    //    //*************************************************************************
    //    TEST(test_allocate_overflow)
    //    {
    //      BD bd(&buffers[0][0]);
    //
    //      // Use up all of the descriptors.
    //      for (size_t i = 0U; i < N_BUFFERS; ++i)
    //      {
    //        BD::descriptor desc = bd.allocate();
    //        CHECK(desc.is_valid());
    //      }
    //
    //      BD::descriptor desc = bd.allocate();
    //      CHECK(!desc.is_valid());
    //    }
    //
    //    //*************************************************************************
    //    TEST(test_allocate_release_rollover)
    //    {
    //      std::queue<BD::descriptor> desc_queue;
    //
    //      BD bd(&buffers[0][0]);
    //
    //      // Use up all of the descriptors, then release/allocate for the rest.
    //      for (size_t i = 0U; i < (N_BUFFERS * 2); ++i)
    //      {
    //        BD::descriptor desc = bd.allocate();
    //        desc_queue.push(desc);
    //
    //        CHECK(desc.is_valid());
    //
    //        if (i >= (N_BUFFERS - 1))
    //        {
    //          desc_queue.front().release();
    //          desc_queue.pop();
    //        }
    //      }
    //    }
    //
    //    //*************************************************************************
    //    TEST(test_descriptors)
    //    {
    //      BD bd(&buffers[0][0]);
    //
    //      BD::descriptor desc1 = bd.allocate();
    //      BD::descriptor desc2 = bd.allocate();
    //      BD::descriptor desc3 = bd.allocate();
    //      BD::descriptor desc4 = bd.allocate();
    //
    //      CHECK(desc1.is_allocated());
    //      CHECK(desc2.is_allocated());
    //      CHECK(desc3.is_allocated());
    //      CHECK(desc4.is_allocated());
    //
    //      CHECK(desc1.data() == &buffers[0][0]);
    //      CHECK(desc2.data() == &buffers[1][0]);
    //      CHECK(desc3.data() == &buffers[2][0]);
    //      CHECK(desc4.data() == &buffers[3][0]);
    //
    //      CHECK(desc1.max_size() == BUFFER_SIZE);
    //      CHECK(desc2.max_size() == BUFFER_SIZE);
    //      CHECK(desc3.max_size() == BUFFER_SIZE);
    //      CHECK(desc4.max_size() == BUFFER_SIZE);
    //
    //      CHECK(desc1.MAX_SIZE == BUFFER_SIZE);
    //      CHECK(desc2.MAX_SIZE == BUFFER_SIZE);
    //      CHECK(desc3.MAX_SIZE == BUFFER_SIZE);
    //      CHECK(desc4.MAX_SIZE == BUFFER_SIZE);
    //
    //      CHECK(desc1.is_valid());
    //      CHECK(desc2.is_valid());
    //      CHECK(desc3.is_valid());
    //      CHECK(desc4.is_valid());
    //
    //      desc1.release();
    //      desc2.release();
    //      desc3.release();
    //      desc4.release();
    //
    //      CHECK(desc1.is_released());
    //      CHECK(desc2.is_released());
    //      CHECK(desc3.is_released());
    //      CHECK(desc4.is_released());
    //    }
    //
    //    //*************************************************************************
    //#if REALTIME_TEST
    //
    //#if defined(ETL_TARGET_OS_WINDOWS) // Only Windows priority is currently supported
    //#define RAISE_THREAD_PRIORITY  SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST)
    //#define FIX_PROCESSOR_AFFINITY1 SetThreadAffinityMask(GetCurrentThread(), 1)
    //#define FIX_PROCESSOR_AFFINITY2 SetThreadAffinityMask(GetCurrentThread(), 2)
    //#else
    //#define RAISE_THREAD_PRIORITY
    //#define FIX_PROCESSOR_AFFINITY1
    //#define FIX_PROCESSOR_AFFINITY2
    //#endif
    //
    //    std::atomic_bool start = false;
    //
    //    //*********************************
    //    struct Notification
    //    {
    //      BD::descriptor    desc;
    //      BD::size_type count;
    //    };
    //
    //    constexpr int N_ITERATIONS = 1000000;
    //
    //    etl::queue_spsc_atomic<BD::notification, N_ITERATIONS + 100> desc_queue;
    //
    //    //*********************************
    //    void Callback(BD::notification n)
    //    {
    //      desc_queue.push(n);
    //    }
    //
    //    //*********************************
    //    void Producer()
    //    {
    //      static char buffers[N_BUFFERS][BUFFER_SIZE];
    //
    //      BD bd(&buffers[0][0], BD::callback_type::create<Callback>());
    //
    //      RAISE_THREAD_PRIORITY;
    //      FIX_PROCESSOR_AFFINITY1;
    //
    //      // Wait for the start flag.
    //      while (!start);
    //
    //      int errors = 0;
    //
    //      for (int i = 0; i < N_ITERATIONS; ++i)
    //      {
    //        BD::descriptor desc;
    //
    //        // Wait until we can allocate a descriptor.
    //        do
    //        {
    //          desc = bd.allocate();
    //        } while (desc.is_valid() == false);
    //
    //        if (!desc.is_allocated())
    //        {
    //          ++errors;
    //        }
    //
    //        // Send a notification to the callback function.
    //        bd.notify(BD::notification(desc, BUFFER_SIZE));
    //      }
    //
    //      CHECK_EQUAL(0, errors);
    //    }
    //
    //    //*********************************
    //    void Consumer()
    //    {
    //      RAISE_THREAD_PRIORITY;
    //      FIX_PROCESSOR_AFFINITY2;
    //
    //      // Wait for the start flag.
    //      while (!start);
    //
    //      int errors = 0;
    //
    //      for (int i = 0; i < N_ITERATIONS;)
    //      {
    //        BD::notification notification;
    //
    //        // Try to get a notification from the queue.
    //        if (desc_queue.pop(notification))
    //        {
    //          CHECK_EQUAL(BUFFER_SIZE, notification.get_count());
    //          CHECK(notification.get_descriptor().is_allocated());
    //
    //          if (!notification.get_descriptor().is_allocated())
    //          {
    //            ++errors;
    //          }
    //
    //          notification.get_descriptor().release();
    //          ++i;
    //        }
    //
    //        CHECK_EQUAL(0, errors);
    //      }
    //    }
    //
    //    //*********************************
    //    TEST(test_multi_thread)
    //    {
    //      std::thread t1(Producer);
    //      std::thread t2(Consumer);
    //
    //      start = true;
    //
    //      t1.join();
    //      t2.join();
    //    }
    //#endif
  };
}
<|endoftext|>