1 /* This file is part of the program psim. 2 3 Copyright (C) 1994-1997, Andrew Cagney <cagney@highland.com.au> 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 3 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; if not, see <http://www.gnu.org/licenses/>. 17 18 */ 19 20 21 #ifndef _MON_C_ 22 #define _MON_C_ 23 24 #include "defs.h" 25 26 #include <stdio.h> 27 28 #include <string.h> 29 #include <unistd.h> 30 #include <stdlib.h> 31 #ifdef HAVE_SYS_TYPES_H 32 #include <sys/types.h> 33 #endif 34 #include <time.h> 35 #include <sys/time.h> 36 37 #ifdef HAVE_SYS_RESOURCE_H 38 #include <sys/resource.h> 39 #endif 40 41 #include "basics.h" 42 #include "cpu.h" 43 #include "mon.h" 44 45 #define MAX_BYTE_READWRITE 9 46 #define MAX_SHIFT_READWRITE 3 47 48 struct _cpu_mon { 49 count_type issue_count[nr_itable_entries]; 50 count_type read_count; 51 count_type read_byte_count[MAX_BYTE_READWRITE]; 52 count_type write_count; 53 count_type write_byte_count[MAX_BYTE_READWRITE]; 54 count_type unaligned_read_count; 55 count_type unaligned_write_count; 56 count_type event_count[nr_mon_events]; 57 }; 58 59 struct _mon { 60 int nr_cpus; 61 cpu_mon cpu_monitor[MAX_NR_PROCESSORS]; 62 }; 63 64 65 INLINE_MON\ 66 (mon *) 67 mon_create(void) 68 { 69 mon *monitor = ZALLOC(mon); 70 return monitor; 71 } 72 73 74 INLINE_MON\ 75 (cpu_mon *) 76 mon_cpu(mon *monitor, 77 int cpu_nr) 78 { 79 if (cpu_nr < 0 || cpu_nr >= MAX_NR_PROCESSORS) 80 error("mon_cpu() - invalid cpu number\n"); 81 return &monitor->cpu_monitor[cpu_nr]; 82 } 83 84 85 INLINE_MON\ 86 (void) 87 mon_init(mon *monitor, 88 int nr_cpus) 89 { 90 memset(monitor, 0, sizeof(*monitor)); 91 monitor->nr_cpus = nr_cpus; 92 } 93 94 95 INLINE_MON\ 96 (void) 97 mon_issue(itable_index index, 98 cpu *processor, 99 unsigned_word cia) 100 { 101 cpu_mon *monitor = cpu_monitor(processor); 102 ASSERT(index <= nr_itable_entries); 103 monitor->issue_count[index] += 1; 104 } 105 106 107 INLINE_MON\ 108 (void) 109 mon_read(unsigned_word ea, 110 unsigned_word ra, 111 unsigned nr_bytes, 112 cpu *processor, 113 unsigned_word cia) 114 { 115 cpu_mon *monitor = cpu_monitor(processor); 116 monitor->read_count += 1; 117 monitor->read_byte_count[nr_bytes] += 1; 118 if ((nr_bytes - 1) & ea) 119 monitor->unaligned_read_count += 1; 120 } 121 122 123 INLINE_MON\ 124 (void) 125 mon_write(unsigned_word ea, 126 unsigned_word ra, 127 unsigned nr_bytes, 128 cpu *processor, 129 unsigned_word cia) 130 { 131 cpu_mon *monitor = cpu_monitor(processor); 132 monitor->write_count += 1; 133 monitor->write_byte_count[nr_bytes] += 1; 134 if ((nr_bytes - 1) & ea) 135 monitor->unaligned_write_count += 1; 136 } 137 138 INLINE_MON\ 139 (void) 140 mon_event(mon_events event, 141 cpu *processor, 142 unsigned_word cia) 143 { 144 cpu_mon *monitor = cpu_monitor(processor); 145 ASSERT(event < nr_mon_events); 146 monitor->event_count[event] += 1; 147 } 148 149 INLINE_MON\ 150 (unsigned) 151 mon_get_number_of_insns(mon *monitor, 152 int cpu_nr) 153 { 154 itable_index index; 155 unsigned total_insns = 0; 156 ASSERT(cpu_nr >= 0 && cpu_nr < monitor->nr_cpus); 157 for (index = 0; index < nr_itable_entries; index++) 158 total_insns += monitor->cpu_monitor[cpu_nr].issue_count[index]; 159 return total_insns; 160 } 161 162 STATIC_INLINE_MON\ 163 (int) 164 mon_sort_instruction_names(const void *ptr_a, const void *ptr_b) 165 { 166 itable_index a = *(const itable_index *)ptr_a; 167 itable_index b = *(const itable_index *)ptr_b; 168 169 return strcmp (itable[a].name, itable[b].name); 170 } 171 172 STATIC_INLINE_MON\ 173 (char *) 174 mon_add_commas(char *buf, 175 int sizeof_buf, 176 count_type value) 177 { 178 int comma = 3; 179 char *endbuf = buf + sizeof_buf - 1; 180 181 *--endbuf = '\0'; 182 do { 183 if (comma-- == 0) 184 { 185 *--endbuf = ','; 186 comma = 2; 187 } 188 189 *--endbuf = (value % 10) + '0'; 190 } while ((value /= 10) != 0); 191 192 ASSERT(endbuf >= buf); 193 return endbuf; 194 } 195 196 197 INLINE_MON\ 198 (void) 199 mon_print_info(psim *system, 200 mon *monitor, 201 int verbose) 202 { 203 char buffer[20]; 204 char buffer1[20]; 205 char buffer2[20]; 206 char buffer4[20]; 207 char buffer8[20]; 208 int cpu_nr; 209 int len_cpu; 210 int len_num = 0; 211 int len_sub_num[MAX_BYTE_READWRITE]; 212 int len; 213 int i; 214 long total_insns = 0; 215 long cpu_insns_second = 0; 216 long total_sim_cycles = 0; 217 long sim_cycles_second = 0; 218 double cpu_time = 0.0; 219 220 for (i = 0; i < MAX_BYTE_READWRITE; i++) 221 len_sub_num[i] = 0; 222 223 for (cpu_nr = 0; cpu_nr < monitor->nr_cpus; cpu_nr++) { 224 count_type num_insns = mon_get_number_of_insns(monitor, cpu_nr); 225 226 total_insns += num_insns; 227 len = strlen (mon_add_commas(buffer, sizeof(buffer), num_insns)); 228 if (len_num < len) 229 len_num = len; 230 231 for (i = 0; i <= MAX_SHIFT_READWRITE; i++) { 232 int size = 1<<i; 233 len = strlen (mon_add_commas(buffer, sizeof(buffer), 234 monitor->cpu_monitor[cpu_nr].read_byte_count[size])); 235 if (len_sub_num[size] < len) 236 len_sub_num[size] = len; 237 238 len = strlen (mon_add_commas(buffer, sizeof(buffer), 239 monitor->cpu_monitor[cpu_nr].write_byte_count[size])); 240 if (len_sub_num[size] < len) 241 len_sub_num[size] = len; 242 } 243 } 244 245 sprintf (buffer, "%d", (int)monitor->nr_cpus + 1); 246 len_cpu = strlen (buffer); 247 248 #ifdef HAVE_GETRUSAGE 249 { 250 struct rusage mytime; 251 if (getrusage (RUSAGE_SELF, &mytime) == 0 252 && (mytime.ru_utime.tv_sec > 0 || mytime.ru_utime.tv_usec > 0)) { 253 254 cpu_time = (double)mytime.ru_utime.tv_sec + (((double)mytime.ru_utime.tv_usec) / 1000000.0); 255 } 256 } 257 if (WITH_EVENTS) 258 total_sim_cycles = event_queue_time(psim_event_queue(system)) - 1; 259 if (cpu_time > 0) { 260 if (total_insns > 0) 261 cpu_insns_second = (long)(((double)total_insns / cpu_time) + 0.5); 262 if (total_sim_cycles) { 263 sim_cycles_second = (long)(((double)total_sim_cycles / cpu_time) + 0.5); 264 } 265 } 266 #endif 267 268 for (cpu_nr = 0; cpu_nr < monitor->nr_cpus; cpu_nr++) { 269 270 if (verbose > 1) { 271 itable_index sort_insns[nr_itable_entries]; 272 int nr_sort_insns = 0; 273 itable_index index; 274 int index2; 275 276 if (cpu_nr) 277 printf_filtered ("\n"); 278 279 for (index = 0; index < nr_itable_entries; index++) { 280 if (monitor->cpu_monitor[cpu_nr].issue_count[index]) { 281 sort_insns[nr_sort_insns++] = index; 282 } 283 } 284 285 qsort((void *)sort_insns, nr_sort_insns, sizeof(sort_insns[0]), mon_sort_instruction_names); 286 287 for (index2 = 0; index2 < nr_sort_insns; index2++) { 288 index = sort_insns[index2]; 289 printf_filtered("CPU #%*d executed %*s %s instruction%s.\n", 290 len_cpu, cpu_nr+1, 291 len_num, mon_add_commas(buffer, 292 sizeof(buffer), 293 monitor->cpu_monitor[cpu_nr].issue_count[index]), 294 itable[index].name, 295 (monitor->cpu_monitor[cpu_nr].issue_count[index] == 1) ? "" : "s"); 296 } 297 298 printf_filtered ("\n"); 299 } 300 301 if (CURRENT_MODEL_ISSUE > 0) 302 { 303 model_data *model_ptr = cpu_model(psim_cpu(system, cpu_nr)); 304 model_print *ptr = model_mon_info(model_ptr); 305 model_print *orig_ptr = ptr; 306 307 while (ptr) { 308 if (ptr->count) 309 printf_filtered("CPU #%*d executed %*s %s%s.\n", 310 len_cpu, cpu_nr+1, 311 len_num, mon_add_commas(buffer, 312 sizeof(buffer), 313 ptr->count), 314 ptr->name, 315 ((ptr->count == 1) 316 ? ptr->suffix_singular 317 : ptr->suffix_plural)); 318 319 ptr = ptr->next; 320 } 321 322 model_mon_info_free(model_ptr, orig_ptr); 323 } 324 325 if (monitor->cpu_monitor[cpu_nr].read_count) 326 printf_filtered ("CPU #%*d executed %*s read%s (%*s 1-byte, %*s 2-byte, %*s 4-byte, %*s 8-byte).\n", 327 len_cpu, cpu_nr+1, 328 len_num, mon_add_commas(buffer, 329 sizeof(buffer), 330 monitor->cpu_monitor[cpu_nr].read_count), 331 (monitor->cpu_monitor[cpu_nr].read_count == 1) ? "" : "s", 332 len_sub_num[1], mon_add_commas(buffer1, 333 sizeof(buffer1), 334 monitor->cpu_monitor[cpu_nr].read_byte_count[1]), 335 len_sub_num[2], mon_add_commas(buffer2, 336 sizeof(buffer2), 337 monitor->cpu_monitor[cpu_nr].read_byte_count[2]), 338 len_sub_num[4], mon_add_commas(buffer4, 339 sizeof(buffer4), 340 monitor->cpu_monitor[cpu_nr].read_byte_count[4]), 341 len_sub_num[8], mon_add_commas(buffer8, 342 sizeof(buffer8), 343 monitor->cpu_monitor[cpu_nr].read_byte_count[8])); 344 345 if (monitor->cpu_monitor[cpu_nr].write_count) 346 printf_filtered ("CPU #%*d executed %*s write%s (%*s 1-byte, %*s 2-byte, %*s 4-byte, %*s 8-byte).\n", 347 len_cpu, cpu_nr+1, 348 len_num, mon_add_commas(buffer, 349 sizeof(buffer), 350 monitor->cpu_monitor[cpu_nr].write_count), 351 (monitor->cpu_monitor[cpu_nr].write_count == 1) ? "" : "s", 352 len_sub_num[1], mon_add_commas(buffer1, 353 sizeof(buffer1), 354 monitor->cpu_monitor[cpu_nr].write_byte_count[1]), 355 len_sub_num[2], mon_add_commas(buffer2, 356 sizeof(buffer2), 357 monitor->cpu_monitor[cpu_nr].write_byte_count[2]), 358 len_sub_num[4], mon_add_commas(buffer4, 359 sizeof(buffer4), 360 monitor->cpu_monitor[cpu_nr].write_byte_count[4]), 361 len_sub_num[8], mon_add_commas(buffer8, 362 sizeof(buffer8), 363 monitor->cpu_monitor[cpu_nr].write_byte_count[8])); 364 365 if (monitor->cpu_monitor[cpu_nr].unaligned_read_count) 366 printf_filtered ("CPU #%*d executed %*s unaligned read%s.\n", 367 len_cpu, cpu_nr+1, 368 len_num, mon_add_commas(buffer, 369 sizeof(buffer), 370 monitor->cpu_monitor[cpu_nr].unaligned_read_count), 371 (monitor->cpu_monitor[cpu_nr].unaligned_read_count == 1) ? "" : "s"); 372 373 if (monitor->cpu_monitor[cpu_nr].unaligned_write_count) 374 printf_filtered ("CPU #%*d executed %*s unaligned write%s.\n", 375 len_cpu, cpu_nr+1, 376 len_num, mon_add_commas(buffer, 377 sizeof(buffer), 378 monitor->cpu_monitor[cpu_nr].unaligned_write_count), 379 (monitor->cpu_monitor[cpu_nr].unaligned_write_count == 1) ? "" : "s"); 380 381 if (monitor->cpu_monitor[cpu_nr].event_count[mon_event_icache_miss]) 382 printf_filtered ("CPU #%*d executed %*s icache miss%s.\n", 383 len_cpu, cpu_nr+1, 384 len_num, mon_add_commas(buffer, 385 sizeof(buffer), 386 monitor->cpu_monitor[cpu_nr].event_count[mon_event_icache_miss]), 387 (monitor->cpu_monitor[cpu_nr].event_count[mon_event_icache_miss] == 1) ? "" : "es"); 388 389 { 390 long nr_insns = mon_get_number_of_insns(monitor, cpu_nr); 391 if (nr_insns > 0) 392 printf_filtered("CPU #%*d executed %*s instructions in total.\n", 393 len_cpu, cpu_nr+1, 394 len_num, mon_add_commas(buffer, 395 sizeof(buffer), 396 nr_insns)); 397 } 398 } 399 400 if (total_insns > 0) { 401 if (monitor->nr_cpus > 1) 402 printf_filtered("\nAll CPUs executed %s instructions in total.\n", 403 mon_add_commas(buffer, sizeof(buffer), total_insns)); 404 } 405 else if (total_sim_cycles > 0) { 406 printf_filtered("\nSimulator performed %s simulation cycles.\n", 407 mon_add_commas(buffer, sizeof(buffer), total_sim_cycles)); 408 } 409 410 if (cpu_insns_second) 411 printf_filtered ("%sSimulator speed was %s instructions/second.\n", 412 (monitor->nr_cpus > 1) ? "" : "\n", 413 mon_add_commas(buffer, sizeof(buffer), cpu_insns_second)); 414 else if (sim_cycles_second) 415 printf_filtered ("Simulator speed was %s simulation cycles/second\n", 416 mon_add_commas(buffer, sizeof(buffer), sim_cycles_second)); 417 else if (cpu_time > 0.0) 418 printf_filtered ("%sSimulator executed for %.2f seconds\n", 419 (monitor->nr_cpus > 1) ? "" : "\n", cpu_time); 420 421 } 422 423 #endif /* _MON_C_ */ 424