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 exits early) */
40 static int signal_pipe[2];
41 
42 /*
43  * Get current system time in milliseconds (1e-3).
44  */
45 uint64_t
lt_millisecond(void)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  * Check if we are out of memory.
55  */
56 void
lt_check_null(void * p)57 lt_check_null(void *p)
58 {
59 	if (p == NULL) {
60 		(void) fprintf(stderr, "Out of memory!\n");
61 		g_assert(0);
62 		exit(2);
63 	}
64 }
65 
66 /*
67  * Safe malloc.
68  */
69 void *
lt_malloc(size_t size)70 lt_malloc(size_t size)
71 {
72 	void *ret = malloc(size);
73 
74 	lt_check_null(ret);
75 
76 	return (ret);
77 }
78 
79 /*
80  * Safe alloc with memory cleared.
81  * It is named "zalloc" because its signature is different from
82  * calloc() in stdlib.
83  */
84 void *
lt_zalloc(size_t size)85 lt_zalloc(size_t size)
86 {
87 	void *ret = calloc(size, 1);
88 
89 	lt_check_null(ret);
90 
91 	return (ret);
92 }
93 
94 /*
95  * Safe strdup.
96  */
97 char *
lt_strdup(const char * str)98 lt_strdup(const char *str)
99 {
100 	char *ret = strdup(str);
101 
102 	lt_check_null(ret);
103 
104 	return (ret);
105 }
106 
107 /*
108  * Get string for current time, e.g. YYYY-MM-DD
109  */
110 void
lt_time_str(char * buffer,int len)111 lt_time_str(char *buffer, int len)
112 {
113 	struct tm tms;
114 	time_t t;
115 	int i;
116 
117 	(void) time(&t);
118 	(void) gmtime_r(&t, &tms);
119 	(void) asctime_r(&tms, buffer, len);
120 
121 	for (i = strlen(buffer)-1; i > 0; --i) {
122 
123 		if (isspace(buffer[i])) {
124 			buffer[i] = '\0';
125 		} else {
126 			break;
127 		}
128 	}
129 }
130 
131 /*
132  * Retrieves the process's executable name and arguments from /proc.
133  */
134 char *
lt_get_proc_field(pid_t pid,lt_field_t field)135 lt_get_proc_field(pid_t pid, lt_field_t field)
136 {
137 	char name[PATH_MAX];
138 	int fd;
139 	int ret;
140 	psinfo_t psinfo;
141 
142 	(void) snprintf(name, PATH_MAX, "/proc/%d/psinfo", (int)pid);
143 	fd = open(name, O_RDONLY);
144 
145 	if (fd == -1) {
146 		return (NULL);
147 	}
148 
149 	ret = read(fd, (char *)&psinfo, sizeof (psinfo_t));
150 	(void) close(fd);
151 
152 	if (ret < 0) {
153 		return (NULL);
154 	}
155 
156 	switch (field) {
157 	case LT_FIELD_FNAME:
158 		return (lt_strdup(psinfo.pr_fname));
159 	case LT_FIELD_PSARGS:
160 		return (lt_strdup(psinfo.pr_psargs));
161 	}
162 	return (NULL);
163 }
164 
165 /*
166  * Helper function to update the data structure.
167  */
168 void
lt_update_stat_value(lt_stat_data_t * entry,lt_stat_type_t type,uint64_t value)169 lt_update_stat_value(lt_stat_data_t *entry,
170     lt_stat_type_t type, uint64_t value)
171 {
172 	switch (type) {
173 	case LT_STAT_COUNT:
174 		entry->lt_s_count += value;
175 		break;
176 	case LT_STAT_SUM:
177 		entry->lt_s_total += value;
178 		break;
179 	case LT_STAT_MAX:
180 		if (value > entry->lt_s_max) {
181 			entry->lt_s_max = value;
182 		}
183 		break;
184 	default:
185 		break;
186 	}
187 }
188 
189 /*
190  * Helper function to sort on total.
191  */
192 int
lt_sort_by_total_desc(lt_stat_entry_t * a,lt_stat_entry_t * b)193 lt_sort_by_total_desc(lt_stat_entry_t *a, lt_stat_entry_t *b)
194 {
195 	g_assert(a != NULL && b != NULL);
196 	/*
197 	 * lt_s_total is of type int64_t, so we can't simply return
198 	 * (b->lt_se_data.lt_s_total - a->lt_se_data.lt_s_total).
199 	 */
200 	if (b->lt_se_data.lt_s_total > a->lt_se_data.lt_s_total) {
201 		return (1);
202 	} else if (b->lt_se_data.lt_s_total < a->lt_se_data.lt_s_total) {
203 		return (-1);
204 	} else {
205 		return (0);
206 	}
207 }
208 
209 /*
210  * Helper function to sort on max.
211  */
212 int
lt_sort_by_max_desc(lt_stat_entry_t * a,lt_stat_entry_t * b)213 lt_sort_by_max_desc(lt_stat_entry_t *a, lt_stat_entry_t *b)
214 {
215 	g_assert(a != NULL && b != NULL);
216 
217 	if (b->lt_se_data.lt_s_max > a->lt_se_data.lt_s_max) {
218 		return (1);
219 	} else if (b->lt_se_data.lt_s_max < a->lt_se_data.lt_s_max) {
220 		return (-1);
221 	} else {
222 		return (0);
223 	}
224 }
225 
226 /*
227  * Helper function to sort on count.
228  */
229 int
lt_sort_by_count_desc(lt_stat_entry_t * a,lt_stat_entry_t * b)230 lt_sort_by_count_desc(lt_stat_entry_t *a, lt_stat_entry_t *b)
231 {
232 	g_assert(a != NULL && b != NULL);
233 
234 	if (b->lt_se_data.lt_s_count > a->lt_se_data.lt_s_count) {
235 		return (1);
236 	} else if (b->lt_se_data.lt_s_count < a->lt_se_data.lt_s_count) {
237 		return (-1);
238 	} else {
239 		return (0);
240 	}
241 }
242 
243 /*
244  * Helper function to sort on average.
245  */
246 int
lt_sort_by_avg_desc(lt_stat_entry_t * a,lt_stat_entry_t * b)247 lt_sort_by_avg_desc(lt_stat_entry_t *a, lt_stat_entry_t *b)
248 {
249 	double avg_a, avg_b;
250 
251 	g_assert(a != NULL && b != NULL);
252 
253 	avg_a = (double)a->lt_se_data.lt_s_total / a->lt_se_data.lt_s_count;
254 	avg_b = (double)b->lt_se_data.lt_s_total / b->lt_se_data.lt_s_count;
255 
256 	if (avg_b > avg_a) {
257 		return (1);
258 	} else if (avg_b < avg_a) {
259 		return (-1);
260 	} else {
261 		return (0);
262 	}
263 }
264 
265 /*
266  * Create pipe for signal handler and wakeup.
267  */
268 void
lt_gpipe_init(void)269 lt_gpipe_init(void)
270 {
271 	(void) pipe(signal_pipe);
272 }
273 
274 /*
275  * Close the pipe used in signal handler.
276  */
277 void
lt_gpipe_deinit(void)278 lt_gpipe_deinit(void)
279 {
280 	(void) close(signal_pipe[0]);
281 	(void) close(signal_pipe[1]);
282 }
283 
284 /*
285  * Break early from the main loop.
286  */
287 void
lt_gpipe_break(const char * ch)288 lt_gpipe_break(const char *ch)
289 {
290 	(void) write(signal_pipe[1], ch, 1);
291 }
292 
293 int
lt_gpipe_readfd(void)294 lt_gpipe_readfd(void)
295 {
296 	return (signal_pipe[0]);
297 }
298 
299 /*
300  * Check if the given file exists.
301  */
302 int
lt_file_exist(const char * name)303 lt_file_exist(const char *name)
304 {
305 	struct stat64 st;
306 
307 	if (stat64(name, &st) == 0) {
308 		return (1);
309 	} else {
310 		return (0);
311 	}
312 }
313