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_CPU_ME, top_cpu_me_create, "%CPU_ME"}, 57 {STATISTIC_CPU_OTHERS, top_cpu_others_create, "%CPU_OTHRS"}, 58 {STATISTIC_BOOSTS, top_boosts_create, "BOOSTS"}, 59 {STATISTIC_TIME, top_time_create, "TIME"}, 60 {STATISTIC_THREADS, top_threadcount_create, "#TH"}, 61 {STATISTIC_PORTS, top_ports_create, "#PORTS"}, 62 {STATISTIC_MREGION, top_mregion_create, "#MREGS"}, 63#ifdef TOP_ANONYMOUS_MEMORY 64 {STATISTIC_RMEM, top_rmem_create, "MEM"}, 65 {STATISTIC_RPRVT, top_rprvt_create, "RPRVT"}, 66 {STATISTIC_PURG, top_purg_create, "PURG"}, 67 {STATISTIC_COMPRESSED, top_compressed_create, "CMPRS"}, 68#else 69 {STATISTIC_RPRVT, top_rprvt_create, "RPRVT"}, 70 {STATISTIC_RSHRD, top_rshrd_create, "RSHRD"}, 71 {STATISTIC_RSIZE, top_rsize_create, "RSIZE"}, 72#endif 73 {STATISTIC_VSIZE, top_vsize_create, "VSIZE"}, 74 {STATISTIC_VPRVT, top_vprvt_create, "VPRVT"}, 75 {STATISTIC_PGRP, top_pgrp_create, "PGRP"}, 76 {STATISTIC_PPID, top_ppid_create, "PPID"}, 77 {STATISTIC_PSTATE, top_pstate_create, "STATE"}, 78 {STATISTIC_UID, top_uid_create, "UID"}, 79 {STATISTIC_WORKQUEUE, top_workqueue_create, "#WQ"}, 80 {STATISTIC_FAULTS, top_faults_create, "FAULTS"}, 81 {STATISTIC_COW_FAULTS, top_cow_faults_create, "COW"}, 82 {STATISTIC_MESSAGES_SENT, top_messages_sent_create, "MSGSENT"}, 83 {STATISTIC_MESSAGES_RECEIVED, top_messages_received_create, "MSGRECV"}, 84 {STATISTIC_SYSBSD, top_sysbsd_create, "SYSBSD"}, 85 {STATISTIC_SYSMACH, top_sysmach_create, "SYSMACH"}, 86 {STATISTIC_CSW, top_csw_create, "CSW"}, 87 {STATISTIC_PAGEINS, top_pageins_create, "PAGEINS"}, 88 {STATISTIC_KPRVT, top_kprvt_create, "KPRVT"}, 89 {STATISTIC_KSHRD, top_kshrd_create, "KSHRD"}, 90 {STATISTIC_IDLEWAKE, top_idlewake_create, "IDLEW"}, 91 {STATISTIC_POWERSCORE, top_powerscore_create, "POWER"}, 92 {STATISTIC_USER, top_user_create, "USER"}, 93 {0, NULL, NULL} 94}; 95 96static void reset_insertion(struct statistics_controller *c) { 97 struct statistic *s; 98 int i; 99 100 for(i = 0; i < c->get_total_possible(c); ++i) { 101 s = c->state[i].instance; 102 103 if(s) { 104 s->callbacks.reset_insertion(s); 105 } 106 } 107} 108 109static void insert_sample(struct statistics_controller *c, const void *sample) { 110 struct statistic *s; 111 int i; 112 113 for(i = 0; i < c->get_total_possible(c); ++i) { 114 s = c->state[i].instance; 115 116 if(s) { 117 if(s->callbacks.insert_cell(s, sample)) 118 fprintf(stderr, "insert cell failed!\n"); 119 } 120 } 121} 122 123static void remove_tail(struct statistics_controller *c) { 124 int i; 125 126 for(i = c->get_total_possible(c) - 1; i >= 0; --i) { 127 if(c->state[i].instance && c->state[i].instance->visible) { 128 c->state[i].instance->visible = false; 129 hide_panel(c->state[i].instance->panel); 130 c->total_active_statistics--; 131 return; 132 } 133 } 134} 135 136/* This is used with the controller to insert a statistic. */ 137static void insert_tail(struct statistics_controller *c) { 138 int i; 139 140 for(i = 0; i < c->get_total_possible(c); ++i) { 141 if(c->state[i].instance && !c->state[i].instance->visible) { 142 c->state[i].instance->visible = true; 143 show_panel(c->state[i].instance->panel); 144 top_panel(c->state[i].instance->panel); 145 c->total_active_statistics++; 146 return; 147 } 148 } 149} 150 151static int get_total_possible(struct statistics_controller *c) { 152 return c->total_possible_statistics; 153} 154 155static int get_total_active(struct statistics_controller *c) { 156 return c->total_active_statistics; 157} 158 159static void iterate(struct statistics_controller *c, 160 bool (*func)(struct statistic *, void *), 161 void *ptr) { 162 struct statistic *s; 163 int i; 164 bool log = top_prefs_get_logging_mode(); 165 166 for(i = 0; i < c->get_total_possible(c); ++i) { 167 s = c->state[i].instance; 168 169 if(s && (s->visible || log)) { 170 if(func(s, ptr)) 171 continue; 172 173 break; 174 } 175 } 176} 177 178struct statistics_controller *create_statistics_controller(WINDOW *parent) { 179 struct statistics_controller *c; 180 int i; 181 int total = 0; 182 int *array; 183 184 c = malloc(sizeof *c); 185 if(NULL == c) 186 return NULL; 187 188 c->parent = parent; 189 190 for(i = 0; i < STATISTIC_TOTAL; ++i) { 191 c->state[i].type = i; 192 c->state[i].instance = NULL; 193 c->state[i].create_statistic = NULL; 194 } 195 196 top_prefs_get_stats(&total, &array); 197 198 for(i = 0; i < total; ++i) { 199 c->state[i].type = array[i]; 200 c->state[i].create_statistic = statistic_name_map[array[i]].creator; 201 strcpy(c->state[i].name, statistic_name_map[array[i]].name); 202 } 203 204 c->total_possible_statistics = total; 205 c->total_active_statistics = 0; 206 207 c->reset_insertion = reset_insertion; 208 c->insert_sample = insert_sample; 209 c->remove_tail = remove_tail; 210 c->insert_tail = insert_tail; 211 c->get_total_possible = get_total_possible; 212 c->get_total_active = get_total_active; 213 c->iterate = iterate; 214 215 for(i = 0; i < c->get_total_possible(c); ++i) { 216 c->state[i].instance = 217 c->state[i].create_statistic(c->parent, c->state[i].name); 218 219 if(NULL == c->state[i].instance) { 220 free(c); 221 return NULL; 222 } 223 224 c->state[i].instance->controller = c; 225 } 226 227 return c; 228} 229 230 231/* Return NULL if an error occurred. */ 232struct statistic *create_statistic(int type, WINDOW *parent, void *ptr, 233 struct statistic_callbacks *callbacks, 234 const char *name) { 235 struct statistic *s; 236 bool log = top_prefs_get_logging_mode(); 237 238 s = malloc(sizeof *s); 239 240 if(NULL == s) { 241 perror("malloc in create_statistic"); 242 return NULL; 243 } 244 245 if(!log) { 246 s->parent = parent; 247 s->window = newwin(1, 1, 0, 0); 248 249 if(NULL == s->window) { 250 free(s); 251 return NULL; 252 } 253 254 s->panel = new_panel(s->window); 255 256 if(NULL == s->panel) { 257 delwin(s->window); 258 free(s); 259 return NULL; 260 } 261 } else { 262 s->parent = NULL; 263 s->window = NULL; 264 s->panel = NULL; 265 } 266 267 s->type = type; 268 s->cells = NULL; 269 s->ptr = ptr; 270 s->header = strdup(name); 271 272 if(NULL == s->header) { 273 if(!log) { 274 del_panel(s->panel); 275 delwin(s->window); 276 } 277 278 free(s); 279 return NULL; 280 } 281 282 s->visible = false; 283 284 if(!log) 285 hide_panel(s->panel); 286 287 s->time_consumed = 0; 288 s->runs = 0; 289 290 s->callbacks = *callbacks; 291 s->destructors = NULL; 292 s->request_size.width = 0; 293 s->request_size.height = 0; 294 s->actual_size.width = 0; 295 s->actual_size.height = 0; 296 297 s->minimum_size.width = 1; 298 s->minimum_size.height = 1; 299 300 s->previous = NULL; 301 s->next = NULL; 302 303 return s; 304} 305 306void destroy_statistic(struct statistic *s) { 307 struct statistic_destructor *dtor, *dtornext; 308 309 310 for(dtor = s->destructors; dtor; ) { 311 dtornext = dtor->next; 312 dtor->destructor(s, dtor->ptr); 313 free(dtor); 314 dtor = dtornext; 315 } 316 317 werase(s->window); 318 del_panel(s->panel); 319 delwin(s->window); 320 321 if(s->header) 322 free(s->header); 323 324 free(s); 325} 326 327/* Return true if an error occurred. */ 328bool create_statistic_destructor(struct statistic *s, 329 void (*destructor)(struct statistic *, void *), 330 void *ptr) { 331 struct statistic_destructor *dtor; 332 333 dtor = malloc(sizeof *dtor); 334 if(NULL == dtor) { 335 perror("malloc in create_statistic_destructor"); 336 return true; 337 } 338 339 dtor->destructor = destructor; 340 dtor->ptr = ptr; 341 dtor->next = s->destructors; 342 343 s->destructors = dtor; 344 345 return false; 346} 347