<commit_before>/* Copyright (c) 2018 PaddlePaddle 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. */

#include <glog/logging.h>
#include <gtest/gtest.h>

#include <thread>  // NOLINT

#include "gflags/gflags.h"
#include "paddle/fluid/inference/api/api_impl.h"
#include "paddle/fluid/inference/tests/test_helper.h"

DEFINE_string(dirname, "", "Directory of the inference model.");

namespace paddle {

PaddleTensor LodTensorToPaddleTensor(framework::LoDTensor* t) {
  PaddleTensor pt;

  if (t->type() == typeid(int64_t)) {
    pt.data.Reset(t->data<void>(), t->numel() * sizeof(int64_t));
    pt.dtype = PaddleDType::INT64;
  } else if (t->type() == typeid(float)) {
    pt.data.Reset(t->data<void>(), t->numel() * sizeof(float));
    pt.dtype = PaddleDType::FLOAT32;
  } else {
    LOG(FATAL) << "unsupported type.";
  }
  pt.shape = framework::vectorize2int(t->dims());
  return pt;
}

NativeConfig GetConfig() {
  NativeConfig config;
  config.model_dir = FLAGS_dirname + "/word2vec.inference.model";
  LOG(INFO) << "dirname  " << config.model_dir;
  config.fraction_of_gpu_memory = 0.15;
#ifdef PADDLE_WITH_CUDA
  config.use_gpu = true;
#else
  config.use_gpu = false;
#endif
  config.device = 0;
  return config;
}

void MainWord2Vec(bool use_gpu) {
  NativeConfig config = GetConfig();
  auto predictor = CreatePaddlePredictor<NativeConfig>(config);
  config.use_gpu = use_gpu;

  framework::LoDTensor first_word, second_word, third_word, fourth_word;
  framework::LoD lod{{0, 1}};
  int64_t dict_size = 2073;  // The size of dictionary

  SetupLoDTensor(&first_word, lod, static_cast<int64_t>(0), dict_size - 1);
  SetupLoDTensor(&second_word, lod, static_cast<int64_t>(0), dict_size - 1);
  SetupLoDTensor(&third_word, lod, static_cast<int64_t>(0), dict_size - 1);
  SetupLoDTensor(&fourth_word, lod, static_cast<int64_t>(0), dict_size - 1);

  std::vector<PaddleTensor> paddle_tensor_feeds;
  paddle_tensor_feeds.push_back(LodTensorToPaddleTensor(&first_word));
  paddle_tensor_feeds.push_back(LodTensorToPaddleTensor(&second_word));
  paddle_tensor_feeds.push_back(LodTensorToPaddleTensor(&third_word));
  paddle_tensor_feeds.push_back(LodTensorToPaddleTensor(&fourth_word));

  std::vector<PaddleTensor> outputs;
  ASSERT_TRUE(predictor->Run(paddle_tensor_feeds, &outputs));
  ASSERT_EQ(outputs.size(), 1UL);
  size_t len = outputs[0].data.length();
  float* data = static_cast<float*>(outputs[0].data.data());
  for (size_t j = 0; j < len / sizeof(float); ++j) {
    ASSERT_LT(data[j], 1.0);
    ASSERT_GT(data[j], -1.0);
  }

  std::vector<paddle::framework::LoDTensor*> cpu_feeds;
  cpu_feeds.push_back(&first_word);
  cpu_feeds.push_back(&second_word);
  cpu_feeds.push_back(&third_word);
  cpu_feeds.push_back(&fourth_word);

  framework::LoDTensor output1;
  std::vector<paddle::framework::LoDTensor*> cpu_fetchs1;
  cpu_fetchs1.push_back(&output1);

  TestInference<platform::CPUPlace>(config.model_dir, cpu_feeds, cpu_fetchs1);

  float* lod_data = output1.data<float>();
  for (int i = 0; i < output1.numel(); ++i) {
    EXPECT_LT(lod_data[i] - data[i], 1e-3);
    EXPECT_GT(lod_data[i] - data[i], -1e-3);
  }
}

void MainImageClassification(bool use_gpu) {
  int batch_size = 2;
  bool repeat = false;
  NativeConfig config = GetConfig();
  config.use_gpu = use_gpu;
  config.model_dir =
      FLAGS_dirname + "/image_classification_resnet.inference.model";

  const bool is_combined = false;
  std::vector<std::vector<int64_t>> feed_target_shapes =
      GetFeedTargetShapes(config.model_dir, is_combined);

  framework::LoDTensor input;
  // Use normilized image pixels as input data,
  // which should be in the range [0.0, 1.0].
  feed_target_shapes[0][0] = batch_size;
  framework::DDim input_dims = framework::make_ddim(feed_target_shapes[0]);
  SetupTensor<float>(&input, input_dims, static_cast<float>(0),
                     static_cast<float>(1));
  std::vector<framework::LoDTensor*> cpu_feeds;
  cpu_feeds.push_back(&input);

  framework::LoDTensor output1;
  std::vector<framework::LoDTensor*> cpu_fetchs1;
  cpu_fetchs1.push_back(&output1);

  TestInference<platform::CPUPlace, false, true>(
      config.model_dir, cpu_feeds, cpu_fetchs1, repeat, is_combined);

  auto predictor = CreatePaddlePredictor(config);
  std::vector<PaddleTensor> paddle_tensor_feeds;
  paddle_tensor_feeds.push_back(LodTensorToPaddleTensor(&input));

  std::vector<PaddleTensor> outputs;
  ASSERT_TRUE(predictor->Run(paddle_tensor_feeds, &outputs));
  ASSERT_EQ(outputs.size(), 1UL);
  size_t len = outputs[0].data.length();
  float* data = static_cast<float*>(outputs[0].data.data());
  float* lod_data = output1.data<float>();
  for (size_t j = 0; j < len / sizeof(float); ++j) {
    EXPECT_NEAR(lod_data[j], data[j], 1e-3);
  }
}

void MainThreadsWord2Vec(bool use_gpu) {
  NativeConfig config = GetConfig();
  config.use_gpu = use_gpu;
  auto main_predictor = CreatePaddlePredictor<NativeConfig>(config);

  // prepare inputs data and reference results
  constexpr int num_jobs = 3;
  std::vector<std::vector<framework::LoDTensor>> jobs(num_jobs);
  std::vector<std::vector<PaddleTensor>> paddle_tensor_feeds(num_jobs);
  std::vector<framework::LoDTensor> refs(num_jobs);
  for (size_t i = 0; i < jobs.size(); ++i) {
    // each job has 4 words
    jobs[i].resize(4);
    for (size_t j = 0; j < 4; ++j) {
      framework::LoD lod{{0, 1}};
      int64_t dict_size = 2073;  // The size of dictionary
      SetupLoDTensor(&jobs[i][j], lod, static_cast<int64_t>(0), dict_size - 1);
      paddle_tensor_feeds[i].push_back(LodTensorToPaddleTensor(&jobs[i][j]));
    }

    // get reference result of each job
    std::vector<paddle::framework::LoDTensor*> ref_feeds;
    std::vector<paddle::framework::LoDTensor*> ref_fetches(1, &refs[i]);
    for (auto& word : jobs[i]) {
      ref_feeds.push_back(&word);
    }
    TestInference<platform::CPUPlace>(config.model_dir, ref_feeds, ref_fetches);
  }

  // create threads and each thread run 1 job
  std::vector<std::thread> threads;
  for (int tid = 0; tid < num_jobs; ++tid) {
    threads.emplace_back([&, tid]() {
      auto predictor = main_predictor->Clone();
      auto& local_inputs = paddle_tensor_feeds[tid];
      std::vector<PaddleTensor> local_outputs;
      ASSERT_TRUE(predictor->Run(local_inputs, &local_outputs));

      // check outputs range
      ASSERT_EQ(local_outputs.size(), 1UL);
      const size_t len = local_outputs[0].data.length();
      float* data = static_cast<float*>(local_outputs[0].data.data());
      for (size_t j = 0; j < len / sizeof(float); ++j) {
        ASSERT_LT(data[j], 1.0);
        ASSERT_GT(data[j], -1.0);
      }

      // check outputs correctness
      float* ref_data = refs[tid].data<float>();
      EXPECT_EQ(refs[tid].numel(), static_cast<int64_t>(len / sizeof(float)));
      for (int i = 0; i < refs[tid].numel(); ++i) {
        EXPECT_NEAR(ref_data[i], data[i], 1e-3);
      }
    });
  }
  for (int i = 0; i < num_jobs; ++i) {
    threads[i].join();
  }
}

void MainThreadsImageClassification(bool use_gpu) {
  constexpr int num_jobs = 4;  // each job run 1 batch
  constexpr int batch_size = 1;
  NativeConfig config = GetConfig();
  config.use_gpu = use_gpu;
  config.model_dir =
      FLAGS_dirname + "/image_classification_resnet.inference.model";

  auto main_predictor = CreatePaddlePredictor<NativeConfig>(config);
  std::vector<framework::LoDTensor> jobs(num_jobs);
  std::vector<std::vector<PaddleTensor>> paddle_tensor_feeds(num_jobs);
  std::vector<framework::LoDTensor> refs(num_jobs);
  for (size_t i = 0; i < jobs.size(); ++i) {
    // prepare inputs
    std::vector<std::vector<int64_t>> feed_target_shapes =
        GetFeedTargetShapes(config.model_dir, /*is_combined*/ false);
    feed_target_shapes[0][0] = batch_size;
    framework::DDim input_dims = framework::make_ddim(feed_target_shapes[0]);
    SetupTensor<float>(&jobs[i], input_dims, 0.f, 1.f);
    paddle_tensor_feeds[i].push_back(LodTensorToPaddleTensor(&jobs[i]));

    // get reference result of each job
    std::vector<framework::LoDTensor*> ref_feeds(1, &jobs[i]);
    std::vector<framework::LoDTensor*> ref_fetches(1, &refs[i]);
    TestInference<platform::CPUPlace>(config.model_dir, ref_feeds, ref_fetches);
  }

  // create threads and each thread run 1 job
  std::vector<std::thread> threads;
  for (int tid = 0; tid < num_jobs; ++tid) {
    threads.emplace_back([&, tid]() {
      auto predictor = main_predictor->Clone();
      auto& local_inputs = paddle_tensor_feeds[tid];
      std::vector<PaddleTensor> local_outputs;
      ASSERT_TRUE(predictor->Run(local_inputs, &local_outputs));

      // check outputs correctness
      ASSERT_EQ(local_outputs.size(), 1UL);
      const size_t len = local_outputs[0].data.length();
      float* data = static_cast<float*>(local_outputs[0].data.data());
      float* ref_data = refs[tid].data<float>();
      EXPECT_EQ((size_t)refs[tid].numel(), len / sizeof(float));
      for (int i = 0; i < refs[tid].numel(); ++i) {
        EXPECT_NEAR(ref_data[i], data[i], 1e-3);
      }
    });
  }
  for (int i = 0; i < num_jobs; ++i) {
    threads[i].join();
  }
}

TEST(inference_api_native, word2vec_cpu) { MainWord2Vec(false /*use_gpu*/); }
TEST(inference_api_native, word2vec_cpu_threads) {
  MainThreadsWord2Vec(false /*use_gpu*/);
}
TEST(inference_api_native, image_classification_cpu) {
  MainThreadsImageClassification(false /*use_gpu*/);
}
TEST(inference_api_native, image_classification_cpu_threads) {
  MainThreadsImageClassification(false /*use_gpu*/);
}

#ifdef PADDLE_WITH_CUDA
TEST(inference_api_native, word2vec_gpu) { MainWord2Vec(true /*use_gpu*/); }
TEST(inference_api_native, word2vec_gpu_threads) {
  MainThreadsWord2Vec(true /*use_gpu*/);
}
TEST(inference_api_native, image_classification_gpu) {
  MainThreadsImageClassification(true /*use_gpu*/);
}
TEST(inference_api_native, image_classification_gpu_threads) {
  MainThreadsImageClassification(true /*use_gpu*/);
}

#endif

}  // namespace paddle
<commit_msg>test=develop<commit_after>/* Copyright (c) 2018 PaddlePaddle 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. */

#include <glog/logging.h>
#include <gtest/gtest.h>

#include <thread>  // NOLINT

#include "gflags/gflags.h"
#include "paddle/fluid/inference/api/api_impl.h"
#include "paddle/fluid/inference/tests/test_helper.h"

#ifdef __clang__
#define ACC_DIFF 4e-3
#else
#define ACC_DIFF 1e-3
#endif

DEFINE_string(dirname, "", "Directory of the inference model.");

