Skip to content

Commit bfb80d8

Browse files
committed
um: add shared memory optimisation for time-travel=ext
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. Co-developed-by: Mordechay Goodstein <[email protected]> Signed-off-by: Mordechay Goodstein <[email protected]> Link: https://patch.msgid.link/20240702192118.6ad0a083f574.Ie41206c8ce4507fe26b991937f47e86c24ca7a31@changeid Signed-off-by: Johannes Berg <[email protected]>
1 parent e20f9b3 commit bfb80d8

File tree

2 files changed

+283
-26
lines changed

2 files changed

+283
-26
lines changed

arch/um/kernel/time.c

Lines changed: 118 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ EXPORT_SYMBOL_GPL(time_travel_mode);
3131
static bool time_travel_start_set;
3232
static unsigned long long time_travel_start;
3333
static unsigned long long time_travel_time;
34+
static unsigned long long time_travel_shm_offset;
3435
static LIST_HEAD(time_travel_events);
3536
static LIST_HEAD(time_travel_irqs);
3637
static unsigned long long time_travel_timer_interval;
@@ -40,8 +41,11 @@ static int time_travel_ext_fd = -1;
4041
static unsigned int time_travel_ext_waiting;
4142
static bool time_travel_ext_prev_request_valid;
4243
static unsigned long long time_travel_ext_prev_request;
43-
static bool time_travel_ext_free_until_valid;
44-
static unsigned long long time_travel_ext_free_until;
44+
static unsigned long long *time_travel_ext_free_until;
45+
static unsigned long long _time_travel_ext_free_until;
46+
static u16 time_travel_shm_id;
47+
static struct um_timetravel_schedshm *time_travel_shm;
48+
static union um_timetravel_schedshm_client *time_travel_shm_client;
4549

4650
static void time_travel_set_time(unsigned long long ns)
4751
{
@@ -58,6 +62,7 @@ enum time_travel_message_handling {
5862
TTMH_IDLE,
5963
TTMH_POLL,
6064
TTMH_READ,
65+
TTMH_READ_START_ACK,
6166
};
6267

6368
static u64 bc_message;
@@ -69,6 +74,40 @@ void _time_travel_print_bc_msg(void)
6974
printk(KERN_INFO "time-travel: received broadcast 0x%llx\n", bc_message);
7075
}
7176

77+
static void time_travel_setup_shm(int fd, u16 id)
78+
{
79+
u32 len;
80+
81+
time_travel_shm = os_mmap_rw_shared(fd, sizeof(*time_travel_shm));
82+
83+
if (!time_travel_shm)
84+
goto out;
85+
86+
len = time_travel_shm->len;
87+
88+
if (time_travel_shm->version != UM_TIMETRAVEL_SCHEDSHM_VERSION ||
89+
len < struct_size(time_travel_shm, clients, id + 1)) {
90+
os_unmap_memory(time_travel_shm, sizeof(*time_travel_shm));
91+
time_travel_shm = NULL;
92+
goto out;
93+
}
94+
95+
time_travel_shm = os_mremap_rw_shared(time_travel_shm,
96+
sizeof(*time_travel_shm),
97+
len);
98+
if (!time_travel_shm)
99+
goto out;
100+
101+
time_travel_shm_offset = time_travel_shm->current_time;
102+
time_travel_shm_client = &time_travel_shm->clients[id];
103+
time_travel_shm_client->capa |= UM_TIMETRAVEL_SCHEDSHM_CAP_TIME_SHARE;
104+
time_travel_shm_id = id;
105+
/* always look at that free_until from now on */
106+
time_travel_ext_free_until = &time_travel_shm->free_until;
107+
out:
108+
os_close_file(fd);
109+
}
110+
72111
static void time_travel_handle_message(struct um_timetravel_msg *msg,
73112
enum time_travel_message_handling mode)
74113
{
@@ -89,7 +128,20 @@ static void time_travel_handle_message(struct um_timetravel_msg *msg,
89128
}
90129
}
91130

92-
ret = os_read_file(time_travel_ext_fd, msg, sizeof(*msg));
131+
if (unlikely(mode == TTMH_READ_START_ACK)) {
132+
int fd[UM_TIMETRAVEL_SHARED_MAX_FDS];
133+
134+
ret = os_rcv_fd_msg(time_travel_ext_fd, fd,
135+
ARRAY_SIZE(fd), msg, sizeof(*msg));
136+
if (ret == sizeof(*msg)) {
137+
time_travel_setup_shm(fd[UM_TIMETRAVEL_SHARED_MEMFD],
138+
msg->time & UM_TIMETRAVEL_START_ACK_ID);
139+
/* we don't use the logging for now */
140+
os_close_file(fd[UM_TIMETRAVEL_SHARED_LOGFD]);
141+
}
142+
} else {
143+
ret = os_read_file(time_travel_ext_fd, msg, sizeof(*msg));
144+
}
93145

