Commit 88b01d82 authored by Chris Wilson's avatar Chris Wilson 🤔

igt/pm_rc6_residency: Measure residency after checking for applicability

CI doesn't run in whole-test mode, but runs each subtest individually.
Tests that are designed to do a block of work to be shared between many
subtests end up running that work multiple times (once per subtest) and
worse, that work is wasted if the subtest will be skipped.

pm_rc6_residency is one such example that measured all the residencies
up front before skipping, each skip was therefore taking in excess of
10s.

v2: Put a small delay back before starting measurements as rc6 doesn't
start until an evaluation interval after idling.
v3: Drop rc6p+ tests; we have no control over the hw whether it decides
to use rc6 or deeper (we can enable it, but not dictate it).
Signed-off-by: Chris Wilson's avatarChris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Ewelina Musial <ewelina.musial@intel.com> #v1
parent c7b20c95
......@@ -53,11 +53,11 @@ struct residencies {
static unsigned long get_rc6_enabled_mask(void)
{
unsigned long rc6_mask;
unsigned long enabled;
rc6_mask = 0;
igt_sysfs_scanf(sysfs, "power/rc6_enable", "%lu", &rc6_mask);
return rc6_mask;
enabled = 0;
igt_sysfs_scanf(sysfs, "power/rc6_enable", "%lu", &enabled);
return enabled;
}
static unsigned long read_rc6_residency(const char *name)
......@@ -85,63 +85,67 @@ static void residency_accuracy(unsigned int diff,
"Sysfs RC6 residency counter is inaccurate.\n");
}
static void read_residencies(int devid, unsigned int rc6_mask,
static unsigned long gettime_ms(void)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
}
static void read_residencies(int devid, unsigned int mask,
struct residencies *res)
{
if (rc6_mask & RC6_ENABLED)
res->duration = gettime_ms();
if (mask & RC6_ENABLED)
res->rc6 = read_rc6_residency("rc6");
if ((rc6_mask & RC6_ENABLED) &&
if ((mask & RC6_ENABLED) &&
(IS_VALLEYVIEW(devid) || IS_CHERRYVIEW(devid)))
res->media_rc6 = read_rc6_residency("media_rc6");
if (rc6_mask & RC6P_ENABLED)
if (mask & RC6P_ENABLED)
res->rc6p = read_rc6_residency("rc6p");
if (rc6_mask & RC6PP_ENABLED)
if (mask & RC6PP_ENABLED)
res->rc6pp = read_rc6_residency("rc6pp");
}
static unsigned long gettime_ms(void)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
res->duration += (gettime_ms() - res->duration) / 2;
}
static void measure_residencies(int devid, unsigned int rc6_mask,
static void measure_residencies(int devid, unsigned int mask,
struct residencies *res)
{
struct residencies start = { };
struct residencies end = { };
int retry;
unsigned long t;
if (!rc6_mask)
if (!mask)
return;
/*
* For some reason my ivb isn't idle even after syncing up with the gpu.
* Let's add a sleep just to make it happy.
*/
sleep(8);
/*
* Retry in case of counter wrap-around. We simply re-run the
* measurement, since the valid counter range is different on
* different platforms and so fixing it up would be non-trivial.
*/
read_residencies(devid, mask, &end);
igt_debug("time=%d: rc6=(%d, %d), rc6p=%d, rc6pp=%d\n",
end.duration, end.rc6, end.media_rc6, end.rc6p, end.rc6pp);
for (retry = 0; retry < 2; retry++) {
t = gettime_ms();
read_residencies(devid, rc6_mask, &start);
start = end;
sleep(SLEEP_DURATION);
read_residencies(devid, rc6_mask, &end);
t = gettime_ms() - t;
read_residencies(devid, mask, &end);
igt_debug("time=%d: rc6=(%d, %d), rc6p=%d, rc6pp=%d\n",
end.duration,
end.rc6, end.media_rc6, end.rc6p, end.rc6pp);
if (end.rc6 >= start.rc6 && end.media_rc6 >= start.media_rc6 &&
end.rc6p >= start.rc6p && end.rc6pp >= start.rc6pp)
if (end.rc6 >= start.rc6 &&
end.media_rc6 >= start.media_rc6 &&
end.rc6p >= start.rc6p &&
end.rc6pp >= start.rc6pp)
break;
}
igt_assert_f(retry < 2, "residency values are not consistent\n");
......@@ -150,7 +154,7 @@ static void measure_residencies(int devid, unsigned int rc6_mask,
res->rc6p = end.rc6p - start.rc6p;
res->rc6pp = end.rc6pp - start.rc6pp;
res->media_rc6 = end.media_rc6 - start.media_rc6;
res->duration = t;
res->duration = end.duration - start.duration;
/*
* For the purposes of this test case we want a given residency value
......@@ -164,11 +168,23 @@ static void measure_residencies(int devid, unsigned int rc6_mask,
res->rc6 += res->rc6p;
}
static unsigned long rc6_enable_us(void)
{
/*
* To know how long we need to wait for the device to enter rc6 once
* idle, we need to look at GEN6_RC_EVALUATION_INTERVAL. Currently,
* this is set to 125000 (12500 * 1280ns or 0.16s) on all platforms.
* We must complete at least one EI with activity below the
* per-platform threshold for RC6 to kick. Therefore, we must wait
* at least 2 EI cycles, before we can expect rc6 to start ticking.
*/
return 2 * 160 * 1000;
}
igt_main
{
unsigned int rc6_mask;
int devid = 0;
struct residencies res;
unsigned int rc6_enabled = 0;
unsigned int devid = 0;
igt_skip_on_simulation();
......@@ -179,33 +195,33 @@ igt_main
fd = drm_open_driver(DRIVER_INTEL);
devid = intel_get_drm_devid(fd);
sysfs = igt_sysfs_open(fd, NULL);
close(fd);
rc6_mask = get_rc6_enabled_mask();
igt_require(rc6_mask);
/* Make sure rc6 counters are running */
igt_drop_caches_set(fd, DROP_IDLE);
usleep(rc6_enable_us());
measure_residencies(devid, rc6_mask, &res);
close(fd);
rc6_enabled = get_rc6_enabled_mask();
igt_require(rc6_enabled);
}
igt_subtest("rc6-accuracy") {
igt_skip_on(!(rc6_mask & RC6_ENABLED));
struct residencies res;
igt_require(rc6_enabled & RC6_ENABLED);
measure_residencies(devid, rc6_enabled, &res);
residency_accuracy(res.rc6, res.duration, "rc6");
}
igt_subtest("media-rc6-accuracy") {
igt_skip_on(!((rc6_mask & RC6_ENABLED) &&
(IS_VALLEYVIEW(devid) || IS_CHERRYVIEW(devid))));
residency_accuracy(res.media_rc6, res.duration, "media_rc6");
}
igt_subtest("rc6p-accuracy") {
igt_skip_on(!(rc6_mask & RC6P_ENABLED));
igt_subtest("media-rc6-accuracy") {
struct residencies res;
residency_accuracy(res.rc6p, res.duration, "rc6p");
}
igt_subtest("rc6pp-accuracy") {
igt_skip_on(!(rc6_mask & RC6PP_ENABLED));
igt_require((rc6_enabled & RC6_ENABLED) &&
(IS_VALLEYVIEW(devid) || IS_CHERRYVIEW(devid)));
residency_accuracy(res.rc6pp, res.duration, "rc6pp");
measure_residencies(devid, rc6_enabled, &res);
residency_accuracy(res.media_rc6, res.duration, "media_rc6");
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment