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