1/* 2 * Copyright (c) 2008 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * The contents of this file constitute Original Code as defined in and 7 * are subject to the Apple Public Source License Version 1.1 (the 8 * "License"). You may not use this file except in compliance with the 9 * License. Please obtain a copy of the License at 10 * http://www.apple.com/publicsource and read it before using this file. 11 * 12 * This Original Code and all software distributed under the License are 13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER 14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the 17 * License for the specific language governing rights and limitations 18 * under the License. 19 * 20 * @APPLE_LICENSE_HEADER_END@ 21 */ 22 23#include <stdlib.h> 24#include <string.h> 25#include <mach/mach_time.h> 26 27#include "statistic.h" 28 29#include "preferences.h" 30 31#include "pid.h" 32#include "pgrp.h" 33#include "ppid.h" 34#include "command.h" 35#include "cpu.h" 36#include "timestat.h" 37#include "threads.h" 38#include "ports.h" 39#include "memstats.h" 40#include "pstate.h" 41#include "user.h" 42#include "workqueue.h" 43#include "uid.h" 44#include "faults.h" 45#include "messages.h" 46#include "syscalls.h" 47#include "csw.h" 48#include "log.h" 49#include "power.h" 50 51struct statistic_name_map statistic_name_map[] = { 52 /*The order of this must match the enum in statistic.h. */ 53 {STATISTIC_PID, top_pid_create, "PID"}, 54 {STATISTIC_COMMAND, top_command_create, "COMMAND"}, 55 {STATISTIC_CPU, top_cpu_create, "%CPU"}, 56 {STATISTIC_TIME, top_time_create, "TIME"}, 57 {STATISTIC_THREADS, top_threadcount_create, "#TH"}, 58 {STATISTIC_PORTS, top_ports_create, "#PORTS"}, 59 {STATISTIC_MREGION, top_mregion_create, "#MREGS"}, 60#ifdef TOP_ANONYMOUS_MEMORY 61 {STATISTIC_RMEM, top_rmem_create, "MEM"}, 62 {STATISTIC_RPRVT, top_rprvt_create, "RPRVT"}, 63 {STATISTIC_PURG, top_purg_create, "PURG"}, 64 {STATISTIC_COMPRESSED, top_compressed_create, "CMPRS"}, 65#else 66 {STATISTIC_RPRVT, top_rprvt_create, "RPRVT"}, 67 {STATISTIC_RSHRD, top_rshrd_create, "RSHRD"}, 68 {STATISTIC_RSIZE, top_rsize_create, "RSIZE"}, 69#endif 70 {STATISTIC_VSIZE, top_vsize_create, "VSIZE"}, 71 {STATISTIC_VPRVT, top_vprvt_create, "VPRVT"}, 72 {STATISTIC_PGRP, top_pgrp_create, "PGRP"}, 73 {STATISTIC_PPID, top_ppid_create, "PPID"}, 74 {STATISTIC_PSTATE, top_pstate_create, "STATE"}, 75 {STATISTIC_UID, top_uid_create, "UID"}, 76 {STATISTIC_WORKQUEUE, top_workqueue_create, "#WQ"}, 77 {STATISTIC_FAULTS, top_faults_create, "FAULTS"}, 78 {STATISTIC_COW_FAULTS, top_cow_faults_create, "COW"}, 79 {STATISTIC_MESSAGES_SENT, top_messages_sent_create, "MSGSENT"}, 80 {STATISTIC_MESSAGES_RECEIVED, top_messages_received_create, "MSGRECV"}, 81 {STATISTIC_SYSBSD, top_sysbsd_create, "SYSBSD"}, 82 {STATISTIC_SYSMACH, top_sysmach_create, "SYSMACH"}, 83 {STATISTIC_CSW, top_csw_create, "CSW"}, 84 {STATISTIC_PAGEINS, top_pageins_create, "PAGEINS"}, 85 {STATISTIC_KPRVT, top_kprvt_create, "KPRVT"}, 86 {STATISTIC_KSHRD, top_kshrd_create, "KSHRD"}, 87 {STATISTIC_IDLEWAKE, top_idlewake_create, "IDLEW"}, 88 {STATISTIC_POWERSCORE, top_powerscore_create, "POWER"}, 89 {STATISTIC_USER, top_user_create, "USER"}, 90 {0, NULL, NULL} 91}; 92 93static void reset_insertion(struct statistics_controller *c) { 94 struct statistic *s; 95 int i; 96 97 for(i = 0; i < c->get_total_possible(c); ++i) { 98 s = c->state[i].instance; 99 100 if(s) { 101 s->callbacks.reset_insertion(s); 102 } 103 } 104} 105 106static void insert_sample(struct statistics_controller *c, const void *sample) { 107 struct statistic *s; 108 int i; 109 110 for(i = 0; i < c->get_total_possible(c); ++i) { 111 s = c->state[i].instance; 112 113 if(s) { 114 if(s->callbacks.insert_cell(s, sample)) 115 fprintf(stderr, "insert cell failed!\n"); 116 } 117 } 118} 119 120static void remove_tail(struct statistics_controller *c) { 121 int i; 122 123 for(i = c->get_total_possible(c) - 1; i >= 0; --i) { 124 if(c->state[i].instance && c->state[i].instance->visible) { 125 c->state[i].instance->visible = false; 126 hide_panel(c->state[i].instance->panel); 127 c->total_active_statistics--; 128 return; 129 } 130 } 131} 132 133/* This is used with the controller to insert a statistic. */ 134static void insert_tail(struct statistics_controller *c) { 135 int i; 136 137 for(i = 0; i < c->get_total_possible(c); ++i) { 138 if(c->state[i].instance && !c->state[i].instance->visible) { 139 c->state[i].instance->visible = true; 140 show_panel(c->state[i].instance->panel); 141 top_panel(c->state[i].instance->panel); 142 c->total_active_statistics++; 143 return; 144 } 145 } 146} 147 148static int get_total_possible(struct statistics_controller *c) { 149 return c->total_possible_statistics; 150} 151 152static int get_total_active(struct statistics_controller *c) { 153 return c->total_active_statistics; 154} 155 156static void iterate(struct statistics_controller *c, 157 bool (*func)(struct statistic *, void *), 158 void *ptr) { 159 struct statistic *s; 160 int i; 161 bool log = top_prefs_get_logging_mode(); 162 163 for(i = 0; i < c->get_total_possible(c); ++i) { 164 s = c->state[i].instance; 165 166 if(s && (s->visible || log)) { 167 if(func(s, ptr)) 168 continue; 169 170 break; 171 } 172 } 173} 174 175struct statistics_controller *create_statistics_controller(WINDOW *parent) { 176 struct statistics_controller *c; 177 int i; 178 int total = 0; 179 int *array; 180 181 c = malloc(sizeof *c); 182 if(NULL == c) 183 return NULL; 184 185 c->parent = parent; 186 187 for(i = 0; i < STATISTIC_TOTAL; ++i) { 188 c->state[i].type = i; 189 c->state[i].instance = NULL; 190 c->state[i].create_statistic = NULL; 191 } 192 193 top_prefs_get_stats(&total, &array); 194 195 for(i = 0; i < total; ++i) { 196 c->state[i].type = array[i]; 197 c->state[i].create_statistic = statistic_name_map[array[i]].creator; 198 strcpy(c->state[i].name, statistic_name_map[array[i]].name); 199 } 200 201 c->total_possible_statistics = total; 202 c->total_active_statistics = 0; 203 204 c->reset_insertion = reset_insertion; 205 c->insert_sample = insert_sample; 206 c->remove_tail = remove_tail; 207 c->insert_tail = insert_tail; 208 c->get_total_possible = get_total_possible; 209 c->get_total_active = get_total_active; 210 c->iterate = iterate; 211 212 for(i = 0; i < c->get_total_possible(c); ++i) { 213 c->state[i].instance = 214 c->state[i].create_statistic(c->parent, c->state[i].name); 215 216 if(NULL == c->state[i].instance) { 217 free(c); 218 return NULL; 219 } 220 221 c->state[i].instance->controller = c; 222 } 223 224 return c; 225} 226 227 228/* Return NULL if an error occurred. */ 229struct statistic *create_statistic(int type, WINDOW *parent, void *ptr, 230 struct statistic_callbacks *callbacks, 231 const char *name) { 232 struct statistic *s; 233 bool log = top_prefs_get_logging_mode(); 234 235 s = malloc(sizeof *s); 236 237 if(NULL == s) { 238 perror("malloc in create_statistic"); 239 return NULL; 240 } 241 242 if(!log) { 243 s->parent = parent; 244 s->window = newwin(1, 1, 0, 0); 245 246 if(NULL == s->window) { 247 free(s); 248 return NULL; 249 } 250 251 s->panel = new_panel(s->window); 252 253 if(NULL == s->panel) { 254 delwin(s->window); 255 free(s); 256 return NULL; 257 } 258 } else { 259 s->parent = NULL; 260 s->window = NULL; 261 s->panel = NULL; 262 } 263 264 s->type = type; 265 s->cells = NULL; 266 s->ptr = ptr; 267 s->header = strdup(name); 268 269 if(NULL == s->header) { 270 if(!log) { 271 del_panel(s->panel); 272 delwin(s->window); 273 } 274 275 free(s); 276 return NULL; 277 } 278 279 s->visible = false; 280 281 if(!log) 282 hide_panel(s->panel); 283 284 s->time_consumed = 0; 285 s->runs = 0; 286 287 s->callbacks = *callbacks; 288 s->destructors = NULL; 289 s->request_size.width = 0; 290 s->request_size.height = 0; 291 s->actual_size.width = 0; 292 s->actual_size.height = 0; 293 294 s->minimum_size.width = 1; 295 s->minimum_size.height = 1; 296 297 s->previous = NULL; 298 s->next = NULL; 299 300 return s; 301} 302 303void destroy_statistic(struct statistic *s) { 304 struct statistic_destructor *dtor, *dtornext; 305 306 307 for(dtor = s->destructors; dtor; ) { 308 dtornext = dtor->next; 309 dtor->destructor(s, dtor->ptr); 310 free(dtor); 311 dtor = dtornext; 312 } 313 314 werase(s->window); 315 del_panel(s->panel); 316 delwin(s->window); 317 318 if(s->header) 319 free(s->header); 320 321 free(s); 322} 323 324/* Return true if an error occurred. */ 325bool create_statistic_destructor(struct statistic *s, 326 void (*destructor)(struct statistic *, void *), 327 void *ptr) { 328 struct statistic_destructor *dtor; 329 330 dtor = malloc(sizeof *dtor); 331 if(NULL == dtor) { 332 perror("malloc in create_statistic_destructor"); 333 return true; 334 } 335 336 dtor->destructor = destructor; 337 dtor->ptr = ptr; 338 dtor->next = s->destructors; 339 340 s->destructors = dtor; 341 342 return false; 343} 344