blob: 874ffcaebd038faf46ea7dda803feedda5fe7980 [file]
// Copyright 2026 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 <lib/syslog/cpp/macros.h>
#include <sys/mman.h>
#include <sys/prctl.h>
#include <unistd.h>
#include <thread>
#include <perftest/perftest.h>
#ifndef PR_SET_VMA
#define PR_SET_VMA 0x53564d41
#endif
#ifndef PR_SET_VMA_ANON_NAME
#define PR_SET_VMA_ANON_NAME 0
#endif
namespace {
bool SupportsSetVmaAnonName() {
const size_t page_size = static_cast<size_t>(sysconf(_SC_PAGESIZE));
void* addr = mmap(nullptr, page_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (addr == MAP_FAILED) {
return false;
}
bool supported = prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, addr, page_size, "probe") == 0;
FX_CHECK(munmap(addr, page_size) == 0);
return supported;
}
// Thread-group leader rename: also renames the process and reads argv[0].
bool PrctlSetNameLeader(perftest::RepeatState* state) {
char orig_name[16] = {};
FX_CHECK(prctl(PR_GET_NAME, orig_name) == 0);
constexpr const char* kNames[2] = {"bench_leader_0", "bench_leader_1"};
size_t i = 0;
while (state->KeepRunning()) {
FX_CHECK(prctl(PR_SET_NAME, kNames[i & 1]) == 0);
++i;
}
FX_CHECK(prctl(PR_SET_NAME, orig_name) == 0);
return true;
}
// Renaming to the current name.
bool PrctlSetNameUnchanged(perftest::RepeatState* state) {
char orig_name[16] = {};
FX_CHECK(prctl(PR_GET_NAME, orig_name) == 0);
FX_CHECK(prctl(PR_SET_NAME, "bench_unchanged") == 0);
while (state->KeepRunning()) {
FX_CHECK(prctl(PR_SET_NAME, "bench_unchanged") == 0);
}
FX_CHECK(prctl(PR_SET_NAME, orig_name) == 0);
return true;
}
// Non-leader rename: only the thread is renamed.
bool PrctlSetNameWorker(perftest::RepeatState* state) {
std::thread worker([state]() {
constexpr const char* kNames[2] = {"bench_worker_0", "bench_worker_1"};
size_t i = 0;
while (state->KeepRunning()) {
FX_CHECK(prctl(PR_SET_NAME, kNames[i & 1]) == 0);
++i;
}
});
worker.join();
return true;
}
bool PrctlSetVmaAnonName(perftest::RepeatState* state) {
const size_t page_size = static_cast<size_t>(sysconf(_SC_PAGESIZE));
void* addr = mmap(nullptr, page_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
FX_CHECK(addr != MAP_FAILED);
constexpr const char* kNames[2] = {"bench_vma_0", "bench_vma_1"};
size_t i = 0;
while (state->KeepRunning()) {
FX_CHECK(prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, addr, page_size, kNames[i & 1]) == 0);
++i;
}
FX_CHECK(munmap(addr, page_size) == 0);
return true;
}
bool PrctlSetVmaAnonNameUnchanged(perftest::RepeatState* state) {
const size_t page_size = static_cast<size_t>(sysconf(_SC_PAGESIZE));
void* addr = mmap(nullptr, page_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
FX_CHECK(addr != MAP_FAILED);
FX_CHECK(prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, addr, page_size, "bench_vma_unchanged") == 0);
while (state->KeepRunning()) {
FX_CHECK(prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, addr, page_size, "bench_vma_unchanged") == 0);
}
FX_CHECK(munmap(addr, page_size) == 0);
return true;
}
void RegisterTests() {
perftest::RegisterTest("Prctl/SetName/Leader", PrctlSetNameLeader);
perftest::RegisterTest("Prctl/SetName/Unchanged", PrctlSetNameUnchanged);
perftest::RegisterTest("Prctl/SetName/Worker", PrctlSetNameWorker);
// PR_SET_VMA_ANON_NAME needs CONFIG_ANON_VMA_NAME on Linux hosts.
if (SupportsSetVmaAnonName()) {
perftest::RegisterTest("Prctl/SetVmaAnonName", PrctlSetVmaAnonName);
perftest::RegisterTest("Prctl/SetVmaAnonName/Unchanged", PrctlSetVmaAnonNameUnchanged);
}
}
PERFTEST_CTOR(RegisterTests)
} // namespace