Skip to content

Commit

Permalink
tests: add ioctl_period test
Browse files Browse the repository at this point in the history
The various corner cases of this came up recently due to e-mail
conversation with Andreas Sandberg
  • Loading branch information
deater committed Oct 28, 2013
1 parent e6ac865 commit 67304db
Show file tree
Hide file tree
Showing 4 changed files with 217 additions and 2 deletions.
3 changes: 3 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
28 October 2013
+ Add ioctl_period test

11 October 2013
+ Add tests/error_returns/e2big
+ Move non-existent test to tests/error_returns
Expand Down
3 changes: 3 additions & 0 deletions run_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ $TESTS_DIR/ioctl/ioctl_flag_group
echo " + $TESTS_DIR/ioctl/ioctl_id"
echo -n " "
$TESTS_DIR/ioctl/ioctl_id
echo " + $TESTS_DIR/ioctl/ioctl_period"
echo -n " "
$TESTS_DIR/ioctl/ioctl_period

echo
echo "* Checking error returns"
Expand Down
23 changes: 21 additions & 2 deletions tests/ioctl/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ LIB = ../../lib

all: \
ioctl_flag_group \
ioctl_id
ioctl_id \
ioctl_period

###

Expand Down Expand Up @@ -51,9 +52,27 @@ ioctl_id.o: ioctl_id.c
$(CC) $(CFLAGS) -c ioctl_id.c




###

ioctl_period: ioctl_period.o $(LIB)/test_utils.o \
$(LIB)/perf_helpers.o \
$(LIB)/instructions_testcode.o
$(CC) $(LFLAGS) -o ioctl_period ioctl_period.o \
$(LIB)/test_utils.o \
$(LIB)/instructions_testcode.o \
$(LIB)/perf_helpers.o -lpthread

ioctl_period.o: ioctl_period.c
$(CC) $(CFLAGS) -c ioctl_period.c



####

clean:
rm -f *~ *.o \
ioctl_flag_group \
ioctl_id
ioctl_id \
ioctl_period
190 changes: 190 additions & 0 deletions tests/ioctl/ioctl_period.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
/* ioctl_period.c */
/* Test the PERF_EVENT_IOC_PERIOD ioctl */

/* by Vince Weaver vincent.weaver _at_ maine.edu */

/* Since 3.7 (3581fe0ef37) ARM behaves differently */
/* and updates the period immediately rather */
/* than after the next overflow. */

/* This ioctl was broken until 2.6.36 */
/* ad0cf3478de8677f720ee06393b3147819568d6a */
/* and always returned EFAULT */


#define _GNU_SOURCE 1

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <unistd.h>
#include <asm/unistd.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <fcntl.h>

#include <errno.h>

#include "perf_event.h"
#include "perf_helpers.h"
#include "test_utils.h"
#include "instructions_testcode.h"

static char test_string[]="Testing ioctl(PERF_EVENT_IOC_PERIOD)...";

#define OVERFLOWS_TO_TRACK 1024
static long long overflow_counts[OVERFLOWS_TO_TRACK];
static int overflows=0;
static int ioctl_errors=0;
static int ioctl_errno=0;

static void our_handler(int signum, siginfo_t *info, void *uc) {
int fd = info->si_fd;
int ret;
long long value;
int read_result;
long long new_period;

/* Turn off measurement */
ioctl(fd,PERF_EVENT_IOC_DISABLE,0);

/* Read out value */
read_result=read(fd,&value,sizeof(long long));

overflow_counts[overflows]=value;

/* Increment, but make sure we don't overflow */
overflows++;
if (overflows>=OVERFLOWS_TO_TRACK) {
overflows=OVERFLOWS_TO_TRACK-1;
}

if (overflows==5) {
new_period=100000;
ret=ioctl(fd, PERF_EVENT_IOC_PERIOD,&new_period);
if (ret<0) {
ioctl_errors++;
ioctl_errno=errno;
}
}

/* Restart for one more sample period */
ret=ioctl(fd, PERF_EVENT_IOC_REFRESH,1);

(void)read_result;
}


int main(int argc, char** argv) {

int fd[2],i;
int quiet;
int validation_errors=0;

long long diff;

struct perf_event_attr pe;

struct sigaction sa;

quiet=test_quiet();

if (!quiet) {
printf("This tests the PERF_EVENT_IOC_PERIOD ioctl.\n\n");
}

memset(&pe,0,sizeof(struct perf_event_attr));

pe.type=PERF_TYPE_HARDWARE;
pe.config=PERF_COUNT_HW_INSTRUCTIONS;
pe.disabled=1;
pe.exclude_kernel=1;
pe.exclude_hv=1;
pe.sample_period=10000;

fd[0]=perf_event_open(&pe,0,-1,-1,0);
if (fd[0]<0) {
fprintf(stderr,"Error opening\n");
exit(1);
}

/* Set up overflow */
memset(&sa, 0, sizeof(struct sigaction));
sa.sa_sigaction = our_handler;
sa.sa_flags = SA_SIGINFO;
if (sigaction( SIGRTMIN+2, &sa, NULL) < 0) {
printf("Error setting up signal handler\n");
}
fcntl(fd[0], F_SETFL, O_RDWR|O_NONBLOCK|O_ASYNC);
fcntl(fd[0], F_SETSIG, SIGRTMIN+2);
fcntl(fd[0], F_SETOWN,getpid());

ioctl(fd[0], PERF_EVENT_IOC_REFRESH,1);

instructions_million();

ioctl(fd[0], PERF_EVENT_IOC_DISABLE,0);

close(fd[0]);

if (!quiet) {
printf("Overflows:\n");
for(i=0;i<overflows;i++) {
printf("\t%d %lld\n",i,overflow_counts[i]);
}
}

if (ioctl_errors) {

if (!quiet) {
if (ioctl_errno==EFAULT) {
fprintf(stderr,"Known issue with kernels <2.6.36, PERF_IOC_PERIOD always fails due to kernel bug.\n");
}
else {
fprintf(stderr,"Unknown failure with PERF_EVENT_IOC_PERIOD: %s\n",strerror(errno));
}
}

test_fail(test_string);
}

/* validate results */
/* should be 10k apart for 0,1,2,3,4,5 */
/* 5-6 and after should be 100k */

for(i=0;i<5;i++) {
diff=overflow_counts[i+1]-overflow_counts[i];

if ((diff>11000) || (diff<9000)) {
if (!quiet) {
fprintf(stderr,"Overflow %i-%i should have been 10,000, was %lld\n",i,i+1,diff);
}
validation_errors++;
}
}

for(i=5;i<overflows-1;i++) {
diff=overflow_counts[i+1]-overflow_counts[i];

if ((diff>101000) || (diff<99000)) {
if (!quiet) {
fprintf(stderr,"Overflow %i-%i should have been 100,000, was %lld\n",i,i+1,diff);
}
validation_errors++;
}
}

if (validation_errors) {
test_fail(test_string);
}

test_pass(test_string);

/* TODO: properly handle ARM post 3.7 case */
/* also check for case where we reset
overflow on running counter?
*/

return 0;
}

0 comments on commit 67304db

Please sign in to comment.