diff options
author | Johannes Berg <johannes.berg@intel.com> | 2019-05-27 10:34:27 +0200 |
---|---|---|
committer | Richard Weinberger <richard@nod.at> | 2019-07-02 23:27:36 +0200 |
commit | 065038706f77a56754e8f0c2556dab7e22dfe577 (patch) | |
tree | 00e8ea2389184678dab2abe1155988b8aa488aad /arch/um/kernel/process.c | |
parent | c7c6f3b95303c7de5d52af56c902fcb5abe827df (diff) | |
download | linux-065038706f77a56754e8f0c2556dab7e22dfe577.tar.gz linux-065038706f77a56754e8f0c2556dab7e22dfe577.tar.bz2 linux-065038706f77a56754e8f0c2556dab7e22dfe577.zip |
um: Support time travel mode
Sometimes it can be useful to run with "time travel" inside the
UML instance, for example for testing. For example, some tests
for the wireless subsystem and userspace are based on hwsim, a
virtual wireless adapter. Some tests can take a long time to
run because they e.g. wait for 120 seconds to elapse for some
regulatory checks. This obviously goes faster if it need not
actually wait that long, but time inside the test environment
just "bumps up" when there's nothing to do.
Add CONFIG_UML_TIME_TRAVEL_SUPPORT to enable code to support
such modes at runtime, selected on the command line:
* just "time-travel", in which time inside the UML instance
can move faster than real time, if there's nothing to do
* "time-travel=inf-cpu" in which time also moves slower and
any CPU processing takes no time at all, which allows to
implement consistent behaviour regardless of host CPU load
(or speed) or debug overhead.
An additional "time-travel-start=<seconds>" parameter is also
supported in this case to start the wall clock at this time
(in unix epoch).
With this enabled, the test mentioned above goes from a runtime
of about 140 seconds (with startup overhead and all) to being
CPU bound and finishing in 15 seconds (on my slow laptop).
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Richard Weinberger <richard@nod.at>
Diffstat (limited to 'arch/um/kernel/process.c')
-rw-r--r-- | arch/um/kernel/process.c | 42 |
1 files changed, 41 insertions, 1 deletions
diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index 691b83b10649..def2091697ca 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c @@ -203,10 +203,50 @@ void initial_thread_cb(void (*proc)(void *), void *arg) kmalloc_ok = save_kmalloc_ok; } +static void time_travel_sleep(unsigned long long duration) +{ + unsigned long long next = time_travel_time + duration; + + if (time_travel_mode != TT_MODE_INFCPU) + os_timer_disable(); + + if (time_travel_timer_mode != TT_TMR_DISABLED || + time_travel_timer_expiry < next) { + if (time_travel_timer_mode == TT_TMR_ONESHOT) + time_travel_timer_mode = TT_TMR_DISABLED; + /* + * time_travel_time will be adjusted in the timer + * IRQ handler so it works even when the signal + * comes from the OS timer + */ + deliver_alarm(); + } else { + time_travel_set_time(next); + } + + if (time_travel_mode != TT_MODE_INFCPU) { + if (time_travel_timer_mode == TT_TMR_PERIODIC) + os_timer_set_interval(time_travel_timer_interval); + else if (time_travel_timer_mode == TT_TMR_ONESHOT) + os_timer_one_shot(time_travel_timer_expiry - next); + } +} + +static void um_idle_sleep(void) +{ + unsigned long long duration = UM_NSEC_PER_SEC; + + if (time_travel_mode != TT_MODE_OFF) { + time_travel_sleep(duration); + } else { + os_idle_sleep(duration); + } +} + void arch_cpu_idle(void) { cpu_tasks[current_thread_info()->cpu].pid = os_getpid(); - os_idle_sleep(UM_NSEC_PER_SEC); + um_idle_sleep(); local_irq_enable(); } |