xref: /titanic_51/usr/src/cmd/latencytop/common/util.c (revision 1fcced4c370617db71610fecffd5451a5894ca5e)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 2008-2009, Intel Corporation.
23  * All Rights Reserved.
24  */
25 
26 #include <unistd.h>
27 #include <libintl.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <ctype.h>
32 #include <procfs.h>
33 #include <fcntl.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 
37 #include "latencytop.h"
38 
39 /* pipe that breaks the event loop (and exit early) */
40 static int signal_pipe[2];
41 
42 /*
43  * Get current system time in milliseconds (1e-3).
44  */
45 uint64_t
46 lt_millisecond(void)
47 {
48 	struct timeval p;
49 	(void) gettimeofday(&p, NULL);
50 	return ((uint64_t)p.tv_sec * 1000 + p.tv_usec / 1000);
51 }
52 
53 /*
54  * Wrapper of gettext().
55  */
56 const char *
57 lt_text(const char *text)
58 {
59 	if (text == NULL) {
60 		return ("");
61 	}
62 
63 	return (gettext(text));
64 }
65 
66 /*
67  * Checks if OOM happens by comparing pointers with NULL in various places.
68  */
69 void
70 lt_check_null(void *p)
71 {
72 	if (p == NULL) {
73 		(void) printf("Out of memory!\n");
74 		g_assert(0);
75 		exit(2);
76 	}
77 }
78 
79 /*
80  * Safe malloc.
81  */
82 void *
83 lt_malloc(size_t size)
84 {
85 	void *ret = malloc(size);
86 
87 	lt_check_null(ret);
88 
89 	return (ret);
90 }
91 
92 /*
93  * Safe alloc with memory cleared.
94  * Named it "zalloc" because its signature is different from
95  * calloc() in stdlib.
96  */
97 void *
98 lt_zalloc(size_t size)
99 {
100 	void *ret = lt_malloc(size);
101 	(void) memset(ret, 0, size);
102 	return (ret);
103 }
104 
105 /*
106  * Safe strdup.
107  */
108 char *
109 lt_strdup(const char *str)
110 {
111 	char *ret = strdup(str);
112 
113 	lt_check_null(ret);
114 
115 	return (ret);
116 }
117 
118 /*
119  * Get string for current time, e.g. YYYY-MM-DD
120  */
121 void
122 lt_time_str(char *buffer, int len)
123 {
124 	struct tm tms;
125 	time_t t;
126 	int i;
127 
128 	(void) time(&t);
129 	(void) gmtime_r(&t, &tms);
130 	(void) asctime_r(&tms, buffer, len);
131 
132 	for (i = strlen(buffer)-1; i > 0; --i) {
133 		if (isspace(buffer[i])) {
134 			buffer[i] = 0;
135 		} else	{
136 			break;
137 		}
138 	}
139 }
140 
141 /*
142  * Retrieves process exeutable name etc. from /proc.
143  */
144 char *
145 lt_get_proc_field(pid_t pid, lt_field_t field)
146 {
147 	char name[PATH_MAX];
148 	int fd;
149 	int ret;
150 	psinfo_t psinfo;
151 
152 	(void) snprintf(name, PATH_MAX, "/proc/%d/psinfo", (int)pid);
153 	fd = open(name, O_RDONLY);
154 	if (fd == -1) {
155 		return (NULL);
156 	}
157 
158 	ret = read(fd, (char *)&psinfo, sizeof (psinfo_t));
159 	(void) close(fd);
160 	if (ret < 0) {
161 		return (NULL);
162 	}
163 
164 	switch (field) {
165 	case LT_FIELD_FNAME:
166 		return (lt_strdup(psinfo.pr_fname));
167 	case LT_FIELD_PSARGS:
168 		return (lt_strdup(psinfo.pr_psargs));
169 	}
170 	return (NULL);
171 }
172 
173 /*
174  * Help function to update the data structure.
175  */
176 void
177 lt_update_stat_value(lt_stat_data_t *entry,
178     lt_stat_type_t type, uint64_t value)
179 {
180 	switch (type) {
181 	case LT_STAT_COUNT:
182 		entry->count += value;
183 		break;
184 	case LT_STAT_SUM:
185 		entry->total += value;
186 		break;
187 	case LT_STAT_MAX:
188 		if (value > entry->max) {
189 			entry->max = value;
190 		}
191 		break;
192 	default:
193 		break;
194 	}
195 }
196 
197 /*
198  * Help function to sort by total.
199  */
200 int
201 lt_sort_by_total_desc(lt_stat_entry_t *a, lt_stat_entry_t *b)
202 {
203 	g_assert(a != NULL && b != NULL);
204 	/*
205 	 * ->data.total is int64, so we can't simply return
206 	 * b->data.total - a->data.total
207 	 */
208 	if (b->data.total > a->data.total) {
209 		return (1);
210 	} else if (b->data.total < a->data.total) {
211 		return (-1);
212 	} else	{
213 		return (0);
214 	}
215 }
216 
217 /*
218  * Help function to sort by max.
219  */
220 int
221 lt_sort_by_max_desc(lt_stat_entry_t *a, lt_stat_entry_t *b)
222 {
223 	g_assert(a != NULL && b != NULL);
224 
225 	if (b->data.max > a->data.max) {
226 		return (1);
227 	} else if (b->data.max < a->data.max) {
228 		return (-1);
229 	} else	{
230 		return (0);
231 	}
232 }
233 
234 /*
235  * Help function to sort by count.
236  */
237 int
238 lt_sort_by_count_desc(lt_stat_entry_t *a, lt_stat_entry_t *b)
239 {
240 	g_assert(a != NULL && b != NULL);
241 
242 	if (b->data.count > a->data.count) {
243 		return (1);
244 	} else if (b->data.count < a->data.count) {
245 		return (-1);
246 	} else	{
247 		return (0);
248 	}
249 }
250 
251 /*
252  * Help function to sort by average.
253  */
254 int
255 lt_sort_by_avg_desc(lt_stat_entry_t *a, lt_stat_entry_t *b)
256 {
257 	double avg_a, avg_b;
258 
259 	g_assert(a != NULL && b != NULL);
260 
261 	avg_a = (double)a->data.total / a->data.count;
262 	avg_b = (double)b->data.total / b->data.count;
263 
264 	if (avg_b > avg_a) {
265 		return (1);
266 	} else if (avg_b < avg_a) {
267 		return (-1);
268 	} else	{
269 		return (0);
270 	}
271 }
272 
273 /*
274  * Create pipe for signal handler and wakeup.
275  */
276 void
277 lt_gpipe_init(void)
278 {
279 	(void) pipe(signal_pipe);
280 }
281 
282 /*
283  * Release pipe used in signal handler.
284  */
285 void
286 lt_gpipe_deinit(void)
287 {
288 	(void) close(signal_pipe[0]);
289 	(void) close(signal_pipe[1]);
290 }
291 
292 /*
293  * Break from main loop early.
294  */
295 void
296 lt_gpipe_break(const char *ch)
297 {
298 	(void) write(signal_pipe[1], ch, 1);
299 }
300 
301 /*
302  * Returns fd# used to detect "break main loop".
303  */
304 int
305 lt_gpipe_readfd(void)
306 {
307 	return (signal_pipe[0]);
308 }
309 
310 /*
311  * Check if a file exists.
312  */
313 int
314 lt_file_exist(const char *name)
315 {
316 	struct stat64 st;
317 
318 	if (stat64(name, &st) == 0) {
319 		return (1);
320 	} else	{
321 		return (0);
322 	}
323 }
324