1/* 2 * Copyright (c) 2002-2004, 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 <sys/time.h> 25#include <mach/mach_time.h> 26#include "libtop.h" 27#include "cpu.h" 28#include "generic.h" 29#include "preferences.h" 30#include "log.h" 31#include "uinteger.h" 32 33extern const libtop_tsamp_t *tsamp; 34extern mach_timebase_info_data_t timebase_info; 35 36static bool cpu_insert_cell(struct statistic *s, const void *sample) { 37 const libtop_psamp_t *psamp = sample; 38 struct timeval elapsed, used; 39 char buf[10]; 40 unsigned long long elapsed_us = 0, used_us = 0; 41 int whole = 0, part = 0; 42 43 if(0 == psamp->p_seq) { 44 whole = 0; 45 part = 0; 46 47 if(-1 == snprintf(buf, sizeof(buf), "%d.%1d", whole, part)) 48 return true; 49 50 return generic_insert_cell(s, buf); 51 } 52 53 54 switch(top_prefs_get_mode()) { 55 case STATMODE_ACCUM: 56 timersub(&tsamp->time, &tsamp->b_time, &elapsed); 57 timersub(&psamp->total_time, &psamp->b_total_time, &used); 58 break; 59 60 61 case STATMODE_EVENT: 62 case STATMODE_DELTA: 63 case STATMODE_NON_EVENT: 64 timersub(&tsamp->time, &tsamp->p_time, &elapsed); 65 timersub(&psamp->total_time, &psamp->p_total_time, &used); 66 break; 67 68 default: 69 fprintf(stderr, "unhandled STATMOMDE in %s\n", __func__); 70 abort(); 71 } 72 73 elapsed_us = (unsigned long long)elapsed.tv_sec * 1000000ULL 74 + (unsigned long long)elapsed.tv_usec; 75 76 used_us = (unsigned long long)used.tv_sec * 1000000ULL 77 + (unsigned long long)used.tv_usec; 78 79 /* Avoid a divide by 0 exception. */ 80 if(elapsed_us > 0) { 81 whole = (used_us * 100ULL) / elapsed_us; 82 part = (((used_us * 100ULL) - (whole * elapsed_us)) * 10ULL) / elapsed_us; 83 } 84 85 //top_log("command %s whole %d part %d\n", psamp->command, whole, part); 86 87 if(-1 == snprintf(buf, sizeof(buf), "%d.%1d", whole, part)) 88 return true; 89 90 return generic_insert_cell(s, buf); 91} 92 93static struct statistic_callbacks callbacks = { 94 .draw = generic_draw, 95 .resize_cells = generic_resize_cells, 96 .move_cells = generic_move_cells, 97 .get_request_size = generic_get_request_size, 98 .get_minimum_size = generic_get_minimum_size, 99 .insert_cell = cpu_insert_cell, 100 .reset_insertion = generic_reset_insertion 101}; 102 103struct statistic *top_cpu_create(WINDOW *parent, const char *name) { 104 return create_statistic(STATISTIC_CPU, parent, NULL, &callbacks, name); 105} 106 107 108static bool cpu_me_insert_cell(struct statistic *s, const void *sample) { 109 110 const libtop_psamp_t *psamp = sample; 111 struct timeval elapsed; 112 char buf[10]; 113 unsigned long long elapsed_ns = 0, used_ns = 0; 114 115 if(0 == psamp->p_seq) { 116 117 if(-1 == snprintf(buf, sizeof(buf), "%7.5f", 0)) 118 return true; 119 120 return generic_insert_cell(s, buf); 121 } 122 123 switch(top_prefs_get_mode()) { 124 case STATMODE_ACCUM: 125 timersub(&tsamp->time, &tsamp->b_time, &elapsed); 126 used_ns = psamp->cpu_billed_to_me - psamp->b_cpu_billed_to_me; 127 break; 128 129 130 case STATMODE_EVENT: 131 case STATMODE_DELTA: 132 case STATMODE_NON_EVENT: 133 timersub(&tsamp->time, &tsamp->p_time, &elapsed); 134 used_ns = psamp->cpu_billed_to_me - psamp->p_cpu_billed_to_me; 135 break; 136 137 default: 138 fprintf(stderr, "unhandled STATMOMDE in %s\n", __func__); 139 abort(); 140 } 141 142 used_ns = used_ns * timebase_info.numer / timebase_info.denom; 143 144 elapsed_ns = (unsigned long long)elapsed.tv_sec * 1000000000ULL 145 + (unsigned long long)elapsed.tv_usec* 1000ULL; 146 147 //top_log("command %s whole %d part %d\n", psamp->command, whole, part); 148 149 if(-1 == snprintf(buf, sizeof(buf), "%7.5f", (((float)used_ns * 100) / (float)elapsed_ns))) 150 return true; 151 152 return generic_insert_cell(s, buf); 153} 154 155static void cpu_me_get_minimum_size(struct statistic *s) { 156 s->minimum_size.width = 7; 157 s->minimum_size.height = 1; 158} 159 160static struct statistic_callbacks callbacks1 = { 161 .draw = generic_draw, 162 .resize_cells = generic_resize_cells, 163 .move_cells = generic_move_cells, 164 .get_request_size = generic_get_request_size, 165 .get_minimum_size = cpu_me_get_minimum_size, 166 .insert_cell = cpu_me_insert_cell, 167 .reset_insertion = generic_reset_insertion 168}; 169 170struct statistic *top_cpu_me_create(WINDOW *parent, const char *name) { 171 return create_statistic(STATISTIC_CPU_ME, parent, NULL, &callbacks1, name); 172} 173 174static bool cpu_others_insert_cell(struct statistic *s, const void *sample) { 175 176 const libtop_psamp_t *psamp = sample; 177 struct timeval elapsed; 178 char buf[10]; 179 unsigned long long elapsed_ns = 0, used_ns = 0; 180 181 if(0 == psamp->p_seq) { 182 183 if(-1 == snprintf(buf, sizeof(buf), "%7.5f", 0)) 184 return true; 185 186 return generic_insert_cell(s, buf); 187 } 188 189 190 switch(top_prefs_get_mode()) { 191 case STATMODE_ACCUM: 192 timersub(&tsamp->time, &tsamp->b_time, &elapsed); 193 used_ns = psamp->cpu_billed_to_others - psamp->b_cpu_billed_to_others; 194 break; 195 196 197 case STATMODE_EVENT: 198 case STATMODE_DELTA: 199 case STATMODE_NON_EVENT: 200 timersub(&tsamp->time, &tsamp->p_time, &elapsed); 201 used_ns = psamp->cpu_billed_to_others - psamp->p_cpu_billed_to_others; 202 break; 203 204 default: 205 fprintf(stderr, "unhandled STATMOMDE in %s\n", __func__); 206 abort(); 207 } 208 209 used_ns = used_ns * timebase_info.numer / timebase_info.denom; 210 211 elapsed_ns = (unsigned long long)elapsed.tv_sec * 1000000000ULL 212 + (unsigned long long)elapsed.tv_usec * 1000ULL; 213 214 //top_log("command %s whole %d part %d\n", psamp->command, whole, part); 215 216 if(-1 == snprintf(buf, sizeof(buf), "%7.5f", (((float)used_ns * 100) / (float)elapsed_ns))) 217 return true; 218 219 return generic_insert_cell(s, buf); 220} 221 222static void cpu_others_get_minimum_size(struct statistic *s) { 223 s->minimum_size.width =10 ; 224 s->minimum_size.height = 1; 225} 226 227static struct statistic_callbacks callbacks2 = { 228 .draw = generic_draw, 229 .resize_cells = generic_resize_cells, 230 .move_cells = generic_move_cells, 231 .get_request_size = generic_get_request_size, 232 .get_minimum_size = cpu_others_get_minimum_size, 233 .insert_cell = cpu_others_insert_cell, 234 .reset_insertion = generic_reset_insertion 235}; 236 237struct statistic *top_cpu_others_create(WINDOW *parent, const char *name) { 238 return create_statistic(STATISTIC_CPU_OTHERS, parent, NULL, &callbacks2, name); 239} 240 241static bool boosts_insert_cell(struct statistic *s, const void *sample) { 242 243 const libtop_psamp_t *psamp = sample; 244 char buf1[GENERIC_INT_SIZE]; 245 char buf2[GENERIC_INT_SIZE]; 246 char buf[GENERIC_INT_SIZE * 2 + 3]; 247 248 if (top_uinteger_format_result(buf1, sizeof(buf1), 249 psamp->assertcnt, psamp->p_assertcnt, 250 psamp->b_assertcnt)) { 251 return true; 252 } 253 if (top_uinteger_format_result(buf2, sizeof(buf2), 254 psamp->boosts, psamp->p_boosts, 255 psamp->b_boosts)) { 256 return true; 257 } 258 sprintf(buf, "%c%s[%s]", ((psamp->boost_donating) ? '*' : ' '), buf1, buf2); 259 260 return generic_insert_cell(s, buf); 261} 262 263static void boosts_get_minimum_size(struct statistic *s) { 264 generic_get_minimum_size(s); 265 s->minimum_size.width += 4; 266} 267 268static struct statistic_callbacks callbacks3 = { 269 .draw = generic_draw, 270 .resize_cells = generic_resize_cells, 271 .move_cells = generic_move_cells, 272 .get_request_size = generic_get_request_size, 273 .get_minimum_size = boosts_get_minimum_size, 274 .insert_cell = boosts_insert_cell, 275 .reset_insertion = generic_reset_insertion 276}; 277 278struct statistic *top_boosts_create(WINDOW *parent, const char *name) { 279 return create_statistic(STATISTIC_BOOSTS, parent, NULL, &callbacks3, name); 280} 281