| // Copyright 2020 The Fuchsia 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 "profile_manager.h" |
| |
| #include <fuchsia/scheduler/cpp/fidl.h> |
| #include <lib/sys/cpp/service_directory.h> |
| #include <lib/zx/profile.h> |
| #include <lib/zx/status.h> |
| #include <threads.h> |
| #include <zircon/assert.h> |
| #include <zircon/threads.h> |
| |
| #include <memory> |
| #include <thread> |
| #include <unordered_map> |
| #include <utility> |
| |
| #include "src/lib/fxl/strings/string_printf.h" |
| |
| namespace hwstress { |
| |
| zx::unowned<zx::thread> HandleFromThread(std::thread* thread) { |
| // The native handle is a thrd_t. We don't currently provide any nice way to convert this, other |
| // than this ugly cast. |
| zx_handle_t handle = thrd_get_zx_handle(static_cast<thrd_t>(thread->native_handle())); |
| return zx::unowned<zx::thread>(handle); |
| } |
| |
| std::unique_ptr<ProfileManager> ProfileManager::CreateFromEnvironment() { |
| std::shared_ptr<sys::ServiceDirectory> svc = sys::ServiceDirectory::CreateFromNamespace(); |
| if (svc == nullptr) { |
| return nullptr; |
| } |
| |
| fuchsia::scheduler::ProfileProviderSyncPtr profile_provider; |
| zx_status_t status = svc->Connect(profile_provider.NewRequest()); |
| if (status != ZX_OK) { |
| return nullptr; |
| } |
| |
| return std::make_unique<ProfileManager>(std::move(profile_provider)); |
| } |
| |
| ProfileManager::ProfileManager(fuchsia::scheduler::ProfileProviderSyncPtr profile_provider) |
| : profile_provider_(std::move(profile_provider)) {} |
| |
| zx_status_t ProfileManager::SetThreadAffinity(const zx::thread& thread, uint32_t mask) { |
| return CreateAndApplyProfile<uint32_t>( |
| &affinity_profiles_, mask, |
| [this](uint32_t mask) -> zx::status<zx::profile> { |
| zx::profile profile; |
| zx_status_t server_status; |
| zx_status_t status = |
| profile_provider_->GetCpuAffinityProfile({mask}, &server_status, &profile); |
| if (status != ZX_OK) { |
| return zx::error(status); |
| } |
| if (server_status != ZX_OK) { |
| return zx::error(server_status); |
| } |
| return zx::ok(std::move(profile)); |
| }, |
| thread); |
| } |
| |
| zx_status_t ProfileManager::SetThreadAffinity(std::thread* thread, uint32_t mask) { |
| return SetThreadAffinity(*HandleFromThread(thread), mask); |
| } |
| |
| zx_status_t ProfileManager::SetThreadPriority(const zx::thread& thread, uint32_t priority) { |
| return CreateAndApplyProfile<uint32_t>( |
| &priority_profiles_, priority, |
| [this](uint32_t priority) -> zx::status<zx::profile> { |
| zx::profile profile; |
| zx_status_t server_status; |
| zx_status_t status = profile_provider_->GetProfile( |
| priority, fxl::StringPrintf("hwstress-priority-%d", priority), &server_status, |
| &profile); |
| if (status != ZX_OK) { |
| return zx::error(status); |
| } |
| if (server_status != ZX_OK) { |
| return zx::error(server_status); |
| } |
| return zx::ok(std::move(profile)); |
| }, |
| thread); |
| } |
| |
| zx_status_t ProfileManager::SetThreadPriority(std::thread* thread, uint32_t priority) { |
| return SetThreadPriority(*HandleFromThread(thread), priority); |
| } |
| |
| } // namespace hwstress |