115 lines
		
	
	
	
		
			2.6 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			115 lines
		
	
	
	
		
			2.6 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								 * Copyright 2014, Michael Ellerman, IBM Corp.
							 | 
						||
| 
								 | 
							
								 * Licensed under GPLv2.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define _GNU_SOURCE
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include <elf.h>
							 | 
						||
| 
								 | 
							
								#include <limits.h>
							 | 
						||
| 
								 | 
							
								#include <stdio.h>
							 | 
						||
| 
								 | 
							
								#include <stdbool.h>
							 | 
						||
| 
								 | 
							
								#include <string.h>
							 | 
						||
| 
								 | 
							
								#include <sys/prctl.h>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include "event.h"
							 | 
						||
| 
								 | 
							
								#include "lib.h"
							 | 
						||
| 
								 | 
							
								#include "utils.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								 * Test that per-event excludes work.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int per_event_excludes(void)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									struct event *e, events[4];
							 | 
						||
| 
								 | 
							
									char *platform;
							 | 
						||
| 
								 | 
							
									int i;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									platform = (char *)get_auxv_entry(AT_BASE_PLATFORM);
							 | 
						||
| 
								 | 
							
									FAIL_IF(!platform);
							 | 
						||
| 
								 | 
							
									SKIP_IF(strcmp(platform, "power8") != 0);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/*
							 | 
						||
| 
								 | 
							
									 * We need to create the events disabled, otherwise the running/enabled
							 | 
						||
| 
								 | 
							
									 * counts don't match up.
							 | 
						||
| 
								 | 
							
									 */
							 | 
						||
| 
								 | 
							
									e = &events[0];
							 | 
						||
| 
								 | 
							
									event_init_opts(e, PERF_COUNT_HW_INSTRUCTIONS,
							 | 
						||
| 
								 | 
							
											PERF_TYPE_HARDWARE, "instructions");
							 | 
						||
| 
								 | 
							
									e->attr.disabled = 1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									e = &events[1];
							 | 
						||
| 
								 | 
							
									event_init_opts(e, PERF_COUNT_HW_INSTRUCTIONS,
							 | 
						||
| 
								 | 
							
											PERF_TYPE_HARDWARE, "instructions(k)");
							 | 
						||
| 
								 | 
							
									e->attr.disabled = 1;
							 | 
						||
| 
								 | 
							
									e->attr.exclude_user = 1;
							 | 
						||
| 
								 | 
							
									e->attr.exclude_hv = 1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									e = &events[2];
							 | 
						||
| 
								 | 
							
									event_init_opts(e, PERF_COUNT_HW_INSTRUCTIONS,
							 | 
						||
| 
								 | 
							
											PERF_TYPE_HARDWARE, "instructions(h)");
							 | 
						||
| 
								 | 
							
									e->attr.disabled = 1;
							 | 
						||
| 
								 | 
							
									e->attr.exclude_user = 1;
							 | 
						||
| 
								 | 
							
									e->attr.exclude_kernel = 1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									e = &events[3];
							 | 
						||
| 
								 | 
							
									event_init_opts(e, PERF_COUNT_HW_INSTRUCTIONS,
							 | 
						||
| 
								 | 
							
											PERF_TYPE_HARDWARE, "instructions(u)");
							 | 
						||
| 
								 | 
							
									e->attr.disabled = 1;
							 | 
						||
| 
								 | 
							
									e->attr.exclude_hv = 1;
							 | 
						||
| 
								 | 
							
									e->attr.exclude_kernel = 1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									FAIL_IF(event_open(&events[0]));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/*
							 | 
						||
| 
								 | 
							
									 * The open here will fail if we don't have per event exclude support,
							 | 
						||
| 
								 | 
							
									 * because the second event has an incompatible set of exclude settings
							 | 
						||
| 
								 | 
							
									 * and we're asking for the events to be in a group.
							 | 
						||
| 
								 | 
							
									 */
							 | 
						||
| 
								 | 
							
									for (i = 1; i < 4; i++)
							 | 
						||
| 
								 | 
							
										FAIL_IF(event_open_with_group(&events[i], events[0].fd));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/*
							 | 
						||
| 
								 | 
							
									 * Even though the above will fail without per-event excludes we keep
							 | 
						||
| 
								 | 
							
									 * testing in order to be thorough.
							 | 
						||
| 
								 | 
							
									 */
							 | 
						||
| 
								 | 
							
									prctl(PR_TASK_PERF_EVENTS_ENABLE);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* Spin for a while */
							 | 
						||
| 
								 | 
							
									for (i = 0; i < INT_MAX; i++)
							 | 
						||
| 
								 | 
							
										asm volatile("" : : : "memory");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									prctl(PR_TASK_PERF_EVENTS_DISABLE);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									for (i = 0; i < 4; i++) {
							 | 
						||
| 
								 | 
							
										FAIL_IF(event_read(&events[i]));
							 | 
						||
| 
								 | 
							
										event_report(&events[i]);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/*
							 | 
						||
| 
								 | 
							
									 * We should see that all events have enabled == running. That
							 | 
						||
| 
								 | 
							
									 * shows that they were all on the PMU at once.
							 | 
						||
| 
								 | 
							
									 */
							 | 
						||
| 
								 | 
							
									for (i = 0; i < 4; i++)
							 | 
						||
| 
								 | 
							
										FAIL_IF(events[i].result.running != events[i].result.enabled);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/*
							 | 
						||
| 
								 | 
							
									 * We can also check that the result for instructions is >= all the
							 | 
						||
| 
								 | 
							
									 * other counts. That's because it is counting all instructions while
							 | 
						||
| 
								 | 
							
									 * the others are counting a subset.
							 | 
						||
| 
								 | 
							
									 */
							 | 
						||
| 
								 | 
							
									for (i = 1; i < 4; i++)
							 | 
						||
| 
								 | 
							
										FAIL_IF(events[0].result.value < events[i].result.value);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									for (i = 0; i < 4; i++)
							 | 
						||
| 
								 | 
							
										event_close(&events[i]);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return 0;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								int main(void)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									return test_harness(per_event_excludes, "per_event_excludes");
							 | 
						||
| 
								 | 
							
								}
							 |