Hi Paul,

I picked up the following test program you had sent out to LKML
recently. With your permission, i would like to add this to LTP.
The following Patch does that exactly.

May i request you to kindly let us know if you are developing any
test case(s) for any kernel feature in future. Then kindly do,

Cc: Subrata Modak <[email protected]>,
Cc: ltp-list <[email protected]>,

Ported-To-And-Tested-On-LTP-By: Subrata Modak <[email protected]>,

---

--- ltp-full-20090331.orig/runtest/perfcounters 2009-04-01 18:01:43.000000000 
+0530
+++ ltp-full-20090331/runtest/perfcounters      2009-04-01 18:08:27.000000000 
+0530
@@ -1,4 +1,5 @@
 # Test some Basic Performance Counters
 
 performance_counter01 performance_counter01
+performance_counter02 performance_counter02
 
--- 
ltp-full-20090331.orig/testcases/kernel/performance_counters/performance_counter02.c
        1970-01-01 05:30:00.000000000 +0530
+++ 
ltp-full-20090331/testcases/kernel/performance_counters/performance_counter02.c 
    2009-04-01 18:06:56.000000000 +0530
@@ -0,0 +1,251 @@
+/******************************************************************************/
+/*                                                                            
*/
+/* Paul Mackerras <[email protected]>, 2009                                    
*/
+/*                                                                            
*/
+/* This program is free software;  you can redistribute it and/or modify      
*/
+/* it under the terms of the GNU General Public License as published by       
*/
+/* the Free Software Foundation; either version 2 of the License, or          
*/
+/* (at your option) any later version.                                        
*/
+/*                                                                            
*/
+/* This program is distributed in the hope that it will be useful,            
*/
+/* but WITHOUT ANY WARRANTY;  without even the implied warranty of            
*/
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See                  
*/
+/* the GNU General Public License for more details.                           
*/
+/*                                                                            
*/
+/* You should have received a copy of the GNU General Public License          
*/
+/* along with this program;  if not, write to the Free Software               
*/
+/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA    
*/
+/*                                                                            
*/
+/******************************************************************************/
+/*
+Here's a little test program that checks whether software counters
+(specifically, the task clock counter) work correctly when they're in
+a group with hardware counters.
+
+What it does is to create several groups, each with one hardware
+counter, counting instructions, plus a task clock counter.  It needs
+to know an upper bound N on the number of hardware counters you have
+(N defaults to 8), and it creates N+4 groups to force them to be
+multiplexed.  It also creates an overall task clock counter.
+
+Then it spins for a while, and then stops all the counters and reads
+them.  It takes the total of the task clock counters in the groups and
+computes the ratio of that total to the overall execution time from
+the overall task clock counter.
+
+That ratio should be equal to the number of actual hardware counters
+that can count instructions.  If the task clock counters in the groups
+don't stop when their group gets taken off the PMU, the ratio will
+instead be close to N+4.  The program will declare that the test fails
+if the ratio is greater than N (actually, N + 0.0001 to allow for FP
+rounding errors).
+
+Could someone run this on x86 on the latest PCL tree and let me know
+what happens?  I don't have an x86 crash box easily to hand.  On
+powerpc, it passes, but I think that is because I am missing setting
+counter->prev_count in arch/powerpc/kernel/perf_counter.c, and I think
+that means that enabling/disabling a group with a task clock counter
+in it won't work correctly (I'll do a test program for that next).
+
+Usage is: ./performance_counter02 [-c num-hw-counters] [-v]
+
+Use -c N if you have more than 8 hardware counters.  The -v flag makes
+it print out the values of each counter.
+*/
+
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <linux/types.h>
+#include <syscall.h>
+
+/* Harness Specific Include Files. */
+#include "test.h"
+#include "usctest.h"
+
+#ifdef __x86_64__
+# define __NR_perf_counter_open        295
+#endif
+
+#ifdef __i386__
+# define __NR_perf_counter_open 333
+#endif
+
+#ifdef __powerpc__
+# define __NR_perf_counter_open 319
+#endif
+
+#define PR_TASK_PERF_COUNTERS_DISABLE           31
+#define PR_TASK_PERF_COUNTERS_ENABLE            32
+
+/* Extern Global Variables */
+extern int  Tst_count;               /* counter for tst_xxx routines.         
*/
+extern char *TESTDIR;                /* temporary dir created by tst_tmpdir() 
*/
+
+/* Global Variables */
+char *TCID     = "performance_counter02"; /* test program identifier.          
*/
+int  TST_TOTAL = 1;                  /* total number of tests in this file.   
*/
+
+typedef unsigned int u32;
+typedef unsigned long long u64;
+typedef long long s64;
+
+struct perf_counter_hw_event {
+        s64                     type;
+        u64                     irq_period;
+        u32                     record_type;
+
+        u32                     disabled     :  1, /* off by default */
+                                nmi          :  1, /* NMI sampling   */
+                                raw          :  1, /* raw event type */
+                                __reserved_1 : 29;
+        u64                     __reserved_2;
+};
+
+enum hw_event_types {
+       PERF_COUNT_CYCLES               =  0,
+       PERF_COUNT_INSTRUCTIONS         =  1,
+       PERF_COUNT_CACHE_REFERENCES     =  2,
+       PERF_COUNT_CACHE_MISSES         =  3,
+       PERF_COUNT_BRANCH_INSTRUCTIONS  =  4,
+       PERF_COUNT_BRANCH_MISSES        =  5,
+
+       /*
+        * Special "software" counters provided by the kernel, even if
+        * the hardware does not support performance counters. These
+        * counters measure various physical and sw events of the
+        * kernel (and allow the profiling of them as well):
+        */
+       PERF_COUNT_CPU_CLOCK            = -1,
+       PERF_COUNT_TASK_CLOCK           = -2,
+       /*
+        * Future software events:
+        */
+       /* PERF_COUNT_PAGE_FAULTS       = -3,
+          PERF_COUNT_CONTEXT_SWITCHES  = -4, */
+};
+
+int sys_perf_counter_open(struct perf_counter_hw_event *hw_event,
+                         pid_t pid, int cpu, int group_fd, unsigned long flags)
+{
+       return syscall(__NR_perf_counter_open, hw_event, pid, cpu, group_fd,
+                      flags);
+}
+
+#define MAX_CTRS       50
+#define LOOPS  1000000000
+
+void do_work(void)
+{
+       int i;
+
+       for (i = 0; i < LOOPS; ++i)
+               asm volatile("" : : "g" (i));
+}
+
+main(int ac, char **av)
+{
+       int tsk0;
+       int hwfd[MAX_CTRS], tskfd[MAX_CTRS];
+       struct perf_counter_hw_event tsk_event;
+       struct perf_counter_hw_event hw_event;
+       unsigned long long vt0, vt[MAX_CTRS], vh[MAX_CTRS], vtsum, vhsum;
+       int i, n, nhw;
+       int verbose = 0;
+       double ratio;
+
+       nhw = 8;
+       while ((i = getopt(ac, av, "c:v")) != -1) {
+               switch (i) {
+               case 'c':
+                       n = atoi(optarg);
+                       break;
+               case 'v':
+                       verbose = 1;
+                       break;
+               case '?':
+                       fprintf(stderr, "Usage: %s [-c #hwctrs] [-v]\n", av[0]);
+                       exit(1);
+               }
+       }
+
+       if (nhw < 0 || nhw > MAX_CTRS - 4) {
+               fprintf(stderr, "invalid number of hw counters specified: %d\n",
+                       nhw);
+               exit(1);
+       }
+
+       n = nhw + 4;
+
+       memset(&tsk_event, 0, sizeof(tsk_event));
+       tsk_event.type = PERF_COUNT_TASK_CLOCK;
+       tsk_event.disabled = 1;
+
+       memset(&hw_event, 0, sizeof(hw_event));
+       hw_event.disabled = 1;
+       hw_event.type = PERF_COUNT_INSTRUCTIONS;
+
+       tsk0 = sys_perf_counter_open(&tsk_event, 0, -1, -1, 0);
+       if (tsk0 == -1) {
+               perror("perf_counter_open");
+               exit(1);
+       }
+
+       tsk_event.disabled = 0;
+       for (i = 0; i < n; ++i) {
+               hwfd[i] =  sys_perf_counter_open(&hw_event, 0, -1, -1, 0);
+               tskfd[i] = sys_perf_counter_open(&tsk_event, 0, -1, hwfd[i], 0);
+               if (tskfd[i] == -1 || hwfd[i] == -1) {
+                       perror("perf_counter_open");
+                       exit(1);
+               }
+       }
+
+       prctl(PR_TASK_PERF_COUNTERS_ENABLE);
+       do_work();
+       prctl(PR_TASK_PERF_COUNTERS_DISABLE);
+
+       if (read(tsk0, &vt0, sizeof(vt0)) != sizeof(vt0)) {
+               fprintf(stderr, "error reading task clock counter\n");
+               exit(1);
+       }
+
+       vtsum = vhsum = 0;
+       for (i = 0; i < n; ++i) {
+               if (read(tskfd[i], &vt[i], sizeof(vt[i])) != sizeof(vt[i]) ||
+                   read(hwfd[i], &vh[i], sizeof(vh[i])) != sizeof(vh[i])) {
+                       fprintf(stderr, "error reading counter(s)\n");
+                       exit(1);
+               }
+               vtsum += vt[i];
+               vhsum += vh[i];
+       }
+
+       printf("overall task clock: %lld\n", vt0);
+       printf("hw sum: %lld, task clock sum: %lld\n", vhsum, vtsum);
+       if (verbose) {
+               printf("hw counters:");
+               for (i = 0; i < n; ++i)
+                       printf(" %lld", vh[i]);
+               printf("\ntask clock counters:");
+               for (i = 0; i < n; ++i)
+                       printf(" %lld", vt[i]);
+               printf("\n");
+       }
+       ratio = (double)vtsum / vt0;
+       printf("ratio: %.2f\n", ratio);
+       if (ratio > nhw + 0.0001) {
+               fprintf(stderr, "test failed\n");
+               exit(1);
+       }
+
+       fprintf(stderr, "test passed\n");
+       exit(0);
+}

---
Regards--
Subrata


------------------------------------------------------------------------------
_______________________________________________
Ltp-list mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/ltp-list

Reply via email to