Jack2 1.9.6
|
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, ¶ms ); 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