Просмотр исходного кода

Implement wasi clock_time/clock_res get (#2637)

Add os_clock_res_get and os_clock_time_get in platform_api_extension.h,
and implement them in posix like platforms and windows platform.
fadumina1 2 лет назад
Родитель
Сommit
a874bf0ff8

+ 31 - 35
core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c

@@ -94,22 +94,9 @@ ns_lookup_list_search(char **list, const char *host)
     return false;
 }
 
-// Converts a POSIX timespec to a CloudABI timestamp.
-static __wasi_timestamp_t
-convert_timespec(const struct timespec *ts)
-{
-    if (ts->tv_sec < 0)
-        return 0;
-    if ((__wasi_timestamp_t)ts->tv_sec >= UINT64_MAX / 1000000000)
-        return UINT64_MAX;
-    return (__wasi_timestamp_t)ts->tv_sec * 1000000000
-           + (__wasi_timestamp_t)ts->tv_nsec;
-}
-
-// Converts a CloudABI clock identifier to a POSIX clock identifier.
 #ifndef BH_PLATFORM_WINDOWS
 static bool
-convert_clockid(__wasi_clockid_t in, clockid_t *out)
+wasi_clockid_to_clockid(__wasi_clockid_t in, clockid_t *out)
 {
     switch (in) {
         case __WASI_CLOCK_MONOTONIC:
@@ -210,22 +197,37 @@ wasi_addr_ip_to_bh_ip_addr_buffer(__wasi_addr_ip_t *addr,
     }
 }
 
+static bool
+wasi_clockid_to_bh_clockid(__wasi_clockid_t in, bh_clock_id_t *out)
+{
+    switch (in) {
+        case __WASI_CLOCK_MONOTONIC:
+            *out = BH_CLOCK_ID_MONOTONIC;
+            return true;
+        case __WASI_CLOCK_PROCESS_CPUTIME_ID:
+            *out = BH_CLOCK_ID_PROCESS_CPUTIME_ID;
+            return true;
+        case __WASI_CLOCK_REALTIME:
+            *out = BH_CLOCK_ID_REALTIME;
+            return true;
+        case __WASI_CLOCK_THREAD_CPUTIME_ID:
+            *out = BH_CLOCK_ID_THREAD_CPUTIME_ID;
+            return true;
+        default:
+            return false;
+    }
+}
+
 __wasi_errno_t
 wasmtime_ssp_clock_res_get(__wasi_clockid_t clock_id,
                            __wasi_timestamp_t *resolution)
 {
-#ifdef BH_PLATFORM_WINDOWS
-    return __WASI_ENOSYS;
-#else
-    clockid_t nclock_id;
-    if (!convert_clockid(clock_id, &nclock_id))
+    bh_clock_id_t bh_clockid;
+    if (!wasi_clockid_to_bh_clockid(clock_id, &bh_clockid))
         return __WASI_EINVAL;
-    struct timespec ts;
-    if (clock_getres(nclock_id, &ts) < 0)
+    if (os_clock_res_get(clock_id, resolution) != BHT_OK)
         return convert_errno(errno);
-    *resolution = convert_timespec(&ts);
-    return 0;
-#endif
+    return __WASI_ESUCCESS;
 }
 
 __wasi_errno_t
@@ -233,18 +235,12 @@ wasmtime_ssp_clock_time_get(__wasi_clockid_t clock_id,
                             __wasi_timestamp_t precision,
                             __wasi_timestamp_t *time)
 {
-#ifdef BH_PLATFORM_WINDOWS
-    return __WASI_ENOSYS;
-#else
-    clockid_t nclock_id;
-    if (!convert_clockid(clock_id, &nclock_id))
+    bh_clock_id_t bh_clockid;
+    if (!wasi_clockid_to_bh_clockid(clock_id, &bh_clockid))
         return __WASI_EINVAL;
-    struct timespec ts;
-    if (clock_gettime(nclock_id, &ts) < 0)
+    if (os_clock_time_get(clock_id, precision, time) != BHT_OK)
         return convert_errno(errno);
-    *time = convert_timespec(&ts);
-    return 0;
-#endif
+    return __WASI_ESUCCESS;
 }
 
 struct fd_prestat {
@@ -2081,7 +2077,7 @@ wasmtime_ssp_poll_oneoff(wasm_exec_env_t exec_env, struct fd_table *curfds,
         };
 #if CONFIG_HAS_CLOCK_NANOSLEEP
         clockid_t clock_id;
-        if (convert_clockid(in[0].u.u.clock.clock_id, &clock_id)) {
+        if (wasi_clockid_to_clockid(in[0].u.u.clock.clock_id, &clock_id)) {
             struct timespec ts;
             convert_timestamp(in[0].u.u.clock.timeout, &ts);
             int ret = clock_nanosleep(

+ 72 - 0
core/shared/platform/common/posix/posix_clock.c

@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2023 Amazon Inc.  All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#include "platform_api_vmcore.h"
+
+#define NANOSECONDS_PER_SECOND 1000000000ULL
+
+static bool
+bh_clockid_to_clockid(bh_clock_id_t in, clockid_t *out)
+{
+    switch (in) {
+        case BH_CLOCK_ID_MONOTONIC:
+            *out = CLOCK_MONOTONIC;
+            return true;
+#if defined(CLOCK_PROCESS_CPUTIME_ID)
+        case BH_CLOCK_ID_PROCESS_CPUTIME_ID:
+            *out = CLOCK_PROCESS_CPUTIME_ID;
+            return true;
+#endif
+        case BH_CLOCK_ID_REALTIME:
+            *out = CLOCK_REALTIME;
+            return true;
+#if defined(CLOCK_THREAD_CPUTIME_ID)
+        case BH_CLOCK_ID_THREAD_CPUTIME_ID:
+            *out = CLOCK_THREAD_CPUTIME_ID;
+            return true;
+#endif
+        default:
+            errno = EINVAL;
+            return false;
+    }
+}
+
+static uint64
+timespec_to_nanoseconds(const struct timespec *ts)
+{
+    if (ts->tv_sec < 0)
+        return 0;
+    if ((uint64)ts->tv_sec >= UINT64_MAX / NANOSECONDS_PER_SECOND)
+        return UINT64_MAX;
+    return (uint64)ts->tv_sec * NANOSECONDS_PER_SECOND + (uint64)ts->tv_nsec;
+}
+
+int
+os_clock_res_get(bh_clock_id_t clock_id, uint64 *resolution)
+{
+    clockid_t nclock_id;
+    if (!bh_clockid_to_clockid(clock_id, &nclock_id))
+        return BHT_ERROR;
+    struct timespec ts;
+    if (clock_getres(nclock_id, &ts) < 0)
+        return BHT_ERROR;
+    *resolution = timespec_to_nanoseconds(&ts);
+
+    return BHT_OK;
+}
+
+int
+os_clock_time_get(bh_clock_id_t clock_id, uint64 precision, uint64 *time)
+{
+    clockid_t nclock_id;
+    if (!bh_clockid_to_clockid(clock_id, &nclock_id))
+        return BHT_ERROR;
+    struct timespec ts;
+    if (clock_gettime(nclock_id, &ts) < 0)
+        return BHT_ERROR;
+    *time = timespec_to_nanoseconds(&ts);
+
+    return 0;
+}

+ 20 - 0
core/shared/platform/include/platform_api_extension.h

@@ -36,6 +36,26 @@ extern "C" {
  * 2. To build the app-mgr and app-framework, you must implement it
  */
 
+/**
+ * Get a resolution of the clock
+ *
+ * @param clock_id clock identifier
+ * @param resolution output variable to store the clock resolution
+ * @return BHT_OK if success; otherwise, BHT_ERROR
+ */
+int
+os_clock_res_get(bh_clock_id_t clock_id, uint64 *resolution);
+
+/**
+ * Get a current time of the clock
+ *
+ * @param clock_id clock identifier
+ * @param time output variable to store the clock time
+ * @return BHT_OK if success; otherwise, BHT_ERROR
+ */
+int
+os_clock_time_get(bh_clock_id_t clock_id, uint64 precision, uint64 *time);
+
 /**
  * Creates a thread
  *

+ 7 - 0
core/shared/platform/include/platform_common.h

@@ -37,6 +37,13 @@ extern "C" {
 #define BH_TIME_T_MAX LONG_MAX
 #endif
 
+typedef enum {
+    BH_CLOCK_ID_REALTIME,
+    BH_CLOCK_ID_MONOTONIC,
+    BH_CLOCK_ID_PROCESS_CPUTIME_ID,
+    BH_CLOCK_ID_THREAD_CPUTIME_ID
+} bh_clock_id_t;
+
 #if defined(_MSC_BUILD)
 #if defined(COMPILING_WASM_RUNTIME_API)
 __declspec(dllexport) void *BH_MALLOC(unsigned int size);

+ 2 - 0
core/shared/platform/linux-sgx/shared_platform.cmake

@@ -36,6 +36,8 @@ endif()
 
 file (GLOB source_all_untrusted ${PLATFORM_SHARED_DIR}/untrusted/*.c)
 
+list(APPEND source_all ${PLATFORM_SHARED_DIR}/../common/posix/posix_clock.c)
+
 set (PLATFORM_SHARED_SOURCE ${source_all})
 
 set (PLATFORM_SHARED_SOURCE_UNTRUSTED ${source_all_untrusted})

+ 160 - 0
core/shared/platform/windows/win_clock.c

@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2023 Amazon Inc.  All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#include "platform_api_vmcore.h"
+#include <winternl.h>
+
+#define NANOSECONDS_PER_SECOND 1000000000ULL
+#define NANOSECONDS_PER_TICK 100
+
+static int
+calculate_monotonic_clock_frequency(uint64 *out_frequency)
+{
+    LARGE_INTEGER frequency;
+    if (!QueryPerformanceFrequency(&frequency)) {
+        return BHT_ERROR;
+    }
+    else {
+        *out_frequency = (uint64)frequency.QuadPart;
+        return BHT_OK;
+    }
+}
+
+// The implementation below derives from the following source:
+// https://github.com/WasmEdge/WasmEdge/blob/b70f48c42922ce5ee7730054b6ac0b1615176285/lib/host/wasi/win.h#L210
+static uint64
+filetime_to_wasi_timestamp(FILETIME filetime)
+{
+    static const uint64 ntto_unix_epoch =
+        134774ULL * 86400ULL * NANOSECONDS_PER_SECOND;
+
+    ULARGE_INTEGER temp = { .LowPart = filetime.dwLowDateTime,
+                            .HighPart = filetime.dwHighDateTime };
+
+    return (temp.QuadPart * 100ull) - ntto_unix_epoch;
+}
+
+static int
+get_performance_counter_value(uint64 *out_counter)
+{
+    LARGE_INTEGER counter;
+    if (!QueryPerformanceCounter(&counter)) {
+        return BHT_ERROR;
+    }
+    else {
+        *out_counter = counter.QuadPart;
+        return BHT_OK;
+    }
+}
+
+int
+os_clock_res_get(bh_clock_id_t clock_id, uint64 *resolution)
+{
+    switch (clock_id) {
+        case BH_CLOCK_ID_MONOTONIC:
+        {
+            uint64 frequency;
+            if (calculate_monotonic_clock_frequency(&frequency) == BHT_ERROR) {
+                return BHT_ERROR;
+            }
+            const uint64 result = (uint64)NANOSECONDS_PER_SECOND / frequency;
+            *resolution = result;
+            return BHT_OK;
+        }
+        case BH_CLOCK_ID_REALTIME:
+        case BH_CLOCK_ID_PROCESS_CPUTIME_ID:
+        case BH_CLOCK_ID_THREAD_CPUTIME_ID:
+        {
+            PULONG maximum_time;
+            PULONG minimum_time;
+            PULONG current_time;
+            NTSTATUS
+            status = NtQueryTimerResolution(&maximum_time, &minimum_time,
+                                            &current_time);
+
+            uint64 result = (uint64)current_time * NANOSECONDS_PER_TICK;
+            *resolution = result / (uint64)NANOSECONDS_PER_SECOND;
+            return BHT_OK;
+        }
+        default:
+            errno = EINVAL;
+            return BHT_ERROR;
+    }
+}
+
+int
+os_clock_time_get(bh_clock_id_t clock_id, uint64 precision, uint64 *time)
+{
+    switch (clock_id) {
+        case BH_CLOCK_ID_REALTIME:
+        {
+            FILETIME sys_now;
+#if NTDDI_VERSION >= NTDDI_WIN8
+            GetSystemTimePreciseAsFileTime(&sys_now);
+#else
+            GetSystemTimeAsFileTime(&SysNow);
+#endif
+            *time = filetime_to_wasi_timestamp(sys_now);
+            return BHT_OK;
+        }
+        case BH_CLOCK_ID_MONOTONIC:
+        {
+            uint64 frequency;
+            if (calculate_monotonic_clock_frequency(&frequency) == BHT_ERROR) {
+                return BHT_ERROR;
+            }
+            uint64 counter;
+            if (get_performance_counter_value(&counter) == BHT_ERROR) {
+                return BHT_ERROR;
+            }
+            if (NANOSECONDS_PER_SECOND % frequency == 0) {
+                *time = counter * NANOSECONDS_PER_SECOND / frequency;
+            }
+            else {
+                uint64 seconds = counter / frequency;
+                uint64 fractions = counter % frequency;
+                *time = seconds * NANOSECONDS_PER_SECOND
+                        + (fractions * NANOSECONDS_PER_SECOND) / frequency;
+            }
+            return BHT_OK;
+        }
+        case BH_CLOCK_ID_PROCESS_CPUTIME_ID:
+        {
+            FILETIME creation_time;
+            FILETIME exit_time;
+            FILETIME kernel_time;
+            FILETIME user_time;
+
+            if (!GetProcessTimes(GetCurrentProcess(), &creation_time,
+                                 &exit_time, &kernel_time, &user_time)) {
+                return BHT_ERROR;
+            }
+            *time = filetime_to_wasi_timestamp(kernel_time)
+                    + filetime_to_wasi_timestamp(user_time);
+
+            return BHT_OK;
+        }
+        case BH_CLOCK_ID_THREAD_CPUTIME_ID:
+        {
+            FILETIME creation_time;
+            FILETIME exit_time;
+            FILETIME kernel_time;
+            FILETIME user_time;
+
+            if (!GetProcessTimes(GetCurrentThread(), &creation_time, &exit_time,
+                                 &kernel_time, &user_time)) {
+                return BHT_ERROR;
+            }
+
+            *time = filetime_to_wasi_timestamp(kernel_time)
+                    + filetime_to_wasi_timestamp(user_time);
+
+            return BHT_OK;
+        }
+        default:
+            errno = EINVAL;
+            return BHT_ERROR;
+    }
+}

+ 1 - 0
product-mini/platforms/nuttx/wamr.mk

@@ -364,6 +364,7 @@ CSRCS += nuttx_platform.c \
          posix_blocking_op.c \
          posix_thread.c \
          posix_time.c \
+         posix_clock.c \
          posix_sleep.c \
          mem_alloc.c \
          ems_kfc.c \

+ 6 - 0
product-mini/platforms/windows/CMakeLists.txt

@@ -153,3 +153,9 @@ target_link_libraries (libiwasm ${LLVM_AVAILABLE_LIBS} ${UV_A_LIBS})
 if (MINGW)
   target_link_libraries (libiwasm ws2_32)
 endif ()
+
+if (WIN32)
+  target_link_libraries(libiwasm ntdll)
+
+  target_link_libraries(iwasm ntdll)  
+endif()