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