namespace paddle {

PaddleTensor LodTensorToPaddleTensor(framework::LoDTensor* t) {
  PaddleTensor pt;

  if (t->type() == typeid(int64_t)) {
    pt.data.Reset(t->data<void>(), t->numel() * sizeof(int64_t));
    pt.dtype = PaddleDType::INT64;
  } else if (t->type() == typeid(float)) {
    pt.data.Reset(t->data<void>(), t->numel() * sizeof(float));
    pt.dtype = PaddleDType::FLOAT32;
  } else {
    LOG(FATAL) << "unsupported type.";
  }
  pt.shape = framework::vectorize2int(t->dims());
  return pt;
}

NativeConfig GetConfig() {
  NativeConfig config;
  config.model_dir = FLAGS_dirname + "/word2vec.inference.model";
  LOG(INFO) << "dirname  " << config.model_dir;
  config.fraction_of_gpu_memory = 0.15;
#ifdef PADDLE_WITH_CUDA
  config.use_gpu = true;
#else
  config.use_gpu = false;
#endif
  config.device = 0;
  return config;
}

void MainWord2Vec(bool use_gpu) {
  NativeConfig config = GetConfig();
  auto predictor = CreatePaddlePredictor<NativeConfig>(config);
  config.use_gpu = use_gpu;

  framework::LoDTensor first_word, second_word, third_word, fourth_word;
  framework::LoD lod{{0, 1}};
  int64_t dict_size = 2073;  // The size of dictionary

  SetupLoDTensor(&first_word, lod, static_cast<int64_t>(0), dict_size - 1);
  SetupLoDTensor(&second_word, lod, static_cast<int64_t>(0), dict_size - 1);
  SetupLoDTensor(&third_word, lod, static_cast<int64_t>(0), dict_size - 1);
  SetupLoDTensor(&fourth_word, lod, static_cast<int64_t>(0), dict_size - 1);

  std::vector<PaddleTensor> paddle_tensor_feeds;
  paddle_tensor_feeds.push_back(LodTensorToPaddleTensor(&first_word));
  paddle_tensor_feeds.push_back(LodTensorToPaddleTensor(&second_word));
  paddle_tensor_feeds.push_back(LodTensorToPaddleTensor(&third_word));
  paddle_tensor_feeds.push_back(LodTensorToPaddleTensor(&fourth_word));

  std::vector<PaddleTensor> outputs;
  ASSERT_TRUE(predictor->Run(paddle_tensor_feeds, &outputs));
  ASSERT_EQ(outputs.size(), 1UL);
  size_t len = outputs[0].data.length();
  float* data = static_cast<float*>(outputs[0].data.data());
  for (size_t j = 0; j < len / sizeof(float); ++j) {
    ASSERT_LT(data[j], 1.0);
    ASSERT_GT(data[j], -1.0);
  }

  std::vector<paddle::framework::LoDTensor*> cpu_feeds;
  cpu_feeds.push_back(&first_word);
  cpu_feeds.push_back(&second_word);
  cpu_feeds.push_back(&third_word);
  cpu_feeds.push_back(&fourth_word);

  framework::LoDTensor output1;
  std::vector<paddle::framework::LoDTensor*> cpu_fetchs1;
  cpu_fetchs1.push_back(&output1);

  TestInference<platform::CPUPlace>(config.model_dir, cpu_feeds, cpu_fetchs1);

  float* lod_data = output1.data<float>();
  for (int i = 0; i < output1.numel(); ++i) {
    EXPECT_LT(lod_data[i] - data[i], ACC_DIFF);
    EXPECT_GT(lod_data[i] - data[i], -ACC_DIFF);
  }
}

void MainImageClassification(bool use_gpu) {
  int batch_size = 2;
  bool repeat = false;
  NativeConfig config = GetConfig();
  config.use_gpu = use_gpu;
  config.model_dir =
      FLAGS_dirname + "/image_classification_resnet.inference.model";

  const bool is_combined = false;
  std::vector<std::vector<int64_t>> feed_target_shapes =
      GetFeedTargetShapes(config.model_dir, is_combined);

  framework::LoDTensor input;
  // Use normilized image pixels as input data,
  // which should be in the range [0.0, 1.0].
  feed_target_shapes[0][0] = batch_size;
  framework::DDim input_dims = framework::make_ddim(feed_target_shapes[0]);
  SetupTensor<float>(&input, input_dims, static_cast<float>(0),
                     static_cast<float>(1));
  std::vector<framework::LoDTensor*> cpu_feeds;
  cpu_feeds.push_back(&input);

  framework::LoDTensor output1;
  std::vector<framework::LoDTensor*> cpu_fetchs1;
  cpu_fetchs1.push_back(&output1);

  TestInference<platform::CPUPlace, false, true>(
      config.model_dir, cpu_feeds, cpu_fetchs1, repeat, is_combined);

  auto predictor = CreatePaddlePredictor(config);
  std::vector<PaddleTensor> paddle_tensor_feeds;
  paddle_tensor_feeds.push_back(LodTensorToPaddleTensor(&input));

  std::vector<PaddleTensor> outputs;
  ASSERT_TRUE(predictor->Run(paddle_tensor_feeds, &outputs));
  ASSERT_EQ(outputs.size(), 1UL);
  size_t len = outputs[0].data.length();
  float* data = static_cast<float*>(outputs[0].data.data());
  float* lod_data = output1.data<float>();
  for (size_t j = 0; j < len / sizeof(float); ++j) {
    EXPECT_NEAR(lod_data[j], data[j], ACC_DIFF);
  }
}

void MainThreadsWord2Vec(bool use_gpu) {
  NativeConfig config = GetConfig();
  config.use_gpu = use_gpu;
  auto main_predictor = CreatePaddlePredictor<NativeConfig>(config);

  // prepare inputs data and reference results
  constexpr int num_jobs = 3;
  std::vector<std::vector<framework::LoDTensor>> jobs(num_jobs);
  std::vector<std::vector<PaddleTensor>> paddle_tensor_feeds(num_jobs);
  std::vector<framework::LoDTensor> refs(num_jobs);
  for (size_t i = 0; i < jobs.size(); ++i) {
    // each job has 4 words
    jobs[i].resize(4);
    for (size_t j = 0; j < 4; ++j) {
      framework::LoD lod{{0, 1}};
      int64_t dict_size = 2073;  // The size of dictionary
      SetupLoDTensor(&jobs[i][j], lod, static_cast<int64_t>(0), dict_size - 1);
      paddle_tensor_feeds[i].push_back(LodTensorToPaddleTensor(&jobs[i][j]));
    }

    // get reference result of each job
    std::vector<paddle::framework::LoDTensor*> ref_feeds;
    std::vector<paddle::framework::LoDTensor*> ref_fetches(1, &refs[i]);
    for (auto& word : jobs[i]) {
      ref_feeds.push_back(&word);
    }
    TestInference<platform::CPUPlace>(config.model_dir, ref_feeds, ref_fetches);
  }

  // create threads and each thread run 1 job
  std::vector<std::thread> threads;
  for (int tid = 0; tid < num_jobs; ++tid) {
    threads.emplace_back([&, tid]() {
      auto predictor = main_predictor->Clone();
      auto& local_inputs = paddle_tensor_feeds[tid];
      std::vector<PaddleTensor> local_outputs;
      ASSERT_TRUE(predictor->Run(local_inputs, &local_outputs));

      // check outputs range
      ASSERT_EQ(local_outputs.size(), 1UL);
      const size_t len = local_outputs[0].data.length();
      float* data = static_cast<float*>(local_outputs[0].data.data());
      for (size_t j = 0; j < len / sizeof(float); ++j) {
        ASSERT_LT(data[j], 1.0);
        ASSERT_GT(data[j], -1.0);
      }

      // check outputs correctness
      float* ref_data = refs[tid].data<float>();
      EXPECT_EQ(refs[tid].numel(), static_cast<int64_t>(len / sizeof(float)));
      for (int i = 0; i < refs[tid].numel(); ++i) {
        EXPECT_NEAR(ref_data[i], data[i], ACC_DIFF);
      }
    });
  }
  for (int i = 0; i < num_jobs; ++i) {
    threads[i].join();
  }
}

void MainThreadsImageClassification(bool use_gpu) {
  constexpr int num_jobs = 4;  // each job run 1 batch
  constexpr int batch_size = 1;
  NativeConfig config = GetConfig();
  config.use_gpu = use_gpu;
  config.model_dir =
      FLAGS_dirname + "/image_classification_resnet.inference.model";

  auto main_predictor = CreatePaddlePredictor<NativeConfig>(config);
  std::vector<framework::LoDTensor> jobs(num_jobs);
  std::vector<std::vector<PaddleTensor>> paddle_tensor_feeds(num_jobs);
  std::vector<framework::LoDTensor> refs(num_jobs);
  for (size_t i = 0; i < jobs.size(); ++i) {
    // prepare inputs
    std::vector<std::vector<int64_t>> feed_target_shapes =
        GetFeedTargetShapes(config.model_dir, /*is_combined*/ false);
    feed_target_shapes[0][0] = batch_size;
    framework::DDim input_dims = framework::make_ddim(feed_target_shapes[0]);
    SetupTensor<float>(&jobs[i], input_dims, 0.f, 1.f);
    paddle_tensor_feeds[i].push_back(LodTensorToPaddleTensor(&jobs[i]));

    // get reference result of each job
    std::vector<framework::LoDTensor*> ref_feeds(1, &jobs[i]);
    std::vector<framework::LoDTensor*> ref_fetches(1, &refs[i]);
    TestInference<platform::CPUPlace>(config.model_dir, ref_feeds, ref_fetches);
  }

  // create threads and each thread run 1 job
  std::vector<std::thread> threads;
  for (int tid = 0; tid < num_jobs; ++tid) {
    threads.emplace_back([&, tid]() {
      auto predictor = main_predictor->Clone();
      auto& local_inputs = paddle_tensor_feeds[tid];
      std::vector<PaddleTensor> local_outputs;
      ASSERT_TRUE(predictor->Run(local_inputs, &local_outputs));

      // check outputs correctness
      ASSERT_EQ(local_outputs.size(), 1UL);
      const size_t len = local_outputs[0].data.length();
      float* data = static_cast<float*>(local_outputs[0].data.data());
      float* ref_data = refs[tid].data<float>();
      EXPECT_EQ((size_t)refs[tid].numel(), len / sizeof(float));
      for (int i = 0; i < refs[tid].numel(); ++i) {
        EXPECT_NEAR(ref_data[i], data[i], ACC_DIFF);
      }
    });
  }
  for (int i = 0; i < num_jobs; ++i) {
    threads[i].join();
  }
}

TEST(inference_api_native, word2vec_cpu) { MainWord2Vec(false /*use_gpu*/); }
TEST(inference_api_native, word2vec_cpu_threads) {
  MainThreadsWord2Vec(false /*use_gpu*/);
}
TEST(inference_api_native, image_classification_cpu) {
  MainThreadsImageClassification(false /*use_gpu*/);
}
TEST(inference_api_native, image_classification_cpu_threads) {
  MainThreadsImageClassification(false /*use_gpu*/);
}

#ifdef PADDLE_WITH_CUDA
TEST(inference_api_native, word2vec_gpu) { MainWord2Vec(true /*use_gpu*/); }
TEST(inference_api_native, word2vec_gpu_threads) {
  MainThreadsWord2Vec(true /*use_gpu*/);
}
TEST(inference_api_native, image_classification_gpu) {
  MainThreadsImageClassification(true /*use_gpu*/);
}
TEST(inference_api_native, image_classification_gpu_threads) {
  MainThreadsImageClassification(true /*use_gpu*/);
}

#endif

}  // namespace paddle
<|endoftext|>


<commit_before>#include <microscopes/common/group_manager.hpp>

using namespace std;
using namespace microscopes::common;

typedef fixed_group_manager<size_t> fixed_group;
typedef group_manager<size_t> group;

static inline bool
almost_eq(float a, float b)
{
  return fabs(a - b) <= 1e-5;
}

template <typename T>
static void assert_vectors_equal(const vector<T> &as, const vector<T> &bs)
{
  MICROSCOPES_CHECK(as.size() == bs.size(), "size");
  for (size_t i = 0; i < as.size(); i++)
    MICROSCOPES_CHECK(as[i] == bs[i], "element");
}

static void
test_fixed_serialization()
{
  const size_t k = 3;
  fixed_group fg(10, k);

  for (size_t i = 0; i < k; i++)
    fg.get_hp_mutator("alphas").set<float>(1.+float(i), i);

  const vector<ssize_t> assignment_vec({
      -1, 2, 1, 0, 0, 1, 2, -1, -1, 0
  });
  for (size_t i = 0; i < assignment_vec.size(); i++) {
    if (assignment_vec[i] == -1)
      continue;
    fg.add_value(assignment_vec[i], i)++;
  }

  const auto serialized = fg.serialize([](size_t i) {
    return to_string(i);
  });

  fixed_group fg1(serialized, [](const string &s) {
      return strtoul(s.c_str(), nullptr, 10);
  });

  for (size_t i = 0; i < k; i++)
    MICROSCOPES_CHECK(
        almost_eq(
          fg.get_hp_mutator("alphas").accessor().get<float>(i),
          fg1.get_hp_mutator("alphas").accessor().get<float>(i)),
      "did not save alphas properly");

  assert_vectors_equal(fg.assignments(), fg1.assignments());
  MICROSCOPES_CHECK(fg.ngroups() == fg1.ngroups(), "ngroups");
  for (size_t i = 0; i < fg.ngroups(); i++)
    MICROSCOPES_CHECK(fg.group(i) == fg1.group(i), "group count/data");
}

static void
test_serialization()
{
  group g(10);

  g.get_hp_mutator("alpha").set<float>(2.0, 0);

  const vector<ssize_t> assignment_vec({
      -1, 2, 1, 0, 6, 1, 2, -1, -1, 5
  });
  for (size_t i = 0; i < 7; i++)
    g.create_group();
  g.delete_group(3);
  for (size_t i = 0; i < assignment_vec.size(); i++) {
    if (assignment_vec[i] == -1)
      continue;
    g.add_value(assignment_vec[i], i)++;
  }

  const auto serialized = g.serialize([](size_t i) {
    return to_string(i);
  });

  group g1(serialized, [](const string &s) {
      return strtoul(s.c_str(), nullptr, 10);
  });

  MICROSCOPES_CHECK(
      almost_eq(
        g.get_hp_mutator("alpha").accessor().get<float>(0),
        g1.get_hp_mutator("alpha").accessor().get<float>(0)),
    "did not save alpha properly");

  assert_vectors_equal(g.assignments(), g1.assignments());
  MICROSCOPES_CHECK(g.ngroups() == g1.ngroups(), "ngroups");
  for (auto gid : g.groups())
    MICROSCOPES_CHECK(g.group(gid) == g1.group(gid), "group count/data");
}

int
main(void)
{
  test_fixed_serialization();
  test_serialization();
  return 0;
}
<commit_msg>Remove fixed references from test_group_manager.cpp<commit_after>#include <microscopes/common/group_manager.hpp>

using namespace std;
using namespace microscopes::common;

typedef group_manager<size_t> group;

static inline bool
almost_eq(float a, float b)
{
  return fabs(a - b) <= 1e-5;
}

