1/* 2 * Copyright (c) 2008, 2009 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 <stdio.h> 24#include <stdlib.h> 25#include <string.h> 26#include <assert.h> 27#include <libutil.h> 28#include <inttypes.h> 29#include <panel.h> 30#include <sys/time.h> 31#include <time.h> 32#include <unistd.h> 33 34#include "libtop.h" 35#include "globalstats.h" 36#include "generic.h" 37#include "log.h" 38#include "preferences.h" 39#include "uinteger.h" 40#include "top.h" 41 42enum { 43 GLOBALSTAT_PROCESSES, GLOBALSTAT_TIME, GLOBALSTAT_LOAD, 44 GLOBALSTAT_CPU, GLOBALSTAT_SHAREDLIBS, 45 GLOBALSTAT_MEMREGIONS, GLOBALSTAT_PHYSMEM, 46 GLOBALSTAT_VM, GLOBALSTAT_SWAP, GLOBALSTAT_PURGEABLE, 47 GLOBALSTAT_NETWORKS, GLOBALSTAT_DISKS 48}; 49 50enum { GLOBALSTAT_TOTAL = GLOBALSTAT_DISKS + 1 }; 51 52enum { GLOBALSTAT_HN_FORMAT = HN_NOSPACE | HN_B }; 53 54struct globalstat_size { 55 int width, height; 56}; 57 58struct globalstat { 59 WINDOW *window; 60 PANEL *panel; 61 int type; 62 char data[120]; 63 int length; 64 int x, y; 65 struct globalstat_size size; 66 int max_width; 67}; 68 69struct globalstat_controller { 70 struct globalstat stats[GLOBALSTAT_TOTAL]; 71 WINDOW *window; 72 PANEL *panel; 73}; 74 75/* Return -1 if an error occurred. */ 76static int humanize_globalstat(char *out, size_t s, int64_t n) { 77 return humanize_number(out, s, n, "", HN_AUTOSCALE, GLOBALSTAT_HN_FORMAT); 78} 79 80static bool init_globalstat(WINDOW *parent, struct globalstat *gs, int type) { 81 82 if(!top_prefs_get_logging_mode()) { 83 gs->window = newwin(1, 1, 0, 0); 84 85 if(NULL == gs->window) 86 return true; 87 88 gs->panel = new_panel(gs->window); 89 90 if(NULL == gs->panel) { 91 delwin(gs->window); 92 return true; 93 } 94 } 95 96 gs->type = type; 97 gs->length = 0; 98 gs->x = 0; 99 gs->y = 0; 100 gs->size.width = 0; 101 gs->size.height = 0; 102 gs->max_width = 0; 103 104 return false; 105}; 106 107static void update_max(struct globalstat *gs) { 108 if(gs->length > gs->max_width) { 109 gs->max_width = gs->length; 110 top_relayout_force(); 111 } 112} 113 114static int get_globalstat_reqwidth(struct globalstat *gs) { 115 return gs->length + 1; 116} 117 118static void set_globalstat_geometry(struct globalstat *gs, int x, int y, 119 int width, int height) { 120 gs->x = x; 121 gs->y = y; 122 gs->size.width = width; 123 gs->size.height = height; 124} 125 126void *top_globalstats_create(WINDOW *parent) { 127 struct globalstat_controller *c; 128 int i; 129 130 c = malloc(sizeof *c); 131 132 if(NULL == c) 133 return NULL; 134 135 136 if(!top_prefs_get_logging_mode()) { 137 c->window = newwin(1, 1, 0, 0); 138 139 if(NULL == c->window) { 140 free(c); 141 return NULL; 142 } 143 144 c->panel = new_panel(c->window); 145 146 if(NULL == c->panel) { 147 delwin(c->window); 148 free(c); 149 return NULL; 150 } 151 } else { 152 c->window = NULL; 153 c->panel = NULL; 154 } 155 156 for(i = 0; i < GLOBALSTAT_TOTAL; ++i) { 157 if(GLOBALSTAT_SHAREDLIBS == i && !top_prefs_get_frameworks()) { 158 /* Skip the framework update. */ 159 continue; 160 } 161 162 if(init_globalstat(c->window, c->stats + i, i)) { 163 --i; 164 /* Cleanup the already created windows. */ 165 for(; i >= 0; --i) { 166 if(!top_prefs_get_logging_mode()) 167 delwin(c->stats[i].window); 168 } 169 free(c); 170 return NULL; 171 } 172 } 173 174 return c; 175} 176 177void top_globalstats_draw(void *ptr) { 178 struct globalstat_controller *c = ptr; 179 int i; 180 181 for(i = 0; i < GLOBALSTAT_TOTAL; ++i) { 182 // MWW: Skip the frameworks window if we've got them disabled 183 if (!top_prefs_get_frameworks() && (i == GLOBALSTAT_SHAREDLIBS)) 184 continue; 185 if(strlen(c->stats[i].data)) 186 mvwaddstr(c->stats[i].window, 0, 0, c->stats[i].data); 187 } 188} 189 190static void reset_globalstat(struct globalstat *gs) { 191 gs->data[0] = '\0'; 192 gs->length = 0; 193} 194 195 196static void update_time(struct globalstat *gs, 197 const libtop_tsamp_t *tsamp) { 198 struct timeval tval; 199 struct tm tm; 200 201 gettimeofday(&tval, NULL); 202 localtime_r(&(tval.tv_sec), &tm); 203 204 if(STATMODE_ACCUM == top_prefs_get_mode()) { 205 unsigned int sec, min, hour; 206 207 timersub(&tsamp->time, &tsamp->b_time, &tval); 208 209 sec = tval.tv_sec; 210 min = sec / 60; 211 hour = min / 60; 212 213 gs->length = snprintf(gs->data, sizeof(gs->data), "%u:%02u:%02u", 214 hour, min % 60, sec % 60); 215 216 if(gs->length < 0) { 217 reset_globalstat(gs); 218 return; 219 } 220 } else if(top_prefs_get_logging_mode()) { 221 gs->length = strftime(gs->data, sizeof(gs->data), "%Y/%m/%d %T", &tm); 222 } else { 223 gs->length = strftime(gs->data, sizeof(gs->data), "%T", &tm); 224 } 225 226 if(0 == gs->length) { 227 reset_globalstat(gs); 228 return; 229 } 230 231 update_max(gs); 232} 233 234 235static void update_processes(struct globalstat *gs, 236 const libtop_tsamp_t *tsamp) { 237 int i, offset, chunksize; 238 239 gs->length = snprintf(gs->data, sizeof(gs->data), 240 "Processes: %" PRIu32 " total, ", 241 (uint32_t)tsamp->nprocs); 242 243 if(gs->length <= 0) { 244 reset_globalstat(gs); 245 return; 246 } 247 248 offset = gs->length; 249 250 for (i = 0; i < LIBTOP_NSTATES; ++i) { 251 if(tsamp->state_breakdown[i]) { 252 chunksize = snprintf(gs->data + offset, 253 sizeof(gs->data) - offset, 254 "%d %s, ", 255 tsamp->state_breakdown[i], 256 libtop_state_str(i)); 257 if(chunksize < 0) 258 break; 259 260 offset += chunksize; 261 } 262 } 263 264 gs->length = offset; 265 266 chunksize = snprintf(gs->data + gs->length, 267 sizeof(gs->data) - gs->length, 268 "%" PRIu32 " threads ", tsamp->threads); 269 270 if(chunksize < 0) { 271 reset_globalstat(gs); 272 return; 273 } 274 275 gs->length += chunksize; 276 assert(gs->length <= sizeof(gs->data)); 277 278 update_max(gs); 279} 280 281static void update_load(struct globalstat *gs, const libtop_tsamp_t *tsamp) { 282 gs->length = snprintf(gs->data, sizeof(gs->data), 283 "Load Avg: %.2f, %.2f, %.2f ", 284 tsamp->loadavg[0], tsamp->loadavg[1], 285 tsamp->loadavg[2]); 286 287 if(gs->length < 0) { 288 reset_globalstat(gs); 289 return; 290 } 291 292 update_max(gs); 293} 294 295static void cpu_percent(unsigned long long ticks, unsigned long long totalticks, 296 unsigned long long *whole, unsigned long long *part) { 297 *whole = 100ULL * ticks / totalticks; 298 *part = (((100ULL * ticks) - (*whole * totalticks)) * 100ULL) 299 / totalticks; 300} 301 302static void update_cpu(struct globalstat *gs, const libtop_tsamp_t *tsamp) { 303 unsigned long long userticks, systicks, idleticks, totalticks; 304 int mode; 305 unsigned long long userwhole, userpart, syswhole, syspart, 306 idlewhole, idlepart; 307 308 userticks = tsamp->cpu.cpu_ticks[CPU_STATE_USER] 309 + tsamp->cpu.cpu_ticks[CPU_STATE_NICE]; 310 systicks = tsamp->cpu.cpu_ticks[CPU_STATE_SYSTEM]; 311 idleticks = tsamp->cpu.cpu_ticks[CPU_STATE_IDLE]; 312 313 mode = top_prefs_get_mode(); 314 315 if(STATMODE_ACCUM == mode) { 316 userticks -= (tsamp->b_cpu.cpu_ticks[CPU_STATE_USER] + 317 tsamp->b_cpu.cpu_ticks[CPU_STATE_NICE]); 318 319 systicks -= tsamp->b_cpu.cpu_ticks[CPU_STATE_SYSTEM]; 320 idleticks -= tsamp->b_cpu.cpu_ticks[CPU_STATE_IDLE]; 321 } 322 323 if(STATMODE_DELTA == mode || STATMODE_NON_EVENT == mode) { 324 userticks -= (tsamp->p_cpu.cpu_ticks[CPU_STATE_USER] + 325 tsamp->p_cpu.cpu_ticks[CPU_STATE_NICE]); 326 327 systicks -= tsamp->p_cpu.cpu_ticks[CPU_STATE_SYSTEM]; 328 idleticks -= tsamp->p_cpu.cpu_ticks[CPU_STATE_IDLE]; 329 } 330 331 totalticks = userticks + systicks + idleticks; 332 333 if(0 == totalticks) 334 return; 335 336 337 cpu_percent(userticks, totalticks, &userwhole, &userpart); 338 cpu_percent(systicks, totalticks, &syswhole, &syspart); 339 cpu_percent(idleticks, totalticks, &idlewhole, &idlepart); 340 341 gs->length = snprintf(gs->data, sizeof(gs->data), 342 "CPU usage: " 343 "%" PRIu64 "." "%" PRIu64 "%% user, " 344 "%" PRIu64 "." "%" PRIu64 "%% sys, " 345 "%" PRIu64 "." "%" PRIu64 "%% idle ", 346 userwhole, userpart, 347 syswhole, syspart, 348 idlewhole, idlepart); 349 350 if(gs->length < 0) { 351 reset_globalstat(gs); 352 return; 353 } 354 355 update_max(gs); 356} 357 358 359static void update_sharedlibs(struct globalstat *gs, 360 const libtop_tsamp_t *tsamp) { 361 char code[6]; 362 char data[6]; 363 char linkedit[6]; 364 365 if((-1 == humanize_number(code, sizeof(code), tsamp->fw_code, "", 366 HN_AUTOSCALE, GLOBALSTAT_HN_FORMAT)) 367 || (-1 == humanize_number(data, sizeof(data), tsamp->fw_data, "", 368 HN_AUTOSCALE, GLOBALSTAT_HN_FORMAT)) 369 || (-1 == humanize_number(linkedit, sizeof(linkedit), 370 tsamp->fw_linkedit, "", HN_AUTOSCALE, 371 GLOBALSTAT_HN_FORMAT))) { 372 373 reset_globalstat(gs); 374 return; 375 } 376 377 gs->length = snprintf(gs->data, sizeof(gs->data), 378 "SharedLibs: " 379 "%s resident, " 380 "%s data, " 381 "%s linkedit.", 382 code, 383 data, 384 linkedit); 385 386 if(gs->length < 0) { 387 reset_globalstat(gs); 388 return; 389 } 390 391 update_max(gs); 392} 393 394static void update_memregions(struct globalstat *gs, 395 const libtop_tsamp_t *tsamp) { 396 char resident[6]; 397 char priv[6]; 398 char shared[6]; 399 400 401 402 403 if((-1 == humanize_globalstat(resident, sizeof(resident), tsamp->rprvt)) 404 || (-1 == humanize_globalstat(priv, sizeof(priv), tsamp->fw_private)) 405 || (-1 == humanize_globalstat(shared, sizeof(shared), tsamp->rshrd))) { 406 reset_globalstat(gs); 407 return; 408 } 409 410 gs->length = snprintf(gs->data, sizeof(gs->data), 411 "MemRegions: %" PRIu32 " total, " 412 "%s resident, " 413 "%s private, " 414 "%s shared.", 415 tsamp->reg, 416 resident, 417 priv, 418 shared); 419 if(gs->length < 0) { 420 reset_globalstat(gs); 421 return; 422 } 423 424 update_max(gs); 425} 426 427static void update_physmem(struct globalstat *gs, 428 const libtop_tsamp_t *tsamp) { 429 char wired[6]; 430 char used[6]; 431 char physfree[6]; 432 uint64_t total_free, total_used, total_used_count; 433 struct top_uinteger wiredresult, usedresult, 434 physfreeresult; 435 436 total_free = (uint64_t)tsamp->vm_stat.free_count * tsamp->pagesize; 437 total_used_count = (uint64_t)tsamp->vm_stat.wire_count + tsamp->vm_stat.inactive_count 438 + tsamp->vm_stat.active_count + tsamp->vm_stat.compressor_page_count; 439 total_used = total_used_count * tsamp->pagesize; 440 441 wiredresult = top_init_uinteger(tsamp->vm_stat.wire_count 442 * tsamp->pagesize, false); 443 usedresult = top_init_uinteger(total_used, false); 444 physfreeresult = top_init_uinteger(total_free, false); 445 446 if(top_humanize_uinteger(wired, sizeof(wired), wiredresult) 447 || top_humanize_uinteger(used, sizeof(used), usedresult) 448 || top_humanize_uinteger(physfree, sizeof(physfree), physfreeresult)) { 449 fprintf(stderr, "top_humanize_uinteger failure in %s\n", __func__); 450 reset_globalstat(gs); 451 return; 452 } 453 454 gs->length = snprintf(gs->data, sizeof(gs->data), 455 "PhysMem: " 456 "%s used (%s wired), " 457 "%s unused.", 458 used, wired, 459 physfree); 460 461 if(gs->length < 0) { 462 reset_globalstat(gs); 463 return; 464 } 465 466 update_max(gs); 467} 468 469static void update_vm(struct globalstat *gs, 470 const libtop_tsamp_t *tsamp) { 471 char vsize[6]; 472 char fwvsize[6]; 473 struct top_uinteger vsize_result, fw_vsize_result; 474 475 vsize_result = top_init_uinteger(tsamp->vsize, false); 476 fw_vsize_result = top_init_uinteger(tsamp->fw_vsize, false); 477 478 if(top_humanize_uinteger(vsize, sizeof(vsize), vsize_result)) 479 return; 480 481 if(top_humanize_uinteger(fwvsize, sizeof(fwvsize), fw_vsize_result)) 482 return; 483 484 gs->length = snprintf(gs->data, sizeof(gs->data), 485 "VM: " 486 "%s vsize, " 487 "%s framework vsize, " 488 "%" PRIu64 "(%" PRIu64 ") swapins, " 489 "%" PRIu64 "(%" PRIu64 ") swapouts.", 490 vsize, 491 fwvsize, 492 (unsigned long long)tsamp->vm_stat.swapins, 493 (unsigned long long)(tsamp->vm_stat.swapins 494 - tsamp->p_vm_stat.swapins), 495 (unsigned long long)tsamp->vm_stat.swapouts, 496 (unsigned long long)(tsamp->vm_stat.swapouts 497 - tsamp->p_vm_stat.swapouts)); 498 499 if(gs->length < 0) { 500 reset_globalstat(gs); 501 return; 502 } 503 504 update_max(gs); 505} 506 507static void update_swap(struct globalstat *gs, 508 const libtop_tsamp_t *tsamp) { 509 struct top_uinteger used_result, available_result; 510 char used[6]; 511 char avail[6]; 512 513 if(!tsamp->xsu_is_valid) { 514 gs->length = snprintf(gs->data, sizeof(gs->data), 515 "Swap: N/A"); 516 517 if(gs->length < 0) 518 reset_globalstat(gs); 519 520 return; 521 } 522 523 /*FIXME a p_xsu added to libtop for delta mode would be nice.*/ 524 used_result = top_init_uinteger(tsamp->xsu.xsu_used, false); 525 available_result = top_init_uinteger(tsamp->xsu.xsu_avail, false); 526 527 if(top_humanize_uinteger(used, sizeof(used), used_result) 528 || top_humanize_uinteger(avail, sizeof(avail), available_result)) { 529 reset_globalstat(gs); 530 return; 531 } 532 533 gs->length = snprintf(gs->data, sizeof(gs->data), 534 "Swap: %s + %s free.", used, avail); 535 536 if(gs->length < 0) 537 reset_globalstat(gs); 538 539 update_max(gs); 540} 541 542static void update_purgeable(struct globalstat *gs, 543 const libtop_tsamp_t *tsamp) { 544 struct top_uinteger purgeable_result, purges_result, prev_purges, 545 purges_delta; 546 char purgeable[6]; 547 char purges[6]; 548 char pdelta[6]; 549 uint64_t purgeable_mem; 550 551 if(!tsamp->purgeable_is_valid) { 552 gs->length = snprintf(gs->data, sizeof(gs->data), 553 "Purgeable: N/A"); 554 555 if(gs->length < 0) 556 reset_globalstat(gs); 557 558 return; 559 } 560 561 purgeable_mem = tsamp->vm_stat.purgeable_count * tsamp->pagesize; 562 563 purgeable_result = top_init_uinteger(purgeable_mem, false); 564 purges_result = top_init_uinteger(tsamp->vm_stat.purges, false); 565 prev_purges = top_init_uinteger(tsamp->p_vm_stat.purges, false); 566 purges_delta = top_sub_uinteger(&purges_result, &prev_purges); 567 568 if(top_humanize_uinteger(purgeable, sizeof(purgeable), purgeable_result) 569 || top_sprint_uinteger(purges, sizeof(purges), purges_result) 570 || top_sprint_uinteger(pdelta, sizeof(pdelta), purges_delta)) { 571 reset_globalstat(gs); 572 return; 573 } 574 575 gs->length = snprintf(gs->data, sizeof(gs->data), 576 "Purgeable: %s %s(%s) pages purged.", 577 purgeable, purges, 578 pdelta); 579 580 if(gs->length < 0) 581 reset_globalstat(gs); 582 583 update_max(gs); 584} 585 586/* Return true if an error occurred. */ 587static bool update_networks(struct globalstat *gs, 588 const libtop_tsamp_t *tsamp) { 589 struct top_uinteger inp, outp, inbytes, outbytes; 590 char inpbuf[GENERIC_INT_SIZE]; 591 char outpbuf[GENERIC_INT_SIZE]; 592 char inbytesbuf[6]; 593 char outbytesbuf[6]; 594 595 inp = top_init_uinteger(tsamp->net_ipackets, false); 596 outp = top_init_uinteger(tsamp->net_opackets, false); 597 598 inbytes = top_init_uinteger(tsamp->net_ibytes, false); 599 outbytes = top_init_uinteger(tsamp->net_obytes, false); 600 601 switch(top_prefs_get_mode()) { 602 case STATMODE_ACCUM: { 603 /* The changes that occurred since the beginning sample. */ 604 struct top_uinteger binp, boutp, binbytes, boutbytes; 605 606 binp = top_init_uinteger(tsamp->b_net_ipackets, false); 607 boutp = top_init_uinteger(tsamp->b_net_opackets, false); 608 binbytes = top_init_uinteger(tsamp->b_net_ibytes, false); 609 boutbytes = top_init_uinteger(tsamp->b_net_obytes, false); 610 611 inp = top_sub_uinteger(&inp, &binp); 612 outp = top_sub_uinteger(&outp, &boutp); 613 614 inbytes = top_sub_uinteger(&inbytes, &binbytes); 615 outbytes = top_sub_uinteger(&outbytes, &boutbytes); 616 } 617 break; 618 619 case STATMODE_DELTA: { 620 /* The changes that occurred since the previous sample. */ 621 struct top_uinteger pinp, poutp, pinbytes, poutbytes; 622 623 pinp = top_init_uinteger(tsamp->p_net_ipackets, false); 624 poutp = top_init_uinteger(tsamp->p_net_opackets, false); 625 pinbytes = top_init_uinteger(tsamp->p_net_ibytes, false); 626 poutbytes = top_init_uinteger(tsamp->p_net_obytes, false); 627 628 inp = top_sub_uinteger(&inp, &pinp); 629 outp = top_sub_uinteger(&outp, &poutp); 630 631 inbytes = top_sub_uinteger(&inbytes, &pinbytes); 632 outbytes = top_sub_uinteger(&outbytes, &poutbytes); 633 } 634 break; 635 } 636 637 if(top_sprint_uinteger(inpbuf, sizeof(inpbuf), inp)) 638 return true; 639 640 if(top_sprint_uinteger(outpbuf, sizeof(outpbuf), outp)) 641 return true; 642 643 if(top_humanize_uinteger(inbytesbuf, sizeof(inbytesbuf), inbytes)) 644 return true; 645 646 if(top_humanize_uinteger(outbytesbuf, sizeof(outbytesbuf), outbytes)) 647 return true; 648 649 gs->length = snprintf(gs->data, sizeof(gs->data), 650 "Networks: " 651 "packets: " 652 "%s/%s in, " 653 "%s/%s out.", 654 inpbuf, inbytesbuf, 655 outpbuf, outbytesbuf); 656 if(-1 == gs->length) { 657 reset_globalstat(gs); 658 return true; 659 } 660 661 update_max(gs); 662 663 return false; 664} 665 666/* Return true if an error ocurred. */ 667static bool update_disks(struct globalstat *gs, const libtop_tsamp_t *tsamp) { 668 char rbuf[GENERIC_INT_SIZE]; 669 char wbuf[GENERIC_INT_SIZE]; 670 char rsizebuf[6]; 671 char wsizebuf[6]; 672 struct top_uinteger rops, wops, rbytes, wbytes; 673 674 rops = top_init_uinteger(tsamp->disk_rops, false); 675 wops = top_init_uinteger(tsamp->disk_wops, false); 676 rbytes = top_init_uinteger(tsamp->disk_rbytes, false); 677 wbytes = top_init_uinteger(tsamp->disk_wbytes, false); 678 679 switch(top_prefs_get_mode()) { 680 case STATMODE_ACCUM: { 681 struct top_uinteger brops, bwops, brbytes, bwbytes; 682 683 brops = top_init_uinteger(tsamp->b_disk_rops, false); 684 bwops = top_init_uinteger(tsamp->b_disk_wops, false); 685 brbytes = top_init_uinteger(tsamp->b_disk_rbytes, false); 686 bwbytes = top_init_uinteger(tsamp->b_disk_wbytes, false); 687 688 rops = top_sub_uinteger(&rops, &brops); 689 wops = top_sub_uinteger(&wops, &bwops); 690 rbytes = top_sub_uinteger(&rbytes, &brbytes); 691 wbytes = top_sub_uinteger(&wbytes, &bwbytes); 692 } 693 break; 694 695 case STATMODE_DELTA: { 696 struct top_uinteger props, pwops, prbytes, pwbytes; 697 698 props = top_init_uinteger(tsamp->p_disk_rops, false); 699 pwops = top_init_uinteger(tsamp->p_disk_wops, false); 700 prbytes = top_init_uinteger(tsamp->p_disk_rbytes, false); 701 pwbytes = top_init_uinteger(tsamp->p_disk_wbytes, false); 702 703 rops = top_sub_uinteger(&rops, &props); 704 wops = top_sub_uinteger(&wops, &pwops); 705 rbytes = top_sub_uinteger(&rbytes, &prbytes); 706 wbytes = top_sub_uinteger(&wbytes, &pwbytes); 707 } 708 break; 709 } 710 711 if(top_sprint_uinteger(rbuf, sizeof(rbuf), rops)) 712 return true; 713 714 if(top_sprint_uinteger(wbuf, sizeof(wbuf), wops)) 715 return true; 716 717 if(top_humanize_uinteger(rsizebuf, sizeof(rsizebuf), rbytes)) 718 return true; 719 720 if(top_humanize_uinteger(wsizebuf, sizeof(wsizebuf), wbytes)) 721 return true; 722 723 gs->length = snprintf(gs->data, sizeof(gs->data), 724 "Disks: " 725 "%s/%s read, " 726 "%s/%s written.", 727 rbuf, rsizebuf, 728 wbuf, wsizebuf); 729 730 if(-1 == gs->length) { 731 reset_globalstat(gs); 732 return true; 733 } 734 735 update_max(gs); 736 737 return false; 738} 739 740bool top_globalstats_update(void *ptr, const void *sample) { 741 const libtop_tsamp_t *tsamp = sample; 742 struct globalstat_controller *c = ptr; 743 int i; 744 745 if (!top_prefs_get_logging_mode()) { 746 for(i = 0; i < GLOBALSTAT_TOTAL; ++i) { 747 // MWW: If we've disabled framework logging one of these windows isn't valid and needs skipping 748 if (!top_prefs_get_frameworks() && (i == GLOBALSTAT_SHAREDLIBS)) continue; 749 werase(c->stats[i].window); 750 } 751 } 752 753 update_processes(c->stats + GLOBALSTAT_PROCESSES, tsamp); 754 update_load(c->stats + GLOBALSTAT_LOAD, tsamp); 755 update_cpu(c->stats + GLOBALSTAT_CPU, tsamp); 756 757 if(top_prefs_get_frameworks()) 758 update_sharedlibs(c->stats + GLOBALSTAT_SHAREDLIBS, tsamp); 759 760 update_memregions(c->stats + GLOBALSTAT_MEMREGIONS, tsamp); 761 update_physmem(c->stats + GLOBALSTAT_PHYSMEM, tsamp); 762 update_vm(c->stats + GLOBALSTAT_VM, tsamp); 763 update_time(c->stats + GLOBALSTAT_TIME, tsamp); 764 765 if(top_prefs_get_swap()) { 766 update_swap(c->stats + GLOBALSTAT_SWAP, tsamp); 767 update_purgeable(c->stats + GLOBALSTAT_PURGEABLE, tsamp); 768 } 769 770 if(update_networks(c->stats + GLOBALSTAT_NETWORKS, tsamp)) 771 top_log("An error occurred while updating the network global stats.\n"); 772 773 if(update_disks(c->stats + GLOBALSTAT_DISKS, tsamp)) 774 top_log("An erorr occurred while updating the disk global stats.\n"); 775 776 return false; 777} 778 779static bool skip_globalstat(int i) { 780 if((GLOBALSTAT_SHAREDLIBS == i && !top_prefs_get_frameworks()) 781 || (GLOBALSTAT_SWAP == i && !top_prefs_get_swap()) 782 || (GLOBALSTAT_PURGEABLE == i && !top_prefs_get_swap())) { 783 return true; 784 } 785 786 return false; 787} 788 789static void setup_globalstats_geometry(struct globalstat_controller *c, 790 int availwidth, int availheight, 791 int *outheight) { 792 struct globalstat *gs; 793 int i; 794 int remaining = availwidth; 795 int gswidth; 796 int x = 0; 797 int y = 0; 798 799 *outheight = 0; 800 801 /* First place the Processes in the upper left. */ 802 gs = c->stats + GLOBALSTAT_PROCESSES; 803 804 gswidth = get_globalstat_reqwidth(gs); 805 806 if(gswidth > availwidth) 807 gswidth = availwidth; 808 809 set_globalstat_geometry(gs, x, y, gswidth, /*height*/ 1); 810 811 remaining -= gswidth; 812 x += gswidth; 813 814 /* 815 * Place the time in the upper right, or if it doesn't fit, 816 * down 1 column, on the left. 817 */ 818 gs = c->stats + GLOBALSTAT_TIME; 819 820 gswidth = get_globalstat_reqwidth(gs); 821 822 if(gswidth > availwidth) 823 gswidth = availwidth; 824 825 if(remaining >= gswidth) { 826 /* There is enough room on the first row for the time. */ 827 set_globalstat_geometry(gs, availwidth - gswidth, y, 828 gswidth, /*height*/ 1); 829 830 /* Go down a row. */ 831 ++y; 832 /* Reset the x to the left most. */ 833 x = 0; 834 remaining = availwidth; 835 } else { 836 /* Move the time down a row. */ 837 ++y; 838 x = 0; 839 remaining = availwidth; 840 841 set_globalstat_geometry(gs, x, y, gswidth, 842 /*height*/ 1); 843 x += gswidth; 844 remaining -= gswidth; 845 } 846 847 for(i = GLOBALSTAT_LOAD; i < GLOBALSTAT_TOTAL; ++i) { 848 if(skip_globalstat(i)) { 849 /* Skip the updates for these. */ 850 continue; 851 } 852 853 gs = c->stats + i; 854 855 gswidth = get_globalstat_reqwidth(gs); 856 857 if(gswidth > availwidth) 858 gswidth = availwidth; 859 860 /* Is the space remaining less than the total globalstat width? */ 861 if(remaining < gswidth) { 862 /* Reset the remaining width. */ 863 ++y; 864 x = 0; 865 remaining = availwidth; 866 } 867 868 set_globalstat_geometry(gs, x, y, gswidth, /*height*/ 1); 869 remaining -= gswidth; 870 x += gswidth; 871 } 872 873 if(remaining != availwidth) 874 ++y; 875 876 *outheight = y; 877} 878 879bool top_globalstats_resize(void *ptr, int width, int height, 880 int *consumed_height) { 881 struct globalstat_controller *c = ptr; 882 int i; 883 884 top_log("%s\n", __func__); 885 886 *consumed_height = 0; 887 888 setup_globalstats_geometry(c, width, height, consumed_height); 889 890 if(ERR == wresize(c->window, *consumed_height, width)) { 891 top_log("wresize error: height %d width %d\n", 892 *consumed_height, width); 893 return true; 894 } 895 896 if(ERR == move_panel(c->panel, 0, 0)) { 897 top_log("move_panel error: 0 0\n"); 898 return true; 899 } 900 901 for(i = 0; i < GLOBALSTAT_TOTAL; ++i) { 902 struct globalstat *gs = c->stats + i; 903 904 // MWW: Skip the frameworks window if we've got them disabled 905 if (!top_prefs_get_frameworks() && (i == GLOBALSTAT_SHAREDLIBS)) continue; 906 907 if(skip_globalstat(i)) { 908 /* Skip and hide the panels for these. */ 909 hide_panel(gs->panel); 910 continue; 911 } 912 913 gs = c->stats + i; 914 915 /* 916 * Avoid errors below by resizing and moving the panel to a known 917 * good size/offfset. 918 */ 919 wresize(gs->window, 1, 1); 920 move_panel(gs->panel, 0, 0); 921 922 if(ERR == move_panel(gs->panel, gs->y, gs->x)) 923 return true; 924 925 if(ERR == wresize(gs->window, gs->size.height, gs->size.width)) 926 return true; 927 928 if(ERR == werase(gs->window)) 929 return true; 930 } 931 932 return false; 933} 934 935 936void top_globalstats_iterate(void *ptr, bool (*iter)(char *, void *), 937 void *dataptr) { 938 struct globalstat_controller *c = ptr; 939 int i; 940 941 for(i = 0; i < GLOBALSTAT_TOTAL; ++i) { 942 if(skip_globalstat(i)) 943 continue; 944 945 if(c->stats[i].length > 0) { 946 if(!iter(c->stats[i].data, dataptr)) 947 break; 948 } 949 } 950} 951 952void top_globalstats_reset(void *ptr) { 953 struct globalstat_controller *c = ptr; 954 int i; 955 956 for(i = 0; i < GLOBALSTAT_TOTAL; ++i) { 957 c->stats[i].max_width = c->stats[i].length; 958 } 959} 960