Flat binary search over APU (#6676)

Signed-off-by: ezeharia <ezeharia@gsitechnology.com>

solve issue Support search over APU board #5202
support Tanimoto/Hamming Flat binary search over APU device .
Search over APU can be done for FAISS_BIN_IDMAP engaine type only.
Dependencies : build with FPGA (- a ) and APU (-w ) . build must contain FPGA flag .
example : ./build.sh -a -w
*** search is not possible without APU device conneted to a server .**
Resolves: #5202
pull/7307/head
Eitan Zcharia 2021-07-23 06:06:17 +03:00 committed by GitHub
parent 91af6ced97
commit 12f1d3c23c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 1115 additions and 8 deletions

View File

@ -158,6 +158,12 @@ if (MILVUS_FPGA_VERSION)
else ()
message(STATUS "Building Milvus CPU version")
endif ()
if (MILVUS_APU_VERSION)
message(STATUS "Building Milvus APU version")
add_compile_definitions("MILVUS_APU_VERSION")
else ()
message(STATUS "Building Milvus CPU version")
endif ()
if (MILVUS_GPU_VERSION)
message(STATUS "Building Milvus GPU version")
add_compile_definitions("MILVUS_GPU_VERSION")
@ -215,6 +221,11 @@ if (MILVUS_FPGA_VERSION)
else ()
set(FPGA_ENABLE "false")
endif ()
if (MILVUS_APU_VERSION)
set(APU_ENABLE "true")
else ()
set(APU_ENABLE "false")
endif ()
if (MILVUS_GPU_VERSION)
set(GPU_ENABLE "true")
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/conf/server_config.template

View File

@ -12,12 +12,13 @@ RUN_CPPLINT="OFF"
CUDA_COMPILER=/usr/local/cuda/bin/nvcc
GPU_VERSION="OFF" #defaults to CPU version
FPGA_VERSION="OFF"
APU_VERSION="OFF"
WITH_MKL="OFF"
WITH_PROMETHEUS="ON"
FIU_ENABLE="OFF"
BUILD_OPENBLAS="ON"
while getopts "p:d:t:f:ulrcgahzmei" arg; do
while getopts "p:d:t:f:ulrcgahzmeiw" arg; do
case $arg in
p)
INSTALL_PREFIX=$OPTARG
@ -62,6 +63,9 @@ while getopts "p:d:t:f:ulrcgahzmei" arg; do
a)
FPGA_VERSION="ON"
;;
w)
APU_VERSION="ON"
;;
h) # help
echo "
@ -79,6 +83,7 @@ parameter:
-e: build without prometheus(default: OFF)
-i: build FIU_ENABLE(default: OFF)
-a: build FPGA(default: OFF)
-w: build APU(default: OFF )
-h: help
usage:
@ -114,6 +119,7 @@ CMAKE_CMD="cmake \
-DENABLE_CPU_PROFILING=${PROFILING} \
-DMILVUS_GPU_VERSION=${GPU_VERSION} \
-DMILVUS_FPGA_VERSION=${FPGA_VERSION} \
-DMILVUS_APU_VERSION=${APU_VERSION} \
-DFAISS_WITH_MKL=${WITH_MKL} \
-DMILVUS_WITH_PROMETHEUS=${WITH_PROMETHEUS} \
-DMILVUS_WITH_FIU=${FIU_ENABLE} \

View File

@ -46,6 +46,9 @@ set_option_category("Milvus Build Option")
define_option(MILVUS_GPU_VERSION "Build GPU version" OFF)
define_option(MILVUS_FPGA_VERSION "Build FPGA version" OFF)
define_option(MILVUS_APU_VERSION "Build APU version" OFF)
#----------------------------------------------------------------------
set_option_category("Thirdparty")

View File

