Skip to content

Commit fa6afb8

Browse files
authored
Move more time functions to native code. NFC (#16439)
I'm pretty this is going to be codesize win for a lot of codebases even though its not showing up in our (minimal) codesize tests.
1 parent 504f4e0 commit fa6afb8

File tree

7 files changed

+113
-99
lines changed

7 files changed

+113
-99
lines changed

src/library.js

+12-86
Original file line numberDiff line numberDiff line change
@@ -391,25 +391,9 @@ LibraryManager.library = {
391391
// time.h
392392
// ==========================================================================
393393

394-
clock__sig: 'i',
395-
clock: function() {
396-
if (_clock.start === undefined) _clock.start = Date.now();
397-
return ((Date.now() - _clock.start) * ({{{ cDefine('CLOCKS_PER_SEC') }}} / 1000))|0;
398-
},
399-
400-
time__sig: 'ii',
401-
time: function(ptr) {
402-
{{{ from64('ptr') }}};
403-
var ret = (Date.now()/1000)|0;
404-
if (ptr) {
405-
{{{ makeSetValue('ptr', 0, 'ret', 'i32') }}};
406-
}
407-
return ret;
408-
},
409-
410-
difftime__sig: 'dii',
411-
difftime: function(time1, time0) {
412-
return time1 - time0;
394+
_emscripten_date_now__sig: 'j',
395+
_emscripten_date_now: function() {
396+
return Date.now();
413397
},
414398

415399
_mktime_js__sig: 'ii',
@@ -549,11 +533,6 @@ LibraryManager.library = {
549533
return ret;
550534
},
551535

552-
dysize: function(year) {
553-
var leap = ((year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0)));
554-
return leap ? 366 : 365;
555-
},
556-
557536
// TODO: Initialize these to defaults on startup from system settings.
558537
// Note: glibc has one fewer underscore for all of these. Also used in other related functions (timegm)
559538
_tzset_js__deps: ['tzset_impl'],
@@ -1246,66 +1225,6 @@ LibraryManager.library = {
12461225
return _strptime(buf, format, tm); // no locale support yet
12471226
},
12481227

1249-
timespec_get__deps: ['clock_gettime', '$setErrNo'],
1250-
timespec_get: function(ts, base) {
1251-
//int timespec_get(struct timespec *ts, int base);
1252-
if (base !== {{{ cDefine('TIME_UTC') }}}) {
1253-
// There is no other implemented value than TIME_UTC; all other values are considered erroneous.
1254-
setErrNo({{{ cDefine('EINVAL') }}});
1255-
return 0;
1256-
}
1257-
var ret = _clock_gettime({{{ cDefine('CLOCK_REALTIME') }}}, ts);
1258-
return ret < 0 ? 0 : base;
1259-
},
1260-
1261-
// ==========================================================================
1262-
// sys/time.h
1263-
// ==========================================================================
1264-
1265-
clock_gettime__sig: 'iii',
1266-
clock_gettime__deps: ['emscripten_get_now', 'emscripten_get_now_is_monotonic', '$setErrNo'],
1267-
clock_gettime: function(clk_id, tp) {
1268-
// int clock_gettime(clockid_t clk_id, struct timespec *tp);
1269-
var now;
1270-
if (clk_id === {{{ cDefine('CLOCK_REALTIME') }}}) {
1271-
now = Date.now();
1272-
} else if ((clk_id === {{{ cDefine('CLOCK_MONOTONIC') }}} || clk_id === {{{ cDefine('CLOCK_MONOTONIC_RAW') }}}) && _emscripten_get_now_is_monotonic) {
1273-
now = _emscripten_get_now();
1274-
} else {
1275-
setErrNo({{{ cDefine('EINVAL') }}});
1276-
return -1;
1277-
}
1278-
{{{ makeSetValue('tp', C_STRUCTS.timespec.tv_sec, '(now/1000)|0', 'i32') }}}; // seconds
1279-
{{{ makeSetValue('tp', C_STRUCTS.timespec.tv_nsec, '((now % 1000)*1000*1000)|0', 'i32') }}}; // nanoseconds
1280-
return 0;
1281-
},
1282-
__clock_gettime__sig: 'iii',
1283-
__clock_gettime: 'clock_gettime', // musl internal alias
1284-
clock_getres__deps: ['emscripten_get_now_res', 'emscripten_get_now_is_monotonic', '$setErrNo'],
1285-
clock_getres: function(clk_id, res) {
1286-
// int clock_getres(clockid_t clk_id, struct timespec *res);
1287-
var nsec;
1288-
if (clk_id === {{{ cDefine('CLOCK_REALTIME') }}}) {
1289-
nsec = 1000 * 1000; // educated guess that it's milliseconds
1290-
} else if (clk_id === {{{ cDefine('CLOCK_MONOTONIC') }}} && _emscripten_get_now_is_monotonic) {
1291-
nsec = _emscripten_get_now_res();
1292-
} else {
1293-
setErrNo({{{ cDefine('EINVAL') }}});
1294-
return -1;
1295-
}
1296-
{{{ makeSetValue('res', C_STRUCTS.timespec.tv_sec, '(nsec/1000000000)|0', 'i32') }}};
1297-
{{{ makeSetValue('res', C_STRUCTS.timespec.tv_nsec, 'nsec', 'i32') }}} // resolution is nanoseconds
1298-
return 0;
1299-
},
1300-
gettimeofday__sig: 'iii',
1301-
// http://pubs.opengroup.org/onlinepubs/000095399/basedefs/sys/time.h.html
1302-
gettimeofday: function(ptr) {
1303-
var now = Date.now();
1304-
{{{ makeSetValue('ptr', C_STRUCTS.timeval.tv_sec, '(now/1000)|0', 'i32') }}}; // seconds
1305-
{{{ makeSetValue('ptr', C_STRUCTS.timeval.tv_usec, '((now % 1000)*1000)|0', 'i32') }}}; // microseconds
1306-
return 0;
1307-
},
1308-
13091228
// ==========================================================================
13101229
// sys/timeb.h
13111230
// ==========================================================================
@@ -2463,8 +2382,9 @@ LibraryManager.library = {
24632382

24642383
// Represents whether emscripten_get_now is guaranteed monotonic; the Date.now
24652384
// implementation is not :(
2385+
$nowIsMonotonic__internal: true,
24662386
#if MIN_IE_VERSION <= 9 || MIN_FIREFOX_VERSION <= 14 || MIN_CHROME_VERSION <= 23 || MIN_SAFARI_VERSION <= 80400 // https://caniuse.com/#feat=high-resolution-time
2467-
emscripten_get_now_is_monotonic: `
2387+
$nowIsMonotonic: `
24682388
((typeof performance == 'object' && performance && typeof performance['now'] == 'function')
24692389
#if ENVIRONMENT_MAY_BE_NODE
24702390
|| ENVIRONMENT_IS_NODE
@@ -2475,9 +2395,15 @@ LibraryManager.library = {
24752395
);`,
24762396
#else
24772397
// Modern environment where performance.now() is supported: (rely on minifier to return true unconditionally from this function)
2478-
emscripten_get_now_is_monotonic: 'true;',
2398+
$nowIsMonotonic: 'true;',
24792399
#endif
24802400

2401+
_emscripten_get_now_is_monotonic__internal: true,
2402+
_emscripten_get_now_is_monotonic__deps: ['$nowIsMonotonic'],
2403+
_emscripten_get_now_is_monotonic: function() {
2404+
return nowIsMonotonic;
2405+
},
2406+
24812407
#if MINIMAL_RUNTIME
24822408
$warnOnce: function(text) {
24832409
if (!warnOnce.shown) warnOnce.shown = {};

src/library_wasi.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ var WasiLibrary = {
137137
// either wait for BigInt support or to legalize on the client.
138138
clock_time_get__nothrow: true,
139139
clock_time_get__sig: 'iiiii',
140-
clock_time_get__deps: ['emscripten_get_now', 'emscripten_get_now_is_monotonic', '$checkWasiClock'],
140+
clock_time_get__deps: ['emscripten_get_now', '$nowIsMonotonic', '$checkWasiClock'],
141141
clock_time_get: function(clk_id, {{{ defineI64Param('precision') }}}, ptime) {
142142
{{{ receiveI64ParamAsI32s('precision') }}}
143143
if (!checkWasiClock(clk_id)) {
@@ -147,7 +147,7 @@ var WasiLibrary = {
147147
// all wasi clocks but realtime are monotonic
148148
if (clk_id === {{{ cDefine('__WASI_CLOCKID_REALTIME') }}}) {
149149
now = Date.now();
150-
} else if (_emscripten_get_now_is_monotonic) {
150+
} else if (nowIsMonotonic) {
151151
now = _emscripten_get_now();
152152
} else {
153153
return {{{ cDefine('ENOSYS') }}};
@@ -161,7 +161,7 @@ var WasiLibrary = {
161161

162162
clock_res_get__nothrow: true,
163163
clock_res_get__sig: 'iii',
164-
clock_res_get__deps: ['emscripten_get_now', 'emscripten_get_now_res', 'emscripten_get_now_is_monotonic', '$checkWasiClock'],
164+
clock_res_get__deps: ['emscripten_get_now', 'emscripten_get_now_res', '$nowIsMonotonic', '$checkWasiClock'],
165165
clock_res_get: function(clk_id, pres) {
166166
if (!checkWasiClock(clk_id)) {
167167
return {{{ cDefine('EINVAL') }}};
@@ -170,7 +170,7 @@ var WasiLibrary = {
170170
// all wasi clocks but realtime are monotonic
171171
if (clk_id === {{{ cDefine('CLOCK_REALTIME') }}}) {
172172
nsec = 1000 * 1000; // educated guess that it's milliseconds
173-
} else if (_emscripten_get_now_is_monotonic) {
173+
} else if (nowIsMonotonic) {
174174
nsec = _emscripten_get_now_res();
175175
} else {
176176
return {{{ cDefine('ENOSYS') }}};

src/struct_info.json

-2
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,6 @@
158158
{
159159
"file": "time.h",
160160
"defines": [
161-
["li", "CLOCKS_PER_SEC"],
162-
"TIME_UTC",
163161
"CLOCK_REALTIME",
164162
"CLOCK_MONOTONIC",
165163
"CLOCK_MONOTONIC_RAW"

system/lib/libc/emscripten_time.c

+91
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@
55
* found in the LICENSE file.
66
*/
77

8+
#include <emscripten/emscripten.h>
89
#include <time.h>
910
#include <stdbool.h>
11+
#include <sys/time.h>
12+
#include <threads.h>
1013
#include "libc.h"
1114

1215
// Replaces musl's __tz.c
@@ -20,6 +23,8 @@ time_t _timegm_js(struct tm *tm);
2023
time_t _mktime_js(struct tm *tm);
2124
void _localtime_js(const time_t *restrict t, struct tm *restrict tm);
2225
void _gmtime_js(const time_t *restrict t, struct tm *restrict tm);
26+
double _emscripten_date_now();
27+
double emscripten_get_now_res();
2328

2429
__attribute__((__weak__))
2530
void tzset() {
@@ -57,5 +62,91 @@ struct tm *__gmtime_r(const time_t *restrict t, struct tm *restrict tm) {
5762
return tm;
5863
}
5964

65+
__attribute__((__weak__))
66+
clock_t __clock() {
67+
static thread_local double start = 0;
68+
if (!start) {
69+
start = _emscripten_date_now();
70+
}
71+
return (_emscripten_date_now() - start) * (CLOCKS_PER_SEC / 1000);
72+
}
73+
74+
__attribute__((__weak__))
75+
time_t __time(time_t *t) {
76+
double ret = _emscripten_date_now() / 1000;
77+
if (t) {
78+
*t = ret;
79+
}
80+
return ret;
81+
}
82+
83+
extern bool _emscripten_get_now_is_monotonic();
84+
static thread_local bool checked_monotonic = false;
85+
static thread_local bool is_monotonic = 0;
86+
87+
__attribute__((__weak__))
88+
int __clock_gettime(clockid_t clk, struct timespec *ts) {
89+
if (!checked_monotonic) {
90+
is_monotonic = _emscripten_get_now_is_monotonic();
91+
checked_monotonic = true;
92+
}
93+
94+
double now_ms;
95+
if (clk == CLOCK_REALTIME) {
96+
now_ms = _emscripten_date_now();
97+
} else if ((clk == CLOCK_MONOTONIC || clk == CLOCK_MONOTONIC_RAW) && is_monotonic) {
98+
now_ms = emscripten_get_now();
99+
} else {
100+
errno = EINVAL;
101+
return -1;
102+
}
103+
104+
long long now_s = now_ms / 1000;
105+
ts->tv_sec = now_s; // seconds
106+
ts->tv_nsec = (now_ms - (now_s * 1000)) * 1000 * 1000; // nanoseconds
107+
return 0;
108+
}
109+
110+
__attribute__((__weak__))
111+
int __clock_getres(clockid_t clk, struct timespec *ts) {
112+
if (!checked_monotonic) {
113+
is_monotonic = _emscripten_get_now_is_monotonic();
114+
checked_monotonic = true;
115+
}
116+
117+
double nsec;
118+
if (clk == CLOCK_REALTIME) {
119+
nsec = 1000 * 1000; // educated guess that it's milliseconds
120+
} else if (clk == CLOCK_MONOTONIC && is_monotonic) {
121+
nsec = emscripten_get_now_res();
122+
} else {
123+
errno = EINVAL;
124+
return -1;
125+
}
126+
ts->tv_sec = (nsec / (1000 * 1000 * 1000));
127+
ts->tv_nsec = nsec;
128+
return 0;
129+
}
130+
131+
__attribute__((__weak__))
132+
int __gettimeofday(struct timeval *restrict tv, void *restrict tz) {
133+
double now_ms = _emscripten_date_now();
134+
long long now_s = now_ms / 1000;
135+
tv->tv_sec = now_s; // seconds
136+
tv->tv_usec = (now_ms - (now_s * 1000)) * 1000; // nicroseconds
137+
return 0;
138+
}
139+
140+
__attribute__((__weak__))
141+
int dysize(int year) {
142+
int leap = ((year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0)));
143+
return leap ? 366 : 365;
144+
}
145+
60146
weak_alias(__gmtime_r, gmtime_r);
61147
weak_alias(__localtime_r, localtime_r);
148+
weak_alias(__time, time);
149+
weak_alias(__clock, clock);
150+
weak_alias(__clock_gettime, clock_gettime);
151+
weak_alias(__clock_getres, clock_getres);
152+
weak_alias(__gettimeofday, gettimeofday);
+4-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
2-
"a.html": 12955,
3-
"a.html.gz": 6995,
4-
"total": 12955,
5-
"total_gz": 6995
2+
"a.html": 12977,
3+
"a.html.gz": 6991,
4+
"total": 12977,
5+
"total_gz": 6991
66
}

tests/reference_struct_info.json

-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
"AUDIO_F32": 33056,
1818
"AUDIO_S16LSB": 32784,
1919
"AUDIO_U8": 8,
20-
"CLOCKS_PER_SEC": 1000000,
2120
"CLOCK_MONOTONIC": 1,
2221
"CLOCK_MONOTONIC_RAW": 4,
2322
"CLOCK_REALTIME": 0,
@@ -351,7 +350,6 @@
351350
"TCSETS": 21506,
352351
"TCSETSF": 21508,
353352
"TCSETSW": 21507,
354-
"TIME_UTC": 1,
355353
"TIOCGPGRP": 21519,
356354
"TIOCGWINSZ": 21523,
357355
"TIOCSPGRP": 21520,

tools/system_libs.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -915,11 +915,13 @@ def get_files(self):
915915
'asctime_r.c',
916916
'asctime.c',
917917
'ctime.c',
918+
'difftime.c',
918919
'gmtime.c',
919920
'localtime.c',
920921
'nanosleep.c',
921922
'clock_nanosleep.c',
922923
'ctime_r.c',
924+
'timespec_get.c',
923925
'utime.c',
924926
])
925927
libc_files += files_in_path(
@@ -1644,7 +1646,6 @@ def get_files(self):
16441646
'__year_to_secs.c',
16451647
'clock.c',
16461648
'clock_gettime.c',
1647-
'difftime.c',
16481649
'gettimeofday.c',
16491650
'localtime_r.c',
16501651
'gmtime_r.c',

0 commit comments

Comments
 (0)