Passify GCC.
[deliverable/binutils-gdb.git] / sim / common / sim-profile.c
CommitLineData
c967f187
DE
1/* Default profiling support.
2 Copyright (C) 1996, 1997 Free Software Foundation, Inc.
3 Contributed by Cygnus Support.
4
5This file is part of GDB, the GNU debugger.
6
7This program is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2, or (at your option)
10any later version.
11
12This program is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License along
18with this program; if not, write to the Free Software Foundation, Inc.,
1959 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
20
21#include "sim-main.h"
22#include "sim-io.h"
23#include "sim-options.h"
24
2317a499
DE
25#define COMMAS(n) sim_add_commas (comma_buf, sizeof (comma_buf), (n))
26
c967f187
DE
27static MODULE_UNINSTALL_FN profile_uninstall;
28
29static void print_bar (SIM_DESC, unsigned int, unsigned int, unsigned int);
30
31static DECLARE_OPTION_HANDLER (profile_option_handler);
32
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)
38
39static 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 },
61#if 0 /*FIXME:wip*/
62 { {"profile-range", required_argument, NULL, OPTION_PROFILE_RANGE},
63 0, NULL, "Specify range of addresses to profile",
64 profile_option_handler },
65#endif
66 { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL }
67};
68
69static SIM_RC
70profile_option_handler (SIM_DESC sd, int opt, char *arg)
71{
72 int i,n;
73
74 switch (opt)
75 {
76 case 'p' :
77 if (! WITH_PROFILE)
78 sim_io_eprintf (sd, "Profiling not compiled in, -p option ignored\n");
79 else
80 {
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;
84 }
85 break;
86
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;
91#else
92 sim_io_eprintf (sd, "Instruction profiling not compiled in, `--profile-insn' ignored\n");
93#endif
94 break;
95
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;
100#else
101 sim_io_eprintf (sd, "Memory profiling not compiled in, `--profile-memory' ignored\n");
102#endif
103 break;
104
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;
109#else
110 sim_io_eprintf (sd, "Model profiling not compiled in, `--profile-model' ignored\n");
111#endif
112 break;
113
114 case OPTION_PROFILE_FILE :
115 /* FIXME: Might want this to apply to pc profiling only,
116 or have two profile file options. */
117 if (! WITH_PROFILE)
118 sim_io_eprintf (sd, "Profiling not compiled in, `--profile-file' ignored\n");
119 else
120 {
121 FILE *f = fopen (arg, "w");
122
123 if (f == NULL)
124 {
125 sim_io_eprintf (sd, "Unable to open profile output file `%s'\n", arg);
126 return SIM_RC_FAIL;
127 }
128 for (n = 0; n < MAX_NR_PROCESSORS; ++n)
129 PROFILE_FILE (CPU_PROFILE_DATA (STATE_CPU (sd, n))) = f;
130 }
131 break;
132
133 case 'F' :
134#if WITH_PROFILE_PC_P
135 /* FIXME: Validate arg. */
136 i = atoi (arg);
137 for (n = 0; n < MAX_NR_PROCESSORS; ++n)
138 PROFILE_PC_FREQ (CPU_PROFILE_DATA (STATE_CPU (sd, n))) = i;
139#else
140 sim_io_eprintf (sd, "PC profiling not compiled in, `--profile-pc-frequency' ignored\n");
141#endif
142 break;
143
144 case 'S' :
145#if WITH_PROFILE_PC_P
146 /* FIXME: Validate arg. */
147 i = atoi (arg);
148 for (n = 0; n < MAX_NR_PROCESSORS; ++n)
149 PROFILE_PC_SIZE (CPU_PROFILE_DATA (STATE_CPU (sd, n))) = i;
150#else
151 sim_io_eprintf (sd, "PC profiling not compiled in, `--profile-pc-size' ignored\n");
152#endif
153 break;
154
155#if 0 /* FIXME:wip */
156 case OPTION_PROFILE_RANGE :
157 break;
158#endif
159 }
160
161 return SIM_RC_OK;
162}
2317a499
DE
163\f
164/* Install profiling support in the simulator. */
c967f187
DE
165
166SIM_RC
167profile_install (SIM_DESC sd)
168{
169 int i;
170
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);
176 return SIM_RC_OK;
177}
178
179static void
180profile_uninstall (SIM_DESC sd)
181{
182 int i;
183
184 for (i = 0; i < MAX_NR_PROCESSORS; ++i)
185 {
186 PROFILE_DATA *data = CPU_PROFILE_DATA (STATE_CPU (sd, i));
187 if (PROFILE_FILE (data) != NULL)
188 fclose (PROFILE_FILE (data));
189 }
190}
2317a499
DE
191\f
192/* Summary printing support. */
c967f187
DE
193
194#if WITH_PROFILE_INSN_P
195
196static void
197profile_print_insn (sim_cpu *cpu, int verbose)
198{
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);
2317a499 202 char comma_buf[20];
c967f187
DE
203
204 sim_io_printf (sd, "Instruction Statistics\n\n");
205
206 /* First pass over data computes various things. */
207 max_val = total = max_name_len = 0;
208 for (i = 1; i < MAX_INSNS; ++i)
209 {
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)
215 max_name_len = n;
216 }
217
2317a499 218 sim_io_printf (sd, " Total: %s insns\n", COMMAS (total));
c967f187
DE
219
220 if (verbose && max_val != 0)
221 {
222 /* Now we can print the histogram. */
223 sim_io_printf (sd, "\n");
224 for (i = 1; i < MAX_INSNS; ++i)
225 {
226 if (PROFILE_INSN_COUNT (data) [i] != 0)
227 {
2317a499 228 sim_io_printf (sd, " %*s: %*s: ",
c967f187 229 max_name_len, INSN_NAME (i),
2317a499
DE
230 max_val < 10000 ? 5 : 10,
231 COMMAS (PROFILE_INSN_COUNT (data) [i]));
c967f187
DE
232 print_bar (sd, PROFILE_HISTOGRAM_WIDTH,
233 PROFILE_INSN_COUNT (data) [i],
234 max_val);
235 sim_io_printf (sd, "\n");
236 }
237 }
238 }
239
240 sim_io_printf (sd, "\n");
241}
242
243#endif
244
245#if WITH_PROFILE_MEMORY_P
246
247static void
248profile_print_memory (sim_cpu *cpu, int verbose)
249{
250 unsigned int i, n;
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);
2317a499 256 char comma_buf[20];
c967f187
DE
257
258 sim_io_printf (sd, "Memory Access Statistics\n\n");
259
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)
263 {
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)
272 max_name_len = n;
273 }
274
275 /* One could use PROFILE_LABEL_WIDTH here. I chose not to. */
2317a499
DE
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));
c967f187
DE
280
281 if (verbose && max_val != 0)
282 {
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)
288 {
289 if (PROFILE_READ_COUNT (data) [i] != 0)
290 {
2317a499 291 sim_io_printf (sd, " %*s read: %*s: ",
c967f187 292 max_name_len, MODE_NAME (i),
2317a499
DE
293 max_val < 10000 ? 5 : 10,
294 COMMAS (PROFILE_READ_COUNT (data) [i]));
c967f187
DE
295 print_bar (sd, PROFILE_HISTOGRAM_WIDTH,
296 PROFILE_READ_COUNT (data) [i],
297 max_val);
298 sim_io_printf (sd, "\n");
299 }
300 if (PROFILE_WRITE_COUNT (data) [i] != 0)
301 {
2317a499 302 sim_io_printf (sd, " %*s write: %*s: ",
c967f187 303 max_name_len, MODE_NAME (i),
2317a499
DE
304 max_val < 10000 ? 5 : 10,
305 COMMAS (PROFILE_WRITE_COUNT (data) [i]));
c967f187
DE
306 print_bar (sd, PROFILE_HISTOGRAM_WIDTH,
307 PROFILE_WRITE_COUNT (data) [i],
308 max_val);
309 sim_io_printf (sd, "\n");
310 }
311 }
312 }
313
314 sim_io_printf (sd, "\n");
315}
316
317#endif
318
319#if WITH_PROFILE_MODEL_P
320
321static void
322profile_print_model (sim_cpu *cpu, int verbose)
323{
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;
2317a499 330 char comma_buf[20];
c967f187
DE
331
332 sim_io_printf (sd, "Model %s Timing Information\n\n",
333 MODEL_NAME (STATE_MODEL (sd)));
2317a499 334 sim_io_printf (sd, " %-*s %s\n",
c967f187 335 PROFILE_LABEL_WIDTH, "Taken branches:",
2317a499
DE
336 COMMAS (PROFILE_MODEL_TAKEN_COUNT (data)));
337 sim_io_printf (sd, " %-*s %s\n",
c967f187 338 PROFILE_LABEL_WIDTH, "Untaken branches:",
2317a499
DE
339 COMMAS (PROFILE_MODEL_UNTAKEN_COUNT (data)));
340 sim_io_printf (sd, " %-*s %s\n",
c967f187 341 PROFILE_LABEL_WIDTH, "Cycles stalled due to branches:",
2317a499
DE
342 COMMAS (cti_stalls));
343 sim_io_printf (sd, " %-*s %s\n",
c967f187 344 PROFILE_LABEL_WIDTH, "Cycles stalled due to loads:",
2317a499
DE
345 COMMAS (load_stalls));
346 sim_io_printf (sd, " %-*s %s\n",
c967f187 347 PROFILE_LABEL_WIDTH, "Total cycles (*approximate*):",
2317a499 348 COMMAS (total));
c967f187
DE
349 sim_io_printf (sd, "\n");
350}
351
352#endif
353
354static void
355print_bar (SIM_DESC sd, unsigned int width,
356 unsigned int val, unsigned int max_val)
357{
358 unsigned int i, count;
359
360 count = ((double) val / (double) max_val) * (double) width;
361
362 for (i = 0; i < count; ++i)
363 sim_io_printf (sd, "*");
364}
365
366/* Print the simulator's execution speed for CPU. */
367
368static void
369profile_print_speed (sim_cpu *cpu)
370{
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);
2317a499 375 char comma_buf[20];
c967f187
DE
376
377 sim_io_printf (sd, "Simulator Execution Speed\n\n");
378
379 if (total != 0)
2317a499
DE
380 sim_io_printf (sd, " Total instructions: %s\n", COMMAS (total));
381
c967f187
DE
382 if (milliseconds < 1000)
383 sim_io_printf (sd, " Total Execution Time: < 1 second\n\n");
384 else
385 {
2317a499
DE
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);
c967f187 393 /* Don't confuse things with data that isn't useful.
2317a499 394 If we ran for less than 2 seconds, only use the data if we
c967f187 395 executed more than 100,000 insns. */
2317a499
DE
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)));
c967f187
DE
399 }
400}
401
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.
406
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.
410
411 Note that results are indented two spaces to distinguish them from
412 section titles. */
413
414void
415profile_print (SIM_DESC sd, int verbose,
416 PROFILE_CALLBACK *misc, PROFILE_CPU_CALLBACK *misc_cpu)
417{
418 int i,c;
419 int print_title_p = 0;
420
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'. */
424
425 for (c = 0; c < MAX_NR_PROCESSORS; ++c)
426 {
427 sim_cpu *cpu = STATE_CPU (sd, c);
428 PROFILE_DATA *data = CPU_PROFILE_DATA (cpu);
429
430 for (i = 0; i < MAX_PROFILE_VALUES; ++i)
431 if (PROFILE_FLAGS (data) [i])
432 print_title_p = 1;
433 /* One could break out early if print_title_p is set. */
434 }
435 if (print_title_p)
436 sim_io_printf (sd, "Summary profiling results:\n\n");
437
438 /* Loop, cpu by cpu, printing results. */
439
440 for (c = 0; c < MAX_NR_PROCESSORS; ++c)
441 {
442 sim_cpu *cpu = STATE_CPU (sd, c);
443 PROFILE_DATA *data = CPU_PROFILE_DATA (cpu);
444
445 if (MAX_NR_PROCESSORS > 1)
446 sim_io_printf (sd, "CPU %d\n\n", c);
447
448#if WITH_PROFILE_INSN_P
449 if (PROFILE_FLAGS (data) [PROFILE_INSN_IDX])
450 profile_print_insn (cpu, verbose);
451#endif
452
453#if WITH_PROFILE_MEMORY_P
454 if (PROFILE_FLAGS (data) [PROFILE_MEMORY_IDX])
455 profile_print_memory (cpu, verbose);
456#endif
457
458#if WITH_PROFILE_MODEL_P
459 if (PROFILE_FLAGS (data) [PROFILE_MODEL_IDX])
460 profile_print_model (cpu, verbose);
461#endif
462
463#if WITH_PROFILE_SCACHE_P && WITH_SCACHE
464 if (PROFILE_FLAGS (data) [PROFILE_SCACHE_IDX])
465 scache_print_profile (cpu, verbose);
466#endif
467
468 /* Print cpu-specific data before the execution speed. */
469 if (misc_cpu != NULL)
470 (*misc_cpu) (cpu, verbose);
471
472 /* Always try to print execution time and speed. */
473 if (verbose
474 || PROFILE_FLAGS (data) [PROFILE_INSN_IDX])
475 profile_print_speed (cpu);
476 }
477
478 /* Finally print non-cpu specific miscellaneous data. */
479
480 if (misc != NULL)
481 (*misc) (sd, verbose);
482}
This page took 0.049506 seconds and 4 git commands to generate.