1# Read the source files and output the statistics #defines plus the
2# initialize and refresh code.
3
4import re, string, sys, textwrap
5from dist import compare_srcfile
6
7# Read the source files.
8from stat_data import groups, dsrc_stats, connection_stats, join_stats
9
10def print_struct(title, name, base, stats):
11    '''Print the structures for the stat.h file.'''
12    f.write('/*\n')
13    f.write(' * Statistics entries for ' + title + '.\n')
14    f.write(' */\n')
15    f.write('#define\tWT_' + name.upper() + '_STATS_BASE\t' + str(base) + '\n')
16    f.write('struct __wt_' + name + '_stats {\n')
17
18    for l in stats:
19        f.write('\tint64_t ' + l.name + ';\n')
20    f.write('};\n\n')
21
22# Update the #defines in the stat.h file.
23tmp_file = '__tmp'
24f = open(tmp_file, 'w')
25skip = 0
26for line in open('../src/include/stat.h', 'r'):
27    if not skip:
28        f.write(line)
29    if line.count('Statistics section: END'):
30        f.write(line)
31        skip = 0
32    elif line.count('Statistics section: BEGIN'):
33        f.write('\n')
34        skip = 1
35        print_struct(
36            'connections', 'connection', 1000, connection_stats)
37        print_struct('data sources', 'dsrc', 2000, dsrc_stats)
38        print_struct('join cursors', 'join', 3000, join_stats)
39f.close()
40compare_srcfile(tmp_file, '../src/include/stat.h')
41
42def print_defines_one(capname, base, stats):
43    for v, l in enumerate(stats, base):
44        desc = l.desc
45        if 'cache_walk' in l.flags:
46            desc += \
47                ', only reported if cache_walk or all statistics are enabled'
48        if 'tree_walk' in l.flags:
49            desc += ', only reported if tree_walk or all statistics are enabled'
50        if len(textwrap.wrap(desc, 70)) > 1:
51            f.write('/*!\n')
52            f.write(' * %s\n' % '\n * '.join(textwrap.wrap(desc, 70)))
53            f.write(' */\n')
54        else:
55            f.write('/*! %s */\n' % desc)
56        #f.write('/*! %s */\n' % '\n * '.join(textwrap.wrap(desc, 70)))
57        f.write('#define\tWT_STAT_' + capname + '_' + l.name.upper() + "\t" *
58            max(1, 6 - int((len('WT_STAT_' + capname + '_' + l.name)) / 8)) +
59            str(v) + '\n')
60
61def print_defines():
62    '''Print the #defines for the wiredtiger.in file.'''
63    f.write('''
64/*!
65 * @name Connection statistics
66 * @anchor statistics_keys
67 * @anchor statistics_conn
68 * Statistics are accessed through cursors with \c "statistics:" URIs.
69 * Individual statistics can be queried through the cursor using the following
70 * keys.  See @ref data_statistics for more information.
71 * @{
72 */
73''')
74    print_defines_one('CONN', 1000, connection_stats)
75    f.write('''
76/*!
77 * @}
78 * @name Statistics for data sources
79 * @anchor statistics_dsrc
80 * @{
81 */
82''')
83    print_defines_one('DSRC', 2000, dsrc_stats)
84    f.write('''
85/*!
86 * @}
87 * @name Statistics for join cursors
88 * @anchor statistics_join
89 * @{
90 */
91''')
92    print_defines_one('JOIN', 3000, join_stats)
93    f.write('/*! @} */\n')
94
95# Update the #defines in the wiredtiger.in file.
96tmp_file = '__tmp'
97f = open(tmp_file, 'w')
98skip = 0
99for line in open('../src/include/wiredtiger.in', 'r'):
100    if not skip:
101        f.write(line)
102    if line.count('Statistics section: END'):
103        f.write(line)
104        skip = 0
105    elif line.count('Statistics section: BEGIN'):
106        f.write(' */\n')
107        skip = 1
108        print_defines()
109        f.write('/*\n')
110f.close()
111compare_srcfile(tmp_file, '../src/include/wiredtiger.in')
112
113def print_func(name, handle, statlist):
114    '''Print the structures/functions for the stat.c file.'''
115    f.write('\n')
116    f.write('static const char * const __stats_' + name + '_desc[] = {\n')
117    for l in statlist:
118        f.write('\t"' + l.desc + '",\n')
119    f.write('};\n')
120
121    f.write('''
122int
123__wt_stat_''' + name + '''_desc(WT_CURSOR_STAT *cst, int slot, const char **p)
124{
125\tWT_UNUSED(cst);
126\t*p = __stats_''' + name + '''_desc[slot];
127\treturn (0);
128}
129''')
130
131    f.write('''
132void
133__wt_stat_''' + name + '_init_single(WT_' + name.upper() + '''_STATS *stats)
134{
135\tmemset(stats, 0, sizeof(*stats));
136}
137''')
138
139    if handle != None:
140        f.write('''
141int
142__wt_stat_''' + name + '''_init(
143    WT_SESSION_IMPL *session, ''' + handle + ''' *handle)
144{
145\tint i;
146
147\tWT_RET(__wt_calloc(session, (size_t)WT_COUNTER_SLOTS,
148\t    sizeof(*handle->stat_array), &handle->stat_array));
149
150\tfor (i = 0; i < WT_COUNTER_SLOTS; ++i) {
151\t\thandle->stats[i] = &handle->stat_array[i];
152\t\t__wt_stat_''' + name + '''_init_single(handle->stats[i]);
153\t}
154\treturn (0);
155}
156
157void
158__wt_stat_''' + name + '''_discard(
159    WT_SESSION_IMPL *session, ''' + handle + ''' *handle)
160{
161\t__wt_free(session, handle->stat_array);
162}
163''')
164
165    f.write('''
166void
167__wt_stat_''' + name + '_clear_single(WT_' + name.upper() + '''_STATS *stats)
168{
169''')
170    for l in statlist:
171        # no_clear: don't clear the value.
172        if 'no_clear' in l.flags:
173            f.write('\t\t/* not clearing ' + l.name + ' */\n')
174        else:
175            f.write('\tstats->' + l.name + ' = 0;\n')
176    f.write('}\n')
177
178    f.write('''
179void
180__wt_stat_''' + name + '_clear_all(WT_' + name.upper() + '''_STATS **stats)
181{
182\tu_int i;
183
184\tfor (i = 0; i < WT_COUNTER_SLOTS; ++i)
185\t\t__wt_stat_''' + name + '''_clear_single(stats[i]);
186}
187''')
188
189    # Single structure aggregation is currently only used by data sources.
190    if name == 'dsrc':
191        f.write('''
192void
193__wt_stat_''' + name + '''_aggregate_single(
194    WT_''' + name.upper() + '_STATS *from, WT_' + name.upper() + '''_STATS *to)
195{
196''')
197        for l in statlist:
198            if 'max_aggregate' in l.flags:
199                o = '\tif (from->' + l.name + ' > to->' + l.name + ')\n' +\
200                    '\t\tto->' + l.name + ' = from->' + l.name + ';\n'
201            else:
202                o = '\tto->' + l.name + ' += from->' + l.name + ';\n'
203                if len(o) > 72:         # Account for the leading tab.
204                    o = o.replace(' += ', ' +=\n\t    ')
205            f.write(o)
206        f.write('}\n')
207
208    f.write('''
209void
210__wt_stat_''' + name + '''_aggregate(
211    WT_''' + name.upper() + '_STATS **from, WT_' + name.upper() + '''_STATS *to)
212{
213''')
214    # Connection level aggregation does not currently have any computation
215    # of a maximum value; I'm leaving in support for it, but don't declare
216    # a temporary variable until it's needed.
217    for l in statlist:
218        if 'max_aggregate' in l.flags:
219            f.write('\tint64_t v;\n\n')
220            break;
221    for l in statlist:
222        if 'max_aggregate' in l.flags:
223            o = '\tif ((v = WT_STAT_READ(from, ' + l.name + ')) > ' +\
224                'to->' + l.name + ')\n'
225            if len(o) > 72:             # Account for the leading tab.
226                o = o.replace(' > ', ' >\n\t    ')
227            o +='\t\tto->' + l.name + ' = v;\n'
228        else:
229            o = '\tto->' + l.name + ' += WT_STAT_READ(from, ' + l.name + ');\n'
230            if len(o) > 72:             # Account for the leading tab.
231                o = o.replace(' += ', ' +=\n\t    ')
232        f.write(o)
233    f.write('}\n')
234
235# Write the stat initialization and refresh routines to the stat.c file.
236f = open(tmp_file, 'w')
237f.write('/* DO NOT EDIT: automatically built by dist/stat.py. */\n\n')
238f.write('#include "wt_internal.h"\n')
239
240print_func('dsrc', 'WT_DATA_HANDLE', dsrc_stats)
241print_func('connection', 'WT_CONNECTION_IMPL', connection_stats)
242print_func('join', None, join_stats)
243f.close()
244compare_srcfile(tmp_file, '../src/support/stat.c')
245