linux/tools/testing/selftests/powerpc/ptrace/perf-hwbreak.c
<<
>>
Prefs
   1/*
   2 * perf events self profiling example test case for hw breakpoints.
   3 *
   4 * This tests perf PERF_TYPE_BREAKPOINT parameters
   5 * 1) tests all variants of the break on read/write flags
   6 * 2) tests exclude_user == 0 and 1
   7 * 3) test array matches (if DAWR is supported))
   8 * 4) test different numbers of breakpoints matches
   9 *
  10 * Configure this breakpoint, then read and write the data a number of
  11 * times. Then check the output count from perf is as expected.
  12 *
  13 * Based on:
  14 *   http://ozlabs.org/~anton/junkcode/perf_events_example1.c
  15 *
  16 * Copyright (C) 2018 Michael Neuling, IBM Corporation.
  17 *
  18 * This program is free software; you can redistribute it and/or
  19 * modify it under the terms of the GNU General Public License
  20 * as published by the Free Software Foundation; either version
  21 * 2 of the License, or (at your option) any later version.
  22 */
  23
  24#include <unistd.h>
  25#include <assert.h>
  26#include <stdio.h>
  27#include <stdlib.h>
  28#include <string.h>
  29#include <sys/ioctl.h>
  30#include <elf.h>
  31#include <pthread.h>
  32#include <sys/syscall.h>
  33#include <linux/perf_event.h>
  34#include <linux/hw_breakpoint.h>
  35#include "utils.h"
  36
  37#define MAX_LOOPS 10000
  38
  39#define DAWR_LENGTH_MAX ((0x3f + 1) * 8)
  40
  41static inline int sys_perf_event_open(struct perf_event_attr *attr, pid_t pid,
  42                                      int cpu, int group_fd,
  43                                      unsigned long flags)
  44{
  45        attr->size = sizeof(*attr);
  46        return syscall(__NR_perf_event_open, attr, pid, cpu, group_fd, flags);
  47}
  48
  49static inline bool breakpoint_test(int len)
  50{
  51        struct perf_event_attr attr;
  52        int fd;
  53
  54        /* setup counters */
  55        memset(&attr, 0, sizeof(attr));
  56        attr.disabled = 1;
  57        attr.type = PERF_TYPE_BREAKPOINT;
  58        attr.bp_type = HW_BREAKPOINT_R;
  59        /* bp_addr can point anywhere but needs to be aligned */
  60        attr.bp_addr = (__u64)(&attr) & 0xfffffffffffff800;
  61        attr.bp_len = len;
  62        fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
  63        if (fd < 0)
  64                return false;
  65        close(fd);
  66        return true;
  67}
  68
  69static inline bool perf_breakpoint_supported(void)
  70{
  71        return breakpoint_test(4);
  72}
  73
  74static inline bool dawr_supported(void)
  75{
  76        return breakpoint_test(DAWR_LENGTH_MAX);
  77}
  78
  79static int runtestsingle(int readwriteflag, int exclude_user, int arraytest)
  80{
  81        int i,j;
  82        struct perf_event_attr attr;
  83        size_t res;
  84        unsigned long long breaks, needed;
  85        int readint;
  86        int readintarraybig[2*DAWR_LENGTH_MAX/sizeof(int)];
  87        int *readintalign;
  88        volatile int *ptr;
  89        int break_fd;
  90        int loop_num = MAX_LOOPS - (rand() % 100); /* provide some variability */
  91        volatile int *k;
  92
  93        /* align to 0x400 boundary as required by DAWR */
  94        readintalign = (int *)(((unsigned long)readintarraybig + 0x7ff) &
  95                               0xfffffffffffff800);
  96
  97        ptr = &readint;
  98        if (arraytest)
  99                ptr = &readintalign[0];
 100
 101        /* setup counters */
 102        memset(&attr, 0, sizeof(attr));
 103        attr.disabled = 1;
 104        attr.type = PERF_TYPE_BREAKPOINT;
 105        attr.bp_type = readwriteflag;
 106        attr.bp_addr = (__u64)ptr;
 107        attr.bp_len = sizeof(int);
 108        if (arraytest)
 109                attr.bp_len = DAWR_LENGTH_MAX;
 110        attr.exclude_user = exclude_user;
 111        break_fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
 112        if (break_fd < 0) {
 113                perror("sys_perf_event_open");
 114                exit(1);
 115        }
 116
 117        /* start counters */
 118        ioctl(break_fd, PERF_EVENT_IOC_ENABLE);
 119
 120        /* Test a bunch of reads and writes */
 121        k = &readint;
 122        for (i = 0; i < loop_num; i++) {
 123                if (arraytest)
 124                        k = &(readintalign[i % (DAWR_LENGTH_MAX/sizeof(int))]);
 125
 126                j = *k;
 127                *k = j;
 128        }
 129
 130        /* stop counters */
 131        ioctl(break_fd, PERF_EVENT_IOC_DISABLE);
 132
 133        /* read and check counters */
 134        res = read(break_fd, &breaks, sizeof(unsigned long long));
 135        assert(res == sizeof(unsigned long long));
 136        /* we read and write each loop, so subtract the ones we are counting */
 137        needed = 0;
 138        if (readwriteflag & HW_BREAKPOINT_R)
 139                needed += loop_num;
 140        if (readwriteflag & HW_BREAKPOINT_W)
 141                needed += loop_num;
 142        needed = needed * (1 - exclude_user);
 143        printf("TESTED: addr:0x%lx brks:% 8lld loops:% 8i rw:%i !user:%i array:%i\n",
 144               (unsigned long int)ptr, breaks, loop_num, readwriteflag, exclude_user, arraytest);
 145        if (breaks != needed) {
 146                printf("FAILED: 0x%lx brks:%lld needed:%lli %i %i %i\n\n",
 147                       (unsigned long int)ptr, breaks, needed, loop_num, readwriteflag, exclude_user);
 148                return 1;
 149        }
 150        close(break_fd);
 151
 152        return 0;
 153}
 154
 155static int runtest(void)
 156{
 157        int rwflag;
 158        int exclude_user;
 159        int ret;
 160
 161        /*
 162         * perf defines rwflag as two bits read and write and at least
 163         * one must be set.  So range 1-3.
 164         */
 165        for (rwflag = 1 ; rwflag < 4; rwflag++) {
 166                for (exclude_user = 0 ; exclude_user < 2; exclude_user++) {
 167                        ret = runtestsingle(rwflag, exclude_user, 0);
 168                        if (ret)
 169                                return ret;
 170
 171                        /* if we have the dawr, we can do an array test */
 172                        if (!dawr_supported())
 173                                continue;
 174                        ret = runtestsingle(rwflag, exclude_user, 1);
 175                        if (ret)
 176                                return ret;
 177                }
 178        }
 179        return 0;
 180}
 181
 182
 183static int perf_hwbreak(void)
 184{
 185        srand ( time(NULL) );
 186
 187        SKIP_IF(!perf_breakpoint_supported());
 188
 189        return runtest();
 190}
 191
 192int main(int argc, char *argv[], char **envp)
 193{
 194        return test_harness(perf_hwbreak, "perf_hwbreak");
 195}
 196