@ -24,7 +24,8 @@ set(MILVUS_THIRDPARTY_DEPENDENCIES
fiu
AWS
oatpp
armadillo)
armadillo
apu)
message(STATUS "Using ${MILVUS_DEPENDENCY_SOURCE} approach to find dependencies")
@ -64,6 +65,8 @@ macro(build_dependency DEPENDENCY_NAME)
build_aws()
elseif("${DEPENDENCY_NAME}" STREQUAL "armadillo")
build_armadillo()
elseif("${DEPENDENCY_NAME}" STREQUAL "apu")
build_apu()
else ()
message(FATAL_ERROR "Unknown thirdparty dependency to build: ${DEPENDENCY_NAME}")
endif ()
@ -339,6 +342,12 @@ else ()
set(ARMADILLO_SOURCE_URL "https://gitlab.com/conradsnicta/armadillo-code/-/archive/9.900.x/armadillo-code-9.900.x.tar.gz")
endif ()
if (DEFINED ENV{MILVUS_APU_URL})
set(APU_SOURCE_URL "$ENV{MILVUS_APU_URL}")
else ()
set(APU_SOURCE_URL "${PROJECT_SOURCE_DIR}/thirdparty/gsi/gsl_sources_milvus/2.8.0/gsi_release_2_8_0.tar.gz")
endif ()
# ----------------------------------------------------------------------
# Google gtest
@ -1148,3 +1157,47 @@ if(MILVUS_FPGA_VERSION)
${INSTALL_DIR}/lib/libarmadillo.so
DESTINATION lib)
endif()
# ----------------------------------------------------------------------
# APU-GSI
macro(build_apu)
message(STATUS "Building APU from source")
set(APU_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/apu_ep-prefix/src/apu_ep")
set(APU_SHARED_LIB "${APU_PREFIX}/lib/libgsl.so")
set (APU_LIBS "${APU_PREFIX}/lib")
set(APU_INCLUDE_DIR "${APU_PREFIX}/include")
externalproject_add(apu_ep
URL
${APU_SOURCE_URL}
${EP_LOG_OPTIONS}
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND "")
file(MAKE_DIRECTORY ${APU_INCLUDE_DIR})
add_library(apu SHARED IMPORTED)
set_target_properties(apu
PROPERTIES
IMPORTED_GLOBAL TRUE
IMPORTED_LOCATION "${APU_SHARED_LIB}"
INTERFACE_INCLUDE_DIRECTORIES "${APU_INCLUDE_DIR}")
add_dependencies(apu apu_ep)
endmacro()
if (MILVUS_APU_VERSION)
resolve_dependency(apu)
get_target_property(APU_INCLUDE_DIR apu INTERFACE_INCLUDE_DIRECTORIES)
include_directories(SYSTEM ${APU_INCLUDE_DIR})
install(FILES
${APU_PREFIX}/lib/libgsl.so
DESTINATION lib)
endif ()

View File

@ -178,6 +178,19 @@ fpga:
search_devices:
- fpga0
#----------------------+------------------------------------------------------------+------------+-----------------+
# APU Config | Description | Type | Default |
#----------------------+------------------------------------------------------------+------------+-----------------+
# enable | Use APU devices or not. | Boolean | false |
#----------------------+------------------------------------------------------------+------------+-----------------+
# apu_devices | The number of APU devices exist for computation. | DeviceList | 1 |
#----------------------+------------------------------------------------------------+------------+-----------------+
apu:
enable: @APU_ENABLE@
search_devices: 1
#----------------------+------------------------------------------------------------+------------+-----------------+
# Logs Config | Description | Type | Default |
#----------------------+------------------------------------------------------------+------------+-----------------+

View File

@ -17,6 +17,7 @@
#include <vector>
#include <faiss/utils/ConcurrentBitset.h>
//#include <scheduler/job/SearchJob.h>
#include "query/GeneralQuery.h"
#include "utils/Json.h"
@ -100,6 +101,9 @@ class ExecutionEngine {
virtual Status
CopyToCpu() = 0;
virtual Status
CopyToApu(uint32_t i) = 0;
// virtual std::shared_ptr<ExecutionEngine>
// Clone() = 0;

View File

@ -38,6 +38,11 @@
#include "knowhere/index/vector_index/fpga/IndexFPGAIVFPQ.h"
#include "knowhere/index/vector_index/fpga/utils.h"
#endif
#ifdef MILVUS_APU_VERSION
#include <knowhere/index/vector_index/fpga/ApuInst.h>
#include <knowhere/index/vector_index/fpga/GsiHammingIndex.h>
#include <knowhere/index/vector_index/fpga/GsiTanimotoIndex.h>
#endif
#ifdef MILVUS_GPU_VERSION
#include "knowhere/index/vector_index/gpu/GPUIndex.h"
#include "knowhere/index/vector_index/gpu/IndexIVFSQHybrid.h"
@ -59,7 +64,6 @@
namespace milvus {
namespace engine {
namespace {
Status
@ -636,6 +640,34 @@ ExecutionEngineImpl::CopyToFpga() {
return Status::OK();
}
Status
ExecutionEngineImpl::CopyToApu(uint32_t row_count) {
#ifdef MILVUS_APU_VERSION
auto cache_index_ =
std::static_pointer_cast<knowhere::VecIndex>(cache::FpgaCacheMgr::GetInstance()->GetItem(location_));
bool already_in_cache = (cache_index_ != nullptr);
if (!already_in_cache) {
cache::FpgaCacheMgr::GetInstance()->ClearCache(); // clear cache to support cache switch .
std::shared_ptr<knowhere::GsiBaseIndex> gsi_index;
// factory is needed here
if (metric_type_ == MetricType::HAMMING)
gsi_index = std::make_shared<knowhere::GsiHammingIndex>(dim_);
else
gsi_index = std::make_shared<knowhere::GsiTanimotoIndex>(dim_);
gsi_index->SetUids(index_->GetUids());
gsi_index->CopyIndexToFpga(row_count, location_);
index_ = gsi_index;
FpgaCache();
} else {
index_ = cache_index_;
}
#endif
return Status::OK();
}
ExecutionEnginePtr
ExecutionEngineImpl::BuildIndex(const std::string& location, EngineType engine_type) {
LOG_ENGINE_DEBUG_ << "Build index file: " << location << " from: " << location_;
@ -838,6 +870,5 @@ ExecutionEngineImpl::Init() {
return Status::OK();
#endif
}
} // namespace engine
} // namespace milvus

View File

@ -60,6 +60,9 @@ class ExecutionEngineImpl : public ExecutionEngine {
Status
CopyToFpga() override;
Status
CopyToApu(uint32_t row_count) override;
#if 0
Status
GetVectorByID(const int64_t id, float* vector, bool hybrid) override;

View File

@ -70,6 +70,11 @@ if (MILVUS_FPGA_VERSION OR KNOWHERE_FPGA_VERSION)
else ()
message(STATUS "Building Knowhere CPU version")
endif ()
if (MILVUS_APU_VERSION OR KNOWHERE_APU_VERSION)
add_compile_definitions("MILVUS_APU_VERSION")
else ()
message(STATUS "Building Knowhere CPU version")
endif ()
if (MILVUS_GPU_VERSION OR KNOWHERE_GPU_VERSION)
message(STATUS "Building Knowhere GPU version")
add_compile_definitions("MILVUS_GPU_VERSION")

View File

@ -47,6 +47,14 @@ if (MILVUS_FPGA_VERSION)
else ()
define_option(KNOWHERE_FPGA_VERSION "Build FPGA version" OFF)
endif ()
#-------------------------------------------------
set_option_category("APU version")
if (MILVUS_APU_VERSION)
define_option(KNOWHERE_APU_VERSION "Build APU version" ON)
else ()
define_option(KNOWHERE_APU_VERSION "Build APU version" OFF)
endif ()
#----------------------------------------------------------------------
set_option_category("GPU version")

View File

@ -80,16 +80,35 @@ if (MILVUS_FPGA_VERSION)
armadillo
${depend_libs}
)
set(index_srcs ${index_srcs}
knowhere/index/vector_index/fpga/Fpga.cpp
knowhere/index/vector_index/fpga/IndexFPGAIVFPQ.cpp
knowhere/index/vector_index/fpga/xilinx_c.cpp
knowhere/index/vector_index/fpga/utils.cpp
knowhere/index/vector_index/fpga/FpgaInst.cpp
)
)
endif ()
if (MILVUS_APU_VERSION)
set(depend_libs
apu
${depend_libs}
)
set(index_srcs ${index_srcs}
knowhere/index/vector_index/fpga/GsiBaseIndex.cpp
knowhere/index/vector_index/fpga/GsiHammingIndex.cpp
knowhere/index/vector_index/fpga/GsiTanimotoIndex.cpp
knowhere/index/vector_index/fpga/Apu.cpp
knowhere/index/vector_index/fpga/ApuInst.cpp
)
endif ()
if (KNOWHERE_GPU_VERSION)
include_directories(${CUDA_INCLUDE_DIRS})
link_directories("${CUDA_TOOLKIT_ROOT_DIR}/lib64")
@ -109,7 +128,7 @@ if (KNOWHERE_GPU_VERSION)
knowhere/index/vector_index/gpu/IndexIVFSQHybrid.cpp
knowhere/index/vector_index/helpers/Cloner.cpp
knowhere/index/vector_index/helpers/FaissGpuResourceMgr.cpp
)
)
endif ()

View File

@ -0,0 +1,248 @@
// Copyright (C) 2019-2020 Zilliz. 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 "knowhere/index/vector_index/fpga/Apu.h"
#include <chrono>
#include <fstream>
#include <string>
#include "knowhere/common/Exception.h"
#include "utils/Log.h"
using milvus::GetThreadName;
using milvus::LogOut;
using milvus::knowhere::KnowhereException;
namespace Fpga {
ApuInterface::ApuInterface() {
InitApu();
}
void
ApuInterface::InitApu() {
unsigned int num_existing_cards = 0;
unsigned int num_req_cards = 8;
gsi_prod_status_t status = gdl_init();
if (status != GSI_SUCCESS) {
KNOWHERE_THROW_MSG("Apu init failed. error code : " + std::to_string(status));
}
status = gdl_context_count_get(&num_existing_cards);
if (status != GSI_SUCCESS) {
KNOWHERE_THROW_MSG("Apu failed to get number of cards. error code : " + std::to_string(status));
}
struct gdl_context_desc cards_desc[GDL_MAX_NUM_CONTEXTS] = {0};
status = gdl_context_desc_get(cards_desc, num_req_cards);
if (status != GSI_SUCCESS) {
KNOWHERE_THROW_MSG("Apu failed to get cards description. error code : " + std::to_string(status));
}
unsigned int num_ready_cards = 0;
gdl_context_handle_t cards_ids[GDL_MAX_NUM_CONTEXTS] = {0};
for (unsigned int i = 0; i < num_existing_cards; ++i) {
if (cards_desc[i].status == GDL_CONTEXT_READY) {
cards_ids[num_ready_cards] = cards_desc[i].ctx_id;
++num_ready_cards;
}
}
num_req_cards = (num_req_cards > num_ready_cards) ? num_ready_cards : num_req_cards;
LOG_ENGINE_DEBUG_ << "Apu available cards: " << num_req_cards;
gsl_ctx_ = NULL;
unsigned int idx_first_occupied_card = 0;
uint32_t max_num_threads = 0;
while ((idx_first_occupied_card + num_req_cards) <= num_ready_cards) {
status = gsl_create_context(&gsl_ctx_, &cards_ids[idx_first_occupied_card], num_req_cards, max_num_threads);
if (0 == status) {
break;
} else if (ENOSYS == status) {
break;
}
++idx_first_occupied_card;
}
if (status != GSI_SUCCESS && status != ENOSYS) {
KNOWHERE_THROW_MSG("Apu failed to create context. error code : " + std::to_string(status));
}
}
void
ApuInterface::PopulateApuParams(uint32_t dimention, uint32_t row_count, const std::string location) {
num_bfeatures_ = dimention;
num_records_ = row_count;
location_ = location;
num_bytes_in_rec_ = num_bfeatures_ / CHAR_BITS;
}
void
ApuInterface::createBdb() {
size_t db_size = num_bytes_in_rec_ * num_records_;
bdb_ = {.row_size = num_bfeatures_,
.row_stride = num_bytes_in_rec_,
.num_rows = num_records_,
.rows_u1 = malloc(db_size)};
std::string records_file_name = location_ + ".rv";
char* rec_file_name = &records_file_name[0];
char* records_file_c = &(rec_file_name)[0];
size_t file_size = 0;
std::ifstream fin(records_file_c, std::ifstream::in | std::ifstream::binary);
if (fin.is_open()) {
fin.seekg(8, std::ios::beg);
file_size = fin.tellg();
fin.read((char*)bdb_.rows_u1, db_size);
fin.close();
}
int status = 0;
bdbh_ = 0;
status = gsl_create_bdb(gsl_ctx_, &bdbh_, &bdb_);
if (status != GSI_SUCCESS) {
KNOWHERE_THROW_MSG("Apu failed create Bdb. error code : " + std::to_string(status));
}
}
void
ApuInterface::loadHammingSessionToApu() {
session_hdl_ = NULL;
int status = 0;
status = gsl_flat_hamming_create_search_session(gsl_ctx_, &session_hdl_, &hamming_desc_);
if (status != GSI_SUCCESS) {
KNOWHERE_THROW_MSG("Apu failed to create search session. error code : " + std::to_string(status));
}
status = gsl_search_in_focus(session_hdl_);
if (status != GSI_SUCCESS) {
KNOWHERE_THROW_MSG("Apu failed to focus search session. error code : " + std::to_string(status));
}
}
void
ApuInterface::loadTanimotoSessionToApu() {
session_hdl_ = NULL;
int status = 0;
status = gsl_flat_tanimoto_create_search_session(gsl_ctx_, &session_hdl_, &tanimoto_desc_);
if (status != GSI_SUCCESS) {
KNOWHERE_THROW_MSG("Apu failed to create search session. error code : " + std::to_string(status));
}
status = gsl_search_in_focus(session_hdl_);
if (status != GSI_SUCCESS) {
KNOWHERE_THROW_MSG("Apu failed to focus search session. error code : " + std::to_string(status));
}
}
void
ApuInterface::Query(gsl_matrix_u32& indices, gsl_matrix_f32& distances, gsl_matrix_u1& queries, APU_METRIC_TYPE type) {
int status;
switch (type) {
case APU_METRIC_TYPE::TANIMOTO: {
auto start_t = std::chrono::steady_clock::now();
status = gsl_flat_tanimoto_search_u1(session_hdl_, &indices, &distances, &queries);
auto end_t = std::chrono::steady_clock::now();
LOG_ENGINE_DEBUG_ << "Apu search time in microseconds: "
<< std::chrono::duration_cast<std::chrono::microseconds>(end_t - start_t).count()
<< " µs";
break;
}
case APU_METRIC_TYPE::HAMMING:
auto start_h = std::chrono::steady_clock::now();
status = gsl_flat_hamming_search_u1(session_hdl_, &indices, &distances, &queries);
auto end_h = std::chrono::steady_clock::now();
LOG_ENGINE_DEBUG_ << "Apu search time in microseconds: "
<< std::chrono::duration_cast<std::chrono::microseconds>(end_h - start_h).count()
<< " µs";
break;
}
if (status != GSI_SUCCESS) {
KNOWHERE_THROW_MSG("Apu query Failed. error code : " + std::to_string(status));
}
}
bool
ApuInterface::isLoadNeeded(std::string cur_location) {
if (location_ == "") {
return true;
} else if (cur_location != location_) {
cleanApuResources(APU_CLEAN_TYPE::NEW_DB);
return true;
}
return false;
}
ApuInterface::~ApuInterface() {
cleanApuResources(APU_CLEAN_TYPE::FULL);
}
void
ApuInterface::cleanApuResources(APU_CLEAN_TYPE type) {
switch (type) {
case APU_CLEAN_TYPE::FULL:
if (session_hdl_)
gsl_search_session_destroy(session_hdl_);
if (bdbh_)
gsl_destroy_bdb(bdbh_);
gdl_exit();
break;
case APU_CLEAN_TYPE::SESSION_HDL:
if (session_hdl_)
gsl_search_session_destroy(session_hdl_);
break;
case APU_CLEAN_TYPE::BDBH:
gsl_destroy_bdb(bdbh_);
break;
case APU_CLEAN_TYPE::NEW_DB:
if (session_hdl_)
gsl_search_session_destroy(session_hdl_);
if (bdbh_)
gsl_destroy_bdb(bdbh_);
break;
}
}
void
ApuInterface::loadSeesionToApu(APU_METRIC_TYPE type) {
switch (type) {
case APU_METRIC_TYPE::TANIMOTO: {
tanimoto_desc_ = {.typical_num_queries = NUM_QUERIES,
.max_num_queries = NUM_QUERIES,
.tanimoto_bdbh = bdbh_,
.max_k = topK_};
loadTanimotoSessionToApu();
}
case APU_METRIC_TYPE::HAMMING: {
hamming_desc_ = {.typical_num_queries = NUM_QUERIES,
.max_num_queries = NUM_QUERIES,
.encoding = NULL,
.hamming_bdbh = bdbh_,
.max_k = topK_,
.rerank = NULL};
loadHammingSessionToApu();
}
}
}
uint32_t
ApuInterface::getTopK() const {
return topK_;
}
void
ApuInterface::setTopK(uint32_t topK) {
topK_ = topK;
}
} // namespace Fpga

View File

@ -0,0 +1,113 @@
// Copyright (C) 2019-2020 Zilliz. 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.
#ifdef MILVUS_APU_VERSION
#ifndef APU_H
#define APU_H
#include <cstdint>
#include <cstdio>
#include <iostream>
#include <memory>
#include <string>
extern "C" {
#include <gsi/libgdl.h>
#include <gsi/libgsl.h>
#include <gsi/libgsl_flat_tanimoto.h>
#include <gsi/libgsl_matrix.h>
}
#define NUM_QUERIES (100)
#define CHAR_BITS (8)
#define INIT_K (50)
#define GSI_SUCCESS (0)
namespace Fpga {
enum class APU_CLEAN_TYPE {
SESSION_HDL = 0,
BDBH = 1,
FULL,
NEW_DB,
};
enum class APU_METRIC_TYPE {
HAMMING = 0,
TANIMOTO = 1,
};
class ApuInterface {
public:
ApuInterface();
~ApuInterface();
void
PopulateApuParams(uint32_t dimention, uint32_t row_count, const std::string location);
void
createBdb();
void
loadSeesionToApu(APU_METRIC_TYPE type);
void
Query(gsl_matrix_u32& indices, gsl_matrix_f32& distances, gsl_matrix_u1& queries, APU_METRIC_TYPE type);
bool
isLoadNeeded(std::string location_);
void
cleanApuResources(APU_CLEAN_TYPE type);
uint32_t
getTopK() const;
void
setTopK(uint32_t topK);
private:
gsl_bdb_hdl bdbh_ = NULL;
void
InitApu();
void
loadHammingSessionToApu();
void
loadTanimotoSessionToApu();
std::string location_ = "";
uint32_t num_records_ = 0;
uint32_t num_bfeatures_ = 0;
uint32_t num_bytes_in_rec_ = 0;
gsl_context gsl_ctx_;
struct gsl_matrix_u1 bdb_;
gsl_search_session_hdl session_hdl_;
gsl_flat_hamming_desc hamming_desc_;
gsl_flat_tanimoto_desc tanimoto_desc_;
uint32_t topK_ = INIT_K;
}; // namespace ApuInterface
using ApuInterfacePtr = std::shared_ptr<ApuInterface>;
} // namespace Fpga
#endif // MILVUS_ENGINE_APU_H
#endif

View File

@ -0,0 +1,21 @@
// Copyright (C) 2019-2020 Zilliz. 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.
#ifdef MILVUS_APU_VERSION
#include "knowhere/index/vector_index/fpga/ApuInst.h"
namespace Fpga {
ApuInterfacePtr ApuInst::instance = nullptr;
std::mutex ApuInst::mutex_;
} // namespace Fpga
#endif

View File

@ -0,0 +1,39 @@
// Copyright (C) 2019-2020 Zilliz. 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.
#ifdef MILVUS_APU_VERSION
#pragma once
#include <memory>
#include <mutex>
#include "Apu.h"
namespace Fpga {
class ApuInst {
public:
static ApuInterfacePtr
getInstance() {
if (instance == nullptr) {
std::lock_guard<std::mutex> lock(mutex_);
if (instance == nullptr) {
instance = std::make_shared<ApuInterface>();
}
}
return instance;
}
private:
static ApuInterfacePtr instance;
static std::mutex mutex_;
};
} // namespace Fpga
#endif

View File

@ -0,0 +1,130 @@
// Copyright (C) 2019-2020 Zilliz. 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 "knowhere/index/vector_index/fpga/GsiBaseIndex.h"
#include <scheduler/job/SearchJob.h>
#include <scheduler/task/SearchTask.h>
#include <fstream>
namespace milvus {
namespace knowhere {
GsiBaseIndex::GsiBaseIndex(uint32_t dim) {
num_bfeatures_ = dim;
}
GsiBaseIndex::~GsiBaseIndex() {
// freeAllocatedMem();
}
void
GsiBaseIndex::AllocateMemory(const DatasetPtr& dataset, const Config& config) {
// allocating memory for search queries
setQueriesInfo(dataset, config);
// allocating memory for result indices
setResultIndicesStruct();
// allocating memory for result distances
setResultDistancesStruct();
}
void
GsiBaseIndex::setResultDistancesStruct() {
distances_ = {.row_size = topK_,
.row_stride = topK_ * sizeof(float),
.num_rows = num_queries_,
.rows_f32 = (float*)calloc(topK_ * num_queries_, sizeof(float))};
if (NULL == distances_.rows_f32) {
// ERROR("no memory to allocate.");
}
// heap_allocations[counter_heap_allocations++] = (void*)distances_.rows_f32;
}
void
GsiBaseIndex::setResultIndicesStruct() {
indices_ = {.row_size = topK_,
.row_stride = topK_ * sizeof(uint32_t),
.num_rows = num_queries_,
.rows_u32 = (uint32_t*)calloc(topK_ * num_queries_, sizeof(uint32_t))};
if (NULL == indices_.rows_u32) {
// ERROR("no memory to allocate.");
}
// heap_allocations[counter_heap_allocations++] = (void*)indices_.rows_u32;
}
void
GsiBaseIndex::setQueriesInfo(const DatasetPtr& dataset, const Config& config) {
queries_ = {.row_size = num_bfeatures_,
.row_stride = num_bytes_in_rec_,
.num_rows = num_queries_,
.rows_u1 = queries_.rows_u1 = (void*)dataset->Get<const void*>(meta::TENSOR)};
// if (NULL == queries_.rows_u1){}
}
void
GsiBaseIndex::freeAllocatedMem() {
std::cout << "cleaning APU allocation" << std::endl;
// free((void*)indices_.rows_u32);
// free((void*)distances_.rows_f32);
for (size_t i = 0; i < counter_heap_allocations; i++) free(heap_allocations[i]);
}
int64_t*
GsiBaseIndex::convertToInt64_t(gsl_matrix_u32* indices, int64_t* ids_int64) {
uint32_t* indices_buff = NULL;
int64_t* indices_buff_int64 = NULL;
uint32_t stride_64 = topK_ * sizeof(int64_t);
for (unsigned int i = 0; i < num_queries_; ++i) {
indices_buff = (uint32_t*)((char*)indices->rows_u32 + indices->row_stride * i);
indices_buff_int64 = (int64_t*)((char*)ids_int64 + stride_64 * i);
for (unsigned int j = 0; j < topK_; ++j) indices_buff_int64[j] = (int64_t)indices_buff[j];
}
return ids_int64;
}
BinarySet
GsiBaseIndex::Serialize(const Config& config) {
return BinarySet();
}
void
GsiBaseIndex::Load(const BinarySet& set) {
}
void
GsiBaseIndex::Train(const DatasetPtr& dataset, const Config& config) {
}
void
GsiBaseIndex::AddWithoutIds(const DatasetPtr& dataset, const Config& config) {
}
int64_t
GsiBaseIndex::Dim() {
return num_bfeatures_;
}
int64_t
GsiBaseIndex::Count() {
return 0;
}
int64_t
GsiBaseIndex::Size() {
return index_size_;
}
} // namespace knowhere
} // namespace milvus

View File

@ -0,0 +1,110 @@
// Copyright (C) 2019-2020 Zilliz. 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.
#ifdef MILVUS_APU_VERSION
#pragma once
#include "index/knowhere/knowhere/index/vector_index/VecIndex.h"
#include "knowhere/index/vector_index/helpers/IndexParameter.h"
#include "scheduler/task/Task.h"
#include <string>
extern "C" {
#include <gsi/libgdl.h>
#include <gsi/libgsl.h>
#include <gsi/libgsl_flat_tanimoto.h>
#include <gsi/libgsl_matrix.h>
}
#define NUM_QUERIES (100)
#define INIT_K (50)
#define MAX_HEAP_ALLOCATIONS (4)
#define O_RDONLY 00
namespace milvus {
namespace knowhere {
class GsiBaseIndex : public VecIndex {
public:
uint32_t topK_ = INIT_K;
uint32_t num_queries_;
uint32_t num_bfeatures_;
uint32_t num_bytes_in_rec_;
int64_t index_size_;
void* heap_allocations[MAX_HEAP_ALLOCATIONS] = {0};
unsigned int counter_heap_allocations;
virtual int64_t
Size();
BinarySet
Serialize(const Config& config) override;
void
Load(const BinarySet& set) override;
void
Train(const DatasetPtr& dataset, const Config& config) override;
void
AddWithoutIds(const DatasetPtr& dataset, const Config& config) override;
int64_t
Dim() override;
int64_t
Count() override;
explicit GsiBaseIndex(uint32_t dim);
~GsiBaseIndex();
virtual void
CopyIndexToFpga(uint32_t row_count, const std::string& location) = 0;
virtual DatasetPtr
Query(const DatasetPtr& dataset, const Config& config, faiss::ConcurrentBitsetPtr blacklist) = 0;
protected:
void
setResultDistancesStruct();
struct gsl_matrix_u32 indices_;
struct gsl_matrix_f32 distances_;
struct gsl_matrix_u1 queries_;
void
AllocateMemory(const DatasetPtr& dataset, const Config& config);
void
setQueriesInfo(const DatasetPtr& dataset, const Config& config);
void
setResultIndicesStruct();
int64_t*
convertToInt64_t(gsl_matrix_u32* indices, int64_t* ids_int64);
void
freeAllocatedMem();
};
} // namespace knowhere
} // namespace milvus
#endif

View File

@ -0,0 +1,61 @@
// Copyright (C) 2019-2020 Zilliz. 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.
#ifdef MILVUS_APU_VERSION
#include "knowhere/index/vector_index/fpga/GsiHammingIndex.h"
#include "ApuInst.h"
#include "scheduler/task/SearchTask.h"
#include <string>
namespace milvus {
namespace knowhere {
void
GsiHammingIndex::CopyIndexToFpga(uint32_t row_count, const std::string& location) {
num_bfeatures_ = Dim();
num_bytes_in_rec_ = num_bfeatures_ / CHAR_BITS;
index_size_ = row_count * num_bytes_in_rec_;
auto apu = Fpga::ApuInst::getInstance();
apu->cleanApuResources(Fpga::APU_CLEAN_TYPE::NEW_DB);
apu->PopulateApuParams(num_bfeatures_, row_count, location);
apu->createBdb();
apu->loadSeesionToApu(Fpga::APU_METRIC_TYPE::HAMMING);
}
DatasetPtr
GsiHammingIndex::Query(const DatasetPtr& dataset, const Config& config, faiss::ConcurrentBitsetPtr blacklist) {
auto apu = Fpga::ApuInst::getInstance();
num_bfeatures_ = Dim();
num_queries_ = static_cast<uint32_t>(dataset.get()->Get<int64_t>(meta::ROWS));
num_bytes_in_rec_ = num_bfeatures_ / CHAR_BITS;
topK_ = config[meta::TOPK];
apu->setTopK(topK_);
AllocateMemory(dataset, config);
apu->Query(indices_, distances_, queries_, Fpga::APU_METRIC_TYPE::HAMMING);
auto ret_ds = std::make_shared<Dataset>();
int64_t* ids_int64 = (int64_t*)calloc(topK_ * num_queries_, sizeof(int64_t));
convertToInt64_t(&indices_, ids_int64);
ret_ds->Set(meta::IDS, ids_int64);
ret_ds->Set(meta::DISTANCE, distances_.rows_f32);
free((void*)indices_.rows_u32);
return ret_ds;
}
#endif
} // namespace knowhere
} // namespace milvus

View File

@ -0,0 +1,38 @@
// Copyright (C) 2019-2020 Zilliz. 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.
#ifdef MILVUS_APU_VERSION
#pragma once
#include "Apu.h"
#include "GsiBaseIndex.h"
#include <memory>
#include <string>
namespace milvus {
namespace knowhere {
class GsiHammingIndex : public GsiBaseIndex {
public:
explicit GsiHammingIndex(uint32_t dim) : GsiBaseIndex(dim) {
index_type_ = IndexEnum::INDEX_FAISS_BIN_IDMAP;
}
void
CopyIndexToFpga(uint32_t row_count, const std::string& location) override;
DatasetPtr
Query(const DatasetPtr& dataset, const Config& config, faiss::ConcurrentBitsetPtr blacklist) override;
};
} // namespace knowhere
} // namespace milvus
#endif

View File

@ -0,0 +1,57 @@
// Copyright (C) 2019-2020 Zilliz. 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 "knowhere/index/vector_index/fpga/GsiTanimotoIndex.h"
#include "ApuInst.h"
#include "scheduler/task/SearchTask.h"
namespace milvus {
namespace knowhere {
void
GsiTanimotoIndex::CopyIndexToFpga(uint32_t row_count, const std::string& location) {
num_bfeatures_ = Dim();
num_bytes_in_rec_ = num_bfeatures_ / CHAR_BITS;
index_size_ = row_count * num_bytes_in_rec_;
auto apu = Fpga::ApuInst::getInstance();
apu->cleanApuResources(Fpga::APU_CLEAN_TYPE::NEW_DB);
apu->PopulateApuParams(num_bfeatures_, row_count, location);
apu->createBdb();
apu->loadSeesionToApu(Fpga::APU_METRIC_TYPE::TANIMOTO);
}
DatasetPtr
GsiTanimotoIndex::Query(const DatasetPtr& dataset, const Config& config, faiss::ConcurrentBitsetPtr blacklist) {
auto apu = Fpga::ApuInst::getInstance();
num_bfeatures_ = Dim();
num_queries_ = static_cast<uint32_t>(dataset.get()->Get<int64_t>(meta::ROWS));
num_bytes_in_rec_ = num_bfeatures_ / CHAR_BITS;
topK_ = config[meta::TOPK];
apu->setTopK(topK_);
AllocateMemory(dataset, config);
apu->Query(indices_, distances_, queries_, Fpga::APU_METRIC_TYPE::TANIMOTO);
auto ret_ds = std::make_shared<Dataset>();
int64_t* ids_int64 = (int64_t*)calloc(topK_ * num_queries_, sizeof(int64_t));
convertToInt64_t(&indices_, ids_int64);
ret_ds->Set(meta::IDS, ids_int64);
ret_ds->Set(meta::DISTANCE, distances_.rows_f32);
free((void*)indices_.rows_u32);
return ret_ds;
}
} // namespace knowhere
} // namespace milvus

View File

@ -0,0 +1,38 @@
// Copyright (C) 2019-2020 Zilliz. 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.
#ifdef MILVUS_APU_VERSION
#pragma once
#include "Apu.h"
#include "GsiBaseIndex.h"
#include <memory>
#include <string>
namespace milvus {
namespace knowhere {
class GsiTanimotoIndex : public GsiBaseIndex {
public:
explicit GsiTanimotoIndex(uint32_t dim) : GsiBaseIndex(dim) {
index_type_ = IndexEnum::INDEX_FAISS_BIN_IDMAP;
}
void
CopyIndexToFpga(uint32_t row_count, const std::string& location) override;
DatasetPtr
Query(const DatasetPtr& dataset, const Config& config, faiss::ConcurrentBitsetPtr blacklist) override;
};
} // namespace knowhere
} // namespace milvus
#endif

View File

@ -29,7 +29,9 @@
#include <mutex>
#include <string>
#include <vector>
#ifdef MILVUS_APU_VERSION
#include "selector/ApuPass.h"
#endif
namespace milvus {
namespace scheduler {
@ -95,10 +97,15 @@ class OptimizerInst {
std::lock_guard<std::mutex> lock(mutex_);
if (instance == nullptr) {
std::vector<PassPtr> pass_list;
#ifdef MILVUS_APU_VERSION
pass_list.push_back(std::make_shared<ApuPass>());
#endif
#ifdef MILVUS_GPU_VERSION
bool enable_gpu = false;
server::Config& config = server::Config::GetInstance();
config.GetGpuResourceConfigEnable(enable_gpu);
if (enable_gpu) {
std::vector<int64_t> build_gpus;
std::vector<int64_t> search_gpus;

View File

@ -13,6 +13,7 @@
#include <utility>
#include "utils/Log.h"
namespace milvus {
namespace scheduler {
@ -29,7 +30,11 @@ FpgaResource::FpgaResource(std::string name, uint64_t device_id, bool enable_exe
void
FpgaResource::LoadFile(TaskPtr task) {
LOG_ENGINE_DEBUG_ << "jack: LoadFile loadType cpu2fpga";
#ifdef MILVUS_APU_VERSION
task->Load(LoadType::CPU2APU, 0);
#else
task->Load(LoadType::CPU2FPGA, 0);
#endif
}
void

View File

@ -0,0 +1,44 @@
// Copyright (C) 2019-2020 Zilliz. 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
#ifdef MILVUS_APU_VERSION
#include "scheduler/selector/ApuPass.h"
#include "scheduler/SchedInst.h"
#include "scheduler/tasklabel/SpecResLabel.h"
namespace milvus {
namespace scheduler {
void
ApuPass::Init() {
}
bool
ApuPass::Run(const TaskPtr& task) {
auto task_type = task->Type();
auto search_task = std::static_pointer_cast<XSearchTask>(task);
if (task_type != TaskType::SearchTask ||
search_task->file_->engine_type_ != (int)engine::EngineType::FAISS_BIN_IDMAP) {
return false;
}
auto apu = ResMgrInst::GetInstance()->GetResource(ResourceType::FPGA, 0);
auto lable = std::make_shared<SpecResLabel>(apu);
task->label() = lable;
return true;
}
} // namespace scheduler
} // namespace milvus
#endif

View File

@ -0,0 +1,35 @@
// Copyright (C) 2019-2020 Zilliz. 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
#ifdef MILVUS_APU_VERSION
#pragma once
#include "Pass.h"
#include <memory>
namespace milvus {
namespace scheduler {
class ApuPass : public Pass {
public:
ApuPass() = default;
void
Init() override;
bool
Run(const TaskPtr& task) override;
};
} // namespace scheduler
} // namespace milvus
#endif

View File

@ -158,6 +158,9 @@ XSearchTask::Load(LoadType type, uint8_t device_id) {
} else if (type == LoadType::CPU2FPGA) {
stat = index_engine_->CopyToFpga();
type_str = "CPU2FPGA";
} else if (type == LoadType::CPU2APU) {
stat = index_engine_->CopyToApu(file_->row_count_);
type_str = "CPU2APU";
} else {
error_msg = "Wrong load type";
stat = Status(SERVER_UNEXPECTED_ERROR, error_msg);

View File

@ -23,7 +23,7 @@
namespace milvus {
namespace scheduler {
enum class LoadType { DISK2CPU, CPU2GPU, GPU2CPU, TEST, CPU2FPGA };
enum class LoadType { DISK2CPU, CPU2GPU, GPU2CPU, TEST, CPU2FPGA, CPU2APU };
enum class TaskType {
SearchTask,

Binary file not shown.

Binary file not shown.

View File

@ -12,3 +12,5 @@ libboost-filesystem-dev libboost-serialization-dev libboost-regex-dev liblapack3
if [ ! -f "/usr/lib/x86_64-linux-gnu/libmysqlclient_r.so" ]; then
sudo ln -s /usr/lib/x86_64-linux-gnu/libmysqlclient.so /usr/lib/x86_64-linux-gnu/libmysqlclient_r.so
fi
sudo dpkg -i ./thirdparty/gsi/gdl_sources_milvus/gsi-sys-full-libs-120.11.300.9.deb