summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMathieu Chartier <mathieuc@google.com>2013-11-13 14:33:28 -0800
committerMathieu Chartier <mathieuc@google.com>2013-11-13 14:48:41 -0800
commitbcd5e9daecad39f0dab3246808b4835caec29ea6 (patch)
tree1221f94faef80c649e7236f0e7c3045383720abb
parentdfcca560e7b92e055a02adb39fdfb11798144cdd (diff)
downloadart-bcd5e9daecad39f0dab3246808b4835caec29ea6.zip
art-bcd5e9daecad39f0dab3246808b4835caec29ea6.tar.gz
art-bcd5e9daecad39f0dab3246808b4835caec29ea6.tar.bz2
Manually manage thread pool stacks.
We now allocate the thread pool worker stack using a MemMap. This enables us to name the maps so that we get more descriptive output for debugging leaks. Appears to fix the mips build 5/5 successful clean-oat and builds. This is probably since glibc caches up to 40 MB of thread stacks before releasing them. Change-Id: I1df2de50cb95838aa0d272a09807021404ba410c
-rw-r--r--compiler/driver/compiler_driver.cc4
-rw-r--r--runtime/barrier_test.cc4
-rw-r--r--runtime/gc/heap.cc2
-rw-r--r--runtime/thread_pool.cc20
-rw-r--r--runtime/thread_pool.h11
-rw-r--r--runtime/thread_pool_test.cc6
6 files changed, 27 insertions, 20 deletions
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 4af492b..d74383e 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -505,7 +505,7 @@ void CompilerDriver::CompileAll(jobject class_loader,
const std::vector<const DexFile*>& dex_files,
base::TimingLogger& timings) {
DCHECK(!Runtime::Current()->IsStarted());
- UniquePtr<ThreadPool> thread_pool(new ThreadPool(thread_count_ - 1));
+ UniquePtr<ThreadPool> thread_pool(new ThreadPool("Compiler driver thread pool", thread_count_ - 1));
PreCompile(class_loader, dex_files, *thread_pool.get(), timings);
Compile(class_loader, dex_files, *thread_pool.get(), timings);
if (dump_stats_) {
@@ -568,7 +568,7 @@ void CompilerDriver::CompileOne(const mirror::ArtMethod* method, base::TimingLog
std::vector<const DexFile*> dex_files;
dex_files.push_back(dex_file);
- UniquePtr<ThreadPool> thread_pool(new ThreadPool(0U));
+ UniquePtr<ThreadPool> thread_pool(new ThreadPool("Compiler driver thread pool", 0U));
PreCompile(jclass_loader, dex_files, *thread_pool.get(), timings);
uint32_t method_idx = method->GetDexMethodIndex();
diff --git a/runtime/barrier_test.cc b/runtime/barrier_test.cc
index 298ae56..91fc143 100644
--- a/runtime/barrier_test.cc
+++ b/runtime/barrier_test.cc
@@ -66,7 +66,7 @@ int32_t BarrierTest::num_threads = 4;
// Check that barrier wait and barrier increment work.
TEST_F(BarrierTest, CheckWait) {
Thread* self = Thread::Current();
- ThreadPool thread_pool(num_threads);
+ ThreadPool thread_pool("Barrier test thread pool", num_threads);
Barrier barrier(0);
AtomicInteger count1(0);
AtomicInteger count2(0);
@@ -121,7 +121,7 @@ class CheckPassTask : public Task {
// Check that barrier pass through works.
TEST_F(BarrierTest, CheckPass) {
Thread* self = Thread::Current();
- ThreadPool thread_pool(num_threads);
+ ThreadPool thread_pool("Barrier test thread pool", num_threads);
Barrier barrier(0);
AtomicInteger count(0);
const int32_t num_tasks = num_threads * 4;
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 69ca620..70df3d3 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -309,7 +309,7 @@ void Heap::DecrementDisableGC(Thread* self) {
void Heap::CreateThreadPool() {
const size_t num_threads = std::max(parallel_gc_threads_, conc_gc_threads_);
if (num_threads != 0) {
- thread_pool_.reset(new ThreadPool(num_threads));
+ thread_pool_.reset(new ThreadPool("Heap thread pool", num_threads));
}
}
diff --git a/runtime/thread_pool.cc b/runtime/thread_pool.cc
index bb6c475..aca0561 100644
--- a/runtime/thread_pool.cc
+++ b/runtime/thread_pool.cc
@@ -28,12 +28,15 @@ static constexpr bool kMeasureWaitTime = false;
ThreadPoolWorker::ThreadPoolWorker(ThreadPool* thread_pool, const std::string& name,
size_t stack_size)
: thread_pool_(thread_pool),
- name_(name),
- stack_size_(stack_size) {
+ name_(name) {
+ std::string error_msg;
+ stack_.reset(MemMap::MapAnonymous(name.c_str(), nullptr, stack_size, PROT_READ | PROT_WRITE,
+ &error_msg));
+ CHECK(stack_.get() != nullptr) << error_msg;
const char* reason = "new thread pool worker thread";
pthread_attr_t attr;
CHECK_PTHREAD_CALL(pthread_attr_init, (&attr), reason);
- CHECK_PTHREAD_CALL(pthread_attr_setstacksize, (&attr, stack_size), reason);
+ CHECK_PTHREAD_CALL(pthread_attr_setstack, (&attr, stack_->Begin(), stack_->Size()), reason);
CHECK_PTHREAD_CALL(pthread_create, (&pthread_, &attr, &Callback, this), reason);
CHECK_PTHREAD_CALL(pthread_attr_destroy, (&attr), reason);
}
@@ -71,8 +74,9 @@ void ThreadPool::AddTask(Thread* self, Task* task) {
}
}
-ThreadPool::ThreadPool(size_t num_threads)
- : task_queue_lock_("task queue lock"),
+ThreadPool::ThreadPool(const char* name, size_t num_threads)
+ : name_(name),
+ task_queue_lock_("task queue lock"),
task_queue_condition_("task queue condition", task_queue_lock_),
completion_condition_("task completion condition", task_queue_lock_),
started_(false),
@@ -85,7 +89,7 @@ ThreadPool::ThreadPool(size_t num_threads)
max_active_workers_(num_threads) {
Thread* self = Thread::Current();
while (GetThreadCount() < num_threads) {
- const std::string name = StringPrintf("Thread pool worker %zu", GetThreadCount());
+ const std::string name = StringPrintf("%s worker thread %zu", name_.c_str(), GetThreadCount());
threads_.push_back(new ThreadPoolWorker(this, name, ThreadPoolWorker::kDefaultStackSize));
}
// Wait for all of the threads to attach.
@@ -270,8 +274,8 @@ void WorkStealingWorker::Run() {
WorkStealingWorker::~WorkStealingWorker() {}
-WorkStealingThreadPool::WorkStealingThreadPool(size_t num_threads)
- : ThreadPool(0),
+WorkStealingThreadPool::WorkStealingThreadPool(const char* name, size_t num_threads)
+ : ThreadPool(name, 0),
work_steal_lock_("work stealing lock"),
steal_index_(0) {
while (GetThreadCount() < num_threads) {
diff --git a/runtime/thread_pool.h b/runtime/thread_pool.h
index b9a97a1..e8f9afe 100644
--- a/runtime/thread_pool.h
+++ b/runtime/thread_pool.h
@@ -24,6 +24,7 @@
#include "base/mutex.h"
#include "closure.h"
#include "locks.h"
+#include "mem_map.h"
namespace art {
@@ -40,7 +41,8 @@ class ThreadPoolWorker {
static const size_t kDefaultStackSize = 1 * MB;
size_t GetStackSize() const {
- return stack_size_;
+ DCHECK(stack_.get() != nullptr);
+ return stack_->Size();
}
virtual ~ThreadPoolWorker();
@@ -52,7 +54,7 @@ class ThreadPoolWorker {
ThreadPool* const thread_pool_;
const std::string name_;
- const size_t stack_size_;
+ UniquePtr<MemMap> stack_;
pthread_t pthread_;
private:
@@ -77,7 +79,7 @@ class ThreadPool {
// after running it, it is the caller's responsibility.
void AddTask(Thread* self, Task* task);
- explicit ThreadPool(size_t num_threads);
+ explicit ThreadPool(const char* name, size_t num_threads);
virtual ~ThreadPool();
// Wait for all tasks currently on queue to get completed.
@@ -107,6 +109,7 @@ class ThreadPool {
return shutting_down_;
}
+ const std::string name_;
Mutex task_queue_lock_;
ConditionVariable task_queue_condition_ GUARDED_BY(task_queue_lock_);
ConditionVariable completion_condition_ GUARDED_BY(task_queue_lock_);
@@ -167,7 +170,7 @@ class WorkStealingWorker : public ThreadPoolWorker {
class WorkStealingThreadPool : public ThreadPool {
public:
- explicit WorkStealingThreadPool(size_t num_threads);
+ explicit WorkStealingThreadPool(const char* name, size_t num_threads);
virtual ~WorkStealingThreadPool();
private:
diff --git a/runtime/thread_pool_test.cc b/runtime/thread_pool_test.cc
index 9b789d2..1b22361 100644
--- a/runtime/thread_pool_test.cc
+++ b/runtime/thread_pool_test.cc
@@ -59,7 +59,7 @@ int32_t ThreadPoolTest::num_threads = 4;
// Check that the thread pool actually runs tasks that you assign it.
TEST_F(ThreadPoolTest, CheckRun) {
Thread* self = Thread::Current();
- ThreadPool thread_pool(num_threads);
+ ThreadPool thread_pool("Thread pool test thread pool", num_threads);
AtomicInteger count(0);
static const int32_t num_tasks = num_threads * 4;
for (int32_t i = 0; i < num_tasks; ++i) {
@@ -74,7 +74,7 @@ TEST_F(ThreadPoolTest, CheckRun) {
TEST_F(ThreadPoolTest, StopStart) {
Thread* self = Thread::Current();
- ThreadPool thread_pool(num_threads);
+ ThreadPool thread_pool("Thread pool test thread pool", num_threads);
AtomicInteger count(0);
static const int32_t num_tasks = num_threads * 4;
for (int32_t i = 0; i < num_tasks; ++i) {
@@ -129,7 +129,7 @@ class TreeTask : public Task {
// Test that adding new tasks from within a task works.
TEST_F(ThreadPoolTest, RecursiveTest) {
Thread* self = Thread::Current();
- ThreadPool thread_pool(num_threads);
+ ThreadPool thread_pool("Thread pool test thread pool", num_threads);
AtomicInteger count(0);
static const int depth = 8;
thread_pool.AddTask(self, new TreeTask(&thread_pool, &count, depth));