<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
<style type="text/css" style="display:none;"><!-- P {margin-top:0;margin-bottom:0;} --></style>
</head>
<body dir="ltr">
<div id="divtagdefaultwrapper" style="font-size:12pt;color:#000000;font-family:Calibri,Helvetica,sans-serif;" dir="ltr">
<p style="margin-top:0;margin-bottom:0"></p>
<div>On my machine, the gradual brightness reduction gives the following pwm measurements</div>
<div><br>
</div>
<div>pwm changed from 65535 to 64758 (-777)</div>
<div>pwm changed from 64758 to 63530 (-1228)</div>
<div>pwm changed from 63530 to 62594 (-936)</div>
<div>pwm changed from 62594 to 61751 (-843)</div>
<div>pwm changed from 61751 to 60825 (-926)</div>
<div>pwm changed from 60825 to 59480 (-1345)</div>
<div>pwm changed from 59480 to 58064 (-1416)</div>
<div>pwm changed from 58064 to 56967 (-1097)</div>
<div>pwm changed from 56967 to 55956 (-1011)</div>
<div>pwm changed from 55956 to 55027 (-929)</div>
<br>
<p></p>
<p style="margin-top:0;margin-bottom:0">I think we can assume a change of at least 1</p>
</div>
<hr style="display:inline-block;width:98%" tabindex="-1">
<div id="divRplyFwdMsg" dir="ltr"><font face="Calibri, sans-serif" style="font-size:11pt" color="#000000"><b>From:</b> Wentland, Harry<br>
<b>Sent:</b> November 29, 2018 3:45:30 PM<br>
<b>To:</b> Francis, David; igt-dev@lists.freedesktop.org<br>
<b>Subject:</b> Re: [igt-dev] [PATCH i-g-t] tests/amdgpu: Add test for Adaptive Backlight Management</font>
<div> </div>
</div>
<div class="BodyFragment"><font size="2"><span style="font-size:11pt;">
<div class="PlainText"><br>
<br>
On 2018-11-28 3:51 p.m., David Francis wrote:<br>
> Adaptive Backlight Management (ABM) is a power-saving<br>
> feature on AMD ASICs that reduces backlight while increasing<br>
> pixel contrast and luminance.  This test confirms that<br>
> ABM is present and enabled, and that backlight performance<br>
> is sane.  It uses AMD-specific debugfs entries to<br>
> read the backlight PWM values.<br>
> <br>
> It has 5 subtests:<br>
> <br>
> dpms_cycle<br>
> Sets brightness to half, then confirms that value is restored<br>
> after dpms off and then on.<br>
> <br>
> backlight_monotonic_basic<br>
> Sets brightness to ten different values, confirming that<br>
> higher brightness values are brighter.<br>
> <br>
> backlight_monotonic_abm<br>
> Same as backlight_monotonic_basic, but with abm enabled.<br>
> <br>
> abm_enabled<br>
> Sets abm to its four intensity levels, confirming that<br>
> abm reduces the backlight, and the reduction is greater<br>
> for higher abm level.<br>
> <br>
> abm_gradual<br>
> Sets abm to off and then maximum intensity, confirming<br>
> that brightness decreases continually over the first<br>
> second and eventually reaches the target value.<br>
> This test takes 30s to run.<br>
> <br>
> Signed-off-by: David Francis <David.Francis@amd.com><br>
> ---<br>
>  tests/Makefile.sources |   1 +<br>
>  tests/amdgpu/amd_abm.c | 361 +++++++++++++++++++++++++++++++++++++++++<br>
>  2 files changed, 362 insertions(+)<br>
>  create mode 100644 tests/amdgpu/amd_abm.c<br>
> <br>
> diff --git a/tests/Makefile.sources b/tests/Makefile.sources<br>
> index 5620c1d6..3d560bee 100644<br>
> --- a/tests/Makefile.sources<br>
> +++ b/tests/Makefile.sources<br>
> @@ -19,6 +19,7 @@ AMDGPU_TESTS = \<br>
>        amdgpu/amd_basic \<br>
>        amdgpu/amd_cs_nop \<br>
>        amdgpu/amd_prime \<br>
> +     amdgpu/amd_abm \<br>
>        $(NULL)<br>
>  <br>
>  TESTS_progs = \<br>
> diff --git a/tests/amdgpu/amd_abm.c b/tests/amdgpu/amd_abm.c<br>
> new file mode 100644<br>
> index 00000000..90a6f99e<br>
> --- /dev/null<br>
> +++ b/tests/amdgpu/amd_abm.c<br>
> @@ -0,0 +1,361 @@<br>
> +/*<br>
> + * Copyright 2018 Advanced Micro Devices, Inc.<br>
> + *<br>
> + * Permission is hereby granted, free of charge, to any person obtaining a<br>
> + * copy of this software and associated documentation files (the "Software"),<br>
> + * to deal in the Software without restriction, including without limitation<br>
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,<br>
> + * and/or sell copies of the Software, and to permit persons to whom the<br>
> + * Software is furnished to do so, subject to the following conditions:<br>
> + *<br>
> + * The above copyright notice and this permission notice shall be included in<br>
> + * all copies or substantial portions of the Software.<br>
> + *<br>
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR<br>
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,<br>
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL<br>
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR<br>
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,<br>
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR<br>
> + * OTHER DEALINGS IN THE SOFTWARE.<br>
> + */<br>
> +<br>
> +#include "igt.h"<br>
> +#include "drmtest.h"<br>
> +#include "igt_kms.h"<br>
> +#include <limits.h><br>
> +#include <errno.h><br>
> +#include <stdbool.h><br>
> +#include <stdlib.h><br>
> +#include <stdio.h><br>
> +#include <string.h><br>
> +#include <fcntl.h><br>
> +#include <time.h><br>
> +<br>
> +#define BACKLIGHT_PATH "/sys/class/backlight/amdgpu_bl0"<br>
> +<br>
> +static int read_current_backlight_pwm(int debugfs_dir)<br>
> +{<br>
> +     char buf[20];<br>
> +<br>
> +     igt_debugfs_simple_read(debugfs_dir, "amdgpu_current_backlight_pwm",<br>
> +                      buf, sizeof(buf));<br>
> +<br>
> +     return strtol(buf, NULL, 0);<br>
> +}<br>
> +<br>
> +static int read_target_backlight_pwm(int debugfs_dir)<br>
> +{<br>
> +     char buf[20];<br>
> +<br>
> +     igt_debugfs_simple_read(debugfs_dir, "amdgpu_target_backlight_pwm",<br>
> +                      buf, sizeof(buf));<br>
> +<br>
> +     return strtol(buf, NULL, 0);<br>
> +}<br>
> +<br>
> +static int backlight_write_brightness(int value)<br>
> +{<br>
> +     int fd;<br>
> +     char full[PATH_MAX];<br>
> +     char src[64];<br>
> +     int len;<br>
> +<br>
> +     igt_assert(snprintf(full, PATH_MAX, "%s/%s", BACKLIGHT_PATH, "brightness") < PATH_MAX);<br>
> +     fd = open(full, O_WRONLY);<br>
> +     if (fd == -1)<br>
> +             return -errno;<br>
> +<br>
> +     len = snprintf(src, sizeof(src), "%i", value);<br>
> +     len = write(fd, src, len);<br>
> +     close(fd);<br>
> +<br>
> +     if (len < 0)<br>
> +             return len;<br>
> +<br>
> +     return 0;<br>
> +}<br>
> +<br>
> +static void set_abm_level(igt_display_t *display, int level)<br>
> +{<br>
> +     int i, ret;<br>
> +     int output_id;<br>
> +     drmModeObjectPropertiesPtr props;<br>
> +     uint32_t prop_id;<br>
> +     drmModePropertyPtr prop;<br>
> +     uint32_t type = DRM_MODE_OBJECT_CONNECTOR;<br>
> +<br>
> +     for (i = 0; i < display->n_outputs; i++) {<br>
> +             output_id = display->outputs[i].id;<br>
> +             props = drmModeObjectGetProperties(display->drm_fd, output_id, type);<br>
> +<br>
> +             for (i = 0; i < props->count_props; i++) {<br>
> +                     prop_id = props->props[i];<br>
> +                     prop = drmModeGetProperty(display->drm_fd, prop_id);<br>
> +<br>
> +                     igt_assert(prop);<br>
> +<br>
> +                     if (strcmp(prop->name, "abm level") == 0) {<br>
> +                             ret = drmModeObjectSetProperty(display->drm_fd, output_id, type, prop_id, level);<br>
> +<br>
> +                             igt_assert_eq(ret, 0);<br>
> +                     }<br>
> +<br>
> +                     drmModeFreeProperty(prop);<br>
> +             }<br>
> +     }<br>
> +<br>
> +}<br>
> +<br>
> +static int backlight_read_max_brightness(int *result)<br>
> +{<br>
> +     int fd;<br>
> +     char full[PATH_MAX];<br>
> +     char dst[64];<br>
> +     int r, e;<br>
> +<br>
> +     igt_assert(snprintf(full, PATH_MAX, "%s/%s", BACKLIGHT_PATH, "max_brightness") < PATH_MAX);<br>
> +<br>
> +     fd = open(full, O_RDONLY);<br>
> +     if (fd == -1)<br>
> +             return -errno;<br>
> +<br>
> +     r = read(fd, dst, sizeof(dst));<br>
> +     e = errno;<br>
> +     close(fd);<br>
> +<br>
> +     if (r < 0)<br>
> +             return -e;<br>
> +<br>
> +     errno = 0;<br>
> +     *result = strtol(dst, NULL, 10);<br>
> +     return errno;<br>
> +}<br>
> +<br>
> +static void skip_if_incompatible(igt_display_t *display, int debugfs_dir)<br>
> +{<br>
> +     int ret, i;<br>
> +     char buf[20];<br>
> +     bool abm_prop_exists;<br>
> +     int output_id;<br>
> +     drmModeObjectPropertiesPtr props;<br>
> +     uint32_t type = DRM_MODE_OBJECT_CONNECTOR;<br>
> +     uint32_t prop_id;<br>
> +     drmModePropertyPtr prop;<br>
> +<br>
> +     ret = igt_debugfs_simple_read(debugfs_dir, "amdgpu_current_backlight_pwm",<br>
> +                      buf, sizeof(buf));<br>
> +<br>
> +     if (ret < 0)<br>
> +             igt_skip("No current backlight debugfs entry.\n");<br>
> +<br>
> +     ret = igt_debugfs_simple_read(debugfs_dir, "amdgpu_target_backlight_pwm",<br>
> +                      buf, sizeof(buf));<br>
> +<br>
> +     if (ret < 0)<br>
> +             igt_skip("No target backlight debugfs entry.\n");<br>
> +<br>
> +     abm_prop_exists = false;<br>
> +<br>
> +     for (i = 0; i < display->n_outputs; i++) {<br>
> +             output_id = display->outputs[i].id;<br>
> +             props = drmModeObjectGetProperties(display->drm_fd, output_id, type);<br>
> +<br>
> +             for (i = 0; i < props->count_props; i++) {<br>
> +                     prop_id = props->props[i];<br>
> +                     prop = drmModeGetProperty(display->drm_fd, prop_id);<br>
> +<br>
> +                     if (strcmp(prop->name, "abm level") == 0)<br>
> +                             abm_prop_exists = true;<br>
> +<br>
> +                     drmModeFreeProperty(prop);<br>
> +             }<br>
> +     }<br>
> +<br>
> +     if (!abm_prop_exists)<br>
> +             igt_skip("No abm level property on any connector.\n");<br>
> +}<br>
> +<br>
> +<br>
> +static void backlight_dpms_cycle(igt_display_t *display, int debugfs, igt_output_t *output)<br>
> +{<br>
> +     int ret;<br>
> +     int max_brightness;<br>
> +     int pwm_1, pwm_2;<br>
> +<br>
> +     ret = backlight_read_max_brightness(&max_brightness);<br>
> +     igt_assert_eq(ret, 0);<br>
> +<br>
> +     set_abm_level(display, 0);<br>
> +     backlight_write_brightness(max_brightness / 2);<br>
> +     usleep(100000);<br>
> +     pwm_1 = read_target_backlight_pwm(debugfs);<br>
> +<br>
> +     kmstest_set_connector_dpms(display->drm_fd, output->config.connector, DRM_MODE_DPMS_OFF);<br>
> +     kmstest_set_connector_dpms(display->drm_fd, output->config.connector, DRM_MODE_DPMS_ON);<br>
> +     usleep(100000);<br>
> +     pwm_2 = read_target_backlight_pwm(debugfs);<br>
> +     igt_assert_eq(pwm_1, pwm_2);<br>
> +}<br>
> +<br>
> +static void backlight_monotonic_basic(igt_display_t *display, int debugfs)<br>
> +{<br>
> +     int ret;<br>
> +     int max_brightness;<br>
> +     int prev_pwm, pwm;<br>
> +     int brightness_step;<br>
> +     int brightness;<br>
> +<br>
> +     ret = backlight_read_max_brightness(&max_brightness);<br>
> +     igt_assert_eq(ret, 0);<br>
> +<br>
> +     brightness_step = max_brightness / 10;<br>
> +<br>
> +     set_abm_level(display, 0);<br>
> +     backlight_write_brightness(max_brightness);<br>
> +     usleep(100000);<br>
> +     prev_pwm = read_target_backlight_pwm(debugfs);<br>
> +     for (brightness = max_brightness - brightness_step;<br>
> +          brightness > 0;<br>
> +          brightness -= brightness_step) {<br>
> +             backlight_write_brightness(brightness);<br>
> +             usleep(100000);<br>
> +             pwm = read_target_backlight_pwm(debugfs);<br>
> +             igt_assert(pwm < prev_pwm);<br>
> +             prev_pwm = pwm;<br>
> +     }<br>
> +<br>
> +}<br>
> +<br>
> +static void backlight_monotonic_abm(igt_display_t *display, int debugfs)<br>
> +{<br>
> +     int ret, i;<br>
> +     int max_brightness;<br>
> +     int prev_pwm, pwm;<br>
> +     int brightness_step;<br>
> +     int brightness;<br>
> +<br>
> +     ret = backlight_read_max_brightness(&max_brightness);<br>
> +     igt_assert_eq(ret, 0);<br>
> +<br>
> +     brightness_step = max_brightness / 10;<br>
> +     for (i = 1; i < 5; i++) {<br>
> +             set_abm_level(display, i);<br>
> +             backlight_write_brightness(max_brightness);<br>
> +             usleep(100000);<br>
> +             prev_pwm = read_target_backlight_pwm(debugfs);<br>
> +             for (brightness = max_brightness - brightness_step;<br>
> +                  brightness > 0;<br>
> +                  brightness -= brightness_step) {<br>
> +                     backlight_write_brightness(brightness);<br>
> +                     usleep(100000);<br>
> +                     pwm = read_target_backlight_pwm(debugfs);<br>
> +                     igt_assert(pwm < prev_pwm);<br>
> +                     prev_pwm = pwm;<br>
> +             }<br>
> +     }<br>
> +}<br>
> +<br>
> +static void abm_enabled(igt_display_t *display, int debugfs)<br>
> +{<br>
> +     int ret, i;<br>
> +     int max_brightness;<br>
> +     int pwm, prev_pwm, pwm_without_abm;<br>
> +<br>
> +     ret = backlight_read_max_brightness(&max_brightness);<br>
> +     igt_assert_eq(ret, 0);<br>
> +<br>
> +     set_abm_level(display, 0);<br>
> +     backlight_write_brightness(max_brightness);<br>
> +     usleep(100000);<br>
> +     prev_pwm = read_target_backlight_pwm(debugfs);<br>
> +     pwm_without_abm = prev_pwm;<br>
> +<br>
> +     for (i = 1; i < 5; i++) {<br>
> +             set_abm_level(display, i);<br>
> +             usleep(100000);<br>
> +             pwm = read_target_backlight_pwm(debugfs);<br>
> +             igt_assert(pwm <= prev_pwm);<br>
> +             igt_assert(pwm < pwm_without_abm);<br>
> +             prev_pwm = pwm;<br>
> +     }<br>
> +<br>
> +}<br>
> +<br>
> +static void abm_gradual(igt_display_t *display, int debugfs)<br>
> +{<br>
> +     int ret, i;<br>
> +     int convergence_delay = 15;<br>
> +     int prev_pwm, pwm, curr;<br>
> +     int max_brightness;<br>
> +<br>
> +     ret = backlight_read_max_brightness(&max_brightness);<br>
> +<br>
> +     igt_assert_eq(ret, 0);<br>
> +<br>
> +     set_abm_level(display, 0);<br>
> +     backlight_write_brightness(max_brightness);<br>
> +<br>
> +     sleep(convergence_delay);<br>
> +     prev_pwm = read_target_backlight_pwm(debugfs);<br>
> +     curr = read_current_backlight_pwm(debugfs);<br>
> +<br>
> +     igt_assert_eq(prev_pwm, curr);<br>
> +     set_abm_level(display, 4);<br>
> +     for (i = 0; i < 10; i++) {<br>
> +             usleep(100000);<br>
> +             pwm = read_current_backlight_pwm(debugfs);<br>
> +             igt_assert(pwm < prev_pwm);<br>
<br>
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.<br>
<br>
Should the usleep time be a function of the convergence_delay?<br>
<br>
Could this give us flaky test results?<br>
<br>
How many PWM steps have you usually seen for each iteration of this function? If it's large we're probably fine.<br>
<br>
Harry<br>
<br>
> +             prev_pwm = pwm;<br>
> +     }<br>
> +<br>
> +     sleep(convergence_delay - 1);<br>
> +<br>
> +     prev_pwm = read_target_backlight_pwm(debugfs);<br>
> +     curr = read_current_backlight_pwm(debugfs);<br>
> +<br>
> +     igt_assert_eq(prev_pwm, curr);<br>
> +}<br>
> +<br>
> +igt_main<br>
> +{<br>
> +     igt_display_t display;<br>
> +     int debugfs;<br>
> +     enum pipe pipe;<br>
> +     igt_output_t *output;<br>
> +<br>
> +     igt_skip_on_simulation();<br>
> +<br>
> +     igt_fixture {<br>
> +             display.drm_fd = drm_open_driver_master(DRIVER_AMDGPU);<br>
> +<br>
> +             if (display.drm_fd == -1)<br>
> +                     igt_skip("Not an amdgpu driver.\n");<br>
> +<br>
> +             debugfs = igt_debugfs_dir(display.drm_fd);<br>
> +<br>
> +             kmstest_set_vt_graphics_mode();<br>
> +<br>
> +             igt_display_require(&display, display.drm_fd);<br>
> +<br>
> +             skip_if_incompatible(&display, debugfs);<br>
> +<br>
> +             for_each_pipe_with_valid_output(&display, pipe, output)<br>
> +                     break;<br>
> +     }<br>
> +<br>
> +     igt_subtest("dpms_cycle")<br>
> +             backlight_dpms_cycle(&display, debugfs, output);<br>
> +     igt_subtest("backlight_monotonic_basic")<br>
> +             backlight_monotonic_basic(&display, debugfs);<br>
> +     igt_subtest("backlight_monotonic_abm")<br>
> +             backlight_monotonic_abm(&display, debugfs);<br>
> +     igt_subtest("abm_enabled")<br>
> +             abm_enabled(&display, debugfs);<br>
> +     igt_subtest("abm_gradual")<br>
> +             abm_gradual(&display, debugfs);<br>
> +<br>
> +     igt_fixture {<br>
> +             igt_display_fini(&display);<br>
> +     }<br>
> +}<br>
> <br>
</div>
</span></font></div>
</body>
</html>