2 Copyright (C) 2008 Grame & RTL
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as published by
6 the Free Software Foundation; either version 2.1 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 #include "JackEngineProfiling.h"
21 #include "JackGraphManager.h"
22 #include "JackClientControl.h"
23 #include "JackEngineControl.h"
24 #include "JackClientInterface.h"
25 #include "JackGlobals.h"
34 JackEngineProfiling::JackEngineProfiling():fAudioCycle(0),fMeasuredClient(0)
36 jack_info("Engine profiling activated, beware %ld MBytes are needed to record profiling points...", sizeof(fProfileTable
) / (1024 * 1024));
38 // Force memory page in
39 memset(fProfileTable
, 0, sizeof(fProfileTable
));
42 JackEngineProfiling::~JackEngineProfiling()
44 std::ofstream
fStream("JackEngineProfiling.log", std::ios_base::ate
);
45 jack_info("Write server and clients timing data...");
47 if (!fStream
.is_open()) {
48 jack_error("JackEngineProfiling::Save cannot open JackEngineProfiling.log file");
51 // For each measured point
52 for (int i
= 2; i
< TIME_POINTS
; i
++) {
54 // Driver timing values
55 long d1
= long(fProfileTable
[i
].fCurCycleBegin
- fProfileTable
[i
- 1].fCurCycleBegin
);
56 long d2
= long(fProfileTable
[i
].fPrevCycleEnd
- fProfileTable
[i
- 1].fCurCycleBegin
);
58 if (d1
<= 0 || fProfileTable
[i
].fAudioCycle
<= 0)
59 continue; // Skip non valid cycles
61 // Print driver delta and end cycle
62 fStream
<< d1
<< "\t" << d2
<< "\t";
64 // For each measured client
65 for (unsigned int j
= 0; j
< fMeasuredClient
; j
++) {
67 int ref
= fIntervalTable
[j
].fRefNum
;
69 // Is valid client cycle
70 if (fProfileTable
[i
].fClientTable
[ref
].fStatus
!= NotTriggered
) {
72 long d5
= long(fProfileTable
[i
].fClientTable
[ref
].fSignaledAt
- fProfileTable
[i
- 1].fCurCycleBegin
);
73 long d6
= long(fProfileTable
[i
].fClientTable
[ref
].fAwakeAt
- fProfileTable
[i
- 1].fCurCycleBegin
);
74 long d7
= long(fProfileTable
[i
].fClientTable
[ref
].fFinishedAt
- fProfileTable
[i
- 1].fCurCycleBegin
);
76 fStream
<< ref
<< "\t" ;
77 fStream
<< ((d5
> 0) ? d5
: 0) << "\t";
78 fStream
<< ((d6
> 0) ? d6
: 0) << "\t" ;
79 fStream
<< ((d7
> 0) ? d7
: 0) << "\t";
80 fStream
<< ((d6
> 0 && d5
> 0) ? (d6
- d5
) : 0) << "\t" ;
81 fStream
<< ((d7
> 0 && d6
> 0) ? (d7
- d6
) : 0) << "\t" ;
82 fStream
<< fProfileTable
[i
].fClientTable
[ref
].fStatus
<< "\t" ;;
84 } else { // Print tabs
85 fStream
<< "\t \t \t \t \t \t \t";
95 std::ofstream
fStream1("Timing1.plot", std::ios_base::ate
);
97 if (!fStream1
.is_open()) {
98 jack_error("JackEngineProfiling::Save cannot open Timing1.plot file");
101 fStream1
<< "set grid\n";
102 fStream1
<< "set title \"Audio driver timing\"\n";
103 fStream1
<< "set xlabel \"audio cycles\"\n";
104 fStream1
<< "set ylabel \"usec\"\n";
105 fStream1
<< "plot \"JackEngineProfiling.log\" using 1 title \"Audio period\" with lines \n";
107 fStream1
<< "set output 'Timing1.svg\n";
108 fStream1
<< "set terminal svg\n";
110 fStream1
<< "set grid\n";
111 fStream1
<< "set title \"Audio driver timing\"\n";
112 fStream1
<< "set xlabel \"audio cycles\"\n";
113 fStream1
<< "set ylabel \"usec\"\n";
114 fStream1
<< "plot \"JackEngineProfiling.log\" using 1 title \"Audio period\" with lines \n";
115 fStream1
<< "unset output\n";
119 std::ofstream
fStream2("Timing2.plot", std::ios_base::ate
);
121 if (!fStream2
.is_open()) {
122 jack_error("JackEngineProfiling::Save cannot open Timing2.plot file");
125 fStream2
<< "set grid\n";
126 fStream2
<< "set title \"Driver end date\"\n";
127 fStream2
<< "set xlabel \"audio cycles\"\n";
128 fStream2
<< "set ylabel \"usec\"\n";
129 fStream2
<< "plot \"JackEngineProfiling.log\" using 2 title \"Driver end date\" with lines \n";
131 fStream2
<< "set output 'Timing2.svg\n";
132 fStream2
<< "set terminal svg\n";
134 fStream2
<< "set grid\n";
135 fStream2
<< "set title \"Driver end date\"\n";
136 fStream2
<< "set xlabel \"audio cycles\"\n";
137 fStream2
<< "set ylabel \"usec\"\n";
138 fStream2
<< "plot \"JackEngineProfiling.log\" using 2 title \"Driver end date\" with lines \n";
139 fStream2
<< "unset output\n";
143 if (fMeasuredClient
> 0) {
144 std::ofstream
fStream3("Timing3.plot", std::ios_base::ate
);
146 if (!fStream3
.is_open()) {
147 jack_error("JackEngineProfiling::Save cannot open Timing3.plot file");
150 fStream3
<< "set multiplot\n";
151 fStream3
<< "set grid\n";
152 fStream3
<< "set title \"Clients end date\"\n";
153 fStream3
<< "set xlabel \"audio cycles\"\n";
154 fStream3
<< "set ylabel \"usec\"\n";
156 for (unsigned int i
= 0; i
< fMeasuredClient
; i
++) {
158 if (i
+ 1 == fMeasuredClient
) { // Last client
159 fStream3
<< "\"JackEngineProfiling.log\" using 1 title \"Audio period\" with lines,\"JackEngineProfiling.log\" using ";
160 fStream3
<< ((i
+ 1) * 7) - 1;
161 fStream3
<< " title \"" << fIntervalTable
[i
].fName
<< "\"with lines";
163 fStream3
<< "\"JackEngineProfiling.log\" using 1 title \"Audio period\" with lines,\"JackEngineProfiling.log\" using ";
164 fStream3
<< ((i
+ 1) * 7) - 1;
165 fStream3
<< " title \"" << fIntervalTable
[i
].fName
<< "\"with lines,";
167 } else if (i
+ 1 == fMeasuredClient
) { // Last client
168 fStream3
<< "\"JackEngineProfiling.log\" using " << ((i
+ 1) * 7) - 1 << " title \"" << fIntervalTable
[i
].fName
<< "\" with lines";
170 fStream3
<< "\"JackEngineProfiling.log\" using " << ((i
+ 1) * 7) - 1 << " title \"" << fIntervalTable
[i
].fName
<< "\" with lines,";
174 fStream3
<< "\n unset multiplot\n";
175 fStream3
<< "set output 'Timing3.svg\n";
176 fStream3
<< "set terminal svg\n";
178 fStream3
<< "set multiplot\n";
179 fStream3
<< "set grid\n";
180 fStream3
<< "set title \"Clients end date\"\n";
181 fStream3
<< "set xlabel \"audio cycles\"\n";
182 fStream3
<< "set ylabel \"usec\"\n";
184 for (unsigned int i
= 0; i
< fMeasuredClient
; i
++) {
186 if ((i
+ 1) == fMeasuredClient
) { // Last client
187 fStream3
<< "\"JackEngineProfiling.log\" using 1 title \"Audio period\" with lines,\"JackEngineProfiling.log\" using ";
188 fStream3
<< ((i
+ 1) * 7) - 1;
189 fStream3
<< " title \"" << fIntervalTable
[i
].fName
<< "\"with lines";
191 fStream3
<< "\"JackEngineProfiling.log\" using 1 title \"Audio period\" with lines,\"JackEngineProfiling.log\" using ";
192 fStream3
<< ((i
+ 1) * 7) - 1;
193 fStream3
<< " title \"" << fIntervalTable
[i
].fName
<< "\"with lines,";
195 } else if ((i
+ 1) == fMeasuredClient
) { // Last client
196 fStream3
<< "\"JackEngineProfiling.log\" using " << ((i
+ 1) * 7) - 1 << " title \"" << fIntervalTable
[i
].fName
<< "\" with lines";
198 fStream3
<< "\"JackEngineProfiling.log\" using " << ((i
+ 1) * 7) - 1 << " title \"" << fIntervalTable
[i
].fName
<< "\" with lines,";
201 fStream3
<< "\nunset multiplot\n";
202 fStream3
<< "unset output\n";
206 // Clients scheduling
207 if (fMeasuredClient
> 0) {
208 std::ofstream
fStream4("Timing4.plot", std::ios_base::ate
);
210 if (!fStream4
.is_open()) {
211 jack_error("JackEngineProfiling::Save cannot open Timing4.plot file");
214 fStream4
<< "set multiplot\n";
215 fStream4
<< "set grid\n";
216 fStream4
<< "set title \"Clients scheduling latency\"\n";
217 fStream4
<< "set xlabel \"audio cycles\"\n";
218 fStream4
<< "set ylabel \"usec\"\n";
220 for (unsigned int i
= 0; i
< fMeasuredClient
; i
++) {
221 if ((i
+ 1) == fMeasuredClient
) { // Last client
222 fStream4
<< "\"JackEngineProfiling.log\" using " << ((i
+ 1) * 7) << " title \"" << fIntervalTable
[i
].fName
<< "\" with lines";
224 fStream4
<< "\"JackEngineProfiling.log\" using " << ((i
+ 1) * 7) << " title \"" << fIntervalTable
[i
].fName
<< "\" with lines,";
228 fStream4
<< "\n unset multiplot\n";
229 fStream4
<< "set output 'Timing4.svg\n";
230 fStream4
<< "set terminal svg\n";
232 fStream4
<< "set multiplot\n";
233 fStream4
<< "set grid\n";
234 fStream4
<< "set title \"Clients scheduling latency\"\n";
235 fStream4
<< "set xlabel \"audio cycles\"\n";
236 fStream4
<< "set ylabel \"usec\"\n";
238 for (unsigned int i
= 0; i
< fMeasuredClient
; i
++) {
239 if ((i
+ 1) == fMeasuredClient
) { // Last client
240 fStream4
<< "\"JackEngineProfiling.log\" using " << ((i
+ 1) * 7) << " title \"" << fIntervalTable
[i
].fName
<< "\" with lines";
242 fStream4
<< "\"JackEngineProfiling.log\" using " << ((i
+ 1) * 7) << " title \"" << fIntervalTable
[i
].fName
<< "\" with lines,";
245 fStream4
<< "\nunset multiplot\n";
246 fStream4
<< "unset output\n";
251 if (fMeasuredClient
> 0) {
252 std::ofstream
fStream5("Timing5.plot", std::ios_base::ate
);
254 if (!fStream5
.is_open()) {
255 jack_error("JackEngineProfiling::Save cannot open Timing5.plot file");
258 fStream5
<< "set multiplot\n";
259 fStream5
<< "set grid\n";
260 fStream5
<< "set title \"Clients duration\"\n";
261 fStream5
<< "set xlabel \"audio cycles\"\n";
262 fStream5
<< "set ylabel \"usec\"\n";
264 for (unsigned int i
= 0; i
< fMeasuredClient
; i
++) {
265 if ((i
+ 1) == fMeasuredClient
) { // Last client
266 fStream5
<< "\"JackEngineProfiling.log\" using " << ((i
+ 1) * 7) + 1 << " title \"" << fIntervalTable
[i
].fName
<< "\" with lines";
268 fStream5
<< "\"JackEngineProfiling.log\" using " << ((i
+ 1) * 7) + 1 << " title \"" << fIntervalTable
[i
].fName
<< "\" with lines,";
272 fStream5
<< "\n unset multiplot\n";
273 fStream5
<< "set output 'Timing5.svg\n";
274 fStream5
<< "set terminal svg\n";
276 fStream5
<< "set multiplot\n";
277 fStream5
<< "set grid\n";
278 fStream5
<< "set title \"Clients duration\"\n";
279 fStream5
<< "set xlabel \"audio cycles\"\n";
280 fStream5
<< "set ylabel \"usec\"\n";
282 for (unsigned int i
= 0; i
< fMeasuredClient
; i
++) {
283 if ((i
+ 1) == fMeasuredClient
) {// Last client
284 fStream5
<< "\"JackEngineProfiling.log\" using " << ((i
+ 1) * 7) + 1 << " title \"" << fIntervalTable
[i
].fName
<< "\" with lines";
286 fStream5
<< "\"JackEngineProfiling.log\" using " << ((i
+ 1) * 7) + 1 << " title \"" << fIntervalTable
[i
].fName
<< "\" with lines,";
289 fStream5
<< "\nunset multiplot\n";
290 fStream5
<< "unset output\n";
294 std::ofstream
fStream6("Timings.html", std::ios_base::ate
);
295 if (!fStream6
.is_open()) {
296 jack_error("JackEngineProfiling::Save cannot open Timings.html file");
298 fStream6
<< "<?xml version='1.0' encoding='utf-8'?>\n";
299 fStream6
<< "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n";
300 fStream6
<< "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n";
301 fStream6
<< "<html xmlns='http://www.w3.org/1999/xhtml' lang='en'>\n";
302 fStream6
<< " <head>\n";
303 fStream6
<< " <title>JACK engine profiling</title>\n";
304 fStream6
<< " <!-- assuming that images are 600px wide -->\n";
305 fStream6
<< " <style media='all' type='text/css'>\n";
306 fStream6
<< " .center { margin-left:auto ; margin-right: auto; width: 650px; height: 550px }\n";
307 fStream6
<< " </style>\n";
308 fStream6
<< " </head>\n";
309 fStream6
<< " <body>\n";
310 fStream6
<< " <h2 style='text-align:center'>JACK engine profiling</h2>\n";
311 fStream6
<< " <div class='center'><object class='center' type='image/svg+xml' data='Timing1.svg'>Timing1</object></div>";
312 fStream6
<< " <div class='center'><object class='center' type='image/svg+xml' data='Timing2.svg'>Timing2</object></div>";
313 fStream6
<< " <div class='center'><object class='center' type='image/svg+xml' data='Timing3.svg'>Timing3</object></div>";
314 fStream6
<< " <div class='center'><object class='center' type='image/svg+xml' data='Timing4.svg'>Timing4</object></div>";
315 fStream6
<< " <div class='center'><object class='center' type='image/svg+xml' data='Timing5.svg'>Timing5</object></div>";
316 fStream6
<< " </body>\n";
317 fStream6
<< "</html>\n";
320 std::ofstream
fStream7("generate_timings", std::ios_base::ate
);
321 if (!fStream7
.is_open()) {
322 jack_error("JackEngineProfiling::Save cannot open generate_timings file");
324 fStream7
<< "gnuplot -persist Timing1.plot \n";
325 fStream7
<< "gnuplot -persist Timing2.plot\n";
326 fStream7
<< "gnuplot -persist Timing3.plot\n";
327 fStream7
<< "gnuplot -persist Timing4.plot\n";
328 fStream7
<< "gnuplot -persist Timing5.plot\n";
332 bool JackEngineProfiling::CheckClient(const char* name
, int cur_point
)
334 for (int i
= 0; i
< MEASURED_CLIENTS
; i
++) {
335 if (strcmp(fIntervalTable
[i
].fName
, name
) == 0) {
336 fIntervalTable
[i
].fEndInterval
= cur_point
;
343 void JackEngineProfiling::Profile(JackClientInterface
** table
,
344 JackGraphManager
* manager
,
345 jack_time_t period_usecs
,
346 jack_time_t cur_cycle_begin
,
347 jack_time_t prev_cycle_end
)
349 fAudioCycle
= (fAudioCycle
+ 1) % TIME_POINTS
;
352 fProfileTable
[fAudioCycle
].fPeriodUsecs
= period_usecs
;
353 fProfileTable
[fAudioCycle
].fCurCycleBegin
= cur_cycle_begin
;
354 fProfileTable
[fAudioCycle
].fPrevCycleEnd
= prev_cycle_end
;
355 fProfileTable
[fAudioCycle
].fAudioCycle
= fAudioCycle
;
357 for (int i
= GetEngineControl()->fDriverNum
; i
< CLIENT_NUM
; i
++) {
358 JackClientInterface
* client
= table
[i
];
359 JackClientTiming
* timing
= manager
->GetClientTiming(i
);
360 if (client
&& client
->GetClientControl()->fActive
&& client
->GetClientControl()->fCallback
[kRealTimeCallback
]) {
362 if (!CheckClient(client
->GetClientControl()->fName
, fAudioCycle
)) {
363 // Keep new measured client
364 fIntervalTable
[fMeasuredClient
].fRefNum
= i
;
365 strcpy(fIntervalTable
[fMeasuredClient
].fName
, client
->GetClientControl()->fName
);
366 fIntervalTable
[fMeasuredClient
].fBeginInterval
= fAudioCycle
;
367 fIntervalTable
[fMeasuredClient
].fEndInterval
= fAudioCycle
;
370 fProfileTable
[fAudioCycle
].fClientTable
[i
].fRefNum
= i
;
371 fProfileTable
[fAudioCycle
].fClientTable
[i
].fSignaledAt
= timing
->fSignaledAt
;
372 fProfileTable
[fAudioCycle
].fClientTable
[i
].fAwakeAt
= timing
->fAwakeAt
;
373 fProfileTable
[fAudioCycle
].fClientTable
[i
].fFinishedAt
= timing
->fFinishedAt
;
374 fProfileTable
[fAudioCycle
].fClientTable
[i
].fStatus
= timing
->fStatus
;
379 JackTimingMeasure
* JackEngineProfiling::GetCurMeasure()
381 return &fProfileTable
[fAudioCycle
];
384 } // end of namespace