// SPDX-License-Identifier: GPL-2.0 
 | 
/* 
 | 
 * Test backward bit in event attribute, read ring buffer from end to 
 | 
 * beginning 
 | 
 */ 
 | 
  
 | 
#include <perf.h> 
 | 
#include <evlist.h> 
 | 
#include <sys/prctl.h> 
 | 
#include "tests.h" 
 | 
#include "debug.h" 
 | 
#include <errno.h> 
 | 
  
 | 
#define NR_ITERS 111 
 | 
  
 | 
static void testcase(void) 
 | 
{ 
 | 
    int i; 
 | 
  
 | 
    for (i = 0; i < NR_ITERS; i++) { 
 | 
        char proc_name[10]; 
 | 
  
 | 
        snprintf(proc_name, sizeof(proc_name), "p:%d\n", i); 
 | 
        prctl(PR_SET_NAME, proc_name); 
 | 
    } 
 | 
} 
 | 
  
 | 
static int count_samples(struct perf_evlist *evlist, int *sample_count, 
 | 
             int *comm_count) 
 | 
{ 
 | 
    int i; 
 | 
  
 | 
    for (i = 0; i < evlist->nr_mmaps; i++) { 
 | 
        struct perf_mmap *map = &evlist->overwrite_mmap[i]; 
 | 
        union perf_event *event; 
 | 
  
 | 
        perf_mmap__read_init(map); 
 | 
        while ((event = perf_mmap__read_event(map)) != NULL) { 
 | 
            const u32 type = event->header.type; 
 | 
  
 | 
            switch (type) { 
 | 
            case PERF_RECORD_SAMPLE: 
 | 
                (*sample_count)++; 
 | 
                break; 
 | 
            case PERF_RECORD_COMM: 
 | 
                (*comm_count)++; 
 | 
                break; 
 | 
            default: 
 | 
                pr_err("Unexpected record of type %d\n", type); 
 | 
                return TEST_FAIL; 
 | 
            } 
 | 
        } 
 | 
        perf_mmap__read_done(map); 
 | 
    } 
 | 
    return TEST_OK; 
 | 
} 
 | 
  
 | 
static int do_test(struct perf_evlist *evlist, int mmap_pages, 
 | 
           int *sample_count, int *comm_count) 
 | 
{ 
 | 
    int err; 
 | 
    char sbuf[STRERR_BUFSIZE]; 
 | 
  
 | 
    err = perf_evlist__mmap(evlist, mmap_pages); 
 | 
    if (err < 0) { 
 | 
        pr_debug("perf_evlist__mmap: %s\n", 
 | 
             str_error_r(errno, sbuf, sizeof(sbuf))); 
 | 
        return TEST_FAIL; 
 | 
    } 
 | 
  
 | 
    perf_evlist__enable(evlist); 
 | 
    testcase(); 
 | 
    perf_evlist__disable(evlist); 
 | 
  
 | 
    err = count_samples(evlist, sample_count, comm_count); 
 | 
    perf_evlist__munmap(evlist); 
 | 
    return err; 
 | 
} 
 | 
  
 | 
  
 | 
int test__backward_ring_buffer(struct test *test __maybe_unused, int subtest __maybe_unused) 
 | 
{ 
 | 
    int ret = TEST_SKIP, err, sample_count = 0, comm_count = 0; 
 | 
    char pid[16], sbuf[STRERR_BUFSIZE]; 
 | 
    struct perf_evlist *evlist; 
 | 
    struct perf_evsel *evsel __maybe_unused; 
 | 
    struct parse_events_error parse_error; 
 | 
    struct record_opts opts = { 
 | 
        .target = { 
 | 
            .uid = UINT_MAX, 
 | 
            .uses_mmap = true, 
 | 
        }, 
 | 
        .freq          = 0, 
 | 
        .mmap_pages   = 256, 
 | 
        .default_interval = 1, 
 | 
    }; 
 | 
  
 | 
    snprintf(pid, sizeof(pid), "%d", getpid()); 
 | 
    pid[sizeof(pid) - 1] = '\0'; 
 | 
    opts.target.tid = opts.target.pid = pid; 
 | 
  
 | 
    evlist = perf_evlist__new(); 
 | 
    if (!evlist) { 
 | 
        pr_debug("Not enough memory to create evlist\n"); 
 | 
        return TEST_FAIL; 
 | 
    } 
 | 
  
 | 
    err = perf_evlist__create_maps(evlist, &opts.target); 
 | 
    if (err < 0) { 
 | 
        pr_debug("Not enough memory to create thread/cpu maps\n"); 
 | 
        goto out_delete_evlist; 
 | 
    } 
 | 
  
 | 
    bzero(&parse_error, sizeof(parse_error)); 
 | 
    /* 
 | 
     * Set backward bit, ring buffer should be writing from end. Record 
 | 
     * it in aux evlist 
 | 
     */ 
 | 
    err = parse_events(evlist, "syscalls:sys_enter_prctl/overwrite/", &parse_error); 
 | 
    if (err) { 
 | 
        pr_debug("Failed to parse tracepoint event, try use root\n"); 
 | 
        ret = TEST_SKIP; 
 | 
        goto out_delete_evlist; 
 | 
    } 
 | 
  
 | 
    perf_evlist__config(evlist, &opts, NULL); 
 | 
  
 | 
    err = perf_evlist__open(evlist); 
 | 
    if (err < 0) { 
 | 
        pr_debug("perf_evlist__open: %s\n", 
 | 
             str_error_r(errno, sbuf, sizeof(sbuf))); 
 | 
        goto out_delete_evlist; 
 | 
    } 
 | 
  
 | 
    ret = TEST_FAIL; 
 | 
    err = do_test(evlist, opts.mmap_pages, &sample_count, 
 | 
              &comm_count); 
 | 
    if (err != TEST_OK) 
 | 
        goto out_delete_evlist; 
 | 
  
 | 
    if ((sample_count != NR_ITERS) || (comm_count != NR_ITERS)) { 
 | 
        pr_err("Unexpected counter: sample_count=%d, comm_count=%d\n", 
 | 
               sample_count, comm_count); 
 | 
        goto out_delete_evlist; 
 | 
    } 
 | 
  
 | 
    err = do_test(evlist, 1, &sample_count, &comm_count); 
 | 
    if (err != TEST_OK) 
 | 
        goto out_delete_evlist; 
 | 
  
 | 
    ret = TEST_OK; 
 | 
out_delete_evlist: 
 | 
    perf_evlist__delete(evlist); 
 | 
    return ret; 
 | 
} 
 |