1 #include <ctype.h>
2 #include <sched.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <sys/resource.h>
7 #include <sys/time.h>
8 #include <unistd.h>
9 #define USEC_PER_SEC 1000000ULL
10 #define MAX_COUNT 1000000000ULL
11 #define NUM_INSTS_GARBAGE 18
12 
13 // Contains information about benchmark options.
14 typedef struct {
15     int cpu_to_lock;
16     int locked_freq;
17 } command_data_t;
18 
usage()19 void usage() {
20     printf("--------------------------------------------------------------------------------\n");
21     printf("Usage:");
22     printf("	crypto [--cpu_to_lock CPU] [--locked_freq FREQ_IN_KHZ]\n\n");
23     printf("!!!!!!Lock the desired core to a desired frequency before invoking this benchmark.\n");
24     printf("Hint: Set scaling_max_freq=scaling_min_freq=FREQ_IN_KHZ. FREQ_IN_KHZ "
25            "can be obtained from scaling_available_freq\n");
26     printf("--------------------------------------------------------------------------------\n");
27 }
28 
processOptions(int argc,char ** argv,command_data_t * cmd_data)29 int processOptions(int argc, char** argv, command_data_t* cmd_data) {
30     // Initialize the command_flags.
31     cmd_data->cpu_to_lock = 0;
32     cmd_data->locked_freq = 1;
33     for (int i = 1; i < argc; i++) {
34         if (argv[i][0] == '-') {
35             int* save_value = NULL;
36             if (strcmp(argv[i], "--cpu_to_lock") == 0) {
37                 save_value = &cmd_data->cpu_to_lock;
38             } else if (strcmp(argv[i], "--locked_freq") == 0) {
39                 save_value = &cmd_data->locked_freq;
40             } else {
41                 printf("Unknown option %s\n", argv[i]);
42                 return -1;
43             }
44             if (save_value) {
45                 // Checking both characters without a strlen() call should be
46                 // safe since as long as the argument exists, one character will
47                 // be present (\0). And if the first character is '-', then
48                 // there will always be a second character (\0 again).
49                 if (i == argc - 1 || (argv[i + 1][0] == '-' && !isdigit(argv[i + 1][1]))) {
50                     printf("The option %s requires one argument.\n", argv[i]);
51                     return -1;
52                 }
53                 *save_value = (int)strtol(argv[++i], NULL, 0);
54             }
55         }
56     }
57     return 0;
58 }
59 /* Performs encryption on garbage values. In Cortex-A57 r0p1 and later
60  * revisions, pairs of dependent AESE/AESMC and AESD/AESIMC instructions are
61  * higher performance when adjacent, and in the described order below. */
garbage_encrypt()62 void garbage_encrypt() {
63     __asm__ __volatile__(
64             "aese  v0.16b, v4.16b ;"
65             "aesmc	v0.16b, v0.16b ;"
66             "aese  v1.16b, v4.16b ;"
67             "aesmc	v1.16b, v1.16b ;"
68             "aese  v2.16b, v4.16b ;"
69             "aesmc	v2.16b, v2.16b ;"
70             "aese  v0.16b, v5.16b ;"
71             "aesmc	v0.16b, v0.16b ;"
72             "aese  v1.16b, v5.16b ;"
73             "aesmc	v1.16b, v1.16b ;"
74             "aese  v2.16b, v5.16b ;"
75             "aesmc	v2.16b, v2.16b ;"
76             "aese  v0.16b, v6.16b ;"
77             "aesmc	v0.16b, v0.16b ;"
78             "aese  v1.16b, v6.16b ;"
79             "aesmc	v1.16b, v1.16b ;"
80             "aese  v2.16b, v6.16b ;"
81             "aesmc	v2.16b, v2.16b ;");
82 }
83 
garbage_decrypt()84 void garbage_decrypt() {
85     __asm__ __volatile__(
86             "aesd  v0.16b, v4.16b ;"
87             "aesimc	v0.16b, v0.16b ;"
88             "aesd  v1.16b, v4.16b ;"
89             "aesimc	v1.16b, v1.16b ;"
90             "aesd  v2.16b, v4.16b ;"
91             "aesimc	v2.16b, v2.16b ;"
92             "aesd  v0.16b, v5.16b ;"
93             "aesimc	v0.16b, v0.16b ;"
94             "aesd  v1.16b, v5.16b ;"
95             "aesimc	v1.16b, v1.16b ;"
96             "aesd  v2.16b, v5.16b ;"
97             "aesimc	v2.16b, v2.16b ;"
98             "aesd  v0.16b, v6.16b ;"
99             "aesimc	v0.16b, v0.16b ;"
100             "aesd  v1.16b, v6.16b ;"
101             "aesimc	v1.16b, v1.16b ;"
102             "aesd  v2.16b, v6.16b ;"
103             "aesimc	v2.16b, v2.16b ;");
104 }
105 
main(int argc,char ** argv)106 int main(int argc, char** argv) {
107     usage();
108     command_data_t cmd_data;
109 
110     if (processOptions(argc, argv, &cmd_data) == -1) {
111         usage();
112         return -1;
113     }
114     unsigned long long count = 0;
115     struct timeval begin_time, end_time, elapsed_time;
116     cpu_set_t cpuset;
117     CPU_ZERO(&cpuset);
118     CPU_SET(cmd_data.cpu_to_lock, &cpuset);
119     if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0) {
120         perror("sched_setaffinity failed");
121         return 1;
122     }
123     gettimeofday(&begin_time, NULL);
124     while (count < MAX_COUNT) {
125         garbage_encrypt();
126         count++;
127     }
128     gettimeofday(&end_time, NULL);
129     timersub(&end_time, &begin_time, &elapsed_time);
130     fprintf(stderr, "encrypt: %llu us\n",
131             elapsed_time.tv_sec * USEC_PER_SEC + elapsed_time.tv_usec);
132     fprintf(stderr, "encrypt instructions: %llu\n", MAX_COUNT * NUM_INSTS_GARBAGE);
133     fprintf(stderr, "encrypt instructions per second: %f\n",
134             (float)(MAX_COUNT * NUM_INSTS_GARBAGE * USEC_PER_SEC) /
135                     (elapsed_time.tv_sec * USEC_PER_SEC + elapsed_time.tv_usec));
136     if (cmd_data.locked_freq != 0) {
137         fprintf(stderr, "encrypt instructions per cycle: %f\n",
138                 (float)(MAX_COUNT * NUM_INSTS_GARBAGE * USEC_PER_SEC) /
139                         ((elapsed_time.tv_sec * USEC_PER_SEC + elapsed_time.tv_usec) * 1000 *
140                          cmd_data.locked_freq));
141     }
142     printf("--------------------------------------------------------------------------------\n");
143 
144     count = 0;
145     gettimeofday(&begin_time, NULL);
146     while (count < MAX_COUNT) {
147         garbage_decrypt();
148         count++;
149     }
150     gettimeofday(&end_time, NULL);
151     timersub(&end_time, &begin_time, &elapsed_time);
152     fprintf(stderr, "decrypt: %llu us\n",
153             elapsed_time.tv_sec * USEC_PER_SEC + elapsed_time.tv_usec);
154     fprintf(stderr, "decrypt instructions: %llu\n", MAX_COUNT * NUM_INSTS_GARBAGE);
155     fprintf(stderr, "decrypt instructions per second: %f\n",
156             (float)(MAX_COUNT * NUM_INSTS_GARBAGE * USEC_PER_SEC) /
157                     (elapsed_time.tv_sec * USEC_PER_SEC + elapsed_time.tv_usec));
158     if (cmd_data.locked_freq != 0) {
159         fprintf(stderr, "decrypt instructions per cycle: %f\n",
160                 (float)(MAX_COUNT * NUM_INSTS_GARBAGE * USEC_PER_SEC) /
161                         ((elapsed_time.tv_sec * USEC_PER_SEC + elapsed_time.tv_usec) * 1000 *
162                          cmd_data.locked_freq));
163     }
164     return 0;
165 }
166