00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "JackEngineProfiling.h"
00021 #include "JackGraphManager.h"
00022 #include "JackClientControl.h"
00023 #include "JackEngineControl.h"
00024 #include "JackClientInterface.h"
00025 #include "JackGlobals.h"
00026 #include "JackTime.h"
00027
00028 #include <iostream>
00029 #include <fstream>
00030
00031 namespace Jack
00032 {
00033
00034 JackEngineProfiling::JackEngineProfiling():fAudioCycle(0),fMeasuredClient(0)
00035 {
00036 jack_info("Engine profiling activated, beware %ld MBytes are needed to record profiling points...", sizeof(fProfileTable) / (1024 * 1024));
00037
00038
00039 memset(fProfileTable, 0, sizeof(fProfileTable));
00040 }
00041
00042 JackEngineProfiling::~JackEngineProfiling()
00043 {
00044 std::ofstream fStream("JackEngineProfiling.log", std::ios_base::ate);
00045 jack_info("Write server and clients timing data...");
00046
00047 if (!fStream.is_open()) {
00048 jack_error("JackEngineProfiling::Save cannot open JackEngineProfiling.log file");
00049 } else {
00050
00051
00052 for (int i = 2; i < TIME_POINTS; i++) {
00053
00054
00055 long d1 = long(fProfileTable[i].fCurCycleBegin - fProfileTable[i - 1].fCurCycleBegin);
00056 long d2 = long(fProfileTable[i].fPrevCycleEnd - fProfileTable[i - 1].fCurCycleBegin);
00057
00058 if (d1 <= 0 || fProfileTable[i].fAudioCycle <= 0)
00059 continue;
00060
00061
00062 fStream << d1 << "\t" << d2 << "\t";
00063
00064
00065 for (unsigned int j = 0; j < fMeasuredClient; j++) {
00066
00067 int ref = fIntervalTable[j].fRefNum;
00068
00069
00070 if (fProfileTable[i].fClientTable[ref].fStatus != NotTriggered) {
00071
00072 long d5 = long(fProfileTable[i].fClientTable[ref].fSignaledAt - fProfileTable[i - 1].fCurCycleBegin);
00073 long d6 = long(fProfileTable[i].fClientTable[ref].fAwakeAt - fProfileTable[i - 1].fCurCycleBegin);
00074 long d7 = long(fProfileTable[i].fClientTable[ref].fFinishedAt - fProfileTable[i - 1].fCurCycleBegin);
00075
00076 fStream << ref << "\t" ;
00077 fStream << ((d5 > 0) ? d5 : 0) << "\t";
00078 fStream << ((d6 > 0) ? d6 : 0) << "\t" ;
00079 fStream << ((d7 > 0) ? d7 : 0) << "\t";
00080 fStream << ((d6 > 0 && d5 > 0) ? (d6 - d5) : 0) << "\t" ;
00081 fStream << ((d7 > 0 && d6 > 0) ? (d7 - d6) : 0) << "\t" ;
00082 fStream << fProfileTable[i].fClientTable[ref].fStatus << "\t" ;;
00083
00084 } else {
00085 fStream << "\t \t \t \t \t \t \t";
00086 }
00087 }
00088
00089
00090 fStream << std::endl;
00091 }
00092 }
00093
00094
00095 std::ofstream fStream1("Timing1.plot", std::ios_base::ate);
00096
00097 if (!fStream1.is_open()) {
00098 jack_error("JackEngineProfiling::Save cannot open Timing1.plot file");
00099 } else {
00100
00101 fStream1 << "set grid\n";
00102 fStream1 << "set title \"Audio driver timing\"\n";
00103 fStream1 << "set xlabel \"audio cycles\"\n";
00104 fStream1 << "set ylabel \"usec\"\n";
00105 fStream1 << "plot \"JackEngineProfiling.log\" using 1 title \"Audio period\" with lines \n";
00106
00107 fStream1 << "set output 'Timing1.svg\n";
00108 fStream1 << "set terminal svg\n";
00109
00110 fStream1 << "set grid\n";
00111 fStream1 << "set title \"Audio driver timing\"\n";
00112 fStream1 << "set xlabel \"audio cycles\"\n";
00113 fStream1 << "set ylabel \"usec\"\n";
00114 fStream1 << "plot \"JackEngineProfiling.log\" using 1 title \"Audio period\" with lines \n";
00115 fStream1 << "unset output\n";
00116 }
00117
00118
00119 std::ofstream fStream2("Timing2.plot", std::ios_base::ate);
00120
00121 if (!fStream2.is_open()) {
00122 jack_error("JackEngineProfiling::Save cannot open Timing2.plot file");
00123 } else {
00124
00125 fStream2 << "set grid\n";
00126 fStream2 << "set title \"Driver end date\"\n";
00127 fStream2 << "set xlabel \"audio cycles\"\n";
00128 fStream2 << "set ylabel \"usec\"\n";
00129 fStream2 << "plot \"JackEngineProfiling.log\" using 2 title \"Driver end date\" with lines \n";
00130
00131 fStream2 << "set output 'Timing2.svg\n";
00132 fStream2 << "set terminal svg\n";
00133
00134 fStream2 << "set grid\n";
00135 fStream2 << "set title \"Driver end date\"\n";
00136 fStream2 << "set xlabel \"audio cycles\"\n";
00137 fStream2 << "set ylabel \"usec\"\n";
00138 fStream2 << "plot \"JackEngineProfiling.log\" using 2 title \"Driver end date\" with lines \n";
00139 fStream2 << "unset output\n";
00140 }
00141
00142
00143 if (fMeasuredClient > 0) {
00144 std::ofstream fStream3("Timing3.plot", std::ios_base::ate);
00145
00146 if (!fStream3.is_open()) {
00147 jack_error("JackEngineProfiling::Save cannot open Timing3.plot file");
00148 } else {
00149
00150 fStream3 << "set multiplot\n";
00151 fStream3 << "set grid\n";
00152 fStream3 << "set title \"Clients end date\"\n";
00153 fStream3 << "set xlabel \"audio cycles\"\n";
00154 fStream3 << "set ylabel \"usec\"\n";
00155 fStream3 << "plot ";
00156 for (unsigned int i = 0; i < fMeasuredClient; i++) {
00157 if (i == 0) {
00158 if (i + 1 == fMeasuredClient) {
00159 fStream3 << "\"JackEngineProfiling.log\" using 1 title \"Audio period\" with lines,\"JackEngineProfiling.log\" using ";
00160 fStream3 << ((i + 1) * 7) - 1;
00161 fStream3 << " title \"" << fIntervalTable[i].fName << "\"with lines";
00162 } else {
00163 fStream3 << "\"JackEngineProfiling.log\" using 1 title \"Audio period\" with lines,\"JackEngineProfiling.log\" using ";
00164 fStream3 << ((i + 1) * 7) - 1;
00165 fStream3 << " title \"" << fIntervalTable[i].fName << "\"with lines,";
00166 }
00167 } else if (i + 1 == fMeasuredClient) {
00168 fStream3 << "\"JackEngineProfiling.log\" using " << ((i + 1) * 7) - 1 << " title \"" << fIntervalTable[i].fName << "\" with lines";
00169 } else {
00170 fStream3 << "\"JackEngineProfiling.log\" using " << ((i + 1) * 7) - 1 << " title \"" << fIntervalTable[i].fName << "\" with lines,";
00171 }
00172 }
00173
00174 fStream3 << "\n unset multiplot\n";
00175 fStream3 << "set output 'Timing3.svg\n";
00176 fStream3 << "set terminal svg\n";
00177
00178 fStream3 << "set multiplot\n";
00179 fStream3 << "set grid\n";
00180 fStream3 << "set title \"Clients end date\"\n";
00181 fStream3 << "set xlabel \"audio cycles\"\n";
00182 fStream3 << "set ylabel \"usec\"\n";
00183 fStream3 << "plot ";
00184 for (unsigned int i = 0; i < fMeasuredClient; i++) {
00185 if (i == 0) {
00186 if ((i + 1) == fMeasuredClient) {
00187 fStream3 << "\"JackEngineProfiling.log\" using 1 title \"Audio period\" with lines,\"JackEngineProfiling.log\" using ";
00188 fStream3 << ((i + 1) * 7) - 1;
00189 fStream3 << " title \"" << fIntervalTable[i].fName << "\"with lines";
00190 } else {
00191 fStream3 << "\"JackEngineProfiling.log\" using 1 title \"Audio period\" with lines,\"JackEngineProfiling.log\" using ";
00192 fStream3 << ((i + 1) * 7) - 1;
00193 fStream3 << " title \"" << fIntervalTable[i].fName << "\"with lines,";
00194 }
00195 } else if ((i + 1) == fMeasuredClient) {
00196 fStream3 << "\"JackEngineProfiling.log\" using " << ((i + 1) * 7) - 1 << " title \"" << fIntervalTable[i].fName << "\" with lines";
00197 } else {
00198 fStream3 << "\"JackEngineProfiling.log\" using " << ((i + 1) * 7) - 1 << " title \"" << fIntervalTable[i].fName << "\" with lines,";
00199 }
00200 }
00201 fStream3 << "\nunset multiplot\n";
00202 fStream3 << "unset output\n";
00203 }
00204 }
00205
00206
00207 if (fMeasuredClient > 0) {
00208 std::ofstream fStream4("Timing4.plot", std::ios_base::ate);
00209
00210 if (!fStream4.is_open()) {
00211 jack_error("JackEngineProfiling::Save cannot open Timing4.plot file");
00212 } else {
00213
00214 fStream4 << "set multiplot\n";
00215 fStream4 << "set grid\n";
00216 fStream4 << "set title \"Clients scheduling latency\"\n";
00217 fStream4 << "set xlabel \"audio cycles\"\n";
00218 fStream4 << "set ylabel \"usec\"\n";
00219 fStream4 << "plot ";
00220 for (unsigned int i = 0; i < fMeasuredClient; i++) {
00221 if ((i + 1) == fMeasuredClient) {
00222 fStream4 << "\"JackEngineProfiling.log\" using " << ((i + 1) * 7) << " title \"" << fIntervalTable[i].fName << "\" with lines";
00223 } else {
00224 fStream4 << "\"JackEngineProfiling.log\" using " << ((i + 1) * 7) << " title \"" << fIntervalTable[i].fName << "\" with lines,";
00225 }
00226 }
00227
00228 fStream4 << "\n unset multiplot\n";
00229 fStream4 << "set output 'Timing4.svg\n";
00230 fStream4 << "set terminal svg\n";
00231
00232 fStream4 << "set multiplot\n";
00233 fStream4 << "set grid\n";
00234 fStream4 << "set title \"Clients scheduling latency\"\n";
00235 fStream4 << "set xlabel \"audio cycles\"\n";
00236 fStream4 << "set ylabel \"usec\"\n";
00237 fStream4 << "plot ";
00238 for (unsigned int i = 0; i < fMeasuredClient; i++) {
00239 if ((i + 1) == fMeasuredClient) {
00240 fStream4 << "\"JackEngineProfiling.log\" using " << ((i + 1) * 7) << " title \"" << fIntervalTable[i].fName << "\" with lines";
00241 } else {
00242 fStream4 << "\"JackEngineProfiling.log\" using " << ((i + 1) * 7) << " title \"" << fIntervalTable[i].fName << "\" with lines,";
00243 }
00244 }
00245 fStream4 << "\nunset multiplot\n";
00246 fStream4 << "unset output\n";
00247 }
00248 }
00249
00250
00251 if (fMeasuredClient > 0) {
00252 std::ofstream fStream5("Timing5.plot", std::ios_base::ate);
00253
00254 if (!fStream5.is_open()) {
00255 jack_error("JackEngineProfiling::Save cannot open Timing5.plot file");
00256 } else {
00257
00258 fStream5 << "set multiplot\n";
00259 fStream5 << "set grid\n";
00260 fStream5 << "set title \"Clients duration\"\n";
00261 fStream5 << "set xlabel \"audio cycles\"\n";
00262 fStream5 << "set ylabel \"usec\"\n";
00263 fStream5 << "plot ";
00264 for (unsigned int i = 0; i < fMeasuredClient; i++) {
00265 if ((i + 1) == fMeasuredClient) {
00266 fStream5 << "\"JackEngineProfiling.log\" using " << ((i + 1) * 7) + 1 << " title \"" << fIntervalTable[i].fName << "\" with lines";
00267 } else {
00268 fStream5 << "\"JackEngineProfiling.log\" using " << ((i + 1) * 7) + 1 << " title \"" << fIntervalTable[i].fName << "\" with lines,";
00269 }
00270 }
00271
00272 fStream5 << "\n unset multiplot\n";
00273 fStream5 << "set output 'Timing5.svg\n";
00274 fStream5 << "set terminal svg\n";
00275
00276 fStream5 << "set multiplot\n";
00277 fStream5 << "set grid\n";
00278 fStream5 << "set title \"Clients duration\"\n";
00279 fStream5 << "set xlabel \"audio cycles\"\n";
00280 fStream5 << "set ylabel \"usec\"\n";
00281 fStream5 << "plot ";
00282 for (unsigned int i = 0; i < fMeasuredClient; i++) {
00283 if ((i + 1) == fMeasuredClient) {
00284 fStream5 << "\"JackEngineProfiling.log\" using " << ((i + 1) * 7) + 1 << " title \"" << fIntervalTable[i].fName << "\" with lines";
00285 } else {
00286 fStream5 << "\"JackEngineProfiling.log\" using " << ((i + 1) * 7) + 1 << " title \"" << fIntervalTable[i].fName << "\" with lines,";
00287 }
00288 }
00289 fStream5 << "\nunset multiplot\n";
00290 fStream5 << "unset output\n";
00291 }
00292 }
00293
00294 std::ofstream fStream6("Timings.html", std::ios_base::ate);
00295 if (!fStream6.is_open()) {
00296 jack_error("JackEngineProfiling::Save cannot open Timings.html file");
00297 } else {
00298 fStream6 << "<?xml version='1.0' encoding='utf-8'?>\n";
00299 fStream6 << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n";
00300 fStream6 << "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n";
00301 fStream6 << "<html xmlns='http://www.w3.org/1999/xhtml' lang='en'>\n";
00302 fStream6 << " <head>\n";
00303 fStream6 << " <title>JACK engine profiling</title>\n";
00304 fStream6 << " <!-- assuming that images are 600px wide -->\n";
00305 fStream6 << " <style media='all' type='text/css'>\n";
00306 fStream6 << " .center { margin-left:auto ; margin-right: auto; width: 650px; height: 550px }\n";
00307 fStream6 << " </style>\n";
00308 fStream6 << " </head>\n";
00309 fStream6 << " <body>\n";
00310 fStream6 << " <h2 style='text-align:center'>JACK engine profiling</h2>\n";
00311 fStream6 << " <div class='center'><object class='center' type='image/svg+xml' data='Timing1.svg'>Timing1</object></div>";
00312 fStream6 << " <div class='center'><object class='center' type='image/svg+xml' data='Timing2.svg'>Timing2</object></div>";
00313 fStream6 << " <div class='center'><object class='center' type='image/svg+xml' data='Timing3.svg'>Timing3</object></div>";
00314 fStream6 << " <div class='center'><object class='center' type='image/svg+xml' data='Timing4.svg'>Timing4</object></div>";
00315 fStream6 << " <div class='center'><object class='center' type='image/svg+xml' data='Timing5.svg'>Timing5</object></div>";
00316 fStream6 << " </body>\n";
00317 fStream6 << "</html>\n";
00318 }
00319
00320 std::ofstream fStream7("generate_timings", std::ios_base::ate);
00321 if (!fStream7.is_open()) {
00322 jack_error("JackEngineProfiling::Save cannot open generate_timings file");
00323 } else {
00324 fStream7 << "gnuplot -persist Timing1.plot \n";
00325 fStream7 << "gnuplot -persist Timing2.plot\n";
00326 fStream7 << "gnuplot -persist Timing3.plot\n";
00327 fStream7 << "gnuplot -persist Timing4.plot\n";
00328 fStream7 << "gnuplot -persist Timing5.plot\n";
00329 }
00330 }
00331
00332 bool JackEngineProfiling::CheckClient(const char* name, int cur_point)
00333 {
00334 for (int i = 0; i < MEASURED_CLIENTS; i++) {
00335 if (strcmp(fIntervalTable[i].fName, name) == 0) {
00336 fIntervalTable[i].fEndInterval = cur_point;
00337 return true;
00338 }
00339 }
00340 return false;
00341 }
00342
00343 void JackEngineProfiling::Profile(JackClientInterface** table,
00344 JackGraphManager* manager,
00345 jack_time_t period_usecs,
00346 jack_time_t cur_cycle_begin,
00347 jack_time_t prev_cycle_end)
00348 {
00349 fAudioCycle = (fAudioCycle + 1) % TIME_POINTS;
00350
00351
00352 fProfileTable[fAudioCycle].fPeriodUsecs = period_usecs;
00353 fProfileTable[fAudioCycle].fCurCycleBegin = cur_cycle_begin;
00354 fProfileTable[fAudioCycle].fPrevCycleEnd = prev_cycle_end;
00355 fProfileTable[fAudioCycle].fAudioCycle = fAudioCycle;
00356
00357 for (int i = GetEngineControl()->fDriverNum; i < CLIENT_NUM; i++) {
00358 JackClientInterface* client = table[i];
00359 JackClientTiming* timing = manager->GetClientTiming(i);
00360 if (client && client->GetClientControl()->fActive && client->GetClientControl()->fCallback[kRealTimeCallback]) {
00361
00362 if (!CheckClient(client->GetClientControl()->fName, fAudioCycle)) {
00363
00364 fIntervalTable[fMeasuredClient].fRefNum = i;
00365 strcpy(fIntervalTable[fMeasuredClient].fName, client->GetClientControl()->fName);
00366 fIntervalTable[fMeasuredClient].fBeginInterval = fAudioCycle;
00367 fIntervalTable[fMeasuredClient].fEndInterval = fAudioCycle;
00368 fMeasuredClient++;
00369 }
00370 fProfileTable[fAudioCycle].fClientTable[i].fRefNum = i;
00371 fProfileTable[fAudioCycle].fClientTable[i].fSignaledAt = timing->fSignaledAt;
00372 fProfileTable[fAudioCycle].fClientTable[i].fAwakeAt = timing->fAwakeAt;
00373 fProfileTable[fAudioCycle].fClientTable[i].fFinishedAt = timing->fFinishedAt;
00374 fProfileTable[fAudioCycle].fClientTable[i].fStatus = timing->fStatus;
00375 }
00376 }
00377 }
00378
00379 JackTimingMeasure* JackEngineProfiling::GetCurMeasure()
00380 {
00381 return &fProfileTable[fAudioCycle];
00382 }
00383
00384 }