|
|
@@ -1,376 +0,0 @@
|
|
1
|
|
-# Homework hw4 task2
|
|
2
|
|
-
|
|
3
|
|
-Die folgenden Informationen sollen helfen, sich schneller in die Materie des
|
|
4
|
|
-'Timings' von Programmen einzuarbeiten:
|
|
5
|
|
-
|
|
6
|
|
-- Das externe Crate [time][] bietet mehr und vor allem einfachere Funktionalität
|
|
7
|
|
- als die Rust Standard-Bibliothek.
|
|
8
|
|
-- Alle Betriebssysteme stellen eine Time API zu Verfügung. Es kann hilfreich
|
|
9
|
|
- sein zu verstehen, wie diese funktioniert. Daher beschäftigt sich das nächste
|
|
10
|
|
- Kapitel ausführlich mit dieser API.
|
|
11
|
|
-- Das Modul [std::mem] aus der Standardbibliothek ist zur Lösung dieser Aufgabe
|
|
12
|
|
- sehr hilfreich.
|
|
13
|
|
-
|
|
14
|
|
-[time]: https://docs.rs/time
|
|
15
|
|
-[std::mem]: https://doc.rust-lang.org/std/mem/
|
|
16
|
|
-
|
|
17
|
|
-## Warmup für das Programm
|
|
18
|
|
-
|
|
19
|
|
-Um mit hoher Wahrscheinlichkeit Instruktionen und Daten aus dem Cache zu beziehen, sollte Ihr Programm ein kleines 'Cache' Warmup durchlaufen.
|
|
20
|
|
-
|
|
21
|
|
-Dies kann über ein simples Inkrementieren erreicht werden. Bei der Berechnung müssen Sie aber darauf achten, dass der Compiler das Ergebnis nicht vorausberechnen kann. Sonst würde bei der Optimierung der Compiler einfach das Ergebnis ausrechnen und das Ergebnis direkt in den Code schreiben. Damit wäre das Warmup (Durchlaufen des Codes) dahin.
|
|
22
|
|
-
|
|
23
|
|
-Mit einer Parameterübergabe durch die Kommandozeile steht das Ergebnis zur Compile-Zeit nicht fest und somit kann der Code nicht einfach 'weg'-optimiert werden. Dazu ein Beispiel:
|
|
24
|
|
-
|
|
25
|
|
-```Rust
|
|
26
|
|
-//where page_count and jump are cmd arguments
|
|
27
|
|
-let mut a = vec![0i32; page_count * jump];
|
|
28
|
|
-
|
|
29
|
|
- // warm up
|
|
30
|
|
- for i in a.iter_mut() {
|
|
31
|
|
- *i += 1;
|
|
32
|
|
- }
|
|
33
|
|
-```
|
|
34
|
|
-
|
|
35
|
|
-## Zeiten lesen in C
|
|
36
|
|
-
|
|
37
|
|
-Das folgende Kapitel muss zur Lösung von task2 nicht komplett verstanden werden.
|
|
38
|
|
-Vielmehr soll es weitere Informationen liefern, wenn Ihnen gewisse
|
|
39
|
|
-Funktionalitäten der Thematik 'Timing' unklar sind.
|
|
40
|
|
-
|
|
41
|
|
-- [Datenstrukturen](#datenstrukturen)
|
|
42
|
|
-- [Zeit lesen](#zeit-lesen)
|
|
43
|
|
-- [Zeitvergleich: Differenzzeitmessung](#zeitvergleich-differenzzeitmessung)
|
|
44
|
|
-
|
|
45
|
|
-### Datenstrukturen
|
|
46
|
|
-
|
|
47
|
|
-Betriebssysteme stellen Anwendungen Zeitgeber mit unterschiedlichen
|
|
48
|
|
-Eigenschaften zur Verfügung, über die das Zeitverhalten kontrolliert wird. Diese
|
|
49
|
|
-sind gekennzeichnet durch ihre
|
|
50
|
|
-
|
|
51
|
|
-- Genauigkeit,
|
|
52
|
|
-- die Zuverlässigkeit,
|
|
53
|
|
-- den Bezugspunkt,
|
|
54
|
|
-- die Darstellung und
|
|
55
|
|
-- den maximalen Zeitbereich.
|
|
56
|
|
-
|
|
57
|
|
-Das Betriebssystem repräsentiert Zeiten unter anderem mit den folgenden
|
|
58
|
|
-Datentypen (Darstellung):
|
|
59
|
|
-
|
|
60
|
|
-- clock_t: Timerticks.
|
|
61
|
|
-- struct timeval: Zeit in Mikrosekunden-Auflösung.
|
|
62
|
|
-- struct timespec: Zeit in Nanosekunden-Auflösung.
|
|
63
|
|
-- struct tm: absolute Zeitangabe.
|
|
64
|
|
-
|
|
65
|
|
-```c
|
|
66
|
|
-struct timeval {
|
|
67
|
|
-
|
|
68
|
|
- time_t tv_sec; /* seconds */
|
|
69
|
|
- suseconds_t tv_usec; /* microseconds */
|
|
70
|
|
-};
|
|
71
|
|
-
|
|
72
|
|
-struct timespec {
|
|
73
|
|
- time_t tv_sec; /* seconds */
|
|
74
|
|
- long tv_nsec; /* nanoseconds */
|
|
75
|
|
-};
|
|
76
|
|
-
|
|
77
|
|
-struct tm
|
|
78
|
|
-{
|
|
79
|
|
- int tm_sec; /* seconds */
|
|
80
|
|
- int tm_min; /* minutes */
|
|
81
|
|
- int tm_hour; /* hours */
|
|
82
|
|
- int tm_mday; /* day of the month */
|
|
83
|
|
- int tm_mon; /* month */
|
|
84
|
|
- int tm_year; /* year */
|
|
85
|
|
- int tm_wday; /* day of the week */
|
|
86
|
|
- int tm_yday; /* day in the year */
|
|
87
|
|
- int tm_isdst; /* daylight saving time */
|
|
88
|
|
-};
|
|
89
|
|
-```
|
|
90
|
|
-
|
|
91
|
|
-Die Strukturen struct timeval und struct timespec bestehen aus jeweils zwei
|
|
92
|
|
-Variablen, die einmal den Sekundenanteil und einmal den Mikro- beziehungsweise
|
|
93
|
|
-den Nanosekundenanteil repräsentieren. Die Darstellung erfolgt jeweils normiert.
|
|
94
|
|
-Das bedeutet, dass der Mikro- oder Nanosekundenanteil immer kleiner als eine
|
|
95
|
|
-volle Sekunde bleibt. Ein Zeitstempel von beispielsweise 1 Sekunde, 123456
|
|
96
|
|
-Mikrosekunden ist gültig, 1 Sekunde, 1234567 Mikrosekunden ist ungültig. In
|
|
97
|
|
-normierter Darstellung ergäbe sich 2 Sekunden, 234567 Mikrosekunden.
|
|
98
|
|
-
|
|
99
|
|
-Die Darstellungs- beziehungsweise Repräsentationsform reflektiert auch den
|
|
100
|
|
-darstellbaren Wertebereich. Da bei den dargestellten Datenstrukturen für den Typ
|
|
101
|
|
-time\_t ein long eingesetzt wird, lassen sich auf einer 32-Bit Maschine rund 4
|
|
102
|
|
-Milliarden Sekunden zählen, auf einer 64-Bit Maschine 2\^64 (mehr als 500
|
|
103
|
|
-Milliarden Jahre).
|
|
104
|
|
-
|
|
105
|
|
-Als Bezugspunkte haben sich die folgenden eingebürgert: *Start des Systems,
|
|
106
|
|
-*Start eines Jobs und \*Start einer Epoche, beispielsweise "Christi Geburt" oder
|
|
107
|
|
-der 1.1.1970 (Unix-Epoche). Dieser Bezugspunkt weist zudem noch eine örtliche
|
|
108
|
|
-Komponente auf: Der Zeitpunkt 19:00 Uhr in Europa entspricht beispielsweise
|
|
109
|
|
-einem anderen Zeitpunkt in den USA (minus sechs Stunden zur Ostküste).
|
|
110
|
|
-
|
|
111
|
|
-Die Genauigkeit wird beeinflußt durch, die Taktung des Zeitgebers, deren
|
|
112
|
|
-Schwankungen und durch Zeitsprünge.
|
|
113
|
|
-
|
|
114
|
|
-Das Attribut Zuverlässigkeit eines Zeitgebers beschreibt dessen Verhalten bei
|
|
115
|
|
-(bewußten) Schwankungen der Taktung und bei Zeitsprüngen: Ein Zeitgeber kann
|
|
116
|
|
-beispielsweise der Systemuhr folgen (CLOCK\_REALTIME) oder unabhängig von
|
|
117
|
|
-jeglicher Modifikation an der Systemzeit einfach weiterzählen
|
|
118
|
|
-(CLOCK\_MONOTONIC). Die Posix-Realzeiterweiterung beziehungsweise Linux-Systeme
|
|
119
|
|
-definieren hierzu folgende Clocks [Man-Page zu
|
|
120
|
|
-clock\_gettime()](http://linux.die.net/man/3/clock_gettime):
|
|
121
|
|
-
|
|
122
|
|
-- **CLOCK\_REALTIME**: Dieser Zeitgeber repräsentiert die systemweite, aktuelle
|
|
123
|
|
- Zeit. Er reagiert auf Zeitsprünge, sowohl vorwärts als auch rückwärts, die
|
|
124
|
|
- beispielsweise beim Aufwachen (Resume) nach einem Suspend (Schlafzustand des
|
|
125
|
|
- gesamten Systems) ausgelöst werden. Er reagiert ebenfalls auf unterschiedliche
|
|
126
|
|
- Taktungen, die beispielsweise durch NTP erfolgen. Dieser Zeitgeber liefert die
|
|
127
|
|
- Sekunden und Nanosekunden seit dem 1.1. 1970 UTC (Unixzeit) zurück.
|
|
128
|
|
-- **CLOCK\_MONOTONIC**: Dieser Zeitgeber läuft entsprechend seiner Auflösung
|
|
129
|
|
- stets vorwärts, ohne dabei Zeitsprünge zu vollziehen. Er ist also unabhängig
|
|
130
|
|
- von der mit Superuserprivilegien zu verändernden Systemuhr. Allerdings
|
|
131
|
|
- reagiert dieser Zeitgeber auf Modifikationen der Taktung, die beispielsweise
|
|
132
|
|
- durch NTP erfolgen.
|
|
133
|
|
-- **CLOCK\_MONOTONIC_RAW**: Dieser Zeitgeber ist linuxspezifisch. Er reagiert
|
|
134
|
|
- weder auf Zeitsprünge noch auf in Betrieb geänderte Taktungen (NTP).
|
|
135
|
|
-- **CLOCK\_PROCESS\_CPUTIME_ID**: Dieser Zeitgeber erfasst die Verarbeitungszeit
|
|
136
|
|
- (Execution Time) des zugehörigen Prozesses. Das funktioniert aber nur
|
|
137
|
|
- zuverlässig auf Single-Core-Systemen beziehungsweise wenn sichergestellt
|
|
138
|
|
- werden kann, dass keine Prozessmigration stattfindet.
|
|
139
|
|
-- **CLOCK\_THREAD\_CPUTIME\_ID**: Dieser Zeitgeber erfasst die Verarbeitungszeit
|
|
140
|
|
- (Execution Time) des zugehörigen Threads. Das funktioniert aber nur
|
|
141
|
|
- zuverlässig auf Single-Core-Systemen beziehungsweise wenn sichergestellt
|
|
142
|
|
- werden kann, dass keine Prozessmigration stattfindet.
|
|
143
|
|
-
|
|
144
|
|
-Der maximale Zeitbereich schließlich ergibt sich durch die Auflösung des
|
|
145
|
|
-Zeitgebers und die Bitbreite der Variablen:
|
|
146
|
|
-
|
|
147
|
|
-```text
|
|
148
|
|
-zeitbereich = auflösung * 2^bitbreite
|
|
149
|
|
-```
|
|
150
|
|
-
|
|
151
|
|
-### Zeit lesen
|
|
152
|
|
-
|
|
153
|
|
-Es gibt unterschiedliche Systemfunktionen, mit denen die aktuelle Zeit gelesen
|
|
154
|
|
-werden kann. Favorisiert ist die Funktion *int clock\_gettime(clockid\_t
|
|
155
|
|
-clk\_id, struct timespec * tp)*, die die Zeit seit dem 1.1.1970 (Unixzeit) als
|
|
156
|
|
-Universal Time (Zeitzone UTC) zurückliefert (struct timespec). Konnte die
|
|
157
|
|
-aktuelle Zeit gelesen werden, gibt die Funktion Null, ansonsten einen Fehlercode
|
|
158
|
|
-zurück. Allerdings ist das Auslesen auf 32-Bit Systemen in so fern
|
|
159
|
|
-problematisch, da der 32-Bit Zähler am 19. Januar 2038 überläuft.
|
|
160
|
|
-
|
|
161
|
|
-```c
|
|
162
|
|
-struct timespec {
|
|
163
|
|
- time_t tv_sec; /* seconds */
|
|
164
|
|
- long tv_nsec; /* nanoseconds */
|
|
165
|
|
-};
|
|
166
|
|
-
|
|
167
|
|
-```
|
|
168
|
|
-
|
|
169
|
|
-```c
|
|
170
|
|
-struct timespec timestamp;
|
|
171
|
|
- ...
|
|
172
|
|
- if (clock_gettime(CLOCK_MONOTONIC,×tamp))
|
|
173
|
|
- {
|
|
174
|
|
- perror("timestamp");
|
|
175
|
|
- return -1;
|
|
176
|
|
- }
|
|
177
|
|
- printf("seconds: %ld, nanoseconds: %ld\n",
|
|
178
|
|
- timestamp.tv\_sec, timestamp.tv\_nsec);
|
|
179
|
|
-```
|
|
180
|
|
-
|
|
181
|
|
-Durch die Wahl der Clock CLOCK\_PROCESS\_CPUTIME\_ID beziehungsweise
|
|
182
|
|
-CLOCK\_THREAD\_CPUTIME\_ID kann auch die Verarbeitungszeit ausgemessen werden
|
|
183
|
|
-(Profiling).
|
|
184
|
|
-
|
|
185
|
|
-Die Genauigkeit der zurückgelieferten Zeit kann mit Hilfe der Funktion
|
|
186
|
|
-*clock\_getres(clockid\_t clk\_id, struct timespec * res)* ausgelesen werden.
|
|
187
|
|
-
|
|
188
|
|
-Die Funktion *clock\_gettime()* ist nicht in der Standard-C-Bibliothek zu
|
|
189
|
|
-finden, sondern in der Realzeit-Bibliothek librt. Daher ist bei der
|
|
190
|
|
-Programmgenerierung diese Bibliothek hinzuzulinken (Parameter -lrt). Steht nur
|
|
191
|
|
-die Standard-C-Bibliothek zur Verfügung, kann
|
|
192
|
|
-
|
|
193
|
|
-- time\_t time(time\_t *t) oder auch
|
|
194
|
|
-- int gettimeofday(struct timeval * tv, struct timezone * tz)
|
|
195
|
|
-
|
|
196
|
|
-eingesetzt werden.
|
|
197
|
|
-
|
|
198
|
|
-*time()* gibt die Sekunden zurück, die seit dem 1.1.1970 (UTC) vergangen sind.
|
|
199
|
|
-
|
|
200
|
|
-```c
|
|
201
|
|
-time_t now;
|
|
202
|
|
-...
|
|
203
|
|
-now = time(NULL);
|
|
204
|
|
-```
|
|
205
|
|
-
|
|
206
|
|
-*gettimeofday()* schreibt an die per tv übergebene Speicheradresse die Sekunden
|
|
207
|
|
-und Mikrosekunden seit dem 1.1.1970. Das Argument tz wird typischerweise mit
|
|
208
|
|
-NULL angegeben.
|
|
209
|
|
-
|
|
210
|
|
-Liegen die Sekunden seit dem 1.1.1970 vor (timestamp.tv\_sec), können diese mit
|
|
211
|
|
-Hilfe der Funktionen
|
|
212
|
|
-
|
|
213
|
|
-- struct tm *localtime\_r(const time\_t *timep, struct tm *result) oder
|
|
214
|
|
-- struct tm *gmtime\_r(const time\_t * timep, struct tm *result)
|
|
215
|
|
-
|
|
216
|
|
-in die Struktur *struct tm* konvertiert werden.
|
|
217
|
|
-
|
|
218
|
|
-```c
|
|
219
|
|
-struct tm absolute_time;
|
|
220
|
|
-if (localtime_r( timestamp.tv_sec, &absolute_time )==NULL)
|
|
221
|
|
-{
|
|
222
|
|
- perror("localtime_r" );
|
|
223
|
|
- return -1;
|
|
224
|
|
-}
|
|
225
|
|
-
|
|
226
|
|
-printf("year: %d\n", absolute_time.tm_year);
|
|
227
|
|
-```
|
|
228
|
|
-
|
|
229
|
|
-Die Funktion *time\_t mktime(struct tm * tm)* konvertiert eine über die Struktur
|
|
230
|
|
-struct tm gegebene Zeit in Sekunden seit dem 1.1.1970 (time\_t).
|
|
231
|
|
-
|
|
232
|
|
-Mit Hilfe der Funktion *clock\_t times(struct tms \ buf)* lässt sich sowohl die
|
|
233
|
|
-aktuelle Zeit zu einem letztlich nicht genau definierten Bezugspunkt, als auch
|
|
234
|
|
-die Verarbeitungszeit (Execution-Time) des aufrufenden Prozesses bestimmen. Die
|
|
235
|
|
-Zeiten werden als Timerticks (clock\_t) zurückgeliefert. Die zurückgelieferte
|
|
236
|
|
-Verarbeitungszeit ist aufgeschlüsselt in die Anteile, die im Userland und die
|
|
237
|
|
-Anteile, die im Kernel verbraucht wurden. Außerdem werden diese Anteile auch für
|
|
238
|
|
-Kindprozesse gelistet.
|
|
239
|
|
-
|
|
240
|
|
-```c
|
|
241
|
|
-#include <stdio.h>
|
|
242
|
|
-#include <sys/times.h>
|
|
243
|
|
-#include <unistd.h>
|
|
244
|
|
-#include <time.h>
|
|
245
|
|
-
|
|
246
|
|
-int main( int argc, char **argv, char **envp )
|
|
247
|
|
-{
|
|
248
|
|
- struct tms exec_time;
|
|
249
|
|
- clock_t act_time;
|
|
250
|
|
- long ticks_per_second;
|
|
251
|
|
- long tickduration_in_ms;
|
|
252
|
|
-
|
|
253
|
|
- ticks_per_second = sysconf(_SC_CLK_TCK);
|
|
254
|
|
- tickduration_in_ms = 1000/ticks_per_second;
|
|
255
|
|
-
|
|
256
|
|
- act_time = times( &exec_time );
|
|
257
|
|
- printf("actual time (in ms): %ld\n", act_time*tickduration_in_ms);
|
|
258
|
|
- printf("execution time (in ms): %ld\n",
|
|
259
|
|
- (exec_time.tms_utime+exec_time.tms_stime)*tickduration_in_ms);
|
|
260
|
|
-
|
|
261
|
|
- return 0;
|
|
262
|
|
-
|
|
263
|
|
-}
|
|
264
|
|
-```
|
|
265
|
|
-
|
|
266
|
|
-Sehr genaue Zeiten lassen sich erfassen, falls der eingesetzte Prozessor einen
|
|
267
|
|
-Zähler besitzt, der mit der Taktfrequenz des Systems getaktet wird. Bei einer
|
|
268
|
|
-x86-Architektur (PC) heißt dieser Zähler Time Stamp Counter (TSC). Der TSC kann
|
|
269
|
|
-auch von einer normalen Applikation ausgelesen werden, allerdings muss
|
|
270
|
|
-sichergestellt sein, dass sich die Taktfrequenz zwischen zwei Messungen ändert.
|
|
271
|
|
-Alternativ kann man sich vom Betriebssystem über die Taktänderung informieren
|
|
272
|
|
-lassen.
|
|
273
|
|
-
|
|
274
|
|
-### Zeitvergleich: Differenzzeitmessung
|
|
275
|
|
-
|
|
276
|
|
-Zwei Absolutzeiten (struct tm) werden am einfachsten über deren Repräsentation
|
|
277
|
|
-in Sekunden verglichen. Die Umwandlung erfolgt über die Funktion (time\_t
|
|
278
|
|
-mktime(struct tm \*tm)). Allerdings ist dabei zu beachten, dass es auf einem
|
|
279
|
|
-32-Bit System am 19. Januar 2038 zu einem Überlauf kommt. Wird einer der beiden
|
|
280
|
|
-Zeitstempel vor dem 19. Januar 2038 genommen, der andere danach, kommt es zu
|
|
281
|
|
-einem falschen Ergebnis, wenn nur die beiden Werte per "\<" beziehungsweise "\>"
|
|
282
|
|
-verglichen werden.
|
|
283
|
|
-
|
|
284
|
|
-Das ist ein generelles Problem und kann dann gelöst werden, wenn sichergestellt
|
|
285
|
|
-ist, dass die zu vergleichenden Zeiten nicht weiter als die Hälfte des gesamten
|
|
286
|
|
-Zeitbereiches auseinanderliegen. In diesem Fall lassen sich die Makros
|
|
287
|
|
-einsetzen, die im Linux-Kernel für den Vergleich zweier Zeiten eingesetzt
|
|
288
|
|
-werden. Das Makro time\_after(a,b) liefert true zurück, falls es sich bei a um
|
|
289
|
|
-eine spätere Zeit als b handelt. Das Makro time\_after\_eq(a,b) liefert true
|
|
290
|
|
-zurück, falls es sich bei a um eine spätere Zeit oder um die gleiche Zeit
|
|
291
|
|
-handelt, wie b handelt. Die Zeitstempel a und b müssen beide vom Typ unsigned
|
|
292
|
|
-long sein. Natürlich können die Makros auch auf andere Datentypen angepasst
|
|
293
|
|
-werden
|
|
294
|
|
-
|
|
295
|
|
-[HEADERDATEI linux/jiffies.h].
|
|
296
|
|
-
|
|
297
|
|
-```c
|
|
298
|
|
-#define time_after(a,b) \
|
|
299
|
|
- (typecheck(unsigned long, a) && \
|
|
300
|
|
- typecheck(unsigned long, b) && \
|
|
301
|
|
- ((long)(b) - (long)(a) < 0))
|
|
302
|
|
-
|
|
303
|
|
-#define time_before(a,b) time_after(b,a)
|
|
304
|
|
-
|
|
305
|
|
-#define time_after_eq(a,b) \
|
|
306
|
|
- (typecheck(unsigned long, a) && \
|
|
307
|
|
- typecheck(unsigned long, b) && \
|
|
308
|
|
- ((long)(a) - (long)(b) \>= 0))
|
|
309
|
|
-
|
|
310
|
|
-#define time_before_eq(a,b) time_after_eq(b,a)
|
|
311
|
|
-```
|
|
312
|
|
-
|
|
313
|
|
-Beim Benchmarking ist es häufig notwendig eine Zeitdauer zu messen, Zeitpunkte
|
|
314
|
|
-zu erfassen oder eine definierte Zeit verstreichen zu lassen. Dabei sind
|
|
315
|
|
-folgende Aspekte zu beachten:
|
|
316
|
|
-
|
|
317
|
|
-- Die Genauigkeit der eingesetzten Zeitgeber,
|
|
318
|
|
-- die maximalen Zeitdifferenzen,
|
|
319
|
|
-- Schwankungen der Zeitbasis, beispielsweise durch Schlafzustände,
|
|
320
|
|
-- Modifikationen an der Zeitbasis des eingesetzten Rechnersystems (Zeitsprünge)
|
|
321
|
|
- und
|
|
322
|
|
-- die Ortsabhängigkeit absoluter Zeitpunkte.
|
|
323
|
|
-
|
|
324
|
|
-Zur Bestimmung einer Zeitdauer verwendet man häufig eine Differenzzeitmessung.
|
|
325
|
|
-Dabei wird vor und nach der auszumessenden Aktion jeweils ein Zeitstempel
|
|
326
|
|
-genommen. Die Zeitdauer ergibt sich aus der Differenz dieser beiden Zeitstempel.
|
|
327
|
|
-
|
|
328
|
|
-Dies ist allerdings nicht immer ganz einfach. Liegt der Zeitstempel
|
|
329
|
|
-beispielsweise in Form der Datenstruktur struct timeval (als Ergebnis der
|
|
330
|
|
-Funktion *gettimeofday()*) vor, müssen die Sekunden zunächst getrennt von den
|
|
331
|
|
-Mikrosekunden subtrahiert werden. Ist der Mikrosekundenanteil negativ, muss der
|
|
332
|
|
-Sekundenanteil um eins erniedrigt und der Mikrosekundenanteil korrigiert werden.
|
|
333
|
|
-Dazu wird auf die Anzahl der Mikrosekunden pro Sekunde (also eine Million) der
|
|
334
|
|
-negative Mikrosekundenanteil addiert.
|
|
335
|
|
-
|
|
336
|
|
-```c
|
|
337
|
|
-#define MICROSECONDS\_PER\_SECOND 1000000
|
|
338
|
|
-
|
|
339
|
|
-struct timespec * diff_time( struct timeval before, struct timeval after,
|
|
340
|
|
- struct timeval *result )
|
|
341
|
|
-{
|
|
342
|
|
- if (result==NULL)
|
|
343
|
|
- return NULL;
|
|
344
|
|
-
|
|
345
|
|
- result->tv_sec = after.tv_sec - before.tv_sec;
|
|
346
|
|
- result->tv_usec= after.tv_usec- before.tv_usec;
|
|
347
|
|
-
|
|
348
|
|
- if (result->tv_usec<0) {
|
|
349
|
|
- result->tv_sec--;
|
|
350
|
|
- /* result->tv_usec is negative, therefore we use "+" */
|
|
351
|
|
- result->tv_usec = MICROSECONDS_PER_SECOND+result->tv_usec;
|
|
352
|
|
- }
|
|
353
|
|
- return result;
|
|
354
|
|
-
|
|
355
|
|
-}
|
|
356
|
|
-```
|
|
357
|
|
-
|
|
358
|
|
-Für Zeitstempel vom Typ struct timeval gilt entsprechendes. Anstelle der
|
|
359
|
|
-MICROSECONDS\_PER\_SECOND sind NANOSECONDS\_PER\_SECOND einzusetzen. Sind die
|
|
360
|
|
-Zeitstempel vorzeichenlos, sieht die Rechnung für den Sekundenanteil etwas
|
|
361
|
|
-komplizierter aus. Das soll hier aber nicht weiter vertieft werden.
|
|
362
|
|
-
|
|
363
|
|
-Etwas einfacher ist die Differenzbildung, wenn aus der Datenstruktur eine
|
|
364
|
|
-einzelne Variable mit der gewünschten Auflösung, beispielsweise Mikrosekunden,
|
|
365
|
|
-generiert wird. Im Fall von struct timeval wird dazu der Sekundenanteil mit
|
|
366
|
|
-einer Million multipliziert und der Mikrosekundenanteil aufaddiert. Bei der
|
|
367
|
|
-Multiplikation können natürlich Informationen verloren gehen, allerdings geht
|
|
368
|
|
-der gleiche Informationsgehalt auch beim zweiten Zeitstempel verloren. Für die
|
|
369
|
|
-Differenzbildung ist das damit nicht relevant, solange der zu messende zeitliche
|
|
370
|
|
-Abstand kleiner als 1000 Sekunden ist und es während der Messung keinen Überlauf
|
|
371
|
|
-beim Sekundenanteil gibt.
|
|
372
|
|
-
|
|
373
|
|
-```c
|
|
374
|
|
-time_in_usec=((nachher.tv_sec*1000000)+nachher.tv_usec)-
|
|
375
|
|
- ((vorher.tv_sec*1000000)+vorher.tv_usec);
|
|
376
|
|
-```
|