Gentoo Archives: gentoo-dev

From: Joshua Kinard <kumba@g.o>
To: gentoo-dev@l.g.o
Subject: [gentoo-dev] Defining TZ in the base system profile?
Date: Thu, 19 Jan 2023 01:49:04
Message-Id: c008858a-4fcc-b895-7703-0526f92045aa@gentoo.org
1 So this article[1] from 2017 popped up again on the tech radar via hackernews[2] and a few other sites[3]. It
2 annotates how if the envvar TZ is undefined on a Linux system, it causes glibc to generate a number of
3 additional syscalls, mainly stat-related calls (in my tests, newfstatat()). If defined to an actual value,
4 such as ":/etc/localtime" (or even an empty string), glibc will instead generate far fewer, if any at all, of
5 these stat-related syscalls.
6
7 Apparently, TZ is accessed quite frequently, so this has a compound effect, according to the article, in glibc
8 making thousands of unnecessary stat-related syscalls to /etc/localtime (which must be hard-coded somewhere in
9 glibc for this case). Given the article's age (five years old), I tested the example C program out, and it
10 does appear to still be accurate on a modern glibc-based system. When TZ is undefined, I get exactly nine
11 newfstatat calls on /etc/localtime. If I define TZ to ":/etc/localtime", I do not get any of these newfstatat
12 calls, and if I set TZ to an empty string, glibc will call openat() against "/usr/share/zoneinfo/Universal"
13 and then generate exactly two newfstatat syscalls on that handle to read it.
14
15 I ran strace() against the undefined TZ case and the ":/etc/localtime" case, normalized the hex addresses to
16 get a clean diff, and this is what it looks like:
17
18 --- a 2023-01-18 20:30:36.826805343 -0500
19 +++ b 2023-01-18 20:30:45.106983600 -0500
20 @@ -1,4 +1,4 @@
21 -# strace ./tz_test
22 +# TZ=":/etc/localtime" strace ./tz_test
23 execve("./tz_test", ["./tz_test"], 0xhhhhhhhhhhhh /* XX vars */) = 0
24 brk(NULL) = 0xhhhhhhhhhhhh
25 mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xhhhhhhhhhhhh
26 @@ -61,15 +61,6 @@ read(3, "TZif2\0\0\0\0\0\0\0\0\0\0\0\0\0
27 lseek(3, -2260, SEEK_CUR) = 1292
28 read(3, "TZif2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\6\0\0\0\6\0\0\0\0"..., 3584) = 2260
29 close(3) = 0
30 -newfstatat(AT_FDCWD, "/etc/localtime", {st_mode=S_IFREG|0644, st_size=3552, ...}, 0) = 0
31 -newfstatat(AT_FDCWD, "/etc/localtime", {st_mode=S_IFREG|0644, st_size=3552, ...}, 0) = 0
32 -newfstatat(AT_FDCWD, "/etc/localtime", {st_mode=S_IFREG|0644, st_size=3552, ...}, 0) = 0
33 -newfstatat(AT_FDCWD, "/etc/localtime", {st_mode=S_IFREG|0644, st_size=3552, ...}, 0) = 0
34 -newfstatat(AT_FDCWD, "/etc/localtime", {st_mode=S_IFREG|0644, st_size=3552, ...}, 0) = 0
35 -newfstatat(AT_FDCWD, "/etc/localtime", {st_mode=S_IFREG|0644, st_size=3552, ...}, 0) = 0
36 -newfstatat(AT_FDCWD, "/etc/localtime", {st_mode=S_IFREG|0644, st_size=3552, ...}, 0) = 0
37 -newfstatat(AT_FDCWD, "/etc/localtime", {st_mode=S_IFREG|0644, st_size=3552, ...}, 0) = 0
38 -newfstatat(AT_FDCWD, "/etc/localtime", {st_mode=S_IFREG|0644, st_size=3552, ...}, 0) = 0
39 write(1, "Godspeed, dear friend!\n", 23Godspeed, dear friend!
40 ) = 23
41 exit_group(0) = ?
42
43 For comparison, I tested the same program on FreeBSD and it does not exhibit this behavior at all, regardless
44 of whether TZ is undefined, a value, or an empty string. I have yet to make a similar test on a mips/musl
45 chroot to see how musl handles this.
46
47 There is a rather old (2010) StackOverflow question[4] about it as well, and someone left an answer in March
48 of last year about the specific code in glibc that handles TZ if it is set or is an empty string.
49
50 So is adding a default definition of TZ to our base system /etc/profile something we want to look at? I
51 haven't tried any other methods of benchmarking to see if not making those additional syscalls is just placebo
52 or if there are actual impacts. Given how long this oddity has been around, I can't tell if it's a genuine
53 bug in glibc, an unoptimized corner case, or just a big nothingburger.
54
55
56 1. https://blog.packagecloud.io/set-environment-variable-save-thousands-of-system-calls/
57 2. https://news.ycombinator.com/item?id=34346346
58 3. https://vermaden.wordpress.com/posts/
59 4.
60 https://stackoverflow.com/questions/4554271/how-to-avoid-excessive-stat-etc-localtime-calls-in-strftime-on-linux
61
62
63 Thoughts?
64
65 --
66 Joshua Kinard
67 Gentoo/MIPS
68 kumba@g.o
69 rsa6144/5C63F4E3F5C6C943 2015-04-27
70 177C 1972 1FB8 F254 BAD0 3E72 5C63 F4E3 F5C6 C943
71
72 "The past tempts us, the present confuses us, the future frightens us. And our lives slip away, moment by
73 moment, lost in that vast, terrible in-between."
74
75 --Emperor Turhan, Centauri Republic

Replies

Subject Author
Re: [gentoo-dev] Defining TZ in the base system profile? "Michał Górny" <mgorny@g.o>
Re: [gentoo-dev] Defining TZ in the base system profile? Ionen Wolkens <ionen@g.o>
Re: [gentoo-dev] Defining TZ in the base system profile? Michael Orlitzky <mjo@g.o>
Re: [gentoo-dev] Defining TZ in the base system profile? "Haelwenn (lanodan) Monnier" <contact@×××××××××.me>