template <typename T>
static void assert_vectors_equal(const vector<T> &as, const vector<T> &bs)
{
  MICROSCOPES_CHECK(as.size() == bs.size(), "size");
  for (size_t i = 0; i < as.size(); i++)
    MICROSCOPES_CHECK(as[i] == bs[i], "element");
}

static void
test_serialization()
{
  group g(10);

  g.get_hp_mutator("alpha").set<float>(2.0, 0);

  const vector<ssize_t> assignment_vec({
      -1, 2, 1, 0, 6, 1, 2, -1, -1, 5
  });
  for (size_t i = 0; i < 7; i++)
    g.create_group();
  g.delete_group(3);
  for (size_t i = 0; i < assignment_vec.size(); i++) {
    if (assignment_vec[i] == -1)
      continue;
    g.add_value(assignment_vec[i], i)++;
  }

  const auto serialized = g.serialize([](size_t i) {
    return to_string(i);
  });

  group g1(serialized, [](const string &s) {
      return strtoul(s.c_str(), nullptr, 10);
  });

  MICROSCOPES_CHECK(
      almost_eq(
        g.get_hp_mutator("alpha").accessor().get<float>(0),
        g1.get_hp_mutator("alpha").accessor().get<float>(0)),
    "did not save alpha properly");

  assert_vectors_equal(g.assignments(), g1.assignments());
  MICROSCOPES_CHECK(g.ngroups() == g1.ngroups(), "ngroups");
  for (auto gid : g.groups())
    MICROSCOPES_CHECK(g.group(gid) == g1.group(gid), "group count/data");
}

int
main(void)
{
  test_serialization();
  return 0;
}
<|endoftext|>


<commit_before>#include "generated_fused_sparse_resnet_block.o.h"

#include "Halide.h"
#include <tiramisu/utils.h>
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <algorithm>
#include "configure.h"
// Original version by: Kyle Spafford Adapted for CSR format
void initRandomWeights(float* fin_values, int* filter_idx, int* filter_finptr, const int n, const int KK, const int fin_size, const int fout_size, int seed)
{
    int nnzAssigned = 0;
    // Figure out the probability that a nonzero should be assigned to a given
    // spot in the matrix
    int total_num_entries = KK * KK * fin_size * fout_size;
    double prob = (double)n / ((double) total_num_entries);

    // Seed random number generator
    srand(seed);

    // Randomly decide whether entry gets a value, but ensure n values
    // are assigned
    int fillRemaining = 0;

    // We order the weights in the values array such that we do blocking over FIN
    for (int fout = 0; fout < fout_size; fout++)
    {
      filter_finptr[fout] = nnzAssigned;
      for (int fin_b = 0; fin_b < fin_size/FIN_BL; fin_b++)
      {
        for (int ky = 0; ky < KK; ky++)
        {
          for (int kx = 0; kx < KK; kx++)
          {
            for (int ffin = 0; ffin<FIN_BL; ffin++){
              int numEntriesLeft = total_num_entries - ((fout * KK * KK * fin_size) + (fin_b * KK * KK * FIN_BL) + (ky * KK * FIN_BL) + kx * FIN_BL + ffin);
              int needToAssign   = n - nnzAssigned;
              if (numEntriesLeft <= needToAssign) {
                fillRemaining = 1;
              }
              if ((nnzAssigned < n && ((double) rand() / (RAND_MAX + 1.0)) <= prob) || fillRemaining)
              {
                filter_idx[nnzAssigned] = (fin_b * FIN_BL + ffin) * (N + 2) * (N + 2) + ky * (N + 2) + kx;
                fin_values[nnzAssigned] = ((float)(rand()%256 - 128)) / 127.f;
                nnzAssigned++;
              }
            }
          }
        }
      }
    }
    filter_finptr[fout_size] = nnzAssigned;
    assert(nnzAssigned == n);
}

int generateCSRWeights(float **filter_values, float density, int **filter_idx, int** filter_finptr, int KK, int fin_size, int fout_size, int seed)
{
  int nNonzero = KK * KK * fin_size * fout_size * density;
  *filter_values = (float *) malloc(nNonzero * sizeof(float));
  *filter_idx = (int *) malloc(nNonzero * sizeof(int));
  *filter_finptr = (int *) malloc((fout_size + 1) * sizeof(int));
  initRandomWeights(*filter_values, *filter_idx, *filter_finptr, nNonzero, KK, fin_size, fout_size, seed);
  return nNonzero;
}

void importCSRFromFile(std::string filename, float** values, int** rowptr, int** colidx, int* FOUT, int* FIN, int* KK, int* NNZ, int* n){
    std::ifstream cFile (filename);

    if (cFile.is_open())
    {
        std::string line;
        // Get first line containing conv size

        getline(cFile, line);
        std::string delimiter = ",";

        size_t pos = 0;
        std::string token;
        // FOUT
        pos = line.find(delimiter);
        token = line.substr(0, pos);
        *FOUT = std::stoi(token);
        line.erase(0, pos + delimiter.length());

        // FIN
        pos = line.find(delimiter);
        token = line.substr(0, pos);
        *FIN = std::stoi(token);
        line.erase(0, pos + delimiter.length());

        // K
        pos = line.find(delimiter);
        token = line.substr(0, pos);
        *KK = std::stoi(token);
        line.erase(0, pos + delimiter.length());

        // NNZ
        pos = line.find(delimiter);
        token = line.substr(0, pos);
        *n = std::stoi(token);
        line.erase(0, pos + delimiter.length());

        // NNZ
        pos = line.find(delimiter);
        token = line.substr(0, pos);
        *NNZ = std::stoi(token);
        line.erase(0, pos + delimiter.length());

        *values = (float*)malloc((*NNZ) * sizeof(float));
        *rowptr = (int*)malloc(((*FOUT) + 1) * sizeof(int));
        *colidx = (int*)malloc((*NNZ) * sizeof(int));
        int i = 0;
        getline(cFile, line);
        while(getline(cFile, line)){
            if(line[0]=='/' || line.empty())
              break;
            (*values)[i] = std::stof(line);
            i++;
        }
        assert(i == *NNZ);

        i = 0;
        while(getline(cFile, line)){
            if(line[0]=='/' || line.empty())
              break;
            (*rowptr)[i] = std::stoi(line);
            i++;
        }
        assert(i == (*FOUT + 1));

        i = 0;
        while(getline(cFile, line)){
            if(line[0]=='/' || line.empty())
              break;
            (*colidx)[i] = std::stoi(line);
            i++;
        }
        assert(i == *NNZ);
    }
    else {
        std::cerr << "Couldn't open config file for reading.\n";
    }
}

int main(int, char **)
{
  std::vector<double> duration_vector;
  double start, end;

  // ---------------------------------------------------------------------
  // ---------------------------------------------------------------------
  // ---------------------------------------------------------------------
  std::string filename = "resnet_10.csr";
  std::string filename2 = "resnet_10.csr";

  float *filter_values;
  int *filter_idx;
  int *filter_finptr;

  int FNNZ;
  int used_FOUT;
  int used_FIN;
  int used_K;
  int n;
  if (IMPORT_CSR_FROM_FILE)
    importCSRFromFile(filename, &filter_values, &filter_finptr, &filter_idx, &used_FOUT, &used_FIN, &used_K, &FNNZ, &n);
  else{
    used_FOUT = FOut;
    used_FIN = FIn;
    used_K = K;
    n = N;
    FNNZ = generateCSRWeights(&filter_values, WEIGHTS_DENSITY, &filter_idx, &filter_finptr, K, FIn, FOut, 2);
  }
  printf("Layer 1 Density : %.2f %%. Weights imported from %s\n", ((float)FNNZ / (FOut * FIn * K * K))*100, filename.c_str());

  // Assertions to ensure that the generated tiramisu code has the right parameters
  // because we are defining the parameters in the configure.h files to get specialized fast code
  assert((used_FOUT == FOut) && ("FOut parameter specified in configure.h doesn't match the csr weights file's FOUT parameter."));
  assert((used_FIN == FIn) && ("FIn parameter specified in configure.h doesn't match the csr weights file's FIn parameter"));
  assert((used_K == K) && ("K parameter specified in configure.h doesn't match the csr weights file's K parameter"));
  assert((n == N) && ("N parameter specified in configure.h doesn't match the csr weights file's N parameter"));

  Halide::Buffer<int> b_SIZES(2);
  b_SIZES(0) = FNNZ;
  Halide::Buffer<float> b_input((N+2) * (N+2) * FIn, BATCH_SIZE);

  Halide::Buffer<float> b_filter_values(filter_values, FNNZ);
  Halide::Buffer<int> b_filter_idx(filter_idx, FNNZ);
  Halide::Buffer<int> b_filter_finptr(filter_finptr, FOut + 1);

  Halide::Buffer<float> b_bias(FOut);
  Halide::Buffer<float> b_bn_scale(FOut);
  Halide::Buffer<float> b_bn_shift(FOut);
  Halide::Buffer<float> b_bn_mean(FOut);
  Halide::Buffer<float> b_bn_variance(FOut);

  Halide::Buffer<float> b_conv1_result(N + 2, N + 2, FOut, BATCH_SIZE);

  // Second convolution
  float *filter_values2;
  int *filter_idx2;
  int *filter_finptr2;

  int FNNZ2;
  if (IMPORT_CSR_FROM_FILE)
    importCSRFromFile(filename2, &filter_values2, &filter_finptr2, &filter_idx2, &used_FOUT, &used_FIN, &used_K, &FNNZ2, &n);
  else{
    used_FOUT = FOut;
    used_FIN = FOut;
    used_K = K;
    n = N;
    FNNZ2 = generateCSRWeights(&filter_values2, WEIGHTS_DENSITY, &filter_idx2, &filter_finptr2, K, FOut, FOut, 5);
  }
  printf("Layer 2 Density : %.2f %%. Weights imported from %s\n", ((float)FNNZ2 / (FOut * FOut * K * K))*100, filename2.c_str());
  // Assertions to ensure that the generated tiramisu code has the right parameters
  // because we are defining the parameters in the configure.h files to get specialized fast code
  assert((used_FOUT == FOut) && ("FOut parameter specified in configure.h doesn't match the csr weights file's FOUT parameter."));
  assert((used_FIN == FOut) && ("FOut parameter specified in configure.h doesn't match the csr weights file's FIn parameter"));
  assert((used_K == K) && ("K parameter specified in configure.h doesn't match the csr weights file's K parameter"));
  assert((n == N) && ("N parameter specified in configure.h doesn't match the csr weights file's N parameter"));

  b_SIZES(1) = FNNZ2;
  Halide::Buffer<float> b_filter_values2(filter_values2, FNNZ2);
  Halide::Buffer<int> b_filter_idx2(filter_idx2, FNNZ2);
  Halide::Buffer<int> b_filter_finptr2(filter_finptr2, FOut + 1);

  Halide::Buffer<float> b_bias2(FOut);
  Halide::Buffer<float> b_bn2_scale(FOut);
  Halide::Buffer<float> b_bn2_shift(FOut);
  Halide::Buffer<float> b_bn2_mean(FOut);
  Halide::Buffer<float> b_bn2_variance(FOut);

  Halide::Buffer<float> b_result(N, N, FOut, BATCH_SIZE);
  srand(3);
  // First convolution
  for (int n=0; n < BATCH_SIZE; ++n)
    for (int z=0; z < FIn; ++z)
      for (int y=0; y < N+2; ++y)
        for (int x=0; x < N+2; ++x)
            b_input(x + y * (N + 2) + z* (N + 2) * (N + 2), n) = ((float)(rand()%256 - 128)) / 127.f;

  for (int q=0; q<FOut; q++)
    b_bias(q) = ((float)(rand()%256 - 128)) / 127.f;

  for (int q=0; q<FOut; q++){
    b_bn_scale(q) = 1.f;
    b_bn_shift(q) = 0.f;
    b_bn_mean(q) = ((float)(rand()%256)) / 127.f;
    b_bn_variance(q) = ((float)(rand()%256)) / 127.f;
  }

  // Second convolution
  for (int q=0; q<FOut; q++)
    b_bias2(q) = ((float)(rand()%256 - 128)) / 127.f;

  for (int q=0; q<FOut; q++){
    b_bn2_scale(q) = 1.f;
    b_bn2_shift(q) = 0.f;
    b_bn2_mean(q) = ((float)(rand()%256)) / 127.f;
    b_bn2_variance(q) = ((float)(rand()%256)) / 127.f;
  }

  std::cout << "Buffers Initialized" << std::endl;
  for (int i = 0; i < NB_TESTS; i++)
  {
    start = rtclock();
		fused_sparse_resnet_block(
      b_SIZES.raw_buffer(),
      b_input.raw_buffer(),
        b_filter_values.raw_buffer(),
        b_filter_idx.raw_buffer(),
        b_filter_finptr.raw_buffer(),
        b_bias.raw_buffer(),
        b_bn_scale.raw_buffer(),
        b_bn_shift.raw_buffer(),
        b_bn_mean.raw_buffer(),
        b_bn_variance.raw_buffer(),
      b_conv1_result.raw_buffer(),
        b_filter_values2.raw_buffer(),
        b_filter_idx2.raw_buffer(),
        b_filter_finptr2.raw_buffer(),
        b_bias2.raw_buffer(),
        b_bn2_scale.raw_buffer(),
        b_bn2_shift.raw_buffer(),
        b_bn2_mean.raw_buffer(),
        b_bn2_variance.raw_buffer(),
      b_result.raw_buffer()
    );
    end = rtclock();
    duration_vector.push_back((end - start) * 1000);
  }

  if (SHOW_OUTPUT)
    print_buffer(b_result);

  print_time("performance_CPU.csv", "Sparse ResNet Block",
             {"Tiramisu"},
             {median(duration_vector)});

  if (WRITE_RESULT_TO_FILE){
    // Write results to file
    FILE* f = fopen("tiramisu_result.txt", "w");
    if (f == NULL) {
      printf("Error creating tiramisu_result.txt.\n");
      return 0;
    }

    for(int b=0; b<BATCH_SIZE; b++)
      for(int fout=0; fout<FOut; fout++)
        for(int y=0; y<N; y++)
          for(int x=0; x<N; x++)
            fprintf(f, "%.17g\n", b_result(x, y, fout, b));

    fclose(f);
  }

  if (CHECK_CORRECTNESS){
    // Compare results with Intel MKL
    std::ifstream mkldnn_result("mkl_result.txt");
    double tmp;
    long nb_correct = 0;

    for(int b=0; b<BATCH_SIZE; b++)
      for(int fout=0; fout<FOut; fout++)
        for(int y=0; y<N; y++)
          for(int x=0; x< N; x++){
            mkldnn_result >> tmp;
            if (std::abs(b_result(x, y, fout, b) - tmp) <= 0.002)
              nb_correct++;
          }

    std::cout << "\n\t\tPercentage of correctness " << 100*(((double)nb_correct)/(BATCH_SIZE * FOut * N * N)) << "%" << std::endl << std::endl;
  }

  free(filter_idx);
  free(filter_values);
  free(filter_finptr);
  return 0;
}
<commit_msg>Fix formatting<commit_after>#include "generated_fused_sparse_resnet_block.o.h"

