1 /*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the root directory of this source tree.
7 */
8
9 /**
10 * @file
11 * Fallback PAL implementations for POSIX-compatible systems.
12 *
13 * Note that this assumes that the platform defines the symbols used in this
14 * file (like fprintf()), because this file will still be built even if the
15 * functions are later overridden. When building for a platform that does not
16 * provide the necessary symbols, clients can use Minimal.cpp instead, but they
17 * will need to override all of the functions.
18 */
19
20 // This cpp file will provide weak implementations of the symbols declared in
21 // Platform.h. Client users can strongly define any or all of the functions to
22 // override them.
23 #define ET_INTERNAL_PLATFORM_WEAKNESS ET_WEAK
24 #include <executorch/runtime/platform/platform.h>
25
26 #include <chrono>
27 #include <cinttypes>
28 #include <cstdio>
29 #include <cstdlib>
30
31 #include <executorch/runtime/platform/compiler.h>
32
33 // The FILE* to write logs to.
34 #define ET_LOG_OUTPUT_FILE stderr
35
36 /**
37 * On debug builds, ensure that `et_pal_init` has been called before
38 * other PAL functions which depend on initialization.
39 */
40 #ifdef NDEBUG
41
42 /**
43 * Assert that the PAL has been initialized.
44 */
45 #define _ASSERT_PAL_INITIALIZED() ((void)0)
46
47 #else // NDEBUG
48
49 /**
50 * Assert that the PAL has been initialized.
51 */
52 #define _ASSERT_PAL_INITIALIZED() \
53 do { \
54 if (!initialized) { \
55 fprintf( \
56 ET_LOG_OUTPUT_FILE, \
57 "ExecuTorch PAL must be initialized before call to %s()", \
58 ET_FUNCTION); \
59 fflush(ET_LOG_OUTPUT_FILE); \
60 et_pal_abort(); \
61 } \
62 } while (0)
63
64 #endif // NDEBUG
65
66 /// Start time of the system (used to zero the system timestamp).
67 static std::chrono::time_point<std::chrono::steady_clock> systemStartTime;
68
69 /// Flag set to true if the PAL has been successfully initialized.
70 static bool initialized = false;
71
72 /**
73 * Initialize the platform abstraction layer.
74 *
75 * This function should be called before any other function provided by the PAL
76 * to initialize any global state. Typically overridden by PAL implementer.
77 */
et_pal_init(void)78 void et_pal_init(void) {
79 if (initialized) {
80 return;
81 }
82
83 systemStartTime = std::chrono::steady_clock::now();
84 initialized = true;
85 }
86
87 /**
88 * Immediately abort execution, setting the device into an error state, if
89 * available.
90 */
et_pal_abort(void)91 ET_NORETURN void et_pal_abort(void) {
92 std::abort();
93 }
94
95 /**
96 * Return a monotonically non-decreasing timestamp in system ticks.
97 *
98 * @retval Timestamp value in system ticks.
99 */
et_pal_current_ticks(void)100 et_timestamp_t et_pal_current_ticks(void) {
101 _ASSERT_PAL_INITIALIZED();
102 auto systemCurrentTime = std::chrono::steady_clock::now();
103 return std::chrono::duration_cast<std::chrono::nanoseconds>(
104 systemCurrentTime - systemStartTime)
105 .count();
106 }
107
108 /**
109 * Return the conversion rate from system ticks to nanoseconds, as a fraction.
110 * To convert an interval from system ticks to nanoseconds, multiply the tick
111 * count by the numerator and then divide by the denominator:
112 * nanoseconds = ticks * numerator / denominator
113 *
114 * @retval The ratio of nanoseconds to system ticks.
115 */
et_pal_ticks_to_ns_multiplier(void)116 et_tick_ratio_t et_pal_ticks_to_ns_multiplier(void) {
117 // The system tick interval is 1 nanosecond, so the conversion factor is 1.
118 return {1, 1};
119 }
120
121 /**
122 * Emit a log message via platform output (serial port, console, etc).
123 *
124 * @param[in] timestamp Timestamp of the log event in system ticks since boot.
125 * @param[in] level Severity level of the message. Must be a printable 7-bit
126 * ASCII uppercase letter.
127 * @param[in] filename Name of the file that created the log event.
128 * @param[in] function Name of the function that created the log event.
129 * @param[in] line Line in the source file where the log event was created.
130 * @param[in] message Message string to log.
131 * @param[in] length Message string length.
132 */
et_pal_emit_log_message(et_timestamp_t timestamp,et_pal_log_level_t level,const char * filename,ET_UNUSED const char * function,size_t line,const char * message,ET_UNUSED size_t length)133 void et_pal_emit_log_message(
134 et_timestamp_t timestamp,
135 et_pal_log_level_t level,
136 const char* filename,
137 ET_UNUSED const char* function,
138 size_t line,
139 const char* message,
140 ET_UNUSED size_t length) {
141 _ASSERT_PAL_INITIALIZED();
142
143 // Not all platforms have ticks == nanoseconds, but this one does.
144 timestamp /= 1000; // To microseconds
145 unsigned long int us = timestamp % 1000000;
146 timestamp /= 1000000; // To seconds
147 unsigned int sec = timestamp % 60;
148 timestamp /= 60; // To minutes
149 unsigned int min = timestamp % 60;
150 timestamp /= 60; // To hours
151 unsigned int hour = timestamp;
152
153 // Use a format similar to glog and folly::logging, except:
154 // - Print time since et_pal_init since we don't have wall time
155 // - Don't include the thread ID, to avoid adding a threading dependency
156 // - Add the string "executorch:" to make the logs more searchable
157 //
158 // Clients who want to change the format or add other fields can override this
159 // weak implementation of et_pal_emit_log_message.
160 fprintf(
161 ET_LOG_OUTPUT_FILE,
162 "%c %02u:%02u:%02u.%06lu executorch:%s:%zu] %s\n",
163 level,
164 hour,
165 min,
166 sec,
167 us,
168 filename,
169 line,
170 message);
171 fflush(ET_LOG_OUTPUT_FILE);
172 }
173
174 /**
175 * NOTE: Core runtime code must not call this directly. It may only be called by
176 * a MemoryAllocator wrapper.
177 *
178 * Allocates size bytes of memory via malloc.
179 *
180 * @param[in] size Number of bytes to allocate.
181 * @returns the allocated memory, or nullptr on failure. Must be freed using
182 * et_pal_free().
183 */
et_pal_allocate(size_t size)184 void* et_pal_allocate(size_t size) {
185 return malloc(size);
186 }
187
188 /**
189 * Frees memory allocated by et_pal_allocate().
190 *
191 * @param[in] ptr Pointer to memory to free. May be nullptr.
192 */
et_pal_free(void * ptr)193 void et_pal_free(void* ptr) {
194 free(ptr);
195 }
196