This test verifies different i915 perf sampling options for fields like
PID, CTX ID, Timestamp, OA Report, TAG, MMIO.

Cc: Lionel Landwerlin <lionel.g.landwer...@intel.com>
Signed-off-by: Sourab Gupta <sourab.gu...@intel.com>
Signed-off-by: Sagar Arun Kamble <sagar.a.kam...@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.gu...@intel.com>
+ *   Sagar Arun Kamble <sagar.a.kam...@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>
+
+#define COLLECT_DATA { \
+       printf("(%s) Collecting data. ", __func__); \
+       printf("Press enter to continue...\n"); \
+       getc(stdin); \
+}
+
+#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 },
+};
+
+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;
+}
+
+
+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;
+}
+
+/* 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;
+       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,
+       };
+       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);
+
+       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);
+               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
+#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);
+
+       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;
+}
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to