Ich habe ein Plattenbearbeitungsprogramm von mir ein paar Minuten unter Streß laufen lassen.
Dies wies in jenen Minuten über 200.000.000 Anrufe auf stat("/etc/localtime",..)
das klingt ein bisschen übertrieben und unnötig.
Die Strace-Ausgabe sieht so aus:
write(1, "C137015 393393093052629137110 47"..., 16384) = 16384
stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=2225, ...}) = 0
stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=2225, ...}) = 0
stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=2225, ...}) = 0
stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=2225, ...}) = 0
stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=2225, ...}) = 0
stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=2225, ...}) = 0
stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=2225, ...}) = 0
stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=2225, ...}) = 0
stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=2225, ...}) = 0
stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=2225, ...}) = 0
stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=2225, ...}) = 0
stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=2225, ...}) = 0
stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=2225, ...}) = 0
stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=2225, ...}) = 0
stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=2225, ...}) = 0
stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=2225, ...}) = 0
stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=2225, ...}) = 0
stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=2225, ...}) = 0
stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=2225, ...}) = 0
stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=2225, ...}) = 0
stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=2225, ...}) = 0
stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=2225, ...}) = 0
stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=2225, ...}) = 0
stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=2225, ...}) = 0
stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=2225, ...}) = 0
stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=2225, ...}) = 0
stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=2225, ...}) = 0
read(0, "\224q\1\207\0\0\202\1\4\203\1\4\204\1\1\205\1\1\206\1\7\207\1\6\211\1\22\212\1\22\213\1"..., 16384) = 16384
Im Wesentlichen stellte sich heraus, dass es 1 stat()-Aufruf für jeden verarbeiteten Datensatz war, und der Übeltäter stellte sich als diese ganz gewöhnliche Codezeile heraus
strftime(call->date_time,DATELEN,"%Y%m%d %H%M%S",&tm_buf);
Also – wie kann ich vermeiden, dass strftime() bei jedem Aufruf stat(/etc/localtime) aufruft?
Dies kann daran liegen, dass Ihre Zeitzone nicht festgelegt ist. strftime
Abfragen /etc/localtime
es zu finden.
Versuchen Sie die Einstellung TZ
Umgebungsvariable.
Hier ist ein Link für dieses Verhalten.
Mit der GNU libc-Bibliothek ist hier ein weiterer Tipp, um dieses Problem zu lösen /etc/lokalzeit nicht konfiguriert ist (dies ist häufig bei winzigen eingebetteten Systemen der Fall). Diese besteht aus zu setzen TZ
Umgebungsvariable in die leere Zeichenfolge. Dadurch verwendet die Bibliothek standardmäßig die UTC.
Hier ist ein Beispiel strace
Ausgabe auf einem eingebetteten System, das eine Protokollierungsfunktion aufruft, die aufruft localtime()
und strftime()
wenn weder /etc/lokalzeit Noch TZ
eingestellt sind. Bei glibc 2.23 löst dies mehrere erfolglose Aufrufe von “openat(/etc/localtime)“:
[...]
[pid 200113] gettid() = 200113
[pid 200113] openat(AT_FDCWD, "/etc/localtime", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid 200113] openat(AT_FDCWD, "/etc/localtime", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid 200113] gettid() = 200113
[pid 200113] openat(AT_FDCWD, "/etc/localtime", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid 200113] openat(AT_FDCWD, "/etc/localtime", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid 200113] getpid() = 200113
[pid 200113] writev(4, [{iov_base="DUH\1\1\0\0\0", iov_len=8}, {iov_base="=\2\0\261ECU1\0\3\r\261\r\32\265\3431\2SWMCSWMC", iov_len=26}, {iov_base="\0\2\0\0'\0Tue Mar 1 13:49:20 2022 _"..., iov_len=151}], 3) = 185
[pid 200113] gettid() = 200113
[pid 200113] openat(AT_FDCWD, "/etc/localtime", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid 200113] openat(AT_FDCWD, "/etc/localtime", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid 200113] gettid() = 200113
[...]
Und hier ist die Ausgabe des gleichen Programms mit strace
Wenn TZ
wird auf die leere Zeichenfolge gesetzt:
$ export TZ=
[...]
[pid 201837] gettid() = 201837
[pid 201837] gettid() = 201837
[pid 201837] getpid() = 201837
[pid 201837] writev(4, [{iov_base="DUH\1\1\0\0\0", iov_len=8}, {iov_base="=\2\0\261ECU1\0\3\24m\r7\253\3171\2SWMCSWMC", iov_len=26}, {iov_base="\0\2\0\0'\0Tue Mar 1 13:52:30 2022 _"..., iov_len=151}], 3) = 185
[pid 201837] gettid() = 201837
[pid 201857] <... read resumed>"DUH\1\f\0\0\0\0DUH\1\6\0\0\0\5\0\0\0\0\0DUH\1\6\0\0\0\5"..., 10024) = 37
[pid 201837] gettid( <unfinished ...>
[pid 201857] read(3, <unfinished ...>
[pid 201837] <... gettid resumed>) = 201837
[pid 201837] getpid() = 201837
[pid 201837] writev(4, [{iov_base="DUH\1\1\0\0\0", iov_len=8}, {iov_base="=\3\0\257ECU1\0\3\24m\r7\253\364A\2SWMCSWMC", iov_len=26}, {iov_base="\0\2\0\0'\0Tue Mar 1 13:52:30 2022 _"..., iov_len=149}], 3) = 183
[...]
NB: Hier ist das entsprechende Quellcode-Snippet der glibc time/tzset.c die UTC setzt, wenn TZ leer ist:
/* Interpret the TZ envariable. */
static void
internal_function
tzset_internal (int always, int explicit)
{
static int is_initialized;
const char *tz;
if (is_initialized && !always)
return;
is_initialized = 1;
/* Examine the TZ environment variable. */
tz = getenv ("TZ");
if (tz == NULL && !explicit)
/* Use the site-wide default. This is a file name which means we
would not see changes to the file if we compare only the file
name for change. We want to notice file changes if tzset() has
been called explicitly. Leave TZ as NULL in this case. */
tz = TZDEFAULT;
if (tz && *tz == '\0')
/* User specified the empty string; use UTC explicitly. */
tz = "Universal";
[...]
Haben Sie einen Beweis dafür, dass dies tatsächlich ein messbares Problem verursacht (dh erhebliche Laufzeitkosten, die von einem Profiler gemessen werden)? Sie sollten nicht versuchen, basierend auf zu optimieren Gefühle (wie “klingt etwas übertrieben”). Holen Sie sich Messungen und verwenden Sie Fakten.
– niemand
29. Dezember 2010 um 14:13 Uhr
+1 für die Frage, wie man Glibc Bloat auf den Grund geht. 🙂
– R.. GitHub HÖR AUF, EIS ZU HELFEN
29. Dezember 2010 um 15:14 Uhr
Hinzufügen
export TZ=:/etc/localtime
zu meinem Shell-Skript eliminiert die wiederholten Syscalls für mich.– shuckc
7. April 2013 um 14:57 Uhr
Und obwohl diese Frage alt ist: AndrewMedico: Ja, natürlich. Es wurde gemessen, dass dies etwa 10 % Auswirkung auf die Leistung hat. @R .. Es scheint auch erforderlich zu sein, um zB Zeitzonenänderungen abzufangen, und posix schreibt vor, dass sich bestimmte Funktionen so verhalten, als ob tzset() aufgerufen wird
– Nr
18. Juni 2014 um 7:35 Uhr
@nein:
tzset
ist erforderlich, um auf Änderungen der zu reagierenTZ
Variable. Es ist nicht erforderlich zu prüfen, ob sich die Datei auf der Festplatte geändert hat, wenn sich die Variable nicht geändert hat.– R.. GitHub HÖR AUF, EIS ZU HELFEN
18. Juni 2014 um 7:39 Uhr