Skip to content

[mlir][sparse] bug fix on all-dense lex insertion #73987

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 30, 2023
Merged

Conversation

aartbik
Copy link
Contributor

@aartbik aartbik commented Nov 30, 2023

Fixes a bug that appended values after insertion completed. Also slight optimization by avoiding all-Dense computation for every lexInsert call

Fixes a bug that appended values after insertion completed.
Also slight optimization by avoiding all-Dense computation
for every lexInsert call
@llvmbot
Copy link
Member

llvmbot commented Nov 30, 2023

@llvm/pr-subscribers-mlir

@llvm/pr-subscribers-mlir-execution-engine

Author: Aart Bik (aartbik)

Changes

Fixes a bug that appended values after insertion completed. Also slight optimization by avoiding all-Dense computation for every lexInsert call


Full diff: https://github.com/llvm/llvm-project/pull/73987.diff

2 Files Affected:

  • (modified) mlir/include/mlir/ExecutionEngine/SparseTensor/Storage.h (+8-12)
  • (modified) mlir/lib/ExecutionEngine/SparseTensor/Storage.cpp (+11-3)
diff --git a/mlir/include/mlir/ExecutionEngine/SparseTensor/Storage.h b/mlir/include/mlir/ExecutionEngine/SparseTensor/Storage.h
index 19c49e6c487dff7..01c5f2382ffe69c 100644
--- a/mlir/include/mlir/ExecutionEngine/SparseTensor/Storage.h
+++ b/mlir/include/mlir/ExecutionEngine/SparseTensor/Storage.h
@@ -186,6 +186,7 @@ class SparseTensorStorageBase {
 
 protected:
   const MapRef map; // non-owning pointers into dim2lvl/lvl2dim vectors
+  const bool allDense;
 };
 
 /// A memory-resident sparse tensor using a storage scheme based on
