Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 15 additions & 14 deletions mlir/lib/IR/AttributeDetail.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,9 @@
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/IntegerSet.h"
#include "mlir/IR/MLIRContext.h"
#include "mlir/Support/StorageUniquer.h"
#include "mlir/Support/ThreadLocalCache.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/Support/TrailingObjects.h"
#include "llvm/Support/Allocator.h"
#include <mutex>

namespace mlir {
namespace detail {
Expand Down Expand Up @@ -396,27 +394,30 @@ class DistinctAttributeUniquer {
Attribute referencedAttr);
};

/// An allocator for distinct attribute storage instances. It uses thread local
/// bump pointer allocators stored in a thread local cache to ensure the storage
/// is freed after the destruction of the distinct attribute allocator.
class DistinctAttributeAllocator {
/// An allocator for distinct attribute storage instances. Uses a synchronized
/// BumpPtrAllocator to ensure thread-safety. The allocated storage is deleted
/// when the DistinctAttributeAllocator is destroyed.
class DistinctAttributeAllocator final {
public:
DistinctAttributeAllocator() = default;

DistinctAttributeAllocator(DistinctAttributeAllocator &&) = delete;
DistinctAttributeAllocator(const DistinctAttributeAllocator &) = delete;
DistinctAttributeAllocator &
operator=(const DistinctAttributeAllocator &) = delete;

/// Allocates a distinct attribute storage using a thread local bump pointer
/// allocator to enable synchronization free parallel allocations.
DistinctAttrStorage *allocate(Attribute referencedAttr) {
return new (allocatorCache.get().Allocate<DistinctAttrStorage>())
std::scoped_lock<std::mutex> guard(allocatorMutex);
return new (allocator.Allocate<DistinctAttrStorage>())
DistinctAttrStorage(referencedAttr);
}
};

private:
ThreadLocalCache<llvm::BumpPtrAllocator> allocatorCache;
/// Used to allocate distict attribute storages. The managed memory is freed
/// automatically when the allocator instance is destroyed.
llvm::BumpPtrAllocator allocator;

/// Used to lock access to the allocator.
std::mutex allocatorMutex;
};
} // namespace detail
} // namespace mlir
Expand Down
1 change: 1 addition & 0 deletions mlir/lib/IR/MLIRContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ManagedStatic.h"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Required on L74. I've juggled some headers around so I think this was being transitively included by accident prior.

#include "llvm/Support/Mutex.h"
#include "llvm/Support/RWMutex.h"
#include "llvm/Support/ThreadPool.h"
Expand Down
9 changes: 7 additions & 2 deletions mlir/lib/Pass/PassCrashRecovery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -411,14 +411,19 @@ struct FileReproducerStream : public mlir::ReproducerStream {

LogicalResult PassManager::runWithCrashRecovery(Operation *op,
AnalysisManager am) {
const bool threadingEnabled = getContext()->isMultithreadingEnabled();
crashReproGenerator->initialize(getPasses(), op, verifyPasses);

// Safely invoke the passes within a recovery context.
LogicalResult passManagerResult = failure();
llvm::CrashRecoveryContext recoveryContext;
recoveryContext.RunSafelyOnThread(
[&] { passManagerResult = runPasses(op, am); });
const auto runPassesFn = [&] { passManagerResult = runPasses(op, am); };
if (threadingEnabled)
recoveryContext.RunSafelyOnThread(runPassesFn);
else
recoveryContext.RunSafely(runPassesFn);
crashReproGenerator->finalize(op, passManagerResult);

return passManagerResult;
}

Expand Down
1 change: 1 addition & 0 deletions mlir/unittests/IR/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ add_mlir_unittest(MLIRIRTests
AttrTypeReplacerTest.cpp
Diagnostic.cpp
DialectTest.cpp
DistinctAttributeAllocatorTest.cpp
InterfaceTest.cpp
IRMapping.cpp
InterfaceAttachmentTest.cpp
Expand Down
45 changes: 45 additions & 0 deletions mlir/unittests/IR/DistinctAttributeAllocatorTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//=== DistinctAttributeAllocatorTest.cpp - DistinctAttr storage alloc test ===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "gtest/gtest.h"

#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinAttributes.h"
#include "mlir/IR/MLIRContext.h"
#include "llvm/Support/CrashRecoveryContext.h"
#include <thread>

using namespace mlir;

//
// Test that a DistinctAttr that is created on a separate thread does
// not have its storage deleted when the thread joins.
//
TEST(DistinctAttributeAllocatorTest, TestAttributeWellFormedAfterThreadJoin) {
MLIRContext ctx;
OpBuilder builder(&ctx);
DistinctAttr attr;

std::thread t([&ctx, &attr]() {
attr = DistinctAttr::create(UnitAttr::get(&ctx));
ASSERT_TRUE(attr);
});
t.join();

// If the attribute storage got deleted after the thread joins (which we don't
// want) then trying to access it triggers an assert in Debug mode, and a
// crash otherwise. Run this in a CrashRecoveryContext to avoid bringing down
// the whole test suite if this test fails. Additionally, MSAN and/or TSAN
// should raise failures here if the attribute storage was deleted.
llvm::CrashRecoveryContext crc;
EXPECT_TRUE(crc.RunSafely([attr]() { (void)attr.getAbstractAttribute(); }));
EXPECT_TRUE(
crc.RunSafely([attr]() { (void)*cast<Attribute>(attr).getImpl(); }));

ASSERT_TRUE(attr);
}