diff options
author | KOSAKI Motohiro <kosaki.motohiro@gmail.com> | 2019-12-01 16:21:05 +0000 |
---|---|---|
committer | KOSAKI Motohiro <kosaki.motohiro@gmail.com> | 2019-12-01 16:34:26 +0000 |
commit | 4d7a6d04b2c71aabb9d6e619f4405887806a5be8 (patch) | |
tree | c27f7dff69239308bca5e36ea4593d67a074ace8 | |
parent | 43811cc3b36739816788cbbac7a49b9bbf756293 (diff) |
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
-rw-r--r-- | hash.c | 14 | ||||
-rw-r--r-- | time.c | 11 |
2 files changed, 14 insertions, 11 deletions
@@ -4711,6 +4711,17 @@ env_delete(VALUE name) nam = env_name(name); 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) { VALUE value = env_str_new2(val); @@ -4718,9 +4729,6 @@ env_delete(VALUE name) if (ENVMATCH(nam, PATH_ENV)) { RB_GC_GUARD(name); } - else if (ENVMATCH(nam, TZ_ENV)) { - ruby_tz_uptodate_p = false; - } return value; } return Qnil; @@ -3139,15 +3139,10 @@ find_time_t(struct tm *tptr, int utc_p, time_t *tp) find_dst = 0 < tptr->tm_isdst; -#if defined(HAVE_MKTIME) - tm0 = *tptr; - if (!utc_p && (guess = mktime(&tm0)) != -1) { - tm = GUESS(&guess); - if (tm && tmcmp(tptr, tm) == 0) { - goto found; - } + /* /etc/localtime might be changed. reload it. */ + if (!ruby_tz_uptodate_p) { + tzset(); } -#endif tm0 = *tptr; if (tm0.tm_mon < 0) { |