Home | History | Annotate | Download | only in crypto-perf
      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