diff options
author | Kenneth Graunke <kenneth@whitecape.org> | 2013-03-22 13:45:36 -0700 |
---|---|---|
committer | Kenneth Graunke <kenneth@whitecape.org> | 2013-04-01 15:30:58 -0700 |
commit | e8c9d68d2d4277460f650c8e1093b904b56bbff0 (patch) | |
tree | 5bb363cd69caf8540d99744a3c71f264e3873bb8 /tests/spec/amd_performance_monitor/measure.c | |
parent | 7b95e3cd516bc0e240925e029c3867a829e53611 (diff) |
Add tests for the GL_AMD_performance_monitor extension.
One of the challenging aspects of testing this extension is that it
defines an implementation-specific set of groups and counters. Many of
the tests here arbitrarily operate on the counters in the first group,
while a few sanity check all counters in all groups.
All tests pass on AMD's Catalyst 12.06 driver on a Radeon 3650, except
for: test_number_of_groups_partial_array, test_delete_monitor_invalid,
and test_get_counter_data_byte_size. I believe the first two are
legitimate bugs in AMD's implementation, and the latter is a
disagreement about the associativity of text within a paragraph. Still,
these are minor details and I believe the tests are valid.
v2: Actually set the test name for the second test.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Diffstat (limited to 'tests/spec/amd_performance_monitor/measure.c')
-rw-r--r-- | tests/spec/amd_performance_monitor/measure.c | 388 |
1 files changed, 388 insertions, 0 deletions
diff --git a/tests/spec/amd_performance_monitor/measure.c b/tests/spec/amd_performance_monitor/measure.c new file mode 100644 index 00000000..bc39c846 --- /dev/null +++ b/tests/spec/amd_performance_monitor/measure.c @@ -0,0 +1,388 @@ +/* + * Copyright © 2013 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. + */ + +/** + * \file measure.c + * + * Some AMD_performance_monitor tests that actually measure things. + */ + +#define __STDC_FORMAT_MACROS +#include <inttypes.h> +#include "piglit-util-gl-common.h" + +PIGLIT_GL_TEST_CONFIG_BEGIN + + config.supports_gl_compat_version = 10; + config.window_visual = PIGLIT_GL_VISUAL_RGB; + +PIGLIT_GL_TEST_CONFIG_END + +/******************************************************************************/ + +/** + * Get a list of group IDs. + */ +static void +get_groups(unsigned **groups, int *num_groups) +{ + glGetPerfMonitorGroupsAMD(num_groups, 0, NULL); + *groups = calloc(*num_groups, sizeof(unsigned)); + glGetPerfMonitorGroupsAMD(NULL, *num_groups, *groups); +} + +/** + * Get a list of counter IDs in a given group. + */ +static void +get_counters(unsigned group, unsigned **counters, int *num_counters, + int *max_active_counters) +{ + glGetPerfMonitorCountersAMD(group, num_counters, NULL, 0, NULL); + *counters = calloc(*num_counters, sizeof(unsigned)); + glGetPerfMonitorCountersAMD(group, NULL, max_active_counters, + *num_counters, *counters); +} + +#define verify(x) \ + if (!(x)) { \ + piglit_report_subtest_result(PIGLIT_FAIL, test_name); \ + return; \ + } + +/******************************************************************************/ + +/** + * Poll until PERFMON_RESULT_AVAILABLE returns 1; glFinish() on each iteration. + * + * Only loop for 5 times to guard against implementations that never finish. + */ +static bool +wait_until_available(unsigned monitor) +{ + int i; + unsigned available = 0; + for (i = 0; !available && i < 5; i++) { + glFinish(); + glGetPerfMonitorCounterDataAMD(monitor, + GL_PERFMON_RESULT_AVAILABLE_AMD, + sizeof(unsigned), &available, + NULL); + } + return available; +} + +/** + * Basic functional test: enable all the counters in the first group + * (up to the maximum that can be active at a time), begin monitoring, + * end monitoring, make sure results are available, sanity check the + * result size, and get the results. + */ +static void +test_basic_measurement(unsigned group) +{ + unsigned monitor; + unsigned *counters; + int num_counters; + int max_active_counters; + unsigned usable_counters; + unsigned result_size = 0; + GLsizei bytes_written = 0; + unsigned *data; + + uint32_t *p; + unsigned value; + + const char *test_name; + + /** + * Test #1: Basic Measurement. + * + * Enable all the counters in the first group (up to the maximum that + * can be active at a time), begin monitoring, end monitoring, make + * sure results are available, sanity check the result size, and get + * the results. + */ + test_name = "basic measurement"; + + get_counters(group, &counters, &num_counters, + &max_active_counters); + verify(max_active_counters >= 0); + verify(piglit_check_gl_error(GL_NO_ERROR)); + + usable_counters = MIN2(num_counters, max_active_counters); + + glGenPerfMonitorsAMD(1, &monitor); + verify(piglit_check_gl_error(GL_NO_ERROR)); + + /* Enable counters 0 .. usable_counters from the list. */ + glSelectPerfMonitorCountersAMD(monitor, true, group, usable_counters, + counters); + verify(piglit_check_gl_error(GL_NO_ERROR)); + + /* Start monitoring */ + glBeginPerfMonitorAMD(monitor); + verify(piglit_check_gl_error(GL_NO_ERROR)); + + /* Drawing...meh */ + glFinish(); + + /* End monitoring */ + glEndPerfMonitorAMD(monitor); + verify(piglit_check_gl_error(GL_NO_ERROR)); + + /* Wait for the result to be available. */ + verify(wait_until_available(monitor)); + verify(piglit_check_gl_error(GL_NO_ERROR)); + + /* Get the result size. */ + glGetPerfMonitorCounterDataAMD(monitor, GL_PERFMON_RESULT_SIZE_AMD, + sizeof(unsigned), &result_size, NULL); + verify(piglit_check_gl_error(GL_NO_ERROR)); + + /* Make sure the size is in bytes. */ + verify(result_size % sizeof(unsigned) == 0); + + /* The format is <Group ID, Group, Value>. The first two are + * uint32_ts. Value is either a float, uint32_t, or uint64_t. + * As a sanity check, make sure the result size is within + * reasonable limits. Don't bother checking the actual types + * since that's a bunch of work. + */ + verify(result_size >= 3 * sizeof(uint32_t) * usable_counters) + verify(result_size <= + (2 * sizeof(uint32_t) + sizeof(uint64_t)) * usable_counters); + + /* Get the results. */ + data = calloc(1, result_size); + glGetPerfMonitorCounterDataAMD(monitor, GL_PERFMON_RESULT_AMD, + result_size, data, &bytes_written); + + verify(bytes_written == result_size); + + piglit_report_subtest_result(PIGLIT_PASS, test_name); + + /** + * Test #2: Verify counter results against specified range. + */ + test_name = "counters in range"; + p = data; + while ((char *) p < ((char *) data) + bytes_written) { + uint32_t group_id = p[0]; + uint32_t counter_id = p[1]; + + /* Counter values */ + uint32_t u32 = p[2]; + float f = ((float *) p)[2]; + uint64_t u64 = ((uint64_t *) p)[1]; + + /* Query results */ + GLenum counter_type = GL_NONE; + uint64_t range[2]; + + /* There's only one group, so it better match */ + verify(group_id == group); + + /* Getting the counter data also validates the counter ID + * without having to walk through the whole list of counters. + */ + glGetPerfMonitorCounterInfoAMD(group_id, counter_id, + GL_COUNTER_TYPE_AMD, + &counter_type); + verify(piglit_check_gl_error(GL_NO_ERROR)); + + glGetPerfMonitorCounterInfoAMD(group_id, counter_id, + GL_COUNTER_RANGE_AMD, + range); + verify(piglit_check_gl_error(GL_NO_ERROR)); + + /* Make sure it falls within the proper range */ + switch (counter_type) { + case GL_UNSIGNED_INT: { + uint32_t min = ((uint32_t *) range)[0]; + uint32_t max = ((uint32_t *) range)[1]; + verify(u32 >= min); + verify(u32 <= max); + break; + } + case GL_UNSIGNED_INT64_AMD: { + verify(u64 >= range[0]); + verify(u64 <= range[1]); + break; + } + case GL_PERCENTAGE_AMD: + case GL_FLOAT: { + float min = ((float *) range)[0]; + float max = ((float *) range)[1]; + verify(f >= min); + verify(f <= max); + break; + } + } + + p += (counter_type == GL_UNSIGNED_INT64_AMD) ? 4 : 3; + } + verify(result_size == ((char *) p - (char *) data)); + + free(data); + + /** + * Test #3: Changing the set of active counters resets queries. + * + * "When SelectPerfMonitorCountersAMD is called on a monitor, any + * outstanding results for that monitor become invalidated and the + * result queries PERFMON_RESULT_SIZE_AMD and + * PERFMON_RESULT_AVAILABLE_AMD are reset to 0." + */ + test_name = "selecting counters resets queries"; + + /* Turn off the first counter. */ + glSelectPerfMonitorCountersAMD(monitor, false, group, 1, counters); + verify(piglit_check_gl_error(GL_NO_ERROR)); + + /* Results should no longer be available. All queries should + * return 0. + */ + value = 0xd0d0d0d0; + glGetPerfMonitorCounterDataAMD(monitor, GL_PERFMON_RESULT_AVAILABLE_AMD, + sizeof(unsigned), &value, NULL); + verify(piglit_check_gl_error(GL_NO_ERROR)); + verify(value == 0); + + value = 0xd0d0d0d0; + glGetPerfMonitorCounterDataAMD(monitor, GL_PERFMON_RESULT_SIZE_AMD, + sizeof(unsigned), &value, NULL); + verify(piglit_check_gl_error(GL_NO_ERROR)); + verify(value == 0); + + piglit_report_subtest_result(PIGLIT_PASS, test_name); + + glDeletePerfMonitorsAMD(1, &monitor); +} + + +/** + * Make sure that calling SelectPerfMonitorCountersAMD on an active monitor + * is possible, resets active queries, and restarts monitoring (so it remains + * active). + * + * This is not actually specified, but matches the behavior of AMD's driver. + * Being an AMD extension, other implementations should probably match theirs. + */ +static void +test_change_counters_while_active(unsigned group) +{ + unsigned monitor; + unsigned *counters; + int num_counters; + int max_active_counters; + unsigned usable_counters; + unsigned data; + const char *test_name = "change counters while active"; + + get_counters(group, &counters, &num_counters, + &max_active_counters); + verify(max_active_counters >= 0); + verify(piglit_check_gl_error(GL_NO_ERROR)); + + usable_counters = MIN2(num_counters, max_active_counters); + + if (usable_counters == 0) + return; /* skip */ + + glGenPerfMonitorsAMD(1, &monitor); + verify(piglit_check_gl_error(GL_NO_ERROR)); + + /* Enable counters 0 .. usable_counters from the list. */ + glSelectPerfMonitorCountersAMD(monitor, true, group, usable_counters, + counters); + verify(piglit_check_gl_error(GL_NO_ERROR)); + + /* Start monitoring */ + glBeginPerfMonitorAMD(monitor); + verify(piglit_check_gl_error(GL_NO_ERROR)); + + /* Turn off the first counter. The specification is unclear whether + * or not this should be allowed while monitoring is active, but it + * apparently is (Catalyst 12.06 on a Radeon 3650). + */ + glSelectPerfMonitorCountersAMD(monitor, false, group, 1, counters); + verify(piglit_check_gl_error(GL_NO_ERROR)); + + /* Verify that all queries have been reset to 0 */ + data = 0xd0d0d0d0; + glGetPerfMonitorCounterDataAMD(monitor, GL_PERFMON_RESULT_AVAILABLE_AMD, + sizeof(unsigned), &data, NULL); + verify(piglit_check_gl_error(GL_NO_ERROR)); + verify(data == 0); + + data = 0xd0d0d0d0; + glGetPerfMonitorCounterDataAMD(monitor, GL_PERFMON_RESULT_SIZE_AMD, + sizeof(unsigned), &data, NULL); + verify(piglit_check_gl_error(GL_NO_ERROR)); + verify(data == 0); + + /* The spec doesn't explicitly mention whether or not monitoring + * is still active, but apparently it is. + */ + glEndPerfMonitorAMD(monitor); + verify(piglit_check_gl_error(GL_NO_ERROR)); + + glDeletePerfMonitorsAMD(1, &monitor); + verify(piglit_check_gl_error(GL_NO_ERROR)); + + piglit_report_subtest_result(PIGLIT_PASS, test_name); +} + + +/******************************************************************************/ + +enum piglit_result +piglit_display(void) +{ + return PIGLIT_FAIL; +} + +/** + * The main test program. + */ +void +piglit_init(int argc, char **argv) +{ + unsigned *groups; + int num_groups; + + piglit_require_extension("GL_AMD_performance_monitor"); + + /* Basic glGetPerfMonitorGroupsAMD() tests */ + get_groups(&groups, &num_groups); + + /* If there are no groups, the rest of the tests can't run. Bail. */ + if (num_groups == 0) + exit(0); + + test_basic_measurement(groups[0]); + test_change_counters_while_active(groups[0]); + + exit(0); +} |