root/tools/testing/selftests/powerpc/ptrace/perf-hwbreak.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sys_perf_event_open
  2. breakpoint_test
  3. perf_breakpoint_supported
  4. dawr_supported
  5. runtestsingle
  6. runtest
  7. perf_hwbreak
  8. main

   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 
  37 static 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 
  45 static 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 
  65 static inline bool perf_breakpoint_supported(void)
  66 {
  67         return breakpoint_test(4);
  68 }
  69 
  70 static inline bool dawr_supported(void)
  71 {
  72         return breakpoint_test(DAWR_LENGTH_MAX);
  73 }
  74 
  75 static 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 
 151 static int runtest(void)
 152 {
 153         int rwflag;
 154         int exclude_user;
 155         int ret;
 156 
 157         /*
 158          * perf defines rwflag as two bits read and write and at least
 159          * one must be set.  So range 1-3.
 160          */
 161         for (rwflag = 1 ; rwflag < 4; rwflag++) {
 162                 for (exclude_user = 0 ; exclude_user < 2; exclude_user++) {
 163                         ret = runtestsingle(rwflag, exclude_user, 0);
 164                         if (ret)
 165                                 return ret;
 166 
 167                         /* if we have the dawr, we can do an array test */
 168                         if (!dawr_supported())
 169                                 continue;
 170                         ret = runtestsingle(rwflag, exclude_user, 1);
 171                         if (ret)
 172                                 return ret;
 173                 }
 174         }
 175         return 0;
 176 }
 177 
 178 
 179 static int perf_hwbreak(void)
 180 {
 181         srand ( time(NULL) );
 182 
 183         SKIP_IF(!perf_breakpoint_supported());
 184 
 185         return runtest();
 186 }
 187 
 188 int main(int argc, char *argv[], char **envp)
 189 {
 190         return test_harness(perf_hwbreak, "perf_hwbreak");
 191 }

/* [<][>][^][v][top][bottom][index][help] */