#include "Halide.h"
#include <tiramisu/utils.h>
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <algorithm>
#include "configure.h"
// Original version by: Kyle Spafford Adapted for CSR format
void initRandomWeights(float* fin_values, int* filter_idx, int* filter_finptr, const int n, const int KK, const int fin_size, const int fout_size, int seed)
{
    int nnzAssigned = 0;
    // Figure out the probability that a nonzero should be assigned to a given
    // spot in the matrix
    int total_num_entries = KK * KK * fin_size * fout_size;
    double prob = (double)n / ((double) total_num_entries);

    // Seed random number generator
    srand(seed);

    // Randomly decide whether entry gets a value, but ensure n values
    // are assigned
    int fillRemaining = 0;

    // We order the weights in the values array such that we do blocking over FIN
    for (int fout = 0; fout < fout_size; fout++)
    {
      filter_finptr[fout] = nnzAssigned;
      for (int fin_b = 0; fin_b < fin_size/FIN_BL; fin_b++)
      {
        for (int ky = 0; ky < KK; ky++)
        {
          for (int kx = 0; kx < KK; kx++)
          {
            for (int ffin = 0; ffin<FIN_BL; ffin++){
              int numEntriesLeft = total_num_entries - ((fout * KK * KK * fin_size) + (fin_b * KK * KK * FIN_BL) + (ky * KK * FIN_BL) + kx * FIN_BL + ffin);
              int needToAssign   = n - nnzAssigned;
              if (numEntriesLeft <= needToAssign) {
                fillRemaining = 1;
              }
              if ((nnzAssigned < n && ((double) rand() / (RAND_MAX + 1.0)) <= prob) || fillRemaining)
              {
                filter_idx[nnzAssigned] = (fin_b * FIN_BL + ffin) * (N + 2) * (N + 2) + ky * (N + 2) + kx;
                fin_values[nnzAssigned] = ((float)(rand()%256 - 128)) / 127.f;
                nnzAssigned++;
              }
            }
          }
        }
      }
    }
    filter_finptr[fout_size] = nnzAssigned;
    assert(nnzAssigned == n);
}

int generateCSRWeights(float **filter_values, float density, int **filter_idx, int** filter_finptr, int KK, int fin_size, int fout_size, int seed)
{
  int nNonzero = KK * KK * fin_size * fout_size * density;
  *filter_values = (float *) malloc(nNonzero * sizeof(float));
  *filter_idx = (int *) malloc(nNonzero * sizeof(int));
  *filter_finptr = (int *) malloc((fout_size + 1) * sizeof(int));
  initRandomWeights(*filter_values, *filter_idx, *filter_finptr, nNonzero, KK, fin_size, fout_size, seed);
  return nNonzero;
}

void importCSRFromFile(std::string filename, float** values, int** rowptr, int** colidx, int* FOUT, int* FIN, int* KK, int* NNZ, int* n){
    std::ifstream cFile (filename);

    if (cFile.is_open())
    {
        std::string line;
        // Get first line containing conv size

        getline(cFile, line);
        std::string delimiter = ",";

        size_t pos = 0;
        std::string token;
        // FOUT
        pos = line.find(delimiter);
        token = line.substr(0, pos);
        *FOUT = std::stoi(token);
        line.erase(0, pos + delimiter.length());

        // FIN
        pos = line.find(delimiter);
        token = line.substr(0, pos);
        *FIN = std::stoi(token);
        line.erase(0, pos + delimiter.length());

        // K
        pos = line.find(delimiter);
        token = line.substr(0, pos);
        *KK = std::stoi(token);
        line.erase(0, pos + delimiter.length());

        // NNZ
        pos = line.find(delimiter);
        token = line.substr(0, pos);
        *n = std::stoi(token);
        line.erase(0, pos + delimiter.length());

        // NNZ
        pos = line.find(delimiter);
        token = line.substr(0, pos);
        *NNZ = std::stoi(token);
        line.erase(0, pos + delimiter.length());

        *values = (float*)malloc((*NNZ) * sizeof(float));
        *rowptr = (int*)malloc(((*FOUT) + 1) * sizeof(int));
        *colidx = (int*)malloc((*NNZ) * sizeof(int));
        int i = 0;
        getline(cFile, line);
        while(getline(cFile, line)){
            if(line[0]=='/' || line.empty())
              break;
            (*values)[i] = std::stof(line);
            i++;
        }
        assert(i == *NNZ);

        i = 0;
        while(getline(cFile, line)){
            if(line[0]=='/' || line.empty())
              break;
            (*rowptr)[i] = std::stoi(line);
            i++;
        }
        assert(i == (*FOUT + 1));

        i = 0;
        while(getline(cFile, line)){
            if(line[0]=='/' || line.empty())
              break;
            (*colidx)[i] = std::stoi(line);
            i++;
        }
        assert(i == *NNZ);
    }
    else {
        std::cerr << "Couldn't open config file for reading.\n";
    }
}

int main(int, char **)
{
  std::vector<double> duration_vector;
  double start, end;

  // ---------------------------------------------------------------------
  // ---------------------------------------------------------------------
  // ---------------------------------------------------------------------
  std::string filename = "resnet_10.csr";
  std::string filename2 = "resnet_10.csr";

  float *filter_values;
  int *filter_idx;
  int *filter_finptr;

  int FNNZ;
  int used_FOUT;
  int used_FIN;
  int used_K;
  int n;
  if (IMPORT_CSR_FROM_FILE)
    importCSRFromFile(filename, &filter_values, &filter_finptr, &filter_idx, &used_FOUT, &used_FIN, &used_K, &FNNZ, &n);
  else{
    used_FOUT = FOut;
    used_FIN = FIn;
    used_K = K;
    n = N;
    FNNZ = generateCSRWeights(&filter_values, WEIGHTS_DENSITY, &filter_idx, &filter_finptr, K, FIn, FOut, 2);
  }
  printf("Layer 1 Density : %.2f %%. Weights imported from %s\n", ((float)FNNZ / (FOut * FIn * K * K))*100, filename.c_str());

  // Assertions to ensure that the generated tiramisu code has the right parameters
  // because we are defining the parameters in the configure.h files to get specialized fast code
  assert((used_FOUT == FOut) && ("FOut parameter specified in configure.h doesn't match the csr weights file's FOUT parameter."));
  assert((used_FIN == FIn) && ("FIn parameter specified in configure.h doesn't match the csr weights file's FIn parameter"));
  assert((used_K == K) && ("K parameter specified in configure.h doesn't match the csr weights file's K parameter"));
  assert((n == N) && ("N parameter specified in configure.h doesn't match the csr weights file's N parameter"));

  Halide::Buffer<int> b_SIZES(2);
  b_SIZES(0) = FNNZ;
  Halide::Buffer<float> b_input((N+2) * (N+2) * FIn, BATCH_SIZE);

  Halide::Buffer<float> b_filter_values(filter_values, FNNZ);
  Halide::Buffer<int> b_filter_idx(filter_idx, FNNZ);
  Halide::Buffer<int> b_filter_finptr(filter_finptr, FOut + 1);

  Halide::Buffer<float> b_bias(FOut);
  Halide::Buffer<float> b_bn_scale(FOut);
  Halide::Buffer<float> b_bn_shift(FOut);
  Halide::Buffer<float> b_bn_mean(FOut);
  Halide::Buffer<float> b_bn_variance(FOut);

  Halide::Buffer<float> b_conv1_result(N + 2, N + 2, FOut, BATCH_SIZE);

  // Second convolution
  float *filter_values2;
  int *filter_idx2;
  int *filter_finptr2;

  int FNNZ2;
  if (IMPORT_CSR_FROM_FILE)
    importCSRFromFile(filename2, &filter_values2, &filter_finptr2, &filter_idx2, &used_FOUT, &used_FIN, &used_K, &FNNZ2, &n);
  else{
    used_FOUT = FOut;
    used_FIN = FOut;
    used_K = K;
    n = N;
    FNNZ2 = generateCSRWeights(&filter_values2, WEIGHTS_DENSITY, &filter_idx2, &filter_finptr2, K, FOut, FOut, 5);
  }
  printf("Layer 2 Density : %.2f %%. Weights imported from %s\n", ((float)FNNZ2 / (FOut * FOut * K * K))*100, filename2.c_str());
  // Assertions to ensure that the generated tiramisu code has the right parameters
  // because we are defining the parameters in the configure.h files to get specialized fast code
  assert((used_FOUT == FOut) && ("FOut parameter specified in configure.h doesn't match the csr weights file's FOUT parameter."));
  assert((used_FIN == FOut) && ("FOut parameter specified in configure.h doesn't match the csr weights file's FIn parameter"));
  assert((used_K == K) && ("K parameter specified in configure.h doesn't match the csr weights file's K parameter"));
  assert((n == N) && ("N parameter specified in configure.h doesn't match the csr weights file's N parameter"));

  b_SIZES(1) = FNNZ2;
  Halide::Buffer<float> b_filter_values2(filter_values2, FNNZ2);
  Halide::Buffer<int> b_filter_idx2(filter_idx2, FNNZ2);
  Halide::Buffer<int> b_filter_finptr2(filter_finptr2, FOut + 1);

  Halide::Buffer<float> b_bias2(FOut);
  Halide::Buffer<float> b_bn2_scale(FOut);
  Halide::Buffer<float> b_bn2_shift(FOut);
  Halide::Buffer<float> b_bn2_mean(FOut);
  Halide::Buffer<float> b_bn2_variance(FOut);

  Halide::Buffer<float> b_result(N, N, FOut, BATCH_SIZE);
  srand(3);
  // First convolution
  for (int n=0; n < BATCH_SIZE; ++n)
    for (int z=0; z < FIn; ++z)
      for (int y=0; y < N+2; ++y)
        for (int x=0; x < N+2; ++x)
            b_input(x + y * (N + 2) + z* (N + 2) * (N + 2), n) = ((float)(rand()%256 - 128)) / 127.f;

  for (int q=0; q<FOut; q++)
    b_bias(q) = ((float)(rand()%256 - 128)) / 127.f;

  for (int q=0; q<FOut; q++){
    b_bn_scale(q) = 1.f;
    b_bn_shift(q) = 0.f;
    b_bn_mean(q) = ((float)(rand()%256)) / 127.f;
    b_bn_variance(q) = ((float)(rand()%256)) / 127.f;
  }

  // Second convolution
  for (int q=0; q<FOut; q++)
    b_bias2(q) = ((float)(rand()%256 - 128)) / 127.f;

  for (int q=0; q<FOut; q++){
    b_bn2_scale(q) = 1.f;
    b_bn2_shift(q) = 0.f;
    b_bn2_mean(q) = ((float)(rand()%256)) / 127.f;
    b_bn2_variance(q) = ((float)(rand()%256)) / 127.f;
  }

  std::cout << "Buffers Initialized" << std::endl;
  for (int i = 0; i < NB_TESTS; i++)
  {
    start = rtclock();
		fused_sparse_resnet_block(
      b_SIZES.raw_buffer(),
      b_input.raw_buffer(),
        b_filter_values.raw_buffer(),
        b_filter_idx.raw_buffer(),
        b_filter_finptr.raw_buffer(),
        b_bias.raw_buffer(),
        b_bn_scale.raw_buffer(),
        b_bn_shift.raw_buffer(),
        b_bn_mean.raw_buffer(),
        b_bn_variance.raw_buffer(),
      b_conv1_result.raw_buffer(),
        b_filter_values2.raw_buffer(),
        b_filter_idx2.raw_buffer(),
        b_filter_finptr2.raw_buffer(),
        b_bias2.raw_buffer(),
        b_bn2_scale.raw_buffer(),
        b_bn2_shift.raw_buffer(),
        b_bn2_mean.raw_buffer(),
        b_bn2_variance.raw_buffer(),
      b_result.raw_buffer()
    );
    end = rtclock();
    duration_vector.push_back((end - start) * 1000);
  }

  if (SHOW_OUTPUT)
    print_buffer(b_result);

  print_time("performance_CPU.csv", "Sparse ResNet Block",
             {"Tiramisu"},
             {median(duration_vector)});

  if (WRITE_RESULT_TO_FILE){
    // Write results to file
    FILE* f = fopen("tiramisu_result.txt", "w");
    if (f == NULL) {
      printf("Error creating tiramisu_result.txt.\n");
      return 0;
    }

    for(int b=0; b<BATCH_SIZE; b++)
      for(int fout=0; fout<FOut; fout++)
        for(int y=0; y<N; y++)
          for(int x=0; x<N; x++)
            fprintf(f, "%.17g\n", b_result(x, y, fout, b));

    fclose(f);
  }

  if (CHECK_CORRECTNESS){
    // Compare results with Intel MKL
    std::ifstream mkldnn_result("mkl_result.txt");
    double tmp;
    long nb_correct = 0;

    for(int b=0; b<BATCH_SIZE; b++)
      for(int fout=0; fout<FOut; fout++)
        for(int y=0; y<N; y++)
          for(int x=0; x< N; x++){
            mkldnn_result >> tmp;
            if (std::abs(b_result(x, y, fout, b) - tmp) <= 0.002)
              nb_correct++;
          }

    std::cout << "\n\t\tPercentage of correctness " << 100*(((double)nb_correct)/(BATCH_SIZE * FOut * N * N)) << "%" << std::endl << std::endl;
  }

  free(filter_idx);
  free(filter_values);
  free(filter_finptr);
  return 0;
}
<|endoftext|>


