Jack2 1.9.6

JackProfiler.cpp

00001 /*
00002 Copyright (C) 2009 Grame
00003 
00004 This program is free software; you can redistribute it and/or modify
00005 it under the terms of the GNU General Public License as published by
00006 the Free Software Foundation; either version 2 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 General Public License for more details.
00013 
00014 You should have received a copy of the GNU General Public License
00015 along with this program; if not, write to the Free Software
00016 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00017 */
00018 
00019 #include "JackProfiler.h"
00020 #include "JackServerGlobals.h"
00021 #include "JackEngineControl.h"
00022 #include "JackLockedEngine.h"
00023 #include "JackArgParser.h"
00024 #include <assert.h>
00025 #include <string>
00026 
00027 namespace Jack
00028 {
00029 
00030     JackProfilerClient::JackProfilerClient(jack_client_t* client, const char* name)
00031         :fClient(client)
00032     {
00033         char port_name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
00034         fRefNum = JackServerGlobals::fInstance->GetEngine()->GetClientRefNum(name);
00035         
00036         snprintf(port_name, sizeof(port_name) - 1, "%s:scheduling", name);
00037         fSchedulingPort = jack_port_register(client, port_name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
00038         
00039         snprintf(port_name, sizeof(port_name) - 1, "%s:duration", name);
00040         fDurationPort = jack_port_register(client, port_name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
00041     }
00042     
00043     JackProfilerClient::~JackProfilerClient()
00044     {
00045         jack_port_unregister(fClient, fSchedulingPort);
00046         jack_port_unregister(fClient, fDurationPort);
00047     }
00048     
00049 #ifdef JACK_MONITOR
00050     JackProfiler::JackProfiler(jack_client_t* client, const JSList* params)
00051         :fClient(client), fLastMeasure(NULL)
00052 #else
00053     JackProfiler::JackProfiler(jack_client_t* client, const JSList* params)
00054         :fClient(client)
00055 #endif
00056     {
00057         jack_log("JackProfiler::JackProfiler");
00058         
00059         fCPULoadPort = fDriverPeriodPort = fDriverEndPort = NULL;
00060       
00061         const JSList* node;
00062         const jack_driver_param_t* param;
00063         for (node = params; node; node = jack_slist_next(node)) {
00064             param = (const jack_driver_param_t*)node->data;
00065             
00066             switch (param->character) {
00067                 case 'c':
00068                     fCPULoadPort = jack_port_register(client, "cpu_load", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
00069                     break;
00070                     
00071                 case 'p':
00072                     fDriverPeriodPort = jack_port_register(client, "driver_period", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
00073                     break;
00074                      
00075                 case 'e':
00076                     fDriverEndPort = jack_port_register(client, "driver_end_time", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
00077                     break;
00078             }
00079         }
00080        
00081         // Resigster all running clients
00082         const char **ports = jack_get_ports(client, NULL, NULL, 0);
00083         if (ports) {
00084             for (int i = 0; ports[i]; ++i) {
00085                 std::string str = std::string(ports[i]);
00086                 ClientRegistration(str.substr(0, str.find_first_of(':')).c_str(), 1, this);
00087             }
00088             free(ports);
00089         }
00090      
00091         jack_set_process_callback(client, Process, this);
00092         jack_set_client_registration_callback(client, ClientRegistration, this);
00093         jack_activate(client);
00094     }
00095 
00096     JackProfiler::~JackProfiler()
00097     {
00098         jack_log("JackProfiler::~JackProfiler");
00099     }
00100     
00101     void JackProfiler::ClientRegistration(const char* name, int val, void *arg)
00102     {
00103     #ifdef JACK_MONITOR
00104         JackProfiler* profiler = static_cast<JackProfiler*>(arg);
00105         
00106         // Filter client or "system" name
00107         if (strcmp(name, jack_get_client_name(profiler->fClient)) == 0 || strcmp(name, "system") == 0)
00108             return;
00109         
00110         profiler->fMutex.Lock();
00111         if (val) {
00112             std::map<std::string, JackProfilerClient*>::iterator it = profiler->fClientTable.find(name);
00113             if (it == profiler->fClientTable.end()) {
00114                 jack_log("Client %s added", name);
00115                 profiler->fClientTable[name] = new JackProfilerClient(profiler->fClient, name);
00116             }
00117         } else {
00118             std::map<std::string, JackProfilerClient*>::iterator it = profiler->fClientTable.find(name);
00119             if (it != profiler->fClientTable.end()) {
00120                 jack_log("Client %s removed", name);
00121                 profiler->fClientTable.erase(it);
00122                 delete((*it).second);
00123             }
00124         }
00125         profiler->fMutex.Unlock();
00126     #endif
00127     }
00128 
00129     int JackProfiler::Process(jack_nframes_t nframes, void* arg)
00130     {
00131         JackProfiler* profiler = static_cast<JackProfiler*>(arg);
00132         
00133         if (profiler->fCPULoadPort) {
00134             float* buffer_cpu_load = (float*)jack_port_get_buffer(profiler->fCPULoadPort, nframes);
00135             float cpu_load = jack_cpu_load(profiler->fClient);
00136             for (unsigned int i = 0; i < nframes; i++) {
00137                 buffer_cpu_load[i] = cpu_load / 100.f;
00138             }
00139         }
00140  
00141     #ifdef JACK_MONITOR      
00142         
00143         JackEngineControl* control = JackServerGlobals::fInstance->GetEngineControl();
00144         JackEngineProfiling* engine_profiler = &control->fProfiler;
00145         JackTimingMeasure* measure = engine_profiler->GetCurMeasure();
00146         
00147        if (profiler->fLastMeasure && profiler->fMutex.Trylock()) {
00148         
00149             if (profiler->fDriverPeriodPort) {
00150                 float* buffer_driver_period = (float*)jack_port_get_buffer(profiler->fDriverPeriodPort, nframes);
00151                 float value1 = (float(measure->fPeriodUsecs) - float(measure->fCurCycleBegin - profiler->fLastMeasure->fCurCycleBegin)) / float(measure->fPeriodUsecs);
00152                 for (unsigned int i = 0; i < nframes; i++) {
00153                     buffer_driver_period[i] = value1;
00154                 }
00155             }
00156             
00157             if (profiler->fDriverEndPort) {
00158                 float* buffer_driver_end_time = (float*)jack_port_get_buffer(profiler->fDriverEndPort, nframes);
00159                 float value2 = (float(measure->fPrevCycleEnd - profiler->fLastMeasure->fCurCycleBegin)) / float(measure->fPeriodUsecs);
00160                 for (unsigned int i = 0; i < nframes; i++) {
00161                     buffer_driver_end_time[i] = value2;
00162                 }
00163             }
00164             
00165             std::map<std::string, JackProfilerClient*>::iterator it;
00166             for (it = profiler->fClientTable.begin(); it != profiler->fClientTable.end(); it++) {
00167                 int ref = (*it).second->fRefNum;
00168                 long d5 = long(measure->fClientTable[ref].fSignaledAt - profiler->fLastMeasure->fCurCycleBegin);
00169                 long d6 = long(measure->fClientTable[ref].fAwakeAt - profiler->fLastMeasure->fCurCycleBegin);
00170                 long d7 = long(measure->fClientTable[ref].fFinishedAt - profiler->fLastMeasure->fCurCycleBegin);
00171                   
00172                 float* buffer_scheduling = (float*)jack_port_get_buffer((*it).second->fSchedulingPort, nframes);
00173                 float value3 = float(d6 - d5) / float(measure->fPeriodUsecs);
00174                 jack_log("Scheduling %f", value3);
00175                 for (unsigned int i = 0; i < nframes; i++) {
00176                     buffer_scheduling[i] = value3;
00177                 }
00178                   
00179                 float* buffer_duration = (float*)jack_port_get_buffer((*it).second->fDurationPort, nframes);
00180                 float value4 = float(d7 - d6) / float(measure->fPeriodUsecs);
00181                 jack_log("Duration %f", value4);
00182                 for (unsigned int i = 0; i < nframes; i++) {
00183                     buffer_duration[i] = value4;
00184                 }
00185             }
00186             
00187             profiler->fMutex.Unlock();
00188         }
00189         profiler->fLastMeasure = measure;
00190     #endif
00191         return 0;
00192     }
00193     
00194 } // namespace Jack
00195 
00196 #ifdef __cplusplus
00197 extern "C"
00198 {
00199 #endif
00200 
00201 #include "driver_interface.h"
00202 
00203     using namespace Jack;
00204     
00205     static Jack::JackProfiler* profiler = NULL;
00206 
00207     SERVER_EXPORT jack_driver_desc_t* jack_get_descriptor()
00208     {
00209         jack_driver_desc_t* desc = (jack_driver_desc_t*)calloc(1, sizeof(jack_driver_desc_t));
00210         
00211         strcpy(desc->name, "profiler");                    // size MUST be less then JACK_DRIVER_NAME_MAX + 1
00212         strcpy(desc->desc, "real-time server profiling");  // size MUST be less then JACK_DRIVER_PARAM_DESC + 1
00213        
00214         desc->nparams = 3;
00215         desc->params = (jack_driver_param_desc_t*)calloc(desc->nparams, sizeof(jack_driver_param_desc_t));
00216         
00217         int i = 0;
00218         strcpy(desc->params[i].name, "cpu-load");
00219         desc->params[i].character = 'c';
00220         desc->params[i].type = JackDriverParamBool;
00221         desc->params[i].value.i = FALSE;
00222         strcpy(desc->params[i].short_desc, "Show DSP CPU load");
00223         strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
00224         
00225         i++;
00226         strcpy(desc->params[i].name, "driver-period");
00227         desc->params[i].character = 'p';
00228         desc->params[i].type = JackDriverParamBool;
00229         desc->params[i].value.i = FALSE;
00230         strcpy(desc->params[i].short_desc, "Show driver period");
00231         strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
00232         
00233         i++;
00234         strcpy(desc->params[i].name, "driver-end-time");
00235         desc->params[i].character = 'e';
00236         desc->params[i].type = JackDriverParamBool;
00237         desc->params[i].value.i = FALSE;
00238         strcpy(desc->params[i].short_desc, "Show driver end time");
00239         strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
00240 
00241         return desc;
00242     }
00243 
00244     SERVER_EXPORT int jack_internal_initialize(jack_client_t* jack_client, const JSList* params)
00245     {
00246         if (profiler) {
00247             jack_info("profiler already loaded");
00248             return 1;
00249         }
00250         
00251         jack_log("Loading profiler");
00252         try {
00253             profiler = new Jack::JackProfiler(jack_client, params);
00254             assert(profiler);
00255             return 0;
00256         } catch (...) {
00257             return 1;
00258         }
00259     }
00260 
00261     SERVER_EXPORT int jack_initialize(jack_client_t* jack_client, const char* load_init)
00262     {
00263         JSList* params = NULL;
00264         bool parse_params = true;
00265         int res = 1;
00266         jack_driver_desc_t* desc = jack_get_descriptor();
00267 
00268         Jack::JackArgParser parser ( load_init );
00269         if ( parser.GetArgc() > 0 )
00270             parse_params = parser.ParseParams ( desc, &params );
00271 
00272         if (parse_params) {
00273             res = jack_internal_initialize ( jack_client, params );
00274             parser.FreeParams ( params );
00275         }
00276         return res;
00277     }
00278 
00279     SERVER_EXPORT void jack_finish(void* arg)
00280     {
00281         Jack::JackProfiler* profiler = static_cast<Jack::JackProfiler*>(arg);
00282 
00283         if (profiler) {
00284             jack_log("Unloading profiler");
00285             delete profiler;
00286         }
00287     }
00288 
00289 #ifdef __cplusplus
00290 }
00291 #endif