@@ -293,8 +294,6 @@ class SparseTensorStorage final : public SparseTensorStorageBase {
   /// Partially specialize lexicographical insertions based on template types.
   void lexInsert(const uint64_t *lvlCoords, V val) final {
     assert(lvlCoords);
-    bool allDense = std::all_of(getLvlTypes().begin(), getLvlTypes().end(),
-                                [](LevelType lt) { return isDenseLT(lt); });
     if (allDense) {
       uint64_t lvlRank = getLvlRank();
       uint64_t valIdx = 0;
@@ -363,10 +362,12 @@ class SparseTensorStorage final : public SparseTensorStorageBase {
 
   /// Finalizes lexicographic insertions.
   void endLexInsert() final {
-    if (values.empty())
-      finalizeSegment(0);
-    else
-      endPath(0);
+    if (!allDense) {
+      if (values.empty())
+        finalizeSegment(0);
+      else
+        endPath(0);
+    }
   }
 
   /// Allocates a new COO object and initializes it with the contents.
@@ -705,7 +706,6 @@ SparseTensorStorage<P, C, V>::SparseTensorStorage(
   // we reserve position/coordinate space based on all previous dense
   // levels, which works well up to first sparse level; but we should
   // really use nnz and dense/sparse distribution.
-  bool allDense = true;
   uint64_t sz = 1;
   for (uint64_t l = 0; l < lvlRank; l++) {
     if (isCompressedLvl(l)) {
@@ -713,23 +713,19 @@ SparseTensorStorage<P, C, V>::SparseTensorStorage(
       positions[l].push_back(0);
       coordinates[l].reserve(sz);
       sz = 1;
-      allDense = false;
     } else if (isLooseCompressedLvl(l)) {
       positions[l].reserve(2 * sz + 1); // last one unused
       positions[l].push_back(0);
       coordinates[l].reserve(sz);
       sz = 1;
-      allDense = false;
     } else if (isSingletonLvl(l)) {
       coordinates[l].reserve(sz);
       sz = 1;
-      allDense = false;
     } else if (is2OutOf4Lvl(l)) {
-      assert(allDense && l == lvlRank - 1 && "unexpected 2:4 usage");
+      assert(l == lvlRank - 1 && "unexpected 2:4 usage");
       sz = detail::checkedMul(sz, lvlSizes[l]) / 2;
       coordinates[l].reserve(sz);
       values.reserve(sz);
-      allDense = false;
     } else { // Dense level.
       assert(isDenseLvl(l));
       sz = detail::checkedMul(sz, lvlSizes[l]);
diff --git a/mlir/lib/ExecutionEngine/SparseTensor/Storage.cpp b/mlir/lib/ExecutionEngine/SparseTensor/Storage.cpp
index 7f8f76f8ec18901..0c7b3a228a65cf7 100644
--- a/mlir/lib/ExecutionEngine/SparseTensor/Storage.cpp
+++ b/mlir/lib/ExecutionEngine/SparseTensor/Storage.cpp
@@ -17,6 +17,13 @@
 
 using namespace mlir::sparse_tensor;
 
+static inline bool isAllDense(uint64_t lvlRank, const LevelType *lvlTypes) {
+  for (uint64_t l = 0; l < lvlRank; l++)
+    if (!isDenseLT(lvlTypes[l]))
+      return false;
+  return true;
+}
+
 SparseTensorStorageBase::SparseTensorStorageBase( // NOLINT
     uint64_t dimRank, const uint64_t *dimSizes, uint64_t lvlRank,
     const uint64_t *lvlSizes, const LevelType *lvlTypes,
@@ -26,15 +33,16 @@ SparseTensorStorageBase::SparseTensorStorageBase( // NOLINT
       lvlTypes(lvlTypes, lvlTypes + lvlRank),
       dim2lvlVec(dim2lvl, dim2lvl + lvlRank),
       lvl2dimVec(lvl2dim, lvl2dim + dimRank),
-      map(dimRank, lvlRank, dim2lvlVec.data(), lvl2dimVec.data()) {
+      map(dimRank, lvlRank, dim2lvlVec.data(), lvl2dimVec.data()),
+      allDense(isAllDense(lvlRank, lvlTypes)) {
   assert(dimSizes && lvlSizes && lvlTypes && dim2lvl && lvl2dim);
   // Validate dim-indexed parameters.
   assert(dimRank > 0 && "Trivial shape is unsupported");
-  for (uint64_t d = 0; d < dimRank; ++d)
+  for (uint64_t d = 0; d < dimRank; d++)
     assert(dimSizes[d] > 0 && "Dimension size zero has trivial storage");
   // Validate lvl-indexed parameters.
   assert(lvlRank > 0 && "Trivial shape is unsupported");
-  for (uint64_t l = 0; l < lvlRank; ++l) {
+  for (uint64_t l = 0; l < lvlRank; l++) {
     assert(lvlSizes[l] > 0 && "Level size zero has trivial storage");
     assert(isDenseLvl(l) || isCompressedLvl(l) || isLooseCompressedLvl(l) ||
            isSingletonLvl(l) || is2OutOf4Lvl(l));

@llvmbot
Copy link
Member

llvmbot commented Nov 30, 2023

@llvm/pr-subscribers-mlir-sparse

Author: Aart Bik (aartbik)

Changes

Fixes a bug that appended values after insertion completed. Also slight optimization by avoiding all-Dense computation for every lexInsert call


Full diff: https://github.com/llvm/llvm-project/pull/73987.diff

2 Files Affected:

  • (modified) mlir/include/mlir/ExecutionEngine/SparseTensor/Storage.h (+8-12)
  • (modified) mlir/lib/ExecutionEngine/SparseTensor/Storage.cpp (+11-3)
diff --git a/mlir/include/mlir/ExecutionEngine/SparseTensor/Storage.h b/mlir/include/mlir/ExecutionEngine/SparseTensor/Storage.h
index 19c49e6c487dff7..01c5f2382ffe69c 100644
--- a/mlir/include/mlir/ExecutionEngine/SparseTensor/Storage.h
+++ b/mlir/include/mlir/ExecutionEngine/SparseTensor/Storage.h
@@ -186,6 +186,7 @@ class SparseTensorStorageBase {
 
 protected:
   const MapRef map; // non-owning pointers into dim2lvl/lvl2dim vectors
+  const bool allDense;
 };
 
 /// A memory-resident sparse tensor using a storage scheme based on
@@ -293,8 +294,6 @@ class SparseTensorStorage final : public SparseTensorStorageBase {
   /// Partially specialize lexicographical insertions based on template types.
   void lexInsert(const uint64_t *lvlCoords, V val) final {
     assert(lvlCoords);
-    bool allDense = std::all_of(getLvlTypes().begin(), getLvlTypes().end(),
-                                [](LevelType lt) { return isDenseLT(lt); });
     if (allDense) {
       uint64_t lvlRank = getLvlRank();
       uint64_t valIdx = 0;
@@ -363,10 +362,12 @@ class SparseTensorStorage final : public SparseTensorStorageBase {
 
   /// Finalizes lexicographic insertions.
   void endLexInsert() final {
-    if (values.empty())
-      finalizeSegment(0);
-    else
-      endPath(0);
+    if (!allDense) {
+      if (values.empty())
+        finalizeSegment(0);
+      else
+        endPath(0);
+    }
   }
 
   /// Allocates a new COO object and initializes it with the contents.
@@ -705,7 +706,6 @@ SparseTensorStorage<P, C, V>::SparseTensorStorage(
   // we reserve position/coordinate space based on all previous dense
   // levels, which works well up to first sparse level; but we should
   // really use nnz and dense/sparse distribution.
-  bool allDense = true;
   uint64_t sz = 1;
   for (uint64_t l = 0; l < lvlRank; l++) {
     if (isCompressedLvl(l)) {
@@ -713,23 +713,19 @@ SparseTensorStorage<P, C, V>::SparseTensorStorage(
       positions[l].push_back(0);
       coordinates[l].reserve(sz);
       sz = 1;
-      allDense = false;
     } else if (isLooseCompressedLvl(l)) {
       positions[l].reserve(2 * sz + 1); // last one unused
       positions[l].push_back(0);
       coordinates[l].reserve(sz);
       sz = 1;
-      allDense = false;
     } else if (isSingletonLvl(l)) {
       coordinates[l].reserve(sz);
       sz = 1;
-      allDense = false;
     } else if (is2OutOf4Lvl(l)) {
-      assert(allDense && l == lvlRank - 1 && "unexpected 2:4 usage");
+      assert(l == lvlRank - 1 && "unexpected 2:4 usage");
       sz = detail::checkedMul(sz, lvlSizes[l]) / 2;
       coordinates[l].reserve(sz);
       values.reserve(sz);
-      allDense = false;
     } else { // Dense level.
       assert(isDenseLvl(l));
       sz = detail::checkedMul(sz, lvlSizes[l]);
diff --git a/mlir/lib/ExecutionEngine/SparseTensor/Storage.cpp b/mlir/lib/ExecutionEngine/SparseTensor/Storage.cpp
index 7f8f76f8ec18901..0c7b3a228a65cf7 100644
--- a/mlir/lib/ExecutionEngine/SparseTensor/Storage.cpp
+++ b/mlir/lib/ExecutionEngine/SparseTensor/Storage.cpp
@@ -17,6 +17,13 @@
 
 using namespace mlir::sparse_tensor;
 
+static inline bool isAllDense(uint64_t lvlRank, const LevelType *lvlTypes) {
+  for (uint64_t l = 0; l < lvlRank; l++)
+    if (!isDenseLT(lvlTypes[l]))
+      return false;
+  return true;
+}
+
 SparseTensorStorageBase::SparseTensorStorageBase( // NOLINT
     uint64_t dimRank, const uint64_t *dimSizes, uint64_t lvlRank,
     const uint64_t *lvlSizes, const LevelType *lvlTypes,
@@ -26,15 +33,16 @@ SparseTensorStorageBase::SparseTensorStorageBase( // NOLINT
       lvlTypes(lvlTypes, lvlTypes + lvlRank),
       dim2lvlVec(dim2lvl, dim2lvl + lvlRank),
       lvl2dimVec(lvl2dim, lvl2dim + dimRank),
-      map(dimRank, lvlRank, dim2lvlVec.data(), lvl2dimVec.data()) {
+      map(dimRank, lvlRank, dim2lvlVec.data(), lvl2dimVec.data()),
+      allDense(isAllDense(lvlRank, lvlTypes)) {
   assert(dimSizes && lvlSizes && lvlTypes && dim2lvl && lvl2dim);
   // Validate dim-indexed parameters.
   assert(dimRank > 0 && "Trivial shape is unsupported");
-  for (uint64_t d = 0; d < dimRank; ++d)
+  for (uint64_t d = 0; d < dimRank; d++)
     assert(dimSizes[d] > 0 && "Dimension size zero has trivial storage");
   // Validate lvl-indexed parameters.
   assert(lvlRank > 0 && "Trivial shape is unsupported");
-  for (uint64_t l = 0; l < lvlRank; ++l) {
+  for (uint64_t l = 0; l < lvlRank; l++) {
     assert(lvlSizes[l] > 0 && "Level size zero has trivial storage");
     assert(isDenseLvl(l) || isCompressedLvl(l) || isLooseCompressedLvl(l) ||
            isSingletonLvl(l) || is2OutOf4Lvl(l));

@aartbik aartbik merged commit 6fb7c2d into llvm:main Nov 30, 2023
@aartbik aartbik deleted the bik branch November 30, 2023 22:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants