summaryrefslogtreecommitdiff
path: root/crypto-perf/crypto.cpp
blob: c18607645871e0840e7eabbea82e8afadac1fc2e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
#include <sched.h>
#include <sys/resource.h>
#include <ctype.h>
#define USEC_PER_SEC 1000000ULL
#define MAX_COUNT 1000000000ULL
#define NUM_INSTS_GARBAGE 18

// Contains information about benchmark options.
typedef struct {
    int cpu_to_lock;
    int locked_freq;
} command_data_t;

void usage() {
    printf("--------------------------------------------------------------------------------\n");
    printf("Usage:");
    printf("	crypto [--cpu_to_lock CPU] [--locked_freq FREQ_IN_KHZ]\n\n");
    printf("!!!!!!Lock the desired core to a desired frequency before invoking this benchmark.\n");
    printf(
          "Hint: Set scaling_max_freq=scaling_min_freq=FREQ_IN_KHZ. FREQ_IN_KHZ "
          "can be obtained from scaling_available_freq\n");
    printf("--------------------------------------------------------------------------------\n");
}

int processOptions(int argc, char **argv, command_data_t *cmd_data) {
    // Initialize the command_flags.
    cmd_data->cpu_to_lock = 0;
    cmd_data->locked_freq = 1;
    for (int i = 1; i < argc; i++) {
        if (argv[i][0] == '-') {
            int *save_value = NULL;
            if (strcmp(argv[i], "--cpu_to_lock") == 0) {
                save_value = &cmd_data->cpu_to_lock;
	    } else if (strcmp(argv[i], "--locked_freq") == 0) {
                save_value = &cmd_data->locked_freq;
            } else {
                printf("Unknown option %s\n", argv[i]);
                return -1;
            }
            if (save_value) {
                // Checking both characters without a strlen() call should be
                // safe since as long as the argument exists, one character will
                // be present (\0). And if the first character is '-', then
                // there will always be a second character (\0 again).
                if (i == argc - 1 ||
                    (argv[i + 1][0] == '-' && !isdigit(argv[i + 1][1]))) {
                    printf("The option %s requires one argument.\n", argv[i]);
                    return -1;
                }
                *save_value = (int)strtol(argv[++i], NULL, 0);
            }
	}
    }
    return 0;
}
/* Performs encryption on garbage values. In Cortex-A57 r0p1 and later
 * revisions, pairs of dependent AESE/AESMC and AESD/AESIMC instructions are
 * higher performance when adjacent, and in the described order below. */
void garbage_encrypt() {
    __asm__ __volatile__(
	"aese  v0.16b, v4.16b ;"
        "aesmc	v0.16b, v0.16b ;"
        "aese  v1.16b, v4.16b ;"
        "aesmc	v1.16b, v1.16b ;"
        "aese  v2.16b, v4.16b ;"
        "aesmc	v2.16b, v2.16b ;"
        "aese  v0.16b, v5.16b ;"
        "aesmc	v0.16b, v0.16b ;"
        "aese  v1.16b, v5.16b ;"
        "aesmc	v1.16b, v1.16b ;"
        "aese  v2.16b, v5.16b ;"
        "aesmc	v2.16b, v2.16b ;"
        "aese  v0.16b, v6.16b ;"
        "aesmc	v0.16b, v0.16b ;"
        "aese  v1.16b, v6.16b ;"
        "aesmc	v1.16b, v1.16b ;"
        "aese  v2.16b, v6.16b ;"
        "aesmc	v2.16b, v2.16b ;");
}

void garbage_decrypt() {
    __asm__ __volatile__(
	"aesd  v0.16b, v4.16b ;"
        "aesimc	v0.16b, v0.16b ;"
        "aesd  v1.16b, v4.16b ;"
        "aesimc	v1.16b, v1.16b ;"
        "aesd  v2.16b, v4.16b ;"
        "aesimc	v2.16b, v2.16b ;"
        "aesd  v0.16b, v5.16b ;"
        "aesimc	v0.16b, v0.16b ;"
        "aesd  v1.16b, v5.16b ;"
        "aesimc	v1.16b, v1.16b ;"
        "aesd  v2.16b, v5.16b ;"
        "aesimc	v2.16b, v2.16b ;"
        "aesd  v0.16b, v6.16b ;"
        "aesimc	v0.16b, v0.16b ;"
        "aesd  v1.16b, v6.16b ;"
        "aesimc	v1.16b, v1.16b ;"
        "aesd  v2.16b, v6.16b ;"
        "aesimc	v2.16b, v2.16b ;");
}


int main(int argc, char **argv) {
    usage();
    command_data_t cmd_data;

    if(processOptions(argc, argv, &cmd_data) == -1) {
        usage();
        return -1;
    }
    unsigned long long count = 0;
    struct timeval begin_time, end_time, elapsed_time;
    cpu_set_t cpuset;
    CPU_ZERO(&cpuset);
    CPU_SET(cmd_data.cpu_to_lock, &cpuset);
    if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0) {
	perror("sched_setaffinity failed");
	return 1;
    }
    gettimeofday(&begin_time, NULL);
    while (count < MAX_COUNT) {
      garbage_encrypt();
      count++;
    }
    gettimeofday(&end_time, NULL);
    timersub(&end_time, &begin_time, &elapsed_time);
    fprintf(stderr, "encrypt: %llu us\n",
            elapsed_time.tv_sec * USEC_PER_SEC + elapsed_time.tv_usec);
    fprintf(stderr, "encrypt instructions: %llu\n",
            MAX_COUNT * NUM_INSTS_GARBAGE);
    fprintf(stderr, "encrypt instructions per second: %f\n",
            (float)(MAX_COUNT * NUM_INSTS_GARBAGE * USEC_PER_SEC) /
                (elapsed_time.tv_sec * USEC_PER_SEC + elapsed_time.tv_usec));
    if (cmd_data.locked_freq != 0) {
	fprintf(stderr, "encrypt instructions per cycle: %f\n",
		(float)(MAX_COUNT * NUM_INSTS_GARBAGE * USEC_PER_SEC) /
		((elapsed_time.tv_sec * USEC_PER_SEC + elapsed_time.tv_usec) *
		 1000 * cmd_data.locked_freq));
    }
    printf("--------------------------------------------------------------------------------\n");

    count = 0;
    gettimeofday(&begin_time, NULL);
    while (count < MAX_COUNT) {
      garbage_decrypt();
      count++;
    }
    gettimeofday(&end_time, NULL);
    timersub(&end_time, &begin_time, &elapsed_time);
    fprintf(stderr, "decrypt: %llu us\n",
            elapsed_time.tv_sec * USEC_PER_SEC + elapsed_time.tv_usec);
    fprintf(stderr, "decrypt instructions: %llu\n",
            MAX_COUNT * NUM_INSTS_GARBAGE);
    fprintf(stderr, "decrypt instructions per second: %f\n",
            (float)(MAX_COUNT * NUM_INSTS_GARBAGE * USEC_PER_SEC) /
                (elapsed_time.tv_sec * USEC_PER_SEC + elapsed_time.tv_usec));
    if (cmd_data.locked_freq != 0) {
	fprintf(stderr, "decrypt instructions per cycle: %f\n",
		(float)(MAX_COUNT * NUM_INSTS_GARBAGE * USEC_PER_SEC) /
		((elapsed_time.tv_sec * USEC_PER_SEC + elapsed_time.tv_usec) *
		 1000 * cmd_data.locked_freq));
    }
    return 0;
}