[3/3] Add tests for the INTEL_performance_query extension.

Submitted by Petri Latvala on March 12, 2014, 12:53 p.m.

Details

Message ID 1394628833-6536-4-git-send-email-petri.latvala@intel.com
State New
Headers show

Not browsing as part of any series.

Commit Message

Petri Latvala March 12, 2014, 12:53 p.m.
As with AMD_performance_monitor, 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 query, while a few sanity check
all counters in all queries.

Signed-off-by: Petri Latvala <petri.latvala@intel.com>
---
 tests/all.py                                       |   6 +
 tests/spec/CMakeLists.txt                          |   1 +
 .../spec/intel_performance_query/CMakeLists.gl.txt |  14 +
 tests/spec/intel_performance_query/CMakeLists.txt  |   1 +
 tests/spec/intel_performance_query/api.c           | 808 +++++++++++++++++++++
 tests/spec/intel_performance_query/measure.c       | 294 ++++++++
 tests/spec/intel_performance_query/minmax.c        |  58 ++
 7 files changed, 1182 insertions(+)
 create mode 100644 tests/spec/intel_performance_query/CMakeLists.gl.txt
 create mode 100644 tests/spec/intel_performance_query/CMakeLists.txt
 create mode 100644 tests/spec/intel_performance_query/api.c
 create mode 100644 tests/spec/intel_performance_query/measure.c
 create mode 100644 tests/spec/intel_performance_query/minmax.c

Patch hide | download patch | download mbox

diff --git a/tests/all.py b/tests/all.py
index 1e1aa3d..ba1eb56 100644
--- a/tests/all.py
+++ b/tests/all.py
@@ -1425,6 +1425,12 @@  import_glsl_parser_tests(spec['AMD_shader_trinary_minmax'],
 			 os.path.join(testsDir, 'spec', 'amd_shader_trinary_minmax'),
 			 [''])
 
+# Group INTEL_performance_query
+spec['INTEL_performance_query'] = Group()
+profile.test_list['spec/INTEL_performance_query/api'] = PlainExecTest('intel_performance_query_api -auto')
+profile.test_list['spec/INTEL_performance_query/measure'] = PlainExecTest('intel_performance_query_measure -auto')
+profile.test_list['spec/INTEL_performance_query/minmax'] = PlainExecTest('intel_performance_query_minmax')
+
 # Group ARB_point_sprite
 arb_point_sprite = Group()
 spec['ARB_point_sprite'] = arb_point_sprite
diff --git a/tests/spec/CMakeLists.txt b/tests/spec/CMakeLists.txt
index 0a513c1..037653e 100644
--- a/tests/spec/CMakeLists.txt
+++ b/tests/spec/CMakeLists.txt
@@ -100,3 +100,4 @@  add_subdirectory (ext_image_dma_buf_import)
 add_subdirectory (arb_blend_func_extended)
 add_subdirectory (ext_unpack_subimage)
 add_subdirectory (arb_vertex_array_object)
