1 /* Default profiling support.
2 Copyright (C) 1996, 1997 Free Software Foundation, Inc.
3 Contributed by Cygnus Support.
5 This file is part of GDB, the GNU debugger.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License along
18 with this program; if not, write to the Free Software Foundation, Inc.,
19 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
23 #include "sim-options.h"
25 #define COMMAS(n) sim_add_commas (comma_buf, sizeof (comma_buf), (n))
27 static MODULE_UNINSTALL_FN profile_uninstall
;
29 static void print_bar (SIM_DESC
, unsigned int, unsigned int, unsigned int);
31 static DECLARE_OPTION_HANDLER (profile_option_handler
);
33 #define OPTION_PROFILE_INSN (OPTION_START + 0)
34 #define OPTION_PROFILE_MEMORY (OPTION_START + 1)
35 #define OPTION_PROFILE_MODEL (OPTION_START + 2)
36 #define OPTION_PROFILE_FILE (OPTION_START + 3)
37 #define OPTION_PROFILE_RANGE (OPTION_START + 4)
39 static const OPTION profile_options
[] = {
40 { {"profile", no_argument
, NULL
, 'p'},
41 'p', NULL
, "Perform profiling",
42 profile_option_handler
},
43 { {"profile-insn", no_argument
, NULL
, OPTION_PROFILE_INSN
},
44 '\0', NULL
, "Perform instruction profiling",
45 profile_option_handler
},
46 { {"profile-memory", no_argument
, NULL
, OPTION_PROFILE_MEMORY
},
47 '\0', NULL
, "Perform memory profiling",
48 profile_option_handler
},
49 { {"profile-model", no_argument
, NULL
, OPTION_PROFILE_MODEL
},
50 '\0', NULL
, "Perform model profiling",
51 profile_option_handler
},
52 { {"profile-file", required_argument
, NULL
, OPTION_PROFILE_FILE
},
53 '\0', "FILE NAME", "Specify profile output file",
54 profile_option_handler
},
55 { {"profile-pc-frequency", required_argument
, NULL
, 'F'},
56 'F', "PC PROFILE FREQUENCY", "Turn on PC profiling at specified frequency",
57 profile_option_handler
},
58 { {"profile-pc-size", required_argument
, NULL
, 'S'},
59 'S', "PC PROFILE SIZE", "Specify PC profiling size",
60 profile_option_handler
},
62 { {"profile-range", required_argument
, NULL
, OPTION_PROFILE_RANGE
},
63 0, NULL
, "Specify range of addresses to profile",
64 profile_option_handler
},
66 { {NULL
, no_argument
, NULL
, 0}, '\0', NULL
, NULL
, NULL
}
70 profile_option_handler (SIM_DESC sd
, int opt
, char *arg
)
78 sim_io_eprintf (sd
, "Profiling not compiled in, -p option ignored\n");
81 for (n
= 0; n
< MAX_NR_PROCESSORS
; ++n
)
82 for (i
= 0; i
< MAX_PROFILE_VALUES
; ++i
)
83 CPU_PROFILE_FLAGS (STATE_CPU (sd
, n
))[i
] = 1;
87 case OPTION_PROFILE_INSN
:
88 #if WITH_PROFILE_INSN_P
89 for (n
= 0; n
< MAX_NR_PROCESSORS
; ++n
)
90 CPU_PROFILE_FLAGS (STATE_CPU (sd
, n
))[PROFILE_INSN_IDX
] = 1;
92 sim_io_eprintf (sd
, "Instruction profiling not compiled in, `--profile-insn' ignored\n");
96 case OPTION_PROFILE_MEMORY
:
97 #if WITH_PROFILE_MEMORY_P
98 for (n
= 0; n
< MAX_NR_PROCESSORS
; ++n
)
99 CPU_PROFILE_FLAGS (STATE_CPU (sd
, n
))[PROFILE_MEMORY_IDX
] = 1;
101 sim_io_eprintf (sd
, "Memory profiling not compiled in, `--profile-memory' ignored\n");
105 case OPTION_PROFILE_MODEL
:
106 #if WITH_PROFILE_MODEL_P
107 for (n
= 0; n
< MAX_NR_PROCESSORS
; ++n
)
108 CPU_PROFILE_FLAGS (STATE_CPU (sd
, n
))[PROFILE_MODEL_IDX
] = 1;
110 sim_io_eprintf (sd
, "Model profiling not compiled in, `--profile-model' ignored\n");
114 case OPTION_PROFILE_FILE
:
115 /* FIXME: Might want this to apply to pc profiling only,
116 or have two profile file options. */
118 sim_io_eprintf (sd
, "Profiling not compiled in, `--profile-file' ignored\n");
121 FILE *f
= fopen (arg
, "w");
125 sim_io_eprintf (sd
, "Unable to open profile output file `%s'\n", arg
);
128 for (n
= 0; n
< MAX_NR_PROCESSORS
; ++n
)
129 PROFILE_FILE (CPU_PROFILE_DATA (STATE_CPU (sd
, n
))) = f
;
134 #if WITH_PROFILE_PC_P
135 /* FIXME: Validate arg. */
137 for (n
= 0; n
< MAX_NR_PROCESSORS
; ++n
)
138 PROFILE_PC_FREQ (CPU_PROFILE_DATA (STATE_CPU (sd
, n
))) = i
;
140 sim_io_eprintf (sd
, "PC profiling not compiled in, `--profile-pc-frequency' ignored\n");
145 #if WITH_PROFILE_PC_P
146 /* FIXME: Validate arg. */
148 for (n
= 0; n
< MAX_NR_PROCESSORS
; ++n
)
149 PROFILE_PC_SIZE (CPU_PROFILE_DATA (STATE_CPU (sd
, n
))) = i
;
151 sim_io_eprintf (sd
, "PC profiling not compiled in, `--profile-pc-size' ignored\n");
155 #if 0 /* FIXME:wip */
156 case OPTION_PROFILE_RANGE
:
164 /* Install profiling support in the simulator. */
167 profile_install (SIM_DESC sd
)
171 sim_add_option_table (sd
, profile_options
);
172 for (i
= 0; i
< MAX_NR_PROCESSORS
; ++i
)
173 memset (CPU_PROFILE_DATA (STATE_CPU (sd
, i
)), 0,
174 sizeof (* CPU_PROFILE_DATA (STATE_CPU (sd
, i
))));
175 sim_module_add_uninstall_fn (sd
, profile_uninstall
);
180 profile_uninstall (SIM_DESC sd
)
184 for (i
= 0; i
< MAX_NR_PROCESSORS
; ++i
)
186 PROFILE_DATA
*data
= CPU_PROFILE_DATA (STATE_CPU (sd
, i
));
187 if (PROFILE_FILE (data
) != NULL
)
188 fclose (PROFILE_FILE (data
));
192 /* Summary printing support. */
194 #if WITH_PROFILE_INSN_P
197 profile_print_insn (sim_cpu
*cpu
, int verbose
)
199 unsigned int i
, n
, total
, max_val
, max_name_len
;
200 SIM_DESC sd
= CPU_STATE (cpu
);
201 PROFILE_DATA
*data
= CPU_PROFILE_DATA (cpu
);
204 sim_io_printf (sd
, "Instruction Statistics\n\n");
206 /* First pass over data computes various things. */
207 max_val
= total
= max_name_len
= 0;
208 for (i
= 1; i
< MAX_INSNS
; ++i
)
210 total
+= PROFILE_INSN_COUNT (data
) [i
];
211 if (PROFILE_INSN_COUNT (data
) [i
] > max_val
)
212 max_val
= PROFILE_INSN_COUNT (data
) [i
];
213 n
= strlen (INSN_NAME (i
));
214 if (n
> max_name_len
)
218 sim_io_printf (sd
, " Total: %s insns\n", COMMAS (total
));
220 if (verbose
&& max_val
!= 0)
222 /* Now we can print the histogram. */
223 sim_io_printf (sd
, "\n");
224 for (i
= 1; i
< MAX_INSNS
; ++i
)
226 if (PROFILE_INSN_COUNT (data
) [i
] != 0)
228 sim_io_printf (sd
, " %*s: %*s: ",
229 max_name_len
, INSN_NAME (i
),
230 max_val
< 10000 ? 5 : 10,
231 COMMAS (PROFILE_INSN_COUNT (data
) [i
]));
232 print_bar (sd
, PROFILE_HISTOGRAM_WIDTH
,
233 PROFILE_INSN_COUNT (data
) [i
],
235 sim_io_printf (sd
, "\n");
240 sim_io_printf (sd
, "\n");
245 #if WITH_PROFILE_MEMORY_P
248 profile_print_memory (sim_cpu
*cpu
, int verbose
)
251 unsigned int total_read
, total_write
;
252 unsigned int max_val
, max_name_len
;
253 /* FIXME: Need to add smp support. */
254 SIM_DESC sd
= CPU_STATE (cpu
);
255 PROFILE_DATA
*data
= CPU_PROFILE_DATA (cpu
);
258 sim_io_printf (sd
, "Memory Access Statistics\n\n");
260 /* First pass over data computes various things. */
261 max_val
= total_read
= total_write
= max_name_len
= 0;
262 for (i
= 0; i
< MAX_MODES
; ++i
)
264 total_read
+= PROFILE_READ_COUNT (data
) [i
];
265 total_write
+= PROFILE_WRITE_COUNT (data
) [i
];
266 if (PROFILE_READ_COUNT (data
) [i
] > max_val
)
267 max_val
= PROFILE_READ_COUNT (data
) [i
];
268 if (PROFILE_WRITE_COUNT (data
) [i
] > max_val
)
269 max_val
= PROFILE_WRITE_COUNT (data
) [i
];
270 n
= strlen (MODE_NAME (i
));
271 if (n
> max_name_len
)
275 /* One could use PROFILE_LABEL_WIDTH here. I chose not to. */
276 sim_io_printf (sd
, " Total read: %s accesses\n",
277 COMMAS (total_read
));
278 sim_io_printf (sd
, " Total write: %s accesses\n",
279 COMMAS (total_write
));
281 if (verbose
&& max_val
!= 0)
283 /* FIXME: Need to separate instruction fetches from data fetches
284 as the former swamps the latter. */
285 /* Now we can print the histogram. */
286 sim_io_printf (sd
, "\n");
287 for (i
= 0; i
< MAX_MODES
; ++i
)
289 if (PROFILE_READ_COUNT (data
) [i
] != 0)
291 sim_io_printf (sd
, " %*s read: %*s: ",
292 max_name_len
, MODE_NAME (i
),
293 max_val
< 10000 ? 5 : 10,
294 COMMAS (PROFILE_READ_COUNT (data
) [i
]));
295 print_bar (sd
, PROFILE_HISTOGRAM_WIDTH
,
296 PROFILE_READ_COUNT (data
) [i
],
298 sim_io_printf (sd
, "\n");
300 if (PROFILE_WRITE_COUNT (data
) [i
] != 0)
302 sim_io_printf (sd
, " %*s write: %*s: ",
303 max_name_len
, MODE_NAME (i
),
304 max_val
< 10000 ? 5 : 10,
305 COMMAS (PROFILE_WRITE_COUNT (data
) [i
]));
306 print_bar (sd
, PROFILE_HISTOGRAM_WIDTH
,
307 PROFILE_WRITE_COUNT (data
) [i
],
309 sim_io_printf (sd
, "\n");
314 sim_io_printf (sd
, "\n");
319 #if WITH_PROFILE_MODEL_P
322 profile_print_model (sim_cpu
*cpu
, int verbose
)
324 SIM_DESC sd
= CPU_STATE (cpu
);
325 PROFILE_DATA
*data
= CPU_PROFILE_DATA (cpu
);
326 unsigned long cti_stalls
= PROFILE_MODEL_CTI_STALL_COUNT (data
);
327 unsigned long load_stalls
= PROFILE_MODEL_LOAD_STALL_COUNT (data
);
328 unsigned long total
= PROFILE_MODEL_CYCLE_COUNT (data
)
329 + cti_stalls
+ load_stalls
;
332 sim_io_printf (sd
, "Model %s Timing Information\n\n",
333 MODEL_NAME (STATE_MODEL (sd
)));
334 sim_io_printf (sd
, " %-*s %s\n",
335 PROFILE_LABEL_WIDTH
, "Taken branches:",
336 COMMAS (PROFILE_MODEL_TAKEN_COUNT (data
)));
337 sim_io_printf (sd
, " %-*s %s\n",
338 PROFILE_LABEL_WIDTH
, "Untaken branches:",
339 COMMAS (PROFILE_MODEL_UNTAKEN_COUNT (data
)));
340 sim_io_printf (sd
, " %-*s %s\n",
341 PROFILE_LABEL_WIDTH
, "Cycles stalled due to branches:",
342 COMMAS (cti_stalls
));
343 sim_io_printf (sd
, " %-*s %s\n",
344 PROFILE_LABEL_WIDTH
, "Cycles stalled due to loads:",
345 COMMAS (load_stalls
));
346 sim_io_printf (sd
, " %-*s %s\n",
347 PROFILE_LABEL_WIDTH
, "Total cycles (*approximate*):",
349 sim_io_printf (sd
, "\n");
355 print_bar (SIM_DESC sd
, unsigned int width
,
356 unsigned int val
, unsigned int max_val
)
358 unsigned int i
, count
;
360 count
= ((double) val
/ (double) max_val
) * (double) width
;
362 for (i
= 0; i
< count
; ++i
)
363 sim_io_printf (sd
, "*");
366 /* Print the simulator's execution speed for CPU. */
369 profile_print_speed (sim_cpu
*cpu
)
371 SIM_DESC sd
= CPU_STATE (cpu
);
372 PROFILE_DATA
*data
= CPU_PROFILE_DATA (cpu
);
373 unsigned long milliseconds
= PROFILE_EXEC_TIME (data
);
374 unsigned long total
= PROFILE_TOTAL_INSN_COUNT (data
);
377 sim_io_printf (sd
, "Simulator Execution Speed\n\n");
380 sim_io_printf (sd
, " Total instructions: %s\n", COMMAS (total
));
382 if (milliseconds
< 1000)
383 sim_io_printf (sd
, " Total Execution Time: < 1 second\n\n");
386 /* The printing of the time rounded to 2 decimal places makes the speed
387 calculation seem incorrect [even though it is correct]. So round
388 MILLISECONDS first. This can marginally affect the result, but it's
389 better that the user not perceive there's a math error. */
390 double secs
= (double) milliseconds
/ 1000;
391 secs
= ((double) (unsigned long) (secs
* 100 + .5)) / 100;
392 sim_io_printf (sd
, " Total Execution Time: %.2f seconds\n", secs
);
393 /* Don't confuse things with data that isn't useful.
394 If we ran for less than 2 seconds, only use the data if we
395 executed more than 100,000 insns. */
396 if (secs
>= 2 || total
>= 100000)
397 sim_io_printf (sd
, " Simulator Speed: %s insns/second\n\n",
398 COMMAS ((unsigned long) ((double) total
/ secs
)));
402 /* Top level function to print all summary profile information.
403 It is [currently] intended that all such data is printed by this function.
404 I'd rather keep it all in one place for now. To that end, MISC_CPU and
405 MISC are callbacks used to print any miscellaneous data.
407 One might want to add a user option that allows printing by type or by cpu
408 (i.e. print all insn data for each cpu first, or print data cpu by cpu).
409 This may be a case of featuritis so it's currently left out.
411 Note that results are indented two spaces to distinguish them from
415 profile_print (SIM_DESC sd
, int verbose
,
416 PROFILE_CALLBACK
*misc
, PROFILE_CPU_CALLBACK
*misc_cpu
)
419 int print_title_p
= 0;
421 /* Only print the title if some data has been collected. */
422 /* FIXME: If the number of processors can be selected on the command line,
423 then MAX_NR_PROCESSORS will need to take an argument of `sd'. */
425 for (c
= 0; c
< MAX_NR_PROCESSORS
; ++c
)
427 sim_cpu
*cpu
= STATE_CPU (sd
, c
);
428 PROFILE_DATA
*data
= CPU_PROFILE_DATA (cpu
);
430 for (i
= 0; i
< MAX_PROFILE_VALUES
; ++i
)
431 if (PROFILE_FLAGS (data
) [i
])
433 /* One could break out early if print_title_p is set. */
436 sim_io_printf (sd
, "Summary profiling results:\n\n");
438 /* Loop, cpu by cpu, printing results. */
440 for (c
= 0; c
< MAX_NR_PROCESSORS
; ++c
)
442 sim_cpu
*cpu
= STATE_CPU (sd
, c
);
443 PROFILE_DATA
*data
= CPU_PROFILE_DATA (cpu
);
445 if (MAX_NR_PROCESSORS
> 1)
446 sim_io_printf (sd
, "CPU %d\n\n", c
);
448 #if WITH_PROFILE_INSN_P
449 if (PROFILE_FLAGS (data
) [PROFILE_INSN_IDX
])
450 profile_print_insn (cpu
, verbose
);
453 #if WITH_PROFILE_MEMORY_P
454 if (PROFILE_FLAGS (data
) [PROFILE_MEMORY_IDX
])
455 profile_print_memory (cpu
, verbose
);
458 #if WITH_PROFILE_MODEL_P
459 if (PROFILE_FLAGS (data
) [PROFILE_MODEL_IDX
])
460 profile_print_model (cpu
, verbose
);
463 #if WITH_PROFILE_SCACHE_P && WITH_SCACHE
464 if (PROFILE_FLAGS (data
) [PROFILE_SCACHE_IDX
])
465 scache_print_profile (cpu
, verbose
);
468 /* Print cpu-specific data before the execution speed. */
469 if (misc_cpu
!= NULL
)
470 (*misc_cpu
) (cpu
, verbose
);
472 /* Always try to print execution time and speed. */
474 || PROFILE_FLAGS (data
) [PROFILE_INSN_IDX
])
475 profile_print_speed (cpu
);
478 /* Finally print non-cpu specific miscellaneous data. */
481 (*misc
) (sd
, verbose
);