// SPDX-License-Identifier: GPL-2.0
#include <sched.h>
#include <sys/syscall.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <sys/utsname.h>
#include <string.h>
#include "arch-tests.h"
#include "linux/perf_event.h"
#include "tests/tests.h"
#include "../perf-sys.h"
#include "pmu.h"
#include "pmus.h"
#include "debug.h"
#include "util.h"
#include "strbuf.h"
#include "../util/env.h"
static int page_size;
#define PERF_MMAP_DATA_PAGES 32L
#define PERF_MMAP_DATA_SIZE (PERF_MMAP_DATA_PAGES * page_size)
#define PERF_MMAP_DATA_MASK (PERF_MMAP_DATA_SIZE - 1)
#define PERF_MMAP_TOTAL_PAGES (PERF_MMAP_DATA_PAGES + 1)
#define PERF_MMAP_TOTAL_SIZE (PERF_MMAP_TOTAL_PAGES * page_size)
#define rmb() asm volatile("lfence":::"memory")
enum {
FD_ERROR,
FD_SUCCESS,
};
enum {
IBS_FETCH,
IBS_OP,
};
struct perf_pmu *fetch_pmu;
struct perf_pmu *op_pmu;
unsigned int perf_event_max_sample_rate;
/* Dummy workload to generate IBS samples. */
static int dummy_workload_1(unsigned long count)
{
int (*func)(void);
int ret = 0;
char *p;
char insn1[] = {
0xb8, 0x01, 0x00, 0x00, 0x00, /* mov 1,%eax */
0xc3, /* ret */
0xcc, /* int 3 */
};
char insn2[] = {
0xb8, 0x02, 0x00, 0x00, 0x00, /* mov 2,%eax */
0xc3, /* ret */
0xcc, /* int 3 */
};
p = calloc(2, page_size);
if (!p) {
printf("malloc() failed. %m");
return 1;
}
func = (void *)((unsigned long)(p + page_size - 1) & ~(page_size - 1));
ret = mprotect(func, page_size, PROT_READ | PROT_WRITE | PROT_EXEC);
if (ret) {
printf("mprotect() failed. %m");
goto out;
}
if (count < 100000)
count = 100000;
else if (count > 10000000)
count = 10000000;
while (count--) {
memcpy((void *)func, insn1, sizeof(insn1));
if (func() != 1) {
pr_debug("ERROR insn1\n");
ret = -1;
goto out;
}
memcpy((void *)func, insn2, sizeof(insn2));
if (func() != 2) {
pr_debug("ERROR insn2\n");
ret = -1;
goto out;
}
}
out:
free(p);
return ret;
}
/* Another dummy workload to generate IBS samples. */
static void dummy_workload_2(char *perf)
{
char bench[] = " bench sched messaging -g 10 -l 5000 > /dev/null 2>&1";
char taskset[] = "taskset -c 0 ";
int ret __maybe_unused;
struct strbuf sb;
char *cmd;
strbuf_init(&sb, 0);
strbuf_add(&sb, taskset, strlen(taskset));
strbuf_add(&sb, perf, strlen(perf));
strbuf_add(&sb, bench, strlen(bench));
cmd = strbuf_detach(&sb, NULL);
ret = system(cmd);
free(cmd);
}
static int sched_affine(int cpu)
{
cpu_set_t set;
CPU_ZERO(&set);
CPU_SET(cpu, &set);
if (sched_setaffinity(getpid(), sizeof(set), &set) == -1) {
pr_debug("sched_setaffinity() failed. [%m]");
return -1;
}
return 0;
}
static void
copy_sample_data(void *src, unsigned long offset, void *dest, size_t size)
{
size_t chunk1_size, chunk2_size;
if ((offset + size) < (size_t)PERF_MMAP_DATA_SIZE) {
memcpy(dest, src + offset, s