Merge branch 'master' into develop
[jack2.git] / common / JackProfiler.cpp
blob54b8091f128fb64ed755c3c33372cbf06dedd78a
1 /*
2 Copyright (C) 2009 Grame
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 #include "JackProfiler.h"
20 #include "JackServerGlobals.h"
21 #include "JackEngineControl.h"
22 #include "JackLockedEngine.h"
23 #include "JackArgParser.h"
24 #include <assert.h>
25 #include <string>
27 namespace Jack
30 JackProfilerClient::JackProfilerClient(jack_client_t* client, const char* name)
31 :fClient(client)
33 char port_name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
34 fRefNum = JackServerGlobals::fInstance->GetEngine()->GetClientRefNum(name);
36 snprintf(port_name, sizeof(port_name) - 1, "%s:scheduling", name);
37 fSchedulingPort = jack_port_register(client, port_name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
39 snprintf(port_name, sizeof(port_name) - 1, "%s:duration", name);
40 fDurationPort = jack_port_register(client, port_name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
43 JackProfilerClient::~JackProfilerClient()
45 jack_port_unregister(fClient, fSchedulingPort);
46 jack_port_unregister(fClient, fDurationPort);
49 #ifdef JACK_MONITOR
50 JackProfiler::JackProfiler(jack_client_t* client, const JSList* params)
51 :fClient(client), fLastMeasure(NULL)
52 #else
53 JackProfiler::JackProfiler(jack_client_t* client, const JSList* params)
54 :fClient(client)
55 #endif
57 jack_log("JackProfiler::JackProfiler");
59 fCPULoadPort = fDriverPeriodPort = fDriverEndPort = NULL;
61 const JSList* node;
62 const jack_driver_param_t* param;
63 for (node = params; node; node = jack_slist_next(node)) {
64 param = (const jack_driver_param_t*)node->data;
66 switch (param->character) {
67 case 'c':
68 fCPULoadPort = jack_port_register(client, "cpu_load", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
69 break;
71 case 'p':
72 fDriverPeriodPort = jack_port_register(client, "driver_period", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
73 break;
75 case 'e':
76 fDriverEndPort = jack_port_register(client, "driver_end_time", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
77 break;
81 // Resigster all running clients
82 const char **ports = jack_get_ports(client, NULL, NULL, 0);
83 if (ports) {
84 for (int i = 0; ports[i]; ++i) {
85 std::string str = std::string(ports[i]);
86 ClientRegistration(str.substr(0, str.find_first_of(':')).c_str(), 1, this);
88 free(ports);
91 jack_set_process_callback(client, Process, this);
92 jack_set_client_registration_callback(client, ClientRegistration, this);
93 jack_activate(client);
96 JackProfiler::~JackProfiler()
98 jack_log("JackProfiler::~JackProfiler");
101 void JackProfiler::ClientRegistration(const char* name, int val, void *arg)
103 #ifdef JACK_MONITOR
104 JackProfiler* profiler = static_cast<JackProfiler*>(arg);
106 // Filter client or "system" name
107 if (strcmp(name, jack_get_client_name(profiler->fClient)) == 0 || strcmp(name, "system") == 0)
108 return;
110 profiler->fMutex.Lock();
111 if (val) {
112 std::map<std::string, JackProfilerClient*>::iterator it = profiler->fClientTable.find(name);
113 if (it == profiler->fClientTable.end()) {
114 jack_log("Client %s added", name);
115 profiler->fClientTable[name] = new JackProfilerClient(profiler->fClient, name);
117 } else {
118 std::map<std::string, JackProfilerClient*>::iterator it = profiler->fClientTable.find(name);
119 if (it != profiler->fClientTable.end()) {
120 jack_log("Client %s removed", name);
121 profiler->fClientTable.erase(it);
122 delete((*it).second);
125 profiler->fMutex.Unlock();
126 #endif
129 int JackProfiler::Process(jack_nframes_t nframes, void* arg)
131 JackProfiler* profiler = static_cast<JackProfiler*>(arg);
133 if (profiler->fCPULoadPort) {
134 float* buffer_cpu_load = (float*)jack_port_get_buffer(profiler->fCPULoadPort, nframes);
135 float cpu_load = jack_cpu_load(profiler->fClient);
136 for (unsigned int i = 0; i < nframes; i++) {
137 buffer_cpu_load[i] = cpu_load / 100.f;
141 #ifdef JACK_MONITOR
143 JackEngineControl* control = JackServerGlobals::fInstance->GetEngineControl();
144 JackEngineProfiling* engine_profiler = &control->fProfiler;
145 JackTimingMeasure* measure = engine_profiler->GetCurMeasure();
147 if (profiler->fLastMeasure && profiler->fMutex.Trylock()) {
149 if (profiler->fDriverPeriodPort) {
150 float* buffer_driver_period = (float*)jack_port_get_buffer(profiler->fDriverPeriodPort, nframes);
151 float value1 = (float(measure->fPeriodUsecs) - float(measure->fCurCycleBegin - profiler->fLastMeasure->fCurCycleBegin)) / float(measure->fPeriodUsecs);
152 for (unsigned int i = 0; i < nframes; i++) {
153 buffer_driver_period[i] = value1;
157 if (profiler->fDriverEndPort) {
158 float* buffer_driver_end_time = (float*)jack_port_get_buffer(profiler->fDriverEndPort, nframes);
159 float value2 = (float(measure->fPrevCycleEnd - profiler->fLastMeasure->fCurCycleBegin)) / float(measure->fPeriodUsecs);
160 for (unsigned int i = 0; i < nframes; i++) {
161 buffer_driver_end_time[i] = value2;
165 std::map<std::string, JackProfilerClient*>::iterator it;
166 for (it = profiler->fClientTable.begin(); it != profiler->fClientTable.end(); it++) {
167 int ref = (*it).second->fRefNum;
168 long d5 = long(measure->fClientTable[ref].fSignaledAt - profiler->fLastMeasure->fCurCycleBegin);
169 long d6 = long(measure->fClientTable[ref].fAwakeAt - profiler->fLastMeasure->fCurCycleBegin);
170 long d7 = long(measure->fClientTable[ref].fFinishedAt - profiler->fLastMeasure->fCurCycleBegin);
172 float* buffer_scheduling = (float*)jack_port_get_buffer((*it).second->fSchedulingPort, nframes);
173 float value3 = float(d6 - d5) / float(measure->fPeriodUsecs);
174 jack_log("Scheduling %f", value3);
175 for (unsigned int i = 0; i < nframes; i++) {
176 buffer_scheduling[i] = value3;
179 float* buffer_duration = (float*)jack_port_get_buffer((*it).second->fDurationPort, nframes);
180 float value4 = float(d7 - d6) / float(measure->fPeriodUsecs);
181 jack_log("Duration %f", value4);
182 for (unsigned int i = 0; i < nframes; i++) {
183 buffer_duration[i] = value4;
187 profiler->fMutex.Unlock();
189 profiler->fLastMeasure = measure;
190 #endif
191 return 0;
194 } // namespace Jack
196 #ifdef __cplusplus
197 extern "C"
199 #endif
201 #include "driver_interface.h"
203 using namespace Jack;
205 static Jack::JackProfiler* profiler = NULL;
207 SERVER_EXPORT jack_driver_desc_t* jack_get_descriptor()
209 jack_driver_desc_t * desc;
210 jack_driver_desc_filler_t filler;
211 jack_driver_param_value_t value;
213 desc = jack_driver_descriptor_construct("profiler", JackDriverNone, "real-time server profiling", &filler);
215 value.i = FALSE;
216 jack_driver_descriptor_add_parameter(desc, &filler, "cpu-load", 'c', JackDriverParamBool, &value, NULL, "Show DSP CPU load", NULL);
217 jack_driver_descriptor_add_parameter(desc, &filler, "driver-period", 'p', JackDriverParamBool, &value, NULL, "Show driver period", NULL);
218 jack_driver_descriptor_add_parameter(desc, &filler, "driver-end-time", 'e', JackDriverParamBool, &value, NULL, "Show driver end time", NULL);
220 return desc;
223 SERVER_EXPORT int jack_internal_initialize(jack_client_t* jack_client, const JSList* params)
225 if (profiler) {
226 jack_info("profiler already loaded");
227 return 1;
230 jack_log("Loading profiler");
231 try {
232 profiler = new Jack::JackProfiler(jack_client, params);
233 assert(profiler);
234 return 0;
235 } catch (...) {
236 return 1;
240 SERVER_EXPORT int jack_initialize(jack_client_t* jack_client, const char* load_init)
242 JSList* params = NULL;
243 bool parse_params = true;
244 int res = 1;
245 jack_driver_desc_t* desc = jack_get_descriptor();
247 Jack::JackArgParser parser ( load_init );
248 if ( parser.GetArgc() > 0 )
249 parse_params = parser.ParseParams ( desc, &params );
251 if (parse_params) {
252 res = jack_internal_initialize ( jack_client, params );
253 parser.FreeParams ( params );
255 return res;
258 SERVER_EXPORT void jack_finish(void* arg)
260 Jack::JackProfiler* profiler = static_cast<Jack::JackProfiler*>(arg);
262 if (profiler) {
263 jack_log("Unloading profiler");
264 delete profiler;
268 #ifdef __cplusplus
270 #endif