00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
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
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
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 }
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");
00212 strcpy(desc->desc, "real-time server profiling");
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