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.

271 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. #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;
  172. jack_driver_desc_filler_t filler;
  173. jack_driver_param_value_t value;
  174. desc = jack_driver_descriptor_construct("profiler", JackDriverNone, "real-time server profiling", &filler);
  175. value.i = FALSE;
  176. jack_driver_descriptor_add_parameter(desc, &filler, "cpu-load", 'c', JackDriverParamBool, &value, NULL, "Show DSP CPU load", NULL);
  177. jack_driver_descriptor_add_parameter(desc, &filler, "driver-period", 'p', JackDriverParamBool, &value, NULL, "Show driver period", NULL);
  178. jack_driver_descriptor_add_parameter(desc, &filler, "driver-end-time", 'e', JackDriverParamBool, &value, NULL, "Show driver end time", NULL);
  179. return desc;
  180. }
  181. SERVER_EXPORT int jack_internal_initialize(jack_client_t* jack_client, const JSList* params)
  182. {
  183. if (profiler) {
  184. jack_info("profiler already loaded");
  185. return 1;
  186. }
  187. jack_log("Loading profiler");
  188. try {
  189. profiler = new Jack::JackProfiler(jack_client, params);
  190. assert(profiler);
  191. return 0;
  192. } catch (...) {
  193. return 1;
  194. }
  195. }
  196. SERVER_EXPORT int jack_initialize(jack_client_t* jack_client, const char* load_init)
  197. {
  198. JSList* params = NULL;
  199. bool parse_params = true;
  200. int res = 1;
  201. jack_driver_desc_t* desc = jack_get_descriptor();
  202. Jack::JackArgParser parser ( load_init );
  203. if ( parser.GetArgc() > 0 )
  204. parse_params = parser.ParseParams ( desc, &params );
  205. if (parse_params) {
  206. res = jack_internal_initialize ( jack_client, params );
  207. parser.FreeParams ( params );
  208. }
  209. return res;
  210. }
  211. SERVER_EXPORT void jack_finish(void* arg)
  212. {
  213. Jack::JackProfiler* profiler = static_cast<Jack::JackProfiler*>(arg);
  214. if (profiler) {
  215. jack_log("Unloading profiler");
  216. delete profiler;
  217. }
  218. }
  219. #ifdef __cplusplus
  220. }
  221. #endif