<commit_before>#include "OutputProbes.h"
#include <gtest/gtest.h>

using namespace ibpm;

namespace {

double tol = 1e-14;

class OutputProbesTest : public testing::Test {
protected:
    OutputProbesTest( ) :
        _nx(8),
        _ny(12),
        _ngrid(3),
        _xLength(2),
        _yLength(_xLength * _ny/_nx),
        _xOffset(-1),
        _yOffset(-3),
        _dx(_xLength/_nx),
        _filename("testOutputProbes.probe"),
        _grid(_nx, _ny, _ngrid, _xLength, _xOffset, _yOffset),
		_flagInitialization(false),
		_probe(_filename, _grid) {
		}

    virtual ~OutputProbesTest() {}

    int _nx;
    int _ny;
    int _ngrid;
    double _xLength;
    double _yLength;
    double _xOffset;
    double _yOffset;
    double _dx;
	string _filename;
	Grid _grid;
	int _lev;
	int _numProbes;
	int _dimen;
	bool _flagInitialization;
	Array::Array2<int> _probePositions;
	OutputProbes _probe;
};

TEST_F(OutputProbesTest, TestgetProbeInfoFunctions){
// test getNumProbes, getProbeIndexX, getProbeIndexY, addProbebyIndex, addProbebyPosition
	int i = 4; 	int j = 3;  // probe 1
	int ii = 6; int jj = 8; // probe 2
	int lev = 0;
	OutputProbes probe(_filename, _grid);
	EXPECT_DOUBLE_EQ( 0, probe.getNumProbes() );
	probe.addProbeByIndex( i , j );
	EXPECT_DOUBLE_EQ( 1, probe.getNumProbes() );
	probe.addProbeByIndex( ii, jj );
	EXPECT_DOUBLE_EQ( 2, probe.getNumProbes() );
	EXPECT_DOUBLE_EQ( i, probe.getProbeIndexX(1) );
	EXPECT_DOUBLE_EQ( j, probe.getProbeIndexY(1) );
	EXPECT_DOUBLE_EQ( ii, probe.getProbeIndexX(2) );
	EXPECT_DOUBLE_EQ( jj, probe.getProbeIndexY(2) );
	EXPECT_DOUBLE_EQ( _grid.getXEdge(lev, ii), probe.getProbeCoordX(2) );
	EXPECT_DOUBLE_EQ( _grid.getYEdge(lev, jj), probe.getProbeCoordY(2) );
	probe.addProbeByPosition( _grid.getXEdge(lev, ii), _grid.getYEdge(lev, jj) );
	EXPECT_DOUBLE_EQ( 3, probe.getNumProbes() );
	EXPECT_DOUBLE_EQ( ii, probe.getProbeIndexX(3) );
	EXPECT_DOUBLE_EQ( jj, probe.getProbeIndexY(3) );
}

}  // namespace
<commit_msg>Deleted ibSolver branch.  Check out an earlier revision to access that data.<commit_after>#include "OutputProbes.h"
#include <gtest/gtest.h>

using namespace ibpm;

namespace {

double tol = 1e-14;

class OutputProbesTest : public testing::Test {
protected:
    OutputProbesTest( ) :
        _nx(8),
        _ny(12),
        _ngrid(3),
        _xLength(2),
        _yLength(_xLength * _ny/_nx),
        _xOffset(-1),
        _yOffset(-3),
        _dx(_xLength/_nx),
        _filename("testOutputProbes.probe"),
        _grid(_nx, _ny, _ngrid, _xLength, _xOffset, _yOffset),
		_flagInitialization(false),
		_probe(_filename, _grid) {
		}

    virtual ~OutputProbesTest() { }

    int _nx;
    int _ny;
    int _ngrid;
    double _xLength;
    double _yLength;
    double _xOffset;
    double _yOffset;
    double _dx;
	string _filename;
	Grid _grid;
	int _lev;
	int _numProbes;
	int _dimen;
	bool _flagInitialization;
	Array::Array2<int> _probePositions;
	OutputProbes _probe;
};

TEST_F(OutputProbesTest, TestgetProbeInfoFunctions){
// test getNumProbes, getProbeIndexX, getProbeIndexY, addProbebyIndex, addProbebyPosition
	int i = 4; 	int j = 3;  // probe 1
	int ii = 6; int jj = 8; // probe 2
	int lev = 0;
	OutputProbes probe(_filename, _grid);
	EXPECT_DOUBLE_EQ( 0, probe.getNumProbes() );
	probe.addProbeByIndex( i , j );
	EXPECT_DOUBLE_EQ( 1, probe.getNumProbes() );
	probe.addProbeByIndex( ii, jj );
	EXPECT_DOUBLE_EQ( 2, probe.getNumProbes() );
	EXPECT_DOUBLE_EQ( i, probe.getProbeIndexX(1) );
	EXPECT_DOUBLE_EQ( j, probe.getProbeIndexY(1) );
	EXPECT_DOUBLE_EQ( ii, probe.getProbeIndexX(2) );
	EXPECT_DOUBLE_EQ( jj, probe.getProbeIndexY(2) );
	EXPECT_DOUBLE_EQ( _grid.getXEdge(lev, ii), probe.getProbeCoordX(2) );
	EXPECT_DOUBLE_EQ( _grid.getYEdge(lev, jj), probe.getProbeCoordY(2) );
	probe.addProbeByPosition( _grid.getXEdge(lev, ii), _grid.getYEdge(lev, jj) );
	EXPECT_DOUBLE_EQ( 3, probe.getNumProbes() );
	EXPECT_DOUBLE_EQ( ii, probe.getProbeIndexX(3) );
	EXPECT_DOUBLE_EQ( jj, probe.getProbeIndexY(3) );
}

}  // namespace
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
// The Loki Library
// Copyright (c) 2006 Peter Kmmel
// Permission to use, copy, modify, distribute and sell this software for any
//     purpose is hereby granted without fee, provided that the above copyright
//     notice appear in all copies and that both that copyright notice and this
//     permission notice appear in supporting documentation.
// The author makes no representations about the
//     suitability of this software for any purpose. It is provided "as is"
//     without express or implied warranty.
////////////////////////////////////////////////////////////////////////////////

// $Header:

#include <loki/ScopeGuard.h>
#include <vector>
#include <string>
#include <iostream>

void Decrement(int& x)
{
	--x;
}

struct UserDatabase
{
    void AddFriend(const std::string&, const std::string&)
    {
        throw 55;
    }
};

class User
{
public:
    User(UserDatabase* db) : fCount(0), pDB_(db)
	{}

    std::string GetName();

    void AddFriend(User& newFriend);
    void AddFriendGuarded(User& newFriend);

    size_t countFriends();

    int fCount;

private:
    typedef std::vector<User*> UserCont;
    UserCont friends_;
    UserDatabase* pDB_;
};

std::string User::GetName()
{
    return "A name";
}

size_t User::countFriends()
{
    return friends_.size();
}

void User::AddFriend(User& newFriend)
{
    friends_.push_back(&newFriend);
    fCount++;
    pDB_->AddFriend(GetName(), newFriend.GetName());
}

void User::AddFriendGuarded(User& newFriend)
{
    friends_.push_back(&newFriend);
    Loki::ScopeGuard guard = Loki::MakeObjGuard(friends_, &UserCont::pop_back);

    fCount++;
    Loki::ScopeGuard guardRef = Loki::MakeGuard(Decrement, Loki::ByRef(fCount));
    (void) guardRef;

    pDB_->AddFriend(GetName(), newFriend.GetName());
    guard.Dismiss();
}

int main()
{
    UserDatabase db;

    User u1(&db);
    User u2(&db);

    try{ u1.AddFriend(u2); }
    catch (...){}
    std::cout << "u1 countFriends: " << u1.countFriends() << "\n";
	std::cout << "u1 fCount      : " << u1.fCount << "\n";

    try{ u2.AddFriendGuarded(u1); }
    catch (...){}
    std::cout << "u2 countFriends: " << u2.countFriends() << "\n";
	std::cout << "u2 fCount      : " << u2.fCount << "\n";

#if defined(__BORLANDC__) || defined(_MSC_VER)
    system("PAUSE");
#endif

}
<commit_msg>use RefToValue.h, add dismiss for the ref guard<commit_after>////////////////////////////////////////////////////////////////////////////////
// The Loki Library
// Copyright (c) 2006 Peter Kmmel
// Permission to use, copy, modify, distribute and sell this software for any
//     purpose is hereby granted without fee, provided that the above copyright
//     notice appear in all copies and that both that copyright notice and this
//     permission notice appear in supporting documentation.
// The author makes no representations about the
//     suitability of this software for any purpose. It is provided "as is"
//     without express or implied warranty.
////////////////////////////////////////////////////////////////////////////////

// $Header:

#include <loki/ScopeGuard.h>
#include <loki/RefToValue.h>

#include <vector>
#include <string>
#include <iostream>

void Decrement(int& x)
{
    --x;
}

struct UserDatabase
{
    void AddFriend(const std::string&, const std::string&)
    {
        throw 55;
    }
};

class User
{
public:
    User(UserDatabase* db) : fCount(0), pDB_(db)
    {}

    std::string GetName();

    void AddFriend(User& newFriend);
    void AddFriendGuarded(User& newFriend);

    size_t countFriends();

    int fCount;

private:
    typedef std::vector<User*> UserCont;
    UserCont friends_;
    UserDatabase* pDB_;
};

std::string User::GetName()
{
    return "A name";
}

size_t User::countFriends()
{
    return friends_.size();
}

void User::AddFriend(User& newFriend)
{
    friends_.push_back(&newFriend);
    fCount++;
    pDB_->AddFriend(GetName(), newFriend.GetName());
}

void User::AddFriendGuarded(User& newFriend)
{
    friends_.push_back(&newFriend);
    Loki::ScopeGuard guard = Loki::MakeObjGuard(friends_, &UserCont::pop_back);

    fCount++;
    Loki::ScopeGuard guardRef = Loki::MakeGuard(Decrement, Loki::ByRef(fCount));

    pDB_->AddFriend(GetName(), newFriend.GetName());
    guard.Dismiss();
    guardRef.Dismiss();
}

int main()
{
    UserDatabase db;

    User u1(&db);
    User u2(&db);

    try{ u1.AddFriend(u2); }
    catch (...){}
    std::cout << "u1 countFriends: " << u1.countFriends() << "\n";
    std::cout << "u1 fCount      : " << u1.fCount << "\n";

    try{ u2.AddFriendGuarded(u1); }
    catch (...){}
    std::cout << "u2 countFriends: " << u2.countFriends() << "\n";
    std::cout << "u2 fCount      : " << u2.fCount << "\n";

#if defined(__BORLANDC__) || defined(_MSC_VER)
    system("PAUSE");
#endif

}
<|endoftext|>


<commit_before>//  Copyright 2010 Gregory Szorc
//
//  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.

#pragma once

#include <zippylog/zippylog.h>
#include <zippylog/broker.hpp>
#include <zippylog/store.hpp>

#include <iostream>
#include <string>

using ::pblog::server::Broker;
using ::std::cout;
using ::std::endl;

int main(int argc, const char * const argv[])
{
    if (argc != 2) {
        cout << "Usage: pblogd /path/to/config/file.lua" << endl;
        return 1;
    }

    Broker broker = Broker(argv[1]);
    broker.run();

    return 0;
}
<commit_msg>reflect project renaming<commit_after>//  Copyright 2010 Gregory Szorc
//
//  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.

#pragma once

#include <zippylog/zippylog.h>
#include <zippylog/broker.hpp>
#include <zippylog/store.hpp>

#include <iostream>
#include <string>

using ::zippylog::server::Broker;
using ::std::cout;
using ::std::endl;

int main(int argc, const char * const argv[])
{
    if (argc != 2) {
        cout << "Usage: pblogd /path/to/config/file.lua" << endl;
        return 1;
    }

    Broker broker = Broker(argv[1]);
    broker.run();

    return 0;
}
<|endoftext|>


<commit_before>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "imported_search_context.h"
#include "attributeiterators.hpp"
#include "imported_attribute_vector.h"
#include "reference_attribute.h"
#include <vespa/searchcommon/attribute/search_context_params.h>
#include <vespa/searchlib/fef/fef.h>
#include <vespa/searchlib/query/queryterm.h>
#include <vespa/searchlib/queryeval/emptysearch.h>
#include "dociditerator.h"

using search::datastore::EntryRef;
using search::queryeval::EmptySearch;
using search::queryeval::SearchIterator;
using search::attribute::ReferenceAttribute;
using search::AttributeVector;

using ReverseMappingRefs = ReferenceAttribute::ReverseMappingRefs;
using ReverseMapping = ReferenceAttribute::ReverseMapping;
using SearchContext = AttributeVector::SearchContext;

