Jack2 1.9.6

JackEngineProfiling.cpp

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