cregit-Linux how code gets into the kernel

Release 4.18 tools/testing/selftests/powerpc/ptrace/perf-hwbreak.c

/*
 * perf events self profiling example test case for hw breakpoints.
 *
 * This tests perf PERF_TYPE_BREAKPOINT parameters
 * 1) tests all variants of the break on read/write flags
 * 2) tests exclude_user == 0 and 1
 * 3) test array matches (if DAWR is supported))
 * 4) test different numbers of breakpoints matches
 *
 * Configure this breakpoint, then read and write the data a number of
 * times. Then check the output count from perf is as expected.
 *
 * Based on:
 *   http://ozlabs.org/~anton/junkcode/perf_events_example1.c
 *
 * Copyright (C) 2018 Michael Neuling, IBM Corporation.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version
 * 2 of the License, or (at your option) any later version.
 */

#include <unistd.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <elf.h>
#include <pthread.h>
#include <sys/syscall.h>
#include <linux/perf_event.h>
#include <linux/hw_breakpoint.h>
#include "utils.h"


#define MAX_LOOPS 10000


#define DAWR_LENGTH_MAX ((0x3f + 1) * 8)


static inline int sys_perf_event_open(struct perf_event_attr *attr, pid_t pid, int cpu, int group_fd, unsigned long flags) { attr->size = sizeof(*attr); return syscall(__NR_perf_event_open, attr, pid, cpu, group_fd, flags); }

Contributors

PersonTokensPropCommitsCommitProp
Michael Neuling51100.00%1100.00%
Total51100.00%1100.00%


static inline bool breakpoint_test(int len) { struct perf_event_attr attr; int fd; /* setup counters */ memset(&attr, 0, sizeof(attr)); attr.disabled = 1; attr.type = PERF_TYPE_BREAKPOINT; attr.bp_type = HW_BREAKPOINT_R; /* bp_addr can point anywhere but needs to be aligned */ attr.bp_addr = (__u64)(&attr) & 0xfffffffffffff800; attr.bp_len = len; fd = sys_perf_event_open(&attr, 0, -1, -1, 0); if (fd < 0) return false; close(fd); return true; }

Contributors

PersonTokensPropCommitsCommitProp
Michael Neuling105100.00%1100.00%
Total105100.00%1100.00%


static inline bool perf_breakpoint_supported(void) { return breakpoint_test(4); }

Contributors

PersonTokensPropCommitsCommitProp
Michael Neuling15100.00%1100.00%
Total15100.00%1100.00%


static inline bool dawr_supported(void) { return breakpoint_test(DAWR_LENGTH_MAX); }

Contributors

PersonTokensPropCommitsCommitProp
Michael Neuling15100.00%1100.00%
Total15100.00%1100.00%


static int runtestsingle(int readwriteflag, int exclude_user, int arraytest) { int i,j; struct perf_event_attr attr; size_t res; unsigned long long breaks, needed; int readint; int readintarraybig[2*DAWR_LENGTH_MAX/sizeof(int)]; int *readintalign; volatile int *ptr; int break_fd; int loop_num = MAX_LOOPS - (rand() % 100); /* provide some variability */ volatile int *k; /* align to 0x400 boundary as required by DAWR */ readintalign = (int *)(((unsigned long)readintarraybig + 0x7ff) & 0xfffffffffffff800); ptr = &readint; if (arraytest) ptr = &readintalign[0]; /* setup counters */ memset(&attr, 0, sizeof(attr)); attr.disabled = 1; attr.type = PERF_TYPE_BREAKPOINT; attr.bp_type = readwriteflag; attr.bp_addr = (__u64)ptr; attr.bp_len = sizeof(int); if (arraytest) attr.bp_len = DAWR_LENGTH_MAX; attr.exclude_user = exclude_user; break_fd = sys_perf_event_open(&attr, 0, -1, -1, 0); if (break_fd < 0) { perror("sys_perf_event_open"); exit(1); } /* start counters */ ioctl(break_fd, PERF_EVENT_IOC_ENABLE); /* Test a bunch of reads and writes */ k = &readint; for (i = 0; i < loop_num; i++) { if (arraytest) k = &(readintalign[i % (DAWR_LENGTH_MAX/sizeof(int))]); j = *k; *k = j; } /* stop counters */ ioctl(break_fd, PERF_EVENT_IOC_DISABLE); /* read and check counters */ res = read(break_fd, &breaks, sizeof(unsigned long long)); assert(res == sizeof(unsigned long long)); /* we read and write each loop, so subtract the ones we are counting */ needed = 0; if (readwriteflag & HW_BREAKPOINT_R) needed += loop_num; if (readwriteflag & HW_BREAKPOINT_W) needed += loop_num; needed = needed * (1 - exclude_user); printf("TESTED: addr:0x%lx brks:% 8lld loops:% 8i rw:%i !user:%i array:%i\n", (unsigned long int)ptr, breaks, loop_num, readwriteflag, exclude_user, arraytest); if (breaks != needed) { printf("FAILED: 0x%lx brks:%lld needed:%lli %i %i %i\n\n", (unsigned long int)ptr, breaks, needed, loop_num, readwriteflag, exclude_user); return 1; } close(break_fd); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Michael Neuling418100.00%1100.00%
Total418100.00%1100.00%


static int runtest(void) { int rwflag; int exclude_user; int ret; /* * perf defines rwflag as two bits read and write and at least * one must be set. So range 1-3. */ for (rwflag = 1 ; rwflag < 4; rwflag++) { for (exclude_user = 0 ; exclude_user < 2; exclude_user++) { ret = runtestsingle(rwflag, exclude_user, 0); if (ret) return ret; /* if we have the dawr, we can do an array test */ if (!dawr_supported()) continue; ret = runtestsingle(rwflag, exclude_user, 1); if (ret) return ret; } } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Michael Neuling95100.00%1100.00%
Total95100.00%1100.00%


static int perf_hwbreak(void) { srand ( time(NULL) ); SKIP_IF(!perf_breakpoint_supported()); return runtest(); }

Contributors

PersonTokensPropCommitsCommitProp
Michael Neuling27100.00%1100.00%
Total27100.00%1100.00%


int main(int argc, char *argv[], char **envp) { return test_harness(perf_hwbreak, "perf_hwbreak"); }

Contributors

PersonTokensPropCommitsCommitProp
Michael Neuling26100.00%1100.00%
Total26100.00%1100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
Michael Neuling797100.00%1100.00%
Total797100.00%1100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.