namespace search {
namespace attribute {

ImportedSearchContext::ImportedSearchContext(
        std::unique_ptr<QueryTermSimple> term,
        const SearchContextParams& params,
        const ImportedAttributeVector& imported_attribute)
    : _imported_attribute(imported_attribute),
      _reference_attribute(*_imported_attribute.getReferenceAttribute()),
      _target_attribute(*_imported_attribute.getTargetAttribute()),
      _target_search_context(_target_attribute.getSearch(std::move(term), params)),
      _referencedLids(_reference_attribute.getReferencedLids()),
      _merger(_reference_attribute.getCommittedDocIdLimit()),
      _fetchPostingsDone(false)
{
}

ImportedSearchContext::~ImportedSearchContext() {
}

unsigned int ImportedSearchContext::approximateHits() const {
    return _reference_attribute.getNumDocs();
}

std::unique_ptr<queryeval::SearchIterator>
ImportedSearchContext::createIterator(fef::TermFieldMatchData* matchData, bool strict) {
    if (_merger.hasArray()) {
        if (_merger.emptyArray()) {
            return SearchIterator::UP(new EmptySearch());
        } else {
            using Posting = btree::BTreeKeyData<uint32_t, int32_t>;
            using DocIt = DocIdIterator<Posting>;
            DocIt postings;
            auto array = _merger.getArray();
            postings.set(&array[0], &array[array.size()]);
            return std::make_unique<AttributePostingListIteratorT<DocIt>>(true, matchData, postings);
        }
    }
    if (!strict) {
        return std::make_unique<AttributeIteratorT<ImportedSearchContext>>(*this, matchData);
    } else {
        return std::make_unique<AttributeIteratorStrict<ImportedSearchContext>>(*this, matchData);
    }
}

namespace {

struct WeightedRef {
    EntryRef revMapIdx;
    int32_t  weight;

    WeightedRef(EntryRef revMapIdx_, int32_t weight_)
        : revMapIdx(revMapIdx_),
          weight(weight_)
    {
    }
};

struct TargetResult {
    std::vector<WeightedRef> weightedRefs;
    size_t sizeSum;

    TargetResult()
        : weightedRefs(),
          sizeSum(0)
    {
    }
};

TargetResult
getTargetResult(ReverseMappingRefs reverseMappingRefs,
                const ReverseMapping &reverseMapping,
                SearchContext &target_search_context)
{
    TargetResult targetResult;
    fef::TermFieldMatchData matchData;
    auto targetItr = target_search_context.createIterator(&matchData, true);
    uint32_t docIdLimit = reverseMappingRefs.size();
    uint32_t lid = 1;
    targetItr->initRange(1, docIdLimit);
    while (lid < docIdLimit) {
        if (targetItr->seek(lid)) {
            EntryRef revMapIdx = reverseMappingRefs[lid];
            if (revMapIdx.valid()) {
                uint32_t size = reverseMapping.frozenSize(revMapIdx);
                targetResult.sizeSum += size;
                targetItr->unpack(lid);
                int32_t weight = matchData.getWeight();
                targetResult.weightedRefs.emplace_back(revMapIdx, weight);
            }
            ++lid;
        } else {
            ++lid;
            uint32_t nextLid = targetItr->getDocId();
            if (nextLid > lid) {
                lid = nextLid;
            }
        }
    }
    return targetResult;
}

class ReverseMappingPostingList
{
    const ReverseMapping &_reverseMapping;
    EntryRef _revMapIdx;
    int32_t _weight;
public:
    ReverseMappingPostingList(const ReverseMapping &reverseMapping, EntryRef revMapIdx, int32_t weight)
        : _reverseMapping(reverseMapping),
          _revMapIdx(revMapIdx),
          _weight(weight)
    {
    }
    ~ReverseMappingPostingList() { }
    template <typename Func>
    void foreach(Func func) const {
        int32_t weight = _weight;
        _reverseMapping.foreach_frozen_key(_revMapIdx, [func, weight](uint32_t lid) { func(lid, weight); });
    }
};

}

void ImportedSearchContext::makeMergedPostings()
{
    TargetResult targetResult(getTargetResult(_reference_attribute.getReverseMappingRefs(),
                                              _reference_attribute.getReverseMapping(),
                                              *_target_search_context));
    _merger.reserveArray(targetResult.weightedRefs.size(), targetResult.sizeSum);
    const auto &reverseMapping = _reference_attribute.getReverseMapping();
    for (const auto &weightedRef : targetResult.weightedRefs) {
        _merger.addToArray(ReverseMappingPostingList(reverseMapping, weightedRef.revMapIdx, weightedRef.weight));
    }
    _merger.merge();
}

void ImportedSearchContext::fetchPostings(bool strict) {
    assert(!_fetchPostingsDone);
    _fetchPostingsDone = true;
    _target_search_context->fetchPostings(strict);
    if (strict) {
        makeMergedPostings();
    }
}

bool ImportedSearchContext::valid() const {
    return _target_search_context->valid();
}

Int64Range ImportedSearchContext::getAsIntegerTerm() const {
    return _target_search_context->getAsIntegerTerm();
}

const QueryTermBase& ImportedSearchContext::queryTerm() const {
    return _target_search_context->queryTerm();
}

const vespalib::string& ImportedSearchContext::attributeName() const {
    return _imported_attribute.getName();
}

bool ImportedSearchContext::cmp(DocId docId, int32_t& weight) const {
    return _target_search_context->cmp(_referencedLids[docId], weight);
}

bool ImportedSearchContext::cmp(DocId docId) const {
    return _target_search_context->cmp(_referencedLids[docId]);
}

} // attribute
} // search
<commit_msg>Avoid race between readers and writer that could cause reader to read uninitialized or unmapped data when accessing target attribute.<commit_after>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "imported_search_context.h"
#include "attributeiterators.hpp"
#include "imported_attribute_vector.h"
#include "reference_attribute.h"
#include <vespa/searchcommon/attribute/search_context_params.h>
#include <vespa/searchlib/fef/fef.h>
#include <vespa/searchlib/query/queryterm.h>
#include <vespa/searchlib/queryeval/emptysearch.h>
#include "dociditerator.h"

using search::datastore::EntryRef;
using search::queryeval::EmptySearch;
using search::queryeval::SearchIterator;
using search::attribute::ReferenceAttribute;
using search::AttributeVector;

using ReverseMappingRefs = ReferenceAttribute::ReverseMappingRefs;
using ReverseMapping = ReferenceAttribute::ReverseMapping;
using SearchContext = AttributeVector::SearchContext;

namespace search {
namespace attribute {

ImportedSearchContext::ImportedSearchContext(
        std::unique_ptr<QueryTermSimple> term,
        const SearchContextParams& params,
        const ImportedAttributeVector& imported_attribute)
    : _imported_attribute(imported_attribute),
      _reference_attribute(*_imported_attribute.getReferenceAttribute()),
      _target_attribute(*_imported_attribute.getTargetAttribute()),
      _target_search_context(_target_attribute.getSearch(std::move(term), params)),
      _referencedLids(_reference_attribute.getReferencedLids()),
      _merger(_reference_attribute.getCommittedDocIdLimit()),
      _fetchPostingsDone(false)
{
}

ImportedSearchContext::~ImportedSearchContext() {
}

unsigned int ImportedSearchContext::approximateHits() const {
    return _reference_attribute.getNumDocs();
}

std::unique_ptr<queryeval::SearchIterator>
ImportedSearchContext::createIterator(fef::TermFieldMatchData* matchData, bool strict) {
    if (_merger.hasArray()) {
        if (_merger.emptyArray()) {
            return SearchIterator::UP(new EmptySearch());
        } else {
            using Posting = btree::BTreeKeyData<uint32_t, int32_t>;
            using DocIt = DocIdIterator<Posting>;
            DocIt postings;
            auto array = _merger.getArray();
            postings.set(&array[0], &array[array.size()]);
            return std::make_unique<AttributePostingListIteratorT<DocIt>>(true, matchData, postings);
        }
    }
    if (!strict) {
        return std::make_unique<AttributeIteratorT<ImportedSearchContext>>(*this, matchData);
    } else {
        return std::make_unique<AttributeIteratorStrict<ImportedSearchContext>>(*this, matchData);
    }
}

namespace {

struct WeightedRef {
    EntryRef revMapIdx;
    int32_t  weight;

    WeightedRef(EntryRef revMapIdx_, int32_t weight_)
        : revMapIdx(revMapIdx_),
          weight(weight_)
    {
    }
};

struct TargetResult {
    std::vector<WeightedRef> weightedRefs;
    size_t sizeSum;

    TargetResult()
        : weightedRefs(),
          sizeSum(0)
    {
    }
};

TargetResult
getTargetResult(ReverseMappingRefs reverseMappingRefs,
                const ReverseMapping &reverseMapping,
                SearchContext &target_search_context,
                uint32_t committedDocIdLimit)
{
    TargetResult targetResult;
    fef::TermFieldMatchData matchData;
    auto targetItr = target_search_context.createIterator(&matchData, true);
    uint32_t docIdLimit = reverseMappingRefs.size();
    if (docIdLimit > committedDocIdLimit) {
        docIdLimit = committedDocIdLimit;
    }
    uint32_t lid = 1;
    targetItr->initRange(1, docIdLimit);
    while (lid < docIdLimit) {
        if (targetItr->seek(lid)) {
            EntryRef revMapIdx = reverseMappingRefs[lid];
            if (revMapIdx.valid()) {
                uint32_t size = reverseMapping.frozenSize(revMapIdx);
                targetResult.sizeSum += size;
                targetItr->unpack(lid);
                int32_t weight = matchData.getWeight();
                targetResult.weightedRefs.emplace_back(revMapIdx, weight);
            }
            ++lid;
        } else {
            ++lid;
            uint32_t nextLid = targetItr->getDocId();
            if (nextLid > lid) {
                lid = nextLid;
            }
        }
    }
    return targetResult;
}

class ReverseMappingPostingList
{
    const ReverseMapping &_reverseMapping;
    EntryRef _revMapIdx;
    int32_t _weight;
public:
    ReverseMappingPostingList(const ReverseMapping &reverseMapping, EntryRef revMapIdx, int32_t weight)
        : _reverseMapping(reverseMapping),
          _revMapIdx(revMapIdx),
          _weight(weight)
    {
    }
    ~ReverseMappingPostingList() { }
    template <typename Func>
    void foreach(Func func) const {
        int32_t weight = _weight;
        _reverseMapping.foreach_frozen_key(_revMapIdx, [func, weight](uint32_t lid) { func(lid, weight); });
    }
};

}

void ImportedSearchContext::makeMergedPostings()
{
    uint32_t committedTargetDocIdLimit = _target_attribute.getCommittedDocIdLimit();
    std::atomic_thread_fence(std::memory_order_acquire);
    TargetResult targetResult(getTargetResult(_reference_attribute.getReverseMappingRefs(),
                                              _reference_attribute.getReverseMapping(),
                                              *_target_search_context,
                                              committedTargetDocIdLimit));
    _merger.reserveArray(targetResult.weightedRefs.size(), targetResult.sizeSum);
    const auto &reverseMapping = _reference_attribute.getReverseMapping();
    for (const auto &weightedRef : targetResult.weightedRefs) {
        _merger.addToArray(ReverseMappingPostingList(reverseMapping, weightedRef.revMapIdx, weightedRef.weight));
    }
    _merger.merge();
}

void ImportedSearchContext::fetchPostings(bool strict) {
    assert(!_fetchPostingsDone);
    _fetchPostingsDone = true;
    _target_search_context->fetchPostings(strict);
    if (strict) {
        makeMergedPostings();
    }
}

bool ImportedSearchContext::valid() const {
    return _target_search_context->valid();
}

Int64Range ImportedSearchContext::getAsIntegerTerm() const {
    return _target_search_context->getAsIntegerTerm();
}

const QueryTermBase& ImportedSearchContext::queryTerm() const {
    return _target_search_context->queryTerm();
}

const vespalib::string& ImportedSearchContext::attributeName() const {
    return _imported_attribute.getName();
}

bool ImportedSearchContext::cmp(DocId docId, int32_t& weight) const {
    return _target_search_context->cmp(_referencedLids[docId], weight);
}

bool ImportedSearchContext::cmp(DocId docId) const {
    return _target_search_context->cmp(_referencedLids[docId]);
}

} // attribute
} // search
<|endoftext|>


<commit_before>#ifndef STAN_MATH_MIX_HPP
#define STAN_MATH_MIX_HPP

#include <stan/math/mix/meta.hpp>
#include <stan/math/mix/fun.hpp>
#include <stan/math/mix/functor.hpp>

#ifdef STAN_OPENCL
#include <stan/math/opencl/rev.hpp>
#endif

#include <stan/math/fwd/core.hpp>
#include <stan/math/fwd/meta.hpp>
#include <stan/math/fwd/fun.hpp>
#include <stan/math/fwd/functor.hpp>

#include <stan/math/rev/core.hpp>
#include <stan/math/rev/meta.hpp>
#include <stan/math/rev/fun.hpp>
#include <stan/math/rev/functor.hpp>

#include <stan/math/prim.hpp>

#endif
<commit_msg>Update mix.hpp<commit_after>#ifndef STAN_MATH_MIX_HPP
#define STAN_MATH_MIX_HPP

#include <stan/math/mix/meta.hpp>
#include <stan/math/mix/fun.hpp>
#include <stan/math/mix/functor.hpp>

#include <stan/math/fwd/core.hpp>
#include <stan/math/fwd/meta.hpp>
#include <stan/math/fwd/fun.hpp>
#include <stan/math/fwd/functor.hpp>

#ifdef STAN_OPENCL
#include <stan/math/opencl/rev.hpp>
#endif

#include <stan/math/rev/core.hpp>
#include <stan/math/rev/meta.hpp>
#include <stan/math/rev/fun.hpp>
#include <stan/math/rev/functor.hpp>

#include <stan/math/prim.hpp>

#endif
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2013 The WebM project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include <string>
#include "test/codec_factory.h"
#include "test/decode_test_driver.h"
#include "test/encode_test_driver.h"
#include "test/i420_video_source.h"
#include "test/ivf_video_source.h"
#include "test/md5_helper.h"
#include "test/util.h"
#include "test/webm_video_source.h"
#include "vpx_ports/vpx_timer.h"
#include "./ivfenc.h"
#include "./vpx_version.h"

using std::tr1::make_tuple;

