All of lore.kernel.org
 help / color / mirror / Atom feed
From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
To: "Kahola, Mika" <mika.kahola@intel.com>,
	"intel-gfx@lists.freedesktop.org"
	<intel-gfx@lists.freedesktop.org>
Subject: Re: [PATCH i-g-t v2] tests/kms_concurrent: Concurrent and interruptible subtests for atomic
Date: Tue, 11 Apr 2017 10:18:45 +0200	[thread overview]
Message-ID: <b5e59547-654d-1081-2659-de3643fc5e8c@linux.intel.com> (raw)
In-Reply-To: <CE530282428B1C41A50D7F1CA460BA651465B11A@IRSMSX102.ger.corp.intel.com>

Op 11-04-17 om 09:42 schreef Kahola, Mika:
>
>> -----Original Message-----
>> From: Maarten Lankhorst [mailto:maarten.lankhorst@linux.intel.com]
>> Sent: Monday, April 10, 2017 3:39 PM
>> To: Kahola, Mika <mika.kahola@intel.com>; intel-gfx@lists.freedesktop.org
>> Subject: Re: [PATCH i-g-t v2] tests/kms_concurrent: Concurrent and interruptible
>> subtests for atomic
>>
>> Op 10-04-17 om 14:11 schreef Mika Kahola:
>>> On Wed, 2017-03-29 at 11:53 +0200, Maarten Lankhorst wrote:
>>>> Op 15-03-17 om 09:43 schreef Mika Kahola:
>>>>> This test case introduces concurrently running test cases for atomic
>>>>> modesetting.
>>>>>
>>>>> The first test or thread draws blue backround with black holes on
>>>>> it.
>>>>> These holes are covered by rectangular, blue planes that are placed
>>>>> randomly like in test case 'kms_plane_multiple'.
>>>>>
>>>>> The second thread changes resolution from higher to lower one and
>>>>> back.
>>>>> The delay between resolution changes is randomly selected between
>>>>> 20 and
>>>>> 50 milliseconds.
>>>>>
>>>>> The test runs by default 32 iterations to increase the coverage.
>>>>>
>>>>> v2: use igt_fork instead of pthreads to create concurrent test runs
>>>>> (Maarten)
>>>>>
>>>>> Signed-off-by: Mika Kahola <mika.kahola@intel.com>
>>>>> ---
>>>>>  tests/Makefile.sources |   1 +
>>>>>  tests/kms_concurrent.c | 630
>>>>> +++++++++++++++++++++++++++++++++++++++++++++++++
>>>>>  2 files changed, 631 insertions(+)
>>>>>  create mode 100644 tests/kms_concurrent.c
>>>>>
>>>>> <snip>
>>>>> +static int
>>>>> +display_commit_mode(data_t *data, igt_crc_t *crc) {
>>>>> +	char buf[256];
>>>>> +	struct drm_event *e = (void *)buf;
>>>>> +	int n, ret;
>>>>> +	int flags = DRM_MODE_PAGE_FLIP_EVENT |
>>>>> DRM_MODE_ATOMIC_ALLOW_MODESET |
>> DRM_MODE_ATOMIC_NONBLOCK;
>>>>> +
>>>>> +	ret = igt_display_try_commit_atomic(&data->display,
>>>>> +					    flags,
>>>>> +					    NULL);
>>>>> +	igt_skip_on(ret != 0);
>>>>> +
>>>>> +	igt_set_timeout(1, "Stuck on page flip");
>>>>> +	ret = read(data->display.drm_fd, buf, sizeof(buf));
>>>>> +	igt_assert(ret >= 0);
>>>>> +
>>>>> +	igt_assert_eq(e->type, DRM_EVENT_FLIP_COMPLETE);
>>>>> +	igt_reset_timeout();
>>>>> +
>>>>> +	return n;
>>>>> +}
>>>>> +
>>>>> +static void
>>>>> +test_grab_crc(data_t *data, color_t *color, igt_crc_t *crc /* out
>>>>> */)
>>>>> +{
>>>>> +	drmModeModeInfo *mode;
>>>>> +	igt_plane_t *primary;
>>>>> +	int ret;
>>>>> +
>>>>> +	igt_output_set_pipe(data->output, data->pipe);
>>>>> +
>>>>> +	primary = igt_output_get_plane_type(data->output,
>>>>> DRM_PLANE_TYPE_PRIMARY);
>>>>> +	data->plane[primary->index] = primary;
>>>>> +
>>>>> +	mode = igt_output_get_mode(data->output);
>>>>> +
>>>>> +	igt_create_color_fb(data->drm_fd, mode->hdisplay, mode-
>>>>>> vdisplay,
>>>>> +			    DRM_FORMAT_XRGB8888,
>>>>> +			    LOCAL_I915_FORMAT_MOD_X_TILED,
>>>>> +			    color->red, color->green, color->blue,
>>>>> +			    &data->fb[primary->index]);
>>>>> +
>>>>> +	igt_plane_set_fb(data->plane[primary->index], &data-
>>>>>> fb[primary->index]);
>>>>> +
>>>>> +	ret = igt_display_try_commit2(&data->display,
>>>>> COMMIT_ATOMIC);
>>>>> +	igt_skip_on(ret != 0);
>>>>> +}
>>>>> +
>>>>> +/*
>>>>> + * Multiple plane position test.
>>>>> + *   - We start by grabbing a reference CRC of a full blue fb
>>>>> being scanned
>>>>> + *     out on the primary plane
>>>>> + *   - Then we scannout number of planes:
>>>>> + *      * the primary plane uses a blue fb with a black rectangle
>>>>> hole
>>>>> + *      * planes, on top of the primary plane, with a blue fb that
>>>>> is set-up
>>>>> + *        to cover the black rectangles of the primary plane fb
>>>>> + *     The resulting CRC should be identical to the reference CRC
>>>>> + */
>>>>> +
>>>>> +static void
>>>>> +create_fb_for_mode_position(data_t *data, drmModeModeInfo *mode,
>>>>> +			    color_t *color, int *rect_x, int
>>>>> *rect_y,
>>>>> +			    int *rect_w, int *rect_h, uint64_t
>>>>> tiling,
>>>>> +			    int max_planes)
>>>>> +{
>>>>> +	unsigned int fb_id;
>>>>> +	cairo_t *cr;
>>>>> +	igt_plane_t *primary;
>>>>> +
>>>>> +	primary = igt_output_get_plane_type(data->output,
>>>>> DRM_PLANE_TYPE_PRIMARY);
>>>>> +
>>>>> +	fb_id = igt_create_fb(data->drm_fd,
>>>>> +			      mode->hdisplay, mode->vdisplay,
>>>>> +			      DRM_FORMAT_XRGB8888,
>>>>> +			      tiling,
>>>>> +			      &data->fb[primary->index]);
>>>>> +	igt_assert(fb_id);
>>>>> +
>>>>> +	cr = igt_get_cairo_ctx(data->drm_fd, &data->fb[primary-
>>>>>> index]);
>>>>> +	igt_paint_color(cr, rect_x[0], rect_y[0],
>>>>> +			mode->hdisplay, mode->vdisplay,
>>>>> +			color->red, color->green, color->blue);
>>>>> +
>>>>> +	for (int i = 0; i < max_planes; i++) {
>>>>> +		if (data->plane[i]->type ==
>>>>> DRM_PLANE_TYPE_PRIMARY)
>>>>> +			continue;
>>>>> +		igt_paint_color(cr, rect_x[i], rect_y[i],
>>>>> +				rect_w[i], rect_h[i], 0.0, 0.0,
>>>>> 0.0);
>>>>> +	}
>>>>> +
>>>>> +	igt_assert(cairo_status(cr) == 0);
>>>>> +	cairo_destroy(cr);
>>>>> +}
>>>>> +
>>>>> +static void
>>>>> +prepare_planes(data_t *data, color_t *color, int max_planes) {
>>>>> +	drmModeModeInfo *mode;
>>>>> +	igt_pipe_t *pipe;
>>>>> +	igt_plane_t *primary;
>>>>> +	int *x;
>>>>> +	int *y;
>>>>> +	int *size;
>>>>> +	int i;
>>>>> +
>>>>> +	igt_output_set_pipe(data->output, data->pipe);
>>>>> +	primary = igt_output_get_plane_type(data->output,
>>>>> DRM_PLANE_TYPE_PRIMARY);
>>>>> +	pipe = primary->pipe;
>>>>> +
>>>>> +	x = malloc(pipe->n_planes * sizeof(*x));
>>>>> +	igt_assert_f(x, "Failed to allocate %ld bytes for variable
>>>>> x\n", (long int) (pipe->n_planes * sizeof(*x)));
>>>>> +	y = malloc(pipe->n_planes * sizeof(*y));
>>>>> +	igt_assert_f(y, "Failed to allocate %ld bytes for variable
>>>>> y\n", (long int) (pipe->n_planes * sizeof(*y)));
>>>>> +	size = malloc(pipe->n_planes * sizeof(*size));
>>>>> +	igt_assert_f(size, "Failed to allocate %ld bytes for
>>>>> variable size\n", (long int) (pipe->n_planes * sizeof(*size)));
>>>>> +
>>>>> +	mode = igt_output_get_mode(data->output);
>>>>> +
>>>>> +	/* planes with random positions */
>>>>> +	x[primary->index] = 0;
>>>>> +	y[primary->index] = 0;
>>>>> +	for (i = 0; i < max_planes; i++) {
>>>>> +		igt_plane_t *plane = igt_output_get_plane(data-
>>>>>> output, i);
>>>>> +
>>>>> +		if (plane->type == DRM_PLANE_TYPE_PRIMARY)
>>>>> +			continue;
>>>>> +		else if (plane->type == DRM_PLANE_TYPE_CURSOR)
>>>>> +			size[i] = SIZE_CURSOR;
>>>>> +		else
>>>>> +			size[i] = SIZE_PLANE;
>>>>> +
>>>>> +		x[i] = rand() % (mode->hdisplay - size[i]);
>>>>> +		y[i] = rand() % (mode->vdisplay - size[i]);
>>>>> +
>>>>> +		data->plane[i] = plane;
>>>>> +
>>>>> +		igt_create_color_fb(data->drm_fd,
>>>>> +				    size[i], size[i],
>>>>> +				    data->plane[i]->type ==
>>>>> DRM_PLANE_TYPE_CURSOR ? DRM_FORMAT_ARGB8888 :
>> DRM_FORMAT_XRGB8888,
>>>>> +				    data->plane[i]->type ==
>>>>> DRM_PLANE_TYPE_CURSOR ? LOCAL_DRM_FORMAT_MOD_NONE :
>>>>> LOCAL_I915_FORMAT_MOD_X_TILED,
>>>>> +				    color->red, color->green,
>>>>> color->blue,
>>>>> +				    &data->fb[i]);
>>>>> +
>>>>> +		igt_plane_set_position(data->plane[i], x[i],
>>>>> y[i]);
>>>>> +		igt_plane_set_fb(data->plane[i], &data->fb[i]);
>>>>> +	}
>>>>> +
>>>>> +	/* primary plane */
>>>>> +	data->plane[primary->index] = primary;
>>>>> +	create_fb_for_mode_position(data, mode, color, x, y, size,
>>>>> size,
>>>>> +				    LOCAL_I915_FORMAT_MOD_X_TILED,
>>>>> max_planes);
>>>>> +	igt_plane_set_fb(data->plane[primary->index], &data-
>>>>>> fb[primary->index]);
>>>>> +}
>>>>> +
>>>>> +static void
>>>>> +test_plane_position_with_output(data_t *data) {
>>>>> +	igt_crc_t *crc;
>>>>> +	color_t blue  = { 0.0f, 0.0f, 1.0f };
>>>>> +	int i;
>>>>> +	int iterations = opt.iterations < 1 ? 1 : opt.iterations;
>>>>> +	bool loop_forever;
>>>>> +	char info[256];
>>>>> +	int max_planes = data->display.pipes[data->pipe].n_planes;
>>>>> +
>>>>> +	if (opt.iterations == LOOP_FOREVER) {
>>>>> +		loop_forever = true;
>>>>> +		sprintf(info, "forever");
>>>>> +	} else {
>>>>> +		loop_forever = false;
>>>>> +		sprintf(info, "for %d %s",
>>>>> +			iterations, iterations > 1 ? "iterations"
>>>>> : "iteration");
>>>>> +	}
>>>>> +
>>>>> +	igt_info("Testing connector %s using pipe %s with %d
>>>>> planes %s with seed %d\n",
>>>>> +		 igt_output_name(data->output),
>>>>> kmstest_pipe_name(data->pipe), max_planes,
>>>>> +		 info, opt.seed);
>>>>> +
>>>>> +	i = 0;
>>>>> +	while (i < iterations || loop_forever) {
>>>>> +		prepare_planes(data, &blue, max_planes);
>>>>> +
>>>>> +		display_commit_mode(data, crc);
>>>>> +
>>>>> +		i++;
>>>>> +	}
>>>>> +}
>>>>> +
>>>>> +static drmModeConnector *
>>>>> +get_connector_connected(int drm_fd) {
>>>>> +	drmModeRes *resources = drmModeGetResources(drm_fd);
>>>>> +	drmModeConnector *connector;
>>>>> +	int i;
>>>>> +
>>>>> +	for (i = 0; i < resources->count_connectors; i++) {
>>>>> +		connector = drmModeGetConnector(drm_fd,
>>>>> +						resources-
>>>>>> connectors[i]);
>>>>> +
>>>>> +		if (connector->connection == DRM_MODE_CONNECTED)
>>>>> +			break;
>>>>> +
>>>>> +		drmModeFreeConnector(connector);
>>>>> +		connector = NULL;
>>>>> +	}
>>>>> +
>>>>> +	drmModeFreeResources(resources);
>>>>> +
>>>>> +	return connector;
>>>>> +}
>>>>> +
>>>>> +static int get_crtc_for_encoder(drmModeRes *resources,
>>>>> +				drmModeEncoder *encoder)
>>>>> +{
>>>>> +	int mask, id;
>>>>> +	int i;
>>>>> +	bool found;
>>>>> +
>>>>> +	for (i = 0; i < resources->count_crtcs; i++) {
>>>>> +		mask = 1 << i;
>>>>> +		id = resources->crtcs[i];
>>>>> +
>>>>> +		found = encoder->possible_crtcs & mask;
>>>>> +		if (found)
>>>>> +			break;
>>>>> +	}
>>>>> +
>>>>> +	if (!found)
>>>>> +		return -EINVAL;
>>>>> +
>>>>> +	return id;
>>>>> +}
>>>>> +
>>>>> +static int get_crtc_for_connector(int drm_fd, drmModeRes
>>>>> *resources,
>>>>> +				  drmModeConnector *connector)
>>>>> +{
>>>>> +	drmModeEncoder *encoder;
>>>>> +	int encoder_id;
>>>>> +	int crtc_id;
>>>>> +	int i;
>>>>> +
>>>>> +	for (i = 0; i < connector->count_encoders; i++) {
>>>>> +		encoder_id = connector->encoders[i];
>>>>> +		encoder = drmModeGetEncoder(drm_fd, encoder_id);
>>>>> +
>>>>> +		if (encoder) {
>>>>> +			crtc_id = get_crtc_for_encoder(resources,
>>>>> encoder);
>>>>> +
>>>>> +			drmModeFreeEncoder(encoder);
>>>>> +
>>>>> +			if (crtc_id != 0)
>>>>> +				break;
>>>>> +		}
>>>>> +	}
>>>>> +
>>>>> +	if (crtc_id == 0)
>>>>> +		return -EINVAL;
>>>>> +
>>>>> +	return crtc_id;
>>>>> +}
>>>>> +
>>>>> +static int get_crtc(int drm_fd)
>>>>> +{
>>>>> +	drmModeRes *resources;
>>>>> +	drmModeConnector *connector;
>>>>> +	drmModeEncoder *encoder;
>>>>> +	int i, id;
>>>>> +
>>>>> +	resources = drmModeGetResources(drm_fd);
>>>>> +	connector = get_connector_connected(drm_fd);
>>>>> +
>>>>> +	for (i = 0; i < resources->count_encoders; i++) {
>>>>> +		encoder = drmModeGetEncoder(drm_fd, resources-
>>>>>> encoders[i]);
>>>>> +
>>>>> +		if (encoder->encoder_id == connector->encoder_id)
>>>>> +			break;
>>>>> +
>>>>> +		drmModeFreeEncoder(encoder);
>>>>> +		encoder = NULL;
>>>>> +	}
>>>>> +
>>>>> +	if (encoder)
>>>>> +		return encoder->crtc_id;
>>>>> +
>>>>> +	id = get_crtc_for_connector(drm_fd, resources, connector);
>>>>> +	igt_assert(id != 0);
>>>>> +
>>>>> +	return id;
>>>>> +}
>>>>> +
>>>>> +static drmModeModeInfo *
>>>>> +get_lowres_mode(data_t *data, drmModeModeInfo *mode_default) {
>>>>> +	drmModeRes *resources = drmModeGetResources(data->drm_fd);
>>>>> +	drmModeModeInfo std_1024_mode = {
>>>>> +		.clock = 65000,
>>>>> +		.hdisplay = 1024,
>>>>> +		.hsync_start = 1048,
>>>>> +		.hsync_end = 1184,
>>>>> +		.htotal = 1344,
>>>>> +		.hskew = 0,
>>>>> +		.vdisplay = 768,
>>>>> +		.vsync_start = 771,
>>>>> +		.vsync_end = 777,
>>>>> +		.vtotal = 806,
>>>>> +		.vscan = 0,
>>>>> +		.vrefresh = 60,
>>>>> +		.flags = 0xA,
>>>>> +		.type = 0x40,
>>>>> +		.name = "Custom 1024x768",
>>>>> +	};
>>>>> +	drmModeModeInfo *mode;
>>>>> +	drmModeConnector *connector;
>>>>> +	bool found;
>>>>> +	int limit = mode_default->vdisplay-SIZE_PLANE;
>>>>> +	int i, j;
>>>>> +
>>>>> +	if (!resources) {
>>>>> +		igt_warn("drmModeGetResources failed: %s\n",
>>>>> strerror(errno));
>>>>> +		return mode;
>>>>> +	}
>>>>> +
>>>>> +	found = false;
>>>>> +	for (i = 0; i < resources->count_connectors; i++) {
>>>>> +
>>>>> +		connector = drmModeGetConnectorCurrent(data-
>>>>>> drm_fd,
>>>>> +						       resources-
>>>>>> connectors[i]);
>>>>> +
>>>>> +		if (!connector) {
>>>>> +			igt_warn("could not get connector %i:
>>>>> %s\n",
>>>>> +				 resources->connectors[i],
>>>>> strerror(errno));
>>>>> +			continue;
>>>>> +		}
>>>>> +
>>>>> +		if (!connector->count_modes)
>>>>> +			continue;
>>>>> +
>>>>> +		for (j = 0; j < connector->count_modes; j++) {
>>>>> +			mode = &connector->modes[j];
>>>>> +
>>>>> +			if (mode->vdisplay < limit) {
>>>>> +				found = true;
>>>>> +				break;
>>>>> +			}
>>>>> +		}
>>>>> +
>>>>> +		drmModeFreeConnector(connector);
>>>>> +	}
>>>>> +
>>>>> +	drmModeFreeResources(resources);
>>>>> +
>>>>> +	if (!found)
>>>>> +		mode = &std_1024_mode;
>>>>> +
>>>>> +	return mode;
>>>>> +}
>>>> Still not completely happy about this part.
>>>>
>>>> I would look at data->output->config.connector for modes, and return
>>>> 1024 mode if nothing's found.
>>>>
>>>> Saves a whole lot of drm calls.
>>> True. A lot of lines can be cleaned out.
>>>>> +static void
>>>>> +test_resolution_with_output(data_t *data) {
>>>>> +	drmModeModeInfo *mode_hi, *mode_lo;
>>>>> +	int ret;
>>>>> +	int iterations = opt.iterations < 1 ? 1 : opt.iterations;
>>>>> +	bool loop_forever;
>>>>> +	int i;
>>>>> +
>>>>> +	if (opt.iterations == LOOP_FOREVER)
>>>>> +		loop_forever = true;
>>>>> +	else
>>>>> +		loop_forever = false;
>>>>> +
>>>>> +	igt_info("Testing resolution with connector %s using pipe
>>>>> %s with seed %d\n",
>>>>> +		 igt_output_name(data->output),
>>>>> kmstest_pipe_name(data->pipe), opt.seed);
>>>>> +
>>>>> +	mode_hi = igt_output_get_mode(data->output);
>>>>> +	mode_lo = get_lowres_mode(data, mode_hi);
>>>>> +
>>>>> +	i = 0;
>>>>> +	while (i < iterations || loop_forever) {
>>>>> +		/* switch to lower resolution */
>>>>> +		ret = drmModeSetCrtc(data->drm_fd, data->crtc_id,
>>>>> data->fb->fb_id, 0, 0,
>>>>> +				     &data->connector_id, 1,
>>>>> mode_lo);
>>>>> +		igt_assert_eq(ret, 0);
>>>>> +
>>>>> +		/* switch back to higher resolution */
>>>>> +		ret = drmModeSetCrtc(data->drm_fd, data->crtc_id,
>>>>> data->fb->fb_id, 0, 0,
>>>>> +				     &data->connector_id, 1,
>>>>> mode_hi);
>>>>> +		igt_assert_eq(ret, 0);
>>>>> +
>>>>> +		i++;
>>>>> +	}
>>>>> +}
>>>> Use igt_output_override_mode + igt_display calls? With the thread
>>>> being a fork now, you can use igt_display. :)
>>> For some reason I keep receiving an error when using
>>> igt_output_override_mode + igt_display calls. The error is
>>>
>>> igt-kms-CRITICAL: Failed assertion:
>>> drmModeDestroyPropertyBlob(display-
>>>> drm_fd, *blob) == 0
>>> igt-kms-CRITICAL: Last errno: 1, Operation not permitted
>>>
>>> Maybe both threads try to access this and this request is not granted?
>>> With drmModeSetCrtc() call I don't see this behavior. Maybe stick with
>>> raw calls instead?
>> data->display.pipes[pipe].mode_blob = 0; in one of the forks of the test should
>> fix it.
> This seems to fix the issue. I'll throw a revised patch of the test shortly.
>
>> -EPERM means that the blob was already destroyed by this fd, but still used
>> globally.
>>
>> kms_rmfb does similar, maybe we should ignore failures?
> Maybe we could ignore these failures. Any harm done elsewhere if we do so?

I'm hesitant to ignore them, for the same reason as calling free() twice is a bad idea, we may end up freeing a different unknown blob.

~Maarten

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

      reply	other threads:[~2017-04-11  8:18 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-03-15  8:43 [PATCH i-g-t v2] tests/kms_concurrent: Concurrent and interruptible subtests for atomic Mika Kahola
2017-03-29  9:53 ` Maarten Lankhorst
2017-04-10 12:11   ` Mika Kahola
2017-04-10 12:39     ` Maarten Lankhorst
2017-04-11  7:42       ` Kahola, Mika
2017-04-11  8:18         ` Maarten Lankhorst [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=b5e59547-654d-1081-2659-de3643fc5e8c@linux.intel.com \
    --to=maarten.lankhorst@linux.intel.com \
    --cc=intel-gfx@lists.freedesktop.org \
    --cc=mika.kahola@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.