From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga07.intel.com (mga07.intel.com [134.134.136.100]) by gabe.freedesktop.org (Postfix) with ESMTPS id E709495FA2 for ; Thu, 4 Aug 2022 11:12:43 +0000 (UTC) Date: Thu, 4 Aug 2022 14:13:15 +0300 From: "Lisovskiy, Stanislav" To: Kamil Konieczny , igt-dev@lists.freedesktop.org Message-ID: References: <20220721115508.22527-1-stanislav.lisovskiy@intel.com> MIME-Version: 1.0 Content-Type: text/plain; charset=iso-8859-1 Content-Disposition: inline Content-Transfer-Encoding: 8bit In-Reply-To: Subject: Re: [igt-dev] [PATCH] igt/tests: Add plane stress test List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: igt-dev-bounces@lists.freedesktop.org Sender: "igt-dev" List-ID: On Fri, Jul 29, 2022 at 12:06:28PM +0200, Kamil Konieczny wrote: > Hi Stanislav, > > I have some general remarks, not for kms parts. > imho in subject line put name of test you want to add, so > instead of "igt/tests: " I would prefer > "tests/i915/i915_pipe_stress: Add plane pipes stress test" > or something similar. > > On 2022-07-21 at 14:55:08 +0300, Stanislav Lisovskiy wrote: > > This test attempts to utilize all connected > > outputs at the same time, using maximum possible > > resolution and amount of planes, to check whether > > we are hiting any kind of bandwidth, watermark or > > other limitations. > > > > Signed-off-by: Stanislav Lisovskiy > > --- > > tests/i915/i915_pipe_stress.c | 896 ++++++++++++++++++++++++++++++++++ > > tests/meson.build | 1 + > > 2 files changed, 897 insertions(+) > > create mode 100644 tests/i915/i915_pipe_stress.c > > > > diff --git a/tests/i915/i915_pipe_stress.c b/tests/i915/i915_pipe_stress.c > > new file mode 100644 > > index 0000000000..1ca0f6f6f8 > > --- /dev/null > > +++ b/tests/i915/i915_pipe_stress.c > > @@ -0,0 +1,896 @@ > > +/* > > + * Copyright © 2019 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. > > + */ > > Please change this into SPDX licence. > > > + > > +#include "igt.h" > > +#include "igt_rand.h" > > +#include "gpgpu_fill.h" > > +#include "drmtest.h" > > +#include "sw_sync.h" > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include "i915/gem.h" > > + > > +IGT_TEST_DESCRIPTION("Stress test how gpu and cpu behaves if maximum amount of planes, " > > + "cpu and gpu utilization is achieved in order to reveal possible " > > + "bandwidth/watermark and similar problems "); > ------------------------------------------------------------- ^ > Put dot at end of decriptions (here and in other descriptions). > > > + > > +#ifndef DRM_CAP_CURSOR_WIDTH > > +#define DRM_CAP_CURSOR_WIDTH 0x8 > > +#endif > > +#ifndef DRM_CAP_CURSOR_HEIGHT > > +#define DRM_CAP_CURSOR_HEIGHT 0x9 > > +#endif > > + > > +#define HAS_XELPD(drm_fd) (intel_display_ver(intel_get_drm_devid(drm_fd)) >= 13) > > + > > +#define N_BLITS 3 > > + > > +#define N_FORMATS 1 > > +static const uint32_t formats[N_FORMATS] = { > > + DRM_FORMAT_XRGB8888, > > +}; > > + > > +#define N_TILING_METHODS 2 > > +static const uint64_t tilings[N_TILING_METHODS] = { > > + DRM_FORMAT_MOD_LINEAR, > > + I915_FORMAT_MOD_Y_TILED, > > +}; > > + > > +static const char *format_str(int format_index) > > +{ > > + switch (formats[format_index]) { > > + case DRM_FORMAT_RGB565: > > + return "rgb565"; > > + case DRM_FORMAT_XRGB8888: > > + return "xrgb8888"; > > + case DRM_FORMAT_XRGB2101010: > > + return "xrgb2101010"; > > + default: > > + igt_assert(false); > > + } > > +} > > + > > +static const char *tiling_str(int tiling_index) > > +{ > > + switch (tilings[tiling_index]) { > > + case DRM_FORMAT_MOD_LINEAR: > > + return "untiled"; > > + case I915_FORMAT_MOD_X_TILED: > > + return "xtiled"; > > + case I915_FORMAT_MOD_Y_TILED: > > + return "ytiled"; > > + default: > > + igt_assert(false); > > + } > > +} > > + > > + > > +#define MAX_CORES 8 > > +#define MAX_PLANES 16 > > + > > +struct data; > > + > > +struct thread_context { > > + struct data *data; > > + int id; > > + void *buf1; > > + void *buf2; > > +}; > > + > > +struct rect { > > + int x; > > + int y; > > + int w; > > + int h; > > +}; > > + > > +struct gpu_context { > > + struct data *data; > > + int pipe; > > + int color; > > + int num_rectangles; > > + struct intel_buf *buf; > > + struct igt_fb *fb_ptr; > > + struct rect blt_rect; > > + struct intel_batchbuffer *batch; > > +}; > > + > > +enum { > > + RUNNING, > > + STOPPED, > > + PAUSED, > > + LAST_STATE = PAUSED > > +} thread_state; > > + > > +struct data { > > + int drm_fd; > > + igt_display_t display; > > + int num_planes[IGT_MAX_PIPES]; > > + uint32_t format; > > + uint64_t modifier; > > + uint32_t devid; > > + struct buf_ops *bops; > > + drm_intel_bufmgr *bufmgr; > > + drmModeModeInfo *last_mode[IGT_MAX_PIPES]; > > + struct igt_fb fb[IGT_MAX_PIPES * MAX_PLANES]; > > + struct igt_fb cursor_fb[IGT_MAX_PIPES]; > > + pthread_t cpu_thread[MAX_CORES]; > > + pthread_t gpu_thread[IGT_MAX_PIPES]; > > + bool cpu_thread_stop[MAX_CORES]; > > + int gpu_thread_state[IGT_MAX_PIPES]; > > + sem_t gpu_thread_pause_ack[IGT_MAX_PIPES]; > > + struct thread_context cpu_context[MAX_CORES]; > > + struct gpu_context gpu_context[IGT_MAX_PIPES]; > > + drmModeModeInfo *highest_mode[IGT_MAX_PIPES]; > > + drmModeConnectorPtr *connectors; > > + drmModeRes *mode_resources; > > + int number_of_cores; > > + const struct intel_execution_engine2 *engine; > > + igt_pipe_crc_t *pipe_crc[IGT_MAX_PIPES]; > > +}; > > + > > +static void stop_gpu_threads(struct data *data); > > +static void start_gpu_threads(struct data *data); > > + > > +struct base_crc { > > + bool set; > > + igt_crc_t crc; > > +}; > > + > > +#define BUF_SIZE (128 * 1024 * 1024) > > + > > +static void *cpu_load(void *d) > > +{ > > + char *buf1, *buf2; > > + struct thread_context *context = (struct thread_context *)d; > > + struct data *data = context->data; > > + > > + buf1 = context->buf1; > > + buf2 = context->buf2; > > + > > + data->cpu_thread_stop[context->id] = false; > > + > > + igt_info("CPU thread cpu id %d start\n", context->id); > > + > > + /* Just to make CPU busy... */ > > + while (!data->cpu_thread_stop[context->id]) { > > + memcpy(buf1, buf2, BUF_SIZE); > > + memcpy(buf2, buf1, BUF_SIZE); > > + } > > + > > + igt_info("CPU thread cpu id %d stop\n", context->id); > > + > > + return NULL; > > +} > > + > > +static struct intel_buf * > > +create_buf(struct data *data, int width, int height, uint32_t region) > > +{ > > + struct intel_buf *buf; > > + uint32_t handle; > > + > > + buf = calloc(1, sizeof(*buf)); > > + igt_assert(buf); > > + > > + /* > > + * Legacy code uses 32 bpp after buffer creation. > > + * Let's do the same due to keep shader intact. > > + */ > > + handle = gem_create_in_memory_regions(data->drm_fd, width * height, region); > > + intel_buf_init_using_handle(data->bops, handle, buf, > > + width/4, height, 32, 0, > > + I915_TILING_NONE, 0); > > + > > + return buf; > > +} > > + > > +static const struct intel_execution_engine2 *get_execution_engine(struct data *data) > > +{ > > + const struct intel_execution_engine2 *e; > > + > > + for_each_physical_engine(data->drm_fd, e) { > > + if (e->class != I915_ENGINE_CLASS_RENDER && > > + e->class != I915_ENGINE_CLASS_COMPUTE) > > + continue; > > + return e; > ---------------------- ^ > Imho you should here allocate memory and memcpy this, or use this > loop in place where you need it (and call worker with e). Hmmm.. Yep, I think those are part of intel_engine_data which is allocated only while for_each_physical_engine is running(see for_each_physical_engine) so yep, I guess it is kind of unsafe. Will do the memcpy. I was for some reason assuming we have a global list of those somewhere, but it is only for static engines, as I understand. I can simply move this to the actual data->engine initialization then and mem alloc and copy there, even though this doesn't seem much elegant to me. Need to check if there any better looking options. Stan > > > + } > > + > > + return NULL; > > +} > > + > > +static void gpgpu_fill(struct data *data, struct intel_buf *buf, > > + igt_fillfunc_t fill, int x, int y, int width, > > + int height, int color) > > +{ > > + fill(data->drm_fd, buf, x, y, width, height, color); > > Do not make such helper, just use fiil where you need this. > > > +} > > + > > +static void fill_gpu(struct gpu_context *context, > > + unsigned int x, unsigned int y, > > + unsigned int width, unsigned int height, > > + uint8_t color) > > +{ > > + struct data *data = context->data; > > + igt_fillfunc_t fill_fn = NULL; > > + > > + fill_fn = igt_get_gpgpu_fillfunc(data->devid); > > + > > + igt_require_f(fill_fn, "no gpgpu-fill function\n"); > > + > > + igt_assert(context->buf); > > + > > + gpgpu_fill(data, context->buf, fill_fn, x, y, width, height, color); > > Just use fill_fn here or save this fn into your data struct and > use that where you need it (then you can have a helper). > > > +} > > + > > +static void *gpu_load(void *ptr) > > +{ > > + struct gpu_context *context = (struct gpu_context *)ptr; > > + struct data *data = context->data; > > + int pipe = context->pipe; > > + int rect_divisor; > > + int rect_width; > > + int rect_height; > > + int frame_width; > > + int frame_height; > > + drmModeModeInfo *mode; > > + int frame = 0; > > + int x, y; > > + int rect; > > + > > + mode = data->highest_mode[pipe]; > > + if (!mode) > > + return NULL; > > + > > + frame_width = mode->hdisplay; > > + frame_height = mode->vdisplay; > > + > > + igt_info("GPU thread pipe %d start\n", pipe); > > + > > + context->buf = create_buf(data, data->highest_mode[pipe]->hdisplay, > > + data->highest_mode[pipe]->vdisplay, > > + INTEL_MEMORY_REGION_ID(I915_SYSTEM_MEMORY, 0)); > > + > > + while (data->gpu_thread_state[pipe] != STOPPED) { > > + > > + /* Fill the framebuffer using shader */ > > + rect = 0; > > + > > + while (rect < context->num_rectangles) { > > + /* divide at least by 2 and up to 8 */ > > + int x_rand, y_rand; > > + rect_divisor = 1 << (hars_petruska_f54_1_random_unsafe_max(3) + 1); > > + > > + rect_width = frame_width / rect_divisor; > > + rect_height = frame_height / rect_divisor; > > + > > + x_rand = hars_petruska_f54_1_random_unsafe_max(frame_width - rect_width); > > + y_rand = hars_petruska_f54_1_random_unsafe_max(frame_height/2 - rect_height); > > + > > + context->blt_rect.x = x + x_rand; > > + context->blt_rect.y = y + y_rand; > > + > > + /* Fill randomly sized and positioned rectangles */ > > + fill_gpu(context, context->blt_rect.x, context->blt_rect.y, > > + context->blt_rect.x + rect_width, > > + context->blt_rect.y + rect_height, > > + context->color); > > + > > + context->color += 4; > > + > > + ++rect; > > + } > > + frame++; > > + } > > + > > + intel_buf_close(data->bops, context->buf); > > + > > + igt_info("GPU thread pipe %d stop. Frames rendered: %d\n", pipe, frame); > > I would prefer igt_debug, but maybe for kms it is ok? > > > + > > + return NULL; > > +} > > + > > +static inline uint32_t pipe_select(enum pipe pipe) > > +{ > > + if (pipe > 1) > > + return pipe << DRM_VBLANK_HIGH_CRTC_SHIFT; > > + else if (pipe > 0) > > + return DRM_VBLANK_SECONDARY; > > + else > > + return 0; > > +} > > + > > +static unsigned get_vblank(int fd, enum pipe pipe, unsigned flags) > > +{ > > + union drm_wait_vblank vbl; > > + > > + memset(&vbl, 0, sizeof(vbl)); > > + vbl.request.type = DRM_VBLANK_RELATIVE | pipe_select(pipe) | flags; > > + if (drmIoctl(fd, DRM_IOCTL_WAIT_VBLANK, &vbl)) > > + return 0; > > + > > + return vbl.reply.sequence; > > +} > > + > > +static int commit_mode(struct data *data, igt_output_t *output, > > + enum pipe pipe, drmModeModeInfo *mode) > > +{ > > + int ret; > > + igt_output_override_mode(output, mode); > > + igt_output_set_pipe(output, pipe); > > + > > + ret = igt_display_try_commit_atomic(&data->display, > > + DRM_MODE_ATOMIC_TEST_ONLY | > > + DRM_MODE_ATOMIC_ALLOW_MODESET, NULL); > > + if (ret) { > > + igt_warn("Could not commit mode: \n"); > > + kmstest_dump_mode(mode); > > + return ret; > > + } > > + > > + igt_display_commit2(&data->display, COMMIT_ATOMIC); > > + > > + return 0; > > +} > > + > > +static void cursor_plane_set_fb(igt_plane_t *plane, struct igt_fb *fb, > > + int width, int height) > > +{ > > + igt_plane_set_fb(plane, fb); > > + igt_fb_set_size(fb, plane, width, height); > > +} > > + > > +static void universal_plane_set_fb(igt_plane_t *plane, struct igt_fb *fb, > > + int width, int height) > > +{ > > + igt_plane_set_fb(plane, fb); > > + igt_plane_set_position(plane, 0, 0); > > + igt_fb_set_size(fb, plane, width, height); > > +} > > + > > +static bool plane_needs_rotation(int drm_fd, uint64_t modifier, igt_plane_t *plane) > > +{ > > + return !HAS_XELPD(drm_fd) && !IS_DG2(intel_get_drm_devid(drm_fd)) && > > + modifier == I915_FORMAT_MOD_Y_TILED && > > + plane->type != DRM_PLANE_TYPE_CURSOR; > > +} > > + > > +static int try_plane_scaling(struct data *data, igt_plane_t *plane, > > + int width, int height) > > +{ > > + int ret; > > + > > + if (plane_needs_rotation(data->drm_fd, data->modifier, plane)) { > > + igt_plane_set_rotation(plane, IGT_ROTATION_90); > > + igt_plane_set_size(plane, height, width); > > + } else { > > + igt_plane_set_size(plane, width, height); > > + } > > + > > + ret = igt_display_try_commit_atomic(&data->display, > > + DRM_MODE_ATOMIC_TEST_ONLY | > > + DRM_MODE_ATOMIC_ALLOW_MODESET, > > + NULL); > > + > > + return ret; > > +} > > + > > +static void cleanup_plane_fbs(struct data *data, enum pipe pipe, int start, int end) > > +{ > > + int i = start; > > + > > + while (i < end) { > > + igt_remove_fb(data->display.drm_fd, > > + &data->fb[pipe * MAX_PLANES + i]); > > + data->fb[pipe * MAX_PLANES + i].fb_id = 0; > > + i++; > > + } > > +} > > + > > +static int pipe_stress(struct data *data, igt_output_t *output, > > + enum pipe pipe, drmModeModeInfo *mode) > > +{ > > + igt_plane_t *plane; > > + int i = 0; > > + int ret; > > + bool new_mode = false; > > + uint64_t cursor_width, cursor_height; > > + > > + do_or_die(drmGetCap(data->drm_fd, DRM_CAP_CURSOR_WIDTH, &cursor_width)); > > + do_or_die(drmGetCap(data->drm_fd, DRM_CAP_CURSOR_HEIGHT, &cursor_height)); > > + > > + if (!mode) > > + mode = igt_output_get_mode(output); > > + > > + if (data->last_mode[pipe] != mode) { > > + ret = commit_mode(data, output, pipe, mode); > > + > > + if (!ret) > > + return ret; > > + > > + data->last_mode[pipe] = mode; > > + new_mode = true; > > + } > > + > > + /* > > + * Looks like we can't have planes on that pipe at all > > + * or mode hasn't changed > > + */ > > + if (!data->num_planes[pipe] || !new_mode) > > + return 0; > > + > > + for_each_plane_on_pipe(&data->display, pipe, plane) { > > + int plane_width, plane_height; > > + if (plane->type == DRM_PLANE_TYPE_CURSOR) { > > + cursor_plane_set_fb(plane, &data->cursor_fb[pipe], > > + cursor_width, cursor_height); > > + plane_width = cursor_width; > > + plane_height = cursor_height; > > + } else { > > + universal_plane_set_fb(plane, &data->fb[pipe * MAX_PLANES + i], > > + mode->hdisplay, mode->vdisplay); > > + > > + plane_width = (mode->hdisplay * 3) / 4; > > + plane_height = (mode->vdisplay * 3) / 4; > > + > > + ret = try_plane_scaling(data, plane, plane_width, plane_height); > > + > > + while (ret) { > > + if (plane_width <= cursor_width || plane_height <= cursor_height) > > + break; > > + > > + plane_width /= 2; > > + plane_height /= 2; > > + > > + ret = try_plane_scaling(data, plane, plane_width, plane_height); > > + > > + igt_info("Reduced plane %d size to %dx%d\n", > > + plane->index, plane_width, plane_height); > > + } > > + if (ret) { > > + igt_info("Plane %d pipe %d try commit failed, exiting\n", i, pipe); > > + data->num_planes[pipe] = i; > > + igt_info("Max num planes for pipe %d set to %d\n", pipe, i); > > + /* > > + * We have now determined max amount of full sized planes, we will just > > + * keep it in mind and be smarter next time. Also lets remove unneeded fbs. > > + * Don't destroy cursor_fb as will take care about it at the end. > > + */ > > + igt_plane_set_fb(plane, NULL); > > + cleanup_plane_fbs(data, pipe, i, MAX_PLANES); > > + } > > + > > + if (++i >= data->num_planes[pipe]) > > + break; > > + } > > + } > > + > > + igt_display_commit2(&data->display, COMMIT_ATOMIC); > > + > > + return 0; > > +} > > + > > +static __u64 get_mode_data_rate(drmModeModeInfo *mode) > > +{ > > + __u64 data_rate = (__u64)mode->hdisplay * (__u64)mode->vdisplay * (__u64)mode->vrefresh; > > + > > + return data_rate; > > +} > > + > > + > > +static drmModeModeInfo *find_highest_mode(drmModeConnector *connector) > > +{ > > + drmModeModeInfo *highest_mode = NULL; > > + int j; > > + > > + for (j = 0; j < connector->count_modes; j++) { > > + if (!highest_mode) { > > + highest_mode = &connector->modes[j]; > > + } else if (connector->modes[j].vdisplay && connector->modes[j].hdisplay) { > > + __u64 highest_data_rate = get_mode_data_rate(highest_mode); > > + __u64 data_rate = get_mode_data_rate(&connector->modes[j]); > > + if (highest_data_rate < data_rate) > > + highest_mode = &connector->modes[j]; > > + } > > + } > > + > > + return highest_mode; > > +} > > + > > +typedef drmModeConnector *drmModeConnectorPtr; > > + > > +static void fill_connector_to_pipe_array(struct data *data, > > + drmModeRes *mode_resources, > > + drmModeConnectorPtr *connectors) > > +{ > > + int pipe = 0; > > + int i; > > + > > + memset(connectors, 0, sizeof(drmModeConnectorPtr) * > > + mode_resources->count_connectors); > > + > > + igt_info("Got %d connectors\n", mode_resources->count_connectors); > > + > > + for (i = 0; i < mode_resources->count_connectors; i++) { > > + drmModeConnector *connector; > > + > > + connector = drmModeGetConnector(data->drm_fd, > > + mode_resources->connectors[i]); > > + > > + if (!connector) { > > + igt_warn("could not get connector %i: %s\n", > > + mode_resources->connectors[i], strerror(errno)); > > + continue; > > + } > > + > > + if (connector->connection == DRM_MODE_CONNECTED) { > > + igt_info("Connector %d connected to pipe %d\n", i, pipe); > > + connectors[pipe] = (drmModeConnectorPtr)connector; > > + ++pipe; > > + if (pipe == IGT_MAX_PIPES) > > + break; > > + } else { > > + igt_info("Connector %d connection status %d\n", > > + i, connector->connection); > > + drmModeFreeConnector(connector); > > + } > > + } > > +} > > + > > +static void release_connectors(drmModeConnectorPtr *connectors) > > +{ > > + int i; > > + > > + for (i = 0; i < IGT_MAX_PIPES; i++) { > > + if (connectors[i]) > > + drmModeFreeConnector(connectors[i]); > > + } > > + free(connectors); > > +} > > + > > +#define MIN_DURATION_SEC 5.0 > > +#define MIN_ITERATIONS 20 > > Put that at begin of file (prefered) or just before first > function which will use it. > > > + > > +static void stress_pipes(struct data *data, struct timespec *start, > > + struct timespec *end) > > +{ > > + int pipe = 0; > > + int ret = 0; > > + igt_output_t *output; > > + igt_crc_t crc, crc2; > > + > > + for_each_connected_output(&data->display, output) { > > + if (!data->highest_mode[pipe]) > > + continue; > > + > > + igt_assert_f(data->display.pipes[pipe].n_planes < MAX_PLANES, > > + "Currently we don't support more than %d planes!", > > + MAX_PLANES); > > + > > + ret = pipe_stress(data, output, pipe, > > + data->highest_mode[pipe]); > > + if (ret) > > + break; > > + > > + igt_pipe_crc_start(data->pipe_crc[pipe]); > > + igt_pipe_crc_get_current(data->display.drm_fd, data->pipe_crc[pipe], &crc); > > + get_vblank(data->display.drm_fd, pipe, > > + DRM_VBLANK_NEXTONMISS); > > + igt_pipe_crc_get_current(data->display.drm_fd, data->pipe_crc[pipe], &crc2); > > + igt_pipe_crc_stop(data->pipe_crc[pipe]); > > + igt_assert_crc_equal(&crc, &crc2); > > + > > + ++pipe; > > + } > > +} > > + > > +static void stress(struct data *data) > > +{ > > + struct timespec start, end; > > + int iterations = 0; > > + bool need_continue; > > + > > + igt_gettime(&start); > > + > > + do { > > + igt_gettime(&end); > > + stress_pipes(data, &start, &end); > > + iterations++; > > + need_continue = > > + igt_time_elapsed(&start, &end) < MIN_DURATION_SEC; > > + } while ((need_continue || iterations < MIN_ITERATIONS)); > > +} > > + > > +static void start_gpu_threads(struct data *data) > > +{ > > + int i; > > + > > + data->bops = buf_ops_create(data->drm_fd); > > + data->engine = get_execution_engine(data); > > + > > + for (i = 0; i < IGT_MAX_PIPES; i++) { > > + if (!data->highest_mode[i]) > > + continue; > > + data->gpu_context[i].data = data; > > + data->gpu_context[i].pipe = i; > > + data->gpu_context[i].fb_ptr = NULL; > > + data->gpu_context[i].blt_rect.x = 0; > > + data->gpu_context[i].blt_rect.y = 0; > > + data->gpu_context[i].blt_rect.w = 0; > > + data->gpu_context[i].blt_rect.h = 0; > > + data->gpu_context[i].num_rectangles = N_BLITS; > > + data->gpu_thread_state[i] = RUNNING; > > + data->gpu_context[i].buf = NULL; > > + igt_info("Starting GPU thread %d\n", i); > > + > > + pthread_create(&data->gpu_thread[i], NULL, gpu_load, > > + (void *)&data->gpu_context[i]); > > + > > + igt_info("GPU thread %d started\n", i); > > + } > > +} > > + > > +static void stop_gpu_threads(struct data *data) > > +{ > > + int i; > > + > > + for (i = 0; i < IGT_MAX_PIPES; i++) { > > + if (!data->highest_mode[i]) > > + continue; > > + igt_info("Stoping GPU thread %d\n", i); > > + data->gpu_thread_state[i] = STOPPED; > > + pthread_join(data->gpu_thread[i], NULL); > > + igt_info("Stopped GPU thread %d\n", i); > > + data->gpu_context[i].fb_ptr = NULL;\ > > + data->gpu_context[i].buf = NULL; > > + } > > + > > + buf_ops_destroy(data->bops); > > +} > > + > > +static void start_cpu_threads(struct data *data) > > +{ > > + int i; > > + > > + for (i = 0; i < data->number_of_cores; i++) { > > + data->cpu_context[i].buf1 = malloc(BUF_SIZE); > > + data->cpu_context[i].buf2 = malloc(BUF_SIZE); > > + data->cpu_context[i].id = i; > > + data->cpu_context[i].data = data; > > + pthread_create(&data->cpu_thread[i], NULL, cpu_load, > > + (void *)&data->cpu_context[i]); > > + } > > +} > > + > > +static void stop_cpu_threads(struct data *data) > > +{ > > + int i; > > + > > + for (i = 0; i < data->number_of_cores; i++) { > > + data->cpu_thread_stop[i] = true; > > + pthread_join(data->cpu_thread[i], NULL); > > + free(data->cpu_context[i].buf1); > > + free(data->cpu_context[i].buf2); > > + } > > +} > > + > > +static void create_framebuffers(struct data *data) > > +{ > > + int i, j; > > + uint64_t cursor_width, cursor_height; > > + > > + do_or_die(drmGetCap(data->drm_fd, DRM_CAP_CURSOR_WIDTH, &cursor_width)); > > + do_or_die(drmGetCap(data->drm_fd, DRM_CAP_CURSOR_HEIGHT, &cursor_height)); > > + > > + for (i = 0; i < IGT_MAX_PIPES; i++) { > > + if (!data->highest_mode[i]) > > + continue; > > + > > + if (!data->cursor_fb[i].fb_id) { > > + igt_create_color_fb(data->drm_fd, > > + cursor_width, cursor_height, > > + data->format, > > + data->modifier, > > + 1.0, 0.0, 0.0, > > + &data->cursor_fb[i]); > > + } > > + > > + for (j = 0; j < data->num_planes[i]; j++) { > > + if (!data->fb[i * MAX_PLANES + j].fb_id) { > > + igt_create_color_pattern_fb(data->drm_fd, > > + data->highest_mode[i]->hdisplay, > > + data->highest_mode[i]->vdisplay, > > + data->format, > > + data->modifier, > > + 0.0, 1.0, 0.0, &data->fb[i * MAX_PLANES + j]); > > + } > > + } > > + } > > +} > > + > > +static void destroy_framebuffers(struct data *data) > > +{ > > + int i, j; > > + > > + for (i = 0; i < IGT_MAX_PIPES; i++) { > > + > > + if (!data->highest_mode[i]) > > + continue; > > + > > + for (j = 0; j < MAX_PLANES; j++) { > > + if (data->fb[i * MAX_PLANES + j].fb_id) { > > + igt_plane_set_fb(&data->display.pipes[i].planes[j], NULL); > > + igt_remove_fb(data->display.drm_fd, &data->fb[i * MAX_PLANES + j]); > > + data->fb[i * MAX_PLANES + j].fb_id = 0; > > + } > > + } > > + if (data->cursor_fb[i].fb_id) { > > + igt_remove_fb(data->display.drm_fd, &data->cursor_fb[i]); > > + data->cursor_fb[i].fb_id = 0; > > + } > > + } > > +} > > + > > +static void prepare_test(struct data *data) > > +{ > > + int i, j; > > + int num_connectors; > > + int num_cpus = (int) sysconf(_SC_NPROCESSORS_ONLN); > > + > > + data->number_of_cores = min(num_cpus, MAX_CORES); > > + > > + for (i = 0; i < IGT_MAX_PIPES; i++) { > > + for (j = 0; j < MAX_PLANES; j++) > > + data->fb[i * MAX_PLANES + j].fb_id = 0; > > + data->cursor_fb[i].fb_id = 0; > > + data->num_planes[i] = -1; > > + data->last_mode[i] = NULL; > > + sem_init(&data->gpu_thread_pause_ack[i], 0, 0); > > + } > > + > > + start_cpu_threads(data); > > + data->mode_resources = drmModeGetResources(data->drm_fd); > > + if (!data->mode_resources) { > > + igt_warn("drmModeGetResources failed: %s\n", strerror(errno)); > > + return; > > + } > > + > > + num_connectors = data->mode_resources->count_connectors; > > + num_connectors = max(num_connectors, IGT_MAX_PIPES); > > + memset(data->highest_mode, 0, sizeof(drmModeModeInfo *) * IGT_MAX_PIPES); > > + data->connectors = > > + (drmModeConnectorPtr *)calloc(sizeof(drmModeConnectorPtr) * num_connectors, 1); > > + fill_connector_to_pipe_array(data, data->mode_resources, data->connectors); > > + > > + for (i = 0; i < IGT_MAX_PIPES; i++) { > > + drmModeConnector *connector = (drmModeConnector *)data->connectors[i]; > > + > > + if (!connector) > > + continue; > > + > > + if (!data->highest_mode[i]) { > > + if (connector->count_modes) > > + data->highest_mode[i] = find_highest_mode(connector); > > + } > > + igt_assert(data->highest_mode[i]); > > + > > + if (data->highest_mode[i]) { > > + igt_info("Using mode: \n"); > > + kmstest_dump_mode(data->highest_mode[i]); > > + data->pipe_crc[i] = igt_pipe_crc_new(data->drm_fd, i, > > + INTEL_PIPE_CRC_SOURCE_AUTO); > > + } else > > + data->pipe_crc[i] = NULL; > > + > > + if (data->num_planes[i] == -1) > > + data->num_planes[i] = data->display.pipes[i].n_planes; > > + > > + igt_info("Max number of planes is %d for pipe %d\n", > > + data->num_planes[i], i); > > + } > > + > > + create_framebuffers(data); > > + start_gpu_threads(data); > > +} > > + > > +static void finish_test(struct data *data) > > +{ > > + int i; > > + > > + stop_gpu_threads(data); > > + > > + /* > > + * As we change tiling/format we need a new FB > > + */ > > + destroy_framebuffers(data); > > + > > + for (i = 0; i < IGT_MAX_PIPES; i++) { > > + data->num_planes[i] = -1; > > + data->last_mode[i] = NULL; > > + if (data->pipe_crc[i]) > > + igt_pipe_crc_free(data->pipe_crc[i]); > > + } > > + > > + stop_cpu_threads(data); > > + release_connectors(data->connectors); > > + drmModeFreeResources(data->mode_resources); > > +} > > + > > +struct data data = { > > + .format = DRM_FORMAT_XRGB8888, > > + .modifier = DRM_FORMAT_MOD_LINEAR, > > + .devid = 0, > > + .bops = NULL > > +}; > > + > > + > > +igt_main { > > + uint8_t format_idx = 0, tiling_idx = 0; > > + > > + igt_fixture { > > + data.drm_fd = data.display.drm_fd = drm_open_driver_master(DRIVER_INTEL); > > + > > + kmstest_set_vt_graphics_mode(); > > + > > + igt_display_require(&data.display, data.display.drm_fd); > > + igt_require(data.display.is_atomic); > > + igt_display_require_output(&data.display); > > + data.devid = intel_get_drm_devid(data.drm_fd); > > + igt_require_gem(data.drm_fd); > > + } > > + > > + for (format_idx = 0; format_idx < N_FORMATS; format_idx++) { > > + for (tiling_idx = 0; tiling_idx < N_TILING_METHODS; tiling_idx++) { > > + if (!igt_display_has_format_mod(&data.display, > > + formats[format_idx], > > + tilings[tiling_idx])) > > + continue; > > + > > + igt_fixture { > > + data.format = formats[format_idx]; > > + data.modifier = tilings[tiling_idx]; > > + } > > Do not use fixture here, just make that normal code. > > Also please use checkpatch from Linux kernel to see if there are > other problems to fix. > > Regards, > Kamil > > > + > > + igt_describe("Start pipe stress test, utilizing cpu and gpu " > > + "simultaneously with maximum amount of planes " > > + "and resolution "); > > + igt_subtest_f("stress-%s-%s", > > + format_str(format_idx), > > + tiling_str(tiling_idx)) { > > + prepare_test(&data); > > + stress(&data); > > + finish_test(&data); > > + } > > + } > > + } > > + > > + igt_fixture { > > + igt_display_fini(&data.display); > > + } > > +} > > diff --git a/tests/meson.build b/tests/meson.build > > index b548dc3b44..8f217e401c 100644 > > --- a/tests/meson.build > > +++ b/tests/meson.build > > @@ -215,6 +215,7 @@ i915_progs = [ > > 'i915_hangman', > > 'i915_module_load', > > 'i915_pciid', > > + 'i915_pipe_stress', > > 'i915_pm_backlight', > > 'i915_pm_lpsp', > > 'i915_pm_rpm', > > -- > > 2.24.1.485.gad05a3d8e5 > >