blob: 0e8015a632dd8d419d7db9c3543e27321abee1f3 [file] [log] [blame]
// 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 <lib/fdio/directory.h>
#include <lib/zx/profile.h>
#include <lib/zx/result.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() {
zx::channel channel0, channel1;
zx_status_t status;
status = zx::channel::create(0u, &channel0, &channel1);
if (status != ZX_OK) {
return nullptr;
}
status = fdio_service_connect(
(std::string("/svc/") + fuchsia::kernel::ProfileResource::Name_).c_str(), channel0.release());
if (status != ZX_OK) {
return nullptr;
}
zx::resource profile_resource;
fuchsia::kernel::ProfileResource_SyncProxy proxy(std::move(channel1));
status = proxy.Get(&profile_resource);
if (status != ZX_OK) {
return nullptr;
}
return std::make_unique<ProfileManager>(std::move(profile_resource));
}
ProfileManager::ProfileManager(zx::resource profile_resource)
: profile_resource_(std::move(profile_resource)) {}
zx_status_t ProfileManager::SetThreadAffinity(const zx::thread& thread, uint32_t mask) {
return CreateAndApplyProfile<uint32_t>(
&affinity_profiles_, mask,
[this](uint32_t mask) -> zx::result<zx::profile> {
zx::profile profile;
zx_profile_info_t info = {
.flags = ZX_PROFILE_INFO_FLAG_CPU_MASK,
.cpu_affinity_mask = {mask},
};
zx_status_t status = zx::profile::create(profile_resource_, 0u, &info, &profile);
if (status != ZX_OK) {
return zx::error(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::result<zx::profile> {
zx::profile profile;
zx_profile_info_t info = {
.flags = ZX_PROFILE_INFO_FLAG_PRIORITY,
.priority = static_cast<int32_t>(priority),
};
zx_status_t status = zx::profile::create(profile_resource_, 0u, &info, &profile);
if (status != ZX_OK) {
return zx::error(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