Skip to content

Commit a75c2be

Browse files
bandi13Andras Fekete
andauthored
Add CUDA support (#7436)
* Redirect the AesEncrypt_C call to device * Fix function declarations * Force CC=nvcc with CUDA * Don't let C++ mangle function names * Add larger parallelization * Add in memory copy to device * `nvcc` does not support '-Wall' nor '-Wno-unused' * Add in README.md * Clean up script to output color coded data * Fix Asymmetric cipher comparisons * Add in standard output parsing in addition to the CSV * Add option to output results in a CSV --------- Co-authored-by: Andras Fekete <andras@wolfssl.com>
1 parent c3d9fb6 commit a75c2be

8 files changed

Lines changed: 1315 additions & 1 deletion

File tree

Makefile.am

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,3 +310,8 @@ merge-clean:
310310
@find ./ | $(GREP) \.BASE | xargs rm -f
311311
@find ./ | $(GREP) \~$$ | xargs rm -f
312312

313+
%.o: %.cu
314+
$(NVCC) -dc $(CUDAFLAGS) -o $@ $<
315+
316+
.cu.lo:
317+
$(LIBTOOL) --tag=CC --mode=compile $(COMPILE) --compile -o $@ $< -static

configure.ac

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4894,6 +4894,19 @@ then
48944894
AM_CFLAGS="$AM_CFLAGS -DWC_RC2"
48954895
fi
48964896

4897+
# CUDA
4898+
AC_ARG_ENABLE([cuda],
4899+
[AS_HELP_STRING([--enable-cuda],[Enable NVidia CUDA support (default: disabled)])],
4900+
[ ENABLED_CUDA=$enableval ],
4901+
[ ENABLED_CUDA=no ]
4902+
)
4903+
4904+
if test "$ENABLED_CUDA" = "yes"
4905+
then
4906+
CC=nvcc
4907+
AM_CFLAGS="$AM_CFLAGS -DWC_CUDA -DHAVE_CUDA"
4908+
fi
4909+
48974910
# Certificate Service Support (CFLAG sections later) keep above FIPS section
48984911
AC_ARG_ENABLE([certservice],
48994912
[AS_HELP_STRING([--enable-certservice],[Enable cert service (default: disabled)])],
@@ -9144,7 +9157,10 @@ fi
91449157
# For distro disable custom build options that interfere with symbol generation
91459158
if test "$GCC" = "yes" && test "$ENABLED_DISTRO" = "no"
91469159
then
9147-
AM_CFLAGS="$AM_CFLAGS -Wall -Wno-unused"
9160+
if test "$ENABLED_CUDA" != "yes"
9161+
then
9162+
AM_CFLAGS="$AM_CFLAGS -Wall -Wno-unused"
9163+
fi
91489164
if test "$ax_enable_debug" = "no"
91499165
then
91509166
AS_IF([test "x$ENABLED_OPTFLAGS" = "xyes"], [
@@ -9429,6 +9445,7 @@ AM_CONDITIONAL([BUILD_LINUXKM],[test "$ENABLED_LINUXKM" = "yes"])
94299445
AM_CONDITIONAL([BUILD_NO_LIBRARY],[test "$ENABLED_NO_LIBRARY" = "yes"])
94309446
AM_CONDITIONAL([BUILD_BENCHMARK],[test "$ENABLED_BENCHMARK" = "yes"])
94319447
AM_CONDITIONAL([BUILD_RC2],[test "x$ENABLED_RC2" = "xyes"])
9448+
AM_CONDITIONAL([BUILD_CUDA],[test "x$ENABLED_CUDA" = "xyes"])
94329449
AM_CONDITIONAL([BUILD_CAAM],[test "x$ENABLED_CAAM" != "xno"])
94339450
AM_CONDITIONAL([BUILD_QNXCAAM],[test "x$ENABLED_CAAM_QNX" = "xyes"])
94349451
AM_CONDITIONAL([BUILD_IOTSAFE],[test "x$ENABLED_IOTSAFE" = "xyes"])
@@ -9753,6 +9770,7 @@ echo " * ARIA: $ENABLED_ARIA"
97539770
echo " * DES3: $ENABLED_DES3"
97549771
echo " * DES3 TLS Suites: $ENABLED_DES3_TLS_SUITES"
97559772
echo " * Camellia: $ENABLED_CAMELLIA"
9773+
echo " * CUDA: $ENABLED_CUDA"
97569774
echo " * SM4-ECB: $ENABLED_SM4_ECB"
97579775
echo " * SM4-CBC: $ENABLED_SM4_CBC"
97589776
echo " * SM4-CTR: $ENABLED_SM4_CTR"

scripts/benchmark_compare.sh

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
#!/bin/bash
2+
# This script is designed to compare the output of wolfcrypt/benchmark test
3+
# application. If the file has an extension ".csv", then it will parse the
4+
# comma separated format, otherwise it will use the standard output format. The
5+
# green colored output field is the better result.
6+
# Usage: benchmark_compare.sh <first file> <second file>
7+
# You can define a few variables to set options:
8+
# THRESHOLD - set the threshold for equality between two results
9+
# OUTPUT_CSV - set to "1" to print CSV
10+
11+
FIRST_FILE=$1
12+
SECOND_FILE=$2
13+
THRESHOLD=${THRESHOLD:-"10"}
14+
OUTPUT_CSV=${OUTPUT_CSV:-"0"}
15+
16+
declare -A symStats
17+
declare -A asymStats
18+
19+
function getAlgo() { # getAlgo <asCSV> <mode> <line>
20+
if [ "$asCSV" = 1 ]; then
21+
declare -a fields
22+
IFS=',' read -ra fields <<< "$line"
23+
if [ "$mode" = 1 ]; then
24+
echo "${fields[0]}"
25+
else
26+
if [ "${fields[2]}" = "" ]; then
27+
echo "${fields[0]}"
28+
else
29+
echo "${fields[0]}-${fields[2]}"
30+
fi
31+
fi
32+
else
33+
if [ "$mode" = 1 ]; then
34+
echo "$line" | sed 's/ *[0-9]* MiB.*//g'
35+
else
36+
if [[ $line == "scrypt"* ]]; then
37+
echo "scrypt"
38+
else
39+
echo "$line" | sed 's/ *[0-9]* ops.*//g' | sed 's/ \+[0-9]\+ \+/-/g'
40+
fi
41+
fi
42+
fi
43+
}
44+
45+
function getValue() { # getValue <asCSV> <mode> <line>
46+
if [ "$asCSV" = 1 ]; then
47+
declare -a fields
48+
IFS=',' read -ra fields <<< "$line"
49+
if [ "$mode" = 1 ]; then
50+
echo "${fields[1]}"
51+
else
52+
echo "${fields[4]}"
53+
fi
54+
else
55+
if [ "$mode" = 1 ]; then
56+
echo "$line" | sed 's/.*seconds, *//g' | sed 's/ *MiB\/s.*//g'
57+
else
58+
echo "$line" | sed 's/.* ms, *//g' | sed 's/ ops\/sec.*//g'
59+
fi
60+
fi
61+
}
62+
63+
asCSV=0
64+
mode=0
65+
while IFS= read -r line; do
66+
if [[ $FIRST_FILE == *".csv" ]]; then
67+
asCSV=1
68+
if [[ $line == *"Symmetric Ciphers"* ]]; then
69+
mode=1
70+
read
71+
read
72+
elif [[ $line == *"Asymmetric Ciphers"* ]]; then
73+
mode=2
74+
read
75+
read
76+
elif [[ $line == "" ]]; then
77+
mode=0
78+
fi
79+
else
80+
asCSV=0
81+
if [[ $line == *"MiB/s"* ]]; then
82+
mode=1
83+
elif [[ $line == *"ops/sec"* ]]; then
84+
mode=2
85+
else
86+
mode=0
87+
fi
88+
fi
89+
if [ "$mode" -ne 0 ]; then
90+
ALGO=`getAlgo "$asCSV" "$mode" "$line"`
91+
VALUE=`getValue "$asCSV" "$mode" "$line"`
92+
93+
if [ "$mode" = "1" ]; then
94+
symStats["${ALGO}"]=${VALUE}
95+
elif [ "$mode" = "2" ]; then
96+
asymStats["${ALGO}"]=${VALUE}
97+
fi
98+
fi
99+
done < ${FIRST_FILE}
100+
101+
RED='\033[0;31m'
102+
GRN='\033[0;32m'
103+
NC='\033[0m' # No Color
104+
function printData() { # printData <ALGO> <val1> <val2>
105+
ALGO=$1
106+
VAL1=$2
107+
VAL2=$3
108+
if (( $(echo "sqrt( (${VAL1} - ${VAL2})^2 ) < ${THRESHOLD}" | bc -l) )); then
109+
# take absolute value and check if less than a threshold
110+
echo "${ALGO},${GRN}${VAL1}${NC},=,${GRN}${VAL2}${NC}\n"
111+
elif (( $(echo "${VAL1} > ${VAL2}" | bc -l) )); then
112+
echo "${ALGO},${GRN}${VAL1}${NC},>,${VAL2}\n"
113+
else
114+
echo "${ALGO},${VAL1},<,${GRN}${VAL2}${NC}\n"
115+
fi
116+
}
117+
118+
asCSV=0
119+
mode=0
120+
while IFS= read -r line; do
121+
if [[ $SECOND_FILE == *".csv" ]]; then
122+
asCSV=1
123+
if [[ $line == *"Symmetric Ciphers"* ]]; then
124+
RES+="ALGO,${FIRST_FILE},diff(MB/s),${SECOND_FILE}\n"
125+
mode=1
126+
read
127+
read
128+
elif [[ $line == *"Asymmetric Ciphers"* ]]; then
129+
RES+="\nALGO,${FIRST_FILE},diff(ops/sec),${SECOND_FILE}\n"
130+
mode=2
131+
read
132+
read
133+
elif [[ $line == "" ]]; then
134+
mode=0
135+
fi
136+
else
137+
asCSV=0
138+
if [[ $line == *"MiB/s"* ]]; then
139+
mode=1
140+
elif [[ $line == *"ops/sec"* ]]; then
141+
mode=2
142+
else
143+
mode=0
144+
fi
145+
fi
146+
if [ "$mode" -ne 0 ]; then
147+
if [[ $line == *","* ]]; then
148+
ALGO=`getAlgo "$asCSV" "$mode" "$line"`
149+
VALUE=`getValue "$asCSV" "$mode" "$line"`
150+
151+
if [ "$mode" = "1" ]; then
152+
RES+=`printData "${ALGO}" "${symStats["${ALGO}"]}" "${VALUE}"`
153+
elif [ "$mode" = "2" ]; then
154+
RES+=`printData "${ALGO}" "${asymStats["${ALGO}"]}" "${VALUE}"`
155+
fi
156+
fi
157+
fi
158+
done < ${SECOND_FILE}
159+
160+
if [ "${OUTPUT_CSV}" = "1" ]; then
161+
echo -e "$RES"
162+
else
163+
echo -e "$RES" | column -t -s ',' -L
164+
fi

scripts/include.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,5 +128,6 @@ dist_noinst_SCRIPTS+= scripts/dtlscid.test
128128
endif
129129

130130
EXTRA_DIST += scripts/bench/bench_functions.sh
131+
EXTRA_DIST += scripts/benchmark_compare.sh
131132

132133
EXTRA_DIST += scripts/user_settings_asm.sh

src/include.am

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ endif
6262

6363
if BUILD_AES
6464
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/aes.c
65+
if BUILD_CUDA
66+
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/cuda/aes-cuda.cu
67+
endif BUILD_CUDA
6568
endif
6669

6770
if BUILD_AESNI
@@ -154,6 +157,9 @@ endif
154157

155158
if BUILD_AES
156159
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/aes.c
160+
if BUILD_CUDA
161+
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/cuda/aes-cuda.cu
162+
endif BUILD_CUDA
157163
if BUILD_ARMASM
158164
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-aes.c
159165
endif BUILD_ARMASM
@@ -639,6 +645,9 @@ endif
639645
if !BUILD_FIPS_CURRENT
640646
if BUILD_AES
641647
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/aes.c
648+
if BUILD_CUDA
649+
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/cuda/aes-cuda.cu
650+
endif BUILD_CUDA
642651
if BUILD_ARMASM
643652
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-aes.c
644653
endif BUILD_ARMASM

wolfcrypt/src/aes.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1915,6 +1915,7 @@ static word32 GetTable8_4(const byte* t, byte o0, byte o1, byte o2, byte o3)
19151915
((word32)(t)[o2] << 8) | ((word32)(t)[o3] << 0))
19161916
#endif
19171917

1918+
#ifndef HAVE_CUDA
19181919
/* Encrypt a block using AES.
19191920
*
19201921
* @param [in] aes AES object.
@@ -2215,6 +2216,11 @@ static void AesEncryptBlocks_C(Aes* aes, const byte* in, byte* out, word32 sz)
22152216
}
22162217
}
22172218
#endif
2219+
#else
2220+
extern void AesEncrypt_C(Aes* aes, const byte* inBlock, byte* outBlock,
2221+
word32 r);
2222+
extern void AesEncryptBlocks_C(Aes* aes, const byte* in, byte* out, word32 sz);
2223+
#endif /* HAVE_CUDA */
22182224

22192225
#else
22202226

@@ -2710,6 +2716,7 @@ static void bs_encrypt(bs_word* state, bs_word* rk, word32 r)
27102716
bs_inv_transpose(state, trans);
27112717
}
27122718

2719+
#ifndef HAVE_CUDA
27132720
/* Encrypt a block using AES.
27142721
*
27152722
* @param [in] aes AES object.
@@ -2761,6 +2768,11 @@ static void AesEncryptBlocks_C(Aes* aes, const byte* in, byte* out, word32 sz)
27612768
}
27622769
}
27632770
#endif
2771+
#else
2772+
extern void AesEncrypt_C(Aes* aes, const byte* inBlock, byte* outBlock,
2773+
word32 r);
2774+
extern void AesEncryptBlocks_C(Aes* aes, const byte* in, byte* out, word32 sz);
2775+
#endif /* HAVE_CUDA */
27642776

27652777
#endif /* !WC_AES_BITSLICED */
27662778

wolfcrypt/src/port/cuda/README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
You will need to have the CUDA libraries and toolchains installed to be able to use this. For the simplest
2+
setup, I used the 'nvidia/cuda:12.3.2-devel-ubuntu22.04' container with the '--gpus=all' flag. Note that
3+
Docker must be set up to allow passing through the CUDA instructions to the host. The container only needs
4+
'automake' and 'libtool' installed: `apt update && apt install -y automake libtool`.
5+
6+
This code was tested with the following:
7+
./configure --enable-all --disable-shared --disable-crl-monitor --enable-cuda CC=nvcc && make check
8+
9+
There are still things that can be done to optimize, but the basic functionality is there.

0 commit comments

Comments
 (0)