namespace {

#define VIDEO_NAME 0
#define THREADS 1

const int kMaxPsnr = 100;
const double kUsecsInSec = 1000000.0;
static const char *kNewEncodeOutputFile = "new_encode.ivf";

/*
 DecodePerfTest takes a tuple of filename + number of threads to decode with
 */
typedef std::tr1::tuple<const char *, unsigned> DecodePerfParam;

const DecodePerfParam kVP9DecodePerfVectors[] = {
  make_tuple("vp90-2-bbb_426x240_tile_1x1_180kbps.webm", 1),
  make_tuple("vp90-2-bbb_640x360_tile_1x2_337kbps.webm", 2),
  make_tuple("vp90-2-bbb_854x480_tile_1x2_651kbps.webm", 2),
  make_tuple("vp90-2-bbb_1280x720_tile_1x4_1310kbps.webm", 4),
  make_tuple("vp90-2-bbb_1920x1080_tile_1x1_2581kbps.webm", 1),
  make_tuple("vp90-2-bbb_1920x1080_tile_1x4_2586kbps.webm", 4),
  make_tuple("vp90-2-bbb_1920x1080_tile_1x4_fpm_2304kbps.webm", 4),
  make_tuple("vp90-2-sintel_426x182_tile_1x1_171kbps.webm", 1),
  make_tuple("vp90-2-sintel_640x272_tile_1x2_318kbps.webm", 2),
  make_tuple("vp90-2-sintel_854x364_tile_1x2_621kbps.webm", 2),
  make_tuple("vp90-2-sintel_1280x546_tile_1x4_1257kbps.webm", 4),
  make_tuple("vp90-2-sintel_1920x818_tile_1x4_fpm_2279kbps.webm", 4),
  make_tuple("vp90-2-tos_426x178_tile_1x1_181kbps.webm", 1),
  make_tuple("vp90-2-tos_640x266_tile_1x2_336kbps.webm", 2),
  make_tuple("vp90-2-tos_854x356_tile_1x2_656kbps.webm", 2),
  make_tuple("vp90-2-tos_854x356_tile_1x2_fpm_546kbps.webm", 2),
  make_tuple("vp90-2-tos_1280x534_tile_1x4_1306kbps.webm", 4),
  make_tuple("vp90-2-tos_1280x534_tile_1x4_fpm_952kbps.webm", 4),
  make_tuple("vp90-2-tos_1920x800_tile_1x4_fpm_2335kbps.webm", 4),
};

/*
 In order to reflect real world performance as much as possible, Perf tests
 *DO NOT* do any correctness checks. Please run them alongside correctness
 tests to ensure proper codec integrity. Furthermore, in this test we
 deliberately limit the amount of system calls we make to avoid OS
 preemption.

 TODO(joshualitt) create a more detailed perf measurement test to collect
   power/temp/min max frame decode times/etc
 */

class DecodePerfTest : public ::testing::TestWithParam<DecodePerfParam> {
};

TEST_P(DecodePerfTest, PerfTest) {
  const char *const video_name = GET_PARAM(VIDEO_NAME);
  const unsigned threads = GET_PARAM(THREADS);

  libvpx_test::WebMVideoSource video(video_name);
  video.Init();

  vpx_codec_dec_cfg_t cfg = vpx_codec_dec_cfg_t();
  cfg.threads = threads;
  libvpx_test::VP9Decoder decoder(cfg, 0);

  vpx_usec_timer t;
  vpx_usec_timer_start(&t);

  for (video.Begin(); video.cxdata() != NULL; video.Next()) {
    decoder.DecodeFrame(video.cxdata(), video.frame_size());
  }

  vpx_usec_timer_mark(&t);
  const double elapsed_secs = double(vpx_usec_timer_elapsed(&t))
                              / kUsecsInSec;
  const unsigned frames = video.frame_number();
  const double fps = double(frames) / elapsed_secs;

  printf("{\n");
  printf("\t\"type\" : \"decode_perf_test\",\n");
  printf("\t\"version\" : \"%s\",\n", VERSION_STRING_NOSP);
  printf("\t\"videoName\" : \"%s\",\n", video_name);
  printf("\t\"threadCount\" : %u,\n", threads);
  printf("\t\"decodeTimeSecs\" : %f,\n", elapsed_secs);
  printf("\t\"totalFrames\" : %u,\n", frames);
  printf("\t\"framesPerSecond\" : %f\n", fps);
  printf("}\n");
}

INSTANTIATE_TEST_CASE_P(VP9, DecodePerfTest,
                        ::testing::ValuesIn(kVP9DecodePerfVectors));

class VP9NewEncodeDecodePerfTest : public ::libvpx_test::EncoderTest,
    public ::libvpx_test::CodecTestWithParam<libvpx_test::TestMode> {
 protected:
  VP9NewEncodeDecodePerfTest()
      : EncoderTest(GET_PARAM(0)),
        encoding_mode_(GET_PARAM(1)),
        speed_(0),
        outfile_(0),
        out_frames_(0) {
  }

  virtual ~VP9NewEncodeDecodePerfTest() {}

  virtual void SetUp() {
    InitializeConfig();
    SetMode(encoding_mode_);

    cfg_.g_lag_in_frames = 25;
    cfg_.rc_min_quantizer = 2;
    cfg_.rc_max_quantizer = 56;
    cfg_.rc_dropframe_thresh = 0;
    cfg_.rc_undershoot_pct = 50;
    cfg_.rc_overshoot_pct = 50;
    cfg_.rc_buf_sz = 1000;
    cfg_.rc_buf_initial_sz = 500;
    cfg_.rc_buf_optimal_sz = 600;
    cfg_.rc_resize_allowed = 0;
    cfg_.rc_end_usage = VPX_VBR;
  }

  virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video,
                                  ::libvpx_test::Encoder *encoder) {
    if (video->frame() == 1) {
      encoder->Control(VP8E_SET_CPUUSED, speed_);
      encoder->Control(VP9E_SET_FRAME_PARALLEL_DECODING, 1);
      encoder->Control(VP9E_SET_TILE_COLUMNS, 2);
    }
  }

  virtual void BeginPassHook(unsigned int /*pass*/) {
    const std::string data_path = getenv("LIBVPX_TEST_DATA_PATH");
    const std::string path_to_source = data_path + "/" + kNewEncodeOutputFile;
    outfile_ = fopen(path_to_source.c_str(), "wb");
  }

  virtual void EndPassHook() {
    if (outfile_) {
      if (!fseek(outfile_, 0, SEEK_SET))
        ivf_write_file_header(outfile_, &cfg_, VP9_FOURCC, out_frames_);
      fclose(outfile_);
      outfile_ = NULL;
    }
  }

  virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) {
    ++out_frames_;

    // Write initial file header if first frame.
    if (pkt->data.frame.pts == 0)
      ivf_write_file_header(outfile_, &cfg_, VP9_FOURCC, out_frames_);

    // Write frame header and data.
    ivf_write_frame_header(outfile_, out_frames_, pkt->data.frame.sz);
    (void)fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz, outfile_);
  }

  virtual bool DoDecode() { return 0; }

  void set_speed(unsigned int speed) {
    speed_ = speed;
  }

 private:
  libvpx_test::TestMode encoding_mode_;
  uint32_t speed_;
  FILE *outfile_;
  uint32_t out_frames_;
};

struct EncodePerfTestVideo {
  EncodePerfTestVideo(const char *name_, uint32_t width_, uint32_t height_,
                      uint32_t bitrate_, int frames_)
      : name(name_),
        width(width_),
        height(height_),
        bitrate(bitrate_),
        frames(frames_) {}
  const char *name;
  uint32_t width;
  uint32_t height;
  uint32_t bitrate;
  int frames;
};

const EncodePerfTestVideo kVP9EncodePerfTestVectors[] = {
  EncodePerfTestVideo("niklas_1280_720_30.yuv", 1280, 720, 600, 470),
};

TEST_P(VP9NewEncodeDecodePerfTest, PerfTest) {
  SetUp();

  // TODO(JBB): Make this work by going through the set of given files.
  const int i = 0;
  const vpx_rational timebase = { 33333333, 1000000000 };
  cfg_.g_timebase = timebase;
  cfg_.rc_target_bitrate = kVP9EncodePerfTestVectors[i].bitrate;

  init_flags_ = VPX_CODEC_USE_PSNR;

  const char *video_name = kVP9EncodePerfTestVectors[i].name;
  libvpx_test::I420VideoSource video(
      video_name,
      kVP9EncodePerfTestVectors[i].width,
      kVP9EncodePerfTestVectors[i].height,
      timebase.den, timebase.num, 0,
      kVP9EncodePerfTestVectors[i].frames);
  set_speed(2);

  ASSERT_NO_FATAL_FAILURE(RunLoop(&video));

  const uint32_t threads = 4;

  libvpx_test::IVFVideoSource decode_video(kNewEncodeOutputFile);
  decode_video.Init();

  vpx_codec_dec_cfg_t cfg = vpx_codec_dec_cfg_t();
  cfg.threads = threads;
  libvpx_test::VP9Decoder decoder(cfg, 0);

  vpx_usec_timer t;
  vpx_usec_timer_start(&t);

  for (decode_video.Begin(); decode_video.cxdata() != NULL;
       decode_video.Next()) {
    decoder.DecodeFrame(decode_video.cxdata(), decode_video.frame_size());
  }

  vpx_usec_timer_mark(&t);
  const double elapsed_secs =
      double(vpx_usec_timer_elapsed(&t)) / kUsecsInSec;
  const unsigned decode_frames = decode_video.frame_number();
  const double fps = double(decode_frames) / elapsed_secs;

  printf("{\n");
  printf("\t\"type\" : \"decode_perf_test\",\n");
  printf("\t\"version\" : \"%s\",\n", VERSION_STRING_NOSP);
  printf("\t\"videoName\" : \"%s\",\n", kNewEncodeOutputFile);
  printf("\t\"threadCount\" : %u,\n", threads);
  printf("\t\"decodeTimeSecs\" : %f,\n", elapsed_secs);
  printf("\t\"totalFrames\" : %u,\n", decode_frames);
  printf("\t\"framesPerSecond\" : %f\n", fps);
  printf("}\n");
}

VP9_INSTANTIATE_TEST_CASE(
  VP9NewEncodeDecodePerfTest, ::testing::Values(::libvpx_test::kTwoPassGood));
}  // namespace
<commit_msg>Resolve several style issues in decode_perf_test<commit_after>/*
 *  Copyright (c) 2013 The WebM project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include <string>
#include "test/codec_factory.h"
#include "test/decode_test_driver.h"
#include "test/encode_test_driver.h"
#include "test/i420_video_source.h"
#include "test/ivf_video_source.h"
#include "test/md5_helper.h"
#include "test/util.h"
#include "test/webm_video_source.h"
#include "vpx_ports/vpx_timer.h"
#include "./ivfenc.h"
#include "./vpx_version.h"

using std::tr1::make_tuple;

namespace {

#define VIDEO_NAME 0
#define THREADS 1

const int kMaxPsnr = 100;
const double kUsecsInSec = 1000000.0;
const char kNewEncodeOutputFile[] = "new_encode.ivf";

/*
 DecodePerfTest takes a tuple of filename + number of threads to decode with
 */
typedef std::tr1::tuple<const char *, unsigned> DecodePerfParam;

const DecodePerfParam kVP9DecodePerfVectors[] = {
  make_tuple("vp90-2-bbb_426x240_tile_1x1_180kbps.webm", 1),
  make_tuple("vp90-2-bbb_640x360_tile_1x2_337kbps.webm", 2),
  make_tuple("vp90-2-bbb_854x480_tile_1x2_651kbps.webm", 2),
  make_tuple("vp90-2-bbb_1280x720_tile_1x4_1310kbps.webm", 4),
  make_tuple("vp90-2-bbb_1920x1080_tile_1x1_2581kbps.webm", 1),
  make_tuple("vp90-2-bbb_1920x1080_tile_1x4_2586kbps.webm", 4),
  make_tuple("vp90-2-bbb_1920x1080_tile_1x4_fpm_2304kbps.webm", 4),
  make_tuple("vp90-2-sintel_426x182_tile_1x1_171kbps.webm", 1),
  make_tuple("vp90-2-sintel_640x272_tile_1x2_318kbps.webm", 2),
  make_tuple("vp90-2-sintel_854x364_tile_1x2_621kbps.webm", 2),
  make_tuple("vp90-2-sintel_1280x546_tile_1x4_1257kbps.webm", 4),
  make_tuple("vp90-2-sintel_1920x818_tile_1x4_fpm_2279kbps.webm", 4),
  make_tuple("vp90-2-tos_426x178_tile_1x1_181kbps.webm", 1),
  make_tuple("vp90-2-tos_640x266_tile_1x2_336kbps.webm", 2),
  make_tuple("vp90-2-tos_854x356_tile_1x2_656kbps.webm", 2),
  make_tuple("vp90-2-tos_854x356_tile_1x2_fpm_546kbps.webm", 2),
  make_tuple("vp90-2-tos_1280x534_tile_1x4_1306kbps.webm", 4),
  make_tuple("vp90-2-tos_1280x534_tile_1x4_fpm_952kbps.webm", 4),
  make_tuple("vp90-2-tos_1920x800_tile_1x4_fpm_2335kbps.webm", 4),
};

/*
 In order to reflect real world performance as much as possible, Perf tests
 *DO NOT* do any correctness checks. Please run them alongside correctness
 tests to ensure proper codec integrity. Furthermore, in this test we
 deliberately limit the amount of system calls we make to avoid OS
 preemption.

 TODO(joshualitt) create a more detailed perf measurement test to collect
   power/temp/min max frame decode times/etc
 */

class DecodePerfTest : public ::testing::TestWithParam<DecodePerfParam> {
};

