daxpy.cpp (3751B)
1 #include "papi.h" 2 #include <cstdlib> 3 #include <iostream> 4 #include <numeric> 5 #include <vector> 6 7 // Broadwell CPU on cluster, you can get one with 8 // salloc -N1 -c32 -t 01:00:00 9 // 10 // Model name: Intel(R) Xeon(R) CPU E5-2683 v4 @ 2.10GHz 11 // L1d cache: 32K 12 // L1i cache: 32K 13 // L2 cache: 256K 14 // L3 cache: 40960K 15 #define L1_SIZE_KB 32 16 #define L2_SIZE_KB 256 17 #define L3_SIZE_KB 40960 18 19 typedef double Real; 20 21 void daxpy(const Real a, const Real *x, Real *y, const int n) 22 { 23 // 2n flops 24 // 3n memory accesses 25 for (int i = 0; i < n; ++i) { 26 y[i] = a * x[i] + y[i]; 27 } 28 } 29 30 int main(int argc, char *argv[]) 31 { 32 int n = 1000000; 33 if (argc > 1) { 34 n = atoi(argv[1]); 35 } 36 std::vector<Real> x(n, 1.0); 37 std::vector<Real> y(n, 0.001); 38 39 // Initialize PAPI 40 int event_set = PAPI_NULL; 41 int events[4] = {PAPI_TOT_CYC, 42 PAPI_TOT_INS, 43 PAPI_LST_INS, 44 PAPI_L1_DCM}; 45 long long int counters[4]; 46 PAPI_library_init(PAPI_VER_CURRENT); 47 PAPI_create_eventset(&event_set); 48 PAPI_add_events(event_set, events, 4); 49 50 // warm up 51 daxpy(1.0, x.data(), y.data(), n); 52 53 // start PAPI measurement 54 PAPI_start(event_set); 55 56 // assuming no overhead to call this timer (will pollute PAPI_TOT_CYC and 57 // PAPI_TOT_INS slightly, neglected here) 58 const long long int t0 = PAPI_get_real_nsec(); 59 60 // run code to be measured 61 daxpy(1.0, x.data(), y.data(), n); 62 63 // assuming no overhead to call this timer (will pollute PAPI_TOT_CYC and 64 // PAPI_TOT_INS slightly, neglected here) 65 const long long int t1 = PAPI_get_real_nsec(); 66 67 // stop PAPI and get counter values 68 PAPI_stop(event_set, counters); 69 70 // clang-format off 71 const long long total_cycles = counters[0]; // cpu cycles 72 const long long total_instructions = counters[1]; // any 73 const long long total_load_stores = counters[2]; // number of such instructions 74 const long long total_l1d_misses = counters[3]; // number of access request to cache line 75 // clang-format on 76 77 const size_t flops = 2 * n; 78 const size_t mem_ops = 3 * n; 79 const double twall = (static_cast<double>(t1) - t0) * 1.0e-9; // seconds 80 const double IPC = static_cast<double>(total_instructions) / total_cycles; 81 const double OI = 82 static_cast<double>(flops) / (total_load_stores * sizeof(Real)); 83 const double OI_theory = 84 static_cast<double>(flops) / (mem_ops * sizeof(Real)); 85 const double float_perf = flops / twall * 1.0e-9; // Gflop/s 86 const double sum = std::accumulate(y.begin(), y.end(), 0.0); 87 88 std::cout << "Result: " << sum << '\n'; 89 std::cout << "Total cycles: " << total_cycles << '\n'; 90 std::cout << "Total instructions: " << total_instructions << '\n'; 91 std::cout << "Instructions per cycle (IPC): " << IPC << '\n'; 92 std::cout << "L1 cache size: " << L1_SIZE_KB << " KB\n"; 93 std::cout << "L2 cache size: " << L2_SIZE_KB << " KB\n"; 94 std::cout << "L3 cache size: " << L3_SIZE_KB << " KB\n"; 95 std::cout << "Total problem size: " << 2 * n * sizeof(Real) / 1024 96 << " KB\n"; 97 std::cout << "Total L1 data misses: " << total_l1d_misses << '\n'; 98 std::cout << "Total load/store: " << total_load_stores 99 << " (expected: " << mem_ops << ")\n"; 100 std::cout << "Operational intensity: " << std::scientific << OI 101 << " (expected: " << OI_theory << ")\n"; 102 std::cout << "Performance [Gflop/s]: " << float_perf << '\n'; 103 std::cout << "Wall-time [micro-seconds]: " << twall * 1.0e6 << '\n'; 104 105 return 0; 106 }