0

webnn: wait on coreml cache dir setup

Move Core ML cache directory setup logic to be called on WebNN context
creation and let context creation wait on the cache directory setup to
be finished.

Bug: 344935458
Change-Id: I045d7f644df7d3db0b5985e3b647812919ab820e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6237277
Reviewed-by: Mark Mentovai <mark@chromium.org>
Reviewed-by: Reilly Grant <reillyg@chromium.org>
Commit-Queue: Phillis Tang <phillis@chromium.org>
Auto-Submit: Phillis Tang <phillis@chromium.org>
Reviewed-by: Avi Drissman <avi@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1417848}
This commit is contained in:
Phillis Tang
2025-02-08 22:02:06 -08:00
committed by Chromium LUCI CQ
parent a8e8fa1698
commit 4247919d79
6 changed files with 117 additions and 27 deletions

@ -2786,6 +2786,7 @@ source_set("browser") {
"//components/remote_cocoa/browser",
"//components/remote_cocoa/common:mojo",
"//media",
"//services/webnn/public/cpp",
"//ui/accelerated_widget_mac",
"//ui/events:dom_keyboard_layout",
]

@ -238,6 +238,7 @@
#if BUILDFLAG(IS_MAC)
#include "content/browser/renderer_host/text_input_host_impl.h"
#include "services/webnn/public/cpp/coreml_initializer.h"
#include "third_party/blink/public/mojom/input/text_input_host.mojom.h"
#endif
@ -304,7 +305,13 @@ void BindWebNNContextProviderForRenderFrame(
RenderFrameHost* host,
mojo::PendingReceiver<webnn::mojom::WebNNContextProvider> receiver) {
auto* process_host = static_cast<RenderProcessHostImpl*>(host->GetProcess());
#if BUILDFLAG(IS_MAC)
webnn::InitializeCacheDirAndRun(base::BindOnce(
&viz::GpuClient::BindWebNNContextProvider,
process_host->GetGpuClient()->GetWeakPtr(), std::move(receiver)));
#else
process_host->GetGpuClient()->BindWebNNContextProvider(std::move(receiver));
#endif
}
void BindWebNNContextProviderForDedicatedWorker(
@ -312,7 +319,13 @@ void BindWebNNContextProviderForDedicatedWorker(
mojo::PendingReceiver<webnn::mojom::WebNNContextProvider> receiver) {
auto* process_host =
static_cast<RenderProcessHostImpl*>(host->GetProcessHost());
#if BUILDFLAG(IS_MAC)
webnn::InitializeCacheDirAndRun(base::BindOnce(
&viz::GpuClient::BindWebNNContextProvider,
process_host->GetGpuClient()->GetWeakPtr(), std::move(receiver)));
#else
process_host->GetGpuClient()->BindWebNNContextProvider(std::move(receiver));
#endif
}
#if BUILDFLAG(IS_MAC)

@ -127,8 +127,6 @@
#endif
#if BUILDFLAG(IS_MAC)
#include "base/apple/foundation_util.h"
#include "base/files/file_util.h"
#include "content/browser/gpu/browser_child_process_backgrounded_bridge.h"
#include "content/browser/gpu/ca_transaction_gpu_coordinator.h"
#endif
@ -535,25 +533,6 @@ void BindDiscardableMemoryReceiverOnUI(
discardable_memory::DiscardableSharedMemoryManager::Get()));
}
#if BUILDFLAG(IS_MAC)
// Create cache directory that's needed for WebNN. WebNN underlying uses Apple's
// Core ML framework that needs access to this directory. By creating the
// directory here we don't need to give the GPU process the ability to create
// directories in the sandbox policy.
void SetUpCoreMLCacheDir() {
base::FilePath cache_dir =
base::GetHomeDir()
.Append("Library")
.Append("Caches")
.Append(base::StrCat({base::apple::BaseBundleID(), ".helper"}))
.Append("com.apple.e5rt.e5bundlecache");
if (!base::CreateDirectory(cache_dir)) {
LOG(ERROR) << "Failed to setup cache directory for WebNN, this might "
"affect the performance and accuracy for WebNN.";
}
}
#endif
} // anonymous namespace
// static
@ -1238,12 +1217,6 @@ void GpuProcessHost::RunServiceImpl(mojo::GenericPendingReceiver receiver) {
}
bool GpuProcessHost::LaunchGpuProcess() {
#if BUILDFLAG(IS_MAC)
base::ThreadPool::PostTask(
FROM_HERE,
{base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN, base::MayBlock()},
base::BindOnce(&SetUpCoreMLCacheDir));
#endif
const base::CommandLine& browser_command_line =
*base::CommandLine::ForCurrentProcess();

@ -22,6 +22,13 @@ component("cpp") {
"webnn_trace.h",
]
if (is_mac) {
sources += [
"coreml_initializer.cc",
"coreml_initializer.h",
]
}
deps = [
"//base",
"//mojo/public/cpp/bindings",

@ -0,0 +1,74 @@
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "services/webnn/public/cpp/coreml_initializer.h"
#include <utility>
#include "base/apple/foundation_util.h"
#include "base/base_paths_posix.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/functional/callback.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/no_destructor.h"
#include "base/one_shot_event.h"
#include "base/path_service.h"
#include "base/strings/strcat.h"
#include "base/task/thread_pool.h"
namespace webnn {
namespace {
void SetupCacheDir() {
base::FilePath cache_dir;
if (!base::PathService::Get(base::DIR_CACHE, &cache_dir)) {
LOG(ERROR) << "Failed to get cache directory for WebNN, this might "
"affect the performance and accuracy for WebNN.";
return;
}
cache_dir =
cache_dir.Append(base::StrCat({base::apple::BaseBundleID(), ".helper"}))
.Append("com.apple.e5rt.e5bundlecache");
if (!base::CreateDirectory(cache_dir)) {
LOG(ERROR) << "Failed to setup cache directory for WebNN, this might "
"affect the performance and accuracy for WebNN.";
}
}
class WebNNCoreMLInitializer {
public:
WebNNCoreMLInitializer() {
base::ThreadPool::PostTaskAndReply(
FROM_HERE,
{base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN, base::MayBlock()},
base::BindOnce(&SetupCacheDir),
base::BindOnce(&WebNNCoreMLInitializer::OnCacheDirSetupDone,
base::Unretained(this)));
}
~WebNNCoreMLInitializer() = delete;
void RunAfterInitialize(base::OnceClosure callback) {
initialized_.Post(FROM_HERE, std::move(callback));
}
private:
void OnCacheDirSetupDone() { initialized_.Signal(); }
base::OneShotEvent initialized_;
};
} // namespace
void InitializeCacheDirAndRun(base::OnceClosure callback) {
// We only need to initialize once for the whole browser process, and no
// teardown logic is needed, so use a global singleton here.
static base::NoDestructor<WebNNCoreMLInitializer> g_webnn_coreml_initializer;
g_webnn_coreml_initializer->RunAfterInitialize(std::move(callback));
}
} // namespace webnn

@ -0,0 +1,22 @@
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SERVICES_WEBNN_PUBLIC_CPP_COREML_INITIALIZER_H_
#define SERVICES_WEBNN_PUBLIC_CPP_COREML_INITIALIZER_H_
#include "base/component_export.h"
#include "base/functional/callback_forward.h"
namespace webnn {
// This sets up cache directory that's needed for WebNN. WebNN underlying uses
// Apple's Core ML framework that needs access to this directory. By creating
// the directory in the browser process, we don't need to give the GPU process
// the ability to create directories in the sandbox policy.
COMPONENT_EXPORT(WEBNN_PUBLIC_CPP)
void InitializeCacheDirAndRun(base::OnceClosure callback);
} // namespace webnn
#endif // SERVICES_WEBNN_PUBLIC_CPP_COREML_INITIALIZER_H_