TEST_P(DecodePerfTest, PerfTest) {
  const char *const video_name = GET_PARAM(VIDEO_NAME);
  const unsigned threads = GET_PARAM(THREADS);

  libvpx_test::WebMVideoSource video(video_name);
  video.Init();

  vpx_codec_dec_cfg_t cfg = vpx_codec_dec_cfg_t();
  cfg.threads = threads;
  libvpx_test::VP9Decoder decoder(cfg, 0);

  vpx_usec_timer t;
  vpx_usec_timer_start(&t);

  for (video.Begin(); video.cxdata() != NULL; video.Next()) {
    decoder.DecodeFrame(video.cxdata(), video.frame_size());
  }

  vpx_usec_timer_mark(&t);
  const double elapsed_secs = double(vpx_usec_timer_elapsed(&t))
                              / kUsecsInSec;
  const unsigned frames = video.frame_number();
  const double fps = double(frames) / elapsed_secs;

  printf("{\n");
  printf("\t\"type\" : \"decode_perf_test\",\n");
  printf("\t\"version\" : \"%s\",\n", VERSION_STRING_NOSP);
  printf("\t\"videoName\" : \"%s\",\n", video_name);
  printf("\t\"threadCount\" : %u,\n", threads);
  printf("\t\"decodeTimeSecs\" : %f,\n", elapsed_secs);
  printf("\t\"totalFrames\" : %u,\n", frames);
  printf("\t\"framesPerSecond\" : %f\n", fps);
  printf("}\n");
}

INSTANTIATE_TEST_CASE_P(VP9, DecodePerfTest,
                        ::testing::ValuesIn(kVP9DecodePerfVectors));

class VP9NewEncodeDecodePerfTest :
    public ::libvpx_test::EncoderTest,
    public ::libvpx_test::CodecTestWithParam<libvpx_test::TestMode> {
 protected:
  VP9NewEncodeDecodePerfTest()
      : EncoderTest(GET_PARAM(0)),
        encoding_mode_(GET_PARAM(1)),
        speed_(0),
        outfile_(0),
        out_frames_(0) {
  }

  virtual ~VP9NewEncodeDecodePerfTest() {}

  virtual void SetUp() {
    InitializeConfig();
    SetMode(encoding_mode_);

    cfg_.g_lag_in_frames = 25;
    cfg_.rc_min_quantizer = 2;
    cfg_.rc_max_quantizer = 56;
    cfg_.rc_dropframe_thresh = 0;
    cfg_.rc_undershoot_pct = 50;
    cfg_.rc_overshoot_pct = 50;
    cfg_.rc_buf_sz = 1000;
    cfg_.rc_buf_initial_sz = 500;
    cfg_.rc_buf_optimal_sz = 600;
    cfg_.rc_resize_allowed = 0;
    cfg_.rc_end_usage = VPX_VBR;
  }

  virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video,
                                  ::libvpx_test::Encoder *encoder) {
    if (video->frame() == 1) {
      encoder->Control(VP8E_SET_CPUUSED, speed_);
      encoder->Control(VP9E_SET_FRAME_PARALLEL_DECODING, 1);
      encoder->Control(VP9E_SET_TILE_COLUMNS, 2);
    }
  }

  virtual void BeginPassHook(unsigned int /*pass*/) {
    const std::string data_path = getenv("LIBVPX_TEST_DATA_PATH");
    const std::string path_to_source = data_path + "/" + kNewEncodeOutputFile;
    outfile_ = fopen(path_to_source.c_str(), "wb");
    ASSERT_TRUE(outfile_ != NULL);
  }

  virtual void EndPassHook() {
    if (outfile_ != NULL) {
      if (!fseek(outfile_, 0, SEEK_SET))
        ivf_write_file_header(outfile_, &cfg_, VP9_FOURCC, out_frames_);
      fclose(outfile_);
      outfile_ = NULL;
    }
  }

  virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) {
    ++out_frames_;

    // Write initial file header if first frame.
    if (pkt->data.frame.pts == 0)
      ivf_write_file_header(outfile_, &cfg_, VP9_FOURCC, out_frames_);

    // Write frame header and data.
    ivf_write_frame_header(outfile_, out_frames_, pkt->data.frame.sz);
    ASSERT_GT(fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz, outfile_), 0);
  }

  virtual bool DoDecode() { return false; }

  void set_speed(unsigned int speed) {
    speed_ = speed;
  }

 private:
  libvpx_test::TestMode encoding_mode_;
  uint32_t speed_;
  FILE *outfile_;
  uint32_t out_frames_;
};

struct EncodePerfTestVideo {
  EncodePerfTestVideo(const char *name_, uint32_t width_, uint32_t height_,
                      uint32_t bitrate_, int frames_)
      : name(name_),
        width(width_),
        height(height_),
        bitrate(bitrate_),
        frames(frames_) {}
  const char *name;
  uint32_t width;
  uint32_t height;
  uint32_t bitrate;
  int frames;
};

const EncodePerfTestVideo kVP9EncodePerfTestVectors[] = {
  EncodePerfTestVideo("niklas_1280_720_30.yuv", 1280, 720, 600, 470),
};

TEST_P(VP9NewEncodeDecodePerfTest, PerfTest) {
  SetUp();

  // TODO(JBB): Make this work by going through the set of given files.
  const int i = 0;
  const vpx_rational timebase = { 33333333, 1000000000 };
  cfg_.g_timebase = timebase;
  cfg_.rc_target_bitrate = kVP9EncodePerfTestVectors[i].bitrate;

  init_flags_ = VPX_CODEC_USE_PSNR;

  const char *video_name = kVP9EncodePerfTestVectors[i].name;
  libvpx_test::I420VideoSource video(
      video_name,
      kVP9EncodePerfTestVectors[i].width,
      kVP9EncodePerfTestVectors[i].height,
      timebase.den, timebase.num, 0,
      kVP9EncodePerfTestVectors[i].frames);
  set_speed(2);

  ASSERT_NO_FATAL_FAILURE(RunLoop(&video));

  const uint32_t threads = 4;

  libvpx_test::IVFVideoSource decode_video(kNewEncodeOutputFile);
  decode_video.Init();

  vpx_codec_dec_cfg_t cfg = vpx_codec_dec_cfg_t();
  cfg.threads = threads;
  libvpx_test::VP9Decoder decoder(cfg, 0);

  vpx_usec_timer t;
  vpx_usec_timer_start(&t);

  for (decode_video.Begin(); decode_video.cxdata() != NULL;
       decode_video.Next()) {
    decoder.DecodeFrame(decode_video.cxdata(), decode_video.frame_size());
  }

  vpx_usec_timer_mark(&t);
  const double elapsed_secs =
      static_cast<double>(vpx_usec_timer_elapsed(&t)) / kUsecsInSec;
  const unsigned decode_frames = decode_video.frame_number();
  const double fps = static_cast<double>(decode_frames) / elapsed_secs;

  printf("{\n");
  printf("\t\"type\" : \"decode_perf_test\",\n");
  printf("\t\"version\" : \"%s\",\n", VERSION_STRING_NOSP);
  printf("\t\"videoName\" : \"%s\",\n", kNewEncodeOutputFile);
  printf("\t\"threadCount\" : %u,\n", threads);
  printf("\t\"decodeTimeSecs\" : %f,\n", elapsed_secs);
  printf("\t\"totalFrames\" : %u,\n", decode_frames);
  printf("\t\"framesPerSecond\" : %f\n", fps);
  printf("}\n");
}

VP9_INSTANTIATE_TEST_CASE(
  VP9NewEncodeDecodePerfTest, ::testing::Values(::libvpx_test::kTwoPassGood));
}  // namespace
<|endoftext|>


<commit_before>#include <mettle.hpp>
using namespace mettle;

#include <iostream>
#include <fcntl.h>
#include <unistd.h>

#include <mettle/driver/posix/scoped_pipe.hpp>
using namespace mettle::posix;

suite<scoped_pipe> test_scoped_pipe("scoped_pipe", [](auto &_) {
  _.setup([](scoped_pipe &pipe) {
    expect("open pipe", pipe.open(), equal_to(0));
  });

  _.test("open()", [](scoped_pipe &pipe) {
    expect("read fd", pipe.read_fd, greater_equal(0));
    expect("write fd", pipe.write_fd, greater_equal(0));
  });

  _.test("close()", [](scoped_pipe &pipe) {
    int read_fd, write_fd;
    read_fd = pipe.read_fd;
    write_fd = pipe.write_fd;

    expect("close read fd", pipe.close_read(), equal_to(0));
    expect("read fd", pipe.read_fd, equal_to(-1));
    expect("close read fd again", pipe.close_read(), equal_to(-1));

    expect("get read fd flags", fcntl(read_fd, F_GETFD), equal_to(-1));
    expect(errno, equal_to(EBADF));

    expect("close write fd", pipe.close_write(), equal_to(0));
    expect("write fd", pipe.write_fd, equal_to(-1));
    expect("close write fd again", pipe.close_write(), equal_to(-1));

    expect("get write fd flags", fcntl(write_fd, F_GETFD), equal_to(-1));
    expect(errno, equal_to(EBADF));
  });

  _.test("~scoped_pipe()", [](scoped_pipe &) {
    int read_fd, write_fd;
    {
      scoped_pipe pipe;
      expect("open pipe", pipe.open(), equal_to(0));
      read_fd = pipe.read_fd;
      write_fd = pipe.write_fd;
    }

    expect("get read fd flags", fcntl(read_fd, F_GETFD), equal_to(-1));
    expect(errno, equal_to(EBADF));

    expect("get write fd flags", fcntl(write_fd, F_GETFD), equal_to(-1));
    expect(errno, equal_to(EBADF));
  });

  _.test("read()/write()", [](scoped_pipe &pipe) {
    char in_data[] = "hello";
    expect(write(pipe.write_fd, in_data, sizeof(in_data)),
           equal_to(sizeof(in_data)));

    char out_data[sizeof(in_data)];
    expect(read(pipe.read_fd, out_data, sizeof(out_data)),
           equal_to(sizeof(in_data)));

    expect(std::string(out_data), equal_to(in_data));
  });

  // These might be a bit dangerous, since we're clobbering stdin/stdout...

  _.test("move_read()", [](scoped_pipe &pipe) {
    pipe.move_read(STDIN_FILENO);
    char in_data[] = "hello";
    expect(write(pipe.write_fd, in_data, sizeof(in_data) - 1),
           equal_to(sizeof(in_data) - 1));
    pipe.close_write();

    std::string out_data;
    std::cin >> out_data;
    expect(std::string(out_data), equal_to(in_data));
  });

  _.test("move_write()", [](scoped_pipe &pipe) {
    pipe.move_write(STDOUT_FILENO);
    char in_data[] = "hello";
    std::cout << in_data << std::flush;
    close(STDOUT_FILENO);

    char out_data[sizeof(in_data)];
    expect(read(pipe.read_fd, out_data, sizeof(out_data)),
           equal_to(sizeof(in_data) - 1));
    expect(std::string(out_data), equal_to(in_data));
  });
});
<commit_msg>Improve scoped_pipe tests<commit_after>#include <mettle.hpp>
using namespace mettle;

#include <iostream>
#include <memory>
#include <fcntl.h>
#include <unistd.h>

#include <mettle/driver/posix/scoped_pipe.hpp>
using namespace mettle::posix;

suite<std::unique_ptr<scoped_pipe>>
test_scoped_pipe("scoped_pipe", [](auto &_) {
  _.setup([](auto &pipe) {
    pipe = std::make_unique<scoped_pipe>();
    expect("open pipe", pipe->open(), equal_to(0));
  });

  _.test("open()", [](auto &pipe) {
    expect("read fd", pipe->read_fd, greater_equal(0));
    expect("write fd", pipe->write_fd, greater_equal(0));

    expect("reopen pipe", [&pipe]() { pipe->open(); }, killed(SIGABRT));
  });

  _.test("close()", [](auto &pipe) {
    int read_fd, write_fd;
    read_fd = pipe->read_fd;
    write_fd = pipe->write_fd;

    expect("close read fd", pipe->close_read(), equal_to(0));
    expect("read fd", pipe->read_fd, equal_to(-1));
    expect("close read fd again", pipe->close_read(), equal_to(-1));

    expect("get read fd flags", fcntl(read_fd, F_GETFD), equal_to(-1));
    expect(errno, equal_to(EBADF));

    expect("close write fd", pipe->close_write(), equal_to(0));
    expect("write fd", pipe->write_fd, equal_to(-1));
    expect("close write fd again", pipe->close_write(), equal_to(-1));

    expect("get write fd flags", fcntl(write_fd, F_GETFD), equal_to(-1));
    expect(errno, equal_to(EBADF));
  });

  _.test("~scoped_pipe()", [](auto &pipe) {
    int read_fd = pipe->read_fd;
    int write_fd = pipe->write_fd;
    pipe.reset();

    expect("get read fd flags", fcntl(read_fd, F_GETFD), equal_to(-1));
    expect(errno, equal_to(EBADF));

    expect("get write fd flags", fcntl(write_fd, F_GETFD), equal_to(-1));
    expect(errno, equal_to(EBADF));
  });

  _.test("read()/write()", [](auto &pipe) {
    char in_data[] = "hello";
    expect("write data", write(pipe->write_fd, in_data, sizeof(in_data)),
           equal_to(sizeof(in_data)));

    char out_data[sizeof(in_data)];
    expect("read data", read(pipe->read_fd, out_data, sizeof(out_data)),
           equal_to(sizeof(in_data)));

    expect(std::string(out_data), equal_to(in_data));
  });

  // These might be a bit dangerous, since we're clobbering stdin/stdout...

  _.test("move_read()", [](auto &pipe) {
    pipe->move_read(STDIN_FILENO);
    char in_data[] = "hello";
    expect("write data", write(pipe->write_fd, in_data, sizeof(in_data) - 1),
           equal_to(sizeof(in_data) - 1));
    pipe->close_write();

    std::string out_data;
    std::cin >> out_data;
    expect(std::string(out_data), equal_to(in_data));
  });

  _.test("move_write()", [](auto &pipe) {
    pipe->move_write(STDOUT_FILENO);
    char in_data[] = "hello";
    std::cout << in_data << std::flush;
    close(STDOUT_FILENO);

    char out_data[sizeof(in_data)];
    expect("read data", read(pipe->read_fd, out_data, sizeof(out_data)),
           equal_to(sizeof(in_data) - 1));
    expect(std::string(out_data), equal_to(in_data));
  });
});
<|endoftext|>