Skip to content

Commit

Permalink
Emulate clock, times, and getrusage using the monotonic clock.
Browse files Browse the repository at this point in the history
Upcoming WASI snapshots omit the `PROCESS_CPUTIME` clock, since WASI has
no inherent concept of processes, and since implementations which don't
use a process for each instance don't have a way to implement it
efficiently.

However, `clock`, `times`, and `getrusage` are useful functions, so
provide optional emulated version of them, using the `MONOTONIC` clock.
This means these implementations will measure not just the program's
own CPU time, but also time spent suspended while other programs are
running.

Due to this difference in behavior, put these implementations behind
a flag. Users must pass `-D_WASI_EMULATED_PROCESS_CLOCK` and link with
`-lwasi-emulated-process-clocks` to enable them.
  • Loading branch information
sunfishcode committed Mar 23, 2021
1 parent 322bd4f commit b9b64a6
Show file tree
Hide file tree
Showing 15 changed files with 117 additions and 82 deletions.
11 changes: 10 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ LIBC_BOTTOM_HALF_ALL_SOURCES := $(LIBC_BOTTOM_HALF_ALL_SOURCES) $(LIBC_BOTTOM_HA

LIBWASI_EMULATED_MMAN_SOURCES = \
$(shell find $(LIBC_BOTTOM_HALF_DIR)/mman -name \*.c)
LIBWASI_EMULATED_PROCESS_CLOCKS_SOURCES = \
$(shell find $(LIBC_BOTTOM_HALF_DIR)/clocks -name \*.c)
LIBWASI_EMULATED_SIGNAL_SOURCES = \
$(shell find $(LIBC_BOTTOM_HALF_DIR)/signal -name \*.c)
LIBWASI_EMULATED_SIGNAL_MUSL_SOURCES = \
Expand Down Expand Up @@ -229,6 +231,7 @@ MUSL_PRINTSCAN_OBJS = $(call objs,$(MUSL_PRINTSCAN_SOURCES))
MUSL_PRINTSCAN_LONG_DOUBLE_OBJS = $(patsubst %.o,%.long-double.o,$(MUSL_PRINTSCAN_OBJS))
MUSL_PRINTSCAN_NO_FLOATING_POINT_OBJS = $(patsubst %.o,%.no-floating-point.o,$(MUSL_PRINTSCAN_OBJS))
LIBWASI_EMULATED_MMAN_OBJS = $(call objs,$(LIBWASI_EMULATED_MMAN_SOURCES))
LIBWASI_EMULATED_PROCESS_CLOCKS_OBJS = $(call objs,$(LIBWASI_EMULATED_PROCESS_CLOCKS_SOURCES))
LIBWASI_EMULATED_SIGNAL_OBJS = $(call objs,$(LIBWASI_EMULATED_SIGNAL_SOURCES))
LIBWASI_EMULATED_SIGNAL_MUSL_OBJS = $(call objs,$(LIBWASI_EMULATED_SIGNAL_MUSL_SOURCES))

Expand Down Expand Up @@ -332,6 +335,8 @@ $(SYSROOT_LIB)/libc-printscan-no-floating-point.a: $(MUSL_PRINTSCAN_NO_FLOATING_

$(SYSROOT_LIB)/libwasi-emulated-mman.a: $(LIBWASI_EMULATED_MMAN_OBJS)

$(SYSROOT_LIB)/libwasi-emulated-process-clocks.a: $(LIBWASI_EMULATED_PROCESS_CLOCKS_OBJS)

$(SYSROOT_LIB)/libwasi-emulated-signal.a: $(LIBWASI_EMULATED_SIGNAL_OBJS) $(LIBWASI_EMULATED_SIGNAL_MUSL_OBJS)

%.a:
Expand Down Expand Up @@ -392,6 +397,9 @@ $(LIBC_TOP_HALF_ALL_OBJS) $(MUSL_PRINTSCAN_LONG_DOUBLE_OBJS) $(MUSL_PRINTSCAN_NO
-Wno-dangling-else \
-Wno-unknown-pragmas

$(LIBWASI_EMULATED_PROCESS_CLOCKS_OBJS): CFLAGS += \
-I$(LIBC_BOTTOM_HALF_CLOUDLIBC_SRC)

include_dirs:
$(RM) -r "$(SYSROOT)"

Expand Down Expand Up @@ -432,6 +440,7 @@ libc: include_dirs \
$(SYSROOT_LIB)/libc-printscan-long-double.a \
$(SYSROOT_LIB)/libc-printscan-no-floating-point.a \
$(SYSROOT_LIB)/libwasi-emulated-mman.a \
$(SYSROOT_LIB)/libwasi-emulated-process-clocks.a \
$(SYSROOT_LIB)/libwasi-emulated-signal.a

finish: startup_files libc
Expand Down Expand Up @@ -467,7 +476,7 @@ finish: startup_files libc
# Generate a test file that includes all public header files.
#
cd "$(SYSROOT)" && \
for header in $$(find include -type f -not -name mman.h -not -name signal.h |grep -v /bits/); do \
for header in $$(find include -type f -not -name mman.h -not -name signal.h -not -name times.h -not -name resource.h |grep -v /bits/); do \
echo '#include <'$$header'>' | sed 's/include\///' ; \
done |LC_ALL=C sort >share/$(MULTIARCH_TRIPLE)/include-all.c ; \
cd - >/dev/null
Expand Down
3 changes: 0 additions & 3 deletions expected/wasm32-wasi/defined-symbols.txt
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,6 @@ cimagl
clearenv
clearerr
clearerr_unlocked
clock
clock_getres
clock_gettime
clock_nanosleep
Expand Down Expand Up @@ -664,7 +663,6 @@ getline
getopt
getopt_long
getopt_long_only
getrusage
getsockopt
getsubopt
gettimeofday
Expand Down Expand Up @@ -1075,7 +1073,6 @@ tgammaf
tgammal
time
timegm
times
timespec_get
toascii
tolower
Expand Down
2 changes: 0 additions & 2 deletions expected/wasm32-wasi/include-all.c
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,6 @@
#include <sys/poll.h>
#include <sys/random.h>
#include <sys/reg.h>
#include <sys/resource.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/stat.h>
Expand All @@ -146,7 +145,6 @@
#include <sys/sysinfo.h>
#include <sys/time.h>
#include <sys/timeb.h>
#include <sys/times.h>
#include <sys/timex.h>
#include <sys/ttydefaults.h>
#include <sys/types.h>
Expand Down
2 changes: 0 additions & 2 deletions expected/wasm32-wasi/predefined-macros.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2309,14 +2309,12 @@
#define _SYS_PARAM_H
#define _SYS_RANDOM_H
#define _SYS_REG_H
#define _SYS_RESOURCE_H
#define _SYS_SELECT_H
#define _SYS_SOCKET_H
#define _SYS_STAT_H
#define _SYS_SYSCALL_H
#define _SYS_SYSINFO_H
#define _SYS_TIMEB_H
#define _SYS_TIMES_H
#define _SYS_TIMEX_H
#define _SYS_TIME_H
#define _SYS_TTYDEFAULTS_H
Expand Down
32 changes: 32 additions & 0 deletions libc-bottom-half/clocks/clock.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#define _WASI_EMULATED_PROCESS_CLOCKS
#include <time.h>
#include <wasi/api.h>
#include <common/time.h>

_Static_assert(
CLOCKS_PER_SEC == NSEC_PER_SEC,
"This implementation assumes that `clock` is in nanoseconds"
);

// Snapshot of the monotonic clock at the start of the program.
static __wasi_timestamp_t start;

// Use a priority of 10 to run fairly early in the implementation-reserved
// constructor priority range.
__attribute__((constructor(10)))
static void init(void) {
(void)__wasi_clock_time_get(__WASI_CLOCKID_MONOTONIC, 0, &start);
}

clock_t __clock(void) {
// Use `MONOTONIC` instead of `PROCESS_CPUTIME_ID` since WASI doesn't have
// an inherent concept of a process. Note that this means we'll incorrectly
// include time from other processes, so this function is only declared by
// the headers if `_WASI_EMULATED_PROCESS_CLOCKS` is defined.
__wasi_timestamp_t now = 0;
(void)__wasi_clock_time_get(__WASI_CLOCKID_MONOTONIC, 0, &now);
return now - start;
}

__attribute__((__weak__, __alias__("__clock")))
clock_t clock(void);
26 changes: 26 additions & 0 deletions libc-bottom-half/clocks/getrusage.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#define _WASI_EMULATED_PROCESS_CLOCKS
#include <sys/resource.h>
#include <errno.h>
#include <time.h>
#include <wasi/api.h>
#include <common/time.h>

clock_t __clock(void);

int getrusage(int who, struct rusage *r_usage) {
switch (who) {
case RUSAGE_SELF: {
__wasi_timestamp_t usertime = __clock();
*r_usage = (struct rusage) {
.ru_utime = timestamp_to_timeval(usertime)
};
return 0;
}
case RUSAGE_CHILDREN:
*r_usage = (struct rusage) {};
return 0;
default:
errno = EINVAL;
return -1;
}
}
24 changes: 24 additions & 0 deletions libc-bottom-half/clocks/times.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#define _WASI_EMULATED_PROCESS_CLOCKS
#include <time.h>
#include <sys/times.h>
#include <wasi/api.h>
#include <common/time.h>

_Static_assert(
CLOCKS_PER_SEC == NSEC_PER_SEC,
"This implementation assumes that `clock` is in nanoseconds"
);

clock_t __clock(void);

clock_t times(struct tms *buffer) {
__wasi_timestamp_t user = __clock();
*buffer = (struct tms){
.tms_utime = user,
.tms_cutime = user
};

__wasi_timestamp_t realtime = 0;
(void)__wasi_clock_time_get(__WASI_CLOCKID_MONOTONIC, 0, &realtime);
return realtime;
}
30 changes: 0 additions & 30 deletions libc-bottom-half/cloudlibc/src/libc/sys/resource/getrusage.c

This file was deleted.

25 changes: 0 additions & 25 deletions libc-bottom-half/cloudlibc/src/libc/sys/times/times.c

This file was deleted.

18 changes: 0 additions & 18 deletions libc-bottom-half/cloudlibc/src/libc/time/clock.c

This file was deleted.

2 changes: 2 additions & 0 deletions libc-top-half/musl/include/sys/param.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@
#define roundup(n,d) (howmany(n,d)*(d))
#define powerof2(n) !(((n)-1) & (n))

#if defined(__wasilibc_unmodified_upstream) || defined(_WASI_EMULATED_PROCESS_CLOCKS)
#include <sys/resource.h>
#endif
#include <endian.h>
#include <limits.h>

Expand Down
6 changes: 6 additions & 0 deletions libc-top-half/musl/include/sys/resource.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
#ifndef _WASI_EMULATED_PROCESS_CLOCKS
#error WASI lacks process-associated clocks; to enable emulation of the `getrusage` function using \
the wall clock, which isn't sensitive to whether the program is running or suspended, \
compile with -D_WASI_EMULATED_PROCESS_CLOCKS and link with -lwasi-emulated-process-clocks
#else
#ifndef _SYS_RESOURCE_H
#define _SYS_RESOURCE_H

Expand Down Expand Up @@ -118,3 +123,4 @@ __REDIR(getrusage, __getrusage_time64);
#endif

#endif
#endif
7 changes: 6 additions & 1 deletion libc-top-half/musl/include/sys/times.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
#ifndef _WASI_EMULATED_PROCESS_CLOCKS
#error WASI lacks process-associated clocks; to enable emulation of the `times` function using \
the wall clock, which isn't sensitive to whether the program is running or suspended, \
compile with -D_WASI_EMULATED_PROCESS_CLOCKS and link with -lwasi-emulated-process-clocks
#else
#ifndef _SYS_TIMES_H
#define _SYS_TIMES_H

Expand Down Expand Up @@ -26,4 +31,4 @@ clock_t times (struct tms *);
#endif

#endif

#endif
9 changes: 9 additions & 0 deletions libc-top-half/musl/include/time.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,16 @@ struct tm {
#include <__header_time.h>
#endif

#if defined(__wasilibc_unmodified_upstream) || defined(_WASI_EMULATED_PROCESS_CLOCKS)
clock_t clock (void);
#else
__attribute__((__deprecated__(
"WASI lacks process-associated clocks; to enable emulation of the `clock` function using "
"the wall clock, which isn't sensitive to whether the program is running or suspended, "
"compile with -D_WASI_EMULATED_PROCESS_CLOCKS and link with -lwasi-emulated-process-clocks"
)))
clock_t clock (void);
#endif
time_t time (time_t *);
double difftime (time_t, time_t);
time_t mktime (struct tm *);
Expand Down
2 changes: 2 additions & 0 deletions libc-top-half/musl/src/conf/sysconf.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#include <unistd.h>
#include <limits.h>
#include <errno.h>
#ifdef __wasilibc_unmodified_upstream // WASI has no process-level accounting
#include <sys/resource.h>
#endif
#ifdef __wasilibc_unmodified_upstream // WASI has no realtime signals
#include <signal.h>
#endif
Expand Down

0 comments on commit b9b64a6

Please sign in to comment.