jack2 codebase
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

292 lines
11KB

  1. /*
  2. Copyright (C) 2009 Grame
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 2 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  14. */
  15. #include "JackProfiler.h"
  16. #include "JackServerGlobals.h"
  17. #include "JackEngineControl.h"
  18. #include "JackLockedEngine.h"
  19. #include "JackArgParser.h"
  20. #include <assert.h>
  21. #include <string>
  22. namespace Jack
  23. {
  24. JackProfilerClient::JackProfilerClient(jack_client_t* client, const char* name)
  25. :fClient(client)
  26. {
  27. char port_name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
  28. fRefNum = JackServerGlobals::fInstance->GetEngine()->GetClientRefNum(name);
  29. snprintf(port_name, sizeof(port_name) - 1, "%s:scheduling", name);
  30. fSchedulingPort = jack_port_register(client, port_name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
  31. snprintf(port_name, sizeof(port_name) - 1, "%s:duration", name);
  32. fDurationPort = jack_port_register(client, port_name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
  33. }
  34. JackProfilerClient::~JackProfilerClient()
  35. {
  36. jack_port_unregister(fClient, fSchedulingPort);
  37. jack_port_unregister(fClient, fDurationPort);
  38. }
  39. #ifdef JACK_MONITOR
  40. JackProfiler::JackProfiler(jack_client_t* client, const JSList* params)
  41. :fClient(client), fLastMeasure(NULL)
  42. #else
  43. JackProfiler::JackProfiler(jack_client_t* client, const JSList* params)
  44. :fClient(client)
  45. #endif
  46. {
  47. jack_log("JackProfiler::JackProfiler");
  48. fCPULoadPort = fDriverPeriodPort = fDriverEndPort = NULL;
  49. const JSList* node;
  50. const jack_driver_param_t* param;
  51. for (node = params; node; node = jack_slist_next(node)) {
  52. param = (const jack_driver_param_t*)node->data;
  53. switch (param->character) {
  54. case 'c':
  55. fCPULoadPort = jack_port_register(client, "cpu_load", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
  56. break;
  57. case 'p':
  58. fDriverPeriodPort = jack_port_register(client, "driver_period", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
  59. break;
  60. case 'e':
  61. fDriverEndPort = jack_port_register(client, "driver_end_time", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
  62. break;
  63. }
  64. }
  65. // Resigster all running clients
  66. const char **ports = jack_get_ports(client, NULL, NULL, 0);
  67. if (ports) {
  68. for (int i = 0; ports[i]; ++i) {
  69. std::string str = std::string(ports[i]);
  70. ClientRegistration(str.substr(0, str.find_first_of(':')).c_str(), 1, this);
  71. }
  72. free(ports);
  73. }
  74. jack_set_process_callback(client, Process, this);
  75. jack_set_client_registration_callback(client, ClientRegistration, this);
  76. jack_activate(client);
  77. }
  78. JackProfiler::~JackProfiler()
  79. {
  80. jack_log("JackProfiler::~JackProfiler");
  81. }
  82. void JackProfiler::ClientRegistration(const char* name, int val, void *arg)
  83. {
  84. #ifdef JACK_MONITOR
  85. JackProfiler* profiler = static_cast<JackProfiler*>(arg);
  86. // Filter client or "system" name
  87. if (strcmp(name, jack_get_client_name(profiler->fClient)) == 0 || strcmp(name, "system") == 0)
  88. return;
  89. profiler->fMutex.Lock();
  90. if (val) {
  91. std::map<std::string, JackProfilerClient*>::iterator it = profiler->fClientTable.find(name);
  92. if (it == profiler->fClientTable.end()) {
  93. jack_log("Client %s added", name);
  94. profiler->fClientTable[name] = new JackProfilerClient(profiler->fClient, name);
  95. }
  96. } else {
  97. std::map<std::string, JackProfilerClient*>::iterator it = profiler->fClientTable.find(name);
  98. if (it != profiler->fClientTable.end()) {
  99. jack_log("Client %s removed", name);
  100. profiler->fClientTable.erase(it);
  101. delete((*it).second);
  102. }
  103. }
  104. profiler->fMutex.Unlock();
  105. #endif
  106. }
  107. int JackProfiler::Process(jack_nframes_t nframes, void* arg)
  108. {
  109. JackProfiler* profiler = static_cast<JackProfiler*>(arg);
  110. if (profiler->fCPULoadPort) {
  111. float* buffer_cpu_load = (float*)jack_port_get_buffer(profiler->fCPULoadPort, nframes);
  112. float cpu_load = jack_cpu_load(profiler->fClient);
  113. for (unsigned int i = 0; i < nframes; i++) {
  114. buffer_cpu_load[i] = cpu_load / 100.f;
  115. }
  116. }
  117. #ifdef JACK_MONITOR
  118. JackEngineControl* control = JackServerGlobals::fInstance->GetEngineControl();
  119. JackEngineProfiling* engine_profiler = &control->fProfiler;
  120. JackTimingMeasure* measure = engine_profiler->GetCurMeasure();
  121. if (profiler->fLastMeasure && profiler->fMutex.Trylock()) {
  122. if (profiler->fDriverPeriodPort) {
  123. float* buffer_driver_period = (float*)jack_port_get_buffer(profiler->fDriverPeriodPort, nframes);
  124. float value1 = (float(measure->fPeriodUsecs) - float(measure->fCurCycleBegin - profiler->fLastMeasure->fCurCycleBegin)) / float(measure->fPeriodUsecs);
  125. for (unsigned int i = 0; i < nframes; i++) {
  126. buffer_driver_period[i] = value1;
  127. }
  128. }
  129. if (profiler->fDriverEndPort) {
  130. float* buffer_driver_end_time = (float*)jack_port_get_buffer(profiler->fDriverEndPort, nframes);
  131. float value2 = (float(measure->fPrevCycleEnd - profiler->fLastMeasure->fCurCycleBegin)) / float(measure->fPeriodUsecs);
  132. for (unsigned int i = 0; i < nframes; i++) {
  133. buffer_driver_end_time[i] = value2;
  134. }
  135. }
  136. std::map<std::string, JackProfilerClient*>::iterator it;
  137. for (it = profiler->fClientTable.begin(); it != profiler->fClientTable.end(); it++) {
  138. int ref = (*it).second->fRefNum;
  139. long d5 = long(measure->fClientTable[ref].fSignaledAt - profiler->fLastMeasure->fCurCycleBegin);
  140. long d6 = long(measure->fClientTable[ref].fAwakeAt - profiler->fLastMeasure->fCurCycleBegin);
  141. long d7 = long(measure->fClientTable[ref].fFinishedAt - profiler->fLastMeasure->fCurCycleBegin);
  142. float* buffer_scheduling = (float*)jack_port_get_buffer((*it).second->fSchedulingPort, nframes);
  143. float value3 = float(d6 - d5) / float(measure->fPeriodUsecs);
  144. jack_log("Scheduling %f", value3);
  145. for (unsigned int i = 0; i < nframes; i++) {
  146. buffer_scheduling[i] = value3;
  147. }
  148. float* buffer_duration = (float*)jack_port_get_buffer((*it).second->fDurationPort, nframes);
  149. float value4 = float(d7 - d6) / float(measure->fPeriodUsecs);
  150. jack_log("Duration %f", value4);
  151. for (unsigned int i = 0; i < nframes; i++) {
  152. buffer_duration[i] = value4;
  153. }
  154. }
  155. profiler->fMutex.Unlock();
  156. }
  157. profiler->fLastMeasure = measure;
  158. #endif
  159. return 0;
  160. }
  161. } // namespace Jack
  162. #ifdef __cplusplus
  163. extern "C"
  164. {
  165. #endif
  166. #include "driver_interface.h"
  167. using namespace Jack;
  168. static Jack::JackProfiler* profiler = NULL;
  169. SERVER_EXPORT jack_driver_desc_t* jack_get_descriptor()
  170. {
  171. jack_driver_desc_t* desc = (jack_driver_desc_t*)calloc(1, sizeof(jack_driver_desc_t));
  172. strcpy(desc->name, "profiler"); // size MUST be less then JACK_DRIVER_NAME_MAX + 1
  173. strcpy(desc->desc, "real-time server profiling"); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1
  174. desc->nparams = 3;
  175. desc->params = (jack_driver_param_desc_t*)calloc(desc->nparams, sizeof(jack_driver_param_desc_t));
  176. int i = 0;
  177. strcpy(desc->params[i].name, "cpu-load");
  178. desc->params[i].character = 'c';
  179. desc->params[i].type = JackDriverParamBool;
  180. desc->params[i].value.i = TRUE;
  181. strcpy(desc->params[i].short_desc, "Show DSP CPU load");
  182. strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
  183. i++;
  184. strcpy(desc->params[i].name, "driver-period");
  185. desc->params[i].character = 'p';
  186. desc->params[i].type = JackDriverParamBool;
  187. desc->params[i].value.i = TRUE;
  188. strcpy(desc->params[i].short_desc, "Show driver period");
  189. strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
  190. i++;
  191. strcpy(desc->params[i].name, "driver-end-time");
  192. desc->params[i].character = 'e';
  193. desc->params[i].type = JackDriverParamBool;
  194. desc->params[i].value.i = TRUE;
  195. strcpy(desc->params[i].short_desc, "Show driver end time");
  196. strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
  197. return desc;
  198. }
  199. SERVER_EXPORT int jack_internal_initialize(jack_client_t* jack_client, const JSList* params)
  200. {
  201. if (profiler) {
  202. jack_info("profiler already loaded");
  203. return 1;
  204. }
  205. jack_log("Loading profiler");
  206. try {
  207. profiler = new Jack::JackProfiler(jack_client, params);
  208. assert(profiler);
  209. return 0;
  210. } catch (...) {
  211. return 1;
  212. }
  213. }
  214. SERVER_EXPORT int jack_initialize(jack_client_t* jack_client, const char* load_init)
  215. {
  216. JSList* params = NULL;
  217. bool parse_params = true;
  218. int res = 1;
  219. jack_driver_desc_t* desc = jack_get_descriptor();
  220. Jack::JackArgParser parser ( load_init );
  221. if ( parser.GetArgc() > 0 )
  222. parse_params = parser.ParseParams ( desc, &params );
  223. if (parse_params) {
  224. res = jack_internal_initialize ( jack_client, params );
  225. parser.FreeParams ( params );
  226. }
  227. return res;
  228. }
  229. SERVER_EXPORT void jack_finish(void* arg)
  230. {
  231. Jack::JackProfiler* profiler = static_cast<Jack::JackProfiler*>(arg);
  232. if (profiler) {
  233. jack_log("Unloading profiler");
  234. delete profiler;
  235. }
  236. }
  237. #ifdef __cplusplus
  238. }
  239. #endif