[igt-dev] [PATCH i-g-t] tests/amdgpu: Add test for Adaptive Backlight Management
Wentland, Harry
Harry.Wentland at amd.com
Thu Nov 29 20:45:30 UTC 2018
On 2018-11-28 3:51 p.m., David Francis wrote:
> Adaptive Backlight Management (ABM) is a power-saving
> feature on AMD ASICs that reduces backlight while increasing
> pixel contrast and luminance. This test confirms that
> ABM is present and enabled, and that backlight performance
> is sane. It uses AMD-specific debugfs entries to
> read the backlight PWM values.
>
> It has 5 subtests:
>
> dpms_cycle
> Sets brightness to half, then confirms that value is restored
> after dpms off and then on.
>
> backlight_monotonic_basic
> Sets brightness to ten different values, confirming that
> higher brightness values are brighter.
>
> backlight_monotonic_abm
> Same as backlight_monotonic_basic, but with abm enabled.
>
> abm_enabled
> Sets abm to its four intensity levels, confirming that
> abm reduces the backlight, and the reduction is greater
> for higher abm level.
>
> abm_gradual
> Sets abm to off and then maximum intensity, confirming
> that brightness decreases continually over the first
> second and eventually reaches the target value.
> This test takes 30s to run.
>
> Signed-off-by: David Francis <David.Francis at amd.com>
> ---
> tests/Makefile.sources | 1 +
> tests/amdgpu/amd_abm.c | 361 +++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 362 insertions(+)
> create mode 100644 tests/amdgpu/amd_abm.c
>
> diff --git a/tests/Makefile.sources b/tests/Makefile.sources
> index 5620c1d6..3d560bee 100644
> --- a/tests/Makefile.sources
> +++ b/tests/Makefile.sources
> @@ -19,6 +19,7 @@ AMDGPU_TESTS = \
> amdgpu/amd_basic \
> amdgpu/amd_cs_nop \
> amdgpu/amd_prime \
> + amdgpu/amd_abm \
> $(NULL)
>
> TESTS_progs = \
> diff --git a/tests/amdgpu/amd_abm.c b/tests/amdgpu/amd_abm.c
> new file mode 100644
> index 00000000..90a6f99e
> --- /dev/null
> +++ b/tests/amdgpu/amd_abm.c
> @@ -0,0 +1,361 @@
> +/*
> + * Copyright 2018 Advanced Micro Devices, Inc.
> + *
> + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 "igt.h"
> +#include "drmtest.h"
> +#include "igt_kms.h"
> +#include <limits.h>
> +#include <errno.h>
> +#include <stdbool.h>
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <string.h>
> +#include <fcntl.h>
> +#include <time.h>
> +
> +#define BACKLIGHT_PATH "/sys/class/backlight/amdgpu_bl0"
> +
> +static int read_current_backlight_pwm(int debugfs_dir)
> +{
> + char buf[20];
> +
> + igt_debugfs_simple_read(debugfs_dir, "amdgpu_current_backlight_pwm",
> + buf, sizeof(buf));
> +
> + return strtol(buf, NULL, 0);
> +}
> +
> +static int read_target_backlight_pwm(int debugfs_dir)
> +{
> + char buf[20];
> +
> + igt_debugfs_simple_read(debugfs_dir, "amdgpu_target_backlight_pwm",
> + buf, sizeof(buf));
> +
> + return strtol(buf, NULL, 0);
> +}
> +
> +static int backlight_write_brightness(int value)
> +{
> + int fd;
> + char full[PATH_MAX];
> + char src[64];
> + int len;
> +
> + igt_assert(snprintf(full, PATH_MAX, "%s/%s", BACKLIGHT_PATH, "brightness") < PATH_MAX);
> + fd = open(full, O_WRONLY);
> + if (fd == -1)
> + return -errno;
> +
> + len = snprintf(src, sizeof(src), "%i", value);
> + len = write(fd, src, len);
> + close(fd);
> +
> + if (len < 0)
> + return len;
> +
> + return 0;
> +}
> +
> +static void set_abm_level(igt_display_t *display, int level)
> +{
> + int i, ret;
> + int output_id;
> + drmModeObjectPropertiesPtr props;
> + uint32_t prop_id;
> + drmModePropertyPtr prop;
> + uint32_t type = DRM_MODE_OBJECT_CONNECTOR;
> +
> + for (i = 0; i < display->n_outputs; i++) {
> + output_id = display->outputs[i].id;
> + props = drmModeObjectGetProperties(display->drm_fd, output_id, type);
> +
> + for (i = 0; i < props->count_props; i++) {
> + prop_id = props->props[i];
> + prop = drmModeGetProperty(display->drm_fd, prop_id);
> +
> + igt_assert(prop);
> +
> + if (strcmp(prop->name, "abm level") == 0) {
> + ret = drmModeObjectSetProperty(display->drm_fd, output_id, type, prop_id, level);
> +
> + igt_assert_eq(ret, 0);
> + }
> +
> + drmModeFreeProperty(prop);
> + }
> + }
> +
> +}
> +
> +static int backlight_read_max_brightness(int *result)
> +{
> + int fd;
> + char full[PATH_MAX];
> + char dst[64];
> + int r, e;
> +
> + igt_assert(snprintf(full, PATH_MAX, "%s/%s", BACKLIGHT_PATH, "max_brightness") < PATH_MAX);
> +
> + fd = open(full, O_RDONLY);
> + if (fd == -1)
> + return -errno;
> +
> + r = read(fd, dst, sizeof(dst));
> + e = errno;
> + close(fd);
> +
> + if (r < 0)
> + return -e;
> +
> + errno = 0;
> + *result = strtol(dst, NULL, 10);
> + return errno;
> +}
> +
> +static void skip_if_incompatible(igt_display_t *display, int debugfs_dir)
> +{
> + int ret, i;
> + char buf[20];
> + bool abm_prop_exists;
> + int output_id;
> + drmModeObjectPropertiesPtr props;
> + uint32_t type = DRM_MODE_OBJECT_CONNECTOR;
> + uint32_t prop_id;
> + drmModePropertyPtr prop;
> +
> + ret = igt_debugfs_simple_read(debugfs_dir, "amdgpu_current_backlight_pwm",
> + buf, sizeof(buf));
> +
> + if (ret < 0)
> + igt_skip("No current backlight debugfs entry.\n");
> +
> + ret = igt_debugfs_simple_read(debugfs_dir, "amdgpu_target_backlight_pwm",
> + buf, sizeof(buf));
> +
> + if (ret < 0)
> + igt_skip("No target backlight debugfs entry.\n");
> +
> + abm_prop_exists = false;
> +
> + for (i = 0; i < display->n_outputs; i++) {
> + output_id = display->outputs[i].id;
> + props = drmModeObjectGetProperties(display->drm_fd, output_id, type);
> +
> + for (i = 0; i < props->count_props; i++) {
> + prop_id = props->props[i];
> + prop = drmModeGetProperty(display->drm_fd, prop_id);
> +
> + if (strcmp(prop->name, "abm level") == 0)
> + abm_prop_exists = true;
> +
> + drmModeFreeProperty(prop);
> + }
> + }
> +
> + if (!abm_prop_exists)
> + igt_skip("No abm level property on any connector.\n");
> +}
> +
> +
> +static void backlight_dpms_cycle(igt_display_t *display, int debugfs, igt_output_t *output)
> +{
> + int ret;
> + int max_brightness;
> + int pwm_1, pwm_2;
> +
> + ret = backlight_read_max_brightness(&max_brightness);
> + igt_assert_eq(ret, 0);
> +
> + set_abm_level(display, 0);
> + backlight_write_brightness(max_brightness / 2);
> + usleep(100000);
> + pwm_1 = read_target_backlight_pwm(debugfs);
> +
> + kmstest_set_connector_dpms(display->drm_fd, output->config.connector, DRM_MODE_DPMS_OFF);
> + kmstest_set_connector_dpms(display->drm_fd, output->config.connector, DRM_MODE_DPMS_ON);
> + usleep(100000);
> + pwm_2 = read_target_backlight_pwm(debugfs);
> + igt_assert_eq(pwm_1, pwm_2);
> +}
> +
> +static void backlight_monotonic_basic(igt_display_t *display, int debugfs)
> +{
> + int ret;
> + int max_brightness;
> + int prev_pwm, pwm;
> + int brightness_step;
> + int brightness;
> +
> + ret = backlight_read_max_brightness(&max_brightness);
> + igt_assert_eq(ret, 0);
> +
> + brightness_step = max_brightness / 10;
> +
> + set_abm_level(display, 0);
> + backlight_write_brightness(max_brightness);
> + usleep(100000);
> + prev_pwm = read_target_backlight_pwm(debugfs);
> + for (brightness = max_brightness - brightness_step;
> + brightness > 0;
> + brightness -= brightness_step) {
> + backlight_write_brightness(brightness);
> + usleep(100000);
> + pwm = read_target_backlight_pwm(debugfs);
> + igt_assert(pwm < prev_pwm);
> + prev_pwm = pwm;
> + }
> +
> +}
> +
> +static void backlight_monotonic_abm(igt_display_t *display, int debugfs)
> +{
> + int ret, i;
> + int max_brightness;
> + int prev_pwm, pwm;
> + int brightness_step;
> + int brightness;
> +
> + ret = backlight_read_max_brightness(&max_brightness);
> + igt_assert_eq(ret, 0);
> +
> + brightness_step = max_brightness / 10;
> + for (i = 1; i < 5; i++) {
> + set_abm_level(display, i);
> + backlight_write_brightness(max_brightness);
> + usleep(100000);
> + prev_pwm = read_target_backlight_pwm(debugfs);
> + for (brightness = max_brightness - brightness_step;
> + brightness > 0;
> + brightness -= brightness_step) {
> + backlight_write_brightness(brightness);
> + usleep(100000);
> + pwm = read_target_backlight_pwm(debugfs);
> + igt_assert(pwm < prev_pwm);
> + prev_pwm = pwm;
> + }
> + }
> +}
> +
> +static void abm_enabled(igt_display_t *display, int debugfs)
> +{
> + int ret, i;
> + int max_brightness;
> + int pwm, prev_pwm, pwm_without_abm;
> +
> + ret = backlight_read_max_brightness(&max_brightness);
> + igt_assert_eq(ret, 0);
> +
> + set_abm_level(display, 0);
> + backlight_write_brightness(max_brightness);
> + usleep(100000);
> + prev_pwm = read_target_backlight_pwm(debugfs);
> + pwm_without_abm = prev_pwm;
> +
> + for (i = 1; i < 5; i++) {
> + set_abm_level(display, i);
> + usleep(100000);
> + pwm = read_target_backlight_pwm(debugfs);
> + igt_assert(pwm <= prev_pwm);
> + igt_assert(pwm < pwm_without_abm);
> + prev_pwm = pwm;
> + }
> +
> +}
> +
> +static void abm_gradual(igt_display_t *display, int debugfs)
> +{
> + int ret, i;
> + int convergence_delay = 15;
> + int prev_pwm, pwm, curr;
> + int max_brightness;
> +
> + ret = backlight_read_max_brightness(&max_brightness);
> +
> + igt_assert_eq(ret, 0);
> +
> + set_abm_level(display, 0);
> + backlight_write_brightness(max_brightness);
> +
> + sleep(convergence_delay);
> + prev_pwm = read_target_backlight_pwm(debugfs);
> + curr = read_current_backlight_pwm(debugfs);
> +
> + igt_assert_eq(prev_pwm, curr);
> + set_abm_level(display, 4);
> + for (i = 0; i < 10; i++) {
> + usleep(100000);
> + pwm = read_current_backlight_pwm(debugfs);
> + igt_assert(pwm < prev_pwm);
This seems like it very much depends on the usleep value above, the range of expected pwm reduction between no ABM and ABM level 4, as well as how quickly/slowly this executes.
Should the usleep time be a function of the convergence_delay?
Could this give us flaky test results?
How many PWM steps have you usually seen for each iteration of this function? If it's large we're probably fine.
Harry
> + prev_pwm = pwm;
> + }
> +
> + sleep(convergence_delay - 1);
> +
> + prev_pwm = read_target_backlight_pwm(debugfs);
> + curr = read_current_backlight_pwm(debugfs);
> +
> + igt_assert_eq(prev_pwm, curr);
> +}
> +
> +igt_main
> +{
> + igt_display_t display;
> + int debugfs;
> + enum pipe pipe;
> + igt_output_t *output;
> +
> + igt_skip_on_simulation();
> +
> + igt_fixture {
> + display.drm_fd = drm_open_driver_master(DRIVER_AMDGPU);
> +
> + if (display.drm_fd == -1)
> + igt_skip("Not an amdgpu driver.\n");
> +
> + debugfs = igt_debugfs_dir(display.drm_fd);
> +
> + kmstest_set_vt_graphics_mode();
> +
> + igt_display_require(&display, display.drm_fd);
> +
> + skip_if_incompatible(&display, debugfs);
> +
> + for_each_pipe_with_valid_output(&display, pipe, output)
> + break;
> + }
> +
> + igt_subtest("dpms_cycle")
> + backlight_dpms_cycle(&display, debugfs, output);
> + igt_subtest("backlight_monotonic_basic")
> + backlight_monotonic_basic(&display, debugfs);
> + igt_subtest("backlight_monotonic_abm")
> + backlight_monotonic_abm(&display, debugfs);
> + igt_subtest("abm_enabled")
> + abm_enabled(&display, debugfs);
> + igt_subtest("abm_gradual")
> + abm_gradual(&display, debugfs);
> +
> + igt_fixture {
> + igt_display_fini(&display);
> + }
> +}
>
More information about the igt-dev
mailing list