Jack2  1.9.9
JackProfiler.cpp
1 /*
2 Copyright (C) 2009 Grame
3 
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.
8 
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.
13 
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.
17 */
18 
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>
26 
27 namespace Jack
28 {
29 
30  JackProfilerClient::JackProfilerClient(jack_client_t* client, const char* name)
31  :fClient(client)
32  {
33  char port_name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
34  fRefNum = JackServerGlobals::fInstance->GetEngine()->GetClientRefNum(name);
35 
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);
38 
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);
41  }
42 
43  JackProfilerClient::~JackProfilerClient()
44  {
45  jack_port_unregister(fClient, fSchedulingPort);
46  jack_port_unregister(fClient, fDurationPort);
47  }
48 
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
56  {
57  jack_log("JackProfiler::JackProfiler");
58 
59  fCPULoadPort = fDriverPeriodPort = fDriverEndPort = NULL;
60 
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;
65 
66  switch (param->character) {
67  case 'c':
68  fCPULoadPort = jack_port_register(client, "cpu_load", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
69  break;
70 
71  case 'p':
72  fDriverPeriodPort = jack_port_register(client, "driver_period", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
73  break;
74 
75  case 'e':
76  fDriverEndPort = jack_port_register(client, "driver_end_time", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
77  break;
78  }
79  }
80 
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);
87  }
88  free(ports);
89  }
90 
91  jack_set_process_callback(client, Process, this);
92  jack_set_client_registration_callback(client, ClientRegistration, this);
93  jack_activate(client);
94  }
95 
96  JackProfiler::~JackProfiler()
97  {
98  jack_log("JackProfiler::~JackProfiler");
99  }
100 
101  void JackProfiler::ClientRegistration(const char* name, int val, void *arg)
102  {
103  #ifdef JACK_MONITOR
104  JackProfiler* profiler = static_cast<JackProfiler*>(arg);
105 
106  // Filter client or "system" name
107  if (strcmp(name, jack_get_client_name(profiler->fClient)) == 0 || strcmp(name, "system") == 0)
108  return;
109 
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);
116  }
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);
123  }
124  }
125  profiler->fMutex.Unlock();
126  #endif
127  }
128 
129  int JackProfiler::Process(jack_nframes_t nframes, void* arg)
130  {
131  JackProfiler* profiler = static_cast<JackProfiler*>(arg);
132 
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;
138  }
139  }
140 
141  #ifdef JACK_MONITOR
142 
143  JackEngineControl* control = JackServerGlobals::fInstance->GetEngineControl();
144  JackEngineProfiling* engine_profiler = &control->fProfiler;
145  JackTimingMeasure* measure = engine_profiler->GetCurMeasure();
146 
147  if (profiler->fLastMeasure && profiler->fMutex.Trylock()) {
148 
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;
154  }
155  }
156 
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;
162  }
163  }
164 
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);
171 
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;
177  }
178 
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;
184  }
185  }
186 
187  profiler->fMutex.Unlock();
188  }
189  profiler->fLastMeasure = measure;
190  #endif
191  return 0;
192  }
193 
194 } // namespace Jack
195 
196 #ifdef __cplusplus
197 extern "C"
198 {
199 #endif
200 
201 #include "driver_interface.h"
202 
203  using namespace Jack;
204 
205  static Jack::JackProfiler* profiler = NULL;
206 
207  SERVER_EXPORT jack_driver_desc_t* jack_get_descriptor()
208  {
209  jack_driver_desc_t * desc;
212 
213  desc = jack_driver_descriptor_construct("profiler", JackDriverNone, "real-time server profiling", &filler);
214 
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);
219 
220  return desc;
221  }
222 
223  SERVER_EXPORT int jack_internal_initialize(jack_client_t* jack_client, const JSList* params)
224  {
225  if (profiler) {
226  jack_info("profiler already loaded");
227  return 1;
228  }
229 
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;
237  }
238  }
239 
240  SERVER_EXPORT int jack_initialize(jack_client_t* jack_client, const char* load_init)
241  {
242  JSList* params = NULL;
243  bool parse_params = true;
244  int res = 1;
245  jack_driver_desc_t* desc = jack_get_descriptor();
246 
247  Jack::JackArgParser parser ( load_init );
248  if ( parser.GetArgc() > 0 )
249  parse_params = parser.ParseParams ( desc, &params );
250 
251  if (parse_params) {
252  res = jack_internal_initialize ( jack_client, params );
253  parser.FreeParams ( params );
254  }
255  return res;
256  }
257 
258  SERVER_EXPORT void jack_finish(void* arg)
259  {
260  Jack::JackProfiler* profiler = static_cast<Jack::JackProfiler*>(arg);
261 
262  if (profiler) {
263  jack_log("Unloading profiler");
264  delete profiler;
265  }
266  }
267 
268 #ifdef __cplusplus
269 }
270 #endif
LIB_EXPORT int jack_set_client_registration_callback(jack_client_t *, JackClientRegistrationCallback registration_callback, void *arg)
Definition: JackAPI.cpp:913
LIB_EXPORT int jack_port_unregister(jack_client_t *, jack_port_t *)
Definition: JackAPI.cpp:1061
LIB_EXPORT int jack_set_process_callback(jack_client_t *client, JackProcessCallback process_callback, void *arg)
Definition: JackAPI.cpp:781
LIB_EXPORT int jack_activate(jack_client_t *client)
Definition: JackAPI.cpp:1019
LIB_EXPORT jack_port_t * jack_port_register(jack_client_t *client, const char *port_name, const char *port_type, unsigned long flags, unsigned long buffer_size)
Definition: JackAPI.cpp:1045
SERVER_EXPORT void jack_info(const char *fmt,...)
Definition: JackError.cpp:99
LIB_EXPORT char * jack_get_client_name(jack_client_t *client)
Definition: JackAPI.cpp:1419
LIB_EXPORT void * jack_port_get_buffer(jack_port_t *, jack_nframes_t)
Definition: JackAPI.cpp:333
Timing stucture for a table of clients.
LIB_EXPORT float jack_cpu_load(jack_client_t *client)
Definition: JackAPI.cpp:1392
Engine control in shared memory.
LIB_EXPORT const char ** jack_get_ports(jack_client_t *, const char *port_name_pattern, const char *type_name_pattern, unsigned long flags)
Definition: JackAPI.cpp:1241
SERVER_EXPORT void jack_log(const char *fmt,...)
Definition: JackError.cpp:107
Server real-time monitoring.
Definition: JackProfiler.h:53