1 /*
2 * Copyright 2005, 2016. Rene Rivera
3 * Distributed under the Boost Software License, Version 1.0.
4 * (See accompanying file LICENSE_1_0.txt or copy at
5 * http://www.boost.org/LICENSE_1_0.txt)
6 */
7
8 #include "jam.h"
9 #include "debug.h"
10 #include "output.h"
11 #include "hash.h"
12 #include <time.h>
13
14
15 static profile_frame * profile_stack = 0;
16 static struct hash * profile_hash = 0;
17 static profile_info profile_other = { 0 };
18 static profile_info profile_total = { 0 };
19
20
profile_init(OBJECT * rulename,profile_frame * frame)21 profile_frame * profile_init( OBJECT * rulename, profile_frame * frame )
22 {
23 if ( DEBUG_PROFILE ) profile_enter( rulename, frame );
24 return frame;
25 }
26
27
profile_enter(OBJECT * rulename,profile_frame * frame)28 void profile_enter( OBJECT * rulename, profile_frame * frame )
29 {
30 if ( DEBUG_PROFILE )
31 {
32 double start = profile_clock();
33 profile_info * p;
34
35 if ( !profile_hash && rulename )
36 profile_hash = hashinit( sizeof( profile_info ), "profile" );
37
38 if ( rulename )
39 {
40 int found;
41 p = (profile_info *)hash_insert( profile_hash, rulename, &found );
42 if ( !found )
43 {
44 p->name = rulename;
45 p->cumulative = 0;
46 p->net = 0;
47 p->num_entries = 0;
48 p->stack_count = 0;
49 p->memory = 0;
50 }
51 }
52 else
53 {
54 p = &profile_other;
55 }
56
57 p->num_entries += 1;
58 p->stack_count += 1;
59
60 frame->info = p;
61
62 frame->caller = profile_stack;
63 profile_stack = frame;
64
65 frame->entry_time = profile_clock();
66 frame->overhead = 0;
67 frame->subrules = 0;
68
69 /* caller pays for the time it takes to play with the hash table */
70 if ( frame->caller )
71 frame->caller->overhead += frame->entry_time - start;
72 }
73 }
74
75
profile_memory(long mem)76 void profile_memory( long mem )
77 {
78 if ( DEBUG_PROFILE )
79 if ( profile_stack && profile_stack->info )
80 profile_stack->info->memory += ((double)mem) / 1024;
81 }
82
83
profile_exit(profile_frame * frame)84 void profile_exit( profile_frame * frame )
85 {
86 if ( DEBUG_PROFILE )
87 {
88 /* Cumulative time for this call. */
89 double t = profile_clock() - frame->entry_time - frame->overhead;
90 /* If this rule is already present on the stack, do not add the time for
91 * this instance.
92 */
93 if ( frame->info->stack_count == 1 )
94 frame->info->cumulative += t;
95 /* Net time does not depend on presence of the same rule in call stack.
96 */
97 frame->info->net += t - frame->subrules;
98
99 if ( frame->caller )
100 {
101 /* Caller's cumulative time must account for this overhead. */
102 frame->caller->overhead += frame->overhead;
103 frame->caller->subrules += t;
104 }
105 /* Pop this stack frame. */
106 --frame->info->stack_count;
107 profile_stack = frame->caller;
108 }
109 }
110
111
dump_profile_entry(void * p_,void * ignored)112 static void dump_profile_entry( void * p_, void * ignored )
113 {
114 profile_info * p = (profile_info *)p_;
115 double mem_each = ( p->memory / ( p->num_entries ? p->num_entries : 1
116 ) );
117 double q = p->net;
118 if (p->num_entries) q /= p->num_entries;
119 if ( !ignored )
120 {
121 profile_total.cumulative += p->net;
122 profile_total.memory += p->memory;
123 }
124 out_printf( "%10ld %12.6f %12.6f %12.8f %10.2f %10.2f %s\n", p->num_entries,
125 p->cumulative, p->net, q, p->memory, mem_each, object_str( p->name ) );
126 }
127
128
profile_dump()129 void profile_dump()
130 {
131 if ( profile_hash )
132 {
133 out_printf( "%10s %12s %12s %12s %10s %10s %s\n", "--count--", "--gross--",
134 "--net--", "--each--", "--mem--", "--each--", "--name--" );
135 hashenumerate( profile_hash, dump_profile_entry, 0 );
136 profile_other.name = constant_other;
137 dump_profile_entry( &profile_other, 0 );
138 profile_total.name = constant_total;
139 dump_profile_entry( &profile_total, (void *)1 );
140 }
141 }
142
profile_clock()143 double profile_clock()
144 {
145 return ((double) clock()) / CLOCKS_PER_SEC;
146 }
147
profile_make_local(char const * scope)148 OBJECT * profile_make_local( char const * scope )
149 {
150 if ( DEBUG_PROFILE )
151 {
152 return object_new( scope );
153 }
154 else
155 {
156 return 0;
157 }
158 }
159