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