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"
31 JackEngineProfiling::JackEngineProfiling():fAudioCycle(0),fMeasuredClient(0)
33 jack_info("Engine profiling activated, beware %ld MBytes are needed to record profiling points...", sizeof(fProfileTable
) / (1024 * 1024));
35 // Force memory page in
36 memset(fProfileTable
, 0, sizeof(fProfileTable
));
39 JackEngineProfiling::~JackEngineProfiling()
41 FILE* file
= fopen("JackEngineProfiling.log", "w");
44 jack_info("Write server and clients timing data...");
47 jack_error("JackEngineProfiling::Save cannot open JackEngineProfiling.log file");
50 // For each measured point
51 for (int i
= 2; i
< TIME_POINTS
; i
++) {
53 // Driver timing values
54 long d1
= long(fProfileTable
[i
].fCurCycleBegin
- fProfileTable
[i
- 1].fCurCycleBegin
);
55 long d2
= long(fProfileTable
[i
].fPrevCycleEnd
- fProfileTable
[i
- 1].fCurCycleBegin
);
57 if (d1
<= 0 || fProfileTable
[i
].fAudioCycle
<= 0)
58 continue; // Skip non valid cycles
60 // Print driver delta and end cycle
61 fprintf(file
, "%ld \t %ld \t", d1
, d2
);
63 // For each measured client
64 for (unsigned int j
= 0; j
< fMeasuredClient
; j
++) {
66 int ref
= fIntervalTable
[j
].fRefNum
;
68 // Is valid client cycle
69 if (fProfileTable
[i
].fClientTable
[ref
].fStatus
!= NotTriggered
) {
71 long d5
= long(fProfileTable
[i
].fClientTable
[ref
].fSignaledAt
- fProfileTable
[i
- 1].fCurCycleBegin
);
72 long d6
= long(fProfileTable
[i
].fClientTable
[ref
].fAwakeAt
- fProfileTable
[i
- 1].fCurCycleBegin
);
73 long d7
= long(fProfileTable
[i
].fClientTable
[ref
].fFinishedAt
- fProfileTable
[i
- 1].fCurCycleBegin
);
75 // Print ref, signal, start, end, scheduling, duration, status
76 fprintf(file
, "%d \t %ld \t %ld \t %ld \t %ld \t %ld \t %d \t",
81 ((d6
> 0 && d5
> 0) ? (d6
- d5
) : 0),
82 ((d7
> 0 && d6
> 0) ? (d7
- d6
) : 0),
83 fProfileTable
[i
].fClientTable
[ref
].fStatus
);
84 } else { // Print tabs
85 fprintf(file
, "\t \t \t \t \t \t \t");
95 file
= fopen("Timing1.plot", "w");
98 jack_error("JackEngineProfiling::Save cannot open Timing1.log file");
101 fprintf(file
, "set grid\n");
102 fprintf(file
, "set title \"Audio driver timing\"\n");
103 fprintf(file
, "set xlabel \"audio cycles\"\n");
104 fprintf(file
, "set ylabel \"usec\"\n");
105 fprintf(file
, "plot \"JackEngineProfiling.log\" using 1 title \"Audio period\" with lines \n");
107 fprintf(file
, "set output 'Timing1.pdf\n");
108 fprintf(file
, "set terminal pdf\n");
110 fprintf(file
, "set grid\n");
111 fprintf(file
, "set title \"Audio driver timing\"\n");
112 fprintf(file
, "set xlabel \"audio cycles\"\n");
113 fprintf(file
, "set ylabel \"usec\"\n");
114 fprintf(file
, "plot \"JackEngineProfiling.log\" using 1 title \"Audio period\" with lines \n");
120 file
= fopen("Timing2.plot", "w");
123 jack_error("JackEngineProfiling::Save cannot open Timing2.log file");
126 fprintf(file
, "set grid\n");
127 fprintf(file
, "set title \"Driver end date\"\n");
128 fprintf(file
, "set xlabel \"audio cycles\"\n");
129 fprintf(file
, "set ylabel \"usec\"\n");
130 fprintf(file
, "plot \"JackEngineProfiling.log\" using 2 title \"Driver end date\" with lines \n");
132 fprintf(file
, "set output 'Timing2.pdf\n");
133 fprintf(file
, "set terminal pdf\n");
135 fprintf(file
, "set grid\n");
136 fprintf(file
, "set title \"Driver end date\"\n");
137 fprintf(file
, "set xlabel \"audio cycles\"\n");
138 fprintf(file
, "set ylabel \"usec\"\n");
139 fprintf(file
, "plot \"JackEngineProfiling.log\" using 2 title \"Driver end date\" with lines \n");
145 if (fMeasuredClient
> 0) {
146 file
= fopen("Timing3.plot", "w");
148 jack_error("JackEngineProfiling::Save cannot open Timing3.log file");
151 fprintf(file
, "set multiplot\n");
152 fprintf(file
, "set grid\n");
153 fprintf(file
, "set title \"Clients end date\"\n");
154 fprintf(file
, "set xlabel \"audio cycles\"\n");
155 fprintf(file
, "set ylabel \"usec\"\n");
156 fprintf(file
, "plot ");
157 for (unsigned int i
= 0; i
< fMeasuredClient
; i
++) {
159 if (i
+ 1 == fMeasuredClient
) { // Last client
160 sprintf(buffer
, "\"JackEngineProfiling.log\" using 1 title \"Audio period\" with lines,\"JackEngineProfiling.log\" using %d title \"%s\" with lines",
161 ((i
+ 1) * 7) - 1 , fIntervalTable
[i
].fName
);
163 sprintf(buffer
, "\"JackEngineProfiling.log\" using 1 title \"Audio period\" with lines,\"JackEngineProfiling.log\" using %d title \"%s\" with lines,",
164 ((i
+ 1) * 7) - 1 , fIntervalTable
[i
].fName
);
166 } else if (i
+ 1 == fMeasuredClient
) { // Last client
167 sprintf(buffer
, "\"JackEngineProfiling.log\" using %d title \"%s\" with lines", ((i
+ 1) * 7) - 1 , fIntervalTable
[i
].fName
);
169 sprintf(buffer
, "\"JackEngineProfiling.log\" using %d title \"%s\" with lines,", ((i
+ 1) * 7) - 1, fIntervalTable
[i
].fName
);
171 fprintf(file
, buffer
);
174 fprintf(file
, "\n unset multiplot\n");
175 fprintf(file
, "set output 'Timing3.pdf\n");
176 fprintf(file
, "set terminal pdf\n");
178 fprintf(file
, "set multiplot\n");
179 fprintf(file
, "set grid\n");
180 fprintf(file
, "set title \"Clients end date\"\n");
181 fprintf(file
, "set xlabel \"audio cycles\"\n");
182 fprintf(file
, "set ylabel \"usec\"\n");
183 fprintf(file
, "plot ");
184 for (unsigned int i
= 0; i
< fMeasuredClient
; i
++) {
186 if ((i
+ 1) == fMeasuredClient
) { // Last client
187 sprintf(buffer
, "\"JackEngineProfiling.log\" using 1 title \"Audio period\" with lines,\"JackEngineProfiling.log\" using %d title \"%s\" with lines",
188 ((i
+ 1) * 7) - 1 , fIntervalTable
[i
].fName
);
190 sprintf(buffer
, "\"JackEngineProfiling.log\" using 1 title \"Audio period\" with lines,\"JackEngineProfiling.log\" using %d title \"%s\" with lines,",
191 ((i
+ 1) * 7) - 1 , fIntervalTable
[i
].fName
);
193 } else if ((i
+ 1) == fMeasuredClient
) { // Last client
194 sprintf(buffer
, "\"JackEngineProfiling.log\" using %d title \"%s\" with lines", ((i
+ 1) * 7) - 1 , fIntervalTable
[i
].fName
);
196 sprintf(buffer
, "\"JackEngineProfiling.log\" using %d title \"%s\" with lines,", ((i
+ 1) * 7) - 1, fIntervalTable
[i
].fName
);
198 fprintf(file
, buffer
);
205 // Clients scheduling
206 if (fMeasuredClient
> 0) {
207 file
= fopen("Timing4.plot", "w");
210 jack_error("JackEngineProfiling::Save cannot open Timing4.log file");
213 fprintf(file
, "set multiplot\n");
214 fprintf(file
, "set grid\n");
215 fprintf(file
, "set title \"Clients scheduling latency\"\n");
216 fprintf(file
, "set xlabel \"audio cycles\"\n");
217 fprintf(file
, "set ylabel \"usec\"\n");
218 fprintf(file
, "plot ");
219 for (unsigned int i
= 0; i
< fMeasuredClient
; i
++) {
220 if ((i
+ 1) == fMeasuredClient
) // Last client
221 sprintf(buffer
, "\"JackEngineProfiling.log\" using %d title \"%s\" with lines", ((i
+ 1) * 7), fIntervalTable
[i
].fName
);
223 sprintf(buffer
, "\"JackEngineProfiling.log\" using %d title \"%s\" with lines,", ((i
+ 1) * 7), fIntervalTable
[i
].fName
);
224 fprintf(file
, buffer
);
227 fprintf(file
, "\n unset multiplot\n");
228 fprintf(file
, "set output 'Timing4.pdf\n");
229 fprintf(file
, "set terminal pdf\n");
231 fprintf(file
, "set multiplot\n");
232 fprintf(file
, "set grid\n");
233 fprintf(file
, "set title \"Clients scheduling latency\"\n");
234 fprintf(file
, "set xlabel \"audio cycles\"\n");
235 fprintf(file
, "set ylabel \"usec\"\n");
236 fprintf(file
, "plot ");
237 for (unsigned int i
= 0; i
< fMeasuredClient
; i
++) {
238 if ((i
+ 1) == fMeasuredClient
) // Last client
239 sprintf(buffer
, "\"JackEngineProfiling.log\" using %d title \"%s\" with lines", ((i
+ 1) * 7), fIntervalTable
[i
].fName
);
241 sprintf(buffer
, "\"JackEngineProfiling.log\" using %d title \"%s\" with lines,", ((i
+ 1) * 7), fIntervalTable
[i
].fName
);
242 fprintf(file
, buffer
);
249 if (fMeasuredClient
> 0) {
250 file
= fopen("Timing5.plot", "w");
253 jack_error("JackEngineProfiling::Save cannot open Timing5.log file");
256 fprintf(file
, "set multiplot\n");
257 fprintf(file
, "set grid\n");
258 fprintf(file
, "set title \"Clients duration\"\n");
259 fprintf(file
, "set xlabel \"audio cycles\"\n");
260 fprintf(file
, "set ylabel \"usec\"\n");
261 fprintf(file
, "plot ");
262 for (unsigned int i
= 0; i
< fMeasuredClient
; i
++) {
263 if ((i
+ 1) == fMeasuredClient
) // Last client
264 sprintf(buffer
, "\"JackEngineProfiling.log\" using %d title \"%s\" with lines", ((i
+ 1) * 7) + 1, fIntervalTable
[i
].fName
);
266 sprintf(buffer
, "\"JackEngineProfiling.log\" using %d title \"%s\" with lines,", ((i
+ 1) * 7) + 1, fIntervalTable
[i
].fName
);
267 fprintf(file
, buffer
);
270 fprintf(file
, "\n unset multiplot\n");
271 fprintf(file
, "set output 'Timing5.pdf\n");
272 fprintf(file
, "set terminal pdf\n");
274 fprintf(file
, "set multiplot\n");
275 fprintf(file
, "set grid\n");
276 fprintf(file
, "set title \"Clients duration\"\n");
277 fprintf(file
, "set xlabel \"audio cycles\"\n");
278 fprintf(file
, "set ylabel \"usec\"\n");
279 fprintf(file
, "plot ");
280 for (unsigned int i
= 0; i
< fMeasuredClient
; i
++) {
281 if ((i
+ 1) == fMeasuredClient
) // Last client
282 sprintf(buffer
, "\"JackEngineProfiling.log\" using %d title \"%s\" with lines", ((i
+ 1) * 7) + 1, fIntervalTable
[i
].fName
);
284 sprintf(buffer
, "\"JackEngineProfiling.log\" using %d title \"%s\" with lines,", ((i
+ 1) * 7) + 1, fIntervalTable
[i
].fName
);
285 fprintf(file
, buffer
);
292 bool JackEngineProfiling::CheckClient(const char* name
, int cur_point
)
294 for (int i
= 0; i
< MEASURED_CLIENTS
; i
++) {
295 if (strcmp(fIntervalTable
[i
].fName
, name
) == 0) {
296 fIntervalTable
[i
].fEndInterval
= cur_point
;
303 void JackEngineProfiling::Profile(JackClientInterface
** table
,
304 JackGraphManager
* manager
,
305 jack_time_t period_usecs
,
306 jack_time_t cur_cycle_begin
,
307 jack_time_t prev_cycle_end
)
309 fAudioCycle
= (fAudioCycle
+ 1) % TIME_POINTS
;
312 fProfileTable
[fAudioCycle
].fPeriodUsecs
= period_usecs
;
313 fProfileTable
[fAudioCycle
].fCurCycleBegin
= cur_cycle_begin
;
314 fProfileTable
[fAudioCycle
].fPrevCycleEnd
= prev_cycle_end
;
315 fProfileTable
[fAudioCycle
].fAudioCycle
= fAudioCycle
;
317 for (int i
= GetEngineControl()->fDriverNum
; i
< CLIENT_NUM
; i
++) {
318 JackClientInterface
* client
= table
[i
];
319 JackClientTiming
* timing
= manager
->GetClientTiming(i
);
320 if (client
&& client
->GetClientControl()->fActive
&& client
->GetClientControl()->fCallback
[kRealTimeCallback
]) {
322 if (!CheckClient(client
->GetClientControl()->fName
, fAudioCycle
)) {
323 // Keep new measured client
324 fIntervalTable
[fMeasuredClient
].fRefNum
= i
;
325 strcpy(fIntervalTable
[fMeasuredClient
].fName
, client
->GetClientControl()->fName
);
326 fIntervalTable
[fMeasuredClient
].fBeginInterval
= fAudioCycle
;
327 fIntervalTable
[fMeasuredClient
].fEndInterval
= fAudioCycle
;
330 fProfileTable
[fAudioCycle
].fClientTable
[i
].fRefNum
= i
;
331 fProfileTable
[fAudioCycle
].fClientTable
[i
].fSignaledAt
= timing
->fSignaledAt
;
332 fProfileTable
[fAudioCycle
].fClientTable
[i
].fAwakeAt
= timing
->fAwakeAt
;
333 fProfileTable
[fAudioCycle
].fClientTable
[i
].fFinishedAt
= timing
->fFinishedAt
;
334 fProfileTable
[fAudioCycle
].fClientTable
[i
].fStatus
= timing
->fStatus
;
339 JackTimingMeasure
* JackEngineProfiling::GetCurMeasure()
341 return &fProfileTable
[fAudioCycle
];
344 } // end of namespace