linux/tools/testing/selftests/powerpc/ptrace/perf-hwbreak.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * perf events self profiling example test case for hw breakpoints.
   4 *
   5 * This tests perf PERF_TYPE_BREAKPOINT parameters
   6 * 1) tests all variants of the break on read/write flags
   7 * 2) tests exclude_user == 0 and 1
   8 * 3) test array matches (if DAWR is supported))
   9 * 4) test different numbers of breakpoints matches
  10 *
  11 * Configure this breakpoint, then read and write the data a number of
  12 * times. Then check the output count from perf is as expected.
  13 *
  14 * Based on:
  15 *   http://ozlabs.org/~anton/junkcode/perf_events_example1.c
  16 *
  17 * Copyright (C) 2018 Michael Neuling, IBM Corporation.
  18 */
  19
  20#include <unistd.h>
  21#include <assert.h>
  22#include <stdio.h>
  23#include <stdlib.h>
  24#include <string.h>
  25#include <sys/ioctl.h>
  26#include <elf.h>
  27#include <pthread.h>
  28#include <sys/syscall.h>
  29#include <linux/perf_event.h>
  30#include <linux/hw_breakpoint.h>
  31#include "utils.h"
  32
  33#define MAX_LOOPS 10000
  34
  35#define DAWR_LENGTH_MAX ((0x3f + 1) * 8)
  36
  37static inline int sys_perf_event_open(struct perf_event_attr *attr, pid_t pid,
  38                                      int cpu, int group_fd,
  39                                      unsigned long flags)
  40{
  41        attr->size = sizeof(*attr);
  42        return syscall(__NR_perf_event_open, attr, pid, cpu, group_fd, flags);
  43}
  44
  45static inline bool breakpoint_test(int len)
  46{
  47        struct perf_event_attr attr;
  48        int fd;
  49
  50        /* setup counters */
  51        memset(&attr, 0, sizeof(attr));
  52        attr.disabled = 1;
  53        attr.type = PERF_TYPE_BREAKPOINT;
  54        attr.bp_type = HW_BREAKPOINT_R;
  55        /* bp_addr can point anywhere but needs to be aligned */
  56        attr.bp_addr = (__u64)(&attr) & 0xfffffffffffff800;
  57        attr.bp_len = len;
  58        fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
  59        if (fd < 0)
  60                return false;
  61        close(fd);
  62        return true;
  63}
  64
  65static inline bool perf_breakpoint_supported(void)
  66{
  67        return breakpoint_test(4);
  68}
  69
  70static inline bool dawr_supported(void)
  71{
  72        return breakpoint_test(DAWR_LENGTH_MAX);
  73}
  74
  75static int runtestsingle(int readwriteflag, int exclude_user, int arraytest)
  76{
  77        int i,j;
  78        struct perf_event_attr attr;
  79        size_t res;
  80        unsigned long long breaks, needed;
  81        int readint;
  82        int readintarraybig[2*DAWR_LENGTH_MAX/sizeof(int)];
  83        int *readintalign;
  84        volatile int *ptr;
  85        int break_fd;
  86        int loop_num = MAX_LOOPS - (rand() % 100); /* provide some variability */
  87        volatile int *k;
  88
  89        /* align to 0x400 boundary as required by DAWR */
  90        readintalign = (int *)(((unsigned long)readintarraybig + 0x7ff) &
  91                               0xfffffffffffff800);
  92
  93        ptr = &readint;
  94        if (arraytest)
  95                ptr = &readintalign[0];
  96
  97        /* setup counters */
  98        memset(&attr, 0, sizeof(attr));
  99        attr.disabled = 1;
 100        attr.type = PERF_TYPE_BREAKPOINT;
 101        attr.bp_type = readwriteflag;
 102        attr.bp_addr = (__u64)ptr;
 103        attr.bp_len = sizeof(int);
 104        if (arraytest)
 105                attr.bp_len = DAWR_LENGTH_MAX;
 106        attr.exclude_user = exclude_user;
 107        break_fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
 108        if (break_fd < 0) {
 109                perror("sys_perf_event_open");
 110                exit(1);
 111        }
 112
 113        /* start counters */
 114        ioctl(break_fd, PERF_EVENT_IOC_ENABLE);
 115
 116        /* Test a bunch of reads and writes */
 117        k = &readint;
 118        for (i = 0; i < loop_num; i++) {
 119                if (arraytest)
 120                        k = &(readintalign[i % (DAWR_LENGTH_MAX/sizeof(int))]);
 121
 122                j = *k;
 123                *k = j;
 124        }
 125
 126        /* stop counters */
 127        ioctl(break_fd, PERF_EVENT_IOC_DISABLE);
 128
 129        /* read and check counters */
 130        res = read(break_fd, &breaks, sizeof(unsigned long long));
 131        assert(res == sizeof(unsigned long long));
 132        /* we read and write each loop, so subtract the ones we are counting */
 133        needed = 0;
 134        if (readwriteflag & HW_BREAKPOINT_R)
 135                needed += loop_num;
 136        if (readwriteflag & HW_BREAKPOINT_W)
 137                needed += loop_num;
 138        needed = needed * (1 - exclude_user);
 139        printf("TESTED: addr:0x%lx brks:% 8lld loops:% 8i rw:%i !user:%i array:%i\n",
 140               (unsigned long int)ptr, breaks, loop_num, readwriteflag, exclude_user, arraytest);
 141        if (breaks != needed) {
 142                printf("FAILED: 0x%lx brks:%lld needed:%lli %i %i %i\n\n",
 143                       (unsigned long int)ptr, breaks, needed, loop_num, readwriteflag, exclude_user);
 144                return 1;
 145        }
 146        close(break_fd);
 147
 148        return 0;
 149}
 150
 151static int runtest_dar_outside(void)
 152{
 153        void *target;
 154        volatile __u16 temp16;
 155        volatile __u64 temp64;
 156        struct perf_event_attr attr;
 157        int break_fd;
 158        unsigned long long breaks;
 159        int fail = 0;
 160        size_t res;
 161
 162        target = malloc(8);
 163        if (!target) {
 164                perror("malloc failed");
 165                exit(EXIT_FAILURE);
 166        }
 167
 168        /* setup counters */
 169        memset(&attr, 0, sizeof(attr));
 170        attr.disabled = 1;
 171        attr.type = PERF_TYPE_BREAKPOINT;
 172        attr.exclude_kernel = 1;
 173        attr.exclude_hv = 1;
 174        attr.exclude_guest = 1;
 175        attr.bp_type = HW_BREAKPOINT_RW;
 176        /* watch middle half of target array */
 177        attr.bp_addr = (__u64)(target + 2);
 178        attr.bp_len = 4;
 179        break_fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
 180        if (break_fd < 0) {
 181                free(target);
 182                perror("sys_perf_event_open");
 183                exit(EXIT_FAILURE);
 184        }
 185
 186        /* Shouldn't hit. */
 187        ioctl(break_fd, PERF_EVENT_IOC_RESET);
 188        ioctl(break_fd, PERF_EVENT_IOC_ENABLE);
 189        temp16 = *((__u16 *)target);
 190        *((__u16 *)target) = temp16;
 191        ioctl(break_fd, PERF_EVENT_IOC_DISABLE);
 192        res = read(break_fd, &breaks, sizeof(unsigned long long));
 193        assert(res == sizeof(unsigned long long));
 194        if (breaks == 0) {
 195                printf("TESTED: No overlap\n");
 196        } else {
 197                printf("FAILED: No overlap: %lld != 0\n", breaks);
 198                fail = 1;
 199        }
 200
 201        /* Hit */
 202        ioctl(break_fd, PERF_EVENT_IOC_RESET);
 203        ioctl(break_fd, PERF_EVENT_IOC_ENABLE);
 204        temp16 = *((__u16 *)(target + 1));
 205        *((__u16 *)(target + 1)) = temp16;
 206        ioctl(break_fd, PERF_EVENT_IOC_DISABLE);
 207        res = read(break_fd, &breaks, sizeof(unsigned long long));
 208        assert(res == sizeof(unsigned long long));
 209        if (breaks == 2) {
 210                printf("TESTED: Partial overlap\n");
 211        } else {
 212                printf("FAILED: Partial overlap: %lld != 2\n", breaks);
 213                fail = 1;
 214        }
 215
 216        /* Hit */
 217        ioctl(break_fd, PERF_EVENT_IOC_RESET);
 218        ioctl(break_fd, PERF_EVENT_IOC_ENABLE);
 219        temp16 = *((__u16 *)(target + 5));
 220        *((__u16 *)(target + 5)) = temp16;
 221        ioctl(break_fd, PERF_EVENT_IOC_DISABLE);
 222        res = read(break_fd, &breaks, sizeof(unsigned long long));
 223        assert(res == sizeof(unsigned long long));
 224        if (breaks == 2) {
 225                printf("TESTED: Partial overlap\n");
 226        } else {
 227                printf("FAILED: Partial overlap: %lld != 2\n", breaks);
 228                fail = 1;
 229        }
 230
 231        /* Shouldn't Hit */
 232        ioctl(break_fd, PERF_EVENT_IOC_RESET);
 233        ioctl(break_fd, PERF_EVENT_IOC_ENABLE);
 234        temp16 = *((__u16 *)(target + 6));
 235        *((__u16 *)(target + 6)) = temp16;
 236        ioctl(break_fd, PERF_EVENT_IOC_DISABLE);
 237        res = read(break_fd, &breaks, sizeof(unsigned long long));
 238        assert(res == sizeof(unsigned long long));
 239        if (breaks == 0) {
 240                printf("TESTED: No overlap\n");
 241        } else {
 242                printf("FAILED: No overlap: %lld != 0\n", breaks);
 243                fail = 1;
 244        }
 245
 246        /* Hit */
 247        ioctl(break_fd, PERF_EVENT_IOC_RESET);
 248        ioctl(break_fd, PERF_EVENT_IOC_ENABLE);
 249        temp64 = *((__u64 *)target);
 250        *((__u64 *)target) = temp64;
 251        ioctl(break_fd, PERF_EVENT_IOC_DISABLE);
 252        res = read(break_fd, &breaks, sizeof(unsigned long long));
 253        assert(res == sizeof(unsigned long long));
 254        if (breaks == 2) {
 255                printf("TESTED: Full overlap\n");
 256        } else {
 257                printf("FAILED: Full overlap: %lld != 2\n", breaks);
 258                fail = 1;
 259        }
 260
 261        free(target);
 262        close(break_fd);
 263        return fail;
 264}
 265
 266static int runtest(void)
 267{
 268        int rwflag;
 269        int exclude_user;
 270        int ret;
 271
 272        /*
 273         * perf defines rwflag as two bits read and write and at least
 274         * one must be set.  So range 1-3.
 275         */
 276        for (rwflag = 1 ; rwflag < 4; rwflag++) {
 277                for (exclude_user = 0 ; exclude_user < 2; exclude_user++) {
 278                        ret = runtestsingle(rwflag, exclude_user, 0);
 279                        if (ret)
 280                                return ret;
 281
 282                        /* if we have the dawr, we can do an array test */
 283                        if (!dawr_supported())
 284                                continue;
 285                        ret = runtestsingle(rwflag, exclude_user, 1);
 286                        if (ret)
 287                                return ret;
 288                }
 289        }
 290
 291        ret = runtest_dar_outside();
 292        return ret;
 293}
 294
 295
 296static int perf_hwbreak(void)
 297{
 298        srand ( time(NULL) );
 299
 300        SKIP_IF(!perf_breakpoint_supported());
 301
 302        return runtest();
 303}
 304
 305int main(int argc, char *argv[], char **envp)
 306{
 307        return test_harness(perf_hwbreak, "perf_hwbreak");
 308}
 309