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