[WIP] feature : add zero copy support for vector index#1032
[WIP] feature : add zero copy support for vector index#1032foxspy wants to merge 1 commit intozilliztech:mainfrom
Conversation
|
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: foxspy The full list of commands accepted by this bot can be found here. The pull request process is described here DetailsNeeds approval from an approver in each of these files:
Approvers can indicate their approval by writing |
|
@foxspy 🔍 Important: PR Classification Needed! For efficient project management and a seamless review process, it's essential to classify your PR correctly. Here's how:
For any PR outside the kind/improvement category, ensure you link to the associated issue using the format: “issue: #”. Thanks for your efforts and contribution to the community!. |
5385cae to
dc5a6ac
Compare
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #1032 +/- ##
=========================================
+ Coverage 0 72.81% +72.81%
=========================================
Files 0 82 +82
Lines 0 7529 +7529
=========================================
+ Hits 0 5482 +5482
- Misses 0 2047 +2047 🚀 New features to boost your workflow:
|
alexanderguzhva
left a comment
There was a problem hiding this comment.
one topic to discuss. Otherwise, lgtm
| MetricType metric_type; | ||
| float metric_arg; ///< argument of the metric type | ||
|
|
||
| std::shared_ptr<MmappedFileMappingOwner> mmap_owner; |
There was a problem hiding this comment.
this is a very tricky point. Although, I understand why this was introduced, I'd like to avoid adding it here. Basically, the approach is similar to a std::string_view, which does not have a business to maintain the memory. Similar, here: It is not Index's instance business to maintain the view.
I'm open for discussions.
There was a problem hiding this comment.
@foxspy any comments on this? Basically, I doubt that we'll able to introduce this variable in vanilla Faiss when porting back
| } | ||
| } | ||
|
|
||
| ZeroCopyIOReader* zr = dynamic_cast<ZeroCopyIOReader*>(f); |
There was a problem hiding this comment.
this is a todo for the future: basically, a reader need to instantiate an object. But this is a later business, because it needs to be properly synchronized with the vanilla faiss first.
So, let's keep the change in the way you proposed it.
There was a problem hiding this comment.
Yes, so I put the PR up first; zero copy is needed here mainly for
- Optimizing memory expansion caused by copying during loading
- The memory will be managed uniformly through Eyrie later, and the index does not hold data, but only views
- The implementation of mmap and zero copy can be unified (mmap externally first, load through zero copy)
If you have any ideas about this, please feel free to communicate; has faiss considered supporting this mode?
dc5a6ac to
7dc2032
Compare
b58a68a to
91cfcde
Compare
Signed-off-by: xianliang.li <xianliang.li@zilliz.com>
91cfcde to
771d36e
Compare
|
|
||
| MemoryIOReader reader(binary->data.get(), binary->size); | ||
| int io_flags = faiss::IO_FLAG_ZERO_COPY; | ||
| faiss::ZeroCopyIOReader reader(binary->data.get(), binary->size); |
There was a problem hiding this comment.
Such an approach won't lead to a memory leak, correct?
There was a problem hiding this comment.
The binary will be held by the index; so there will be no memory leak
| MetricType metric_type; | ||
| float metric_arg; ///< argument of the metric type | ||
|
|
||
| std::shared_ptr<MmappedFileMappingOwner> mmap_owner; |
There was a problem hiding this comment.
@foxspy any comments on this? Basically, I doubt that we'll able to introduce this variable in vanilla Faiss when porting back
|
|
||
| namespace faiss { | ||
|
|
||
| ZeroCopyIOReader::ZeroCopyIOReader(uint8_t* data, size_t size) : data_(data), rp_(0), total_(size) { |
There was a problem hiding this comment.
A duplicate code, similar to src/io/memory_io.h
There was a problem hiding this comment.
This is because Knowhere is a hub that is adapted to multiple indexes. For indexes other than faiss, it uses the memory_io.h. Faiss needs to remain independent zerocopy_io.cpp and not rely on related objects of knowhere.
|
Zero copy may cause data misalignment, because data serialization in Faiss does not require alignment, which may cause performance degradation or even crashes in some scenarios. @alexanderguzhva Do you have any suggestions for this? |
I'm not sure I follow. Any examples? |
|
I mean that this PR totally makes sense, with the exception of adding a memory owner directly to the |
| return; | ||
| } | ||
| } | ||
| target.resize(size); |
There was a problem hiding this comment.
this particular line 118 is not needed
A simple example is, if https://github.com/zilliztech/knowhere/pull/1032/files#diff-d05f16d9b1473d49c536582f9433cca57d6a2909a5a729dec54c383f598b57c4R119 assign 0x5ffffff3 to float *, it will cause misalignment of memory access. Although I have tried it on x64 and arm machines, it will not cause a crash, but I know that this will generally lead to performance degradation (may cause multiple memory accesses); some older machines may also have strange problems; for example, scann also has SIMD requirements for alignment https://github.com/zilliztech/knowhere/blob/main/thirdparty/faiss/faiss/utils/AlignedTable.h#L115, which will cause memory expansion (duplicated binary + memory copy) if not handled |
Summary: This PR introduces a backport of a combination of zilliztech/knowhere#996 and zilliztech/knowhere#1032 that allow to have memory-mapped and zerocopy indces. The root underlying idea is that we replace certain `std::vector<>` containers with a custom `faiss::MaybeOwnedVector<>` container, which may behave either as `std::vector<>`, or as a view of a certain pointer / descriptor. We don't replace all the instances of `std::vector<>`, but the largest ones. This change affects `IndexFlatCodes`-based and `IndexHNSW` CPU indices. (done) alter IVF lists as well. (done) alter binary indices as well. Memory-mapped index works like this: ```C++ std::unique_ptr<faiss::Index> index_mm( faiss::read_index(filenamename.c_str(), faiss::IO_FLAG_MMAP_IFC)); ``` In theory, it should be ready to be used from Python. All the descriptor management should be working. Zero-copy index works like this: ```C++ #include <faiss/impl/zerocopy_io.h> faiss::ZeroCopyIOReader reader(buffer.data(), buffer.size()); std::unique_ptr<faiss::Index> index_zc(faiss::read_index(&reader)); ``` All the pointer management for `faiss::ZeroCopyIOReader` should be handled manually. I'm not sure how to plug this into Python yet, maybe, some ref-counting is required. (done) some refactoring Pull Request resolved: #4199 Reviewed By: mengdilin Differential Revision: D69972250 Pulled By: mdouze fbshipit-source-id: 98a3f94d6884814873d3534ee25f960892ef1076
Summary: This PR introduces a backport of a combination of zilliztech/knowhere#996 and zilliztech/knowhere#1032 that allow to have memory-mapped and zerocopy indces. The root underlying idea is that we replace certain `std::vector<>` containers with a custom `faiss::MaybeOwnedVector<>` container, which may behave either as `std::vector<>`, or as a view of a certain pointer / descriptor. We don't replace all the instances of `std::vector<>`, but the largest ones. This change affects `IndexFlatCodes`-based and `IndexHNSW` CPU indices. (done) alter IVF lists as well. (done) alter binary indices as well. Memory-mapped index works like this: ```C++ std::unique_ptr<faiss::Index> index_mm( faiss::read_index(filenamename.c_str(), faiss::IO_FLAG_MMAP_IFC)); ``` In theory, it should be ready to be used from Python. All the descriptor management should be working. Zero-copy index works like this: ```C++ #include <faiss/impl/zerocopy_io.h> faiss::ZeroCopyIOReader reader(buffer.data(), buffer.size()); std::unique_ptr<faiss::Index> index_zc(faiss::read_index(&reader)); ``` All the pointer management for `faiss::ZeroCopyIOReader` should be handled manually. I'm not sure how to plug this into Python yet, maybe, some ref-counting is required. (done) some refactoring Pull Request resolved: facebookresearch/faiss#4199 Reviewed By: mengdilin Differential Revision: D69972250 Pulled By: mdouze fbshipit-source-id: 98a3f94d6884814873d3534ee25f960892ef1076
Summary: This PR introduces a backport of a combination of zilliztech/knowhere#996 and zilliztech/knowhere#1032 that allow to have memory-mapped and zerocopy indces. The root underlying idea is that we replace certain `std::vector<>` containers with a custom `faiss::MaybeOwnedVector<>` container, which may behave either as `std::vector<>`, or as a view of a certain pointer / descriptor. We don't replace all the instances of `std::vector<>`, but the largest ones. This change affects `IndexFlatCodes`-based and `IndexHNSW` CPU indices. (done) alter IVF lists as well. (done) alter binary indices as well. Memory-mapped index works like this: ```C++ std::unique_ptr<faiss::Index> index_mm( faiss::read_index(filenamename.c_str(), faiss::IO_FLAG_MMAP_IFC)); ``` In theory, it should be ready to be used from Python. All the descriptor management should be working. Zero-copy index works like this: ```C++ #include <faiss/impl/zerocopy_io.h> faiss::ZeroCopyIOReader reader(buffer.data(), buffer.size()); std::unique_ptr<faiss::Index> index_zc(faiss::read_index(&reader)); ``` All the pointer management for `faiss::ZeroCopyIOReader` should be handled manually. I'm not sure how to plug this into Python yet, maybe, some ref-counting is required. (done) some refactoring Pull Request resolved: facebookresearch#4199 Reviewed By: mengdilin Differential Revision: D69972250 Pulled By: mdouze fbshipit-source-id: 98a3f94d6884814873d3534ee25f960892ef1076
issue: #1031