Jack2 1.9.6
|
00001 /* 00002 Copyright (C) 2008 Grame & RTL 00003 00004 This program is free software; you can redistribute it and/or modify 00005 it under the terms of the GNU Lesser General Public License as published by 00006 the Free Software Foundation; either version 2.1 of the License, or 00007 (at your option) any later version. 00008 00009 This program is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 GNU Lesser General Public License for more details. 00013 00014 You should have received a copy of the GNU Lesser General Public License 00015 along with this program; if not, write to the Free Software 00016 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 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 // Force memory page in 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 // For each measured point 00052 for (int i = 2; i < TIME_POINTS; i++) { 00053 00054 // Driver timing values 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; // Skip non valid cycles 00060 00061 // Print driver delta and end cycle 00062 fStream << d1 << "\t" << d2 << "\t"; 00063 00064 // For each measured client 00065 for (unsigned int j = 0; j < fMeasuredClient; j++) { 00066 00067 int ref = fIntervalTable[j].fRefNum; 00068 00069 // Is valid client cycle 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 { // Print tabs 00085 fStream << "\t \t \t \t \t \t \t"; 00086 } 00087 } 00088 00089 // Terminate line 00090 fStream << std::endl; 00091 } 00092 } 00093 00094 // Driver period 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 // Driver end date 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 // Clients end date 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) { // Last client 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) { // Last client 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) { // Last client 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) { // Last client 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 // Clients scheduling 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) { // Last client 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) { // Last client 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 // Clients duration 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) { // Last client 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) {// Last client 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 // Keeps cycle data 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 // Keep new measured client 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 } // end of namespace