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