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