Commit 5c883604 authored by Tat Dat Duong's avatar Tat Dat Duong
Browse files

refactor: merge two trees into one

parent 3df6db3e
Loading
Loading
Loading
Loading
+0 −7
Original line number Diff line number Diff line
include_directories( ${GTEST_INCLUDE_DIRS} )
include_directories( ~/.local/include )
include_directories( src )

add_subdirectory( test )
add_subdirectory( unittest )
add_subdirectory( benchmark )
 No newline at end of file
+0 −2
Original line number Diff line number Diff line
add_btree_executable(blinktree benchmark_host.cpp)
add_btree_executable(blinktree benchmark_cuda.cu)
 No newline at end of file
+0 −204
Original line number Diff line number Diff line
#pragma once

#include <algorithm>
#include <chrono>
#include <cstdlib>
#include <iostream>
#include <map>
#include <numeric>
#include <random>
#include <set>
#include <sstream>
#include <utility>
#include <vector>

namespace Benchmark {

namespace Device {
struct Cuda;
struct Host;
} // namespace Device

template <typename Device> struct BenchTimer;

namespace Generators {
template <typename Type> std::vector<Type> increasing(int size) {
  std::vector<Type> res(size);
  std::iota(res.begin(), res.end(), 0);
  return res;
}

template <typename Type> std::vector<Type> decreasing(int size) {
  std::vector<Type> res(size);
  std::iota(res.begin(), res.end(), 0);
  std::reverse(res.begin(), res.end());
  return res;
}

template <typename Type> std::vector<Type> shuffle(int size) {
  std::vector<Type> res(size);
  std::iota(res.begin(), res.end(), 0);

  std::random_device rd;
  std::mt19937 g(rd());
  std::shuffle(res.begin(), res.end(), g);

  return res;
}

template <typename Type> std::vector<Type> almostSorted(int size, int swapCount = 5) {
  std::vector<Type> res(size);
  std::iota(res.begin(), res.end(), 0);

  for (int i = 0; i < swapCount; ++i) {
    size_t targetIndex = rand() % (size - 2);
    std::swap(res[targetIndex], res[targetIndex + 1]);
  }
  return res;
}
} // namespace Generators

#ifdef HAVE_CUDA
template <> struct BenchTimer<Device::Cuda> {
  float mTime;
  cudaEvent_t mStart, mStop;

  std::map<std::string, float> mValues;

  double getTime() { return mTime; }

public:
  void start() {
    cudaEventCreate(&mStart);
    cudaEventCreate(&mStop);
    cudaEventRecord(mStart, nullptr);
  }

  void stop(std::string name) {
    cudaEventRecord(mStop, nullptr);
    cudaEventSynchronize(mStop);
    cudaEventElapsedTime(&mTime, mStart, mStop);

    cudaEventDestroy(mStart);
    cudaEventDestroy(mStop);

    mValues[name] = getTime();
  }

  std::map<std::string, double> getTimers() {
    std::map<std::string, double> res;
    for (auto &it : mValues)
      res[it.first] = (double)it.second;
    return res;
  }
};
#endif

template <> struct BenchTimer<Device::Host> {
  std::chrono::high_resolution_clock::time_point tp;
  std::chrono::high_resolution_clock::duration dur;

  std::map<std::string, double> mValues;

  double getTime() {
    return std::chrono::duration_cast<std::chrono::microseconds>(dur).count() / 1000.0;
  }

public:
  void start() { tp = std::chrono::high_resolution_clock::now(); }

  void stop(std::string name) {
    dur = std::chrono::high_resolution_clock::now() - tp;
    mValues[name] = getTime();
  }

  std::map<std::string, double> getTimers() { return mValues; }
};

template <typename Device, typename Type, typename Code>
std::map<std::string, double> runner(Code &&code, std::vector<Type> input, int attempts) {
  std::map<std::string, double> sums;

  if (attempts == 0) {
    return sums;
  }

  for (int attempt = 0; attempt < attempts; ++attempt) {
    Benchmark::BenchTimer<Device> timer;
    code(timer, input);

    for (auto const &it : timer.getTimers()) {
      sums[it.first] += it.second;
    }
  }

  std::map<std::string, double> result;
  for (auto const &it : sums) {
    result[it.first] = it.second / (attempts * 1.);
  }
  return result;
}

template <typename Device, typename Type, typename Code>
void execute(const std::string name, Code &&code, int from = 10, int to = 25, int attempts = 10) {

  std::map<std::string, std::vector<std::string>> result;

  for (int pow = from; pow <= to; ++pow) {
    size_t size = 1 << pow;

    std::set<std::string> keys;

    auto increasing = runner<Device>(code, Generators::increasing<Type>(size), attempts);
    std::cout << name << "[" << pow << "] "
              << "increasing(#" << attempts << ")" << std::endl;

    auto decreasing = runner<Device>(code, Generators::decreasing<Type>(size), attempts);
    std::cout << name << "[" << pow << "] "
              << "decreasing(#" << attempts << ")" << std::endl;

    auto shuffle = runner<Device>(code, Generators::shuffle<Type>(size), attempts);
    std::cout << name << "[" << pow << "] "
              << "shuffle(#" << attempts << ")" << std::endl;

    auto almostSorted = runner<Device>(code, Generators::almostSorted<Type>(size), attempts);
    std::cout << name << "[" << pow << "] "
              << "almostSorted(#" << attempts << ")" << std::endl;

    for (auto const &it : increasing) {
      keys.insert(it.first);
    }

    for (auto const &it : decreasing) {
      keys.insert(it.first);
    }

    for (auto const &it : shuffle) {
      keys.insert(it.first);
    }

    for (auto const &it : almostSorted) {
      keys.insert(it.first);
    }

    for (auto &key : keys) {
      std::stringstream ss;
      ss << "(" << pow << "," << increasing[key] << "," << decreasing[key] << "," << shuffle[key]
         << "," << almostSorted[key] << ")";

      result[name + "_" + key].push_back(ss.str());
    }
  }

  std::cout << std::endl;

  for (auto const &it : result) {
    std::cout << it.first << " = (" << std::endl;
    for (auto const &row : it.second) {
      std::cout << "    " << row << std::endl;
    }
    std::cout << ")" << std::endl;
  }
}

} // namespace Benchmark
+0 −36
Original line number Diff line number Diff line
#include "BTreeContainer/Default.hpp"
#include "TNL/Devices/Cuda.h"
#include "benchmark.hpp"

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

  using KeyType = uint64_t;
  using ValueType = uint64_t;
  const size_t Order = 15;

  Benchmark::execute<Benchmark::Device::Cuda, KeyType>(
      "btree_cuda_v4_link", [](auto &timer, auto input) {
        size_t size = getContainerSize(input.size(), Order);
        BTreeContainer<KeyType, ValueType, Order, TNL::Devices::Cuda> container(size);

        Containers::Array<KeyType, TNL::Devices::Cuda> keys(input);
        Containers::Array<ValueType, TNL::Devices::Cuda> values(input);
        container.init();

        timer.start();
        container.insert(keys, values);
        timer.stop("insert");

        values.reset();

        Containers::Array<ValueType, TNL::Devices::Cuda> results(input.size());
        Containers::Array<bool, TNL::Devices::Cuda> mask(input.size());
        timer.start();
        container.find(keys, results, mask);
        timer.stop("query");

        cudaDeviceSynchronize();
      });

  return 0;
}
 No newline at end of file
+0 −35
Original line number Diff line number Diff line
#include "BTreeContainer/Default.hpp"
#include "TNL/Devices/Cuda.h"
#include "benchmark.hpp"

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

  using KeyType = uint64_t;
  using ValueType = uint64_t;
  const size_t Order = 15;

  Benchmark::execute<Benchmark::Device::Host, KeyType>(
      "btree_host_v4_link", [](auto &timer, auto input) {
        size_t size = getContainerSize(input.size(), Order);
        BTreeContainer<KeyType, ValueType, Order, TNL::Devices::Host> container(size);

        Containers::Array<KeyType, TNL::Devices::Host> keys(input);
        Containers::Array<ValueType, TNL::Devices::Host> values(input);
        container.init();

        timer.start();
        container.insert(keys, values);
        timer.stop("insert");

        values.reset();

        Containers::Array<ValueType, TNL::Devices::Host> results(input.size());
        Containers::Array<bool, TNL::Devices::Host> mask(input.size());

        timer.start();
        container.find(keys, results, mask);
        timer.stop("query");
      });

  return 0;
}
 No newline at end of file
Loading