1*288bf522SAndroid Build Coastguard Worker #include <stdio.h>
2*288bf522SAndroid Build Coastguard Worker #include <sys/time.h>
3*288bf522SAndroid Build Coastguard Worker #include <getopt.h>
4*288bf522SAndroid Build Coastguard Worker
5*288bf522SAndroid Build Coastguard Worker #include <thread>
6*288bf522SAndroid Build Coastguard Worker #include <iostream>
7*288bf522SAndroid Build Coastguard Worker #include <iomanip>
8*288bf522SAndroid Build Coastguard Worker
9*288bf522SAndroid Build Coastguard Worker #include <sched.h>
10*288bf522SAndroid Build Coastguard Worker
11*288bf522SAndroid Build Coastguard Worker #include "Profiler.h"
12*288bf522SAndroid Build Coastguard Worker
13*288bf522SAndroid Build Coastguard Worker extern "C" void icache_test(long count, long step);
14*288bf522SAndroid Build Coastguard Worker
15*288bf522SAndroid Build Coastguard Worker static constexpr size_t MAX_CODE_SIZE = 128*1024;
16*288bf522SAndroid Build Coastguard Worker static constexpr size_t CACHE_LINE_SIZE = 64;
17*288bf522SAndroid Build Coastguard Worker static constexpr size_t MAX_ITERATIONS_COUNT = MAX_CODE_SIZE / CACHE_LINE_SIZE;
18*288bf522SAndroid Build Coastguard Worker static constexpr size_t REPETITIONS = 0x800000L;
19*288bf522SAndroid Build Coastguard Worker
20*288bf522SAndroid Build Coastguard Worker
21*288bf522SAndroid Build Coastguard Worker using namespace utils;
22*288bf522SAndroid Build Coastguard Worker
23*288bf522SAndroid Build Coastguard Worker static cpu_set_t g_cpu_set;
24*288bf522SAndroid Build Coastguard Worker
printUsage(char * name)25*288bf522SAndroid Build Coastguard Worker static void printUsage(char* name) {
26*288bf522SAndroid Build Coastguard Worker std::string exec_name(name);
27*288bf522SAndroid Build Coastguard Worker std::string usage(
28*288bf522SAndroid Build Coastguard Worker "ICACHE is a command-line tool for testing the L1 instruction cache performance.\n"
29*288bf522SAndroid Build Coastguard Worker "(Make sure security.perf_harden is set to 0)\n\n"
30*288bf522SAndroid Build Coastguard Worker "Usages:\n"
31*288bf522SAndroid Build Coastguard Worker " ICACHE [options]\n"
32*288bf522SAndroid Build Coastguard Worker "\n"
33*288bf522SAndroid Build Coastguard Worker "Options:\n"
34*288bf522SAndroid Build Coastguard Worker " --help, -h\n"
35*288bf522SAndroid Build Coastguard Worker " print this message\n\n"
36*288bf522SAndroid Build Coastguard Worker " --affinity=N, -a N\n"
37*288bf522SAndroid Build Coastguard Worker " Specify which CPU the test should run on.\n\n"
38*288bf522SAndroid Build Coastguard Worker );
39*288bf522SAndroid Build Coastguard Worker const std::string from("ICACHE");
40*288bf522SAndroid Build Coastguard Worker for (size_t pos = usage.find(from); pos != std::string::npos; pos = usage.find(from, pos)) {
41*288bf522SAndroid Build Coastguard Worker usage.replace(pos, from.length(), exec_name);
42*288bf522SAndroid Build Coastguard Worker }
43*288bf522SAndroid Build Coastguard Worker printf("%s", usage.c_str());
44*288bf522SAndroid Build Coastguard Worker }
45*288bf522SAndroid Build Coastguard Worker
handleCommandLineArgments(int argc,char * argv[])46*288bf522SAndroid Build Coastguard Worker static int handleCommandLineArgments(int argc, char* argv[]) {
47*288bf522SAndroid Build Coastguard Worker static constexpr const char* OPTSTR = "ha:";
48*288bf522SAndroid Build Coastguard Worker static const struct option OPTIONS[] = {
49*288bf522SAndroid Build Coastguard Worker { "help", no_argument, 0, 'h' },
50*288bf522SAndroid Build Coastguard Worker { "affinity", required_argument, 0, 'a' },
51*288bf522SAndroid Build Coastguard Worker { 0, 0, 0, 0 } // termination of the option list
52*288bf522SAndroid Build Coastguard Worker };
53*288bf522SAndroid Build Coastguard Worker int opt;
54*288bf522SAndroid Build Coastguard Worker int option_index = 0;
55*288bf522SAndroid Build Coastguard Worker while ((opt = getopt_long(argc, argv, OPTSTR, OPTIONS, &option_index)) >= 0) {
56*288bf522SAndroid Build Coastguard Worker std::string arg(optarg ? optarg : "");
57*288bf522SAndroid Build Coastguard Worker switch (opt) {
58*288bf522SAndroid Build Coastguard Worker default:
59*288bf522SAndroid Build Coastguard Worker case 'h':
60*288bf522SAndroid Build Coastguard Worker printUsage(argv[0]);
61*288bf522SAndroid Build Coastguard Worker exit(0);
62*288bf522SAndroid Build Coastguard Worker break;
63*288bf522SAndroid Build Coastguard Worker case 'a':
64*288bf522SAndroid Build Coastguard Worker size_t cpu = std::stoi(arg);
65*288bf522SAndroid Build Coastguard Worker if (cpu < std::thread::hardware_concurrency()) {
66*288bf522SAndroid Build Coastguard Worker CPU_SET(cpu, &g_cpu_set);
67*288bf522SAndroid Build Coastguard Worker } else {
68*288bf522SAndroid Build Coastguard Worker std::cerr << "N must be < " << std::thread::hardware_concurrency() << std::endl;
69*288bf522SAndroid Build Coastguard Worker exit(0);
70*288bf522SAndroid Build Coastguard Worker }
71*288bf522SAndroid Build Coastguard Worker break;
72*288bf522SAndroid Build Coastguard Worker }
73*288bf522SAndroid Build Coastguard Worker }
74*288bf522SAndroid Build Coastguard Worker return optind;
75*288bf522SAndroid Build Coastguard Worker }
76*288bf522SAndroid Build Coastguard Worker
main(int argc,char * argv[])77*288bf522SAndroid Build Coastguard Worker int main(int argc, char* argv[]) {
78*288bf522SAndroid Build Coastguard Worker CPU_ZERO(&g_cpu_set);
79*288bf522SAndroid Build Coastguard Worker
80*288bf522SAndroid Build Coastguard Worker [[maybe_unused]] int option_index = handleCommandLineArgments(argc, argv);
81*288bf522SAndroid Build Coastguard Worker [[maybe_unused]] int num_args = argc - option_index;
82*288bf522SAndroid Build Coastguard Worker
83*288bf522SAndroid Build Coastguard Worker if (CPU_COUNT(&g_cpu_set)) {
84*288bf522SAndroid Build Coastguard Worker sched_setaffinity(gettid(), sizeof(g_cpu_set), &g_cpu_set);
85*288bf522SAndroid Build Coastguard Worker }
86*288bf522SAndroid Build Coastguard Worker
87*288bf522SAndroid Build Coastguard Worker Profiler& profiler = Profiler::get();
88*288bf522SAndroid Build Coastguard Worker profiler.resetEvents(Profiler::EV_CPU_CYCLES | Profiler::EV_L1I_RATES);
89*288bf522SAndroid Build Coastguard Worker
90*288bf522SAndroid Build Coastguard Worker if (!profiler.isValid()) {
91*288bf522SAndroid Build Coastguard Worker fprintf(stderr, "performance counters not enabled. try \"setprop security.perf_harden 0\"\n");
92*288bf522SAndroid Build Coastguard Worker exit(0);
93*288bf522SAndroid Build Coastguard Worker }
94*288bf522SAndroid Build Coastguard Worker
95*288bf522SAndroid Build Coastguard Worker size_t const stepInBytes = 1024; // 1 KiB steps
96*288bf522SAndroid Build Coastguard Worker size_t const step = stepInBytes / CACHE_LINE_SIZE;
97*288bf522SAndroid Build Coastguard Worker
98*288bf522SAndroid Build Coastguard Worker std::cout << std::fixed << std::setprecision(2);
99*288bf522SAndroid Build Coastguard Worker
100*288bf522SAndroid Build Coastguard Worker printf("[KiB]\t[cyc]\t[refs]\t[MPKI]\t[ns]\n");
101*288bf522SAndroid Build Coastguard Worker
102*288bf522SAndroid Build Coastguard Worker Profiler::Counters counters;
103*288bf522SAndroid Build Coastguard Worker
104*288bf522SAndroid Build Coastguard Worker for (size_t i=step ; i <= MAX_ITERATIONS_COUNT ; i += step) {
105*288bf522SAndroid Build Coastguard Worker profiler.reset();
106*288bf522SAndroid Build Coastguard Worker
107*288bf522SAndroid Build Coastguard Worker auto now = std::chrono::steady_clock::now();
108*288bf522SAndroid Build Coastguard Worker profiler.start();
109*288bf522SAndroid Build Coastguard Worker icache_test(REPETITIONS, i);
110*288bf522SAndroid Build Coastguard Worker profiler.stop();
111*288bf522SAndroid Build Coastguard Worker auto duration = std::chrono::steady_clock::now() - now;
112*288bf522SAndroid Build Coastguard Worker
113*288bf522SAndroid Build Coastguard Worker profiler.readCounters(&counters);
114*288bf522SAndroid Build Coastguard Worker
115*288bf522SAndroid Build Coastguard Worker std::cout << ((i*CACHE_LINE_SIZE)/1024) << "\t"
116*288bf522SAndroid Build Coastguard Worker << counters.getCpuCycles()/double(REPETITIONS) << "\t"
117*288bf522SAndroid Build Coastguard Worker << counters.getL1IReferences()/double(REPETITIONS) << "\t"
118*288bf522SAndroid Build Coastguard Worker << counters.getMPKI(counters.getL1IMisses()) << "\t"
119*288bf522SAndroid Build Coastguard Worker << duration.count()/double(REPETITIONS) << "\t"
120*288bf522SAndroid Build Coastguard Worker << std::endl;
121*288bf522SAndroid Build Coastguard Worker }
122*288bf522SAndroid Build Coastguard Worker
123*288bf522SAndroid Build Coastguard Worker return 0;
124*288bf522SAndroid Build Coastguard Worker }
125