With external time travel, a LOT of message can end up being exchanged on the socket, taking a significant amount of time just to do that. Add a new shared memory optimisation to that, where a number of changes are made: - the controller sends a client ID and a shared memory FD (and a logging FD we don't use) in the ACK message to the initial START - the shared memory holds the current time and the free_until value, so that there's no need to exchange messages for that - if the client that's running has shared memory support, any client (the running one included) can request the next time it wants to run inside the shared memory, rather than sending a message, by also updating the free_until value - when shared memory is enabled, RUN/WAIT messages no longer have an ACK, further cutting down on messages Together, this can reduce the number of messages very significantly, and reduce overall test/simulation run time.
Showing the changes to include/uapi (1 of 2 files). Show all
Unified · Split
| @@ -1,17 +1,6 @@ | |||
| 1 | /* SPDX-License-Identifier: BSD-3-Clause */ | ||
| 1 | /* | 2 | /* |
| 2 | * Permission to use, copy, modify, and/or distribute this software for any | 3 | * Copyright (C) 2019 - 2023 Intel Corporation |
| 3 | * purpose with or without fee is hereby granted, provided that the above | ||
| 4 | * copyright notice and this permission notice appear in all copies. | ||
| 5 | * | ||
| 6 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
| 7 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
| 8 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
| 9 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
| 10 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
| 11 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
| 12 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
| 13 | * | ||
| 14 | * Copyright (C) 2019 Intel Corporation | ||
| 15 | */ | 4 | */ |
| 16 | #ifndef _UAPI_LINUX_UM_TIMETRAVEL_H | 5 | #ifndef _UAPI_LINUX_UM_TIMETRAVEL_H |
| 17 | #define _UAPI_LINUX_UM_TIMETRAVEL_H | 6 | #define _UAPI_LINUX_UM_TIMETRAVEL_H |
| @@ -50,6 +39,36 @@ struct um_timetravel_msg { · 32 unmodified lines | |||
| 50 | __u64 time; | 39 | __u64 time; |
| 51 | }; | 40 | }; |
| 52 | 41 | ||
| 42 | /* max number of file descriptors that can be sent/received in a message */ | ||
| 43 | #define UM_TIMETRAVEL_MAX_FDS 2 | ||
| 44 | |||
| 45 | /** | ||
| 46 | * enum um_timetravel_shared_mem_fds - fds sent in ACK message for START message | ||
| 47 | */ | ||
| 48 | enum um_timetravel_shared_mem_fds { | ||
| 49 | /** | ||
| 50 | * @UM_TIMETRAVEL_SHARED_MEMFD: Index of the shared memory file | ||
| 51 | * descriptor in the control message | ||
| 52 | */ | ||
| 53 | UM_TIMETRAVEL_SHARED_MEMFD, | ||
| 54 | /** | ||
| 55 | * @UM_TIMETRAVEL_SHARED_LOGFD: Index of the logging file descriptor | ||
| 56 | * in the control message | ||
| 57 | */ | ||
| 58 | UM_TIMETRAVEL_SHARED_LOGFD, | ||
| 59 | UM_TIMETRAVEL_SHARED_MAX_FDS, | ||
| 60 | }; | ||
| 61 | |||
| 62 | /** | ||
| 63 | * enum um_timetravel_start_ack - ack-time mask for start message | ||
| 64 | */ | ||
| 65 | enum um_timetravel_start_ack { | ||
| 66 | /** | ||
| 67 | * @UM_TIMETRAVEL_START_ACK_ID: client ID that controller allocated. | ||
| 68 | */ | ||
| 69 | UM_TIMETRAVEL_START_ACK_ID = 0xffff, | ||
| 70 | }; | ||
| 71 | |||
| 53 | /** | 72 | /** |
| 54 | * enum um_timetravel_ops - Operation codes | 73 | * enum um_timetravel_ops - Operation codes |
| 55 | */ | 74 | */ |
| @@ -57,7 +76,9 @@ enum um_timetravel_ops { · 1 unmodified line | |||
| 57 | /** | 76 | /** |
| 58 | * @UM_TIMETRAVEL_ACK: response (ACK) to any previous message, | 77 | * @UM_TIMETRAVEL_ACK: response (ACK) to any previous message, |
| 59 | * this usually doesn't carry any data in the 'time' field | 78 | * this usually doesn't carry any data in the 'time' field |
| 60 | * unless otherwise specified below | 79 | * unless otherwise specified below, note: while using shared |
| 80 | * memory no ACK for WAIT and RUN messages, for more info see | ||
| 81 | * &struct um_timetravel_schedshm. | ||
| 61 | */ | 82 | */ |
| 62 | UM_TIMETRAVEL_ACK = 0, | 83 | UM_TIMETRAVEL_ACK = 0, |
| 63 | 84 | ||
| @@ -136,4 +157,134 @@ enum um_timetravel_ops { · 72 unmodified lines | |||
| 136 | UM_TIMETRAVEL_BROADCAST = 9, | 157 | UM_TIMETRAVEL_BROADCAST = 9, |
| 137 | }; | 158 | }; |
| 138 | 159 | ||
| 160 | /* version of struct um_timetravel_schedshm */ | ||
| 161 | #define UM_TIMETRAVEL_SCHEDSHM_VERSION 2 | ||
| 162 | |||
| 163 | /** | ||
| 164 | * enum um_timetravel_schedshm_cap - time travel capabilities of every client | ||
| 165 | * | ||
| 166 | * These flags must be set immediately after processing the ACK to | ||
| 167 | * the START message, before sending any message to the controller. | ||
| 168 | */ | ||
| 169 | enum um_timetravel_schedshm_cap { | ||
| 170 | /** | ||
| 171 | * @UM_TIMETRAVEL_SCHEDSHM_CAP_TIME_SHARE: client can read current time | ||
| 172 | * update internal time request to shared memory and read | ||
| 173 | * free until and send no Ack on RUN and doesn't expect ACK on | ||
| 174 | * WAIT. | ||
| 175 | */ | ||
| 176 | UM_TIMETRAVEL_SCHEDSHM_CAP_TIME_SHARE = 0x1, | ||
| 177 | }; | ||
| 178 | |||
| 179 | /** | ||
| 180 | * enum um_timetravel_schedshm_flags - time travel flags of every client | ||
| 181 | */ | ||
| 182 | enum um_timetravel_schedshm_flags { | ||
| 183 | /** | ||
| 184 | * @UM_TIMETRAVEL_SCHEDSHM_FLAGS_REQ_RUN: client has a request to run. | ||
| 185 | * It's set by client when it has a request to run, if (and only | ||
| 186 | * if) the @running_id points to a client that is able to use | ||
| 187 | * shared memory, i.e. has %UM_TIMETRAVEL_SCHEDSHM_CAP_TIME_SHARE | ||
| 188 | * (this includes the client itself). Otherwise, a message must | ||
| 189 | * be used. | ||
| 190 | */ | ||
| 191 | UM_TIMETRAVEL_SCHEDSHM_FLAGS_REQ_RUN = 0x1, | ||
| 192 | }; | ||
| 193 | |||
| 194 | /** | ||
| 195 | * DOC: Time travel shared memory overview | ||
| 196 | * | ||
| 197 | * The main purpose of the shared memory is to avoid all time travel message | ||
| 198 | * that don't need any action, for example current time can be held in shared | ||
| 199 | * memory without the need of any client to send a message UM_TIMETRAVEL_GET | ||
| 200 | * in order to know what's the time. | ||
| 201 | * | ||
| 202 | * Since this is shared memory with all clients and controller and controller | ||
| 203 | * creates the shared memory space, all time values are absolute to controller | ||
| 204 | * time. So first time client connects to shared memory mode it should take the | ||
| 205 | * current_time value in shared memory and keep it internally as a diff to | ||
| 206 | * shared memory times, and once shared memory is initialized, any interaction | ||
| 207 | * with the controller must happen in the controller time domain, including any | ||
| 208 | * messages (for clients that are not using shared memory, the controller will | ||
| 209 | * handle an offset and make the clients think they start at time zero.) | ||
| 210 | * | ||
| 211 | * Along with the shared memory file descriptor is sent to the client a logging | ||
| 212 | * file descriptor, to have all logs related to shared memory, | ||
| 213 | * logged into one place. note: to have all logs synced into log file at write, | ||
| 214 | * file should be flushed (fflush) after writing to it. | ||
| 215 | * | ||
| 216 | * To avoid memory corruption, we define below for each field who can write to | ||
| 217 | * it at what time, defined in the structure fields. | ||
| 218 | * | ||
| 219 | * To avoid having to pack this struct, all fields in it must be naturally aligned | ||
| 220 | * (i.e. aligned to their size). | ||
| 221 | */ | ||
| 222 | |||
| 223 | /** | ||
| 224 | * union um_timetravel_schedshm_client - UM time travel client struct | ||
| 225 | * | ||
| 226 | * Every entity using the shared memory including the controller has a place in | ||
| 227 | * the um_timetravel_schedshm clients array, that holds info related to the client | ||
| 228 | * using the shared memory, and can be set only by the client after it gets the | ||
| 229 | * fd memory. | ||
| 230 | * | ||
| 231 | * @capa: bit fields with client capabilities see | ||
| 232 | * &enum um_timetravel_schedshm_cap, set by client once after getting the | ||
| 233 | * shared memory file descriptor. | ||
| 234 | * @flags: bit fields for flags see &enum um_timetravel_schedshm_flags for doc. | ||
| 235 | * @req_time: request time to run, set by client on every request it needs. | ||
| 236 | * @name: unique id sent to the controller by client with START message. | ||
| 237 | */ | ||
| 238 | union um_timetravel_schedshm_client { | ||
| 239 | struct { | ||
| 240 | __u32 capa; | ||
| 241 | __u32 flags; | ||
| 242 | __u64 req_time; | ||
| 243 | __u64 name; | ||
| 244 | }; | ||
| 245 | char reserve[128]; /* reserved for future usage */ | ||
| 246 | }; | ||
| 247 | |||
| 248 | /** | ||
| 249 | * struct um_timetravel_schedshm - UM time travel shared memory struct | ||
| 250 | * | ||
| 251 | * @hdr: header fields: | ||
| 252 | * @version: Current version struct UM_TIMETRAVEL_SCHEDSHM_VERSION, | ||
| 253 | * set by controller once at init, clients must check this after mapping | ||
| 254 | * and work without shared memory if they cannot handle the indicated | ||
| 255 | * version. | ||
| 256 | * @len: Length of all the memory including header (@hdr), clients should once | ||
| 257 | * per connection first mmap the header and take the length (@len) to remap the entire size. | ||
| 258 | * This is done in order to support dynamic struct size letting number of | ||
| 259 | * clients be dynamic based on controller support. | ||
| 260 | * @free_until: Stores the next request to run by any client, in order for the | ||
| 261 | * current client to know how long it can still run. A client needs to (at | ||
| 262 | * least) reload this value immediately after communicating with any other | ||
| 263 | * client, since the controller will update this field when a new request | ||
| 264 | * is made by any client. Clients also must update this value when they | ||
| 265 | * insert/update an own request into the shared memory while not running | ||
| 266 | * themselves, and the new request is before than the current value. | ||
| 267 | * current_time: Current time, can only be set by the client in running state | ||
| 268 | * (indicated by @running_id), though that client may only run until @free_until, | ||
| 269 | * so it must remain smaller than @free_until. | ||
| 270 | * @running_id: The current client in state running, set before a client is | ||
| 271 | * notified that it's now running. | ||
| 272 | * @max_clients: size of @clients array, set once at init by the controller. | ||
| 273 | * @clients: clients array see &union um_timetravel_schedshm_client for doc, | ||
| 274 | * set only by client. | ||
| 275 | */ | ||
| 276 | struct um_timetravel_schedshm { | ||
| 277 | union { | ||
| 278 | struct { | ||
| 279 | __u32 version; | ||
| 280 | __u32 len; | ||
| 281 | __u64 free_until; | ||
| 282 | __u64 current_time; | ||
| 283 | __u16 running_id; | ||
| 284 | __u16 max_clients; | ||
| 285 | }; | ||
| 286 | char hdr[4096]; /* align to 4K page size */ | ||
| 287 | }; | ||
| 288 | union um_timetravel_schedshm_client clients[]; | ||
| 289 | }; | ||
| 139 | #endif /* _UAPI_LINUX_UM_TIMETRAVEL_H */ | 290 | #endif /* _UAPI_LINUX_UM_TIMETRAVEL_H */ |