1 /* timer.c -- Timer support
2  * Created: Sat Oct  7 13:05:31 1995 by faith@dict.org
3  * Copyright 1995-1998, 2002 Rickard E. Faith (faith@dict.org)
4  * Copyright 2002-2008 Aleksey Cheusov (vle@gmx.net)
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining
7  * a copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sublicense, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be
15  * included in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  *
25  * \section{Timer Support}
26  *
27  * \intro These routines provide access to a microsecond-resolution time
28  * that can be used for profiling.
29  *
30  */
31 
32 #include "maaP.h"
33 
34 static hsh_HashTable _tim_Hash;
35 
36 typedef struct tim_Entry {
37 	double real;			/* wall time in sec */
38 	double self_user;		/* user time in sec */
39 	double self_system;		/* system time in sec */
40 	double children_user;	/* user time in sec */
41 	double children_system;	/* system time in sec */
42 	struct timeval real_mark;
43 	struct rusage  self_mark;
44 	struct rusage  children_mark;
45 } *tim_Entry;
46 
_tim_check(void)47 static void _tim_check(void)
48 {
49 	if (!_tim_Hash) _tim_Hash = hsh_create(NULL, NULL);
50 }
51 
52 /* \doc Start the named timer. */
53 
tim_start(const char * name)54 void tim_start(const char *name)
55 {
56 	tim_Entry entry;
57 
58 	_tim_check();
59 	if (!(entry = (tim_Entry)__UNCONST(hsh_retrieve(_tim_Hash, name)))) {
60 		entry = xmalloc(sizeof(struct tim_Entry ));
61 		entry->real            = 0.0;
62 		entry->self_user       = 0.0;
63 		entry->self_system     = 0.0;
64 		entry->children_user   = 0.0;
65 		entry->children_system = 0.0;
66 		hsh_insert(_tim_Hash, name, entry);
67 	}
68 
69 	gettimeofday(&entry->real_mark, NULL);
70 
71 	getrusage(RUSAGE_SELF, &entry->self_mark);
72 	getrusage(RUSAGE_CHILDREN, &entry->children_mark);
73 }
74 
75 /* \doc Stop the named timer. */
76 
tim_stop(const char * name)77 void tim_stop(const char *name)
78 {
79 	tim_Entry entry;
80 	struct timeval  real;
81 	struct rusage   rusage;
82 
83 #define DIFFTIME(now,then)							\
84 	(((now).tv_sec - (then).tv_sec)					\
85 	 + ((now).tv_usec - (then).tv_usec)/1000000)
86 
87 	_tim_check();
88 	gettimeofday(&real, NULL);
89 
90 	if (!(entry = (tim_Entry)__UNCONST(hsh_retrieve(_tim_Hash, name))))
91 		err_internal (__func__, "No timer: %s",
92 					  (name ? name : "<null>"));
93 
94 	entry->real   = DIFFTIME(real, entry->real_mark);
95 	getrusage(RUSAGE_SELF, &rusage);
96 	entry->self_user   = DIFFTIME(rusage.ru_utime, entry->self_mark.ru_utime);
97 	entry->self_system = DIFFTIME(rusage.ru_stime, entry->self_mark.ru_stime);
98 
99 	getrusage(RUSAGE_CHILDREN, &rusage);
100 	entry->children_user
101 		= DIFFTIME(rusage.ru_utime, entry->children_mark.ru_utime);
102 	entry->children_system
103 		= DIFFTIME(rusage.ru_stime, entry->children_mark.ru_stime);
104 }
105 
106 /* \doc Reset the named timer to zero elapsed time.  Use |tim_start| to reset
107    the start time.  */
108 
tim_reset(const char * name)109 void tim_reset(const char *name)
110 {
111 	tim_Entry entry;
112 
113 	_tim_check();
114 	if (!(entry = (tim_Entry)__UNCONST(hsh_retrieve(_tim_Hash, name))))
115 		err_internal (__func__, "No timer: %s",
116 					  (name ? name : "<null>"));
117 
118 	entry->real            = 0.0;
119 	entry->self_user       = 0.0;
120 	entry->self_system     = 0.0;
121 	entry->children_user   = 0.0;
122 	entry->children_system = 0.0;
123 }
124 
125 /* \doc Get the wall time in seconds from the named timer.  The return
126    value is a |double| and has microsecond resolution if the current system
127    provides that accuracy (most don't). */
128 
tim_get_real(const char * name)129 double tim_get_real(const char *name)
130 {
131 	tim_Entry entry;
132 
133 	_tim_check();
134 	if (!(entry = (tim_Entry)__UNCONST(hsh_retrieve(_tim_Hash, name))))
135 		err_internal (__func__, "No timer: %s",
136 					  (name ? name : "<null>"));
137 
138 	return entry->real;
139 }
140 
141 /* \doc Get the number of seconds of user CPU time. */
142 
tim_get_user(const char * name)143 double tim_get_user(const char *name)
144 {
145 	tim_Entry entry;
146 
147 	_tim_check();
148 	if (!(entry = (tim_Entry)__UNCONST(hsh_retrieve(_tim_Hash, name))))
149 		err_internal (__func__, "No timer: %s",
150 					  (name ? name : "<null>"));
151 
152 #if 0
153 	printf("self: maxrss %ld ixrss %ld idrss %ld isrss %ld minflt %ld"
154 		   " majflt %ld nswap %ld inblock %ld outblock %ld msgsnd %ld"
155 		   " msgrcv %ld nsignals %ld nvcwm %ld nivcsm %ld\n",
156 		   entry->self_mark.ru_maxrss,
157 		   entry->self_mark.ru_ixrss,
158 		   entry->self_mark.ru_idrss,
159 		   entry->self_mark.ru_isrss,
160 		   entry->self_mark.ru_minflt,
161 		   entry->self_mark.ru_majflt,
162 		   entry->self_mark.ru_nswap,
163 		   entry->self_mark.ru_inblock,
164 		   entry->self_mark.ru_oublock,
165 		   entry->self_mark.ru_msgsnd,
166 		   entry->self_mark.ru_msgrcv,
167 		   entry->self_mark.ru_nsignals,
168 		   entry->self_mark.ru_nvcsw,
169 		   entry->self_mark.ru_nivcsw);
170 	printf("chld: maxrss %ld ixrss %ld idrss %ld isrss %ld minflt %ld"
171 		   " majflt %ld nswap %ld inblock %ld outblock %ld msgsnd %ld"
172 		   " msgrcv %ld nsignals %ld nvcwm %ld nivcsm %ld\n",
173 		   entry->children_mark.ru_maxrss,
174 		   entry->children_mark.ru_ixrss,
175 		   entry->children_mark.ru_idrss,
176 		   entry->children_mark.ru_isrss,
177 		   entry->children_mark.ru_minflt,
178 		   entry->children_mark.ru_majflt,
179 		   entry->children_mark.ru_nswap,
180 		   entry->children_mark.ru_inblock,
181 		   entry->children_mark.ru_oublock,
182 		   entry->children_mark.ru_msgsnd,
183 		   entry->children_mark.ru_msgrcv,
184 		   entry->children_mark.ru_nsignals,
185 		   entry->children_mark.ru_nvcsw,
186 		   entry->children_mark.ru_nivcsw);
187 #endif
188 
189 	return (entry->self_user + entry->children_user);
190 }
191 
192 /* \doc Get the number of seconds of system CPU time. */
193 
tim_get_system(const char * name)194 double tim_get_system(const char *name)
195 {
196 	tim_Entry entry;
197 
198 	_tim_check();
199 	if (!(entry = (tim_Entry)__UNCONST(hsh_retrieve(_tim_Hash, name))))
200 		err_internal (__func__, "No timer: %s",
201 					  (name ? name : "<null>"));
202 
203 	return (entry->self_system + entry->children_system);
204 }
205 
206 /* \doc Print the named timer values to |str|.  The format is similar to
207    "time(1)". */
208 
tim_print_timer(FILE * str,const char * name)209 void tim_print_timer(FILE *str, const char *name)
210 {
211    fprintf(str, "%-20s %0.3fr %0.3fu %0.3fs\n",
212 	    name,
213 	    tim_get_real(name),
214 	    tim_get_user(name),
215 	    tim_get_system(name));
216 }
217 
_tim_iterator(const void * key,const void * datum,void * arg)218 static int _tim_iterator(const void *key, const void *datum, void *arg)
219 {
220 	FILE *str = (FILE *)arg;
221 
222 	tim_print_timer(str, key);
223 	return 0;
224 }
225 
226 /* \doc Print all the timers to |str|.  The order is arbitary. */
227 
tim_print_timers(FILE * str)228 void tim_print_timers(FILE *str)
229 {
230 	if (_tim_Hash) hsh_iterate_arg(_tim_Hash, _tim_iterator, str);
231 }
232 
_tim_freer(const void * key,const void * datum)233 static int _tim_freer(const void *key, const void *datum)
234 {
235 	xfree(__UNCONST(datum)); /* Discard const */
236 	return 0;
237 }
238 
239 /* \doc Free all memory associated with the timers.  This function is
240    called automatically at program termination.  There should never be a
241    need to call this function in user-level code. */
242 
_tim_shutdown(void)243 void _tim_shutdown(void)
244 {
245 	if (_tim_Hash) {
246 		hsh_iterate(_tim_Hash, _tim_freer);
247 		hsh_destroy(_tim_Hash);
248 	}
249 	_tim_Hash = NULL;
250 }
251