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
  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
  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 *
  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 *
  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 *
  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
 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 *
 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
 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
 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
 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
 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
 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
 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
 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
 288 lt_gpipe_break(const char *ch)
 289 {
 290         (void) write(signal_pipe[1], ch, 1);
 291 }
 292 
 293 int
 294 lt_gpipe_readfd(void)
 295 {
 296         return (signal_pipe[0]);
 297 }
 298 
 299 /*
 300  * Check if the given file exists.
 301  */
 302 int
 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 }