1 /*
2     This file is part of GNU APL, a free implementation of the
3     ISO/IEC Standard 13751, "Programming Language APL, Extended"
4 
5     Copyright (C) 2008-2015  Dr. Jürgen Sauermann
6 
7     This program is free software: you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation, either version 3 of the License, or
10     (at your option) any later version.
11 
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16 
17     You should have received a copy of the GNU General Public License
18     along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20 
21 #ifndef __PERFORMANCE_HH_DEFINED__
22 #define __PERFORMANCE_HH_DEFINED__
23 
24 #include <stdint.h>
25 
26 #include <iostream>
27 
28 #include "../config.h"
29 
30 #if defined(PERFORMANCE_COUNTERS_WANTED)
31 
32 # define PERFORMANCE_START(counter) const uint64_t counter = cycle_counter();
33 # define PERFORMANCE_END(statistics, counter, len) \
34    Performance::statistics.add_sample(cycle_counter() - counter, len);
35 # define CELL_PERFORMANCE_END(get_stat, counter, subseq)   \
36    { const uint64_t end = cycle_counter();                 \
37      CellFunctionStatistics * stat = get_stat;             \
38      if (stat)   stat->add_sample(end - counter, subseq); }
39 
40 #else
41 
42 # define PERFORMANCE_START(counter)
43 # define PERFORMANCE_END(statistics, counter, len)
44 # define CELL_PERFORMANCE_END(get_stat, counter, subseq)
45 
46 #endif
47 
48 using namespace std;
49 
50 //-----------------------------------------------------------------------------
51 /// performance statistics IDs
52 enum Pfstat_ID
53 {
54         PFS_MIN1 = 0,
55         PFS_MIN1_1 = PFS_MIN1 - 1,
56 #define perfo_1( id,  ab, name, _thr) PFS_ ## id ## ab,
57 #define perfo_2(_id, _ab, name, _thr)
58 #define perfo_3(_id, _ab, name, _thr)
59 #define perfo_4(_id, _ab, name, _thr)
60 #include "Performance.def"
61         PFS_MAX1,
62         PFS_MAX1_1 = PFS_MAX1 - 1,
63 
64         PFS_MIN2,
65         PFS_MIN2_1 = PFS_MIN2 - 1,
66 #define perfo_1(_id, _ab, name, _thr)
67 #define perfo_2( id,  ab, name, _thr) PFS_ ## id ## ab,
68 #define perfo_3(_id, _ab, name, _thr)
69 #define perfo_4(_id, _ab, name, _thr)
70 #include "Performance.def"
71         PFS_MAX2,
72         PFS_MAX2_1 = PFS_MAX2 - 1,
73 
74         PFS_MIN3,
75         PFS_MIN3_1 = PFS_MIN3 - 1,
76 #define perfo_1(_id, _ab, name, _thr)
77 #define perfo_2(_id, _ab, name, _thr)
78 #define perfo_3( id,  ab, name, _thr) PFS_ ## id ## ab,
79 #define perfo_4( id,  ab, name, _thr) PFS_ ## id ## ab,
80 #include "Performance.def"
81         PFS_MAX3,
82         PFS_MAX3_1 = PFS_MAX3 - 1,
83 
84         PFS_SCALAR_B_overhead,
85         PFS_SCALAR_AB_overhead,
86         PFS_ALL
87 };
88 //=============================================================================
89 /// one statistics for computing the mean and the variance of samples
90 class Statistics_record
91 {
92 public:
93    /// constructor
Statistics_record()94    Statistics_record()   { reset(); }
95 
96    /// constructor
Statistics_record(uint64_t cnt,uint64_t da,double da2)97    Statistics_record(uint64_t cnt, uint64_t da, double da2)
98    : count(cnt),
99      data(da),
100      data2(da2)
101    {}
102 
103    /// reset record to count 0, mean 0, variance 0
reset()104    void reset()
105       {
106         count = 0;
107         data = 0;
108         data2 = 0;
109       }
110 
111    /// add one sample
add_sample(uint64_t val)112    void add_sample(uint64_t val)
113       {
114         ++count;
115         data += val;
116         data2 += val*val;
117       }
118 
119    /// print count, data, and data2
120    void print(ostream & out);
121 
122    /// write count, data, and data2 to file
123    void save_record(ostream & outf);
124 
125    /// return the number of samples
get_count() const126    uint64_t get_count() const
127       { return count; }
128 
129    /// return the sum of samples
get_sum() const130    uint64_t get_sum() const
131       { return data; }
132 
133    /// return the average
get_average() const134    uint64_t get_average() const
135       { return average(data, count); }
136 
137    /// return the sum of squares
get_sum2() const138    double get_sum2() const
139       { return data2; }
140 
141    /// the average of \b count items with sum \b sum
average(uint64_t sum,uint64_t count)142    static uint64_t average(uint64_t sum, uint64_t count)
143       { return count ? sum/count : 0; }
144 
145    /// print num as 5 characters (digits, dot, and multiplier (k, m, g, ...)
146    static void print5(ostream & out, uint64_t num);
147 
148 protected:
149    /// number of samples
150    uint64_t count;
151 
152    /// sum of sample values
153    uint64_t data;
154 
155    /// sum of squares of sample values
156    double data2;   // can grow quickly!
157 };
158 //=============================================================================
159 /// Base class for different kinds of statistics
160 class Statistics
161 {
162 public:
163    /// constructor
Statistics(Pfstat_ID _id)164    Statistics(Pfstat_ID _id)
165   : id(_id)
166    {}
167 
168    /// destructor
169    virtual ~Statistics();
170 
171    /// print statistics
172    virtual void print(ostream & out) = 0;
173 
174    /// write statistics to file
175    virtual void save_data(ostream & outf, const char * perf_name) = 0;
176 
177    /// reset \b this statistics
178    virtual void reset() = 0;
179 
180    /// return the statistics for the first passes
get_first_record() const181    virtual const Statistics_record * get_first_record() const
182       { return 0; }
183 
184    /// return the statistics for the subsequent passes
get_record() const185    virtual const Statistics_record * get_record() const
186       { return 0; }
187 
188    /// return the name of \b this statistics
get_name() const189    const char * get_name() const
190       { return get_name(id); }
191 
192    /// return the name of the statistics with ID \b id
193    static const char * get_name(Pfstat_ID id);
194 
195 protected:
196    /// the ID of \b this statistics
197    const Pfstat_ID id;
198 };
199 //=============================================================================
200 /// Performance counters for an entire APL system function
201 class FunctionStatistics : public Statistics
202 {
203 public:
204    /// constructor: FunctionStatistics with ID \b id
FunctionStatistics(Pfstat_ID id)205    FunctionStatistics(Pfstat_ID id)
206    : Statistics(id)
207    { reset(); }
208 
209    /// overloaded Statistics::print()
reset()210    virtual void reset()
211         {
212           vec_cycles.reset();
213           vec_lengths.reset();
214         }
215 
216    /// overloaded Statistics::print()
217    virtual void print(ostream & out);
218 
219    /// overloaded Statistics::save_data()
220    virtual void save_data(ostream & outf, const char * perf_name);
221 
222    /// return the (CPU-)cycles statistics
get_record() const223    virtual const Statistics_record * get_record() const
224       { return &vec_cycles; }
225 
226    /// return the (CPU-)cycles statistics
get_data() const227    const Statistics_record & get_data() const
228       { return vec_cycles; }
229 
230    /// add a sample
add_sample(uint64_t cycles,uint64_t veclen)231    void add_sample(uint64_t cycles, uint64_t veclen)
232       {
233          vec_cycles.add_sample(cycles);
234          vec_lengths.add_sample(veclen);
235        }
236 
237 protected:
238    /// a statistics of vector lengths
239    Statistics_record vec_lengths;
240 
241    /// the cycles executed
242    Statistics_record vec_cycles;
243 };
244 //-----------------------------------------------------------------------------
245 /// Performance counters for one cell level function
246 class CellFunctionStatistics : public Statistics
247 {
248 public:
249    /// constructor: reset this statistics
CellFunctionStatistics(Pfstat_ID _id)250    CellFunctionStatistics(Pfstat_ID _id)
251    : Statistics(_id)
252    { reset(); }
253 
254    /// reset this statistics: clear \b first and \b subsequent records
reset()255    virtual void reset()
256         {
257           first.reset();
258           subsequent.reset();
259         }
260 
261    /// add a sample to \b this statistics
add_sample(uint64_t val,bool subseq)262    void add_sample(uint64_t val, bool subseq)
263       {
264          if (subseq)   subsequent.add_sample(val);
265          else          first.add_sample(val);
266        }
267 
268    /// overloaded Statistics::print()
269    virtual void print(ostream & out);
270 
271    /// overloaded Statistics::save_data()
272    virtual void save_data(ostream & outf, const char * perf_name);
273 
274    /// return the record for the first executions
get_first_record() const275    virtual const Statistics_record * get_first_record() const
276       { return  &first; }
277 
278    /// return the record for subsequent executions
get_record() const279    virtual const Statistics_record * get_record() const
280       { return  &subsequent; }
281 
282    /// return the cycles sum
get_sum() const283    uint64_t get_sum() const
284       { return first.get_sum() + subsequent.get_sum(); }
285 
286    /// return the square of cycles sums
get_sum2() const287    double get_sum2() const
288       { return first.get_sum2() + subsequent.get_sum2(); }
289 
290    /// return the number of first executions
get_count1() const291    uint64_t get_count1() const
292       { return first.get_count(); }
293 
294    /// return the number of subsequent executions
get_countN() const295    uint64_t get_countN() const
296       { return subsequent.get_count(); }
297 
298    /// return the number of all executions
get_count() const299    uint64_t get_count() const
300       { return first.get_count() + subsequent.get_count(); }
301 
302 protected:
303    /// statistics for first executions
304    Statistics_record first;
305 
306    /// statistics for subsequent executions
307    Statistics_record subsequent;
308 };
309 //=============================================================================
310 /**
311      Performance (cycle-) counters at different levels
312  **/
313 /// A class containing performance counters for several functions
314 class Performance
315 {
316 public:
317 
318    /// return statistics object for ID \b id
319    static Statistics * get_statistics(Pfstat_ID id);
320 
321    /// return statistics type of ID \b id
322    static int get_statistics_type(Pfstat_ID id);
323 
324    /// print all counters
325    static void print(Pfstat_ID which, ostream & out);
326 
327    /// write all counters to .def file
328    static void save_data(ostream & out, ostream & out_file);
329 
330    /// reset all counters
331    static void reset_all();
332 
333 #define perfo_1(id, ab, name, thr)                   \
334    /** monadic cell function statistics **/          \
335    static CellFunctionStatistics cfs_ ## id ## ab;   \
336    /** monadic parallel executionthreshold **/       \
337    static const ShapeItem thresh_ ## id ## ab = thr;
338 
339 #define perfo_2(id, ab, name, thr)                   \
340    /** dyadic cell function statistics **/           \
341    static CellFunctionStatistics cfs_ ## id ## ab;   \
342    /** dyadic parallel executionthreshold **/        \
343    static const ShapeItem thresh_ ## id ## ab = thr;
344 
345 #define perfo_3(id, ab, name, thr)                   \
346    /** function statistics **/                       \
347    static FunctionStatistics fs_ ## id ## ab;
348 
349 #define perfo_4(id, ab, name, thr)                   \
350    /** function statistics **/                       \
351    static FunctionStatistics fs_ ## id ## ab;
352 
353 #include "Performance.def"
354 };
355 
356 #endif // __PERFORMANCE_HH_DEFINED__
357