add (copy of 2.0-ongoing) rubberband to 3.0
[ardour.git] / libs / rubberband / src / Profiler.cpp
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
2
3 /*
4     Rubber Band
5     An audio time-stretching and pitch-shifting library.
6     Copyright 2007-2008 Chris Cannam.
7     
8     This program is free software; you can redistribute it and/or
9     modify it under the terms of the GNU General Public License as
10     published by the Free Software Foundation; either version 2 of the
11     License, or (at your option) any later version.  See the file
12     COPYING included with this distribution for more information.
13 */
14
15 #include "Profiler.h"
16
17 #include <algorithm>
18 #include <set>
19 #include <string>
20 #include <map>
21
22 #include <cstdio>
23
24 namespace RubberBand {
25
26 #ifndef NO_TIMING
27
28 Profiler::ProfileMap
29 Profiler::m_profiles;
30
31 Profiler::WorstCallMap
32 Profiler::m_worstCalls;
33
34 void
35 Profiler::add(const char *id, float ms)
36 {
37     ProfileMap::iterator pmi = m_profiles.find(id);
38     if (pmi != m_profiles.end()) {
39         ++pmi->second.first;
40         pmi->second.second += ms;
41     } else {
42         m_profiles[id] = TimePair(1, ms);
43     }
44
45     WorstCallMap::iterator wci = m_worstCalls.find(id);
46     if (wci != m_worstCalls.end()) {
47         if (ms > wci->second) wci->second = ms;
48     } else {
49         m_worstCalls[id] = ms;
50     }
51 }
52
53 void
54 Profiler::dump()
55 {
56 #ifdef PROFILE_CLOCKS
57     fprintf(stderr, "Profiling points [CPU time]:\n");
58 #else
59     fprintf(stderr, "Profiling points [Wall time]:\n");
60 #endif
61
62     fprintf(stderr, "\nBy name:\n");
63
64     typedef std::set<const char *, std::less<std::string> > StringSet;
65
66     StringSet profileNames;
67     for (ProfileMap::const_iterator i = m_profiles.begin();
68          i != m_profiles.end(); ++i) {
69         profileNames.insert(i->first);
70     }
71
72     for (StringSet::const_iterator i = profileNames.begin();
73          i != profileNames.end(); ++i) {
74
75         ProfileMap::const_iterator j = m_profiles.find(*i);
76         if (j == m_profiles.end()) continue;
77
78         const TimePair &pp(j->second);
79         fprintf(stderr, "%s(%d):\n", *i, pp.first);
80         fprintf(stderr, "\tReal: \t%f ms      \t[%f ms total]\n",
81                 (pp.second / pp.first),
82                 (pp.second));
83
84         WorstCallMap::const_iterator k = m_worstCalls.find(*i);
85         if (k == m_worstCalls.end()) continue;
86         
87         fprintf(stderr, "\tWorst:\t%f ms/call\n", k->second);
88     }
89
90     typedef std::multimap<float, const char *> TimeRMap;
91     typedef std::multimap<int, const char *> IntRMap;
92     TimeRMap totmap, avgmap, worstmap;
93     IntRMap ncallmap;
94
95     for (ProfileMap::const_iterator i = m_profiles.begin();
96          i != m_profiles.end(); ++i) {
97         totmap.insert(TimeRMap::value_type(i->second.second, i->first));
98         avgmap.insert(TimeRMap::value_type(i->second.second /
99                                            i->second.first, i->first));
100         ncallmap.insert(IntRMap::value_type(i->second.first, i->first));
101     }
102
103     for (WorstCallMap::const_iterator i = m_worstCalls.begin();
104          i != m_worstCalls.end(); ++i) {
105         worstmap.insert(TimeRMap::value_type(i->second, i->first));
106     }
107
108     fprintf(stderr, "\nBy total:\n");
109     for (TimeRMap::const_iterator i = totmap.end(); i != totmap.begin(); ) {
110         --i;
111         fprintf(stderr, "%-40s  %f ms\n", i->second, i->first);
112     }
113
114     fprintf(stderr, "\nBy average:\n");
115     for (TimeRMap::const_iterator i = avgmap.end(); i != avgmap.begin(); ) {
116         --i;
117         fprintf(stderr, "%-40s  %f ms\n", i->second, i->first);
118     }
119
120     fprintf(stderr, "\nBy worst case:\n");
121     for (TimeRMap::const_iterator i = worstmap.end(); i != worstmap.begin(); ) {
122         --i;
123         fprintf(stderr, "%-40s  %f ms\n", i->second, i->first);
124     }
125
126     fprintf(stderr, "\nBy number of calls:\n");
127     for (IntRMap::const_iterator i = ncallmap.end(); i != ncallmap.begin(); ) {
128         --i;
129         fprintf(stderr, "%-40s  %d\n", i->second, i->first);
130     }
131 }
132
133 Profiler::Profiler(const char* c) :
134     m_c(c),
135     m_ended(false)
136 {
137 #ifdef PROFILE_CLOCKS
138     m_start = clock();
139 #else
140     (void)gettimeofday(&m_start, 0);
141 #endif
142 }
143
144 Profiler::~Profiler()
145 {
146     if (!m_ended) end();
147 }
148
149 void
150 Profiler::end()
151 {
152 #ifdef PROFILE_CLOCKS
153     clock_t end = clock();
154     clock_t elapsed = end - m_start;
155     float ms = float((double(elapsed) / double(CLOCKS_PER_SEC)) * 1000.0);
156 #else
157     struct timeval tv;
158     (void)gettimeofday(&tv, 0);
159
160     tv.tv_sec -= m_start.tv_sec;
161     if (tv.tv_usec < m_start.tv_usec) {
162         tv.tv_usec += 1000000;
163         tv.tv_sec -= 1;
164     }
165     tv.tv_usec -= m_start.tv_usec;
166     float ms = float((double(tv.tv_sec) + (double(tv.tv_usec) / 1000000.0)) * 1000.0);
167 #endif
168
169     add(m_c, ms);
170
171     m_ended = true;
172 }
173  
174 #endif
175
176 }