On Fri, Sep 23, 2016 at 06:10:29PM +0530, Nautiyal Ankit wrote: > From: Ramalingam C <ramalingam.c@xxxxxxxxx> > > Idleness DRRS: > By default the DRRS state will be at DRRS_HIGH_RR. When a Display > content is Idle for more than 1Sec Idleness will be declared and > DRRS_LOW_RR will be invoked, changing the refresh rate to the > lower most refresh rate supported by the panel. As soon as there > is a display content change there will be a DRRS state transition > as DRRS_LOW_RR--> DRRS_HIGH_RR, changing the refresh rate to the > highest refresh rate supported by the panel. > > To test this, Idleness DRRS IGT will probe the DRRS state at below > instances and compare with the expected state. > > Instance Expected State > 1. Immediately after rendering the still image DRRS_HIGH_RR > 2. After a delay of 1.2Sec DRRS_LOW_RR > 3. After changing the frame buffer DRRS_HIGH_RR > 4. After a delay of 1.2Sec DRRS_LOW_RR > 5. After changing the frame buffer DRRS_HIGH_RR > 6. After a delay of 1.2Sec DRRS_LOW_RR > > The test checks the driver DRRS state from the debugfs entry. To check the > actual refresh-rate, a separate thread counts the number of vblanks > received per sec. The refresh-rate calculated is checked against the > expected refresh-rate with a tolerance value of 2. > > This patch is a continuation of the earlier work > https://patchwork.freedesktop.org/patch/45472/ towards igt for idleness > > DRRS. The code is tested on Broxton BXT_T platform. > > v2: Addressed the comments and suggestions from Vlad, Marius. > The signoff details from the earlier work are also included. > > Signed-off-by: Ramalingam C <ramalingam.c@xxxxxxxxx> > Signed-off-by: Vandana Kannan <vandana.kannan@xxxxxxxxx> > Signed-off-by: aknautiy <ankit.k.nautiyal@xxxxxxxxx> > --- > tests/Makefile.sources | 1 + > tests/kms_drrs.c | 612 +++++++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 613 insertions(+) > create mode 100644 tests/kms_drrs.c > > diff --git a/tests/Makefile.sources b/tests/Makefile.sources > index a837977..5f31521 100644 > --- a/tests/Makefile.sources > +++ b/tests/Makefile.sources > @@ -91,6 +91,7 @@ TESTS_progs_M = \ > kms_cursor_crc \ > kms_cursor_legacy \ > kms_draw_crc \ > + kms_drrs \ > kms_fbc_crc \ > kms_fbcon_fbt \ > kms_flip \ > diff --git a/tests/kms_drrs.c b/tests/kms_drrs.c > new file mode 100644 > index 0000000..69f8b06 > --- /dev/null > +++ b/tests/kms_drrs.c > @@ -0,0 +1,612 @@ > +/* > + * Copyright © 2016 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. > + * > + */ > + > +#include "drmtest.h" > +#include "igt_debugfs.h" > +#include "igt_kms.h" > +#include "intel_chipset.h" > +#include "intel_batchbuffer.h" > +#include "ioctl_wrappers.h" > +#include <time.h> > +#include <pthread.h> > +#include <stdlib.h> > +#include <sys/time.h> > +IGT_TEST_DESCRIPTION( > +"Performs write operations and then waits for DRRS to invoke the" > +"Low Refresh Rate and then disturbs the contents of the screen once" > +"again hence DRRS revert back to High Refresh Rate(Default)."); > + > +#define DRRS_STATUS_BYTES_CNT 1000 > +#define SET 1 > +#define RESET 0 > + > +/* > + * Structure to store data to create 2 framebuffers, fb[0] and fb[1] on a given > + * display. To disturb the content of the screen, we replace fb[0] by fb[1] and > + * vice versa. > + */ > +typedef struct { > + int drm_fd; > + uint32_t devid; > + uint32_t handle[2]; > + igt_display_t display; > + igt_output_t *output; > + enum pipe pipe; > + igt_plane_t *primary; > + struct igt_fb fb[2]; > + uint32_t fb_id[2]; > +} data_t; > + > +/* > + * Structure to count vblank and note the starting time of the counter > + */ > +typedef struct { > + unsigned int vbl_count; > + struct timeval start; > +} vbl_info; > + > +/* > + * Condition variables,mutex, and shared variables for thread synchronization > + */ > +pthread_mutex_t rr_mutex; > +pthread_cond_t cv_rr_calc_requested; > +pthread_cond_t cv_rr_calc_completed; > +int rr_calc_requested = RESET; > +int rr_calc_completed = RESET; > +int thread_flag = SET; > +int refresh_rate_shared = -1; > + > +/* > + * Structure for refresh rate type > + */ > +typedef struct{ > + int rate; > + const char *name; > +} refresh_rate_t; > + > +/* > + * vblank_handler : > + * User defined vblank event handler, to count vblanks. > + * The control reaches this function after a vblank event is registered > + */ > +static void vblank_handler(int fd, unsigned int frame, > + unsigned int sec, unsigned int usec, void *data) > +{ > + /* The control reaches this function after a vblank event is > + * registered > + */ > + vbl_info *info = (vbl_info *) data; > + > + if (info == NULL) { > + igt_info("ERROR: Invalid Data passed to the vblank handler\n"); > + return; > + } > + info->vbl_count++; > +} > + > + > +/* > + * read_drrs_status : > + * Func to read the DRRS status from debugfs > + */ > +static bool read_drrs_status(char *str) > +{ > + FILE *status; > + int cnt; > + > + status = igt_debugfs_fopen("i915_drrs_status", "r"); > + igt_assert(status); > + > + cnt = fread(str, DRRS_STATUS_BYTES_CNT - 1, 1, status); > + if (!cnt) { > + if (!feof(status)) { > + igt_info("ERROR: %d at fread\n", ferror(status)); > + return false; > + } > + clearerr(status); > + } > + fclose(status); > + return true; > +} > + > +/* > + * is_drrs_supported : > + * Func to check for DRRS support > + */ > +static bool is_drrs_supported(void) > +{ > + char str[DRRS_STATUS_BYTES_CNT] = {}; > + > + if (!read_drrs_status(str)) { > + igt_info("ERROR: Debugfs read FAILED\n"); > + return false; > + } > + return strstr(str, "DRRS Supported: Yes") != NULL; > +} > + > +/* > + * is_drrs_enabled : > + * Func to check if DRRS is enabled by driver > + */ > +static bool is_drrs_enabled(void) > +{ > + char str[DRRS_STATUS_BYTES_CNT] = {}; > + > + if (!read_drrs_status(str)) { > + igt_info("ERROR: Debugfs read FAILED\n"); > + return false; > + } > + return strstr(str, "Idleness DRRS: Disabled") == NULL; > +} > + > +/* > + * prepare_crtc : > + * Func to prepare crtc for the given display > + */ > +static bool prepare_crtc(data_t *data) > +{ > + if (data == NULL) > + return false; > + igt_display_t *display = &data->display; > + igt_output_t *output = data->output; > + > + /* select the pipe we want to use */ > + igt_output_set_pipe(output, data->pipe); > + igt_display_commit(display); > + > + if (!output->valid) { > + igt_output_set_pipe(output, PIPE_ANY); > + igt_display_commit(display); > + return false; > + } > + > + return true; > +} > + > +/* > + * calculate_refresh_rate : > + * Func to calculate the refresh rate by counting > + * vblanks in 1 sec. It returns the calculated refresh rate on success. > + * Returns -1 in case of error. > + */ > +int calculate_refresh_rate(data_t *data) > +{ > + drmEventContext evctx; > + drmVBlank vbl; > + vbl_info handler_info; > + struct timeval start_time, curr_time; > + double time_elapsed; > + int refresh_rate = 0, vbl_count = 0; > + /*set up event context for handling vblank events*/ > + memset(&evctx, 0, sizeof(evctx)); > + evctx.version = DRM_EVENT_CONTEXT_VERSION; > + evctx.vblank_handler = vblank_handler; > + evctx.page_flip_handler = NULL; > + > + /*initialize the vbl count to zero and set the starting time*/ > + handler_info.vbl_count = 0; > + gettimeofday(&start_time, NULL); > + handler_info.start = start_time; > + curr_time = start_time; > + > + time_elapsed = 0.0; > + /* To count vblanks in 1 sec. Loop till > + * (current-time - starting time) <= 1.0 sec > + */ > + while (time_elapsed <= 1.0) { > + int ret; > + > + vbl.request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT; > + vbl.request.sequence = 1; > + vbl.request.signal = (unsigned long)&handler_info; > + ret = drmWaitVBlank(data->drm_fd, &vbl); > + if (ret != 0) { > + igt_info("ERROR : drmWaitVBlank FAILED :%d\n", ret); > + return -1; > + } > + /*call drmHandleEvent() to handle vblank event */ > + ret = drmHandleEvent(data->drm_fd, &evctx); Looks quite complicated. What you want is just static double vbl_rate(const union drm_wait_vblank *start, const union drm_wait_vblank *end) { double s, e; s = start->reply.tval_sec + 1e-6*start->reply.tval_usec; e = end->reply.tval_sec + 1e-6*end->reply.tval_usec; return (end->reply.sequence - start->reply.sequnce) / (e - s); } static int calculate_refresh_rate(int fd, int pipe, int period_ms) { union drm_wait_vblank start, end; struct timeval tv; memset(&start, 0, sizeof(start)); start.request.type = DRM_VBLANK_RELATIVE | pipe_select(pipe); igt_assert(drmWaitVblank(fb, &start) == 0); while (igt_milliseconds_elapsed(&tv) < period_ms) { memset(&end, 0, sizeof(end)); end.request.type = DRM_VBLANK_RELATIVE | pipe_select(pipe); end.sequence = 1; igt_assert(drmWaitVblank(fb, &end) == 0); } return vbl_rate(&start, &end); } right? Call that igt_pipe_measure_vrefresh(int fd, enum pipe pipe, int min_period_ms); or igt_crtc_measure_vrefresh(with igt_pipe_t instead of enum pipe). and be done. > + if (ret != 0) { > + igt_info("ERROR : drmHandleEvent FAILED %d\n", ret); > + return -1; > + } > + > + gettimeofday(&curr_time, NULL); > + time_elapsed = curr_time.tv_sec + curr_time.tv_usec * 1e-6 - > + (start_time.tv_sec + start_time.tv_usec * 1e-6); > + } > + if (!time_elapsed) { > + igt_info("ERROR: Incorrect measurement of vblank duration\n"); > + return -1; > + } > + vbl_count = handler_info.vbl_count; > + /* calculate the refresh rate; rr=vblank_count/time_taken */ > + refresh_rate = vbl_count / time_elapsed; > + return refresh_rate; > +} > + > +/* > + * worker_thread_func : > + * Func which is run by a worker thread to calculate the refresh_rate, > + * when signalled by the master thread. > + */ > +void *worker_thread_func(void *ptr) > +{ > + data_t *data = (data_t *) ptr; > + > + while (1) { > + int refresh_rate = 0; > + /*wait for signal from master*/ > + pthread_mutex_lock(&rr_mutex); > + while (!rr_calc_requested) > + pthread_cond_wait(&cv_rr_calc_requested, &rr_mutex); > + > + /* checkpoint for thread termination */ > + if (thread_flag == RESET) { > + pthread_mutex_unlock(&rr_mutex); > + pthread_exit(NULL); > + } > + rr_calc_requested = RESET; > + pthread_mutex_unlock(&rr_mutex); > + /*calculate refresh_rate*/ > + refresh_rate = calculate_refresh_rate(data); > + > + /* signal the master */ > + pthread_mutex_lock(&rr_mutex); > + refresh_rate_shared = refresh_rate; > + rr_calc_completed = SET; > + pthread_mutex_unlock(&rr_mutex); > + pthread_cond_signal(&cv_rr_calc_completed); > + } > + return NULL; > +} You are calculating the refresh rate synchronously, so what's the point of the thread? You are serialising on this thread > +static int execute_test(data_t *data) > +{ Split up this monolith into separate subtests and groups thereof. -Chris -- Chris Wilson, Intel Open Source Technology Centre _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx