From 84a8e89b10a85beaacdc9d465c910748a589eb27 Mon Sep 17 00:00:00 2001 From: Gregory Comer Date: Sun, 4 May 2025 00:46:12 -0700 Subject: [PATCH] Introduce PAL function table Summary: This is part 1 of the implementation of the PAL changes described in https://github.com/pytorch/executorch/discussions/10432. This PR introduces a struct (`pal_table`) to hold function pointers to the PAL function implementations. There is a singleton instance of this struct, which is initialized with the weak/strong et_pal_ functions - maintaining backwards compatibility with the existing override mechanism. I've then added wrapper functions for the PAL into the executorch::runtime namespace which dispatch through the function table. It is intended that callers use these functions instead of the "raw" et_pal_ methods in order to correctly dispatch through the function table. In the following PR, I update ET callers to do this. Differential Revision: D74121895 --- runtime/platform/platform.cpp | 76 +++++++++++++++++++++++ runtime/platform/platform.h | 111 ++++++++++++++++++++++++++++++++++ runtime/platform/targets.bzl | 1 + 3 files changed, 188 insertions(+) create mode 100644 runtime/platform/platform.cpp diff --git a/runtime/platform/platform.cpp b/runtime/platform/platform.cpp new file mode 100644 index 00000000000..5be3b343088 --- /dev/null +++ b/runtime/platform/platform.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include + +namespace executorch { +namespace runtime { + +/** + * The singleton instance of the PAL table. + */ +static pal_table global_pal_table = { + .init = et_pal_init, + .abort = et_pal_abort, + .current_ticks = et_pal_current_ticks, + .ticks_to_ns_multiplier = et_pal_ticks_to_ns_multiplier, + .emit_log_message = et_pal_emit_log_message, + .allocate = et_pal_allocate, + .free = et_pal_free, +}; + +/** + * Retrieve a pointer to the singleton instance of the PAL function table. This + * can be used to override the default implementations of the PAL functions. + */ +pal_table* get_pal_table() { + return &global_pal_table; +} + +void pal_init() { + get_pal_table()->init(); +} + +ET_NORETURN void pal_abort() { + get_pal_table()->abort(); + // This should be unreachable, but in case the PAL implementation doesn't + // abort, force it here. + std::abort(); +} + +et_timestamp_t pal_current_ticks() { + return get_pal_table()->current_ticks(); +} + +et_tick_ratio_t pal_ticks_to_ns_multiplier() { + return get_pal_table()->ticks_to_ns_multiplier(); +} + +void pal_emit_log_message( + et_timestamp_t timestamp, + et_pal_log_level_t level, + const char* filename, + const char* function, + size_t line, + const char* message, + size_t length) { + get_pal_table()->emit_log_message( + timestamp, level, filename, function, line, message, length); +} + +void* pal_allocate(size_t size) { + return get_pal_table()->allocate(size); +} + +void pal_free(void* ptr) { + get_pal_table()->free(ptr); +} + +} // namespace runtime +} // namespace executorch diff --git a/runtime/platform/platform.h b/runtime/platform/platform.h index 03cdef8eb2f..a15529c25e5 100644 --- a/runtime/platform/platform.h +++ b/runtime/platform/platform.h @@ -11,6 +11,10 @@ * Platform abstraction layer to allow individual platform libraries to override * symbols in ExecuTorch. PAL functions are defined as C functions so a platform * library implementer can use C in lieu of C++. + * + * The et_pal_ methods should not be called directly. Use the corresponding methods + * in the executorch::runtime namespace instead to appropriately dispatch through + * the PAL function table. */ #pragma once @@ -53,12 +57,14 @@ typedef struct { * to initialize any global state. Typically overridden by PAL implementer. */ void et_pal_init(void) ET_INTERNAL_PLATFORM_WEAKNESS; +typedef void (*et_pal_init_t)(void); /** * Immediately abort execution, setting the device into an error state, if * available. */ ET_NORETURN void et_pal_abort(void) ET_INTERNAL_PLATFORM_WEAKNESS; +typedef void (*et_pal_abort_t)(void); /** * Return a monotonically non-decreasing timestamp in system ticks. @@ -66,6 +72,7 @@ ET_NORETURN void et_pal_abort(void) ET_INTERNAL_PLATFORM_WEAKNESS; * @retval Timestamp value in system ticks. */ et_timestamp_t et_pal_current_ticks(void) ET_INTERNAL_PLATFORM_WEAKNESS; +typedef et_timestamp_t (*et_pal_current_ticks_t)(void); /** * Return the conversion rate from system ticks to nanoseconds as a fraction. @@ -79,6 +86,7 @@ et_timestamp_t et_pal_current_ticks(void) ET_INTERNAL_PLATFORM_WEAKNESS; * * @retval The ratio of nanoseconds to system ticks. */ +typedef et_tick_ratio_t (*et_pal_ticks_to_ns_multiplier_t)(void); et_tick_ratio_t et_pal_ticks_to_ns_multiplier(void) ET_INTERNAL_PLATFORM_WEAKNESS; @@ -114,6 +122,14 @@ void et_pal_emit_log_message( size_t line, const char* message, size_t length) ET_INTERNAL_PLATFORM_WEAKNESS; +typedef void (*et_pal_emit_log_message_t)( + et_timestamp_t timestamp, + et_pal_log_level_t level, + const char* filename, + const char* function, + size_t line, + const char* message, + size_t length); /** * NOTE: Core runtime code must not call this directly. It may only be called by @@ -126,6 +142,7 @@ void et_pal_emit_log_message( * et_pal_free(). */ void* et_pal_allocate(size_t size) ET_INTERNAL_PLATFORM_WEAKNESS; +typedef void* (*et_pal_allocate_t)(size_t size); /** * Frees memory allocated by et_pal_allocate(). @@ -133,5 +150,99 @@ void* et_pal_allocate(size_t size) ET_INTERNAL_PLATFORM_WEAKNESS; * @param[in] ptr Pointer to memory to free. May be nullptr. */ void et_pal_free(void* ptr) ET_INTERNAL_PLATFORM_WEAKNESS; +typedef void (*et_pal_free_t)(void* ptr); } // extern "C" + +namespace executorch { +namespace runtime { + +/** + * Table of pointers to platform abstraction layer functions. + */ +struct pal_table { + et_pal_init_t init; + et_pal_abort_t abort; + et_pal_current_ticks_t current_ticks; + et_pal_ticks_to_ns_multiplier_t ticks_to_ns_multiplier; + et_pal_emit_log_message_t emit_log_message; + et_pal_allocate_t allocate; + et_pal_free_t free; +}; + +/** + * Retrieve a pointer to the singleton instance of the PAL function table. This + * can be used to override the default implementations of the PAL functions. + */ +pal_table* get_pal_table(void); + +/** + * Initialize the platform abstraction layer. + * + * This function should be called before any other function provided by the PAL + * to initialize any global state. Typically overridden by PAL implementer. + */ +void pal_init(); + +/** + * Immediately abort execution, setting the device into an error state, if + * available. + */ +ET_NORETURN void pal_abort(); + +/** + * Return a monotonically non-decreasing timestamp in system ticks. + * + * @retval Timestamp value in system ticks. + */ +et_timestamp_t pal_current_ticks(); + +/** + * Return the conversion rate from system ticks to nanoseconds as a fraction. + * To convert a system ticks to nanoseconds, multiply the tick count by the + * numerator and then divide by the denominator: + * nanoseconds = ticks * numerator / denominator + * + * The utility method executorch::runtime::ticks_to_ns(et_timestamp_t) can also + * be used to perform the conversion for a given tick count. It is defined in + * torch/executor/runtime/platform/clock.h. + * + * @retval The ratio of nanoseconds to system ticks. + */ +et_tick_ratio_t pal_ticks_to_ns_multiplier(); + +/** + * Severity level of a log message. Values must map to printable 7-bit ASCII + * uppercase letters. + */ +void pal_emit_log_message( + et_timestamp_t timestamp, + et_pal_log_level_t level, + const char* filename, + const char* function, + size_t line, + const char* message, + size_t length); + +/** + * NOTE: Core runtime code must not call this directly. It may only be called by + * a MemoryAllocator wrapper. + * + * Allocates size bytes of memory. + * + * @param[in] size Number of bytes to allocate. + * @returns the allocated memory, or nullptr on failure. Must be freed using + * et_pal_free(). + */ +void* pal_allocate(size_t size); + +/** + * Frees memory allocated by et_pal_allocate(). + * + * @param[in] ptr Pointer to memory to free. May be nullptr. + */ +void pal_free(void* ptr); + + +} // namespace runtime +} // namespace executorch diff --git a/runtime/platform/targets.bzl b/runtime/platform/targets.bzl index 68322ffe97f..3bfeb9f4149 100644 --- a/runtime/platform/targets.bzl +++ b/runtime/platform/targets.bzl @@ -73,6 +73,7 @@ def define_common_targets(): srcs = [ "abort.cpp", "log.cpp", + "platform.cpp", "profiler.cpp", "runtime.cpp", ],