162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * perf events self profiling example test case for hw breakpoints. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * This tests perf PERF_TYPE_BREAKPOINT parameters 662306a36Sopenharmony_ci * 1) tests all variants of the break on read/write flags 762306a36Sopenharmony_ci * 2) tests exclude_user == 0 and 1 862306a36Sopenharmony_ci * 3) test array matches (if DAWR is supported)) 962306a36Sopenharmony_ci * 4) test different numbers of breakpoints matches 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * Configure this breakpoint, then read and write the data a number of 1262306a36Sopenharmony_ci * times. Then check the output count from perf is as expected. 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * Based on: 1562306a36Sopenharmony_ci * http://ozlabs.org/~anton/junkcode/perf_events_example1.c 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * Copyright (C) 2018 Michael Neuling, IBM Corporation. 1862306a36Sopenharmony_ci */ 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#define _GNU_SOURCE 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include <unistd.h> 2362306a36Sopenharmony_ci#include <assert.h> 2462306a36Sopenharmony_ci#include <sched.h> 2562306a36Sopenharmony_ci#include <stdio.h> 2662306a36Sopenharmony_ci#include <stdlib.h> 2762306a36Sopenharmony_ci#include <signal.h> 2862306a36Sopenharmony_ci#include <string.h> 2962306a36Sopenharmony_ci#include <sys/ioctl.h> 3062306a36Sopenharmony_ci#include <sys/wait.h> 3162306a36Sopenharmony_ci#include <sys/ptrace.h> 3262306a36Sopenharmony_ci#include <sys/resource.h> 3362306a36Sopenharmony_ci#include <sys/sysinfo.h> 3462306a36Sopenharmony_ci#include <asm/ptrace.h> 3562306a36Sopenharmony_ci#include <elf.h> 3662306a36Sopenharmony_ci#include <pthread.h> 3762306a36Sopenharmony_ci#include <sys/syscall.h> 3862306a36Sopenharmony_ci#include <linux/perf_event.h> 3962306a36Sopenharmony_ci#include <linux/hw_breakpoint.h> 4062306a36Sopenharmony_ci#include "utils.h" 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#ifndef PPC_DEBUG_FEATURE_DATA_BP_ARCH_31 4362306a36Sopenharmony_ci#define PPC_DEBUG_FEATURE_DATA_BP_ARCH_31 0x20 4462306a36Sopenharmony_ci#endif 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#define MAX_LOOPS 10000 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#define DAWR_LENGTH_MAX ((0x3f + 1) * 8) 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ciint nprocs; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistatic volatile int a = 10; 5362306a36Sopenharmony_cistatic volatile int b = 10; 5462306a36Sopenharmony_cistatic volatile char c[512 + 8] __attribute__((aligned(512))); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic void perf_event_attr_set(struct perf_event_attr *attr, 5762306a36Sopenharmony_ci __u32 type, __u64 addr, __u64 len, 5862306a36Sopenharmony_ci bool exclude_user) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci memset(attr, 0, sizeof(struct perf_event_attr)); 6162306a36Sopenharmony_ci attr->type = PERF_TYPE_BREAKPOINT; 6262306a36Sopenharmony_ci attr->size = sizeof(struct perf_event_attr); 6362306a36Sopenharmony_ci attr->bp_type = type; 6462306a36Sopenharmony_ci attr->bp_addr = addr; 6562306a36Sopenharmony_ci attr->bp_len = len; 6662306a36Sopenharmony_ci attr->exclude_kernel = 1; 6762306a36Sopenharmony_ci attr->exclude_hv = 1; 6862306a36Sopenharmony_ci attr->exclude_guest = 1; 6962306a36Sopenharmony_ci attr->exclude_user = exclude_user; 7062306a36Sopenharmony_ci attr->disabled = 1; 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistatic int 7462306a36Sopenharmony_ciperf_process_event_open_exclude_user(__u32 type, __u64 addr, __u64 len, bool exclude_user) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci struct perf_event_attr attr; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci perf_event_attr_set(&attr, type, addr, len, exclude_user); 7962306a36Sopenharmony_ci return syscall(__NR_perf_event_open, &attr, getpid(), -1, -1, 0); 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistatic int perf_process_event_open(__u32 type, __u64 addr, __u64 len) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci struct perf_event_attr attr; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci perf_event_attr_set(&attr, type, addr, len, 0); 8762306a36Sopenharmony_ci return syscall(__NR_perf_event_open, &attr, getpid(), -1, -1, 0); 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cistatic int perf_cpu_event_open(long cpu, __u32 type, __u64 addr, __u64 len) 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci struct perf_event_attr attr; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci perf_event_attr_set(&attr, type, addr, len, 0); 9562306a36Sopenharmony_ci return syscall(__NR_perf_event_open, &attr, -1, cpu, -1, 0); 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic void close_fds(int *fd, int n) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci int i; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci for (i = 0; i < n; i++) 10362306a36Sopenharmony_ci close(fd[i]); 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic unsigned long read_fds(int *fd, int n) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci int i; 10962306a36Sopenharmony_ci unsigned long c = 0; 11062306a36Sopenharmony_ci unsigned long count = 0; 11162306a36Sopenharmony_ci size_t res; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci for (i = 0; i < n; i++) { 11462306a36Sopenharmony_ci res = read(fd[i], &c, sizeof(c)); 11562306a36Sopenharmony_ci assert(res == sizeof(unsigned long long)); 11662306a36Sopenharmony_ci count += c; 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci return count; 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistatic void reset_fds(int *fd, int n) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci int i; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci for (i = 0; i < n; i++) 12662306a36Sopenharmony_ci ioctl(fd[i], PERF_EVENT_IOC_RESET); 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cistatic void enable_fds(int *fd, int n) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci int i; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci for (i = 0; i < n; i++) 13462306a36Sopenharmony_ci ioctl(fd[i], PERF_EVENT_IOC_ENABLE); 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistatic void disable_fds(int *fd, int n) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci int i; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci for (i = 0; i < n; i++) 14262306a36Sopenharmony_ci ioctl(fd[i], PERF_EVENT_IOC_DISABLE); 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cistatic int perf_systemwide_event_open(int *fd, __u32 type, __u64 addr, __u64 len) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci int i, ncpus, cpu, ret = 0; 14862306a36Sopenharmony_ci struct rlimit rlim; 14962306a36Sopenharmony_ci cpu_set_t *mask; 15062306a36Sopenharmony_ci size_t size; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci if (getrlimit(RLIMIT_NOFILE, &rlim)) { 15362306a36Sopenharmony_ci perror("getrlimit"); 15462306a36Sopenharmony_ci return -1; 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci rlim.rlim_cur = 65536; 15762306a36Sopenharmony_ci if (setrlimit(RLIMIT_NOFILE, &rlim)) { 15862306a36Sopenharmony_ci perror("setrlimit"); 15962306a36Sopenharmony_ci return -1; 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci ncpus = get_nprocs_conf(); 16362306a36Sopenharmony_ci size = CPU_ALLOC_SIZE(ncpus); 16462306a36Sopenharmony_ci mask = CPU_ALLOC(ncpus); 16562306a36Sopenharmony_ci if (!mask) { 16662306a36Sopenharmony_ci perror("malloc"); 16762306a36Sopenharmony_ci return -1; 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci CPU_ZERO_S(size, mask); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci if (sched_getaffinity(0, size, mask)) { 17362306a36Sopenharmony_ci perror("sched_getaffinity"); 17462306a36Sopenharmony_ci ret = -1; 17562306a36Sopenharmony_ci goto done; 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci for (i = 0, cpu = 0; i < nprocs && cpu < ncpus; cpu++) { 17962306a36Sopenharmony_ci if (!CPU_ISSET_S(cpu, size, mask)) 18062306a36Sopenharmony_ci continue; 18162306a36Sopenharmony_ci fd[i] = perf_cpu_event_open(cpu, type, addr, len); 18262306a36Sopenharmony_ci if (fd[i] < 0) { 18362306a36Sopenharmony_ci perror("perf_systemwide_event_open"); 18462306a36Sopenharmony_ci close_fds(fd, i); 18562306a36Sopenharmony_ci ret = fd[i]; 18662306a36Sopenharmony_ci goto done; 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci i++; 18962306a36Sopenharmony_ci } 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci if (i < nprocs) { 19262306a36Sopenharmony_ci printf("Error: Number of online cpus reduced since start of test: %d < %d\n", i, nprocs); 19362306a36Sopenharmony_ci close_fds(fd, i); 19462306a36Sopenharmony_ci ret = -1; 19562306a36Sopenharmony_ci } 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_cidone: 19862306a36Sopenharmony_ci CPU_FREE(mask); 19962306a36Sopenharmony_ci return ret; 20062306a36Sopenharmony_ci} 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_cistatic inline bool breakpoint_test(int len) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci int fd; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci /* bp_addr can point anywhere but needs to be aligned */ 20762306a36Sopenharmony_ci fd = perf_process_event_open(HW_BREAKPOINT_R, (__u64)(&fd) & 0xfffffffffffff800, len); 20862306a36Sopenharmony_ci if (fd < 0) 20962306a36Sopenharmony_ci return false; 21062306a36Sopenharmony_ci close(fd); 21162306a36Sopenharmony_ci return true; 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_cistatic inline bool perf_breakpoint_supported(void) 21562306a36Sopenharmony_ci{ 21662306a36Sopenharmony_ci return breakpoint_test(4); 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_cistatic inline bool dawr_supported(void) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci return breakpoint_test(DAWR_LENGTH_MAX); 22262306a36Sopenharmony_ci} 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_cistatic int runtestsingle(int readwriteflag, int exclude_user, int arraytest) 22562306a36Sopenharmony_ci{ 22662306a36Sopenharmony_ci int i,j; 22762306a36Sopenharmony_ci size_t res; 22862306a36Sopenharmony_ci unsigned long long breaks, needed; 22962306a36Sopenharmony_ci int readint; 23062306a36Sopenharmony_ci int readintarraybig[2*DAWR_LENGTH_MAX/sizeof(int)]; 23162306a36Sopenharmony_ci int *readintalign; 23262306a36Sopenharmony_ci volatile int *ptr; 23362306a36Sopenharmony_ci int break_fd; 23462306a36Sopenharmony_ci int loop_num = MAX_LOOPS - (rand() % 100); /* provide some variability */ 23562306a36Sopenharmony_ci volatile int *k; 23662306a36Sopenharmony_ci __u64 len; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci /* align to 0x400 boundary as required by DAWR */ 23962306a36Sopenharmony_ci readintalign = (int *)(((unsigned long)readintarraybig + 0x7ff) & 24062306a36Sopenharmony_ci 0xfffffffffffff800); 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci ptr = &readint; 24362306a36Sopenharmony_ci if (arraytest) 24462306a36Sopenharmony_ci ptr = &readintalign[0]; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci len = arraytest ? DAWR_LENGTH_MAX : sizeof(int); 24762306a36Sopenharmony_ci break_fd = perf_process_event_open_exclude_user(readwriteflag, (__u64)ptr, 24862306a36Sopenharmony_ci len, exclude_user); 24962306a36Sopenharmony_ci if (break_fd < 0) { 25062306a36Sopenharmony_ci perror("perf_process_event_open_exclude_user"); 25162306a36Sopenharmony_ci exit(1); 25262306a36Sopenharmony_ci } 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci /* start counters */ 25562306a36Sopenharmony_ci ioctl(break_fd, PERF_EVENT_IOC_ENABLE); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci /* Test a bunch of reads and writes */ 25862306a36Sopenharmony_ci k = &readint; 25962306a36Sopenharmony_ci for (i = 0; i < loop_num; i++) { 26062306a36Sopenharmony_ci if (arraytest) 26162306a36Sopenharmony_ci k = &(readintalign[i % (DAWR_LENGTH_MAX/sizeof(int))]); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci j = *k; 26462306a36Sopenharmony_ci *k = j; 26562306a36Sopenharmony_ci } 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci /* stop counters */ 26862306a36Sopenharmony_ci ioctl(break_fd, PERF_EVENT_IOC_DISABLE); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci /* read and check counters */ 27162306a36Sopenharmony_ci res = read(break_fd, &breaks, sizeof(unsigned long long)); 27262306a36Sopenharmony_ci assert(res == sizeof(unsigned long long)); 27362306a36Sopenharmony_ci /* we read and write each loop, so subtract the ones we are counting */ 27462306a36Sopenharmony_ci needed = 0; 27562306a36Sopenharmony_ci if (readwriteflag & HW_BREAKPOINT_R) 27662306a36Sopenharmony_ci needed += loop_num; 27762306a36Sopenharmony_ci if (readwriteflag & HW_BREAKPOINT_W) 27862306a36Sopenharmony_ci needed += loop_num; 27962306a36Sopenharmony_ci needed = needed * (1 - exclude_user); 28062306a36Sopenharmony_ci printf("TESTED: addr:0x%lx brks:% 8lld loops:% 8i rw:%i !user:%i array:%i\n", 28162306a36Sopenharmony_ci (unsigned long int)ptr, breaks, loop_num, readwriteflag, exclude_user, arraytest); 28262306a36Sopenharmony_ci if (breaks != needed) { 28362306a36Sopenharmony_ci printf("FAILED: 0x%lx brks:%lld needed:%lli %i %i %i\n\n", 28462306a36Sopenharmony_ci (unsigned long int)ptr, breaks, needed, loop_num, readwriteflag, exclude_user); 28562306a36Sopenharmony_ci return 1; 28662306a36Sopenharmony_ci } 28762306a36Sopenharmony_ci close(break_fd); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci return 0; 29062306a36Sopenharmony_ci} 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_cistatic int runtest_dar_outside(void) 29362306a36Sopenharmony_ci{ 29462306a36Sopenharmony_ci void *target; 29562306a36Sopenharmony_ci volatile __u16 temp16; 29662306a36Sopenharmony_ci volatile __u64 temp64; 29762306a36Sopenharmony_ci int break_fd; 29862306a36Sopenharmony_ci unsigned long long breaks; 29962306a36Sopenharmony_ci int fail = 0; 30062306a36Sopenharmony_ci size_t res; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci target = malloc(8); 30362306a36Sopenharmony_ci if (!target) { 30462306a36Sopenharmony_ci perror("malloc failed"); 30562306a36Sopenharmony_ci exit(EXIT_FAILURE); 30662306a36Sopenharmony_ci } 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci /* watch middle half of target array */ 30962306a36Sopenharmony_ci break_fd = perf_process_event_open(HW_BREAKPOINT_RW, (__u64)(target + 2), 4); 31062306a36Sopenharmony_ci if (break_fd < 0) { 31162306a36Sopenharmony_ci free(target); 31262306a36Sopenharmony_ci perror("perf_process_event_open"); 31362306a36Sopenharmony_ci exit(EXIT_FAILURE); 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci /* Shouldn't hit. */ 31762306a36Sopenharmony_ci ioctl(break_fd, PERF_EVENT_IOC_RESET); 31862306a36Sopenharmony_ci ioctl(break_fd, PERF_EVENT_IOC_ENABLE); 31962306a36Sopenharmony_ci temp16 = *((__u16 *)target); 32062306a36Sopenharmony_ci *((__u16 *)target) = temp16; 32162306a36Sopenharmony_ci ioctl(break_fd, PERF_EVENT_IOC_DISABLE); 32262306a36Sopenharmony_ci res = read(break_fd, &breaks, sizeof(unsigned long long)); 32362306a36Sopenharmony_ci assert(res == sizeof(unsigned long long)); 32462306a36Sopenharmony_ci if (breaks == 0) { 32562306a36Sopenharmony_ci printf("TESTED: No overlap\n"); 32662306a36Sopenharmony_ci } else { 32762306a36Sopenharmony_ci printf("FAILED: No overlap: %lld != 0\n", breaks); 32862306a36Sopenharmony_ci fail = 1; 32962306a36Sopenharmony_ci } 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci /* Hit */ 33262306a36Sopenharmony_ci ioctl(break_fd, PERF_EVENT_IOC_RESET); 33362306a36Sopenharmony_ci ioctl(break_fd, PERF_EVENT_IOC_ENABLE); 33462306a36Sopenharmony_ci temp16 = *((__u16 *)(target + 1)); 33562306a36Sopenharmony_ci *((__u16 *)(target + 1)) = temp16; 33662306a36Sopenharmony_ci ioctl(break_fd, PERF_EVENT_IOC_DISABLE); 33762306a36Sopenharmony_ci res = read(break_fd, &breaks, sizeof(unsigned long long)); 33862306a36Sopenharmony_ci assert(res == sizeof(unsigned long long)); 33962306a36Sopenharmony_ci if (breaks == 2) { 34062306a36Sopenharmony_ci printf("TESTED: Partial overlap\n"); 34162306a36Sopenharmony_ci } else { 34262306a36Sopenharmony_ci printf("FAILED: Partial overlap: %lld != 2\n", breaks); 34362306a36Sopenharmony_ci fail = 1; 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci /* Hit */ 34762306a36Sopenharmony_ci ioctl(break_fd, PERF_EVENT_IOC_RESET); 34862306a36Sopenharmony_ci ioctl(break_fd, PERF_EVENT_IOC_ENABLE); 34962306a36Sopenharmony_ci temp16 = *((__u16 *)(target + 5)); 35062306a36Sopenharmony_ci *((__u16 *)(target + 5)) = temp16; 35162306a36Sopenharmony_ci ioctl(break_fd, PERF_EVENT_IOC_DISABLE); 35262306a36Sopenharmony_ci res = read(break_fd, &breaks, sizeof(unsigned long long)); 35362306a36Sopenharmony_ci assert(res == sizeof(unsigned long long)); 35462306a36Sopenharmony_ci if (breaks == 2) { 35562306a36Sopenharmony_ci printf("TESTED: Partial overlap\n"); 35662306a36Sopenharmony_ci } else { 35762306a36Sopenharmony_ci printf("FAILED: Partial overlap: %lld != 2\n", breaks); 35862306a36Sopenharmony_ci fail = 1; 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci /* Shouldn't Hit */ 36262306a36Sopenharmony_ci ioctl(break_fd, PERF_EVENT_IOC_RESET); 36362306a36Sopenharmony_ci ioctl(break_fd, PERF_EVENT_IOC_ENABLE); 36462306a36Sopenharmony_ci temp16 = *((__u16 *)(target + 6)); 36562306a36Sopenharmony_ci *((__u16 *)(target + 6)) = temp16; 36662306a36Sopenharmony_ci ioctl(break_fd, PERF_EVENT_IOC_DISABLE); 36762306a36Sopenharmony_ci res = read(break_fd, &breaks, sizeof(unsigned long long)); 36862306a36Sopenharmony_ci assert(res == sizeof(unsigned long long)); 36962306a36Sopenharmony_ci if (breaks == 0) { 37062306a36Sopenharmony_ci printf("TESTED: No overlap\n"); 37162306a36Sopenharmony_ci } else { 37262306a36Sopenharmony_ci printf("FAILED: No overlap: %lld != 0\n", breaks); 37362306a36Sopenharmony_ci fail = 1; 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci /* Hit */ 37762306a36Sopenharmony_ci ioctl(break_fd, PERF_EVENT_IOC_RESET); 37862306a36Sopenharmony_ci ioctl(break_fd, PERF_EVENT_IOC_ENABLE); 37962306a36Sopenharmony_ci temp64 = *((__u64 *)target); 38062306a36Sopenharmony_ci *((__u64 *)target) = temp64; 38162306a36Sopenharmony_ci ioctl(break_fd, PERF_EVENT_IOC_DISABLE); 38262306a36Sopenharmony_ci res = read(break_fd, &breaks, sizeof(unsigned long long)); 38362306a36Sopenharmony_ci assert(res == sizeof(unsigned long long)); 38462306a36Sopenharmony_ci if (breaks == 2) { 38562306a36Sopenharmony_ci printf("TESTED: Full overlap\n"); 38662306a36Sopenharmony_ci } else { 38762306a36Sopenharmony_ci printf("FAILED: Full overlap: %lld != 2\n", breaks); 38862306a36Sopenharmony_ci fail = 1; 38962306a36Sopenharmony_ci } 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci free(target); 39262306a36Sopenharmony_ci close(break_fd); 39362306a36Sopenharmony_ci return fail; 39462306a36Sopenharmony_ci} 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_cistatic void multi_dawr_workload(void) 39762306a36Sopenharmony_ci{ 39862306a36Sopenharmony_ci a += 10; 39962306a36Sopenharmony_ci b += 10; 40062306a36Sopenharmony_ci c[512 + 1] += 'a'; 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_cistatic int test_process_multi_diff_addr(void) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci unsigned long long breaks1 = 0, breaks2 = 0; 40662306a36Sopenharmony_ci int fd1, fd2; 40762306a36Sopenharmony_ci char *desc = "Process specific, Two events, diff addr"; 40862306a36Sopenharmony_ci size_t res; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci fd1 = perf_process_event_open(HW_BREAKPOINT_RW, (__u64)&a, (__u64)sizeof(a)); 41162306a36Sopenharmony_ci if (fd1 < 0) { 41262306a36Sopenharmony_ci perror("perf_process_event_open"); 41362306a36Sopenharmony_ci exit(EXIT_FAILURE); 41462306a36Sopenharmony_ci } 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci fd2 = perf_process_event_open(HW_BREAKPOINT_RW, (__u64)&b, (__u64)sizeof(b)); 41762306a36Sopenharmony_ci if (fd2 < 0) { 41862306a36Sopenharmony_ci close(fd1); 41962306a36Sopenharmony_ci perror("perf_process_event_open"); 42062306a36Sopenharmony_ci exit(EXIT_FAILURE); 42162306a36Sopenharmony_ci } 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci ioctl(fd1, PERF_EVENT_IOC_RESET); 42462306a36Sopenharmony_ci ioctl(fd2, PERF_EVENT_IOC_RESET); 42562306a36Sopenharmony_ci ioctl(fd1, PERF_EVENT_IOC_ENABLE); 42662306a36Sopenharmony_ci ioctl(fd2, PERF_EVENT_IOC_ENABLE); 42762306a36Sopenharmony_ci multi_dawr_workload(); 42862306a36Sopenharmony_ci ioctl(fd1, PERF_EVENT_IOC_DISABLE); 42962306a36Sopenharmony_ci ioctl(fd2, PERF_EVENT_IOC_DISABLE); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci res = read(fd1, &breaks1, sizeof(breaks1)); 43262306a36Sopenharmony_ci assert(res == sizeof(unsigned long long)); 43362306a36Sopenharmony_ci res = read(fd2, &breaks2, sizeof(breaks2)); 43462306a36Sopenharmony_ci assert(res == sizeof(unsigned long long)); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci close(fd1); 43762306a36Sopenharmony_ci close(fd2); 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci if (breaks1 != 2 || breaks2 != 2) { 44062306a36Sopenharmony_ci printf("FAILED: %s: %lld != 2 || %lld != 2\n", desc, breaks1, breaks2); 44162306a36Sopenharmony_ci return 1; 44262306a36Sopenharmony_ci } 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci printf("TESTED: %s\n", desc); 44562306a36Sopenharmony_ci return 0; 44662306a36Sopenharmony_ci} 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_cistatic int test_process_multi_same_addr(void) 44962306a36Sopenharmony_ci{ 45062306a36Sopenharmony_ci unsigned long long breaks1 = 0, breaks2 = 0; 45162306a36Sopenharmony_ci int fd1, fd2; 45262306a36Sopenharmony_ci char *desc = "Process specific, Two events, same addr"; 45362306a36Sopenharmony_ci size_t res; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci fd1 = perf_process_event_open(HW_BREAKPOINT_RW, (__u64)&a, (__u64)sizeof(a)); 45662306a36Sopenharmony_ci if (fd1 < 0) { 45762306a36Sopenharmony_ci perror("perf_process_event_open"); 45862306a36Sopenharmony_ci exit(EXIT_FAILURE); 45962306a36Sopenharmony_ci } 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci fd2 = perf_process_event_open(HW_BREAKPOINT_RW, (__u64)&a, (__u64)sizeof(a)); 46262306a36Sopenharmony_ci if (fd2 < 0) { 46362306a36Sopenharmony_ci close(fd1); 46462306a36Sopenharmony_ci perror("perf_process_event_open"); 46562306a36Sopenharmony_ci exit(EXIT_FAILURE); 46662306a36Sopenharmony_ci } 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci ioctl(fd1, PERF_EVENT_IOC_RESET); 46962306a36Sopenharmony_ci ioctl(fd2, PERF_EVENT_IOC_RESET); 47062306a36Sopenharmony_ci ioctl(fd1, PERF_EVENT_IOC_ENABLE); 47162306a36Sopenharmony_ci ioctl(fd2, PERF_EVENT_IOC_ENABLE); 47262306a36Sopenharmony_ci multi_dawr_workload(); 47362306a36Sopenharmony_ci ioctl(fd1, PERF_EVENT_IOC_DISABLE); 47462306a36Sopenharmony_ci ioctl(fd2, PERF_EVENT_IOC_DISABLE); 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci res = read(fd1, &breaks1, sizeof(breaks1)); 47762306a36Sopenharmony_ci assert(res == sizeof(unsigned long long)); 47862306a36Sopenharmony_ci res = read(fd2, &breaks2, sizeof(breaks2)); 47962306a36Sopenharmony_ci assert(res == sizeof(unsigned long long)); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci close(fd1); 48262306a36Sopenharmony_ci close(fd2); 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci if (breaks1 != 2 || breaks2 != 2) { 48562306a36Sopenharmony_ci printf("FAILED: %s: %lld != 2 || %lld != 2\n", desc, breaks1, breaks2); 48662306a36Sopenharmony_ci return 1; 48762306a36Sopenharmony_ci } 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci printf("TESTED: %s\n", desc); 49062306a36Sopenharmony_ci return 0; 49162306a36Sopenharmony_ci} 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_cistatic int test_process_multi_diff_addr_ro_wo(void) 49462306a36Sopenharmony_ci{ 49562306a36Sopenharmony_ci unsigned long long breaks1 = 0, breaks2 = 0; 49662306a36Sopenharmony_ci int fd1, fd2; 49762306a36Sopenharmony_ci char *desc = "Process specific, Two events, diff addr, one is RO, other is WO"; 49862306a36Sopenharmony_ci size_t res; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci fd1 = perf_process_event_open(HW_BREAKPOINT_W, (__u64)&a, (__u64)sizeof(a)); 50162306a36Sopenharmony_ci if (fd1 < 0) { 50262306a36Sopenharmony_ci perror("perf_process_event_open"); 50362306a36Sopenharmony_ci exit(EXIT_FAILURE); 50462306a36Sopenharmony_ci } 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci fd2 = perf_process_event_open(HW_BREAKPOINT_R, (__u64)&b, (__u64)sizeof(b)); 50762306a36Sopenharmony_ci if (fd2 < 0) { 50862306a36Sopenharmony_ci close(fd1); 50962306a36Sopenharmony_ci perror("perf_process_event_open"); 51062306a36Sopenharmony_ci exit(EXIT_FAILURE); 51162306a36Sopenharmony_ci } 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci ioctl(fd1, PERF_EVENT_IOC_RESET); 51462306a36Sopenharmony_ci ioctl(fd2, PERF_EVENT_IOC_RESET); 51562306a36Sopenharmony_ci ioctl(fd1, PERF_EVENT_IOC_ENABLE); 51662306a36Sopenharmony_ci ioctl(fd2, PERF_EVENT_IOC_ENABLE); 51762306a36Sopenharmony_ci multi_dawr_workload(); 51862306a36Sopenharmony_ci ioctl(fd1, PERF_EVENT_IOC_DISABLE); 51962306a36Sopenharmony_ci ioctl(fd2, PERF_EVENT_IOC_DISABLE); 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci res = read(fd1, &breaks1, sizeof(breaks1)); 52262306a36Sopenharmony_ci assert(res == sizeof(unsigned long long)); 52362306a36Sopenharmony_ci res = read(fd2, &breaks2, sizeof(breaks2)); 52462306a36Sopenharmony_ci assert(res == sizeof(unsigned long long)); 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci close(fd1); 52762306a36Sopenharmony_ci close(fd2); 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci if (breaks1 != 1 || breaks2 != 1) { 53062306a36Sopenharmony_ci printf("FAILED: %s: %lld != 1 || %lld != 1\n", desc, breaks1, breaks2); 53162306a36Sopenharmony_ci return 1; 53262306a36Sopenharmony_ci } 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci printf("TESTED: %s\n", desc); 53562306a36Sopenharmony_ci return 0; 53662306a36Sopenharmony_ci} 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_cistatic int test_process_multi_same_addr_ro_wo(void) 53962306a36Sopenharmony_ci{ 54062306a36Sopenharmony_ci unsigned long long breaks1 = 0, breaks2 = 0; 54162306a36Sopenharmony_ci int fd1, fd2; 54262306a36Sopenharmony_ci char *desc = "Process specific, Two events, same addr, one is RO, other is WO"; 54362306a36Sopenharmony_ci size_t res; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci fd1 = perf_process_event_open(HW_BREAKPOINT_R, (__u64)&a, (__u64)sizeof(a)); 54662306a36Sopenharmony_ci if (fd1 < 0) { 54762306a36Sopenharmony_ci perror("perf_process_event_open"); 54862306a36Sopenharmony_ci exit(EXIT_FAILURE); 54962306a36Sopenharmony_ci } 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci fd2 = perf_process_event_open(HW_BREAKPOINT_W, (__u64)&a, (__u64)sizeof(a)); 55262306a36Sopenharmony_ci if (fd2 < 0) { 55362306a36Sopenharmony_ci close(fd1); 55462306a36Sopenharmony_ci perror("perf_process_event_open"); 55562306a36Sopenharmony_ci exit(EXIT_FAILURE); 55662306a36Sopenharmony_ci } 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci ioctl(fd1, PERF_EVENT_IOC_RESET); 55962306a36Sopenharmony_ci ioctl(fd2, PERF_EVENT_IOC_RESET); 56062306a36Sopenharmony_ci ioctl(fd1, PERF_EVENT_IOC_ENABLE); 56162306a36Sopenharmony_ci ioctl(fd2, PERF_EVENT_IOC_ENABLE); 56262306a36Sopenharmony_ci multi_dawr_workload(); 56362306a36Sopenharmony_ci ioctl(fd1, PERF_EVENT_IOC_DISABLE); 56462306a36Sopenharmony_ci ioctl(fd2, PERF_EVENT_IOC_DISABLE); 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci res = read(fd1, &breaks1, sizeof(breaks1)); 56762306a36Sopenharmony_ci assert(res == sizeof(unsigned long long)); 56862306a36Sopenharmony_ci res = read(fd2, &breaks2, sizeof(breaks2)); 56962306a36Sopenharmony_ci assert(res == sizeof(unsigned long long)); 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci close(fd1); 57262306a36Sopenharmony_ci close(fd2); 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci if (breaks1 != 1 || breaks2 != 1) { 57562306a36Sopenharmony_ci printf("FAILED: %s: %lld != 1 || %lld != 1\n", desc, breaks1, breaks2); 57662306a36Sopenharmony_ci return 1; 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci printf("TESTED: %s\n", desc); 58062306a36Sopenharmony_ci return 0; 58162306a36Sopenharmony_ci} 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_cistatic int test_syswide_multi_diff_addr(void) 58462306a36Sopenharmony_ci{ 58562306a36Sopenharmony_ci unsigned long long breaks1 = 0, breaks2 = 0; 58662306a36Sopenharmony_ci int *fd1 = malloc(nprocs * sizeof(int)); 58762306a36Sopenharmony_ci int *fd2 = malloc(nprocs * sizeof(int)); 58862306a36Sopenharmony_ci char *desc = "Systemwide, Two events, diff addr"; 58962306a36Sopenharmony_ci int ret; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci ret = perf_systemwide_event_open(fd1, HW_BREAKPOINT_RW, (__u64)&a, (__u64)sizeof(a)); 59262306a36Sopenharmony_ci if (ret) 59362306a36Sopenharmony_ci exit(EXIT_FAILURE); 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci ret = perf_systemwide_event_open(fd2, HW_BREAKPOINT_RW, (__u64)&b, (__u64)sizeof(b)); 59662306a36Sopenharmony_ci if (ret) { 59762306a36Sopenharmony_ci close_fds(fd1, nprocs); 59862306a36Sopenharmony_ci exit(EXIT_FAILURE); 59962306a36Sopenharmony_ci } 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci reset_fds(fd1, nprocs); 60262306a36Sopenharmony_ci reset_fds(fd2, nprocs); 60362306a36Sopenharmony_ci enable_fds(fd1, nprocs); 60462306a36Sopenharmony_ci enable_fds(fd2, nprocs); 60562306a36Sopenharmony_ci multi_dawr_workload(); 60662306a36Sopenharmony_ci disable_fds(fd1, nprocs); 60762306a36Sopenharmony_ci disable_fds(fd2, nprocs); 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci breaks1 = read_fds(fd1, nprocs); 61062306a36Sopenharmony_ci breaks2 = read_fds(fd2, nprocs); 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci close_fds(fd1, nprocs); 61362306a36Sopenharmony_ci close_fds(fd2, nprocs); 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci free(fd1); 61662306a36Sopenharmony_ci free(fd2); 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci if (breaks1 != 2 || breaks2 != 2) { 61962306a36Sopenharmony_ci printf("FAILED: %s: %lld != 2 || %lld != 2\n", desc, breaks1, breaks2); 62062306a36Sopenharmony_ci return 1; 62162306a36Sopenharmony_ci } 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci printf("TESTED: %s\n", desc); 62462306a36Sopenharmony_ci return 0; 62562306a36Sopenharmony_ci} 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_cistatic int test_syswide_multi_same_addr(void) 62862306a36Sopenharmony_ci{ 62962306a36Sopenharmony_ci unsigned long long breaks1 = 0, breaks2 = 0; 63062306a36Sopenharmony_ci int *fd1 = malloc(nprocs * sizeof(int)); 63162306a36Sopenharmony_ci int *fd2 = malloc(nprocs * sizeof(int)); 63262306a36Sopenharmony_ci char *desc = "Systemwide, Two events, same addr"; 63362306a36Sopenharmony_ci int ret; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci ret = perf_systemwide_event_open(fd1, HW_BREAKPOINT_RW, (__u64)&a, (__u64)sizeof(a)); 63662306a36Sopenharmony_ci if (ret) 63762306a36Sopenharmony_ci exit(EXIT_FAILURE); 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci ret = perf_systemwide_event_open(fd2, HW_BREAKPOINT_RW, (__u64)&a, (__u64)sizeof(a)); 64062306a36Sopenharmony_ci if (ret) { 64162306a36Sopenharmony_ci close_fds(fd1, nprocs); 64262306a36Sopenharmony_ci exit(EXIT_FAILURE); 64362306a36Sopenharmony_ci } 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci reset_fds(fd1, nprocs); 64662306a36Sopenharmony_ci reset_fds(fd2, nprocs); 64762306a36Sopenharmony_ci enable_fds(fd1, nprocs); 64862306a36Sopenharmony_ci enable_fds(fd2, nprocs); 64962306a36Sopenharmony_ci multi_dawr_workload(); 65062306a36Sopenharmony_ci disable_fds(fd1, nprocs); 65162306a36Sopenharmony_ci disable_fds(fd2, nprocs); 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci breaks1 = read_fds(fd1, nprocs); 65462306a36Sopenharmony_ci breaks2 = read_fds(fd2, nprocs); 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci close_fds(fd1, nprocs); 65762306a36Sopenharmony_ci close_fds(fd2, nprocs); 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci free(fd1); 66062306a36Sopenharmony_ci free(fd2); 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci if (breaks1 != 2 || breaks2 != 2) { 66362306a36Sopenharmony_ci printf("FAILED: %s: %lld != 2 || %lld != 2\n", desc, breaks1, breaks2); 66462306a36Sopenharmony_ci return 1; 66562306a36Sopenharmony_ci } 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci printf("TESTED: %s\n", desc); 66862306a36Sopenharmony_ci return 0; 66962306a36Sopenharmony_ci} 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_cistatic int test_syswide_multi_diff_addr_ro_wo(void) 67262306a36Sopenharmony_ci{ 67362306a36Sopenharmony_ci unsigned long long breaks1 = 0, breaks2 = 0; 67462306a36Sopenharmony_ci int *fd1 = malloc(nprocs * sizeof(int)); 67562306a36Sopenharmony_ci int *fd2 = malloc(nprocs * sizeof(int)); 67662306a36Sopenharmony_ci char *desc = "Systemwide, Two events, diff addr, one is RO, other is WO"; 67762306a36Sopenharmony_ci int ret; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci ret = perf_systemwide_event_open(fd1, HW_BREAKPOINT_W, (__u64)&a, (__u64)sizeof(a)); 68062306a36Sopenharmony_ci if (ret) 68162306a36Sopenharmony_ci exit(EXIT_FAILURE); 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci ret = perf_systemwide_event_open(fd2, HW_BREAKPOINT_R, (__u64)&b, (__u64)sizeof(b)); 68462306a36Sopenharmony_ci if (ret) { 68562306a36Sopenharmony_ci close_fds(fd1, nprocs); 68662306a36Sopenharmony_ci exit(EXIT_FAILURE); 68762306a36Sopenharmony_ci } 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci reset_fds(fd1, nprocs); 69062306a36Sopenharmony_ci reset_fds(fd2, nprocs); 69162306a36Sopenharmony_ci enable_fds(fd1, nprocs); 69262306a36Sopenharmony_ci enable_fds(fd2, nprocs); 69362306a36Sopenharmony_ci multi_dawr_workload(); 69462306a36Sopenharmony_ci disable_fds(fd1, nprocs); 69562306a36Sopenharmony_ci disable_fds(fd2, nprocs); 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci breaks1 = read_fds(fd1, nprocs); 69862306a36Sopenharmony_ci breaks2 = read_fds(fd2, nprocs); 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci close_fds(fd1, nprocs); 70162306a36Sopenharmony_ci close_fds(fd2, nprocs); 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci free(fd1); 70462306a36Sopenharmony_ci free(fd2); 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci if (breaks1 != 1 || breaks2 != 1) { 70762306a36Sopenharmony_ci printf("FAILED: %s: %lld != 1 || %lld != 1\n", desc, breaks1, breaks2); 70862306a36Sopenharmony_ci return 1; 70962306a36Sopenharmony_ci } 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci printf("TESTED: %s\n", desc); 71262306a36Sopenharmony_ci return 0; 71362306a36Sopenharmony_ci} 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_cistatic int test_syswide_multi_same_addr_ro_wo(void) 71662306a36Sopenharmony_ci{ 71762306a36Sopenharmony_ci unsigned long long breaks1 = 0, breaks2 = 0; 71862306a36Sopenharmony_ci int *fd1 = malloc(nprocs * sizeof(int)); 71962306a36Sopenharmony_ci int *fd2 = malloc(nprocs * sizeof(int)); 72062306a36Sopenharmony_ci char *desc = "Systemwide, Two events, same addr, one is RO, other is WO"; 72162306a36Sopenharmony_ci int ret; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci ret = perf_systemwide_event_open(fd1, HW_BREAKPOINT_W, (__u64)&a, (__u64)sizeof(a)); 72462306a36Sopenharmony_ci if (ret) 72562306a36Sopenharmony_ci exit(EXIT_FAILURE); 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci ret = perf_systemwide_event_open(fd2, HW_BREAKPOINT_R, (__u64)&a, (__u64)sizeof(a)); 72862306a36Sopenharmony_ci if (ret) { 72962306a36Sopenharmony_ci close_fds(fd1, nprocs); 73062306a36Sopenharmony_ci exit(EXIT_FAILURE); 73162306a36Sopenharmony_ci } 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci reset_fds(fd1, nprocs); 73462306a36Sopenharmony_ci reset_fds(fd2, nprocs); 73562306a36Sopenharmony_ci enable_fds(fd1, nprocs); 73662306a36Sopenharmony_ci enable_fds(fd2, nprocs); 73762306a36Sopenharmony_ci multi_dawr_workload(); 73862306a36Sopenharmony_ci disable_fds(fd1, nprocs); 73962306a36Sopenharmony_ci disable_fds(fd2, nprocs); 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci breaks1 = read_fds(fd1, nprocs); 74262306a36Sopenharmony_ci breaks2 = read_fds(fd2, nprocs); 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci close_fds(fd1, nprocs); 74562306a36Sopenharmony_ci close_fds(fd2, nprocs); 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci free(fd1); 74862306a36Sopenharmony_ci free(fd2); 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci if (breaks1 != 1 || breaks2 != 1) { 75162306a36Sopenharmony_ci printf("FAILED: %s: %lld != 1 || %lld != 1\n", desc, breaks1, breaks2); 75262306a36Sopenharmony_ci return 1; 75362306a36Sopenharmony_ci } 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci printf("TESTED: %s\n", desc); 75662306a36Sopenharmony_ci return 0; 75762306a36Sopenharmony_ci} 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_cistatic int runtest_multi_dawr(void) 76062306a36Sopenharmony_ci{ 76162306a36Sopenharmony_ci int ret = 0; 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci ret |= test_process_multi_diff_addr(); 76462306a36Sopenharmony_ci ret |= test_process_multi_same_addr(); 76562306a36Sopenharmony_ci ret |= test_process_multi_diff_addr_ro_wo(); 76662306a36Sopenharmony_ci ret |= test_process_multi_same_addr_ro_wo(); 76762306a36Sopenharmony_ci ret |= test_syswide_multi_diff_addr(); 76862306a36Sopenharmony_ci ret |= test_syswide_multi_same_addr(); 76962306a36Sopenharmony_ci ret |= test_syswide_multi_diff_addr_ro_wo(); 77062306a36Sopenharmony_ci ret |= test_syswide_multi_same_addr_ro_wo(); 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci return ret; 77362306a36Sopenharmony_ci} 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_cistatic int runtest_unaligned_512bytes(void) 77662306a36Sopenharmony_ci{ 77762306a36Sopenharmony_ci unsigned long long breaks = 0; 77862306a36Sopenharmony_ci int fd; 77962306a36Sopenharmony_ci char *desc = "Process specific, 512 bytes, unaligned"; 78062306a36Sopenharmony_ci __u64 addr = (__u64)&c + 8; 78162306a36Sopenharmony_ci size_t res; 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci fd = perf_process_event_open(HW_BREAKPOINT_RW, addr, 512); 78462306a36Sopenharmony_ci if (fd < 0) { 78562306a36Sopenharmony_ci perror("perf_process_event_open"); 78662306a36Sopenharmony_ci exit(EXIT_FAILURE); 78762306a36Sopenharmony_ci } 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci ioctl(fd, PERF_EVENT_IOC_RESET); 79062306a36Sopenharmony_ci ioctl(fd, PERF_EVENT_IOC_ENABLE); 79162306a36Sopenharmony_ci multi_dawr_workload(); 79262306a36Sopenharmony_ci ioctl(fd, PERF_EVENT_IOC_DISABLE); 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci res = read(fd, &breaks, sizeof(breaks)); 79562306a36Sopenharmony_ci assert(res == sizeof(unsigned long long)); 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci close(fd); 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci if (breaks != 2) { 80062306a36Sopenharmony_ci printf("FAILED: %s: %lld != 2\n", desc, breaks); 80162306a36Sopenharmony_ci return 1; 80262306a36Sopenharmony_ci } 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci printf("TESTED: %s\n", desc); 80562306a36Sopenharmony_ci return 0; 80662306a36Sopenharmony_ci} 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci/* There is no perf api to find number of available watchpoints. Use ptrace. */ 80962306a36Sopenharmony_cistatic int get_nr_wps(bool *arch_31) 81062306a36Sopenharmony_ci{ 81162306a36Sopenharmony_ci struct ppc_debug_info dbginfo; 81262306a36Sopenharmony_ci int child_pid; 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci child_pid = fork(); 81562306a36Sopenharmony_ci if (!child_pid) { 81662306a36Sopenharmony_ci int ret = ptrace(PTRACE_TRACEME, 0, NULL, 0); 81762306a36Sopenharmony_ci if (ret) { 81862306a36Sopenharmony_ci perror("PTRACE_TRACEME failed\n"); 81962306a36Sopenharmony_ci exit(EXIT_FAILURE); 82062306a36Sopenharmony_ci } 82162306a36Sopenharmony_ci kill(getpid(), SIGUSR1); 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci sleep(1); 82462306a36Sopenharmony_ci exit(EXIT_SUCCESS); 82562306a36Sopenharmony_ci } 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci wait(NULL); 82862306a36Sopenharmony_ci if (ptrace(PPC_PTRACE_GETHWDBGINFO, child_pid, NULL, &dbginfo)) { 82962306a36Sopenharmony_ci perror("Can't get breakpoint info"); 83062306a36Sopenharmony_ci exit(EXIT_FAILURE); 83162306a36Sopenharmony_ci } 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci *arch_31 = !!(dbginfo.features & PPC_DEBUG_FEATURE_DATA_BP_ARCH_31); 83462306a36Sopenharmony_ci return dbginfo.num_data_bps; 83562306a36Sopenharmony_ci} 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_cistatic int runtest(void) 83862306a36Sopenharmony_ci{ 83962306a36Sopenharmony_ci int rwflag; 84062306a36Sopenharmony_ci int exclude_user; 84162306a36Sopenharmony_ci int ret; 84262306a36Sopenharmony_ci bool dawr = dawr_supported(); 84362306a36Sopenharmony_ci bool arch_31 = false; 84462306a36Sopenharmony_ci int nr_wps = get_nr_wps(&arch_31); 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci /* 84762306a36Sopenharmony_ci * perf defines rwflag as two bits read and write and at least 84862306a36Sopenharmony_ci * one must be set. So range 1-3. 84962306a36Sopenharmony_ci */ 85062306a36Sopenharmony_ci for (rwflag = 1 ; rwflag < 4; rwflag++) { 85162306a36Sopenharmony_ci for (exclude_user = 0 ; exclude_user < 2; exclude_user++) { 85262306a36Sopenharmony_ci ret = runtestsingle(rwflag, exclude_user, 0); 85362306a36Sopenharmony_ci if (ret) 85462306a36Sopenharmony_ci return ret; 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci /* if we have the dawr, we can do an array test */ 85762306a36Sopenharmony_ci if (!dawr) 85862306a36Sopenharmony_ci continue; 85962306a36Sopenharmony_ci ret = runtestsingle(rwflag, exclude_user, 1); 86062306a36Sopenharmony_ci if (ret) 86162306a36Sopenharmony_ci return ret; 86262306a36Sopenharmony_ci } 86362306a36Sopenharmony_ci } 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci ret = runtest_dar_outside(); 86662306a36Sopenharmony_ci if (ret) 86762306a36Sopenharmony_ci return ret; 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci if (dawr && nr_wps > 1) { 87062306a36Sopenharmony_ci nprocs = get_nprocs(); 87162306a36Sopenharmony_ci ret = runtest_multi_dawr(); 87262306a36Sopenharmony_ci if (ret) 87362306a36Sopenharmony_ci return ret; 87462306a36Sopenharmony_ci } 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci if (dawr && arch_31) 87762306a36Sopenharmony_ci ret = runtest_unaligned_512bytes(); 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci return ret; 88062306a36Sopenharmony_ci} 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_cistatic int perf_hwbreak(void) 88462306a36Sopenharmony_ci{ 88562306a36Sopenharmony_ci srand ( time(NULL) ); 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci SKIP_IF_MSG(!perf_breakpoint_supported(), "Perf breakpoints not supported"); 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci return runtest(); 89062306a36Sopenharmony_ci} 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ciint main(int argc, char *argv[], char **envp) 89362306a36Sopenharmony_ci{ 89462306a36Sopenharmony_ci return test_harness(perf_hwbreak, "perf_hwbreak"); 89562306a36Sopenharmony_ci} 896