94146
if (ret == 0)
95147
panic("time-travel external link is broken\n");
@@ -105,10 +157,20 @@ static void time_travel_handle_message(struct um_timetravel_msg *msg,
105157
return;
106158
case UM_TIMETRAVEL_RUN:
107159
time_travel_set_time(msg->time);
160+
if (time_travel_shm) {
161+
/* no request right now since we're running */
162+
time_travel_shm_client->flags &=
163+
~UM_TIMETRAVEL_SCHEDSHM_FLAGS_REQ_RUN;
164+
/* no ack for shared memory RUN */
165+
return;
166+
}
108167
break;
109168
case UM_TIMETRAVEL_FREE_UNTIL:
110-
time_travel_ext_free_until_valid = true;
111-
time_travel_ext_free_until = msg->time;
169+
/* not supposed to get this with shm, but ignore it */
170+
if (time_travel_shm)
171+
break;
172+
time_travel_ext_free_until = &_time_travel_ext_free_until;
173+
_time_travel_ext_free_until = msg->time;
112174
break;
113175
case UM_TIMETRAVEL_BROADCAST:
114176
bc_message = msg->time;
@@ -149,15 +211,23 @@ static u64 time_travel_ext_req(u32 op, u64 time)
149211
block_signals_hard();
150212
os_write_file(time_travel_ext_fd, &msg, sizeof(msg));
151213

214+
/* no ACK expected for WAIT in shared memory mode */
215+
if (msg.op == UM_TIMETRAVEL_WAIT && time_travel_shm)
216+
goto done;
217+
152218
while (msg.op != UM_TIMETRAVEL_ACK)
153-
time_travel_handle_message(&msg, TTMH_READ);
219+
time_travel_handle_message(&msg,
220+
op == UM_TIMETRAVEL_START ?
221+
TTMH_READ_START_ACK :
222+
TTMH_READ);
154223

155224
if (msg.seq != mseq)
156225
panic("time-travel: ACK message has different seqno! op=%d, seq=%d != %d time=%lld\n",
157226
msg.op, msg.seq, mseq, msg.time);
158227

159228
if (op == UM_TIMETRAVEL_GET)
160229
time_travel_set_time(msg.time);
230+
done:
161231
unblock_signals_hard();
162232

163233
return msg.time;
@@ -193,20 +263,48 @@ static void time_travel_ext_update_request(unsigned long long time)
193263
/*
194264
* if we're running and are allowed to run past the request
195265
* then we don't need to update it either
266+
*
267+
* Note for shm we ignore FREE_UNTIL messages and leave the pointer
268+
* to shared memory, and for non-shm the offset is 0.
196269
*/
197-
if (!time_travel_ext_waiting && time_travel_ext_free_until_valid &&
198-
time < time_travel_ext_free_until)
270+
if (!time_travel_ext_waiting && time_travel_ext_free_until &&
271+
time < (*time_travel_ext_free_until - time_travel_shm_offset))
199272
return;
200273

201274
time_travel_ext_prev_request = time;
202275
time_travel_ext_prev_request_valid = true;
276+
277+
if (time_travel_shm) {
278+
union um_timetravel_schedshm_client *running;
279+
280+
running = &time_travel_shm->clients[time_travel_shm->running_id];
281+
282+
if (running->capa & UM_TIMETRAVEL_SCHEDSHM_CAP_TIME_SHARE) {
283+
time_travel_shm_client->flags |=
284+
UM_TIMETRAVEL_SCHEDSHM_FLAGS_REQ_RUN;
285+
time += time_travel_shm_offset;
286+
time_travel_shm_client->req_time = time;
287+
if (time < time_travel_shm->free_until)
288+
time_travel_shm->free_until = time;
289+
return;
290+
}
291+
}
292+
203293
time_travel_ext_req(UM_TIMETRAVEL_REQUEST, time);
204294
}
205295

206296
void __time_travel_propagate_time(void)
207297
{
208298
static unsigned long long last_propagated;
209299

300+
if (time_travel_shm) {
301+
if (time_travel_shm->running_id != time_travel_shm_id)
302+
panic("time-travel: setting time while not running\n");
303+
time_travel_shm->current_time = time_travel_time +
304+
time_travel_shm_offset;
305+
return;
306+
}
307+
210308
if (last_propagated == time_travel_time)
211309
return;
212310

@@ -222,9 +320,12 @@ static bool time_travel_ext_request(unsigned long long time)
222320
* If we received an external sync point ("free until") then we
223321
* don't have to request/wait for anything until then, unless
224322
* we're already waiting.
323+
*
324+
* Note for shm we ignore FREE_UNTIL messages and leave the pointer
325+
* to shared memory, and for non-shm the offset is 0.
225326
*/
226-
if (!time_travel_ext_waiting && time_travel_ext_free_until_valid &&
227-
time < time_travel_ext_free_until)
327+
if (!time_travel_ext_waiting && time_travel_ext_free_until &&
328+
time < (*time_travel_ext_free_until - time_travel_shm_offset))
228329
return false;
229330

230331
time_travel_ext_update_request(time);
@@ -238,7 +339,8 @@ static void time_travel_ext_wait(bool idle)
238339
};
239340

240341
time_travel_ext_prev_request_valid = false;
241-
time_travel_ext_free_until_valid = false;
342+
if (!time_travel_shm)
343+
time_travel_ext_free_until = NULL;
242344
time_travel_ext_waiting++;
243345

244346
time_travel_ext_req(UM_TIMETRAVEL_WAIT, -1);
@@ -261,7 +363,11 @@ static void time_travel_ext_wait(bool idle)
261363

262364
static void time_travel_ext_get_time(void)
263365
{
264-
time_travel_ext_req(UM_TIMETRAVEL_GET, -1);
366+
if (time_travel_shm)
367+
time_travel_set_time(time_travel_shm->current_time -
368+
time_travel_shm_offset);
369+
else
370+
time_travel_ext_req(UM_TIMETRAVEL_GET, -1);
265371
}
266372

267373
static void __time_travel_update_time(unsigned long long ns, bool idle)

0 commit comments

Comments
 (0)