xref: /aosp_15_r20/external/igt-gpu-tools/tools/intel_residency.c (revision d83cc019efdc2edc6c4b16e9034a3ceb8d35d77c)
1 /*
2  * Copyright © 2016 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  *
23  * Authors: Paulo Zanoni <[email protected]>
24  *
25  */
26 
27 #include <sys/time.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <fcntl.h>
31 #include <inttypes.h>
32 #include <unistd.h>
33 #include <signal.h>
34 #include <time.h>
35 #include <getopt.h>
36 #include "igt.h"
37 
38 #define IA32_TIME_STAMP_COUNTER		0x10
39 
40 #define MSR_PKG_CST_CONFIG_CONTROL	0xE2
41 #define  PKG_CST_LIMIT_MASK		0x7
42 #define  PKG_CST_LIMIT_C0		0x0
43 #define  PKG_CST_LIMIT_C2		0x1
44 #define  PKG_CST_LIMIT_C3		0x2
45 #define  PKG_CST_LIMIT_C6		0x3
46 #define  PKG_CST_LIMIT_C7		0x4
47 #define  PKG_CST_LIMIT_C7s		0x5
48 #define  PKG_CST_NO_LIMIT		0x7
49 
50 #define MSR_PKG_C2_RESIDENCY		0x60D
51 #define MSR_PKG_C3_RESIDENCY		0x3F8
52 #define MSR_PKG_C6_RESIDENCY		0x3F9
53 #define MSR_PKG_C7_RESIDENCY		0x3FA
54 #define MSR_PKG_C8_RESIDENCY		0x630
55 #define MSR_PKG_C9_RESIDENCY		0x631
56 #define MSR_PKG_C10_RESIDENCY		0x632
57 
58 #define NUM_PC_STATES 7
59 
60 const char *res_msr_names[] = {
61 	"PC2", "PC3", "PC6", "PC7", "PC8", "PC9", "PC10"
62 };
63 
64 const uint32_t res_msr_addrs[] = {
65 	MSR_PKG_C2_RESIDENCY,
66 	MSR_PKG_C3_RESIDENCY,
67 	MSR_PKG_C6_RESIDENCY,
68 	MSR_PKG_C7_RESIDENCY,
69 	MSR_PKG_C8_RESIDENCY,
70 	MSR_PKG_C9_RESIDENCY,
71 	MSR_PKG_C10_RESIDENCY,
72 };
73 
74 int msr_fd;
75 
76 uint32_t deepest_pc_state;
77 uint64_t idle_res;
78 
79 #define MAX_CONNECTORS 32
80 #define MAX_PLANES 32
81 struct {
82 	int fd;
83 	drmModeResPtr res;
84 	drmModeConnectorPtr connectors[MAX_CONNECTORS];
85 	drm_intel_bufmgr *bufmgr;
86 } drm;
87 
88 struct {
89 	uint32_t crtc_id;
90 	uint32_t connector_id;
91 	drmModeModeInfoPtr mode;
92 } modeset;
93 
94 int vblank_interval_us;
95 struct igt_fb fbs[2], cursor, *front_fb, *back_fb;
96 
97 struct {
98 	int draw_size;
99 	bool do_page_flip;
100 	bool do_draw;
101 	bool do_draw_and_flip;
102 	int res_warm_time;
103 	int res_calc_time;
104 	int loop_inc;
105 	char *test_name;
106 } opts = {
107 	.draw_size = 0,
108 	.do_page_flip = true,
109 	.do_draw = true,
110 	.do_draw_and_flip = true,
111 	.res_warm_time = 1,
112 	.res_calc_time = 4,
113 	.loop_inc = 2,
114 	.test_name = NULL,
115 };
116 
msr_read(uint32_t addr)117 static uint64_t msr_read(uint32_t addr)
118 {
119 	int rc;
120 	uint64_t ret;
121 
122 	rc = pread(msr_fd, &ret, sizeof(uint64_t), addr);
123 	igt_assert(rc == sizeof(ret));
124 
125 	return ret;
126 }
127 
setup_msr(void)128 static void setup_msr(void)
129 {
130 #if 0
131 	uint64_t control;
132 	const char *limit;
133 #endif
134 
135 	/* Make sure our Kernel supports MSR and the module is loaded. */
136 	igt_assert(system("modprobe -q msr > /dev/null 2>&1") != -1);
137 
138 	msr_fd = open("/dev/cpu/0/msr", O_RDONLY);
139 	igt_assert_f(msr_fd >= 0,
140 		     "Can't open /dev/cpu/0/msr.\n");
141 
142 #if 0
143 	/* FIXME: why is this code not printing the truth? */
144 	control = msr_read(MSR_PKG_CST_CONFIG_CONTROL);
145 	printf("Control: 0x016%" PRIx64 "\n", control);
146 	switch (control & PKG_CST_LIMIT_MASK) {
147 	case PKG_CST_LIMIT_C0:
148 		limit = "C0";
149 		break;
150 	case PKG_CST_LIMIT_C2:
151 		limit = "C2";
152 		break;
153 	case PKG_CST_LIMIT_C3:
154 		limit = "C3";
155 		break;
156 	case PKG_CST_LIMIT_C6:
157 		limit = "C6";
158 		break;
159 	case PKG_CST_LIMIT_C7:
160 		limit = "C7";
161 		break;
162 	case PKG_CST_LIMIT_C7s:
163 		limit = "C7s";
164 		break;
165 	case PKG_CST_NO_LIMIT:
166 		limit = "no limit";
167 		break;
168 	default:
169 		limit = "unknown";
170 		break;
171 	}
172 	printf("Package C state limit: %s\n", limit);
173 #endif
174 }
175 
teardown_msr(void)176 static void teardown_msr(void)
177 {
178 	close(msr_fd);
179 }
180 
setup_drm(void)181 static void setup_drm(void)
182 {
183 	int i;
184 
185 	drm.fd = drm_open_driver_master(DRIVER_INTEL);
186 
187 	drm.res = drmModeGetResources(drm.fd);
188 	igt_assert(drm.res->count_connectors <= MAX_CONNECTORS);
189 
190 	for (i = 0; i < drm.res->count_connectors; i++)
191 		drm.connectors[i] = drmModeGetConnector(drm.fd,
192 						drm.res->connectors[i]);
193 
194 	drm.bufmgr = drm_intel_bufmgr_gem_init(drm.fd, 4096);
195 	igt_assert(drm.bufmgr);
196 	drm_intel_bufmgr_gem_enable_reuse(drm.bufmgr);
197 }
198 
teardown_drm(void)199 static void teardown_drm(void)
200 {
201 	int i;
202 
203 	drm_intel_bufmgr_destroy(drm.bufmgr);
204 
205 	for (i = 0; i < drm.res->count_connectors; i++)
206 		drmModeFreeConnector(drm.connectors[i]);
207 
208 	drmModeFreeResources(drm.res);
209 	close(drm.fd);
210 }
211 
draw_rect(struct igt_fb * fb,enum igt_draw_method method,uint32_t color)212 static void draw_rect(struct igt_fb *fb, enum igt_draw_method method,
213 		      uint32_t color)
214 {
215 	drmModeClip clip;
216 	int rc;
217 
218 	switch (opts.draw_size) {
219 	case 0:
220 		clip.x1 = fb->width / 2 - 32;
221 		clip.x2 = fb->width / 2 + 32;
222 		clip.y1 = fb->height / 2 - 32;
223 		clip.y2 = fb->height / 2 + 32;
224 		break;
225 	case 1:
226 		clip.x1 = fb->width / 4;
227 		clip.x2 = fb->width / 4 + fb->width / 2;
228 		clip.y1 = fb->height / 4;
229 		clip.y2 = fb->height / 4 + fb->height / 2;
230 		break;
231 	case 2:
232 		clip.x1 = 0;
233 		clip.x2 = fb->width;
234 		clip.y1 = 0;
235 		clip.y2 = fb->height;
236 		break;
237 	default:
238 		igt_assert(false);
239 	}
240 
241 	igt_draw_rect_fb(drm.fd, drm.bufmgr, NULL, fb, method, clip.x1, clip.y1,
242 			 clip.x2 - clip.x1, clip.y2 - clip.y1, color);
243 
244 	if (method == IGT_DRAW_MMAP_WC) {
245 		rc = drmModeDirtyFB(drm.fd, fb->fb_id, &clip, 1);
246 		igt_assert(rc == 0 || rc == -ENOSYS);
247 	}
248 }
249 
setup_modeset(void)250 static void setup_modeset(void)
251 {
252 	int i;
253 	drmModeConnectorPtr connector;
254 
255 	for (i = 0; i < drm.res->count_connectors; i++) {
256 		connector = drm.connectors[i];
257 
258 		if (connector->connection == DRM_MODE_CONNECTED &&
259 		    connector->count_modes > 0)
260 			break;
261 	}
262 	igt_assert(i < drm.res->count_connectors);
263 
264 	modeset.connector_id = connector->connector_id;
265 	modeset.mode = &connector->modes[0];
266 	modeset.crtc_id = kmstest_find_crtc_for_connector(drm.fd, drm.res,
267 							  connector, 0);
268 
269 	for (i = 0; i < 2; i++) {
270 		igt_create_fb(drm.fd, modeset.mode->hdisplay,
271 			      modeset.mode->vdisplay,  DRM_FORMAT_XRGB8888,
272 			      LOCAL_I915_FORMAT_MOD_X_TILED, &fbs[i]);
273 		igt_draw_fill_fb(drm.fd, &fbs[i], 0x80);
274 	}
275 	draw_rect(&fbs[1], IGT_DRAW_BLT, 0x800000);
276 
277 	igt_create_fb(drm.fd, 64, 64, DRM_FORMAT_ARGB8888,
278 		     LOCAL_DRM_FORMAT_MOD_NONE, &cursor);
279 	igt_draw_fill_fb(drm.fd, &cursor, 0xFF008000);
280 }
281 
teardown_modeset(void)282 static void teardown_modeset(void)
283 {
284 	igt_remove_fb(drm.fd, &fbs[0]);
285 	igt_remove_fb(drm.fd, &fbs[1]);
286 	igt_remove_fb(drm.fd, &cursor);
287 }
288 
setup_vblank_interval(void)289 static void setup_vblank_interval(void)
290 {
291 	uint64_t vrefresh, interval;
292 
293 	vrefresh = ((uint64_t) modeset.mode->clock * 1000 * 1000) /
294 		   (modeset.mode->htotal * modeset.mode->vtotal);
295 	interval = 1000000000 / vrefresh;
296 
297 	vblank_interval_us = interval;
298 
299 	printf("Interval between vblanks:\t%dus\n", vblank_interval_us);
300 }
301 
302 bool alarm_received;
alarm_handler(int signal)303 static void alarm_handler(int signal)
304 {
305 	alarm_received = true;
306 }
307 
setup_alarm(void)308 static void setup_alarm(void)
309 {
310 	struct sigaction sa;
311 
312 	sa.sa_handler = alarm_handler;
313 	sigemptyset(&sa.sa_mask);
314 	sa.sa_flags = 0;
315 	sigaction(SIGALRM, &sa, NULL);
316 }
317 
set_alarm(time_t sec,suseconds_t usec)318 static void set_alarm(time_t sec, suseconds_t usec)
319 {
320 	struct itimerval timerval = {{0, 0}, {sec, usec}};
321 
322 	alarm_received = false;
323 	igt_assert(setitimer(ITIMER_REAL, &timerval, NULL) == 0);
324 }
325 
unset_mode(void)326 static void unset_mode(void)
327 {
328 	int rc;
329 
330 	kmstest_unset_all_crtcs(drm.fd, drm.res);
331 	rc = drmModeSetCursor(drm.fd, modeset.crtc_id, 0, 0, 0);
332 	igt_assert(rc == 0);
333 }
334 
set_mode(void)335 static void set_mode(void)
336 {
337 	int rc;
338 
339 	front_fb = &fbs[0];
340 	back_fb = &fbs[1];
341 	rc = drmModeSetCrtc(drm.fd, modeset.crtc_id, front_fb->fb_id, 0, 0,
342 			    &modeset.connector_id, 1, modeset.mode);
343 	igt_assert(rc == 0);
344 
345 	/* TODO: it seems we need a cursor in order to reach PC7 on BDW. Why? */
346 	rc = drmModeMoveCursor(drm.fd, modeset.crtc_id, 0, 0);
347 	igt_assert(rc == 0);
348 
349 	rc = drmModeSetCursor(drm.fd, modeset.crtc_id, cursor.gem_handle,
350 			      cursor.width, cursor.height);
351 	igt_assert(rc == 0);
352 }
353 
wait_vblanks(int n_vblanks)354 static void wait_vblanks(int n_vblanks)
355 {
356 	drmVBlank vblank;
357 
358 	if (!n_vblanks)
359 		return;
360 
361 	vblank.request.type = DRM_VBLANK_RELATIVE;
362 	vblank.request.sequence = n_vblanks;
363 	vblank.request.signal = 0;
364 	drmWaitVBlank(drm.fd, &vblank);
365 }
366 
page_flip(void)367 static void page_flip(void)
368 {
369 	struct igt_fb *tmp_fb;
370 	int rc;
371 
372 	rc = drmModePageFlip(drm.fd, modeset.crtc_id, back_fb->fb_id, 0, NULL);
373 	igt_assert(rc == 0);
374 
375 	tmp_fb = front_fb;
376 	front_fb = back_fb;
377 	back_fb = tmp_fb;
378 }
379 
wait_until_idle(void)380 static void wait_until_idle(void)
381 {
382 	uint64_t tsc, pc, res;
383 
384 	do {
385 		set_alarm(0, 500 * 1000);
386 
387 		tsc = msr_read(IA32_TIME_STAMP_COUNTER);
388 		pc = msr_read(deepest_pc_state);
389 
390 		while (!alarm_received)
391 			pause();
392 
393 		pc = msr_read(deepest_pc_state) - pc;
394 		tsc = msr_read(IA32_TIME_STAMP_COUNTER) - tsc;
395 
396 		res = pc * 100 / tsc;
397 
398 		/*printf("res:%02"PRIu64"\n", res);*/
399 	} while (res < idle_res && idle_res - res > 3);
400 
401 	if (res > idle_res && res - idle_res > 3)
402 		fprintf(stderr, "The calculated idle residency may be too low "
403 			"(got %02"PRIu64"%%)\n", res);
404 }
405 
do_measurement(void (* callback)(void * ptr),void * ptr)406 static uint64_t do_measurement(void (*callback)(void *ptr), void *ptr)
407 {
408 	uint64_t tsc, pc;
409 
410 	wait_until_idle();
411 
412 	set_alarm(opts.res_warm_time, 0);
413 	callback(ptr);
414 
415 	set_alarm(opts.res_calc_time, 0);
416 
417 	tsc = msr_read(IA32_TIME_STAMP_COUNTER);
418 	pc = msr_read(deepest_pc_state);
419 
420 	callback(ptr);
421 
422 	pc = msr_read(deepest_pc_state) - pc;
423 	tsc = msr_read(IA32_TIME_STAMP_COUNTER) - tsc;
424 
425 	return pc * 100 / tsc;
426 }
427 
setup_idle(void)428 static void setup_idle(void)
429 {
430 	uint64_t tsc, pc[NUM_PC_STATES], res, best_res;
431 	int pc_i, best_pc_i = 0, retries, consecutive_not_best;
432 
433 	for (retries = 0; ; retries++) {
434 
435 		set_alarm(opts.res_warm_time, 0);
436 		while (!alarm_received)
437 			pause();
438 
439 		set_alarm(opts.res_calc_time, 0);
440 
441 		tsc = msr_read(IA32_TIME_STAMP_COUNTER);
442 		for (pc_i = best_pc_i; pc_i < NUM_PC_STATES; pc_i++)
443 			pc[pc_i] = msr_read(res_msr_addrs[pc_i]);
444 
445 		while (!alarm_received)
446 			pause();
447 
448 		for (pc_i = best_pc_i; pc_i < NUM_PC_STATES; pc_i++)
449 			pc[pc_i] = msr_read(res_msr_addrs[pc_i]) - pc[pc_i];
450 		tsc = msr_read(IA32_TIME_STAMP_COUNTER) - tsc;
451 
452 		for (pc_i = NUM_PC_STATES -1; pc_i >= best_pc_i; pc_i--)
453 			if (pc[pc_i] != 0)
454 				break;
455 		igt_require_f(pc_i >= 0, "We're not reaching any PC states!\n");
456 
457 		res = pc[pc_i] * 100 / tsc;
458 
459 		if (retries == 0 || pc_i > best_pc_i || res > best_res) {
460 			best_pc_i = pc_i;
461 			best_res = res;
462 			consecutive_not_best = 0;
463 		} else {
464 			consecutive_not_best++;
465 			if (consecutive_not_best > 2)
466 				break;
467 		}
468 	}
469 
470 	deepest_pc_state = res_msr_addrs[best_pc_i];
471 	idle_res = best_res;
472 
473 	printf("Stable idle residency retries:\t%d\n", retries);
474 	printf("Deepest PC state reached when idle:\t%s\n",
475 	       res_msr_names[best_pc_i]);
476 	printf("Idle residency for this state:\t%02"PRIu64"%%\n", idle_res);
477 }
478 
print_result(int ops,int vblanks,uint64_t res)479 static void print_result(int ops, int vblanks, uint64_t res)
480 {
481 	printf("- %02d ops every %02d vblanks:\t%02"PRIu64"%%\n",
482 	       ops, vblanks, res);
483 	fflush(stdout);
484 }
485 
486 struct page_flip_data {
487 	int n_vblanks;
488 };
489 
page_flip_cb(void * ptr)490 static void page_flip_cb(void *ptr)
491 {
492 	struct page_flip_data *data = ptr;
493 
494 	while (!alarm_received) {
495 		page_flip();
496 		wait_vblanks(data->n_vblanks);
497 	}
498 }
499 
page_flip_test(void)500 static void page_flip_test(void)
501 {
502 	struct page_flip_data data;
503 	int n_vblanks;
504 	uint64_t res;
505 
506 	printf("\nPage flip test:\n");
507 
508 	for (n_vblanks = 1; n_vblanks <= 64; n_vblanks *= opts.loop_inc) {
509 		data.n_vblanks = n_vblanks;
510 		res = do_measurement(page_flip_cb, &data);
511 		print_result(1, n_vblanks, res);
512 	}
513 }
514 
515 struct draw_data {
516 	enum igt_draw_method method;
517 	int n_vblanks;
518 	int ops_per_vblank;
519 };
520 
draw_cb(void * ptr)521 static void draw_cb(void *ptr)
522 {
523 	struct draw_data *data = ptr;
524 	struct timespec req;
525 	int i, ops;
526 
527 	req.tv_sec = 0;
528 	req.tv_nsec = vblank_interval_us * 1000 / data->ops_per_vblank;
529 
530 	for (i = 0; !alarm_received; i++) {
531 		for (ops = 0; ops < data->ops_per_vblank; ops++) {
532 			draw_rect(front_fb, data->method, i << 8);
533 
534 			/* The code that stops the callbacks relies on SIGALRM,
535 			 * so we have to use nanosleep since it doesn't use
536 			 * signals. */
537 			if (data->ops_per_vblank > 1)
538 				nanosleep(&req, NULL);
539 		}
540 
541 		if (data->n_vblanks)
542 			wait_vblanks(data->n_vblanks);
543 	}
544 }
545 
draw_test(void)546 static void draw_test(void)
547 {
548 	struct draw_data data;
549 	enum igt_draw_method method;
550 	int i;
551 	uint64_t res;
552 
553 	for (method = 0; method < IGT_DRAW_METHOD_COUNT; method++) {
554 		data.method = method;
555 
556 		printf("\nDraw %s test:\n",
557 		       igt_draw_get_method_name(method));
558 
559 		data.n_vblanks = 0;
560 		for (i = 32; i >= 2; i /= opts.loop_inc) {
561 			data.ops_per_vblank = i;
562 			res = do_measurement(draw_cb, &data);
563 			print_result(i, 1, res);
564 		}
565 
566 		data.ops_per_vblank = 1;
567 		for (i = 1; i <= 64; i *= opts.loop_inc) {
568 			data.n_vblanks = i ;
569 			res = do_measurement(draw_cb, &data);
570 			print_result(1, i, res);
571 		}
572 	}
573 }
574 
draw_and_flip_cb(void * ptr)575 static void draw_and_flip_cb(void *ptr)
576 {
577 	struct draw_data *data = ptr;
578 	int i, ops;
579 
580 	for (i = 0; !alarm_received; i++) {
581 		for (ops = 0; ops < data->ops_per_vblank; ops++)
582 			draw_rect(back_fb, data->method, i << 8);
583 
584 		page_flip();
585 		wait_vblanks(1);
586 	}
587 }
588 
draw_and_flip_test(void)589 static void draw_and_flip_test(void)
590 {
591 	struct draw_data data;
592 	enum igt_draw_method method;
593 	int i;
594 	uint64_t res;
595 
596 	for (method = 0; method < IGT_DRAW_METHOD_COUNT; method++) {
597 		data.method = method;
598 
599 		/* Doing everything consumes too much time! */
600 		if (method != IGT_DRAW_MMAP_CPU && method != IGT_DRAW_BLT)
601 			continue;
602 
603 		printf("\nDraw and flip %s test:\n",
604 		       igt_draw_get_method_name(method));
605 
606 		for (i = 16; i >= 1; i /= opts.loop_inc) {
607 			data.ops_per_vblank = 1;
608 			res = do_measurement(draw_and_flip_cb, &data);
609 			print_result(i, 1, res);
610 		}
611 	}
612 }
613 
parse_opts(int argc,char * argv[])614 static void parse_opts(int argc, char *argv[])
615 {
616 	int opt;
617 	char short_opts[] = "d:lrbw:c:i:fsn:";
618 	struct option long_opts[] = {
619 		{ "draw-size",        required_argument, NULL, 'd'},
620 		{ "no-flip",          no_argument,       NULL, 'l'},
621 		{ "no-draw",          no_argument,       NULL, 'r'},
622 		{ "no-draw-and-flip", no_argument,       NULL, 'b'},
623 		{ "warm-time",        required_argument, NULL, 'w'},
624 		{ "calc-time",        required_argument, NULL, 'c'},
625 		{ "loop-increment",   required_argument, NULL, 'i'},
626 		{ "fast",             no_argument,       NULL, 'f'},
627 		{ "slow",             no_argument,       NULL, 's'},
628 		{ "name",             required_argument, NULL, 'n'},
629 		{ 0 },
630 	};
631 
632 	while (1) {
633 		opt = getopt_long(argc, argv, short_opts, long_opts, NULL);
634 
635 		switch (opt) {
636 		case 'd':
637 			if (strcmp(optarg, "s") == 0)
638 				opts.draw_size = 0;
639 			else if (strcmp(optarg, "m") == 0)
640 				opts.draw_size = 1;
641 			else if (strcmp(optarg, "l") == 0)
642 				opts.draw_size = 2;
643 			else
644 				igt_assert(false);
645 			break;
646 		case 'l':
647 			opts.do_page_flip = false;
648 			break;
649 		case 'r':
650 			opts.do_draw = false;
651 			break;
652 		case 'b':
653 			opts.do_draw_and_flip = false;
654 			break;
655 		case 'w':
656 			opts.res_warm_time = atoi(optarg);
657 			break;
658 		case 'c':
659 			opts.res_calc_time = atoi(optarg);
660 			break;
661 		case 'i':
662 			opts.loop_inc = atoi(optarg);
663 			break;
664 		case 'f':
665 			opts.res_warm_time = 1;
666 			opts.res_calc_time = 2;
667 			opts.loop_inc = 4;
668 			break;
669 		case 's':
670 			opts.res_warm_time = 2;
671 			opts.res_calc_time = 6;
672 			opts.loop_inc = 2;
673 			break;
674 		case 'n':
675 			opts.test_name = optarg;
676 			break;
677 		case -1:
678 			return;
679 		default:
680 			igt_assert(false);
681 		}
682 	}
683 }
684 
main(int argc,char * argv[])685 int main(int argc, char *argv[])
686 {
687 	parse_opts(argc, argv);
688 
689 	setup_msr();
690 	setup_drm();
691 	setup_modeset();
692 	setup_vblank_interval();
693 	setup_alarm();
694 
695 	printf("Test name:\t%s\n", opts.test_name);
696 
697 	unset_mode();
698 	set_mode();
699 
700 	setup_idle();
701 
702 	if (opts.do_page_flip)
703 		page_flip_test();
704 
705 	if (opts.do_draw)
706 		draw_test();
707 
708 	if (opts.do_draw_and_flip)
709 		draw_and_flip_test();
710 
711 	teardown_modeset();
712 	teardown_drm();
713 	teardown_msr();
714 	return 0;
715 }
716