diff options
11 files changed, 68 insertions, 326 deletions
diff --git a/eval/src/tests/eval/value_type/value_type_test.cpp b/eval/src/tests/eval/value_type/value_type_test.cpp index cf61da00cca..42b34c0d3ea 100644 --- a/eval/src/tests/eval/value_type/value_type_test.cpp +++ b/eval/src/tests/eval/value_type/value_type_test.cpp @@ -80,7 +80,7 @@ TEST("require that 'tensor<float>()' is normalized to 'double'") { EXPECT_EQUAL(t.dimensions().size(), 0u); } -TEST("require that use of unbound dimensions result in error types") { +TEST("require that use of zero-size dimensions result in error types") { EXPECT_TRUE(ValueType::tensor_type({{"x", 0}}).is_error()); } @@ -276,13 +276,10 @@ TEST("require that dimension predicates work as expected") { ValueType::Dimension z("z", 0); EXPECT_TRUE(x.is_mapped()); EXPECT_TRUE(!x.is_indexed()); - EXPECT_TRUE(!x.is_bound()); EXPECT_TRUE(!y.is_mapped()); EXPECT_TRUE(y.is_indexed()); - EXPECT_TRUE(y.is_bound()); EXPECT_TRUE(!z.is_mapped()); EXPECT_TRUE(z.is_indexed()); - EXPECT_TRUE(!z.is_bound()); } TEST("require that removing dimensions from non-tensor types gives error type") { diff --git a/eval/src/vespa/eval/eval/function.cpp b/eval/src/vespa/eval/eval/function.cpp index 8b9e440318d..65c70a5bd7d 100644 --- a/eval/src/vespa/eval/eval/function.cpp +++ b/eval/src/vespa/eval/eval/function.cpp @@ -30,18 +30,6 @@ bool has_duplicates(const std::vector<vespalib::string> &list) { return false; } -bool check_tensor_lambda_type(const ValueType &type) { - if (!type.is_tensor() || type.dimensions().empty()) { - return false; - } - for (const auto &dim: type.dimensions()) { - if (!dim.is_indexed() || !dim.is_bound()) { - return false; - } - } - return true; -} - //----------------------------------------------------------------------------- class Params { @@ -566,7 +554,7 @@ void parse_tensor_lambda(ParseContext &ctx) { ctx.eat(')'); type_spec.push_back(')'); ValueType type = ValueType::from_spec(type_spec); - if (!check_tensor_lambda_type(type)) { + if (!type.is_dense()) { ctx.fail("invalid tensor type"); return; } diff --git a/eval/src/vespa/eval/eval/value_type.h b/eval/src/vespa/eval/eval/value_type.h index 423c8e15d92..0eb3e1ca28e 100644 --- a/eval/src/vespa/eval/eval/value_type.h +++ b/eval/src/vespa/eval/eval/value_type.h @@ -32,7 +32,6 @@ public: bool operator!=(const Dimension &rhs) const { return !(*this == rhs); } bool is_mapped() const { return (size == npos); } bool is_indexed() const { return (size != npos); } - bool is_bound() const { return ((size != npos) && (size != 0)); } }; private: diff --git a/eval/src/vespa/eval/tensor/dense/dense_tensor_view.h b/eval/src/vespa/eval/tensor/dense/dense_tensor_view.h index c09202e50d0..1ec4daf40fd 100644 --- a/eval/src/vespa/eval/tensor/dense/dense_tensor_view.h +++ b/eval/src/vespa/eval/tensor/dense/dense_tensor_view.h @@ -21,11 +21,9 @@ public: DenseTensorView(const eval::ValueType &type_in, TypedCells cells_in) : _typeRef(type_in), _cellsRef(cells_in) - {} - explicit DenseTensorView(const eval::ValueType &type_in) - : _typeRef(type_in), - _cellsRef() - {} + { + assert(_typeRef.cell_type() == cells_in.type); + } const eval::ValueType &fast_type() const { return _typeRef; } const TypedCells &cellsRef() const { return _cellsRef; } @@ -45,6 +43,11 @@ public: eval::TensorSpec toSpec() const override; void accept(TensorVisitor &visitor) const override; protected: + explicit DenseTensorView(const eval::ValueType &type_in) + : _typeRef(type_in), + _cellsRef() + {} + void initCellsRef(TypedCells cells_in) { assert(_typeRef.cell_type() == cells_in.type); _cellsRef = cells_in; diff --git a/eval/src/vespa/eval/tensor/dense/mutable_dense_tensor_view.cpp b/eval/src/vespa/eval/tensor/dense/mutable_dense_tensor_view.cpp index 08abc391179..ae3e8ad9023 100644 --- a/eval/src/vespa/eval/tensor/dense/mutable_dense_tensor_view.cpp +++ b/eval/src/vespa/eval/tensor/dense/mutable_dense_tensor_view.cpp @@ -6,31 +6,10 @@ using vespalib::eval::ValueType; namespace vespalib::tensor { -MutableDenseTensorView::MutableValueType::MutableValueType(ValueType type_in) - : _type(type_in) -{ - std::vector<ValueType::Dimension> &dimensions = - const_cast<std::vector<ValueType::Dimension> &>(_type.dimensions()); - for (auto &dim : dimensions) { - if (!dim.is_bound()) { - _unboundDimSizes.emplace_back(&dim.size); - } - } -} - -MutableDenseTensorView::MutableValueType::~MutableValueType() = default; - MutableDenseTensorView::MutableDenseTensorView(ValueType type_in) - : DenseTensorView(_concreteType._type), - _concreteType(type_in) -{ -} - -MutableDenseTensorView::MutableDenseTensorView(ValueType type_in, TypedCells cells_in) - : DenseTensorView(_concreteType._type, cells_in), - _concreteType(type_in) + : DenseTensorView(_type), + _type(type_in) { } } - diff --git a/eval/src/vespa/eval/tensor/dense/mutable_dense_tensor_view.h b/eval/src/vespa/eval/tensor/dense/mutable_dense_tensor_view.h index d71903d6c47..db241ef6a2b 100644 --- a/eval/src/vespa/eval/tensor/dense/mutable_dense_tensor_view.h +++ b/eval/src/vespa/eval/tensor/dense/mutable_dense_tensor_view.h @@ -13,46 +13,13 @@ namespace vespalib::tensor { class MutableDenseTensorView : public DenseTensorView { private: - struct MutableValueType - { - eval::ValueType _type; - private: - std::vector<eval::ValueType::Dimension::size_type *> _unboundDimSizes; - - public: - MutableValueType(eval::ValueType type_in); - ~MutableValueType(); - const eval::ValueType &fast_type() const { return _type; } - void setUnboundDimensions(const uint32_t *unboundDimSizeBegin, const uint32_t *unboundDimSizeEnd) { - const uint32_t *unboundDimSizePtr = unboundDimSizeBegin; - for (auto unboundDimSize : _unboundDimSizes) { - *unboundDimSize = *unboundDimSizePtr++; - } - assert(unboundDimSizePtr == unboundDimSizeEnd); - (void) unboundDimSizeEnd; - } - void setUnboundDimensionsForEmptyTensor() { - for (auto unboundDimSize : _unboundDimSizes) { - *unboundDimSize = 1; - } - } - }; - - MutableValueType _concreteType; + eval::ValueType _type; public: MutableDenseTensorView(eval::ValueType type_in); - MutableDenseTensorView(eval::ValueType type_in, TypedCells cells_in); void setCells(TypedCells cells_in) { initCellsRef(cells_in); } - void setUnboundDimensions(const uint32_t *unboundDimSizeBegin, const uint32_t *unboundDimSizeEnd) { - _concreteType.setUnboundDimensions(unboundDimSizeBegin, unboundDimSizeEnd); - } - void setUnboundDimensionsForEmptyTensor() { - _concreteType.setUnboundDimensionsForEmptyTensor(); - } }; } - diff --git a/searchlib/src/vespa/searchlib/tensor/dense_tensor_attribute.cpp b/searchlib/src/vespa/searchlib/tensor/dense_tensor_attribute.cpp index ba4c64f1744..a2b9f136ed9 100644 --- a/searchlib/src/vespa/searchlib/tensor/dense_tensor_attribute.cpp +++ b/searchlib/src/vespa/searchlib/tensor/dense_tensor_attribute.cpp @@ -27,57 +27,30 @@ class TensorReader : public ReaderBase private: static constexpr uint8_t tensorIsNotPresent = 0; static constexpr uint8_t tensorIsPresent = 1; - vespalib::eval::ValueType _tensorType; - uint32_t _numUnboundDims; - size_t _numBoundCells; - std::vector<uint32_t> _unboundDimSizes; public: TensorReader(AttributeVector &attr); ~TensorReader(); - size_t getNumCells(); - const vespalib::eval::ValueType &tensorType() const { return _tensorType; } - const std::vector<uint32_t> &getUnboundDimSizes() const { return _unboundDimSizes; } + bool is_present(); void readTensor(void *buf, size_t len) { _datFile->ReadBuf(buf, len); } }; TensorReader::TensorReader(AttributeVector &attr) - : ReaderBase(attr), - _tensorType(vespalib::eval::ValueType::from_spec(getDatHeader().getTag(tensorTypeTag).asString())), - _numUnboundDims(0), - _numBoundCells(1), - _unboundDimSizes() + : ReaderBase(attr) { - for (const auto & dim : _tensorType.dimensions()) { - if (dim.is_bound()) { - _numBoundCells *= dim.size; - } else { - ++_numUnboundDims; - } - } - _unboundDimSizes.resize(_numUnboundDims); } TensorReader::~TensorReader() = default; -size_t -TensorReader::getNumCells() { +bool +TensorReader::is_present() { unsigned char detect; _datFile->ReadBuf(&detect, sizeof(detect)); if (detect == tensorIsNotPresent) { - return 0u; + return false; } if (detect != tensorIsPresent) { LOG_ABORT("should not be reached"); } - size_t numCells = _numBoundCells; - if (_numUnboundDims != 0) { - _datFile->ReadBuf(&_unboundDimSizes[0], _numUnboundDims * sizeof(uint32_t)); - for (auto i = 0u; i < _numUnboundDims; ++i) { - assert(_unboundDimSizes[i] != 0u); - numCells *= _unboundDimSizes[i]; - // TODO: sanity check numCells - } - } - return numCells; + return true; } } @@ -140,16 +113,12 @@ DenseTensorAttribute::onLoad() assert(getConfig().tensorType().to_spec() == tensorReader.getDatHeader().getTag(tensorTypeTag).asString()); uint32_t numDocs(tensorReader.getDocIdLimit()); - uint32_t cellSize(_denseTensorStore.getCellSize()); _refVector.reset(); _refVector.unsafe_reserve(numDocs); for (uint32_t lid = 0; lid < numDocs; ++lid) { - size_t numCells = tensorReader.getNumCells(); - if (numCells != 0u) { - const auto &unboundDimSizes = tensorReader.getUnboundDimSizes(); - auto raw = _denseTensorStore.allocRawBuffer(numCells, unboundDimSizes); - size_t rawLen = numCells * cellSize; - tensorReader.readTensor(raw.data, rawLen); + if (tensorReader.is_present()) { + auto raw = _denseTensorStore.allocRawBuffer(); + tensorReader.readTensor(raw.data, _denseTensorStore.getBufSize()); _refVector.push_back(raw.ref); } else { _refVector.push_back(EntryRef()); diff --git a/searchlib/src/vespa/searchlib/tensor/dense_tensor_attribute_saver.cpp b/searchlib/src/vespa/searchlib/tensor/dense_tensor_attribute_saver.cpp index fb0554112ef..d78adab81b5 100644 --- a/searchlib/src/vespa/searchlib/tensor/dense_tensor_attribute_saver.cpp +++ b/searchlib/src/vespa/searchlib/tensor/dense_tensor_attribute_saver.cpp @@ -40,17 +40,15 @@ DenseTensorAttributeSaver::onSave(IAttributeSaveTarget &saveTarget) { std::unique_ptr<BufferWriter> datWriter(saveTarget.datWriter().allocBufferWriter()); - const uint32_t unboundDimSizesSize = _tensorStore.unboundDimSizesSize(); const uint32_t docIdLimit(_refs.size()); const uint32_t cellSize = _tensorStore.getCellSize(); for (uint32_t lid = 0; lid < docIdLimit; ++lid) { if (_refs[lid].valid()) { auto raw = _tensorStore.getRawBuffer(_refs[lid]); datWriter->write(&tensorIsPresent, sizeof(tensorIsPresent)); - size_t numCells = _tensorStore.getNumCells(raw); - size_t rawLen = numCells * cellSize + unboundDimSizesSize; - datWriter->write(static_cast<const char *>(raw) - unboundDimSizesSize, - rawLen); + size_t numCells = _tensorStore.getNumCells(); + size_t rawLen = numCells * cellSize; + datWriter->write(static_cast<const char *>(raw), rawLen); } else { datWriter->write(&tensorIsNotPresent, sizeof(tensorIsNotPresent)); } diff --git a/searchlib/src/vespa/searchlib/tensor/dense_tensor_store.cpp b/searchlib/src/vespa/searchlib/tensor/dense_tensor_store.cpp index 11a6839ca59..dc459d7d246 100644 --- a/searchlib/src/vespa/searchlib/tensor/dense_tensor_store.cpp +++ b/searchlib/src/vespa/searchlib/tensor/dense_tensor_store.cpp @@ -30,32 +30,30 @@ size_t size_of(CellType type) { abort(); } +size_t my_align(size_t size, size_t alignment) { + size += alignment - 1; + return (size - (size % alignment)); +} + } DenseTensorStore::TensorSizeCalc::TensorSizeCalc(const ValueType &type) - : _numBoundCells(1u), - _numUnboundDims(0u), + : _numCells(1u), _cellSize(size_of(type.cell_type())) { - for (const auto & dim : type.dimensions()) { - if (dim.is_bound()) { - _numBoundCells *= dim.size; - } else { - ++_numUnboundDims; - } + for (const auto &dim: type.dimensions()) { + _numCells *= dim.size; } } size_t -DenseTensorStore::TensorSizeCalc::arraySize() const +DenseTensorStore::TensorSizeCalc::alignedSize() const { - size_t tensorSize = (_numBoundCells * _cellSize) + (_numUnboundDims * sizeof(uint32_t)); - return DenseTensorStore::BufferType::align(tensorSize, DENSE_TENSOR_ALIGNMENT); + return my_align(bufSize(), DENSE_TENSOR_ALIGNMENT); } DenseTensorStore::BufferType::BufferType(const TensorSizeCalc &tensorSizeCalc) - : datastore::BufferType<char>(tensorSizeCalc.arraySize(), MIN_BUFFER_ARRAYS, RefType::offsetSize()), - _unboundDimSizesSize(tensorSizeCalc._numUnboundDims * sizeof(uint32_t)) + : datastore::BufferType<char>(tensorSizeCalc.alignedSize(), MIN_BUFFER_ARRAYS, RefType::offsetSize()) {} DenseTensorStore::BufferType::~BufferType() = default; @@ -64,15 +62,7 @@ void DenseTensorStore::BufferType::cleanHold(void *buffer, size_t offset, size_t numElems, CleanContext) { - // Clear both tensor dimension size information and cells. - memset(static_cast<char *>(buffer) + offset - _unboundDimSizesSize, 0, numElems); -} - -size_t -DenseTensorStore::BufferType::getReservedElements(uint32_t bufferId) const -{ - return datastore::BufferType<char>::getReservedElements(bufferId) + - align(_unboundDimSizesSize); + memset(static_cast<char *>(buffer) + offset, 0, numElems); } DenseTensorStore::DenseTensorStore(const ValueType &type) @@ -81,15 +71,12 @@ DenseTensorStore::DenseTensorStore(const ValueType &type) _tensorSizeCalc(type), _bufferType(_tensorSizeCalc), _type(type), - _emptyCells() + _emptySpace() { - _emptyCells.resize(_tensorSizeCalc._numBoundCells, 0.0); + _emptySpace.resize(getBufSize(), 0); _store.addType(&_bufferType); _store.initActiveBuffers(); - if (_tensorSizeCalc._numUnboundDims == 0) { - // In this case each tensor use the same amount of memory and we can re-use previously allocated raw buffers by using free lists. - _store.enableFreeLists(); - } + _store.enableFreeLists(); } DenseTensorStore::~DenseTensorStore() @@ -103,61 +90,32 @@ DenseTensorStore::getRawBuffer(RefType ref) const return _store.getEntryArray<char>(ref, _bufferType.getArraySize()); } - -size_t -DenseTensorStore::getNumCells(const void *buffer) const -{ - const uint32_t *unboundDimSizeEnd = static_cast<const uint32_t *>(buffer); - const uint32_t *unboundDimSizeStart = unboundDimSizeEnd - _tensorSizeCalc._numUnboundDims; - size_t numCells = _tensorSizeCalc._numBoundCells; - for (auto unboundDimSize = unboundDimSizeStart; unboundDimSize != unboundDimSizeEnd; ++unboundDimSize) { - numCells *= *unboundDimSize; - } - return numCells; -} - namespace { -void clearPadAreaAfterBuffer(char *buffer, size_t bufSize, size_t alignedBufSize, uint32_t unboundDimSizesSize) { - size_t padSize = alignedBufSize - unboundDimSizesSize - bufSize; +void clearPadAreaAfterBuffer(char *buffer, size_t bufSize, size_t alignedBufSize) { + size_t padSize = alignedBufSize - bufSize; memset(buffer + bufSize, 0, padSize); } } Handle<char> -DenseTensorStore::allocRawBuffer(size_t numCells) +DenseTensorStore::allocRawBuffer() { - size_t bufSize = numCells * _tensorSizeCalc._cellSize; - size_t alignedBufSize = alignedSize(numCells); + size_t bufSize = getBufSize(); + size_t alignedBufSize = _tensorSizeCalc.alignedSize(); auto result = _concreteStore.freeListRawAllocator<char>(_typeId).alloc(alignedBufSize); - clearPadAreaAfterBuffer(result.data, bufSize, alignedBufSize, unboundDimSizesSize()); + clearPadAreaAfterBuffer(result.data, bufSize, alignedBufSize); return result; } -Handle<char> -DenseTensorStore::allocRawBuffer(size_t numCells, - const std::vector<uint32_t> &unboundDimSizes) -{ - assert(unboundDimSizes.size() == _tensorSizeCalc._numUnboundDims); - auto ret = allocRawBuffer(numCells); - if (_tensorSizeCalc._numUnboundDims > 0) { - memcpy(ret.data - unboundDimSizesSize(), - &unboundDimSizes[0], unboundDimSizesSize()); - } - assert(numCells == getNumCells(ret.data)); - return ret; -} - void DenseTensorStore::holdTensor(EntryRef ref) { if (!ref.valid()) { return; } - const void *buffer = getRawBuffer(ref); - size_t numCells = getNumCells(buffer); - _concreteStore.holdElem(ref, alignedSize(numCells)); + _concreteStore.holdElem(ref, _tensorSizeCalc.alignedSize()); } TensorStore::EntryRef @@ -167,111 +125,32 @@ DenseTensorStore::move(EntryRef ref) return RefType(); } auto oldraw = getRawBuffer(ref); - size_t numCells = getNumCells(oldraw); - auto newraw = allocRawBuffer(numCells); - memcpy(newraw.data - unboundDimSizesSize(), - static_cast<const char *>(oldraw) - unboundDimSizesSize(), - numCells * _tensorSizeCalc._cellSize + unboundDimSizesSize()); - _concreteStore.holdElem(ref, alignedSize(numCells)); + auto newraw = allocRawBuffer(); + memcpy(newraw.data, static_cast<const char *>(oldraw), getBufSize()); + _concreteStore.holdElem(ref, _tensorSizeCalc.alignedSize()); return newraw.ref; } -namespace { - -void makeConcreteType(MutableDenseTensorView &tensor, - const void *buffer, - uint32_t numUnboundDims) -{ - const uint32_t *unboundDimSizeEnd = static_cast<const uint32_t *>(buffer); - const uint32_t *unboundDimSizeBegin = unboundDimSizeEnd - numUnboundDims; - tensor.setUnboundDimensions(unboundDimSizeBegin, unboundDimSizeEnd); -} - -} - std::unique_ptr<Tensor> DenseTensorStore::getTensor(EntryRef ref) const { if (!ref.valid()) { return std::unique_ptr<Tensor>(); } - auto raw = getRawBuffer(ref); - size_t numCells = getNumCells(raw); - vespalib::tensor::TypedCells cells_ref(raw, _type.cell_type(), numCells); - if (_tensorSizeCalc._numUnboundDims == 0) { - return std::make_unique<DenseTensorView>(_type, cells_ref); - } else { - auto result = std::make_unique<MutableDenseTensorView>(_type, cells_ref); - makeConcreteType(*result, raw, _tensorSizeCalc._numUnboundDims); - return result; - } + vespalib::tensor::TypedCells cells_ref(getRawBuffer(ref), _type.cell_type(), getNumCells()); + return std::make_unique<DenseTensorView>(_type, cells_ref); } void DenseTensorStore::getTensor(EntryRef ref, MutableDenseTensorView &tensor) const { if (!ref.valid()) { - vespalib::tensor::TypedCells cells_ref(&_emptyCells[0], _type.cell_type(), _emptyCells.size()); + vespalib::tensor::TypedCells cells_ref(&_emptySpace[0], _type.cell_type(), getNumCells()); tensor.setCells(cells_ref); - if (_tensorSizeCalc._numUnboundDims > 0) { - tensor.setUnboundDimensionsForEmptyTensor(); - } } else { - auto raw = getRawBuffer(ref); - size_t numCells = getNumCells(raw); - vespalib::tensor::TypedCells cells_ref(raw, _type.cell_type(), numCells); + vespalib::tensor::TypedCells cells_ref(getRawBuffer(ref), _type.cell_type(), getNumCells()); tensor.setCells(cells_ref); - if (_tensorSizeCalc._numUnboundDims > 0) { - makeConcreteType(tensor, raw, _tensorSizeCalc._numUnboundDims); - } - } -} - -namespace { - -void -checkMatchingType(const ValueType &lhs, const ValueType &rhs, size_t numCells) -{ - (void) numCells; - size_t checkNumCells = 1u; - auto rhsItr = rhs.dimensions().cbegin(); - auto rhsItrEnd = rhs.dimensions().cend(); - (void) rhsItrEnd; - for (const auto &dim : lhs.dimensions()) { - (void) dim; - assert(rhsItr != rhsItrEnd); - assert(dim.name == rhsItr->name); - assert(rhsItr->is_bound()); - assert(!dim.is_bound() || dim.size == rhsItr->size); - checkNumCells *= rhsItr->size; - ++rhsItr; - } - assert(lhs.cell_type() == rhs.cell_type()); - assert(numCells == checkNumCells); - assert(rhsItr == rhsItrEnd); -} - -void -setDenseTensorUnboundDimSizes(void *buffer, const ValueType &lhs, uint32_t numUnboundDims, const ValueType &rhs) -{ - uint32_t *unboundDimSizeEnd = static_cast<uint32_t *>(buffer); - uint32_t *unboundDimSize = unboundDimSizeEnd - numUnboundDims; - auto rhsItr = rhs.dimensions().cbegin(); - auto rhsItrEnd = rhs.dimensions().cend(); - (void) rhsItrEnd; - for (const auto &dim : lhs.dimensions()) { - assert (rhsItr != rhsItrEnd); - if (!dim.is_bound()) { - assert(unboundDimSize != unboundDimSizeEnd); - *unboundDimSize = rhsItr->size; - ++unboundDimSize; - } - ++rhsItr; } - assert (rhsItr == rhsItrEnd); - assert(unboundDimSize == unboundDimSizeEnd); -} - } template <class TensorType> @@ -279,10 +158,10 @@ TensorStore::EntryRef DenseTensorStore::setDenseTensor(const TensorType &tensor) { size_t numCells = tensor.cellsRef().size; - checkMatchingType(_type, tensor.type(), numCells); - auto raw = allocRawBuffer(numCells); - setDenseTensorUnboundDimSizes(raw.data, _type, _tensorSizeCalc._numUnboundDims, tensor.type()); - memcpy(raw.data, tensor.cellsRef().data, numCells * _tensorSizeCalc._cellSize); + assert(numCells == getNumCells()); + assert(tensor.type() == _type); + auto raw = allocRawBuffer(); + memcpy(raw.data, tensor.cellsRef().data, getBufSize()); return raw.ref; } diff --git a/searchlib/src/vespa/searchlib/tensor/dense_tensor_store.h b/searchlib/src/vespa/searchlib/tensor/dense_tensor_store.h index 6b87bb76b87..bd52709e423 100644 --- a/searchlib/src/vespa/searchlib/tensor/dense_tensor_store.h +++ b/searchlib/src/vespa/searchlib/tensor/dense_tensor_store.h @@ -12,16 +12,6 @@ namespace search::tensor { /** * Class for storing dense tensors with known bounds in memory, used * by DenseTensorAttribute. - * - * Tensor dimension size information for unbound dimensions is at - * negative offset to preserve cell array aligment without - * introducing excessive padding, e.g. if tensor store is setup for - * tensors of type tensor(x[]) then a tensor of type tensor(x[3]) will - * use 32 bytes (inclusive 4 bytes padding). - * - * If both start of tensor dimension size information and start of - * tensor cells were to be 32 byte aligned then tensors of type tensor(x[3]) - * would use 64 bytes. */ class DenseTensorStore : public TensorStore { @@ -32,57 +22,45 @@ public: struct TensorSizeCalc { - size_t _numBoundCells; // product of bound dimension sizes - uint32_t _numUnboundDims; - uint32_t _cellSize; // size of a cell (e.g. double => 8) - + size_t _numCells; // product of dimension sizes + uint32_t _cellSize; // size of a cell (e.g. double => 8, float => 4) + TensorSizeCalc(const ValueType &type); - size_t arraySize() const; + size_t bufSize() const { return (_numCells * _cellSize); } + size_t alignedSize() const; }; class BufferType : public datastore::BufferType<char> { using CleanContext = datastore::BufferType<char>::CleanContext; - uint32_t _unboundDimSizesSize; public: BufferType(const TensorSizeCalc &tensorSizeCalc); ~BufferType() override; void cleanHold(void *buffer, size_t offset, size_t numElems, CleanContext cleanCtx) override; - uint32_t unboundDimSizesSize() const { return _unboundDimSizesSize; } - size_t getReservedElements(uint32_t bufferId) const override; - static size_t align(size_t size, size_t alignment) { - size += alignment - 1; - return (size - (size % alignment)); - } - size_t align(size_t size) const { return align(size, _arraySize); } }; private: DataStoreType _concreteStore; TensorSizeCalc _tensorSizeCalc; BufferType _bufferType; ValueType _type; // type of dense tensor - std::vector<double> _emptyCells; + std::vector<char> _emptySpace; size_t unboundCells(const void *buffer) const; template <class TensorType> TensorStore::EntryRef setDenseTensor(const TensorType &tensor); - datastore::Handle<char> allocRawBuffer(size_t numCells); - size_t alignedSize(size_t numCells) const { - return _bufferType.align(numCells * _tensorSizeCalc._cellSize + unboundDimSizesSize()); - } public: DenseTensorStore(const ValueType &type); ~DenseTensorStore() override; const ValueType &type() const { return _type; } - uint32_t unboundDimSizesSize() const { return _bufferType.unboundDimSizesSize(); } - size_t getNumCells(const void *buffer) const; + size_t getNumCells() const { return _tensorSizeCalc._numCells; } uint32_t getCellSize() const { return _tensorSizeCalc._cellSize; } + size_t getBufSize() const { return _tensorSizeCalc.bufSize(); } const void *getRawBuffer(RefType ref) const; - datastore::Handle<char> allocRawBuffer(size_t numCells, const std::vector<uint32_t> &unboundDimSizes); + datastore::Handle<char> allocRawBuffer(); void holdTensor(EntryRef ref) override; EntryRef move(EntryRef ref) override; std::unique_ptr<Tensor> getTensor(EntryRef ref) const; diff --git a/searchlib/src/vespa/searchlib/tensor/tensor_attribute.cpp b/searchlib/src/vespa/searchlib/tensor/tensor_attribute.cpp index 7dd666ac74f..89b8e77e136 100644 --- a/searchlib/src/vespa/searchlib/tensor/tensor_attribute.cpp +++ b/searchlib/src/vespa/searchlib/tensor/tensor_attribute.cpp @@ -30,21 +30,6 @@ constexpr uint32_t TENSOR_ATTRIBUTE_VERSION = 0; // minimum dead bytes in tensor attribute before consider compaction constexpr size_t DEAD_SLACK = 0x10000u; - -ValueType -createEmptyTensorType(const ValueType &type) -{ - std::vector<ValueType::Dimension> list; - for (const auto &dim : type.dimensions()) { - if (dim.is_indexed() && !dim.is_bound()) { - list.emplace_back(dim.name, 1); - } else { - list.emplace_back(dim); - } - } - return ValueType::tensor_type(std::move(list)); -} - struct CallMakeEmptyTensor { template <typename CT> static Tensor::UP call(const ValueType &type) { @@ -81,7 +66,7 @@ TensorAttribute::TensorAttribute(vespalib::stringref name, const Config &cfg, Te cfg.getGrowStrategy().getDocsGrowDelta(), getGenerationHolder()), _tensorStore(tensorStore), - _emptyTensor(createEmptyTensor(createEmptyTensorType(cfg.tensorType()))), + _emptyTensor(createEmptyTensor(cfg.tensorType())), _compactGeneration(0) { } |