Skip to content

[Impeller] ResourceManagerVK never terminates it's thread #134482

@matanlurey

Description

@matanlurey

/cc @jonahwilliams

Starting at flutter/engine#45474 (flutter/engine@8d07c29), the ResourceManagerVK's spawn thread never terminates:

image

In practice, this doesn't (?) impact applications, because there is only a single instance per ContextVK, and the app eventually exits. It does impact unit testing, but we don't have much that spawns enough threads to notice the impact.

Here is a simple reproduction case using @gaaclarke's CreateMockVulkanContext():

$  ninja -j1000 -C ../out/host_debug_impeller_vulkan impeller_unittests && ../out/host_debug_impeller_vulkan/impeller_unittests --gtest_filter="MockVulkanContextTest.*" --gtest_repeat=10000

Note the --gtest_repeat=10000, because that (on my PC) is the magnitude required where threads are no longer created and the test runner crashes (around 4k or so), I didn't see the problem originally when running at --gtest_repeat=1000.

// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "flutter/testing/testing.h"  // IWYU pragma: keep
#include "gtest/gtest.h"
#include "impeller/renderer/backend/vulkan/command_pool_vk.h"
#include "impeller/renderer/backend/vulkan/test/mock_vulkan.h"

namespace impeller {
namespace testing {

TEST(MockVulkanContextTest, IsThreadSafe) {
  // In a typical app, there is a single ContextVK per app, shared b/w threads.
  //
  // This test ensures that the (mock) ContextVK is thread-safe.
  auto const context = CreateMockVulkanContext();

  // Spawn two threads, and have them create a CommandPoolVK each.
  std::thread thread1([&context]() {
    auto const pool = CommandPoolVK::GetThreadLocal(context.get());
    EXPECT_TRUE(pool);
  });

  std::thread thread2([&context]() {
    auto const pool = CommandPoolVK::GetThreadLocal(context.get());
    EXPECT_TRUE(pool);
  });

  thread1.join();
  thread2.join();

  context->Shutdown();
}

}  // namespace testing
}  // namespace impeller

It's likely the cause is this self-closure:

std::shared_ptr<ResourceManagerVK> ResourceManagerVK::Create() {
  auto manager = std::shared_ptr<ResourceManagerVK>(new ResourceManagerVK());
  manager->waiter_ = std::thread([manager]() { manager->Start(); });
  manager->waiter_.detach();
  return manager;
}

I'm investigating, and if we can't find a fix, or it's causing other problems, we'll revert.

Metadata

Metadata

Assignees

Labels

P1High-priority issues at the top of the work liste: impellerImpeller rendering backend issues and features requests

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions