[Intel-gfx] [PATCH i-g-t 1/1] igt/dapc: Test Driver Assisted Performance Capture (DAPC)

Kamble, Sagar A sagar.a.kamble at intel.com
Wed Aug 30 11:17:34 UTC 2017


Thanks Lionel for the review. Will revamp the testcase.


Thanks

Sagar

On 8/29/2017 2:21 PM, Lionel Landwerlin wrote:
> Hi Sagar,
>
> Thanks for writing this test. It looks promising but there are a few 
> issues that needs to be addressed for this to run in CI.
> Please have a look at the comments below.
>
> Thanks!
>
> On 28/08/17 10:53, Sagar Arun Kamble wrote:
>> This test verifies different i915 perf sampling options for fields like
>> PID, CTX ID, Timestamp, OA Report, TAG, MMIO.
>>
>> Cc: Lionel Landwerlin <lionel.g.landwerlin at intel.com>
>> Signed-off-by: Sourab Gupta <sourab.gupta at intel.com>
>> Signed-off-by: Sagar Arun Kamble <sagar.a.kamble at intel.com>
>> ---
>>   tests/Makefile.sources |    1 +
>>   tests/dapc.c           | 1017 
>> ++++++++++++++++++++++++++++++++++++++++++++++++
>>   2 files changed, 1018 insertions(+)
>>   create mode 100644 tests/dapc.c
>>
>> diff --git a/tests/Makefile.sources b/tests/Makefile.sources
>> index bb013c7..61feb0d 100644
>> --- a/tests/Makefile.sources
>> +++ b/tests/Makefile.sources
>> @@ -26,6 +26,7 @@ TESTS_progs = \
>>       core_getversion \
>>       core_prop_blob \
>>       core_setmaster_vs_auth \
>> +    dapc \
>>       debugfs_test \
>>       drm_import_export \
>>       drm_mm \
>> diff --git a/tests/dapc.c b/tests/dapc.c
>> new file mode 100644
>> index 0000000..f49b1cd
>> --- /dev/null
>> +++ b/tests/dapc.c
>> @@ -0,0 +1,1017 @@
>> +/*
>> + * Copyright © 2017 Intel Corporation
>> + *
>> + * Permission is hereby granted, free of charge, to any person 
>> obtaining a
>> + * copy of this software and associated documentation files (the 
>> "Software"),
>> + * to deal in the Software without restriction, including without 
>> limitation
>> + * the rights to use, copy, modify, merge, publish, distribute, 
>> sublicense,
>> + * and/or sell copies of the Software, and to permit persons to whom 
>> the
>> + * Software is furnished to do so, subject to the following conditions:
>> + *
>> + * The above copyright notice and this permission notice (including 
>> the next
>> + * paragraph) shall be included in all copies or substantial 
>> portions of the
>> + * Software.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
>> EXPRESS OR
>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
>> MERCHANTABILITY,
>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO 
>> EVENT SHALL
>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 
>> OR OTHER
>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 
>> ARISING
>> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 
>> OTHER DEALINGS
>> + * IN THE SOFTWARE.
>> + *
>> + * dapc: Driver Assisted Performance Capture
>> + *     This tests the i915 perf functionality to sample various 
>> metrics by
>> + *     associating with the CS stream or just standalone periodic OA 
>> samples.
>> + *     Verifies fields like PID, CTX ID, Timestamp, OA Report, MMIO, 
>> Tags are
>> + *     generated properly for each sample.
>> + *
>> + * Authors:
>> + *   Sourab Gupta <sourab.gupta at intel.com>
>> + *   Sagar Arun Kamble <sagar.a.kamble at intel.com>
>> + *
>> + */
>> +#define _GNU_SOURCE
>> +#include "xf86drm.h"
>> +#include "i915_drm.h"
>> +#include "igt_core.h"
>> +#include <linux/perf_event.h>
>> +#include <asm/unistd.h>
>> +#include <sys/types.h>
>> +#include <sys/stat.h>
>> +#include <fcntl.h>
>> +#include <sys/mman.h>
>> +#include <sys/ioctl.h>
>> +#include <dirent.h>
>> +#include <limits.h>
>> +#include <errno.h>
>> +#include <stdint.h>
>> +#include <stdbool.h>
>> +#include <stdlib.h>
>> +#include <stdio.h>
>> +#include <unistd.h>
>> +#include <string.h>
>> +#include <assert.h>
>> +#include <time.h>
>> +
>
> To be able to run this test in the continuous integration system, we 
> need it to be autonomous.
> The following macro requires user interaction. Unfortunately that 
> won't work.
> Please look at the other tests to create subtests and make sure we can 
> run this in the CI.
> Thanks!
Yes. Will update this.
>
>> +#define COLLECT_DATA { \
>> +    printf("(%s) Collecting data. ", __func__); \
>> +    printf("Press enter to continue...\n"); \
>> +    getc(stdin); \
>> +}
>> +
>
> It would be good to test stream configurations with different sizes.
> For example only Pid, or Tag & Pid or SourceInfo & ctx ID & Tag, etc...
> And verify that we get reports with appropriate sizes.
Sure. Will try to add testcases for those combinations too.
>
>> +#define OA_SAMPLE_SIZE_MAX    (8 +    /* drm_i915_perf_record_header 
>> */ \
>> +                 8 +    /* source info */ \
>> +                 8 +    /* ctx ID */ \
>> +                 8 +    /* Pid */ \
>> +                 8 +    /* Tag */ \
>> +                 256) /* raw OA counter snapshot */
>> +
>> +#define TS_SAMPLE_SIZE_MAX    (8 +    /* drm_i915_perf_record_header 
>> */ \
>> +                 8 +    /* ctx ID */ \
>> +                 8 +    /* Pid */ \
>> +                 8 +    /* Tag */ \
>> +                 8)    /* Timestamp */ \
>> +
>> +#define TS_MMIO_SAMPLE_SIZE_MAX    (8 +   /* 
>> drm_i915_perf_record_header */ \
>> +                 8 +   /* ctx ID */ \
>> +                 8 +   /* Pid */ \
>> +                 8 +   /* Tag */ \
>> +                 8 +   /* Timestamp */ \
>> +                 4*I915_PERF_MMIO_NUM_MAX)    /* MMIO reg */
>> +
>> +#define OA_TS_MMIO_SAMPLE_SIZE_MAX (8 +   /* 
>> drm_i915_perf_record_header */ \
>> +                    8 +   /* source info */ \
>> +                    8 +   /* ctx ID */ \
>> +                    8 +   /* Pid */ \
>> +                    8 +   /* Tag */ \
>> +                    8 +   /* Timestamp */ \
>> +                    (4*I915_PERF_MMIO_NUM_MAX) + /* MMIO reg*/ \
>> +                    256) /* raw OA counter snapshot */
>> +
>> +#define READ_OA_BUF_SIZE_MAX        (100*OA_SAMPLE_SIZE_MAX)
>> +#define READ_TS_BUF_SIZE_MAX        (100*TS_SAMPLE_SIZE_MAX)
>> +#define READ_TS_MMIO_BUF_SIZE_MAX (100*TS_MMIO_SAMPLE_SIZE_MAX)
>> +#define READ_OA_TS_MMIO_BUF_SIZE_MAX (100*OA_TS_MMIO_SAMPLE_SIZE_MAX)
>> +
>> +#define SAMPLE_OA    (1<<0)
>> +#define SAMPLE_TS    (1<<1)
>> +#define SAMPLE_MMIO    (1<<2)
>> +
>> +struct intel_device {
>> +    uint32_t device;
>> +    uint32_t subsystem_device;
>> +    uint32_t subsystem_vendor;
>> +};
>> +
>> +enum platform {
>> +    ARCH_HSW,
>> +    ARCH_BDW,
>> +    ARCH_SKL,
>> +} arch;
>> +
>> +/* DAPC OA samples read() from i915 perf */
>> +struct dapc_oa_sample {
>> +    struct drm_i915_perf_record_header header;
>> +    uint64_t source_info;
>> +    uint64_t ctx_id;
>> +    uint64_t pid;
>> +    uint64_t tag;
>> +    uint8_t oa_report[];
>> +};
>> +
>> +/* DAPC timestamp samples read() from i915 perf */
>> +struct dapc_ts_sample {
>> +    struct drm_i915_perf_record_header header;
>> +    uint64_t ctx_id;
>> +    uint64_t pid;
>> +    uint64_t tag;
>> +    uint64_t timestamp;
>> +};
>> +
>> +/* DAPC timestamp + mmio samples read() from i915 perf */
>> +struct dapc_ts_mmio_sample {
>> +    struct drm_i915_perf_record_header header;
>> +    uint64_t ctx_id;
>> +    uint64_t pid;
>> +    uint64_t tag;
>> +    uint64_t timestamp;
>> +    uint32_t mmio[2];
>> +};
>> +
>> +/* DAPC OA + timestamp + mmio samples read() from i915 perf */
>> +struct dapc_oa_ts_mmio_sample {
>> +    struct drm_i915_perf_record_header header;
>> +    uint64_t source_info;
>> +    uint64_t ctx_id;
>> +    uint64_t pid;
>> +    uint64_t tag;
>> +    uint64_t timestamp;
>> +
>> +    /*
>> +     * Hardcoding 2 here since the array size would depend on no. of 
>> mmio
>> +     * values queried. TODO: Find a better way to do this.
>> +     */
>> +    uint32_t mmio[2];
>> +    uint8_t oa_report[];
>> +};
>> +
>> +struct i915_oa_format {
>> +    int format;
>> +    int size;
>> +};
>> +
>> +static struct i915_oa_format hsw_oa_formats[I915_OA_FORMAT_MAX] = {
>> +    [I915_OA_FORMAT_A13]        = { 0, 64 },
>> +    [I915_OA_FORMAT_A29]        = { 1, 128 },
>> +    [I915_OA_FORMAT_A13_B8_C8]  = { 2, 128 },
>> +    /* A29_B8_C8 Disallowed as 192 bytes doesn't factor into buffer 
>> size */
>> +    [I915_OA_FORMAT_B4_C8]        = { 4, 64 },
>> +    [I915_OA_FORMAT_A45_B8_C8]  = { 5, 256 },
>> +    [I915_OA_FORMAT_B4_C8_A16]  = { 6, 128 },
>> +    [I915_OA_FORMAT_C4_B8]        = { 7, 64 },
>> +};
>> +
>> +static struct i915_oa_format 
>> gen8_plus_oa_formats[I915_OA_FORMAT_MAX] = {
>> +    [I915_OA_FORMAT_A12]            = { 0, 64 },
>> +    [I915_OA_FORMAT_A12_B8_C8]        = { 2, 128 },
>> +    [I915_OA_FORMAT_A32u40_A4u32_B8_C8] = { 5, 256 },
>> +    [I915_OA_FORMAT_C4_B8]            = { 7, 64 },
>> +};
>> +
>
> I'm not sure it's worth testing all the configs, maybe just limit the 
> test to TestOa.
> You can pickup the uuids in perf.c.
Ok. Will update.
>
>> +static const char * const hsw_guids[] = {
>> +    "403d8832-1a27-4aa6-a64e-f5389ce7b212",
>> +    "39ad14bc-2380-45c4-91eb-fbcb3aa7ae7b",
>> +    "3865be28-6982-49fe-9494-e4d1b4795413",
>> +    "bb5ed49b-2497-4095-94f6-26ba294db88a",
>> +    "3358d639-9b5f-45ab-976d-9b08cbfc6240",
>> +    "bc274488-b4b6-40c7-90da-b77d7ad16189",
>> +};
>> +
>> +/*
>> + * Need to update GUID based on latest i915 configuration. Currently
>> + * first GUID is being tested.
>> + */
>> +static const char * const skl_guids[] = {
>> +    "1651949f-0ac0-4cb1-a06f-dafd74a407d1",
>> +    "f519e481-24d2-4d42-87c9-3fdd12c00202",
>> +    "fdfc01cc-e28e-423a-aae0-b5ed5d4d7a9f",
>> +    "c9c7ace5-614a-4f8e-90c7-30064c36cad2",
>> +    "99797dc2-b48f-4d83-b973-613cff01202b",
>> +    "afa148ea-77fb-48ee-b8f8-e5e971ecf589",
>> +    "bfce7061-e6f1-4a78-bed8-c9cc69af70f9",
>> +    "c35ddcab-b1f2-452f-969a-a8209d531a00",
>> +    "2b0d0c83-706a-4cb6-b55e-d6bcf51fa6d3",
>> +    "d084f6a9-f706-4b74-b98c-65daa5340517",
>> +    "c7ed493c-54ff-4152-baf4-07e31e7a24cb",
>> +    "43ad9300-198a-4734-8f3a-2a2151b9dab6",
>> +    "ccfce3f2-6c63-4630-a043-f2a0243fed8f",
>> +    "2e564b28-98fa-42a0-8bbc-7915de3cc03c",
>> +    "a305533f-7e36-4fb6-8749-c6280bce3457",
>> +    "34ecd59f-6b52-4004-916f-afe9530a0442",
>> +    "ee1990d9-6e93-4c7c-aa9e-b40e1ec4d41b",
>> +};
>> +
>> +static struct intel_device intel_dev;
>> +static int drm_fd = -1;
>> +static int drm_card = -1;
>> +static int perf_event_fd_rcs = -1;
>> +
>> +static uint64_t read_file_uint64(const char *file)
>> +{
>> +    char buf[32];
>> +    int fd, n;
>> +
>> +    fd = open(file, 0);
>> +    if (fd < 0)
>> +        return 0;
>> +    n = read(fd, buf, sizeof(buf) - 1);
>> +    close(fd);
>> +    if (n < 0)
>> +        return 0;
>> +
>> +    buf[n] = '\0';
>> +    return strtoull(buf, 0, 0);
>> +}
>> +
>> +static uint32_t read_device_param(int id, const char *param)
>> +{
>> +    char *name;
>> +    int ret = asprintf(&name, "/sys/class/drm/renderD%u/device/%s",
>> +               id, param);
>> +    uint32_t value;
>> +
>> +    assert(ret != -1);
>> +
>> +    value = read_file_uint64(name);
>> +    free(name);
>> +
>> +    return value;
>> +}
>> +
>> +static int get_card_for_fd(int fd)
>> +{
>> +    struct stat sb;
>> +    int mjr, mnr;
>> +    char buffer[128];
>> +    DIR *drm_dir;
>> +    int entry_size;
>> +    struct dirent *entry1, *entry2;
>> +    int name_max;
>> +
>> +    if (fstat(fd, &sb)) {
>> +        printf("Failed to stat DRM fd\n");
>> +        return -1;
>> +    }
>> +
>> +    mjr = major(sb.st_rdev);
>> +    mnr = minor(sb.st_rdev);
>> +
>> +    snprintf(buffer, sizeof(buffer), "/sys/dev/char/%d:%d/device/drm",
>> +         mjr, mnr);
>> +
>> +    drm_dir = opendir(buffer);
>> +    assert(drm_dir != NULL);
>> +
>> +    name_max = pathconf(buffer, _PC_NAME_MAX);
>> +
>> +    if (name_max == -1)
>> +        name_max = 255;
>> +
>> +    entry_size = 256;
>> +    entry1 = alloca(entry_size);
>> +
>> +    while ((readdir_r(drm_dir, entry1, &entry2) == 0) && entry2 != 
>> NULL)
>> +        if (entry2->d_type == DT_DIR &&
>> +            strncmp(entry2->d_name, "card", 4) == 0)
>> +            return strtoull(entry2->d_name + 4, NULL, 10);
>> +
>> +    return -1;
>> +}
>> +
>> +
>
> You can replace the following function with __drm_open_driver_render.
Ok. Will update.
>
>> +static int open_render_node(struct intel_device *dev)
>> +{
>> +    char *name;
>> +    int i, fd;
>> +
>> +    for (i = 128; i < (128 + 16); i++) {
>> +        int ret;
>> +
>> +        ret = asprintf(&name, "/dev/dri/renderD%u", i);
>> +        assert(ret != -1);
>> +
>> +        fd = open(name, O_RDWR);
>> +        free(name);
>> +
>> +        if (fd == -1)
>> +            continue;
>> +
>> +        if (read_device_param(i, "vendor") != 0x8086) {
>> +            close(fd);
>> +            fd = -1;
>> +            continue;
>> +        }
>> +
>> +        dev->device = read_device_param(i, "device");
>> +        dev->subsystem_device = read_device_param(i,
>> +                              "subsystem_device");
>> +        dev->subsystem_vendor = read_device_param(i,
>> +                              "subsystem_vendor");
>> +
>> +        return fd;
>> +    }
>> +
>> +    return fd;
>> +}
>
> The following function can be replaced by igt_ioctl().
Ok. Will update.
>
>> +
>> +/* Handle restarting ioctl if interrupted... */
>> +static int perf_ioctl(int fd, unsigned long request, void *arg)
>> +{
>> +    int ret;
>> +
>> +    do {
>> +        ret = ioctl(fd, request, arg);
>> +    } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
>> +
>> +    return ret;
>> +}
>> +
>> +int read_perf_dapc_samples(uint8_t *temp_buf, uint8_t *out_data,
>> +               uint8_t sample_flags, int fd)
>> +{
>> +    int count, max_read_size = 16*1024*1024, size_copied = 0, offset 
>> = 0;
>> +
>> +    if (sample_flags & SAMPLE_OA)
>> +        max_read_size = READ_OA_BUF_SIZE_MAX;
>> +    else if (sample_flags & SAMPLE_TS)
>> +        max_read_size = READ_TS_BUF_SIZE_MAX;
>> +    else if (sample_flags & (SAMPLE_TS|SAMPLE_MMIO))
>> +        max_read_size = READ_TS_MMIO_BUF_SIZE_MAX;
>> +    else if (sample_flags & (SAMPLE_OA|SAMPLE_TS|SAMPLE_MMIO)) {
>> +        max_read_size = READ_OA_TS_MMIO_BUF_SIZE_MAX;
>> +    } else {
>> +        printf("Unknown sample flags: %d\n", sample_flags);
>> +        return -1;
>> +    }
>> +
>> +    count = read(fd, temp_buf, max_read_size);
>> +
>> +    if (count < 0) {
>> +        printf("Error reading i915 OA event stream. Errno:%d", errno);
>> +        perror("Error : ");
>> +        return count;
>> +    }
>> +
>> +    if (count == 0)
>> +        return 0;
>> +
>> +    while (offset < count) {
>> +        struct drm_i915_perf_record_header *header =
>> +        (struct drm_i915_perf_record_header *)(temp_buf + offset);
>> +
>> +        if (header->size == 0) {
>> +            printf("Spurious header size == 0\n");
>> +            /* XXX: How should we handle this instead of exiting()*/
>> +            exit(1);
>> +        }
>> +
>> +        offset += header->size;
>> +
>> +        switch (header->type) {
>> +        case DRM_I915_PERF_RECORD_OA_BUFFER_LOST:
>> +            printf("i915_oa: OA buffer overflow\n");
>> +            break;
>> +        case DRM_I915_PERF_RECORD_OA_REPORT_LOST:
>> +            printf("i915_oa: OA report lost\n");
>> +            break;
>> +        case DRM_I915_PERF_RECORD_SAMPLE:
>> +            if (sample_flags & SAMPLE_OA) {
>> +                struct dapc_oa_sample *sample =
>> +                    (struct dapc_oa_sample *)header;
>> +
>> +                if (sample->source_info ==
>> +                    I915_PERF_SAMPLE_OA_SOURCE_RCS) {
>> +                    /* DAPC sample */
>> +                    printf("DAPC OA sample\n");
>> +                } else {
>> +                    /* Periodic sample. No need to copy */
>> +                    printf("Periodic sample\n");
>> +                    continue;
>> +                }
>> +            }
>> +            memcpy(out_data + size_copied, header, header->size);
>> +            size_copied += header->size;
>> +            break;
>> +        default:
>> +            printf("i915_oa: Spurious header type = %d\n",
>> +                   header->type);
>> +        }
>> +    }
>> +
>> +    return size_copied;
>> +}
>> +
>> +bool read_metrics_id_from_sysfs(int *metrics_id)
>> +{
>> +    char buffer[128];
>> +    const char *guid;
>> +
>> +    assert(drm_card >= 0);
>> +
>> +    /*
>> +     * Select render basic metrics ID - i.e. first guid, from the arch
>> +     * specific guids.
>> +     */
>> +    switch (arch) {
>> +    case ARCH_HSW:
>> +        guid = hsw_guids[0];
>> +        break;
>
> You defined ARCH_BDW, but it appears to be missing here.
Yes. Will update.
>
>> +    case ARCH_SKL:
>> +        guid = skl_guids[0];
>> +        break;
>> +    default:
>> +        printf("guid not found for the arch\n");
>> +        return false;
>> +    }
>> +
>> +    snprintf(buffer, sizeof(buffer),
>> +         "/sys/class/drm/card%d/metrics/%s/id",
>> +         drm_card, guid);
>> +    *metrics_id = read_file_uint64(buffer);
>> +
>> +    return true;
>> +}
>> +
>> +static void open_i915_rcs_oa_stream(int report_format, int metrics_id)
>> +{
>> +    int period_exponent = 16;//0;
>> +    int ring_id = I915_EXEC_RENDER; /* RCS */
>> +    struct drm_i915_perf_open_param param;
>> +    uint64_t properties[] = {
>> +        DRM_I915_PERF_PROP_SAMPLE_OA, true,
>> +        DRM_I915_PERF_PROP_OA_METRICS_SET, metrics_id,
>> +        DRM_I915_PERF_PROP_OA_FORMAT, report_format,
>> +        DRM_I915_PERF_PROP_OA_EXPONENT, period_exponent,
>> +        DRM_I915_PERF_PROP_ENGINE, ring_id,
>> +        DRM_I915_PERF_PROP_SAMPLE_OA_SOURCE, true,
>> +        DRM_I915_PERF_PROP_SAMPLE_CTX_ID, true,
>> +        DRM_I915_PERF_PROP_SAMPLE_PID, true,
>> +        DRM_I915_PERF_PROP_SAMPLE_TAG, true,
>> +    };
>
> This test will potentially run on older kernels, where the feature 
> you're adding won't be available.
> It needs to handle this case an just skip the tests if opening the 
> stream with newer options isn't supported.
Ok. Will update.
>
>> +    int fd;
>> +
>> +    memset(&param, 0, sizeof(param));
>> +
>> +    param.flags = 0;
>> +    param.flags |= I915_PERF_FLAG_FD_CLOEXEC;
>> +    param.flags |= I915_PERF_FLAG_FD_NONBLOCK;
>> +
>> +    param.properties_ptr = (uint64_t)properties;
>> +    param.num_properties = sizeof(properties) / 16;
>> +
>> +    fd = perf_ioctl(drm_fd, DRM_IOCTL_I915_PERF_OPEN, &param);
>> +
>> +    if (fd == -1) {
>> +        perror("Error opening i915 perf event : ");
>> +        return;
>> +    }
>> +
>> +    printf("Opened i915 perf event.\n");
>> +    perf_event_fd_rcs = fd;
>> +}
>> +
>> +static void open_i915_rcs_ts_stream(void)
>> +{
>> +    struct drm_i915_perf_open_param param;
>> +    int ring_id = I915_EXEC_RENDER; /* RCS */
>> +    uint64_t properties[] = {
>> +        DRM_I915_PERF_PROP_ENGINE, ring_id,
>> +        DRM_I915_PERF_PROP_SAMPLE_TS, true,
>> +        DRM_I915_PERF_PROP_SAMPLE_CTX_ID, true,
>> +        DRM_I915_PERF_PROP_SAMPLE_PID, true,
>> +        DRM_I915_PERF_PROP_SAMPLE_TAG, true,
>> +    };
>> +    int fd;
>> +
>> +    memset(&param, 0, sizeof(param));
>> +
>> +    param.flags = 0;
>> +    param.flags |= I915_PERF_FLAG_FD_CLOEXEC;
>> +    param.flags |= I915_PERF_FLAG_FD_NONBLOCK;
>> +
>> +    param.properties_ptr = (uint64_t)properties;
>> +    param.num_properties = sizeof(properties) / 16;
>> +
>> +    fd = perf_ioctl(drm_fd, DRM_IOCTL_I915_PERF_OPEN, &param);
>> +
>> +    if (fd == -1) {
>> +        perror("Error opening i915 perf event : ");
>> +        return;
>> +    }
>> +
>> +    printf("Opened i915 perf event.\n");
>> +    perf_event_fd_rcs = fd;
>> +}
>> +
>> +static void open_i915_rcs_ts_mmio_stream(
>> +            struct drm_i915_perf_mmio_list *mmio_list)
>> +{
>> +    struct drm_i915_perf_open_param param;
>> +    int ring_id = I915_EXEC_RENDER; /* RCS */
>> +    uint64_t properties[] = {
>> +        DRM_I915_PERF_PROP_ENGINE, ring_id,
>> +        DRM_I915_PERF_PROP_SAMPLE_TS, true,
>> +        DRM_I915_PERF_PROP_SAMPLE_MMIO, (uint64_t)mmio_list,
>> +        DRM_I915_PERF_PROP_SAMPLE_CTX_ID, true,
>> +        DRM_I915_PERF_PROP_SAMPLE_PID, true,
>> +        DRM_I915_PERF_PROP_SAMPLE_TAG, true,
>> +    };
>> +    int fd;
>> +
>> +    memset(&param, 0, sizeof(param));
>> +
>> +    param.flags = 0;
>> +    param.flags |= I915_PERF_FLAG_FD_CLOEXEC;
>> +    param.flags |= I915_PERF_FLAG_FD_NONBLOCK;
>> +
>> +    param.properties_ptr = (uint64_t)properties;
>> +    param.num_properties = sizeof(properties) / 16;
>> +
>> +    fd = perf_ioctl(drm_fd, DRM_IOCTL_I915_PERF_OPEN, &param);
>> +
>> +    if (fd == -1) {
>> +        perror("Error opening i915 perf event : ");
>> +        return;
>> +    }
>> +
>> +    printf("Opened i915 perf event.\n");
>> +    perf_event_fd_rcs = fd;
>> +}
>> +
>> +static void open_i915_rcs_oa_ts_mmio_stream(int report_format, int 
>> metrics_id,
>> +            struct drm_i915_perf_mmio_list *mmio_list)
>> +{
>> +    int period_exponent = 16;//0;
>> +    int ring_id = I915_EXEC_RENDER; /* RCS */
>> +    struct drm_i915_perf_open_param param;
>> +    uint64_t properties[] = {
>> +        DRM_I915_PERF_PROP_SAMPLE_OA, true,
>> +        DRM_I915_PERF_PROP_OA_METRICS_SET, metrics_id,
>> +        DRM_I915_PERF_PROP_OA_FORMAT, report_format,
>> +        DRM_I915_PERF_PROP_OA_EXPONENT, period_exponent,
>> +        DRM_I915_PERF_PROP_ENGINE, ring_id,
>> +        DRM_I915_PERF_PROP_SAMPLE_OA_SOURCE, true,
>> +        DRM_I915_PERF_PROP_SAMPLE_TS, true,
>> +        DRM_I915_PERF_PROP_SAMPLE_MMIO, (uint64_t)mmio_list,
>> +        DRM_I915_PERF_PROP_SAMPLE_CTX_ID, true,
>> +        DRM_I915_PERF_PROP_SAMPLE_PID, true,
>> +        DRM_I915_PERF_PROP_SAMPLE_TAG, true,
>> +    };
>> +    int fd;
>> +
>> +    memset(&param, 0, sizeof(param));
>> +
>> +    param.flags = 0;
>> +    param.flags |= I915_PERF_FLAG_FD_CLOEXEC;
>> +    param.flags |= I915_PERF_FLAG_FD_NONBLOCK;
>> +
>> +    param.properties_ptr = (uint64_t)properties;
>> +    param.num_properties = sizeof(properties) / 16;
>> +
>> +    fd = perf_ioctl(drm_fd, DRM_IOCTL_I915_PERF_OPEN, &param);
>> +
>> +    if (fd == -1) {
>> +        perror("Error opening i915 perf event : ");
>> +        return;
>> +    }
>> +
>> +    printf("Opened i915 perf event.\n");
>> +    perf_event_fd_rcs = fd;
>> +}
>> +
>> +static void open_i915_periodic_oa_stream(int report_format, int 
>> metrics_id)
>> +{
>> +    int period_exponent = 16;//0;
>> +    struct drm_i915_perf_open_param param;
>> +    uint64_t properties[] = {
>> +        DRM_I915_PERF_PROP_SAMPLE_OA, true,
>> +        DRM_I915_PERF_PROP_OA_METRICS_SET, metrics_id,
>> +        DRM_I915_PERF_PROP_OA_FORMAT, report_format,
>> +        DRM_I915_PERF_PROP_OA_EXPONENT, period_exponent,
>> +        DRM_I915_PERF_PROP_SAMPLE_OA_SOURCE, true,
>> +    };
>> +    int fd;
>> +
>> +    memset(&param, 0, sizeof(param));
>> +
>> +    param.flags = 0;
>> +    param.flags |= I915_PERF_FLAG_FD_CLOEXEC;
>> +    param.flags |= I915_PERF_FLAG_FD_NONBLOCK;
>> +
>> +    param.properties_ptr = (uint64_t)properties;
>> +    param.num_properties = sizeof(properties) / 16;
>> +
>> +    fd = perf_ioctl(drm_fd, DRM_IOCTL_I915_PERF_OPEN, &param);
>> +
>> +    if (fd == -1) {
>> +        perror("Error opening i915 perf event : ");
>> +        return;
>> +    }
>> +
>> +    printf("Opened i915 perf event.\n");
>> +    perf_event_fd_rcs = fd;
>> +}
>> +
>> +static void close_i915_perf_stream(void)
>> +{
>> +    if (perf_event_fd_rcs != -1) {
>> +        close(perf_event_fd_rcs);
>> +        perf_event_fd_rcs = -1;
>> +    }
>> +}
>> +
>> +static void test_perf_dapc_rcs_oa(void)
>> +{
>> +    uint64_t report_format;
>> +    int metrics_id;
>> +    int size, report_size, current_size = 0;
>> +    uint8_t *dapc_data, *temp_buffer, *current_hdr;
>> +    int ret = 0;
>> +
>> +    if (arch == ARCH_HSW) {
>> +        report_format = I915_OA_FORMAT_A29;
>> +        report_size = hsw_oa_formats[report_format].size;
>> +    } else {
>> +        report_format = I915_OA_FORMAT_A12;
>> +        report_size = gen8_plus_oa_formats[report_format].size;
>> +    }
>> +
>> +    if (report_size < 0)
>> +        return;
>> +
>> +    dapc_data = malloc(READ_OA_BUF_SIZE_MAX);
>> +    temp_buffer = malloc(READ_OA_BUF_SIZE_MAX);
>> +
>> +    ret = read_metrics_id_from_sysfs(&metrics_id);
>> +    if (!ret) {
>> +        printf("Reading metrics id from sysfs failed\n");
>> +        return;
>> +    }
>> +
>> +    open_i915_rcs_oa_stream(report_format, metrics_id);
>> +
>> +    /* Collect samples */
>> +    COLLECT_DATA;
>> +
>> +    /* Read samples */
>> +    size = read_perf_dapc_samples(temp_buffer, dapc_data, SAMPLE_OA,
>> +                      perf_event_fd_rcs);
>
> What if size = -1?
> This needs to be checked, in the other tests too.
Will update.
>
>> +
>> +    current_hdr = dapc_data;
>> +
>> +    printf("size retrieved = %d\n", size);
>> +    /* Verify the sanity of DAPC node headers */
>> +    while (current_size < size) {
>> +        struct dapc_oa_sample *sample = (struct dapc_oa_sample *)
>> +                    (current_hdr + current_size);
>> +
>> +        igt_assert(sample->pid != 0);
>
> I'm not sure that's good enough.
> There is a need to verify that the pid actually matches something we 
> know is correct.
>
> I would suggest to spawn a child process that emits a rendercopy and 
> verify in the parent process that we get the number of written pixels 
> in the A21 counter :
>
> https://github.com/djdeath/intel-gpu-tools/blob/wip/djdeath/oa-next/tests/perf.c#L3593 
>
>
> It should verify that the reports containing the written pixels are 
> tagged with the appropriate PID.
Thanks for the suggestion. Will update. Probably something similar needs 
to be done for verifying ctx id.
>
>> +        printf("pid = %lu, ctx_id = %lu, OA(first 8 bytes):0x%llx, "
>> +               "oa ts=0x%x\n",
>> +            sample->pid, sample->ctx_id,
>> +            *(unsigned long long int *)sample->oa_report,
>> +            *(uint32_t *)(sample->oa_report + 4));
>> +
>> +        current_size += sample->header.size;
>> +    }
>> +    close_i915_perf_stream();
>> +
>> +    free(dapc_data);
>> +    free(temp_buffer);
>> +}
>> +
>> +static void test_perf_dapc_rcs_ts(void)
>> +{
>> +
>> +    uint64_t prev_ts = 0, init_ts = 0;
>> +    int size, current_size = 0;
>> +    uint8_t *dapc_data, *temp_buffer, *current_hdr;
>> +
>> +    dapc_data = malloc(READ_TS_BUF_SIZE_MAX);
>> +    temp_buffer = malloc(READ_TS_BUF_SIZE_MAX);
>> +
>> +    memset(dapc_data, 0, READ_TS_BUF_SIZE_MAX);
>> +    memset(temp_buffer, 0, READ_TS_BUF_SIZE_MAX);
>> +
>> +    open_i915_rcs_ts_stream();
>> +
>> +    /* Collect samples */
>> +    COLLECT_DATA;
>> +
>> +    /* Read samples */
>> +    size = read_perf_dapc_samples(temp_buffer, dapc_data, SAMPLE_TS,
>> +                      perf_event_fd_rcs);
>> +
>> +    current_hdr = dapc_data;
>> +
>> +    printf("size collected = %d\n", size);
>> +
>> +    /* Verify the sanity of DAPC data */
>> +    while (current_size < size) {
>> +        struct dapc_ts_sample *sample = (struct dapc_ts_sample *)
>> +                        (current_hdr + current_size);
>> +        uint64_t ts = sample->timestamp;
>> +
>> +        igt_assert(sample->pid != 0);
>> +        printf("pid = %lu, ctx_id = %lu, tag=%lu, ts=0x%llx\n",
>> +            sample->pid, sample->ctx_id, sample->tag,
>> +            (unsigned long long)ts);
>> +
>> +        igt_assert(ts > init_ts);
>> +        igt_assert(ts > prev_ts);
>> +        prev_ts = ts;
>> +
>> +        current_size += sample->header.size;
>> +    }
>> +
>> +    printf("total size read = %d\n", current_size);
>> +    close_i915_perf_stream();
>> +
>> +    free(dapc_data);
>> +    free(temp_buffer);
>> +}
>> +
>> +
>> +static void test_perf_dapc_rcs_ts_mmio(void)
>> +{
>> +
>> +    uint64_t prev_ts = 0, init_ts = 0;
>> +    int r, size, current_size = 0;
>> +    uint8_t *dapc_data, *temp_buffer, *current_hdr;
>> +    struct drm_i915_perf_mmio_list mmio;
>> +
>> +    dapc_data = malloc(READ_TS_MMIO_BUF_SIZE_MAX);
>> +    temp_buffer = malloc(READ_TS_MMIO_BUF_SIZE_MAX);
>> +
>> +    memset(&mmio, 0, sizeof(mmio));
>> +
>> +#define GEN6_GT_GFX_RC6                0x138108
>
> You can read the rc6 residency info from 
> /sys/kernel/debug/dri/0/i915_drpc_info.
> Maybe you could read it once there before opening the stream, then 
> close the steam and read it once more.
> Then verify that all the reports read have with the bounds of the 2 
> reads.
Thanks for the suggestion. Will update.
>
>> +#define GEN6_GT_GFX_RC6p 0x13810C
>> +    mmio.mmio_list[0] = GEN6_GT_GFX_RC6;
>> +    mmio.mmio_list[1] = GEN6_GT_GFX_RC6p;
>> +    mmio.num_mmio = 2;
>> +
>> +    open_i915_rcs_ts_mmio_stream(&mmio);
>> +
>> +    /* Collect samples */
>> +    COLLECT_DATA;
>> +
>> +    /* Read samples */
>> +    size = read_perf_dapc_samples(temp_buffer, dapc_data,
>> +                      SAMPLE_TS|SAMPLE_MMIO, perf_event_fd_rcs);
>> +
>> +    current_hdr = dapc_data;
>> +
>> +    printf("size collected = %d\n", size);
>> +    /* Verify the sanity of DAPC data */
>> +    while (current_size < size) {
>> +        struct dapc_ts_mmio_sample *sample =
>> +                        (struct dapc_ts_mmio_sample *)
>> +                        (current_hdr + current_size);
>> +        uint64_t ts = sample->timestamp;
>> +
>> +        igt_assert(sample->pid != 0);
>> +        printf("pid = %lu, ctx_id = %lu, ts=0x%llx\n",
>> +            sample->pid, sample->ctx_id,
>> +            (unsigned long long)ts);
>> +
>> +        igt_assert(ts > init_ts);
>> +        igt_assert(ts > prev_ts);
>> +        prev_ts = ts;
>> +
>> +        for (r = 0; r < mmio.num_mmio; r++) {
>> +            printf("mmio 0x%08X = 0x%08X\n",
>> +            mmio.mmio_list[r],
>> +            sample->mmio[r]);
>> +        }
>> +
>> +        current_size += sample->header.size;
>> +    }
>> +
>> +    printf("total size read = %d\n", current_size);
>> +    close_i915_perf_stream();
>> +
>> +    free(dapc_data);
>> +    free(temp_buffer);
>> +}
>> +
>> +static void test_perf_dapc_rcs_oa_ts_mmio(void)
>> +{
>> +
>> +    uint64_t report_format;
>> +    uint64_t prev_ts = 0, init_ts = 0;
>> +    int r, report_size, size, metrics_id, current_size = 0;
>> +    uint8_t *dapc_data, *temp_buffer, *current_hdr;
>> +    struct drm_i915_perf_mmio_list mmio;
>> +    int ret = 0;
>> +
>> +    if (arch == ARCH_HSW) {
>> +        report_format = I915_OA_FORMAT_A29;
>> +        report_size = hsw_oa_formats[report_format].size;
>> +    } else {
>> +        report_format = I915_OA_FORMAT_A12;
>> +        report_size = gen8_plus_oa_formats[report_format].size;
>> +    }
>> +
>> +    if (report_size < 0)
>> +        return;
>> +
>> +    dapc_data = malloc(READ_OA_TS_MMIO_BUF_SIZE_MAX);
>> +    temp_buffer = malloc(READ_OA_TS_MMIO_BUF_SIZE_MAX);
>> +
>> +    memset(&mmio, 0, sizeof(mmio));
>> +
>> +#define GEN6_GT_GFX_RC6                0x138108
>> +#define GEN6_GT_GFX_RC6p            0x13810C
>> +    mmio.mmio_list[0] = GEN6_GT_GFX_RC6;
>> +    mmio.mmio_list[1] = GEN6_GT_GFX_RC6p;
>> +    mmio.num_mmio = 2;
>> +
>> +    ret = read_metrics_id_from_sysfs(&metrics_id);
>> +    if (!ret) {
>> +        printf("Reading metrics id from sysfs failed\n");
>> +        return;
>> +    }
>> +
>> +    open_i915_rcs_oa_ts_mmio_stream(report_format, metrics_id, &mmio);
>> +
>> +    /* Collect samples */
>> +    COLLECT_DATA;
>> +
>> +    /* Read samples */
>> +    size = read_perf_dapc_samples(temp_buffer, dapc_data,
>> +                      SAMPLE_OA|SAMPLE_TS|SAMPLE_MMIO,
>> +                      perf_event_fd_rcs);
>> +
>> +    current_hdr = dapc_data;
>> +
>> +    printf("size collected = %d\n", size);
>> +    /* Verify the sanity of DAPC data */
>> +    while (current_size < size) {
>> +        struct dapc_oa_ts_mmio_sample *sample =
>> +                (struct dapc_oa_ts_mmio_sample *)
>> +                        (current_hdr + current_size);
>> +        uint64_t ts = sample->timestamp;
>> +
>> +        igt_assert(sample->pid != 0);
>> +        printf("pid = %lu, ctx_id = %lu, ts=0x%llx\n",
>> +            sample->pid, sample->ctx_id,
>> +            (unsigned long long)ts);
>> +
>> +        igt_assert(ts > init_ts);
>> +        igt_assert(ts > prev_ts);
>> +        prev_ts = ts;
>> +
>> +        for (r = 0; r < mmio.num_mmio; r++) {
>> +            printf("mmio 0x%08X = 0x%08X\n",
>> +            mmio.mmio_list[r], sample->mmio[r]);
>> +        }
>> +
>> +        current_size += sample->header.size;
>> +        printf("current size = %d\n", current_size);
>> +    }
>> +
>> +    printf("total size read = %d\n", current_size);
>> +    close_i915_perf_stream();
>> +
>> +    free(dapc_data);
>> +    free(temp_buffer);
>> +}
>> +
>> +static void test_perf_dapc_periodic_oa(void)
>> +{
>> +    uint64_t report_format;
>> +    int size, report_size, metrics_id;
>> +    uint8_t *dapc_data, *temp_buffer;
>> +    int ret = 0;
>> +
>> +    if (arch == ARCH_HSW) {
>> +        report_format = I915_OA_FORMAT_A29;
>> +        report_size = hsw_oa_formats[report_format].size;
>> +    } else {
>> +        report_format = I915_OA_FORMAT_A12;
>> +        report_size = gen8_plus_oa_formats[report_format].size;
>> +    }
>> +
>> +    if (report_size < 0)
>> +        return;
>> +
>> +    dapc_data = malloc(READ_OA_BUF_SIZE_MAX);
>> +    temp_buffer = malloc(READ_OA_BUF_SIZE_MAX);
>> +
>> +    ret = read_metrics_id_from_sysfs(&metrics_id);
>> +    if (!ret) {
>> +        printf("Reading metrics id from sysfs failed\n");
>> +        return;
>> +    }
>> +
>> +    open_i915_periodic_oa_stream(report_format, metrics_id);
>> +
>> +    /* Collect samples */
>> +    COLLECT_DATA;
>> +
>> +    /* Read samples */
>> +    size = read_perf_dapc_samples(temp_buffer, dapc_data, SAMPLE_OA,
>> +                      perf_event_fd_rcs);
>
> What are you testing here?
Will try to add checks for the source info, timestamp monotonic property.
>
>> +
>> +    close_i915_perf_stream();
>> +
>> +    free(dapc_data);
>> +    free(temp_buffer);
>> +}
>> +
>> +static bool
>> +initialize(void)
>> +{
>> +
>> +    if (intel_dev.device)
>> +        return true;
>> +
>> +    drm_fd = open_render_node(&intel_dev);
>> +    if (drm_fd < 0) {
>> +        printf("Failed to open render node\n");
>> +        return false;
>> +    }
>> +
>> +    drm_card = get_card_for_fd(drm_fd);
>> +    if (drm_card < 0) {
>> +        printf("Failed to get drm card info\n");
>> +        return false;
>> +    }
>> +
>> +    return true;
>> +}
>> +
>> +int main(int argc, char **argv)
>> +{
>> +    bool ret;
>> +    int option;
>> +    int platform;
>> +
>> +    if (argc != 3) {
>> +        printf("Usage: \n./dapc <Platform> <Test_mode>\
>> +        \nPlatform: 0-HSW, 1-BDW, 2-SKL\n\
>> +        \nTest_mode:\n\
>> +        \t0 - RCS OA mode\n\
>> +        \t1 - RCS TS mode\n\
>> +        \t2 - RCS TS+MMIO mode\n\
>> +        \t3 - RCS OA+TS+MMIO mode\n\
>> +        \t4 - Periodic OA mode\n");
>> +        return 0;
>> +    }
>> +
>> +    ret = initialize();
>> +    if (!ret)
>> +        return -1;
>> +
>> +    platform = atoi(argv[1]);
>> +    switch (platform) {
>> +    case 0:
>> +        arch = ARCH_HSW;
>> +        break;
>> +    case 1:
>> +        arch = ARCH_BDW;
>> +        break;
>> +    case 2:
>> +        arch = ARCH_SKL;
>> +        break;
>> +    default:
>> +        fprintf(stderr, "Invalid platform:%d\n", platform);
>> +        return -1;
>> +    }
>> +
>> +    option = atoi(argv[2]);
>> +    switch (option) {
>> +    case 0:
>> +        test_perf_dapc_rcs_oa();
>> +        break;
>> +    case 1:
>> +        test_perf_dapc_rcs_ts();
>> +        break;
>> +    case 2:
>> +        test_perf_dapc_rcs_ts_mmio();
>> +        break;
>> +    case 3:
>> +        test_perf_dapc_rcs_oa_ts_mmio();
>> +        break;
>> +    case 4:
>> +        test_perf_dapc_periodic_oa();
>> +        break;
>> +    default:
>> +        fprintf(stderr, "Invalid Option:%d\n", option);
>> +        return -1;
>> +    }
>> +
>> +    return 0;
>> +}
>
>



More information about the Intel-gfx mailing list