+add_subdirectory (intel_performance_query)
diff --git a/tests/spec/intel_performance_query/CMakeLists.gl.txt b/tests/spec/intel_performance_query/CMakeLists.gl.txt
new file mode 100644
index 0000000..7d10e0b
--- /dev/null
+++ b/tests/spec/intel_performance_query/CMakeLists.gl.txt
@@ -0,0 +1,14 @@ 
+include_directories(
+	${GLEXT_INCLUDE_DIR}
+	${OPENGL_INCLUDE_PATH}
+)
+
+link_libraries (
+	piglitutil_${piglit_target_api}
+	${OPENGL_gl_LIBRARY}
+	${OPENGL_glu_LIBRARY}
+)
+
+piglit_add_executable (intel_performance_query_api api.c)
+piglit_add_executable (intel_performance_query_minmax minmax.c)
+piglit_add_executable (intel_performance_query_measure measure.c)
diff --git a/tests/spec/intel_performance_query/CMakeLists.txt b/tests/spec/intel_performance_query/CMakeLists.txt
new file mode 100644
index 0000000..144a306
--- /dev/null
+++ b/tests/spec/intel_performance_query/CMakeLists.txt
@@ -0,0 +1 @@ 
+piglit_include_target_api()
diff --git a/tests/spec/intel_performance_query/api.c b/tests/spec/intel_performance_query/api.c
new file mode 100644
index 0000000..afb7fcb
--- /dev/null
+++ b/tests/spec/intel_performance_query/api.c
@@ -0,0 +1,808 @@ 
+/*
+ * Copyright © 2014 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 api.c
+ *
+ * Basic INTEL_performance_query infrastructure tests.  These test the
+ * mechanism to retrieve counter and query information, string
+ * processing, and various error conditions.  They do not actually
+ * activate monitoring.
+ */
+
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+#include "piglit-util-gl-common.h"
+
+PIGLIT_GL_TEST_CONFIG_BEGIN
+
+	config.supports_gl_compat_version = 30;
+	config.supports_gl_es_version = 20;
+	config.window_visual = PIGLIT_GL_VISUAL_RGB;
+
+PIGLIT_GL_TEST_CONFIG_END
+
+/******************************************************************************/
+
+/**
+ * Get a list of query IDs.
+ */
+static void
+get_queries(GLuint ** queries, unsigned *num_queries)
+{
+	GLuint queryid;
+	unsigned i;
+
+	/* Enumerate all query ids first to get their count */
+	*num_queries = 0;
+	for (glGetFirstPerfQueryIdINTEL(&queryid);
+	     queryid != 0;
+	     glGetNextPerfQueryIdINTEL(queryid, &queryid)) {
+		++(*num_queries);
+	}
+
+	*queries = calloc(*num_queries, sizeof(unsigned));
+
+	/* And now collect them */
+	i = 0;
+	for (glGetFirstPerfQueryIdINTEL(&queryid);
+	     queryid != 0;
+	     glGetNextPerfQueryIdINTEL(queryid, &queryid)) {
+		(*queries)[i++] = queryid;
+	}
+}
+
+/**
+ * Get a list of counter IDs in a given query.
+ */
+static void
+get_counters(GLuint query, GLuint ** counters, unsigned *num_counters)
+{
+	unsigned i;
+
+	glGetPerfQueryInfoINTEL(query, 0, NULL, NULL,
+				num_counters, NULL, NULL);
+
+	/* Counters start from 1 and are continuous */
+	*counters = calloc(*num_counters, sizeof(unsigned));
+	for (i = 0; i < *num_counters; ++i) {
+		(*counters)[i] = i + 1;
+	}
+}
+
+/**
+ * Return true if x is in xs.
+ */
+static bool
+in_list(int x, unsigned *xs, int elts)
+{
+	int i;
+	for (i = 0; i < elts; ++i) {
+		if (x == xs[i])
+			return true;
+	}
+	return false;
+}
+
+/**
+ * Find an invalid query ID.
+ */
+static GLuint
+find_invalid_query(unsigned *queries, int num_queries)
+{
+	unsigned invalid_query = ~0;
+
+	/* Most implementations probably use small consecutive integers, so
+	 * start at ~0 and work backwards.  Hopefully we shouldn't loop.
+	 */
+	while (in_list(invalid_query, queries, num_queries))
+		--invalid_query;
+
+	return invalid_query;
+}
+
+/**
+ * Find an invalid counter ID.
+ */
+static unsigned
+find_invalid_counter(unsigned *counters, int num_counters)
+{
+	unsigned invalid_counter = ~0;
+
+	/* Most implementations probably use small consecutive integers, so
+	 * start at ~0 and work backwards.  Hopefully we shouldn't loop.
+	 */
+	while (in_list(invalid_counter, counters, num_counters))
+		--invalid_counter;
+
+	return invalid_counter;
+}
+
+#define report(pass) \
+	do { \
+		piglit_report_subtest_result((pass) ? \
+		PIGLIT_PASS : PIGLIT_FAIL, __FUNCTION__); \
+		return; \
+	} while (0)
+
+/******************************************************************************/
+
+/** Call glGetFirstPerfQueryIdINTEL() with a NULL queryId pointer.
+ *
+ * Verify that it doesn't attempt to write the query id and crash.
+ */
+static void
+test_first_query_null_queryid_pointer(void)
+{
+	glGetFirstPerfQueryIdINTEL(NULL);
+	report(piglit_check_gl_error(GL_INVALID_VALUE));
+}
+
+/******************************************************************************/
+
+/** Call glGetNextPerfQueryIdINTEL() with a NULL nextQueryId.
+ *
+ * Verify that it doesn't attempt to write the query id and crash.
+ */
+static void
+test_next_query_null_nextqueryid_pointer(unsigned validquery)
+{
+	glGetNextPerfQueryIdINTEL(validquery, NULL);
+	report(piglit_check_gl_error(GL_INVALID_VALUE));
+}
+
+/** Call glGetNextPerfQueryIdINTEL() with an invalid query id.
+ *
+ * Verify that it produces INVALID_VALUE.
+ */
+static void
+test_next_query_invalid_queryid(unsigned invalidquery)
+{
+	unsigned dummy;
+
+	glGetNextPerfQueryIdINTEL(invalidquery, &dummy);
+	report(piglit_check_gl_error(GL_INVALID_VALUE));
+}
+
+/******************************************************************************/
+
+/** Call glGetPerfQueryIdByNameINTEL() with a NULL query id pointer.
+ *
+ * Verify that it doesn't attempt to write a query id and crash.
+ */
+static void
+test_get_query_by_name_null_queryid_pointer(const char *validname)
+{
+	glGetPerfQueryIdByNameINTEL(validname, NULL);
+	/* The specification does not say that this should produce an error. */
+}
+
+/** Call glGetPerfQueryIdByNameINTEL() with a NULL name pointer.
+ *
+ * Verify that it doesn't attempt to read the name and crash.
+ */
+static void
+test_get_query_by_name_null_name_pointer(void)
+{
+	unsigned dummy;
+
+	glGetPerfQueryIdByNameINTEL(NULL, &dummy);
+	report(piglit_check_gl_error(GL_INVALID_VALUE));
+}
+
+/** Call glGetPerfQueryIdByNameINTEL() with an invalid name.
+ *
+ * Verify that it produces INVALID_VALUE.
+ */
+static void
+test_get_query_by_name_invalid_name(const char *invalidname)
+{
+	unsigned dummy;
+
+	glGetPerfQueryIdByNameINTEL(invalidname, &dummy);
+	report(piglit_check_gl_error(GL_INVALID_VALUE));
+}
+
+/******************************************************************************/
+
+/** Call glGetPerfQueryInfoINTEL() with an invalid query id.
+ *
+ * Verify that it produces INVALID_VALUE.
+ */
+static void
+test_get_perf_query_info_invalid_queryid(unsigned invalidquery)
+{
+	char name[256];
+	GLuint datasize;
+	GLuint counters;
+	GLuint instances;
+	GLuint caps;
+
+	glGetPerfQueryInfoINTEL(invalidquery,
+				sizeof(name), name,
+				&datasize, &counters, &instances, &caps);
+	report(piglit_check_gl_error(GL_INVALID_VALUE));
+}
+
+/** Call glGetPerfQueryInfoINTEL() with NULL pointers.
+ *
+ * Verify that it doesn't attempt to write data to them and crash.
+ * Verify that it doesn't produce an error.
+ */
+static void
+test_get_perf_query_info_null_pointers(unsigned validquery)
+{
+	glGetPerfQueryInfoINTEL(validquery, 0, NULL, NULL, NULL, NULL, NULL);
+	report(piglit_check_gl_error(GL_NO_ERROR));
+}
+
+/** Call glGetPerfQueryInfoINTEL() with a single character buffer.
+ *
+ * Verify that length is correct, the string is zero-terminated,
+ * and no buffer overflows occur.
+ */
+static void
+test_get_perf_query_info_single_character_buffer(unsigned validquery)
+{
+	char name[3] = "```";
+	bool pass = true;
+
+	glGetPerfQueryInfoINTEL(validquery, 1, name, NULL, NULL, NULL, NULL);
+	pass = piglit_check_gl_error(GL_NO_ERROR);
+
+	/* Verify buffer contents: only the first character should change,
+	 * and it should be the terminator.
+	 */
+	pass = name[0] == '\0' && pass;
+	pass = name[1] == '`' && pass;
+	pass = name[2] == '`' && pass;
+
+	report(pass);
+}
+
+/******************************************************************************/
+
+/** Call glGetPerfCounterInfoINTEL() with an invalid query id.
+ *
+ * Verify that it produces INVALID_VALUE.
+ */
+static void
+test_get_perf_counter_info_invalid_queryid(unsigned invalidquery)
+{
+	char name[256];
+	char desc[1024];
+	GLuint offset;
+	GLuint datasize;
+	GLuint type;
+	GLuint datatype;
+	GLuint64 maxvalue;
+
+	/* 1 is a valid counter ID */
+	glGetPerfCounterInfoINTEL(invalidquery, 1,
+				  sizeof(name), name,
+				  sizeof(desc), desc,
+				  &offset, &datasize, &type,
+				  &datatype, &maxvalue);
+	report(piglit_check_gl_error(GL_INVALID_VALUE));
+}
+
+/** Call glGetPerfCounterInfoINTEL() with a valid query id but invalid
+ * counter id.
+ *
+ * Verify that it produces INVALID_VALUE.
+ */
+static void
+test_get_perf_counter_info_invalid_counterid(unsigned validquery,
+					     unsigned invalidcounter)
+{
+	char name[256];
+	char desc[1024];
+	GLuint offset;
+	GLuint datasize;
+	GLuint type;
+	GLuint datatype;
+	GLuint64 maxvalue;
+
+	glGetPerfCounterInfoINTEL(validquery, invalidcounter,
+				  sizeof(name), name,
+				  sizeof(desc), desc,
+				  &offset, &datasize, &type,
+				  &datatype, &maxvalue);
+	report(piglit_check_gl_error(GL_INVALID_VALUE));
+}
+
+/** Call glGetPerfCounterInfoINTEL() with NULL pointers.
+ *
+ * Verify that it doesn't attempt to write data to them and crash.
+ * Verify that it doesn't produce an error.
+ */
+static void
+test_get_perf_counter_info_null_pointers(unsigned validquery,
+					 unsigned validcounter)
+{
+	glGetPerfCounterInfoINTEL(validquery, validcounter,
+				  0, NULL,
+				  0, NULL, NULL, NULL, NULL, NULL, NULL);
+	report(piglit_check_gl_error(GL_NO_ERROR));
+}
+
+/** Call glGetPerfCounterInfoINTEL() with single character buffers.
+ *
+ * Verify that length is correct, the string is zero-terminated,
+ * and no buffer overflows occur.
+ */
+static void
+test_get_perf_counter_info_single_character_buffer(unsigned validquery,
+						   unsigned validcounter)
+{
+	char name[3] = "```";
+	char desc[3] = "```";
+	bool pass = true;
+
+	glGetPerfCounterInfoINTEL(validquery, validcounter,
+				  1, name,
+				  1, desc, NULL, NULL, NULL, NULL, NULL);
+	pass = piglit_check_gl_error(GL_NO_ERROR);
+
+	/* Verify buffer contents: only the first character should change,
+	 * and it should be the terminator.
+	 */
+	pass = name[0] == '\0' && pass;
+	pass = name[1] == '`' && pass;
+	pass = name[2] == '`' && pass;
+
+	pass = desc[0] == '\0' && pass;
+	pass = desc[1] == '`' && pass;
+	pass = desc[2] == '`' && pass;
+
+	report(pass);
+}
+
+/**
+ * Call glGetPerfQueryInfoINTEL() on every query and verify that all
+ * queries have a valid capsMask value.
+ */
+static void
+test_query_info(unsigned *queries, unsigned num_queries)
+{
+	int i;
+
+	for (i = 0; i < num_queries; ++i) {
+		char name[256];
+		GLuint datasize;
+		GLuint counters;
+		GLuint instances;
+		GLuint caps;
+
+		glGetPerfQueryInfoINTEL(queries[i],
+					sizeof(name), name,
+					&datasize, &counters,
+					&instances, &caps);
+
+		if (caps != GL_PERFQUERY_SINGLE_CONTEXT_INTEL &&
+		    caps != GL_PERFQUERY_GLOBAL_CONTEXT_INTEL) {
+			printf("Query %u has an invalid capability mask: %x\n",
+			       queries[i], caps);
+			report(false);
+			break;
+		}
+	}
+
+	report(true);
+}
+
+/**
+ * Call glGetPerfCounterInfoINTEL() on every query/counter pair and verify that
+ * all counters have a valid type and datatype.
+ */
+static void
+test_counter_info(unsigned *queries, unsigned num_queries)
+{
+	int i;
+	int j;
+
+	for (i = 0; i < num_queries; ++i) {
+		unsigned *counters;
+		unsigned num_counters;
+		get_counters(queries[i], &counters, &num_counters);
+
+		if (!piglit_automatic) {
+			char queryname[256];
+
+			glGetPerfQueryInfoINTEL(queries[i], sizeof(queryname),
+						queryname, NULL, NULL, NULL,
+						NULL);
+			printf("Query %u [%s]:\n", queries[i], queryname);
+		}
+
+		for (j = 0; j < num_counters; ++j) {
+			char name[256];
+			char desc[1024];
+			GLuint offset;
+			GLuint datasize;
+			GLuint type;
+			GLuint datatype;
+			GLuint64 maxvalue;
+
+			memset(name, 0, sizeof(name));
+			memset(desc, 0, sizeof(desc));
+
+			glGetPerfCounterInfoINTEL(queries[i], counters[j],
+						  sizeof(name), name,
+						  sizeof(desc), desc,
+						  &offset, &datasize, &type,
+						  &datatype, &maxvalue);
+
+			if (!piglit_automatic)
+				printf(" Counter %u [%s]: %s\n", counters[j],
+				       name, desc);
+
+			switch (datatype) {
+			default:
+				printf("Query %u/Counter %u has an invalid datatype: %x\n",
+				       queries[i], counters[j], datatype);
+				report(false);
+				break;
+			case GL_PERFQUERY_COUNTER_DATA_UINT32_INTEL:
+			case GL_PERFQUERY_COUNTER_DATA_UINT64_INTEL:
+			case GL_PERFQUERY_COUNTER_DATA_FLOAT_INTEL:
+			case GL_PERFQUERY_COUNTER_DATA_DOUBLE_INTEL:
+			case GL_PERFQUERY_COUNTER_DATA_BOOL32_INTEL:
+				break;
+			}
+
+			switch (type) {
+			default:
+				printf("Query %u/Counter %u has an invalid type: %x\n",
+				       queries[i], counters[j], type);
+				report(false);
+				break;
+			case GL_PERFQUERY_COUNTER_EVENT_INTEL:
+			case GL_PERFQUERY_COUNTER_DURATION_NORM_INTEL:
+			case GL_PERFQUERY_COUNTER_DURATION_RAW_INTEL:
+			case GL_PERFQUERY_COUNTER_THROUGHPUT_INTEL:
+			case GL_PERFQUERY_COUNTER_RAW_INTEL:
+			case GL_PERFQUERY_COUNTER_TIMESTAMP_INTEL:
+				break;
+			}
+		}
+		free(counters);
+	}
+
+	report(true);
+}
+
+/******************************************************************************/
+
+/**
+ * Call glBeginPerfQueryINTEL() on an invalid query handle.
+ * (Should be run before any Gen tests to ensure this handle is invalid.)
+ *
+ * Verify that it produces INVALID_VALUE.
+ */
+void
+test_begin_invalid_query_handle(void)
+{
+	glBeginPerfQueryINTEL(777);
+	report(piglit_check_gl_error(GL_INVALID_VALUE));
+}
+
+/**
+ * Call glEndPerfQueryINTEL() on an invalid query handle.
+ * (Should be run before any Gen tests to ensure this ID is invalid.)
+ *
+ * Verify that it produces INVALID_VALUE or INVALID_OPERATION.
+ * XXX: Only INVALID_OPERATION is actually specified, assume
+ * INVALID_VALUE can also be generated.
+ */
+void
+test_end_invalid_query_handle(void)
+{
+	GLenum error;
+	glEndPerfQueryINTEL(777);
+	error = glGetError();
+	report(error == GL_INVALID_VALUE || error == GL_INVALID_OPERATION);
+}
+
+/**
+ * Call glCreatePerfQueryINTEL() with an invalid query id.
+ *
+ * Verify that it produces INVALID_VALUE.
+ */
+static void
+test_create_perf_query_invalid_query(unsigned invalidquery)
+{
+	GLuint handle;
+	glCreatePerfQueryINTEL(invalidquery, &handle);
+	report(piglit_check_gl_error(GL_INVALID_VALUE));
+}
+
+/**
+ * Call glCreatePerfQueryINTEL() with a NULL queryhandle pointer.
+ *
+ * Verify that it doesn't attempt to write a handle and crash,
+ * and produces INVALID_VALUE.
+ * XXX: This isn't actually specified, but it seems like it ought to be.
+ */
+static void
+test_create_perf_query_null_handle_pointer(unsigned validquery)
+{
+	glCreatePerfQueryINTEL(validquery, NULL);
+	report(piglit_check_gl_error(GL_INVALID_VALUE));
+}
+
+/**
+ * Call glDeletePerfQueryINTEL() with an invalid query handle.
+ *
+ * Verify that it produces INVALID_VALUE.
+ */
+static void
+test_delete_perf_query_invalid_handle(void)
+{
+	glDeletePerfQueryINTEL(777);
+	report(piglit_check_gl_error(GL_INVALID_VALUE));
+}
+
+/**
+ * Call glGetPerfQueryDataINTEL() with an invalid query handle.
+ * (Should be run before any Gen tests to ensure this ID is invalid.)
+ *
+ * Verify that it produces INVALID_VALUE.
+ * XXX: This isn't actually specified, but it seems like it ought to be.
+ */
+static void
+test_get_query_data_invalid_query_handle(void)
+{
+	char data[1024];
+	GLuint bytes;
+	glGetPerfQueryDataINTEL(777, GL_PERFQUERY_DONOT_FLUSH_INTEL,
+				sizeof(data), data, &bytes);
+	report(piglit_check_gl_error(GL_INVALID_VALUE));
+}
+
+/**
+ * Call glGetPerfQueryDataINTEL() with a NULL data pointer.
+ *
+ * Verify that it doesn't attempt to write data and crash, and
+ * produces INVALID_VALUE.
+ */
+static void
+test_get_query_data_null_data_pointer(void)
+{
+	GLuint query;
+	GLuint handle;
+	GLuint bytes;
+
+	glGetFirstPerfQueryIdINTEL(&query);
+	glCreatePerfQueryINTEL(query, &handle);
+
+	glGetPerfQueryDataINTEL(handle, GL_PERFQUERY_DONOT_FLUSH_INTEL,
+				128, NULL, &bytes);
+	report(piglit_check_gl_error(GL_INVALID_VALUE));
+}
+
+/**
+ * Call glGetPerfQueryDataINTEL() with a NULL byteswritten pointer.
+ *
+ * Verify that it doesn't attempt to write data and crash, and
+ * produces INVALID_VALUE.
+ */
+static void
+test_get_query_data_null_byteswritten_pointer(void)
+{
+	GLuint query;
+	GLuint handle;
+	char data[1024];
+
+	glGetFirstPerfQueryIdINTEL(&query);
+	glCreatePerfQueryINTEL(query, &handle);
+
+	glGetPerfQueryDataINTEL(handle, GL_PERFQUERY_DONOT_FLUSH_INTEL,
+				sizeof(data), data, NULL);
+	report(piglit_check_gl_error(GL_INVALID_VALUE));
+}
+
+/**
+ * Call glGetPerfQueryDataINTEL on a query handle that hasn't been started.
+ *
+ * Verify that no data is written in such case.
+ */
+static void
+test_initial_state(void)
+{
+	bool pass = true;
+	unsigned query;
+	unsigned handle;
+	unsigned bytes = 0xd0d0d0d0;
+	char data[1024];
+
+	glGetFirstPerfQueryIdINTEL(&query);
+	glCreatePerfQueryINTEL(query, &handle);
+	pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
+
+	memset(data, '`', sizeof(data));
+
+	glGetPerfQueryDataINTEL(handle, GL_PERFQUERY_DONOT_FLUSH_INTEL,
+				sizeof(data), data, &bytes);
+	pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
+
+	pass = bytes == 0 && pass;
+	pass = data[0] == '`' && pass;
+
+	glDeletePerfQueryINTEL(handle);
+	report(pass);
+}
+
+/**
+ * "If a performance query is not currently started, an
+ * INVALID_OPERATION error will be generated."
+ */
+static void
+test_end_without_begin(void)
+{
+	bool pass = true;
+	unsigned query;
+	unsigned handle;
+
+	glGetFirstPerfQueryIdINTEL(&query);
+	glCreatePerfQueryINTEL(query, &handle);
+	pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
+
+	glEndPerfQueryINTEL(handle);
+	report(piglit_check_gl_error(GL_INVALID_OPERATION));
+
+	glDeletePerfQueryINTEL(handle);
+}
+
+/**
+ * "Note that some query types, they cannot be collected in the same
+ * time. Therefore calls of BeginPerfQueryINTEL() cannot be nested if
+ * they refer to queries of such different types. In such case
+ * INVALID_OPERATION error is generated."
+ *
+ * Impossible to know for sure which different queries cannot be used
+ * at the same time.  Assume that the same query cannot be started
+ * twice, so verify that calling Begin twice on the same query
+ * produces INVALID_OPERATION.
+ */
+static void
+test_double_begin(void)
+{
+	bool pass = true;
+	unsigned query;
+	unsigned handle;
+	GLenum error;
+
+	glGetFirstPerfQueryIdINTEL(&query);
+	glCreatePerfQueryINTEL(query, &handle);
+	pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
+
+	glBeginPerfQueryINTEL(handle);
+
+	error = glGetError();
+	if (error != GL_NO_ERROR) {
+		glDeletePerfQueryINTEL(handle);
+		/* Query couldn't start for some reason; bail. */
+		if (error == GL_INVALID_OPERATION)
+			return;
+		/* We weren't expecting this other error. */
+		report(false);
+	}
+
+	/* Double begin */
+	glBeginPerfQueryINTEL(handle);
+	pass = piglit_check_gl_error(GL_INVALID_OPERATION) && pass;
+
+	glDeletePerfQueryINTEL(handle);
+	report(pass);
+}
+
+/******************************************************************************/
+
+enum piglit_result
+piglit_display(void)
+{
+	return PIGLIT_FAIL;
+}
+
+/**
+ * The main test program.
+ */
+void
+piglit_init(int argc, char **argv)
+{
+	unsigned *queries;
+	unsigned num_queries;
+	unsigned *counters;
+	unsigned num_counters;
+	unsigned invalid_query;
+	unsigned valid_query;
+	unsigned invalid_counter;
+	unsigned valid_counter;
+	char valid_name[256];
+
+	piglit_require_extension("GL_INTEL_performance_query");
+
+	test_first_query_null_queryid_pointer();
+
+	get_queries(&queries, &num_queries);
+
+	/* If there are no valid queries, the rest of the tests can't run.
+	 * Bail.
+	 */
+	if (num_queries == 0)
+		exit(0);
+
+	invalid_query = find_invalid_query(queries, num_queries);
+	valid_query = queries[0];
+
+	test_next_query_null_nextqueryid_pointer(valid_query);
+	test_next_query_invalid_queryid(invalid_query);
+
+	glGetPerfQueryInfoINTEL(valid_query, sizeof(valid_name), valid_name,
+				NULL, NULL, NULL, NULL);
+
+	test_get_query_by_name_null_queryid_pointer(valid_name);
+	test_get_query_by_name_null_name_pointer();
+	test_get_query_by_name_invalid_name
+		("We assume this is an invalid name of a query");
+	test_get_perf_query_info_invalid_queryid(invalid_query);
+	test_get_perf_query_info_null_pointers(valid_query);
+	test_get_perf_query_info_single_character_buffer(valid_query);
+	test_get_perf_counter_info_invalid_queryid(invalid_query);
+
+	get_counters(valid_query, &counters, &num_counters);
+
+	/* If there are no counters, the rest of the tests can't run.
+	 * Bail.
+	 */
+	if (num_counters == 0)
+		exit(0);
+
+	invalid_counter = find_invalid_counter(counters, num_counters);
+	valid_counter = counters[0];
+
+	test_get_perf_counter_info_invalid_counterid(valid_query,
+						     invalid_counter);
+	test_get_perf_counter_info_null_pointers(valid_query, valid_counter);
+	test_get_perf_counter_info_single_character_buffer(valid_query,
+							   valid_counter);
+	test_query_info(queries, num_queries);
+	test_counter_info(queries, num_queries);
+	test_begin_invalid_query_handle();
+	test_end_invalid_query_handle();
+	test_create_perf_query_invalid_query(invalid_query);
+	test_create_perf_query_null_handle_pointer(valid_query);
+	test_delete_perf_query_invalid_handle();
+	test_get_query_data_invalid_query_handle();
+	test_get_query_data_null_data_pointer();
+	test_get_query_data_null_byteswritten_pointer();
+	test_initial_state();
+	test_end_without_begin();
+	test_double_begin();
+
+	free(counters);
+	free(queries);
+
+	exit(0);
+}
diff --git a/tests/spec/intel_performance_query/measure.c b/tests/spec/intel_performance_query/measure.c
new file mode 100644
index 0000000..e11b5f7
--- /dev/null
+++ b/tests/spec/intel_performance_query/measure.c
@@ -0,0 +1,294 @@ 
+/*
+ * Copyright © 2014 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 INTEL_performance_query 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 = 30;
+	config.supports_gl_es_version = 20;
+	config.window_visual = PIGLIT_GL_VISUAL_RGB;
+
+PIGLIT_GL_TEST_CONFIG_END
+
+/******************************************************************************/
+
+/**
+ * Get a list of query IDs.
+ */
+static void
+get_queries(unsigned **queries, unsigned *num_queries)
+{
+	unsigned queryid;
+	unsigned i;
+
+	/* Enumerate all query ids first to get their count */
+	*num_queries = 0;
+	for (glGetFirstPerfQueryIdINTEL(&queryid);
+	     queryid != 0;
+	     glGetNextPerfQueryIdINTEL(queryid, &queryid)) {
+		++(*num_queries);
+	}
+
+	*queries = calloc(*num_queries, sizeof(unsigned));
+
+	/* And now collect them */
+	i = 0;
+	for (glGetFirstPerfQueryIdINTEL(&queryid);
+	     queryid != 0;
+	     glGetNextPerfQueryIdINTEL(queryid, &queryid)) {
+		(*queries)[i++] = queryid;
+	}
+}
+
+/**
+ * Get a list of counter IDs in a given query.
+ */
+static void
+get_counters(unsigned query, unsigned **counters, unsigned *num_counters)
+{
+	unsigned i;
+
+	glGetPerfQueryInfoINTEL(query, 0, NULL, NULL,
+				num_counters, NULL, NULL);
+
+	/* Counters start from 1 and are continuous */
+	*counters = calloc(*num_counters, sizeof(unsigned));
+	for (i = 0; i < *num_counters; ++i) {
+		(*counters)[i] = i + 1;
+	}
+}
+
+/**
+ * Get the size of a counter value of a given datatype enum in bytes.
+ */
+static unsigned
+value_size(GLuint datatype)
+{
+	switch (datatype) {
+	default:
+		/* Return 0 so the caller can report correct data to piglit. */
+		return 0;
+	case GL_PERFQUERY_COUNTER_DATA_UINT32_INTEL:
+	case GL_PERFQUERY_COUNTER_DATA_FLOAT_INTEL:
+	case GL_PERFQUERY_COUNTER_DATA_BOOL32_INTEL:
+		return sizeof(uint32_t);
+	case GL_PERFQUERY_COUNTER_DATA_UINT64_INTEL:
+	case GL_PERFQUERY_COUNTER_DATA_DOUBLE_INTEL:
+		return sizeof(uint64_t);
+	}
+}
+
+#define verify(x)						\
+  if (!(x)) {							\
+    piglit_report_subtest_result(PIGLIT_FAIL, "%s", test_name); \
+    return;                                                     \
+  }
+
+/******************************************************************************/
+
+/**
+ * Basic functional test: create a query of the first query (this
+ * terminology is too overloaded) begin monitoring, end monitoring,
+ * make sure results are available, sanity check the result size, and
+ * get the results.
+ */
+static void
+test_basic_measurement(unsigned query)
+{
+	unsigned handle;
+	unsigned *counters;
+	unsigned num_counters;
+	unsigned result_size = 0;
+	GLuint bytes_written = 0;
+	char *data;
+	unsigned i;
+
+	const char *test_name;
+
+	/**
+	* Test #1: Initialization
+	*
+	* Begin monitoring, end monitoring.
+	*/
+	test_name = "initialization";
+
+	get_counters(query, &counters, &num_counters);
+	verify(num_counters > 0);
+	verify(piglit_check_gl_error(GL_NO_ERROR));
+
+	glCreatePerfQueryINTEL(query, &handle);
+	verify(piglit_check_gl_error(GL_NO_ERROR));
+
+	/* Start monitoring */
+	glBeginPerfQueryINTEL(handle);
+	verify(piglit_check_gl_error(GL_NO_ERROR));
+
+	/* Drawing...meh */
+	piglit_draw_triangle(0.0, 0.0, 1.0, 1.0, 0.5, 0.5);
+
+	/* End monitoring */
+	glEndPerfQueryINTEL(handle);
+	verify(piglit_check_gl_error(GL_NO_ERROR));
+
+	piglit_report_subtest_result(PIGLIT_PASS, "%s", test_name);
+
+	/**
+	* Test #2: Receiving results
+	*
+	* Grab the data and sanity check its size as much as possible.
+	*/
+
+	test_name = "result retrieval";
+
+	/* Get the result size. */
+	glGetPerfQueryInfoINTEL(query, 0, NULL, &result_size, NULL, NULL,
+				NULL);
+	verify(piglit_check_gl_error(GL_NO_ERROR));
+
+	/* Get the results. */
+
+	/* Allocate more than the query info says, in case the
+	 * implementation lied about the size.
+	 */
+	data = calloc(1, result_size + 32);
+	/* Pass GL_PERFQUERY_WAIT_INTEL which will make the function
+	 * return only when results are available.
+	 */
+	glGetPerfQueryDataINTEL(handle, GL_PERFQUERY_WAIT_INTEL,
+				result_size + 32, data, &bytes_written);
+	verify(piglit_check_gl_error(GL_NO_ERROR));
+	verify(bytes_written == result_size);
+
+	piglit_report_subtest_result(PIGLIT_PASS, "%s", test_name);
+
+	/**
+	* Test #3: Data
+	*
+	* Check that the data sizes and offsets are correct.
+	*/
+	test_name = "data";
+
+	/* Counter values are one of float, double, uint32_t, uint64_t or
+	 * bool32_t. Now, the specification implicitly allows counters to
+	 * alias and extra data to exist between values (GetPerfCounterInfo
+	 * gives counter data offset in bytes) so we don't have many sanity
+	 * checks on the result_size the spec would restrict.
+	 */
+	verify(result_size >= sizeof(uint32_t));
+	verify(result_size % sizeof(uint32_t) == 0);
+
+	for (i = 0; i < num_counters; ++i) {
+		char name[256];
+		GLuint offset;
+		GLuint size;
+		GLuint datatype;
+		glGetPerfCounterInfoINTEL(query, counters[i],
+					  sizeof(name), name,
+					  0, NULL,
+					  &offset, &size,
+					  NULL, &datatype, NULL);
+		verify(piglit_check_gl_error(GL_NO_ERROR));
+		verify(offset + size <= result_size);
+		/* This tests that the datatype enum is valid */
+		verify(value_size(datatype) != 0);
+		/* In theory, the specification allows counter values to be
+		 * _multiple_ values of the reported data type.
+		 */
+		verify(size >= value_size(datatype));
+		verify(size % value_size(datatype) == 0);
+
+		/* Print the counter value for manual inspection. */
+		if (!piglit_automatic) {
+			char *p;
+
+			p = data + offset;
+			printf("%u [%s]: ", i, name);
+			switch (datatype) {
+			case GL_PERFQUERY_COUNTER_DATA_UINT32_INTEL:
+				printf("%" PRIu32 "\n", *((uint32_t *) p));
+				break;
+			case GL_PERFQUERY_COUNTER_DATA_UINT64_INTEL:
+				printf("%" PRIu64 "\n", *((uint64_t *) p));
+				break;
+			case GL_PERFQUERY_COUNTER_DATA_FLOAT_INTEL:
+				printf("%f\n", *((float *) p));
+				break;
+			case GL_PERFQUERY_COUNTER_DATA_DOUBLE_INTEL:
+				printf("%f\n", *((double *) p));
+				break;
+			case GL_PERFQUERY_COUNTER_DATA_BOOL32_INTEL:
+				printf("%" PRIu32 "\n", *((uint32_t *) p));
+				break;
+			default:
+				verify(!"not reached, should have already checked for validity");
+				break;
+			}
+		}
+	}
+
+	piglit_report_subtest_result(PIGLIT_PASS, "%s", test_name);
+
+	free(data);
+
+	glDeletePerfQueryINTEL(handle);
+}
+
+
+/******************************************************************************/
+
+enum piglit_result
+piglit_display(void)
+{
+	return PIGLIT_FAIL;
+}
+
+/**
+ * The main test program.
+ */
+void
+piglit_init(int argc, char **argv)
+{
+	unsigned *queries;
+	unsigned num_queries;
+
+	piglit_require_extension("GL_INTEL_performance_query");
+
+	get_queries(&queries, &num_queries);
+
+	/* If there are no queries, the rest of the tests can't run.  Bail. */
+	if (num_queries == 0)
+		exit(0);
+
+	test_basic_measurement(queries[0]);
+
+	exit(0);
+}
diff --git a/tests/spec/intel_performance_query/minmax.c b/tests/spec/intel_performance_query/minmax.c
new file mode 100644
index 0000000..8258fb6
--- /dev/null
+++ b/tests/spec/intel_performance_query/minmax.c
@@ -0,0 +1,58 @@ 
+/* Copyright © 2014 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.
+ */
+
+#include "piglit-util-gl-common.h"
+#include "minmax-test.h"
+
+PIGLIT_GL_TEST_CONFIG_BEGIN
+
+	config.supports_gl_compat_version = 30;
+	config.supports_gl_es_version = 20;
+
+PIGLIT_GL_TEST_CONFIG_END
+
+enum piglit_result
+piglit_display(void)
+{
+	return PIGLIT_FAIL;
+}
+
+void
+piglit_init(int argc, char **argv)
+{
+	GLboolean extended;
+
+	piglit_require_extension("GL_INTEL_performance_query");
+	piglit_print_minmax_header();
+
+	piglit_test_min_int(GL_PERFQUERY_QUERY_NAME_LENGTH_MAX_INTEL, 256);
+	piglit_test_min_int(GL_PERFQUERY_COUNTER_NAME_LENGTH_MAX_INTEL, 256);
+	piglit_test_min_int(GL_PERFQUERY_COUNTER_DESC_LENGTH_MAX_INTEL, 1024);
+
+	/* No value tested for this */
+	glGetBooleanv(GL_PERFQUERY_GPA_EXTENDED_COUNTERS_INTEL, &extended);
+
+	if (!piglit_check_gl_error(GL_NO_ERROR))
+		piglit_report_result(PIGLIT_FAIL);
+
+	piglit_report_result(piglit_minmax_pass ? PIGLIT_PASS : PIGLIT_FAIL);
+}