861 lines
30 KiB
Diff
861 lines
30 KiB
Diff
From 508f9aed76b8f6788be60a8e39849ee6c1a32fcc Mon Sep 17 00:00:00 2001
|
|
From: modric <wangyu283@huawei.com>
|
|
Date: Wed, 9 Nov 2022 15:19:58 +0800
|
|
Subject: [PATCH 4/4] asynchronous switchless example
|
|
|
|
---
|
|
.../enclave/CMakeLists.txt | 16 +-
|
|
.../switchless_performance/enclave/enclave.c | 77 ++
|
|
examples/switchless_performance/host/main.c | 656 +++++++++++++++++-
|
|
.../switchless_performance/switchless.edl | 13 +
|
|
4 files changed, 750 insertions(+), 12 deletions(-)
|
|
|
|
diff --git a/examples/switchless_performance/enclave/CMakeLists.txt b/examples/switchless_performance/enclave/CMakeLists.txt
|
|
index 69aab4c..f7b72b1 100644
|
|
--- a/examples/switchless_performance/enclave/CMakeLists.txt
|
|
+++ b/examples/switchless_performance/enclave/CMakeLists.txt
|
|
@@ -62,7 +62,21 @@ set(COMMON_C_FLAGS "-W -Wall -Werror -fno-short-enums -fno-omit-frame-pointer -f
|
|
set(COMMON_C_LINK_FLAGS "-Wl,-z,now -Wl,-z,relro -Wl,-z,noexecstack -Wl,-nostdlib -nodefaultlibs -nostartfiles")
|
|
|
|
if(CC_GP)
|
|
- set(CMAKE_C_FLAGS "${COMMON_C_FLAGS} -march=armv8-a")
|
|
+ if (CMAKE_COMPILER_IS_GNUCC)
|
|
+ execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpfullversion -dumpversion
|
|
+ OUTPUT_VARIABLE GCC_VERSION)
|
|
+ string(REGEX MATCHALL "[0-9]+" GCC_VERSION_COMPONENTS ${GCC_VERSION})
|
|
+ list(GET GCC_VERSION_COMPONENTS 0 GCC_MAJOR)
|
|
+ list(GET GCC_VERSION_COMPONENTS 1 GCC_MINOR)
|
|
+ set(GCC_VERSION "${GCC_MAJOR}.${GCC_MINOR}")
|
|
+ endif()
|
|
+
|
|
+ if (GCC_VERSION GREATER_EQUAL "9.4")
|
|
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=armv8-a -mno-outline-atomics")
|
|
+ else()
|
|
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=armv8-a")
|
|
+ endif()
|
|
+
|
|
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS} -s -fPIC")
|
|
set(CMAKE_SHARED_LINKER_FLAGS "${COMMON_C_LINK_FLAGS} -Wl,-s")
|
|
|
|
diff --git a/examples/switchless_performance/enclave/enclave.c b/examples/switchless_performance/enclave/enclave.c
|
|
index 1320e53..8b1466f 100644
|
|
--- a/examples/switchless_performance/enclave/enclave.c
|
|
+++ b/examples/switchless_performance/enclave/enclave.c
|
|
@@ -28,10 +28,87 @@ void test_toupper(char *buf, int len)
|
|
}
|
|
}
|
|
|
|
+static int i = 0;
|
|
+static int j = 0;
|
|
+
|
|
void ecall_empty(void)
|
|
{
|
|
+ printf("normal %d\n", __atomic_add_fetch(&i, 1, __ATOMIC_ACQ_REL));
|
|
+}
|
|
+
|
|
+int ecall_empty1(char *buf, int len)
|
|
+{
|
|
+ printf("normal1 %d\n", __atomic_add_fetch(&i, 1, __ATOMIC_ACQ_REL));
|
|
+
|
|
+ if (buf == NULL || len < 0) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ for (int i = 0; i < len; ++i) {
|
|
+ if (buf[i] >= 'a' && buf[i] <= 'z') {
|
|
+ buf[i] = buf[i] - ('a' - 'A');
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+int ecall_empty2(char *buf1, int len1, char *buf2, int len2)
|
|
+{
|
|
+ printf("normal2 %d\n", __atomic_add_fetch(&i, 1, __ATOMIC_ACQ_REL));
|
|
+
|
|
+ if (buf1 == NULL || len1 < 0 || buf2 == NULL || len2 < 0) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ for (int i = 0; i < len2; ++i) {
|
|
+ if (buf1[i] >= 'a' && buf1[i] <= 'z') {
|
|
+ buf2[i] = buf1[i] - ('a' - 'A');
|
|
+ } else {
|
|
+ buf2[i] = buf1[i];
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 2;
|
|
}
|
|
|
|
void ecall_empty_switchless(void)
|
|
{
|
|
+ printf("sl %d\n", __atomic_add_fetch(&j, 1, __ATOMIC_ACQ_REL));
|
|
+}
|
|
+
|
|
+int ecall_empty_switchless1(char *buf, int len)
|
|
+{
|
|
+ printf("sl1 %d\n", __atomic_add_fetch(&j, 1, __ATOMIC_ACQ_REL));
|
|
+
|
|
+ if (buf == NULL || len < 0) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ for (int i = 0; i < len; ++i) {
|
|
+ if (buf[i] >= 'a' && buf[i] <= 'z') {
|
|
+ buf[i] = buf[i] - ('a' - 'A');
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+int ecall_empty_switchless2(char *buf1, int len1, char *buf2, int len2)
|
|
+{
|
|
+ printf("sl2 %d\n", __atomic_add_fetch(&j, 1, __ATOMIC_ACQ_REL));
|
|
+
|
|
+ if (buf1 == NULL || len1 < 0 || buf2 == NULL || len2 < 0) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ for (int i = 0; i < len2; ++i) {
|
|
+ if (buf1[i] >= 'a' && buf1[i] <= 'z') {
|
|
+ buf2[i] = buf1[i] - ('a' - 'A');
|
|
+ } else {
|
|
+ buf2[i] = buf1[i];
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 2;
|
|
}
|
|
diff --git a/examples/switchless_performance/host/main.c b/examples/switchless_performance/host/main.c
|
|
index f80db25..ea4994f 100644
|
|
--- a/examples/switchless_performance/host/main.c
|
|
+++ b/examples/switchless_performance/host/main.c
|
|
@@ -63,23 +63,600 @@ void fini_enclave(cc_enclave_t *enclave)
|
|
|
|
void benchmark_ecall_empty(bool is_switchless, unsigned long nrepeats)
|
|
{
|
|
- struct timespec time_start;
|
|
- struct timespec time_end;
|
|
- struct timespec duration = {0, 0};
|
|
+ struct timeval tval_before;
|
|
+ struct timeval tval_after;
|
|
+ struct timeval duration;
|
|
cc_enclave_result_t(*ecall_fn)(cc_enclave_t *) = is_switchless ? ecall_empty_switchless : ecall_empty;
|
|
|
|
- clock_gettime(CLOCK_REALTIME, &time_start);
|
|
+ gettimeofday(&tval_before, NULL);
|
|
unsigned long tmp_nrepeats = nrepeats;
|
|
while (tmp_nrepeats--) {
|
|
ecall_fn(&g_enclave);
|
|
}
|
|
- clock_gettime(CLOCK_REALTIME, &time_end);
|
|
|
|
- duration.tv_sec += time_end.tv_sec - time_start.tv_sec;
|
|
- duration.tv_nsec += time_end.tv_nsec - time_start.tv_nsec;
|
|
+ gettimeofday(&tval_after, NULL);
|
|
+ timersub(&tval_after, &tval_before, &duration);
|
|
|
|
- printf("Repeating an %s empty ecall for %lu times takes %lu.%09lus\n",
|
|
- is_switchless ? "[switchless]" : "[ ordinary ]", nrepeats, duration.tv_sec, duration.tv_nsec);
|
|
+ printf("Repeating an %s empty ecall for %lu times takes %ld.%06lds\n",
|
|
+ is_switchless ? "[switchless]" : "[ ordinary ]", nrepeats, (long)duration.tv_sec, (long)duration.tv_usec);
|
|
+}
|
|
+
|
|
+/* ecall_empty_switchless */
|
|
+void benchmark_ecall_empty_sl_async(unsigned long nrepeats)
|
|
+{
|
|
+ cc_enclave_result_t ret_code;
|
|
+ cc_enclave_result_t ret;
|
|
+ struct timeval tval_before;
|
|
+ struct timeval tval_after;
|
|
+ struct timeval duration;
|
|
+ int processed_cursor = 0;
|
|
+ int retry_count = 0;
|
|
+
|
|
+ int *arr = (int *)calloc(nrepeats, sizeof(int));
|
|
+ if (arr == NULL) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ // BEGIN
|
|
+ gettimeofday(&tval_before, NULL);
|
|
+
|
|
+ for (int i = 0; i < nrepeats; ++i) {
|
|
+ ret_code = ecall_empty_switchless_async(&g_enclave, &arr[i]);
|
|
+ if (ret_code != CC_SUCCESS) {
|
|
+ if (ret_code == CC_ERROR_SWITCHLESS_TASK_POOL_FULL) {
|
|
+ // The task pool is full. You should try again later.
|
|
+ --i;
|
|
+ ++retry_count;
|
|
+ } else {
|
|
+ // Asynchronous invocation failed
|
|
+ printf("Asynchronous invocation failed, ret=%x\n", ret_code);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ ret = cc_sl_get_async_result(&g_enclave, arr[processed_cursor], NULL);
|
|
+ if (ret == CC_ERROR_SWITCHLESS_ASYNC_TASK_UNFINISHED) {
|
|
+ // Invoking processing
|
|
+ } else if (ret == CC_SUCCESS) {
|
|
+ // Obtaining the result succeeded
|
|
+ processed_cursor++;
|
|
+ } else {
|
|
+ // Failed to obtain the result
|
|
+ processed_cursor++;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ while (processed_cursor < nrepeats) {
|
|
+ ret = cc_sl_get_async_result(&g_enclave, arr[processed_cursor], NULL);
|
|
+ if (ret == CC_ERROR_SWITCHLESS_ASYNC_TASK_UNFINISHED) {
|
|
+ // Invoking processing
|
|
+ continue;
|
|
+ } else if (ret == CC_SUCCESS) {
|
|
+ // Obtaining the result succeeded
|
|
+ processed_cursor++;
|
|
+ } else {
|
|
+ // Failed to obtain the result
|
|
+ processed_cursor++;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // END
|
|
+ gettimeofday(&tval_after, NULL);
|
|
+ timersub(&tval_after, &tval_before, &duration);
|
|
+
|
|
+ free(arr);
|
|
+
|
|
+ printf("retry_count:%d, processed_cursor:%d\n", retry_count, processed_cursor);
|
|
+ printf("Repeating an empty sl async ecall for %lu times takes %ld.%06lds\n", nrepeats,
|
|
+ (long int)duration.tv_sec, (long int)duration.tv_usec);
|
|
+}
|
|
+
|
|
+void benchmark_ecall_empty_sl_async_rollback(unsigned long nrepeats)
|
|
+{
|
|
+ cc_enclave_result_t ret_code;
|
|
+ cc_enclave_result_t ret;
|
|
+ struct timeval tval_before;
|
|
+ struct timeval tval_after;
|
|
+ struct timeval duration;
|
|
+ int processed_cursor = 0;
|
|
+ int rollback_count = 0;
|
|
+ unsigned long tmp_nrepeats = nrepeats;
|
|
+
|
|
+ int *arr = (int *)calloc(nrepeats, sizeof(int));
|
|
+ if (arr == NULL) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ // BEGIN
|
|
+ gettimeofday(&tval_before, NULL);
|
|
+
|
|
+ for (int i = 0; i < tmp_nrepeats; ++i) {
|
|
+ ret_code = ecall_empty_switchless_async(&g_enclave, &arr[i]);
|
|
+ if (ret_code == CC_SUCCESS) {
|
|
+ if (arr[i] == -1) {
|
|
+ // rollback to common invoking when asynchronous switchless fails, and the common call is successful now
|
|
+ --i;
|
|
+ --tmp_nrepeats;
|
|
+ rollback_count++;
|
|
+ }
|
|
+ } else {
|
|
+ // Asynchronous invocation failed
|
|
+ printf("Asynchronous invocation failed, ret=%x\n", ret_code);
|
|
+ }
|
|
+
|
|
+ ret = cc_sl_get_async_result(&g_enclave, arr[processed_cursor], NULL);
|
|
+ if (ret == CC_ERROR_SWITCHLESS_ASYNC_TASK_UNFINISHED) {
|
|
+ // Invoking processing
|
|
+ } else if (ret == CC_SUCCESS) {
|
|
+ // Obtaining the result succeeded
|
|
+ processed_cursor++;
|
|
+ } else {
|
|
+ // Failed to obtain the result
|
|
+ processed_cursor++;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ while (processed_cursor < tmp_nrepeats) {
|
|
+ ret = cc_sl_get_async_result(&g_enclave, arr[processed_cursor], NULL);
|
|
+ if (ret == CC_ERROR_SWITCHLESS_ASYNC_TASK_UNFINISHED) {
|
|
+ // Invoking processing
|
|
+ continue;
|
|
+ } else if (ret == CC_SUCCESS) {
|
|
+ // Obtaining the result succeeded
|
|
+ processed_cursor++;
|
|
+ } else {
|
|
+ // Failed to obtain the result
|
|
+ processed_cursor++;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // END
|
|
+ gettimeofday(&tval_after, NULL);
|
|
+ timersub(&tval_after, &tval_before, &duration);
|
|
+
|
|
+ free(arr);
|
|
+
|
|
+ printf("rollback_count:%d, processed_cursor:%d\n", rollback_count, processed_cursor);
|
|
+ printf("Repeating an empty sl async ecall rollback for %lu times takes %ld.%06lds\n", nrepeats,
|
|
+ (long int)duration.tv_sec, (long int)duration.tv_usec);
|
|
+}
|
|
+
|
|
+
|
|
+/* ecall_empty_switchless1 */
|
|
+void benchmark_ecall_empty_sl_async1(unsigned long nrepeats)
|
|
+{
|
|
+ cc_enclave_result_t ret_code;
|
|
+ cc_enclave_result_t ret;
|
|
+ struct timeval tval_before;
|
|
+ struct timeval tval_after;
|
|
+ struct timeval duration;
|
|
+ int processed_cursor = 0;
|
|
+ int retry_count = 0;
|
|
+ int one_share_buf_len = 32;
|
|
+ int retval;
|
|
+
|
|
+ int *arr = (int *)calloc(nrepeats, sizeof(int));
|
|
+ if (arr == NULL) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ char *sharebuf = (char *)cc_malloc_shared_memory(&g_enclave, nrepeats * one_share_buf_len);
|
|
+ if (sharebuf == NULL) {
|
|
+ free(arr);
|
|
+ printf("Error: malloc shared memory failed.\n");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ // BEGIN
|
|
+ gettimeofday(&tval_before, NULL);
|
|
+
|
|
+ for (int i = 0; i < nrepeats; ++i) {
|
|
+ strcpy(sharebuf + i * one_share_buf_len, "aAbBcCdD");
|
|
+ ret_code = ecall_empty_switchless1_async(&g_enclave, &arr[i], NULL, sharebuf + i * one_share_buf_len,
|
|
+ sizeof("aAbBcCdD"));
|
|
+ if (ret_code != CC_SUCCESS) {
|
|
+ if (ret_code == CC_ERROR_SWITCHLESS_TASK_POOL_FULL) {
|
|
+ // The task pool is full. You should try again later.
|
|
+ --i;
|
|
+ ++retry_count;
|
|
+ } else {
|
|
+ // Asynchronous invocation failed
|
|
+ printf("Asynchronous invocation failed, ret=%x\n", ret_code);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ ret = cc_sl_get_async_result(&g_enclave, arr[processed_cursor], &retval);
|
|
+ if (ret == CC_ERROR_SWITCHLESS_ASYNC_TASK_UNFINISHED) {
|
|
+ // Invoking processing
|
|
+ } else if (ret == CC_SUCCESS) {
|
|
+ // Obtaining the result succeeded, and check the execution result.
|
|
+ if (retval != 1) {
|
|
+ printf("get result retval err:%d, index:%d\n", retval, processed_cursor);
|
|
+ }
|
|
+
|
|
+ if (strcmp("AABBCCDD", sharebuf + processed_cursor * one_share_buf_len)) {
|
|
+ printf("get result buffer err:%s, index:%d\n", sharebuf + processed_cursor * one_share_buf_len,
|
|
+ processed_cursor);
|
|
+ }
|
|
+
|
|
+ processed_cursor++;
|
|
+ } else {
|
|
+ // Failed to obtain the result
|
|
+ processed_cursor++;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ while (processed_cursor < nrepeats) {
|
|
+ ret = cc_sl_get_async_result(&g_enclave, arr[processed_cursor], &retval);
|
|
+ if (ret == CC_ERROR_SWITCHLESS_ASYNC_TASK_UNFINISHED) {
|
|
+ // Invoking processing
|
|
+ continue;
|
|
+ } else if (ret == CC_SUCCESS) {
|
|
+ // Obtaining the result succeeded, and check the execution result.
|
|
+ if (retval != 1) {
|
|
+ printf("get result retval err:%d, index:%d\n", retval, processed_cursor);
|
|
+ }
|
|
+
|
|
+ if (strcmp("AABBCCDD", sharebuf + processed_cursor * one_share_buf_len)) {
|
|
+ printf("get result buffer err:%s, index:%d\n", sharebuf + processed_cursor * one_share_buf_len,
|
|
+ processed_cursor);
|
|
+ }
|
|
+
|
|
+ processed_cursor++;
|
|
+ } else {
|
|
+ // Failed to obtain the result
|
|
+ processed_cursor++;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // END
|
|
+ gettimeofday(&tval_after, NULL);
|
|
+ timersub(&tval_after, &tval_before, &duration);
|
|
+
|
|
+ free(arr);
|
|
+
|
|
+ ret = cc_free_shared_memory(&g_enclave, sharebuf);
|
|
+ if (ret != CC_SUCCESS) {
|
|
+ printf("Error: free shared memory failed:%x.\n", ret);
|
|
+ }
|
|
+
|
|
+ printf("retry_count:%d, processed_cursor:%d\n", retry_count, processed_cursor);
|
|
+ printf("Repeating an empty sl async ecall [1] for %lu times takes %ld.%06lds\n", nrepeats,
|
|
+ (long int)duration.tv_sec, (long int)duration.tv_usec);
|
|
+}
|
|
+
|
|
+void benchmark_ecall_empty_sl_async_rollback1(unsigned long nrepeats)
|
|
+{
|
|
+ cc_enclave_result_t ret_code;
|
|
+ cc_enclave_result_t ret;
|
|
+ struct timeval tval_before;
|
|
+ struct timeval tval_after;
|
|
+ struct timeval duration;
|
|
+ int processed_cursor = 0;
|
|
+ int one_share_buf_len = 32;
|
|
+ int rollback_count = 0;
|
|
+ int retval;
|
|
+ unsigned long tmp_nrepeats = nrepeats;
|
|
+
|
|
+ int *arr = (int *)calloc(nrepeats, sizeof(int));
|
|
+ if (arr == NULL) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ char *sharebuf = (char *)cc_malloc_shared_memory(&g_enclave, nrepeats * one_share_buf_len);
|
|
+ if (sharebuf == NULL) {
|
|
+ free(arr);
|
|
+ printf("Error: malloc shared memory failed.\n");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ // BEGIN
|
|
+ gettimeofday(&tval_before, NULL);
|
|
+
|
|
+ for (int i = 0; i < tmp_nrepeats; ++i) {
|
|
+ strcpy(sharebuf + i * one_share_buf_len, "aAbBcCdD");
|
|
+ ret_code = ecall_empty_switchless1_async(&g_enclave, &arr[i], &retval, sharebuf + i * one_share_buf_len,
|
|
+ sizeof("aAbBcCdD"));
|
|
+ if (ret_code == CC_SUCCESS) {
|
|
+ if (arr[i] == -1) {
|
|
+ /*
|
|
+ * rollback to common invoking when asynchronous switchless fails, and the common call
|
|
+ * is successful now, check the execution result.
|
|
+ */
|
|
+ if (retval != 1) {
|
|
+ printf("get result retval err:%d, index:%d\n", retval, i);
|
|
+ }
|
|
+
|
|
+ if (strcmp("AABBCCDD", sharebuf + i * one_share_buf_len)) {
|
|
+ printf("get result buffer err:%s, index:%d\n", sharebuf + i * one_share_buf_len, i);
|
|
+ }
|
|
+
|
|
+ --i;
|
|
+ --tmp_nrepeats;
|
|
+ rollback_count++;
|
|
+ }
|
|
+ } else {
|
|
+ // Asynchronous invocation failed
|
|
+ printf("Asynchronous invocation failed, ret=%x\n", ret_code);
|
|
+ }
|
|
+
|
|
+ ret = cc_sl_get_async_result(&g_enclave, arr[processed_cursor], &retval);
|
|
+ if (ret == CC_ERROR_SWITCHLESS_ASYNC_TASK_UNFINISHED) {
|
|
+ // Invoking processing
|
|
+ } else if (ret == CC_SUCCESS) {
|
|
+ // Obtaining the result succeeded, check the execution result.
|
|
+ if (retval != 1) {
|
|
+ printf("get result retval err:%d, index:%d\n", retval, processed_cursor);
|
|
+ }
|
|
+
|
|
+ if (strcmp("AABBCCDD", sharebuf + processed_cursor * one_share_buf_len)) {
|
|
+ printf("get result buffer err:%s, index:%d\n", sharebuf + processed_cursor * one_share_buf_len,
|
|
+ processed_cursor);
|
|
+ }
|
|
+
|
|
+ processed_cursor++;
|
|
+ } else {
|
|
+ // Failed to obtain the result
|
|
+ processed_cursor++;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ while (processed_cursor < tmp_nrepeats) {
|
|
+ ret = cc_sl_get_async_result(&g_enclave, arr[processed_cursor], &retval);
|
|
+ if (ret == CC_ERROR_SWITCHLESS_ASYNC_TASK_UNFINISHED) {
|
|
+ // Invoking processing
|
|
+ continue;
|
|
+ } else if (ret == CC_SUCCESS) {
|
|
+ // Obtaining the result succeeded, check the execution result.
|
|
+ if (retval != 1) {
|
|
+ printf("get result retval err:%d, index:%d\n", retval, processed_cursor);
|
|
+ }
|
|
+
|
|
+ if (strcmp("AABBCCDD", sharebuf + processed_cursor * one_share_buf_len)) {
|
|
+ printf("get result buffer err:%s, index:%d\n", sharebuf + processed_cursor * one_share_buf_len,
|
|
+ processed_cursor);
|
|
+ }
|
|
+
|
|
+ processed_cursor++;
|
|
+ } else {
|
|
+ // Failed to obtain the result
|
|
+ processed_cursor++;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // END
|
|
+ gettimeofday(&tval_after, NULL);
|
|
+ timersub(&tval_after, &tval_before, &duration);
|
|
+
|
|
+ free(arr);
|
|
+ ret = cc_free_shared_memory(&g_enclave, sharebuf);
|
|
+ if (ret != CC_SUCCESS) {
|
|
+ printf("Error: free shared memory failed:%x.\n", ret);
|
|
+ }
|
|
+
|
|
+ printf("rollback_count:%d, processed_cursor:%d\n", rollback_count, processed_cursor);
|
|
+ printf("Repeating an empty sl async ecall rollback [1] for %lu times takes %ld.%06lds\n", nrepeats,
|
|
+ (long int)duration.tv_sec, (long int)duration.tv_usec);
|
|
+}
|
|
+
|
|
+/* ecall_empty_switchless2 */
|
|
+void benchmark_ecall_empty_sl_async2(unsigned long nrepeats)
|
|
+{
|
|
+ cc_enclave_result_t ret_code;
|
|
+ cc_enclave_result_t ret;
|
|
+ struct timeval tval_before;
|
|
+ struct timeval tval_after;
|
|
+ struct timeval duration;
|
|
+ int processed_cursor = 0;
|
|
+ int retry_count = 0;
|
|
+ int one_share_buf_len = 32;
|
|
+ int half_one_share_buf_len = 16;
|
|
+ int retval;
|
|
+
|
|
+ int *arr = (int *)calloc(nrepeats, sizeof(int));
|
|
+ if (arr == NULL) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ char *sharebuf = (char *)cc_malloc_shared_memory(&g_enclave, nrepeats * one_share_buf_len);
|
|
+ if (sharebuf == NULL) {
|
|
+ free(arr);
|
|
+ printf("Error: malloc shared memory failed.\n");
|
|
+ return;
|
|
+ }
|
|
+ memset(sharebuf, 0, nrepeats * one_share_buf_len);
|
|
+
|
|
+ // BEGIN
|
|
+ gettimeofday(&tval_before, NULL);
|
|
+
|
|
+ for (int i = 0; i < nrepeats; ++i) {
|
|
+ strcpy(sharebuf + i * one_share_buf_len, "aAbBcCdD");
|
|
+ ret_code = ecall_empty_switchless2_async(&g_enclave, &arr[i], NULL, sharebuf + i * one_share_buf_len,
|
|
+ sizeof("aAbBcCdD"), sharebuf + i * one_share_buf_len + half_one_share_buf_len, sizeof("aAbBcCdD"));
|
|
+ if (ret_code != CC_SUCCESS) {
|
|
+ if (ret_code == CC_ERROR_SWITCHLESS_TASK_POOL_FULL) {
|
|
+ // The task pool is full. You should try again later.
|
|
+ --i;
|
|
+ ++retry_count;
|
|
+ } else {
|
|
+ // Asynchronous invocation failed
|
|
+ printf("Asynchronous invocation failed, ret=%x\n", ret_code);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ ret = cc_sl_get_async_result(&g_enclave, arr[processed_cursor], &retval);
|
|
+ if (ret == CC_ERROR_SWITCHLESS_ASYNC_TASK_UNFINISHED) {
|
|
+ // Invoking processing
|
|
+ } else if (ret == CC_SUCCESS) {
|
|
+ // Obtaining the result succeeded, check the execution result.
|
|
+ if (retval != 2) {
|
|
+ printf("get result retval err:%d, index:%d\n", retval, processed_cursor);
|
|
+ }
|
|
+
|
|
+ if (strcmp("AABBCCDD", sharebuf + processed_cursor * one_share_buf_len + half_one_share_buf_len)) {
|
|
+ printf("get result buffer err:%s, index:%d\n",
|
|
+ sharebuf + processed_cursor * one_share_buf_len + half_one_share_buf_len, processed_cursor);
|
|
+ }
|
|
+
|
|
+ processed_cursor++;
|
|
+ } else {
|
|
+ // Failed to obtain the result
|
|
+ processed_cursor++;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ while (processed_cursor < nrepeats) {
|
|
+ ret = cc_sl_get_async_result(&g_enclave, arr[processed_cursor], &retval);
|
|
+ if (ret == CC_ERROR_SWITCHLESS_ASYNC_TASK_UNFINISHED) {
|
|
+ // Invoking processing
|
|
+ continue;
|
|
+ } else if (ret == CC_SUCCESS) {
|
|
+ // Obtaining the result succeeded, check the execution result.
|
|
+ if (retval != 2) {
|
|
+ printf("get result retval err:%d, index:%d\n", retval, processed_cursor);
|
|
+ }
|
|
+
|
|
+ if (strcmp("AABBCCDD", sharebuf + processed_cursor * one_share_buf_len + half_one_share_buf_len)) {
|
|
+ printf("get result buffer err:%s, index:%d\n",
|
|
+ sharebuf + processed_cursor * one_share_buf_len + half_one_share_buf_len, processed_cursor);
|
|
+ }
|
|
+
|
|
+ processed_cursor++;
|
|
+ } else {
|
|
+ // Failed to obtain the result
|
|
+ processed_cursor++;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // END
|
|
+ gettimeofday(&tval_after, NULL);
|
|
+ timersub(&tval_after, &tval_before, &duration);
|
|
+
|
|
+ free(arr);
|
|
+
|
|
+ ret = cc_free_shared_memory(&g_enclave, sharebuf);
|
|
+ if (ret != CC_SUCCESS) {
|
|
+ printf("Error: free shared memory failed:%x.\n", ret);
|
|
+ }
|
|
+
|
|
+ printf("retry_count:%d, processed_cursor:%d\n", retry_count, processed_cursor);
|
|
+ printf("Repeating an empty sl async ecall [2] for %lu times takes %ld.%06lds\n", nrepeats,
|
|
+ (long int)duration.tv_sec, (long int)duration.tv_usec);
|
|
+}
|
|
+
|
|
+void benchmark_ecall_empty_sl_async_rollback2(unsigned long nrepeats)
|
|
+{
|
|
+ cc_enclave_result_t ret_code;
|
|
+ cc_enclave_result_t ret;
|
|
+ struct timeval tval_before;
|
|
+ struct timeval tval_after;
|
|
+ struct timeval duration;
|
|
+ int processed_cursor = 0;
|
|
+ int one_share_buf_len = 32;
|
|
+ int half_one_share_buf_len = 16;
|
|
+ int rollback_count = 0;
|
|
+ int retval;
|
|
+ unsigned long tmp_nrepeats = nrepeats;
|
|
+
|
|
+ int *arr = (int *)calloc(nrepeats, sizeof(int));
|
|
+ if (arr == NULL) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ char *sharebuf = (char *)cc_malloc_shared_memory(&g_enclave, nrepeats * one_share_buf_len);
|
|
+ if (sharebuf == NULL) {
|
|
+ free(arr);
|
|
+ printf("Error: malloc shared memory failed.\n");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ // BEGIN
|
|
+ gettimeofday(&tval_before, NULL);
|
|
+
|
|
+ for (int i = 0; i < tmp_nrepeats; ++i) {
|
|
+ strcpy(sharebuf + i * one_share_buf_len, "aAbBcCdD");
|
|
+ ret_code = ecall_empty_switchless2_async(&g_enclave, &arr[i], &retval, sharebuf + i * one_share_buf_len,
|
|
+ sizeof("aAbBcCdD"), sharebuf + i * one_share_buf_len + half_one_share_buf_len, sizeof("aAbBcCdD"));
|
|
+ if (ret_code == CC_SUCCESS) {
|
|
+ if (arr[i] == -1) {
|
|
+ /*
|
|
+ * rollback to common invoking when asynchronous switchless fails, and the common call
|
|
+ * is successful now, check the execution result.
|
|
+ */
|
|
+ if (retval != 2) {
|
|
+ printf("get result retval err:%d, index:%d\n", retval, i);
|
|
+ }
|
|
+
|
|
+ if (strcmp("AABBCCDD", sharebuf + i * one_share_buf_len + half_one_share_buf_len)) {
|
|
+ printf("get result buffer err:%s, index:%d\n",
|
|
+ sharebuf + i * one_share_buf_len + half_one_share_buf_len, i);
|
|
+ }
|
|
+
|
|
+ --i;
|
|
+ --tmp_nrepeats;
|
|
+ rollback_count++;
|
|
+ }
|
|
+ } else {
|
|
+ // Asynchronous invocation failed
|
|
+ printf("Asynchronous invocation failed, ret=%x\n", ret_code);
|
|
+ }
|
|
+
|
|
+ ret = cc_sl_get_async_result(&g_enclave, arr[processed_cursor], &retval);
|
|
+ if (ret == CC_ERROR_SWITCHLESS_ASYNC_TASK_UNFINISHED) {
|
|
+ // Invoking processing
|
|
+ } else if (ret == CC_SUCCESS) {
|
|
+ // Obtaining the result succeeded, check the execution result.
|
|
+ if (retval != 2) {
|
|
+ printf("get result retval err:%d, index:%d\n", retval, processed_cursor);
|
|
+ }
|
|
+
|
|
+ if (strcmp("AABBCCDD", sharebuf + processed_cursor * one_share_buf_len + half_one_share_buf_len)) {
|
|
+ printf("get result buffer err:%s, index:%d\n",
|
|
+ sharebuf + processed_cursor * one_share_buf_len + half_one_share_buf_len, processed_cursor);
|
|
+ }
|
|
+
|
|
+ processed_cursor++;
|
|
+ } else {
|
|
+ // Failed to obtain the result
|
|
+ processed_cursor++;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ while (processed_cursor < tmp_nrepeats) {
|
|
+ ret = cc_sl_get_async_result(&g_enclave, arr[processed_cursor], &retval);
|
|
+ if (ret == CC_ERROR_SWITCHLESS_ASYNC_TASK_UNFINISHED) {
|
|
+ // Invoking processing
|
|
+ continue;
|
|
+ } else if (ret == CC_SUCCESS) {
|
|
+ // Obtaining the result succeeded, check the execution result.
|
|
+ if (retval != 2) {
|
|
+ printf("get result retval err:%d, index:%d\n", retval, processed_cursor);
|
|
+ }
|
|
+
|
|
+ if (strcmp("AABBCCDD", sharebuf + processed_cursor * one_share_buf_len + half_one_share_buf_len)) {
|
|
+ printf("get result buffer err:%s, index:%d\n",
|
|
+ sharebuf + processed_cursor * one_share_buf_len + half_one_share_buf_len, processed_cursor);
|
|
+ }
|
|
+
|
|
+ processed_cursor++;
|
|
+ } else {
|
|
+ // Failed to obtain the result
|
|
+ processed_cursor++;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // END
|
|
+ gettimeofday(&tval_after, NULL);
|
|
+ timersub(&tval_after, &tval_before, &duration);
|
|
+
|
|
+ free(arr);
|
|
+ ret = cc_free_shared_memory(&g_enclave, sharebuf);
|
|
+ if (ret != CC_SUCCESS) {
|
|
+ printf("Error: free shared memory failed:%x.\n", ret);
|
|
+ }
|
|
+
|
|
+ printf("rollback_count:%d, processed_cursor:%d\n", rollback_count, processed_cursor);
|
|
+ printf("Repeating an empty sl async ecall rollback [2] for %lu times takes %ld.%06lds\n", nrepeats,
|
|
+ (long int)duration.tv_sec, (long int)duration.tv_usec);
|
|
}
|
|
|
|
#define TEST_STR "switchless"
|
|
@@ -106,11 +683,35 @@ void transfer_data_using_shared_memory()
|
|
}
|
|
}
|
|
|
|
+void onetime_normal(void)
|
|
+{
|
|
+ cc_enclave_result_t ret;
|
|
+ int retval;
|
|
+
|
|
+ char buf[] = "aAbBcCdD";
|
|
+ ret = ecall_empty1(&g_enclave, &retval, buf, sizeof(buf));
|
|
+ if (ret != CC_SUCCESS) {
|
|
+ printf("Error: ecall_empty1, ret:%x.\n", ret);
|
|
+ return;
|
|
+ }
|
|
+ printf("buf:%s, retval:%d\n", buf, retval);
|
|
+
|
|
+ char buf1[] = "aAbBcCdD";
|
|
+ char buf2[32] = {0};
|
|
+ ret = ecall_empty2(&g_enclave, &retval, buf1, sizeof(buf1), buf2, sizeof(buf1) - 3);
|
|
+ if (ret != CC_SUCCESS) {
|
|
+ printf("Error: ecall_empty2, ret:%x.\n", ret);
|
|
+ return;
|
|
+ }
|
|
+ printf("buf2:%s, retval:%d\n", buf2, retval);
|
|
+}
|
|
+
|
|
int main(void)
|
|
{
|
|
cc_sl_config_t sl_cfg = CC_USWITCHLESS_CONFIG_INITIALIZER;
|
|
sl_cfg.num_tworkers = 2; /* 2 tworkers */
|
|
- sl_cfg.sl_call_pool_size_qwords = 2; /* 2 * 64 tasks */
|
|
+ sl_cfg.sl_call_pool_size_qwords = 8; /* 2 * 64 tasks */
|
|
+ sl_cfg.rollback_to_common = false;
|
|
enclave_features_t features = {ENCLAVE_FEATURE_SWITCHLESS, (void *)&sl_cfg};
|
|
|
|
if (!init_enclave(&features)) {
|
|
@@ -119,14 +720,47 @@ int main(void)
|
|
}
|
|
|
|
printf("\n1. Running a benchmark that compares [ordinary] and [switchless] ecall\n");
|
|
- unsigned long nrepeats = 100000;
|
|
+ unsigned long nrepeats = 10000;
|
|
+ benchmark_ecall_empty(false, nrepeats);
|
|
+ benchmark_ecall_empty(true, nrepeats);
|
|
+
|
|
+ benchmark_ecall_empty_sl_async(nrepeats);
|
|
+ benchmark_ecall_empty_sl_async1(nrepeats);
|
|
+ benchmark_ecall_empty_sl_async2(nrepeats);
|
|
+
|
|
+ printf("\n2. Transfer data using shared memory\n");
|
|
+ transfer_data_using_shared_memory();
|
|
+
|
|
+ printf("\n3. normal ecall\n");
|
|
+ onetime_normal();
|
|
+
|
|
+ fini_enclave(&g_enclave);
|
|
+
|
|
+#if 1
|
|
+ printf("\n=================================================\n");
|
|
+
|
|
+ sl_cfg.rollback_to_common = true;
|
|
+ if (!init_enclave(&features)) {
|
|
+ printf("Error: init enclave failed\n");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ printf("\n1. Running a benchmark that compares [ordinary] and [switchless] ecall\n");
|
|
benchmark_ecall_empty(false, nrepeats);
|
|
benchmark_ecall_empty(true, nrepeats);
|
|
|
|
+ benchmark_ecall_empty_sl_async_rollback(nrepeats);
|
|
+ benchmark_ecall_empty_sl_async_rollback1(nrepeats);
|
|
+ benchmark_ecall_empty_sl_async_rollback2(nrepeats);
|
|
+
|
|
printf("\n2. Transfer data using shared memory\n");
|
|
transfer_data_using_shared_memory();
|
|
|
|
+ printf("\n3. normal ecall\n");
|
|
+ onetime_normal();
|
|
+
|
|
fini_enclave(&g_enclave);
|
|
+#endif
|
|
|
|
return 0;
|
|
}
|
|
diff --git a/examples/switchless_performance/switchless.edl b/examples/switchless_performance/switchless.edl
|
|
index 344ee57..3c6f32e 100644
|
|
--- a/examples/switchless_performance/switchless.edl
|
|
+++ b/examples/switchless_performance/switchless.edl
|
|
@@ -16,8 +16,21 @@ enclave {
|
|
from "secgear_tswitchless.edl" import *;
|
|
trusted {
|
|
public void ecall_empty(void);
|
|
+
|
|
+ /* test [in, out] params */
|
|
+ public int ecall_empty1([in, out, size=len]char *buf, int len);
|
|
+
|
|
+ /* test [in] and [out] params */
|
|
+ public int ecall_empty2([in, size=len1]char *buf1, int len1, [out, size=len2]char *buf2, int len2);
|
|
+
|
|
public void ecall_empty_switchless(void) transition_using_threads;
|
|
|
|
+ /* test [in, out] params */
|
|
+ public int ecall_empty_switchless1([in, out, size=len]char *buf, int len) transition_using_threads;
|
|
+
|
|
+ /* test [in] and [out] params */
|
|
+ public int ecall_empty_switchless2([in, size=len1]char *buf1, int len1, [out, size=len2]char *buf2, int len2) transition_using_threads;
|
|
+
|
|
public void test_toupper([in, out, size=len]char *buf, int len) transition_using_threads;
|
|
};
|
|
};
|
|
--
|
|
2.27.0
|
|
|