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 <unistd.h> 28 29#include "statistic.h" 30#include "generic.h" 31#include "preferences.h" 32#include "globalstats.h" 33#include "top.h" 34#include "sig.h" 35 36struct log_get_total_data { 37 int total; 38}; 39 40static bool log_get_total_iter(struct statistic *s, void *ptr) { 41 struct log_get_total_data *data = ptr; 42 struct generic_cells *cells; 43 44 cells = s->cells; 45 46 if(NULL == cells) 47 return false; 48 49 data->total = cells->length; 50 51 return false; 52} 53 54/* Get the total number of processes this run. */ 55static int log_get_total(void *tinst) { 56 struct statistics_controller *c = tinst; 57 struct log_get_total_data data; 58 59 data.total = 0; 60 61 c->iterate(c, log_get_total_iter, &data); 62 63 return data.total; 64} 65 66struct log_print_header_data { 67 int x; 68 int xoffset; 69 bool have_limit; 70 int ncols; 71 int column; 72}; 73 74static bool log_print_header_iter(struct statistic *s, void *ptr) { 75 struct log_print_header_data *data = ptr; 76 int max_width, headerlen; 77 struct generic_cells *cells; 78 int i, afterx; 79 80 cells = s->cells; 81 82 if(NULL == cells) 83 return false; 84 85 max_width = cells->max_width; 86 87 headerlen = (int)strlen(s->header); 88 89 if(headerlen > max_width) 90 max_width = headerlen; 91 92 afterx = max_width + data->x; 93 94 for(i = 0; i < data->xoffset; ++i) 95 putchar(' '); 96 97 printf("%s", s->header); 98 99 for(i = headerlen; i < max_width; ++i) 100 putchar(' '); 101 102 data->x = afterx; 103 data->xoffset = /*padding*/ 1; 104 105 data->column++; 106 107 if(data->have_limit && data->column >= data->ncols) 108 return false; /*stop iterating*/ 109 110 return true; 111} 112 113static void log_print_header(void *tinst) { 114 struct statistics_controller *c = tinst; 115 struct log_print_header_data data; 116 117 data.x = 0; 118 data.xoffset = 0; 119 data.have_limit = top_prefs_get_ncols(&data.ncols); 120 data.column = 0; 121 122 c->iterate(c, log_print_header_iter, &data); 123} 124 125struct log_print_cell_data { 126 int x; 127 int xoffset; 128 bool have_limit; 129 int ncols; /* The limit of the columns. */ 130 int column; /* The current number of columns. */ 131 int row; 132}; 133 134static bool log_print_cell(struct statistic *s, void *ptr) { 135 struct log_print_cell_data *data = ptr; 136 struct generic_cells *cells; 137 size_t i; 138 int pad; 139 int afterx; 140 int max_width; 141 int headerlen; 142 143 cells = s->cells; 144 145 if(NULL == cells) 146 return false; 147 148 max_width = cells->max_width; 149 150 headerlen = (int)strlen(s->header); 151 152 if(headerlen > max_width) 153 max_width = headerlen; 154 155 afterx = data->x + max_width; 156 157 assert(data->row < cells->length); 158 159 /* Add padding to the left. */ 160 for(pad = 0; pad < data->xoffset; ++pad) { 161 putchar(' '); 162 } 163 164 printf("%s", cells->array[data->row].string); 165 166 for(i = cells->array[data->row].length; i < (size_t)max_width; ++i) { 167 putchar(' '); 168 } 169 170 data->x = afterx; 171 data->xoffset = 1; 172 173 data->column++; 174 175 /* See if we have displayed all of the columns requested. */ 176 if(data->have_limit && data->column >= data->ncols) 177 return false; 178 179 return true; 180} 181 182static bool log_print_globalstats(char *s, void *ptr) { 183 printf("%s\n", s); 184 return true; 185} 186 187static void log_print_all(void *tinst) { 188 struct statistics_controller *c = tinst; 189 struct log_print_cell_data data; 190 int y, ylimit; 191 192 top_globalstats_iterate(c->globalstats, log_print_globalstats, NULL); 193 putchar('\n'); 194 195 log_print_header(tinst); 196 putchar('\n'); 197 198 data.x = 0; 199 data.xoffset = /*padding*/ 0; 200 data.have_limit = top_prefs_get_ncols(&data.ncols); 201 data.column = 0; 202 data.row = 0; 203 204 ylimit = log_get_total(tinst); 205 206 for(y = 0; y < ylimit; ++y) { 207 data.x = 0; 208 data.xoffset = 0; 209 data.column = 0; 210 c->iterate(c, log_print_cell, &data); 211 data.row++; 212 putchar('\n'); 213 } 214} 215 216void top_logging_loop_body(void *tinst) { 217 top_insert(tinst); 218 log_print_all(tinst); 219 fflush(stdout); 220 sleep(top_prefs_get_sleep()); 221 222 if(top_signal_is_exit_set()) 223 exit(EXIT_SUCCESS); 224} 225 226void top_logging_loop(void *tinst) { 227 int samples; 228 bool forever = false; 229 230 if(0 == top_prefs_get_samples()) 231 forever = true; 232 233 if(forever) { 234 while(1) 235 top_logging_loop_body(tinst); 236 } else { 237 for(samples = top_prefs_get_samples(); samples > 0; --samples) 238 top_logging_loop_body(tinst); 239 240 /* We displayed the requested number of samples. */ 241 exit(EXIT_SUCCESS); 242 } 243} 244