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 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 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. */ 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 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 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 1; 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