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.

275 lines
10KB

  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. #ifdef _WIN32
  21. #include "JackWinNamedPipe.h"
  22. #include "JackWinNamedPipeServerChannel.h"
  23. #endif
  24. #include <assert.h>
  25. #include <string>
  26. namespace Jack
  27. {
  28. SERVER_EXPORT JackProfilerClient::JackProfilerClient(jack_client_t* client, const char* name)
  29. :fClient(client)
  30. {
  31. char port_name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
  32. fRefNum = JackServerGlobals::fInstance->GetEngine()->GetClientRefNum(name);
  33. snprintf(port_name, sizeof(port_name) - 1, "%s:scheduling", name);
  34. fSchedulingPort = jack_port_register(client, port_name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
  35. snprintf(port_name, sizeof(port_name) - 1, "%s:duration", name);
  36. fDurationPort = jack_port_register(client, port_name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
  37. }
  38. SERVER_EXPORT JackProfilerClient::~JackProfilerClient()
  39. {
  40. jack_port_unregister(fClient, fSchedulingPort);
  41. jack_port_unregister(fClient, fDurationPort);
  42. }
  43. #ifdef JACK_MONITOR
  44. JackProfiler::JackProfiler(jack_client_t* client, const JSList* params)
  45. :fClient(client), fLastMeasure(NULL)
  46. #else
  47. JackProfiler::JackProfiler(jack_client_t* client, const JSList* params)
  48. :fClient(client)
  49. #endif
  50. {
  51. jack_log("JackProfiler::JackProfiler");
  52. fCPULoadPort = fDriverPeriodPort = fDriverEndPort = NULL;
  53. const JSList* node;
  54. const jack_driver_param_t* param;
  55. for (node = params; node; node = jack_slist_next(node)) {
  56. param = (const jack_driver_param_t*)node->data;
  57. switch (param->character) {
  58. case 'c':
  59. fCPULoadPort = jack_port_register(client, "cpu_load", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
  60. break;
  61. case 'p':
  62. fDriverPeriodPort = jack_port_register(client, "driver_period", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
  63. break;
  64. case 'e':
  65. fDriverEndPort = jack_port_register(client, "driver_end_time", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
  66. break;
  67. }
  68. }
  69. // Resigster all running clients
  70. const char **ports = jack_get_ports(client, NULL, NULL, 0);
  71. if (ports) {
  72. for (int i = 0; ports[i]; ++i) {
  73. std::string str = std::string(ports[i]);
  74. ClientRegistration(str.substr(0, str.find_first_of(':')).c_str(), 1, this);
  75. }
  76. free(ports);
  77. }
  78. jack_set_process_callback(client, Process, this);
  79. jack_set_client_registration_callback(client, ClientRegistration, this);
  80. jack_activate(client);
  81. }
  82. JackProfiler::~JackProfiler()
  83. {
  84. jack_log("JackProfiler::~JackProfiler");
  85. }
  86. void JackProfiler::ClientRegistration(const char* name, int val, void *arg)
  87. {
  88. #ifdef JACK_MONITOR
  89. JackProfiler* profiler = static_cast<JackProfiler*>(arg);
  90. // Filter client or "system" name
  91. if (strcmp(name, jack_get_client_name(profiler->fClient)) == 0 || strcmp(name, "system") == 0)
  92. return;
  93. profiler->fMutex.Lock();
  94. if (val) {
  95. std::map<std::string, JackProfilerClient*>::iterator it = profiler->fClientTable.find(name);
  96. if (it == profiler->fClientTable.end()) {
  97. jack_log("Client %s added", name);
  98. profiler->fClientTable[name] = new JackProfilerClient(profiler->fClient, name);
  99. }
  100. } else {
  101. std::map<std::string, JackProfilerClient*>::iterator it = profiler->fClientTable.find(name);
  102. if (it != profiler->fClientTable.end()) {
  103. jack_log("Client %s removed", name);
  104. profiler->fClientTable.erase(it);
  105. delete((*it).second);
  106. }
  107. }
  108. profiler->fMutex.Unlock();
  109. #endif
  110. }
  111. int JackProfiler::Process(jack_nframes_t nframes, void* arg)
  112. {
  113. JackProfiler* profiler = static_cast<JackProfiler*>(arg);
  114. if (profiler->fCPULoadPort) {
  115. float* buffer_cpu_load = (float*)jack_port_get_buffer(profiler->fCPULoadPort, nframes);
  116. float cpu_load = jack_cpu_load(profiler->fClient);
  117. for (unsigned int i = 0; i < nframes; i++) {
  118. buffer_cpu_load[i] = cpu_load / 100.f;
  119. }
  120. }
  121. #ifdef JACK_MONITOR
  122. JackEngineControl* control = JackServerGlobals::fInstance->GetEngineControl();
  123. JackEngineProfiling* engine_profiler = &control->fProfiler;
  124. JackTimingMeasure* measure = engine_profiler->GetCurMeasure();
  125. if (profiler->fLastMeasure && profiler->fMutex.Trylock()) {
  126. if (profiler->fDriverPeriodPort) {
  127. float* buffer_driver_period = (float*)jack_port_get_buffer(profiler->fDriverPeriodPort, nframes);
  128. float value1 = (float(measure->fPeriodUsecs) - float(measure->fCurCycleBegin - profiler->fLastMeasure->fCurCycleBegin)) / float(measure->fPeriodUsecs);
  129. for (unsigned int i = 0; i < nframes; i++) {
  130. buffer_driver_period[i] = value1;
  131. }
  132. }
  133. if (profiler->fDriverEndPort) {
  134. float* buffer_driver_end_time = (float*)jack_port_get_buffer(profiler->fDriverEndPort, nframes);
  135. float value2 = (float(measure->fPrevCycleEnd - profiler->fLastMeasure->fCurCycleBegin)) / float(measure->fPeriodUsecs);
  136. for (unsigned int i = 0; i < nframes; i++) {
  137. buffer_driver_end_time[i] = value2;
  138. }
  139. }
  140. std::map<std::string, JackProfilerClient*>::iterator it;
  141. for (it = profiler->fClientTable.begin(); it != profiler->fClientTable.end(); it++) {
  142. int ref = (*it).second->fRefNum;
  143. long d5 = long(measure->fClientTable[ref].fSignaledAt - profiler->fLastMeasure->fCurCycleBegin);
  144. long d6 = long(measure->fClientTable[ref].fAwakeAt - profiler->fLastMeasure->fCurCycleBegin);
  145. long d7 = long(measure->fClientTable[ref].fFinishedAt - profiler->fLastMeasure->fCurCycleBegin);
  146. float* buffer_scheduling = (float*)jack_port_get_buffer((*it).second->fSchedulingPort, nframes);
  147. float value3 = float(d6 - d5) / float(measure->fPeriodUsecs);
  148. jack_log("Scheduling %f", value3);
  149. for (unsigned int i = 0; i < nframes; i++) {
  150. buffer_scheduling[i] = value3;
  151. }
  152. float* buffer_duration = (float*)jack_port_get_buffer((*it).second->fDurationPort, nframes);
  153. float value4 = float(d7 - d6) / float(measure->fPeriodUsecs);
  154. jack_log("Duration %f", value4);
  155. for (unsigned int i = 0; i < nframes; i++) {
  156. buffer_duration[i] = value4;
  157. }
  158. }
  159. profiler->fMutex.Unlock();
  160. }
  161. profiler->fLastMeasure = measure;
  162. #endif
  163. return 0;
  164. }
  165. } // namespace Jack
  166. #ifdef __cplusplus
  167. extern "C"
  168. {
  169. #endif
  170. #include "driver_interface.h"
  171. using namespace Jack;
  172. static JackProfiler* profiler = NULL;
  173. SERVER_EXPORT jack_driver_desc_t* jack_get_descriptor()
  174. {
  175. jack_driver_desc_t * desc;
  176. jack_driver_desc_filler_t filler;
  177. jack_driver_param_value_t value;
  178. desc = jack_driver_descriptor_construct("profiler", JackDriverNone, "real-time server profiling", &filler);
  179. value.i = FALSE;
  180. jack_driver_descriptor_add_parameter(desc, &filler, "cpu-load", 'c', JackDriverParamBool, &value, NULL, "Show DSP CPU load", NULL);
  181. jack_driver_descriptor_add_parameter(desc, &filler, "driver-period", 'p', JackDriverParamBool, &value, NULL, "Show driver period", NULL);
  182. jack_driver_descriptor_add_parameter(desc, &filler, "driver-end-time", 'e', JackDriverParamBool, &value, NULL, "Show driver end time", NULL);
  183. return desc;
  184. }
  185. SERVER_EXPORT int jack_internal_initialize(jack_client_t* jack_client, const JSList* params)
  186. {
  187. if (profiler) {
  188. jack_info("profiler already loaded");
  189. return 1;
  190. }
  191. jack_log("Loading profiler");
  192. try {
  193. profiler = new JackProfiler(jack_client, params);
  194. assert(profiler);
  195. return 0;
  196. } catch (...) {
  197. return 1;
  198. }
  199. }
  200. SERVER_EXPORT int jack_initialize(jack_client_t* jack_client, const char* load_init)
  201. {
  202. JSList* params = NULL;
  203. bool parse_params = true;
  204. int res = 1;
  205. jack_driver_desc_t* desc = jack_get_descriptor();
  206. JackArgParser parser ( load_init );
  207. if ( parser.GetArgc() > 0 )
  208. parse_params = parser.ParseParams ( desc, &params );
  209. if (parse_params) {
  210. res = jack_internal_initialize ( jack_client, params );
  211. parser.FreeParams ( params );
  212. }
  213. return res;
  214. }
  215. SERVER_EXPORT void jack_finish(void* arg)
  216. {
  217. JackProfiler* profiler = static_cast<JackProfiler*>(arg);
  218. if (profiler) {
  219. jack_log("Unloading profiler");
  220. delete profiler;
  221. }
  222. }
  223. #ifdef __cplusplus
  224. }
  225. #endif