1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

Avoid unnecessary tzset() call

Akatsuki reported ENV['TZ'] = 'UTC' improved 7x-8x faster on following code.
t = Time.now; 100000.times { Time.new(2019) }; Time.now - t
https://hackerslab.aktsk.jp/2019/12/01/141551

commit 4bc1669127(reduce tzset) dramatically improved this situation. But still,
TZ=UTC is faster than default.

This patch removs unnecessary tzset() call completely.

Performance check
  ----------------------
test program: t = Time.now; 100000.times { Time.new(2019) }; Time.now - t
before:         0.387sec
before(w/ TZ):  0.197sec
after:          0.162sec
after(w/ TZ):   0.165sec

OK. Now, Time creation 2x faster *and* TZ=UTC doesn't improve anything.
We can forget this hack completely. :)

Side note:
This patch slightly changes Time.new(t) behavior implicitly. Before this patch, it might changes
default timezone implicitly. But after this patch, it doesn't. You need to reset TZ
(I mean ENV['TZ'] = nil) explicitly.
But I don't think this is big impact. Don't try to change /etc/localtime on runtime.

Side note2: following test might be useful for testing "ENV['TZ'] = nil".
  -----------------------------------------
% cat <<'End' | sudo sh -s
rm -f /etc/localtime-; cp -a /etc/localtime /etc/localtime-
rm /etc/localtime; ln -s /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
./ruby -e '
p Time.new(2000).zone # JST
File.unlink("/etc/localtime"); File.symlink("/usr/share/zoneinfo/America/Los_Angeles", "/etc/localtime")
p Time.new(2000).zone # JST (ruby does not follow /etc/localtime modification automatically)
ENV["TZ"] = nil
p Time.new(2000).zone # PST (ruby detect /etc/localtime modification)
'
rm /etc/localtime; cp -a /etc/localtime- /etc/localtime; rm /etc/localtime-
End
This commit is contained in:
KOSAKI Motohiro 2019-12-01 16:21:05 +00:00
parent 43811cc3b3
commit 4d7a6d04b2
2 changed files with 14 additions and 11 deletions

14
hash.c
View file

@ -4711,6 +4711,17 @@ env_delete(VALUE name)
nam = env_name(name); nam = env_name(name);
val = getenv(nam); val = getenv(nam);
/*
* ENV['TZ'] = nil has a special meaning.
* TZ is no longer considered up-to-date and ruby call tzset() as needed.
* It could be useful if sysadmin change /etc/localtime.
* This hack might works only on Linux glibc.
*/
if (ENVMATCH(nam, TZ_ENV)) {
ruby_tz_uptodate_p = FALSE;
}
if (val) { if (val) {
VALUE value = env_str_new2(val); VALUE value = env_str_new2(val);
@ -4718,9 +4729,6 @@ env_delete(VALUE name)
if (ENVMATCH(nam, PATH_ENV)) { if (ENVMATCH(nam, PATH_ENV)) {
RB_GC_GUARD(name); RB_GC_GUARD(name);
} }
else if (ENVMATCH(nam, TZ_ENV)) {
ruby_tz_uptodate_p = false;
}
return value; return value;
} }
return Qnil; return Qnil;

11
time.c
View file

@ -3139,15 +3139,10 @@ find_time_t(struct tm *tptr, int utc_p, time_t *tp)
find_dst = 0 < tptr->tm_isdst; find_dst = 0 < tptr->tm_isdst;
#if defined(HAVE_MKTIME) /* /etc/localtime might be changed. reload it. */
tm0 = *tptr; if (!ruby_tz_uptodate_p) {
if (!utc_p && (guess = mktime(&tm0)) != -1) { tzset();
tm = GUESS(&guess);
if (tm && tmcmp(tptr, tm) == 0) {
goto found;
}
} }
#endif
tm0 = *tptr; tm0 = *tptr;
if (tm0.tm_mon < 0) { if (tm0.tm_mon < 0) {