PAPI  5.7.0.0
papi_ref_cyc.c
Go to the documentation of this file.
1 /* This test exercises the PAPI_TOT_CYC and PAPI_REF_CYC counters.
2 
3  PAPI_TOT_CYC should measure the number of cycles required to do
4  a fixed amount of work.
5  It should be roughly constant for constant work, regardless of the
6  speed state a core is in.
7 
8  PAPI_REF_CYC should measure the number of cycles at a constant
9  reference clock rate, independent of the actual clock rate of the core.
10 */
11 
12 /*
13  PAPI_REF_CYC has various issues on Intel chips:
14 
15  On older machines PAPI uses UNHALTED_REFERENCE_CYCLES but this
16  means different things on different architectures
17 
18  + On Core2/Atom this maps to the special Fixed Counter 2
19  CPU_CLK_UNHALTED.REF
20  This counts at the same rate as the TSC (PAPI_get_real_cyc())
21  And also seems to match PAPI_TOT_CYC
22  It is documented as having a fixed ratio to the
23  CPU_CLK_UNHALTED.BUS (3c/1) event.
24 
25  + On Nehalem/Westemere this also maps to Fixed Counter 2.
26  Again, counts same rate as the TSC and returns
27  CPU_CLK_UNHALTED.REF_P (3c/1)
28  times the "Maximum Non-Turbo Ratio"
29 
30  + Same for Sandybridge/Ivybridge
31 
32  On newer HSW,BDW,SKL machines PAPI uses a different type of event
33  CPU_CLK_THREAD_UNHALTED:REF_XCLK
34 
35  + On Haswell machines this is just the reference clock
36  (100MHz?)
37  + On Sandybridge this is off by a factor of 8x?
38 */
39 
40 /* NOTE:
41  PAPI_get_virt_cyc() returns a lie!
42  It's just virt_time() * max_theoretical_MHz
43  so no point in checking that */
44 
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <unistd.h>
48 
49 #include "papi.h"
50 #include "papi_test.h"
51 
52 #include "testcode.h"
53 
54 #define NUM_FLOPS 20000000
55 
56 static void work (int EventSet, int sleep_test, int quiet)
57 {
58  int retval;
59  long long values[2];
60  long long elapsed_us, elapsed_cyc, elapsed_virt_us, elapsed_virt_cyc;
61  double cycles_error;
62  int numflops = NUM_FLOPS;
63 
64  /* Gather before stats */
67  elapsed_virt_us = PAPI_get_virt_usec( );
68  elapsed_virt_cyc = PAPI_get_virt_cyc( );
69 
70  /* Start PAPI */
72  if ( retval != PAPI_OK ) {
73  test_fail( __FILE__, __LINE__, "PAPI_start", retval );
74  }
75 
76  /* our test code */
77  if (sleep_test) {
78  sleep(2);
79  }
80  else {
81  do_flops( numflops, 1 );
82  }
83 
84  /* Stop PAPI */
86  if ( retval != PAPI_OK ) {
87  test_fail( __FILE__, __LINE__, "PAPI_stop", retval );
88  }
89 
90  /* Calculate total values */
91  elapsed_virt_us = PAPI_get_virt_usec( ) - elapsed_virt_us;
92  elapsed_virt_cyc = PAPI_get_virt_cyc( ) - elapsed_virt_cyc;
95 
96  if (!quiet) {
97  printf( "-------------------------------------------------------------------------\n" );
98  if (sleep_test) printf("Sleeping for 2s\n");
99  else printf( "Using %d iterations of c += a*b\n", numflops );
100  printf( "-------------------------------------------------------------------------\n" );
101 
102  printf( "PAPI_TOT_CYC : \t%10lld\n", values[0] );
103  printf( "PAPI_REF_CYC : \t%10lld\n", values[1] );
104  printf( "Real usec : \t%10lld\n", elapsed_us );
105  printf( "Real cycles : \t%10lld\n", elapsed_cyc );
106  printf( "Virt usec : \t%10lld\n", elapsed_virt_us );
107  printf( "Virt cycles (estimate) : \t%10lld\n", elapsed_virt_cyc );
108  printf( "Estimated GHz : \t%10.3lf\n", (double) elapsed_cyc/(double)elapsed_us/1000.0);
109 
110  printf( "-------------------------------------------------------------------------\n" );
111  }
112 
113 
114  if (sleep_test) {
115  if (!quiet) {
116  printf( "Verification: PAPI_REF_CYC should be much lower than real_usec\n");
117  }
118  if (values[1]>elapsed_us) {
119  if (!quiet) printf("PAPI_REF_CYC too high!\n");
120  test_fail( __FILE__, __LINE__, "PAPI_REF_CYC too high", 0 );
121  }
122 
123  }
124  else {
125  /* PAPI_REF_CYC should be roughly the same as TSC when busy */
126  /* on Intel chips */
127  if (!quiet) {
128  printf( "Verification: real_cyc should be roughly PAPI_REF_CYC\n");
129  printf( " real_usec should be roughly virt_usec (on otherwise idle system)\n");
130  }
131 
132  cycles_error=100.0*
133  ((double)values[1]-((double)elapsed_cyc))
134  /values[1];
135 
136  if ((cycles_error>10.0) || (cycles_error<-10.0)) {
137  if (!quiet) printf("Error of %.2f%%\n",cycles_error);
138  test_fail( __FILE__, __LINE__, "PAPI_REF_CYC validation", 0 );
139  }
140 
141  cycles_error=100.0*
142  ((double)elapsed_us-(double)elapsed_virt_us)
143  /(double)elapsed_us;
144 
145  if ((cycles_error>10.0) || (cycles_error<-10.0)) {
146  if (!quiet) printf("Error of %.2f%%\n",cycles_error);
147  test_warn( __FILE__, __LINE__, "real_us validation", 0 );
148  }
149  }
150 }
151 
152 
153 int
154 main( int argc, char **argv )
155 {
156  int retval;
157  int EventSet = PAPI_NULL;
158  int quiet;
159 
160  /* Set TESTS_QUIET variable */
161  quiet = tests_quiet( argc, argv );
162 
163  /* Init the PAPI library */
165  if ( retval != PAPI_VER_CURRENT ) {
166  test_fail( __FILE__, __LINE__, "PAPI_library_init", retval );
167  }
168 
169  /* Check the ref cycles event */
170  retval = PAPI_query_named_event("PAPI_REF_CYC");
171  if (PAPI_OK!=retval) {
172  if (!quiet) printf("No PAPI_REF_CYC available\n");
173  test_skip( __FILE__, __LINE__,
174  "PAPI_REF_CYC is not defined on this platform.", 0);
175  }
176 
177  /* create an eventset */
179  if ( retval != PAPI_OK ) {
180  test_fail( __FILE__, __LINE__, "PAPI_create_eventset", retval );
181  }
182 
183  /* add core cycle event */
184  retval = PAPI_add_named_event( EventSet, "PAPI_TOT_CYC");
185  if ( retval != PAPI_OK ) {
186  test_fail( __FILE__, __LINE__,
187  "PAPI_add_named_event: PAPI_TOT_CYC", retval );
188  }
189 
190  /* add ref cycle event */
191  retval = PAPI_add_named_event( EventSet, "PAPI_REF_CYC");
192  if ( retval != PAPI_OK ) {
193  test_fail( __FILE__, __LINE__,
194  "PAPI_add_events: PAPI_REF_CYC", retval );
195  }
196 
197  if (!quiet) {
198  printf("Test case sleeping: "
199  "Look at TOT and REF cycles.\n");
200  }
201 
202  work(EventSet, 1, quiet);
203 // do_flops(10*numflops);
204 
205  if (!quiet) {
206  printf( "\nTest case busy:\n" );
207  }
208 
209  work(EventSet, 0, quiet);
210 
211  test_pass( __FILE__ );
212 
213  return 0;
214 }
215 
#define PAPI_OK
Definition: fpapi.h:105
int PAPI_stop(int EventSet, long long *values)
Definition: papi.c:2314
void test_pass(const char *filename)
Definition: test_utils.c:432
long long PAPI_get_virt_usec(void)
Definition: papi.c:6372
int main(int argc, char **argv)
Definition: papi_ref_cyc.c:154
#define NUM_FLOPS
Definition: papi_ref_cyc.c:54
static void work(int EventSet, int sleep_test, int quiet)
Definition: papi_ref_cyc.c:56
long long PAPI_get_virt_cyc(void)
Definition: papi.c:6300
#define PAPI_VER_CURRENT
Definition: fpapi.h:14
int EventSet
int retval
Definition: zero_fork.c:53
void test_warn(const char *file, int line, const char *call, int retval)
Definition: test_utils.c:524
Return codes and api definitions.
void test_skip(const char *file, int line, const char *call, int retval)
Definition: test_utils.c:561
int PAPI_add_named_event(int EventSet, const char *EventName)
Definition: papi.c:1876
int PAPI_library_init(int version)
Definition: papi.c:500
int quiet
Definition: rapl_overflow.c:18
long long elapsed_cyc
Definition: zero_fork.c:50
int PAPI_query_named_event(const char *EventName)
Definition: papi.c:756
#define PAPI_NULL
Definition: fpapi.h:13
int PAPI_create_eventset(int *EventSet)
Definition: papi.c:1464
void do_flops(int n)
Definition: multiplex.c:23
long long PAPI_get_real_usec(void)
Definition: papi.c:6264
int tests_quiet(int argc, char **argv)
Definition: test_utils.c:376
void test_fail(const char *file, int line, const char *call, int retval)
Definition: test_utils.c:468
long long PAPI_get_real_cyc(void)
Definition: papi.c:6217
int PAPI_start(int EventSet)
Definition: papi.c:2096
static long long values[NUM_EVENTS]
Definition: init_fini.c:10
long long elapsed_us
Definition: zero_fork.c:50