[igt-dev] [PATCH i-g-t] tests/amdgpu: Add test for Adaptive Backlight Management
Li, Sun peng (Leo)
Sunpeng.Li at amd.com
Thu Jan 3 16:55:21 UTC 2019
On 2018-12-07 9:34 a.m., Francis, David wrote:
> On my machine, the gradual brightness reduction gives the following pwm
> measurements
>
> pwm changed from 65535 to 64758 (-777)
> pwm changed from 64758 to 63530 (-1228)
> pwm changed from 63530 to 62594 (-936)
> pwm changed from 62594 to 61751 (-843)
> pwm changed from 61751 to 60825 (-926)
> pwm changed from 60825 to 59480 (-1345)
> pwm changed from 59480 to 58064 (-1416)
> pwm changed from 58064 to 56967 (-1097)
> pwm changed from 56967 to 55956 (-1011)
> pwm changed from 55956 to 55027 (-929)
>
> I think we can assume a change of at least 1
>
> ------------------------------------------------------------------------
> *From:* Wentland, Harry
> *Sent:* November 29, 2018 3:45:30 PM
> *To:* Francis, David; igt-dev at lists.freedesktop.org
> *Subject:* Re: [igt-dev] [PATCH i-g-t] tests/amdgpu: Add test for
> Adaptive Backlight Management
>
>
> 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;
Are we guaranteed to end up with the correct output here? This would
give us the first valid output to run the dpms_cycle test on, but will
it be the ABM output? pm_backlight.c seems to be doing some name
matching to check this.
Leo
>> + }
>> +
>> + 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);
>> + }
>> +}
>>
>
> _______________________________________________
> igt-dev mailing list
> igt-dev at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/igt-dev
>
More information about the igt-dev
mailing list