1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181#include <profiling/profile-internal.h>
182#include <vm/vm_kern.h>
183#include <stdlib.h>
184#include <string.h>
185
186#if defined(MACH_KERNEL) || defined(_KERNEL)
187
188#include <mach_assert.h>
189#if MACH_ASSERT && !defined(DEBUG_PROFILE)
190#define DEBUG_PROFILE 1
191#endif
192
193#else
194#include <assert.h>
195#define panic(str) exit(1)
196#endif
197
198#ifndef PROFILE_NUM_FUNCS
199#define PROFILE_NUM_FUNCS 2000
200#endif
201
202#ifndef PROFILE_NUM_ARCS
203#define PROFILE_NUM_ARCS 8000
204#endif
205
206
207
208
209
210extern int _profile_do_stats;
211extern size_t _profile_size;
212extern size_t _profile_stats_size;
213extern size_t _profile_md_size;
214extern size_t _profile_profil_size;
215extern size_t _profile_hash_size;
216
217
218
219
220
221struct profile_vars _profile_vars = { 0 };
222struct hasharc _gprof_dummy = { 0 };
223
224
225
226
227
228static void *_profile_md_acontext(struct profile_vars *pv,
229 void *ptr,
230 size_t len,
231 acontext_type_t type);
232
233static void _profile_reset_alloc(struct profile_vars *,
234 acontext_type_t);
235
236extern void _bogus_function(void);
237
238
239#if NCPUS > 1
240struct profile_vars *_profile_vars_cpus[NCPUS] = { &_profile_vars };
241struct profile_vars _profile_vars_aux[NCPUS-1];
242#define PROFILE_VARS(cpu) (_profile_vars_cpus[(cpu)])
243#else
244#define PROFILE_VARS(cpu) (&_profile_vars)
245#endif
246
247void *
248_profile_alloc_pages (size_t size)
249{
250 vm_offset_t addr;
251
252
253
254
255
256
257
258 if (PROFILE_VARS(0)->active) {
259 panic("Call to _profile_alloc_pages while profiling is running.");
260 }
261
262 if (kmem_alloc(kernel_map, &addr, size)) {
263 panic("Could not allocate memory for profiling");
264 }
265
266 memset((void *)addr, '\0', size);
267 if (PROFILE_VARS(0)->debug) {
268 printf("Allocated %d bytes for profiling, address 0x%x\n", (int)size, (int)addr);
269 }
270
271 return((caddr_t)addr);
272}
273
274void
275_profile_free_pages(void *addr, size_t size)
276{
277 if (PROFILE_VARS(0)->debug) {
278 printf("Freed %d bytes for profiling, address 0x%x\n", (int)size, (int)addr);
279 }
280
281 kmem_free(kernel_map, (vm_offset_t)addr, size);
282 return;
283}
284
285void _profile_error(struct profile_vars *pv)
286{
287 panic("Fatal error in profiling");
288}
289
290
291
292
293
294
295static void *
296_profile_md_acontext(struct profile_vars *pv,
297 void *ptr,
298 size_t len,
299 acontext_type_t type)
300{
301 struct memory {
302 struct alloc_context context;
303 struct page_list plist;
304 int data[1];
305 };
306
307 struct memory *mptr = (struct memory *)ptr;
308 struct alloc_context *context = &mptr->context;
309 struct page_list *plist = &mptr->plist;
310
311#ifdef DEBUG_PROFILE
312 _profile_printf("_profile_md_acontext: pv= 0x%lx, ptr= 0x%lx, len= %6ld, type= %d\n",
313 (long)pv,
314 (long)ptr,
315 (long)len,
316 (int)type);
317#endif
318
319
320 context->next = pv->acontext[type];
321 context->plist = plist;
322 context->lock = 0;
323
324
325 plist->ptr = plist->first = (void *)&mptr->data[0];
326 plist->next = (struct page_list *)0;
327 plist->bytes_free = len - ((char *)plist->ptr - (char *)ptr);
328 plist->bytes_allocated = 0;
329 plist->num_allocations = 0;
330
331
332 pv->stats.num_context[type]++;
333 pv->stats.wasted[type] += plist->bytes_free;
334 pv->stats.overhead[type] += len - plist->bytes_free;
335
336
337 pv->acontext[type] = context;
338
339 return (void *)((char *)ptr+len);
340}
341
342
343
344
345
346
347void
348_profile_md_init(struct profile_vars *pv,
349 profile_type_t type,
350 profile_alloc_mem_t alloc_mem)
351{
352 size_t page_size = pv->page_size;
353 size_t arc_size;
354 size_t func_size;
355 size_t misc_size;
356 size_t hash_size;
357 size_t extra_arc_size;
358 size_t extra_func_size;
359 size_t callback_size = page_size;
360 void *ptr;
361 acontext_type_t ac;
362 int i;
363 static struct {
364 size_t c_size;
365 size_t *asm_size_ptr;
366 const char *name;
367 } sizes[] = {
368 { sizeof(struct profile_profil), &_profile_profil_size, "profile_profil" },
369 { sizeof(struct profile_stats), &_profile_stats_size, "profile_stats" },
370 { sizeof(struct profile_md), &_profile_md_size, "profile_md" },
371 { sizeof(struct profile_vars), &_profile_size, "profile_vars" }};
372
373#ifdef DEBUG_PROFILE
374 _profile_printf("_profile_md_init: pv = 0x%lx, type = %d, alloc = %d\n",
375 (long) pv,
376 (int)type,
377 (int)alloc_mem);
378#endif
379
380 for (i = 0; i < sizeof (sizes) / sizeof(sizes[0]); i++) {
381 if (sizes[i].c_size != *sizes[i].asm_size_ptr) {
382 _profile_printf("C thinks struct %s is %ld bytes, asm thinks it is %ld bytes\n",
383 sizes[i].name,
384 (long)sizes[i].c_size,
385 (long)*sizes[i].asm_size_ptr);
386
387 panic(sizes[i].name);
388 }
389 }
390
391
392 if (type == PROFILE_GPROF) {
393 pv->md.save_mcount_ptr = _gprof_mcount;
394
395 } else if (type == PROFILE_PROF) {
396 pv->md.save_mcount_ptr = _prof_mcount;
397
398 } else {
399 pv->md.save_mcount_ptr = _dummy_mcount;
400 }
401
402 pv->vars_size = sizeof(struct profile_vars);
403 pv->plist_size = sizeof(struct page_list);
404 pv->acontext_size = sizeof(struct alloc_context);
405 pv->callback_size = sizeof(struct callback);
406 pv->major_version = PROFILE_MAJOR_VERSION;
407 pv->minor_version = PROFILE_MINOR_VERSION;
408 pv->type = type;
409 pv->do_profile = 1;
410 pv->use_dci = 1;
411 pv->use_profil = 1;
412 pv->output_uarea = 1;
413 pv->output_stats = (prof_flag_t) _profile_do_stats;
414 pv->output_clock = 1;
415 pv->multiple_sections = 1;
416 pv->init_format = 0;
417 pv->bogus_func = _bogus_function;
418
419#ifdef DEBUG_PROFILE
420 pv->debug = 1;
421#endif
422
423 if (!pv->error_msg) {
424 pv->error_msg = "error in profiling";
425 }
426
427 if (!pv->page_size) {
428 pv->page_size = 4096;
429 }
430
431 pv->stats.stats_size = sizeof(struct profile_stats);
432 pv->stats.major_version = PROFILE_MAJOR_VERSION;
433 pv->stats.minor_version = PROFILE_MINOR_VERSION;
434
435 pv->md.md_size = sizeof(struct profile_md);
436 pv->md.major_version = PROFILE_MAJOR_VERSION;
437 pv->md.minor_version = PROFILE_MINOR_VERSION;
438 pv->md.hash_size = _profile_hash_size;
439 pv->md.num_cache = MAX_CACHE;
440 pv->md.mcount_ptr_ptr = &_mcount_ptr;
441 pv->md.dummy_ptr = &_gprof_dummy;
442 pv->md.alloc_pages = _profile_alloc_pages;
443
444
445 for (ac = ACONTEXT_FIRST; ac < ACONTEXT_MAX; ac++) {
446 pv->acontext[ac] = (struct alloc_context *)0;
447 }
448
449
450 if (!alloc_mem) {
451 return;
452 }
453
454
455 switch (type) {
456 default:
457 misc_size = page_size;
458 ptr = _profile_alloc_pages(misc_size + callback_size);
459 ptr = _profile_md_acontext(pv, ptr, misc_size, ACONTEXT_MISC);
460 ptr = _profile_md_acontext(pv, ptr, callback_size, ACONTEXT_CALLBACK);
461 break;
462
463 case PROFILE_GPROF:
464
465#if defined(MACH_KERNEL) || defined(_KERNEL)
466
467
468
469
470
471
472
473
474 extra_arc_size = 4*page_size;
475 extra_func_size = 2*page_size;
476#else
477 extra_arc_size = extra_func_size = 0;
478#endif
479
480
481 arc_size = ROUNDUP(PROFILE_NUM_ARCS * sizeof(struct hasharc), page_size);
482 func_size = ROUNDUP(PROFILE_NUM_FUNCS * sizeof(struct gfuncs), page_size);
483 hash_size = _profile_hash_size * sizeof (struct hasharc *);
484 misc_size = ROUNDUP(hash_size + page_size, page_size);
485
486 ptr = _profile_alloc_pages(arc_size
487 + func_size
488 + misc_size
489 + callback_size
490 + extra_arc_size
491 + extra_func_size);
492
493#if defined(MACH_KERNEL) || defined(_KERNEL)
494 ptr = _profile_md_acontext(pv, ptr, extra_arc_size, ACONTEXT_GPROF);
495 ptr = _profile_md_acontext(pv, ptr, extra_func_size, ACONTEXT_GFUNC);
496#endif
497 ptr = _profile_md_acontext(pv, ptr, arc_size, ACONTEXT_GPROF);
498 ptr = _profile_md_acontext(pv, ptr, func_size, ACONTEXT_GFUNC);
499 ptr = _profile_md_acontext(pv, ptr, misc_size, ACONTEXT_MISC);
500 ptr = _profile_md_acontext(pv, ptr, callback_size, ACONTEXT_CALLBACK);
501
502
503 pv->md.hash_ptr = (struct hasharc **) _profile_alloc(pv, hash_size, ACONTEXT_MISC);
504 break;
505
506 case PROFILE_PROF:
507
508 func_size = ROUNDUP(PROFILE_NUM_FUNCS * sizeof(struct prof_ext), page_size);
509 misc_size = page_size;
510
511 ptr = _profile_alloc_pages(func_size
512 + misc_size
513 + callback_size);
514
515 ptr = _profile_md_acontext(pv, ptr, func_size, ACONTEXT_PROF);
516 ptr = _profile_md_acontext(pv, ptr, misc_size, ACONTEXT_MISC);
517 ptr = _profile_md_acontext(pv, ptr, callback_size, ACONTEXT_CALLBACK);
518 break;
519 }
520}
521
522
523
524
525
526
527int
528_profile_md_start(void)
529{
530 _mcount_ptr = _profile_vars.md.save_mcount_ptr;
531 return 0;
532}
533
534int
535_profile_md_stop(void)
536{
537 _mcount_ptr = _dummy_mcount;
538 return 0;
539}
540
541
542
543
544
545
546static void
547_profile_reset_alloc(struct profile_vars *pv, acontext_type_t ac)
548{
549 struct alloc_context *aptr;
550 struct page_list *plist;
551
552 for (aptr = pv->acontext[ac];
553 aptr != (struct alloc_context *)0;
554 aptr = aptr->next) {
555
556 for (plist = aptr->plist;
557 plist != (struct page_list *)0;
558 plist = plist->next) {
559
560 plist->ptr = plist->first;
561 plist->bytes_free += plist->bytes_allocated;
562 plist->bytes_allocated = 0;
563 plist->num_allocations = 0;
564 memset(plist->first, '\0', plist->bytes_allocated);
565 }
566 }
567}
568
569
570
571
572
573
574
575void
576_profile_reset(struct profile_vars *pv)
577{
578 struct alloc_context *aptr;
579 struct page_list *plist;
580 struct gfuncs *gfunc;
581
582 if (pv->active) {
583 _profile_md_stop();
584 }
585
586
587 for (aptr = pv->acontext[ACONTEXT_GFUNC];
588 aptr != (struct alloc_context *)0;
589 aptr = aptr->next) {
590
591 for (plist = aptr->plist;
592 plist != (struct page_list *)0;
593 plist = plist->next) {
594
595 for (gfunc = (struct gfuncs *)plist->first;
596 gfunc < (struct gfuncs *)plist->ptr;
597 gfunc++) {
598
599 *(gfunc->unique_ptr) = (struct hasharc *)0;
600 }
601 }
602 }
603
604
605 _profile_reset_alloc(pv, ACONTEXT_GPROF);
606 _profile_reset_alloc(pv, ACONTEXT_GFUNC);
607 _profile_reset_alloc(pv, ACONTEXT_PROF);
608
609 memset((void *)pv->profil_buf, '\0', pv->profil_info.profil_len);
610 memset((void *)pv->md.hash_ptr, '\0', pv->md.hash_size * sizeof(struct hasharc *));
611 memset((void *)&pv->stats, '\0', sizeof(pv->stats));
612
613 pv->stats.stats_size = sizeof(struct profile_stats);
614 pv->stats.major_version = PROFILE_MAJOR_VERSION;
615 pv->stats.minor_version = PROFILE_MINOR_VERSION;
616
617 if (pv->active) {
618 _profile_md_start();
619 }
620}
621
622
623
624
625
626
627size_t
628_gprof_write(struct profile_vars *pv, struct callback *callback_ptr)
629{
630 struct alloc_context *aptr;
631 struct page_list *plist;
632 size_t bytes = 0;
633 struct hasharc *hptr;
634 int i;
635
636 for (aptr = pv->acontext[ACONTEXT_GPROF];
637 aptr != (struct alloc_context *)0;
638 aptr = aptr->next) {
639
640 for (plist = aptr->plist; plist != (struct page_list *)0; plist = plist->next) {
641 hptr = (struct hasharc *)plist->first;
642 for (i = 0; i < plist->num_allocations; (i++, hptr++)) {
643
644 struct gprof_arc arc = hptr->arc;
645 int nrecs = 1 + (hptr->overflow * 2);
646 int j;
647
648 if (pv->check_funcs) {
649 if (arc.frompc < pv->profil_info.lowpc ||
650 arc.frompc > pv->profil_info.highpc) {
651
652 arc.frompc = (prof_uptrint_t)pv->bogus_func;
653 }
654
655 if (arc.selfpc < pv->profil_info.lowpc ||
656 arc.selfpc > pv->profil_info.highpc) {
657
658 arc.selfpc = (prof_uptrint_t)pv->bogus_func;
659 }
660 }
661
662
663
664 for (j = 0; j < nrecs; j++) {
665 bytes += sizeof (arc);
666 if ((*pv->fwrite_func)((void *)&arc,
667 sizeof(arc),
668 1,
669 pv->stream) != 1) {
670
671 _profile_error(pv);
672 }
673
674 arc.count = 0x80000000;
675 }
676 }
677 }
678 }
679
680 return bytes;
681}
682
683
684
685
686
687
688size_t
689_prof_write(struct profile_vars *pv, struct callback *callback_ptr)
690{
691 struct alloc_context *aptr;
692 struct page_list *plist;
693 size_t bytes = 0;
694 struct prof_ext prof_st;
695 struct prof_int *pptr;
696 struct gfuncs *gptr;
697 int nrecs;
698 int i, j;
699
700
701 for (aptr = pv->acontext[ACONTEXT_PROF];
702 aptr != (struct alloc_context *)0;
703 aptr = aptr->next) {
704
705 for (plist = aptr->plist; plist != (struct page_list *)0; plist = plist->next) {
706 pptr = (struct prof_int *)plist->first;
707
708 for (i = 0; i < plist->num_allocations; (i++, pptr++)) {
709
710
711
712 prof_st = pptr->prof;
713 nrecs = 1 + (pptr->overflow * 2);
714
715 for (j = 0; j < nrecs; j++) {
716 bytes += sizeof (struct prof_ext);
717 if ((*pv->fwrite_func)((void *)&prof_st,
718 sizeof(prof_st),
719 1,
720 pv->stream) != 1) {
721
722 _profile_error(pv);
723 }
724
725 prof_st.cncall = 0x80000000;
726 }
727 }
728 }
729 }
730
731
732 for (aptr = pv->acontext[ACONTEXT_GFUNC];
733 aptr != (struct alloc_context *)0;
734 aptr = aptr->next) {
735
736 for (plist = aptr->plist; plist != (struct page_list *)0; plist = plist->next) {
737 gptr = (struct gfuncs *)plist->first;
738
739 for (i = 0; i < plist->num_allocations; (i++, gptr++)) {
740
741
742
743 prof_st = gptr->prof.prof;
744 nrecs = 1 + (gptr->prof.overflow * 2);
745
746 for (j = 0; j < nrecs; j++) {
747 bytes += sizeof (struct prof_ext);
748 if ((*pv->fwrite_func)((void *)&prof_st,
749 sizeof(prof_st),
750 1,
751 pv->stream) != 1) {
752
753 _profile_error(pv);
754 }
755
756 prof_st.cncall = 0x80000000;
757 }
758 }
759 }
760 }
761
762 return bytes;
763}
764
765
766
767
768
769
770
771void
772_profile_update_stats(struct profile_vars *pv)
773{
774 struct alloc_context *aptr;
775 struct page_list *plist;
776 struct hasharc *hptr;
777 struct prof_int *pptr;
778 struct gfuncs *fptr;
779 LHISTCOUNTER *lptr;
780 int i;
781
782 for(i = 0; i < MAX_BUCKETS+1; i++) {
783 pv->stats.buckets[i] = 0;
784 }
785
786 pv->stats.hash_buckets = 0;
787
788 if (pv->md.hash_ptr) {
789 for (i = 0; i < pv->md.hash_size; i++) {
790 long nbuckets = 0;
791 struct hasharc *hptr;
792
793 for (hptr = pv->md.hash_ptr[i]; hptr; hptr = hptr->next) {
794 nbuckets++;
795 }
796
797 pv->stats.buckets[ (nbuckets < MAX_BUCKETS) ? nbuckets : MAX_BUCKETS ]++;
798 if (pv->stats.hash_buckets < nbuckets) {
799 pv->stats.hash_buckets = nbuckets;
800 }
801 }
802 }
803
804
805 if (pv->check_funcs) {
806 pv->stats.bogus_count = 0;
807
808 for (aptr = pv->acontext[ACONTEXT_GPROF];
809 aptr != (struct alloc_context *)0;
810 aptr = aptr->next) {
811
812 for (plist = aptr->plist;
813 plist != (struct page_list *)0;
814 plist = plist->next) {
815
816 hptr = (struct hasharc *)plist->first;
817 for (i = 0; i < plist->num_allocations; (i++, hptr++)) {
818
819 if (hptr->arc.frompc < pv->profil_info.lowpc ||
820 hptr->arc.frompc > pv->profil_info.highpc) {
821 pv->stats.bogus_count++;
822 }
823
824 if (hptr->arc.selfpc < pv->profil_info.lowpc ||
825 hptr->arc.selfpc > pv->profil_info.highpc) {
826 pv->stats.bogus_count++;
827 }
828 }
829 }
830 }
831 }
832
833
834 PROF_ULONG_TO_CNT(pv->stats.prof_overflow, 0);
835 PROF_ULONG_TO_CNT(pv->stats.gprof_overflow, 0);
836
837 for (aptr = pv->acontext[ACONTEXT_GPROF];
838 aptr != (struct alloc_context *)0;
839 aptr = aptr->next) {
840
841 for (plist = aptr->plist;
842 plist != (struct page_list *)0;
843 plist = plist->next) {
844
845 hptr = (struct hasharc *)plist->first;
846 for (i = 0; i < plist->num_allocations; (i++, hptr++)) {
847 PROF_CNT_ADD(pv->stats.gprof_overflow, hptr->overflow);
848 }
849 }
850 }
851
852 for (aptr = pv->acontext[ACONTEXT_PROF];
853 aptr != (struct alloc_context *)0;
854 aptr = aptr->next) {
855
856 for (plist = aptr->plist;
857 plist != (struct page_list *)0;
858 plist = plist->next) {
859
860 pptr = (struct prof_int *)plist->first;
861 for (i = 0; i < plist->num_allocations; (i++, pptr++)) {
862 PROF_CNT_ADD(pv->stats.prof_overflow, pptr->overflow);
863 }
864 }
865 }
866
867 for (aptr = pv->acontext[ACONTEXT_GFUNC];
868 aptr != (struct alloc_context *)0;
869 aptr = aptr->next) {
870
871 for (plist = aptr->plist;
872 plist != (struct page_list *)0;
873 plist = plist->next) {
874
875 fptr = (struct gfuncs *)plist->first;
876 for (i = 0; i < plist->num_allocations; (i++, fptr++)) {
877 PROF_CNT_ADD(pv->stats.prof_overflow, fptr->prof.overflow);
878 }
879 }
880 }
881
882
883 lptr = (LHISTCOUNTER *)pv->profil_buf;
884
885 if (pv->use_profil &&
886 pv->profil_info.counter_size == sizeof(LHISTCOUNTER) &&
887 lptr != (LHISTCOUNTER *)0) {
888
889 PROF_ULONG_TO_CNT(pv->stats.overflow_ticks, 0);
890 for (i = 0; i < pv->stats.profil_buckets; i++) {
891 PROF_CNT_ADD(pv->stats.overflow_ticks, lptr[i].high);
892 }
893 }
894}
895
896#if !defined(_KERNEL) && !defined(MACH_KERNEL)
897
898
899
900
901
902int _profile_debug(void)
903{
904 _profile_update_stats(&_profile_vars);
905 _profile_print_stats(stderr, &_profile_vars.stats, &_profile_vars.profil_info);
906 return 0;
907}
908
909
910
911
912
913void _profile_print_stats(FILE *stream,
914 const struct profile_stats *stats,
915 const struct profile_profil *pinfo)
916{
917 int i;
918 prof_cnt_t total_hits;
919 acontext_type_t ac;
920 int width_cname = 0;
921 int width_alloc = 0;
922 int width_wasted = 0;
923 int width_overhead = 0;
924 int width_context = 0;
925 static const char *cname[ACONTEXT_MAX] = ACONTEXT_NAMES;
926 char buf[20];
927
928 if (!stats) {
929 return;
930 }
931
932 if (!stream) {
933 stream = stdout;
934 }
935
936 sprintf(buf, "%ld.%ld", (long)stats->major_version, (long)stats->minor_version);
937 fprintf(stream, "%12s profiling version number\n", buf);
938 fprintf(stream, "%12lu size of profile_vars\n", (long unsigned)sizeof(struct profile_vars));
939 fprintf(stream, "%12lu size of profile_stats\n", (long unsigned)sizeof(struct profile_stats));
940 fprintf(stream, "%12lu size of profile_md\n", (long unsigned)sizeof(struct profile_md));
941 fprintf(stream, "%12s calls to _{,g}prof_mcount\n", PROF_CNT_TO_DECIMAL((char *)0, stats->cnt));
942 fprintf(stream, "%12s calls to old mcount\n", PROF_CNT_TO_DECIMAL((char *)0, stats->old_mcount));
943 fprintf(stream, "%12s calls to _dummy_mcount\n", PROF_CNT_TO_DECIMAL((char *)0, stats->dummy));
944 fprintf(stream, "%12lu functions profiled\n", (long unsigned)stats->prof_records);
945 fprintf(stream, "%12lu gprof arcs\n", (long unsigned)stats->gprof_records);
946
947 if (pinfo) {
948 fprintf(stream, "%12lu profil buckets\n", (long unsigned)stats->profil_buckets);
949 fprintf(stream, "%12lu profil lowpc [0x%lx]\n",
950 (long unsigned)pinfo->lowpc,
951 (long unsigned)pinfo->lowpc);
952
953 fprintf(stream, "%12lu profil highpc [0x%lx]\n",
954 (long unsigned)pinfo->highpc,
955 (long unsigned)pinfo->highpc);
956
957 fprintf(stream, "%12lu profil highpc-lowpc\n", (long unsigned)(pinfo->highpc - pinfo->lowpc));
958 fprintf(stream, "%12lu profil buffer length\n", (long unsigned)pinfo->profil_len);
959 fprintf(stream, "%12lu profil sizeof counters\n", (long unsigned)pinfo->counter_size);
960 fprintf(stream, "%12lu profil scale (%g)\n",
961 (long unsigned)pinfo->scale,
962 ((double)pinfo->scale) / ((double) 0x10000));
963
964
965 for (i = 0; i < sizeof (pinfo->profil_unused) / sizeof (pinfo->profil_unused[0]); i++) {
966 if (pinfo->profil_unused[i]) {
967 fprintf(stream, "%12lu profil unused[%2d] {0x%.8lx}\n",
968 (long unsigned)pinfo->profil_unused[i],
969 i,
970 (long unsigned)pinfo->profil_unused[i]);
971 }
972 }
973 }
974
975 if (stats->max_cpu) {
976 fprintf(stream, "%12lu current cpu/thread\n", (long unsigned)stats->my_cpu);
977 fprintf(stream, "%12lu max cpu/thread+1\n", (long unsigned)stats->max_cpu);
978 }
979
980 if (stats->bogus_count != 0) {
981 fprintf(stream,
982 "%12lu gprof functions found outside of range\n",
983 (long unsigned)stats->bogus_count);
984 }
985
986 if (PROF_CNT_NE_0(stats->too_low)) {
987 fprintf(stream,
988 "%12s histogram ticks were too low\n",
989 PROF_CNT_TO_DECIMAL((char *)0, stats->too_low));
990 }
991
992 if (PROF_CNT_NE_0(stats->too_high)) {
993 fprintf(stream,
994 "%12s histogram ticks were too high\n",
995 PROF_CNT_TO_DECIMAL((char *)0, stats->too_high));
996 }
997
998 if (PROF_CNT_NE_0(stats->acontext_locked)) {
999 fprintf(stream,
1000 "%12s times an allocation context was locked\n",
1001 PROF_CNT_TO_DECIMAL((char *)0, stats->acontext_locked));
1002 }
1003
1004 if (PROF_CNT_NE_0(stats->kernel_ticks)
1005 || PROF_CNT_NE_0(stats->user_ticks)
1006 || PROF_CNT_NE_0(stats->idle_ticks)) {
1007
1008 prof_cnt_t total_ticks;
1009 long double total_ticks_dbl;
1010
1011 total_ticks = stats->kernel_ticks;
1012 PROF_CNT_LADD(total_ticks, stats->user_ticks);
1013 PROF_CNT_LADD(total_ticks, stats->idle_ticks);
1014 total_ticks_dbl = PROF_CNT_TO_LDOUBLE(total_ticks);
1015
1016 fprintf(stream,
1017 "%12s total ticks\n",
1018 PROF_CNT_TO_DECIMAL((char *)0, total_ticks));
1019
1020 fprintf(stream,
1021 "%12s ticks within the kernel (%5.2Lf%%)\n",
1022 PROF_CNT_TO_DECIMAL((char *)0, stats->kernel_ticks),
1023 100.0L * (PROF_CNT_TO_LDOUBLE(stats->kernel_ticks) / total_ticks_dbl));
1024
1025 fprintf(stream,
1026 "%12s ticks within user space (%5.2Lf%%)\n",
1027 PROF_CNT_TO_DECIMAL((char *)0, stats->user_ticks),
1028 100.0L * (PROF_CNT_TO_LDOUBLE(stats->user_ticks) / total_ticks_dbl));
1029
1030 fprintf(stream,
1031 "%12s ticks idle (%5.2Lf%%)\n",
1032 PROF_CNT_TO_DECIMAL((char *)0, stats->idle_ticks),
1033 100.0L * (PROF_CNT_TO_LDOUBLE(stats->idle_ticks) / total_ticks_dbl));
1034 }
1035
1036 if (PROF_CNT_NE_0(stats->overflow_ticks)) {
1037 fprintf(stream, "%12s times a HISTCOUNTER counter would have overflowed\n",
1038 PROF_CNT_TO_DECIMAL((char *)0, stats->overflow_ticks));
1039 }
1040
1041 if (PROF_CNT_NE_0(stats->hash_num)) {
1042 long double total_buckets = 0.0L;
1043
1044 for (i = 0; i <= MAX_BUCKETS; i++) {
1045 total_buckets += (long double)stats->buckets[i];
1046 }
1047
1048 fprintf(stream, "%12lu max bucket(s) on hash chain.\n", (long unsigned)stats->hash_buckets);
1049 for (i = 0; i < MAX_BUCKETS; i++) {
1050 if (stats->buckets[i] != 0) {
1051 fprintf(stream, "%12lu bucket(s) had %d entries (%5.2Lf%%)\n",
1052 (long unsigned)stats->buckets[i], i,
1053 100.0L * ((long double)stats->buckets[i] / total_buckets));
1054 }
1055 }
1056
1057 if (stats->buckets[MAX_BUCKETS] != 0) {
1058 fprintf(stream, "%12lu bucket(s) had more than %d entries (%5.2Lf%%)\n",
1059 (long unsigned)stats->buckets[MAX_BUCKETS], MAX_BUCKETS,
1060 100.0L * ((long double)stats->buckets[MAX_BUCKETS] / total_buckets));
1061 }
1062 }
1063
1064 PROF_ULONG_TO_CNT(total_hits, 0);
1065 for (i = 0; i < MAX_CACHE; i++) {
1066 PROF_CNT_LADD(total_hits, stats->cache_hits[i]);
1067 }
1068
1069 if (PROF_CNT_NE_0(total_hits)) {
1070 long double total = PROF_CNT_TO_LDOUBLE(stats->cnt);
1071 long double total_hits_dbl = PROF_CNT_TO_LDOUBLE(total_hits);
1072
1073 fprintf(stream,
1074 "%12s cache hits (%.2Lf%%)\n",
1075 PROF_CNT_TO_DECIMAL((char *)0, total_hits),
1076 100.0L * (total_hits_dbl / total));
1077
1078 for (i = 0; i < MAX_CACHE; i++) {
1079 if (PROF_CNT_NE_0(stats->cache_hits[i])) {
1080 fprintf(stream,
1081 "%12s times cache#%d matched (%5.2Lf%% of cache hits, %5.2Lf%% total)\n",
1082 PROF_CNT_TO_DECIMAL((char *)0, stats->cache_hits[i]),
1083 i+1,
1084 100.0L * (PROF_CNT_TO_LDOUBLE(stats->cache_hits[i]) / total_hits_dbl),
1085 100.0L * (PROF_CNT_TO_LDOUBLE(stats->cache_hits[i]) / total));
1086 }
1087 }
1088
1089 if (PROF_CNT_NE_0(stats->hash_num)) {
1090 fprintf(stream, "%12s times hash table searched\n", PROF_CNT_TO_DECIMAL((char *)0, stats->hash_num));
1091 fprintf(stream, "%12s hash buckets searched\n", PROF_CNT_TO_DECIMAL((char *)0, stats->hash_search));
1092 fprintf(stream, "%12.4Lf average buckets searched\n",
1093 PROF_CNT_TO_LDOUBLE(stats->hash_search) / PROF_CNT_TO_LDOUBLE(stats->hash_num));
1094 }
1095 }
1096
1097 for (i = 0; i < sizeof (stats->stats_unused) / sizeof (stats->stats_unused[0]); i++) {
1098 if (PROF_CNT_NE_0(stats->stats_unused[i])) {
1099 fprintf(stream, "%12s unused[%2d] {0x%.8lx 0x%.8lx}\n",
1100 PROF_CNT_TO_DECIMAL((char *)0, stats->stats_unused[i]),
1101 i,
1102 (unsigned long)stats->stats_unused[i].high,
1103 (unsigned long)stats->stats_unused[i].low);
1104 }
1105 }
1106
1107
1108 for (ac = ACONTEXT_FIRST; ac < ACONTEXT_MAX; ac++) {
1109 int len;
1110
1111 if (stats->num_context[ac] == 0) {
1112 continue;
1113 }
1114
1115 len = strlen (cname[ac]);
1116 if (len > width_cname)
1117 width_cname = len;
1118
1119 len = sprintf (buf, "%lu", (long unsigned)stats->num_alloc[ac]);
1120 if (len > width_alloc)
1121 width_alloc = len;
1122
1123 len = sprintf (buf, "%lu", (long unsigned)stats->wasted[ac]);
1124 if (len > width_wasted)
1125 width_wasted = len;
1126
1127 len = sprintf (buf, "%lu", (long unsigned)stats->overhead[ac]);
1128 if (len > width_overhead)
1129 width_overhead = len;
1130
1131 len = sprintf (buf, "%lu", (long unsigned)stats->num_context[ac]);
1132 if (len > width_context)
1133 width_context = len;
1134 }
1135
1136
1137 for (ac = ACONTEXT_FIRST; ac < ACONTEXT_MAX; ac++) {
1138 if (stats->num_context[ac] == 0) {
1139 continue;
1140 }
1141
1142 fprintf (stream,
1143 "%12lu bytes in %-*s %*lu alloc, %*lu unused, %*lu over, %*lu context\n",
1144 (long unsigned)stats->bytes_alloc[ac],
1145 width_cname, cname[ac],
1146 width_alloc, (long unsigned)stats->num_alloc[ac],
1147 width_wasted, (long unsigned)stats->wasted[ac],
1148 width_overhead, (long unsigned)stats->overhead[ac],
1149 width_context, (long unsigned)stats->num_context[ac]);
1150 }
1151}
1152
1153
1154
1155
1156
1157
1158void _profile_merge_stats(struct profile_stats *old_stats, const struct profile_stats *new_stats)
1159{
1160 int i;
1161
1162
1163 if (!old_stats || !new_stats)
1164 return;
1165
1166
1167 if (old_stats->major_version == 0) {
1168 *old_stats = *new_stats;
1169
1170
1171 } else {
1172 if (old_stats->prof_records < new_stats->prof_records)
1173 old_stats->prof_records = new_stats->prof_records;
1174
1175 if (old_stats->gprof_records < new_stats->gprof_records)
1176 old_stats->gprof_records = new_stats->gprof_records;
1177
1178 if (old_stats->hash_buckets < new_stats->hash_buckets)
1179 old_stats->hash_buckets = new_stats->hash_buckets;
1180
1181 if (old_stats->bogus_count < new_stats->bogus_count)
1182 old_stats->bogus_count = new_stats->bogus_count;
1183
1184 PROF_CNT_LADD(old_stats->cnt, new_stats->cnt);
1185 PROF_CNT_LADD(old_stats->dummy, new_stats->dummy);
1186 PROF_CNT_LADD(old_stats->old_mcount, new_stats->old_mcount);
1187 PROF_CNT_LADD(old_stats->hash_search, new_stats->hash_search);
1188 PROF_CNT_LADD(old_stats->hash_num, new_stats->hash_num);
1189 PROF_CNT_LADD(old_stats->user_ticks, new_stats->user_ticks);
1190 PROF_CNT_LADD(old_stats->kernel_ticks, new_stats->kernel_ticks);
1191 PROF_CNT_LADD(old_stats->idle_ticks, new_stats->idle_ticks);
1192 PROF_CNT_LADD(old_stats->overflow_ticks, new_stats->overflow_ticks);
1193 PROF_CNT_LADD(old_stats->acontext_locked, new_stats->acontext_locked);
1194 PROF_CNT_LADD(old_stats->too_low, new_stats->too_low);
1195 PROF_CNT_LADD(old_stats->too_high, new_stats->too_high);
1196 PROF_CNT_LADD(old_stats->prof_overflow, new_stats->prof_overflow);
1197 PROF_CNT_LADD(old_stats->gprof_overflow, new_stats->gprof_overflow);
1198
1199 for (i = 0; i < (int)ACONTEXT_MAX; i++) {
1200 if (old_stats->num_alloc[i] < new_stats->num_alloc[i])
1201 old_stats->num_alloc[i] = new_stats->num_alloc[i];
1202
1203 if (old_stats->bytes_alloc[i] < new_stats->bytes_alloc[i])
1204 old_stats->bytes_alloc[i] = new_stats->bytes_alloc[i];
1205
1206 if (old_stats->num_context[i] < new_stats->num_context[i])
1207 old_stats->num_context[i] = new_stats->num_context[i];
1208
1209 if (old_stats->wasted[i] < new_stats->wasted[i])
1210 old_stats->wasted[i] = new_stats->wasted[i];
1211
1212 if (old_stats->overhead[i] < new_stats->overhead[i])
1213 old_stats->overhead[i] = new_stats->overhead[i];
1214
1215 }
1216
1217 for (i = 0; i < MAX_BUCKETS+1; i++) {
1218 if (old_stats->buckets[i] < new_stats->buckets[i])
1219 old_stats->buckets[i] = new_stats->buckets[i];
1220 }
1221
1222 for (i = 0; i < MAX_CACHE; i++) {
1223 PROF_CNT_LADD(old_stats->cache_hits[i], new_stats->cache_hits[i]);
1224 }
1225
1226 for (i = 0; i < sizeof(old_stats->stats_unused) / sizeof(old_stats->stats_unused[0]); i++) {
1227 PROF_CNT_LADD(old_stats->stats_unused[i], new_stats->stats_unused[i]);
1228 }
1229 }
1230}
1231
1232#endif
1233
1234
1235
1236
1237
1238
1239
1240
1241void
1242_bogus_function(void)
1243{
1244}
1245