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.

345 lines
15KB

  1. /*
  2. Copyright (C) 2008 Grame & RTL
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU Lesser General Public License as published by
  5. the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  14. */
  15. #include "JackEngineProfiling.h"
  16. #include "JackGraphManager.h"
  17. #include "JackClientControl.h"
  18. #include "JackEngineControl.h"
  19. #include "JackClientInterface.h"
  20. #include "JackGlobals.h"
  21. #include "JackTime.h"
  22. namespace Jack
  23. {
  24. JackEngineProfiling::JackEngineProfiling():fAudioCycle(0),fMeasuredClient(0)
  25. {
  26. jack_info("Engine profiling activated, beware %ld MBytes are needed to record profiling points...", sizeof(fProfileTable) / (1024 * 1024));
  27. // Force memory page in
  28. memset(fProfileTable, 0, sizeof(fProfileTable));
  29. }
  30. JackEngineProfiling::~JackEngineProfiling()
  31. {
  32. FILE* file = fopen("JackEngineProfiling.log", "w");
  33. char buffer[1024];
  34. jack_info("Write server and clients timing data...");
  35. if (file == NULL) {
  36. jack_error("JackEngineProfiling::Save cannot open JackEngineProfiling.log file");
  37. } else {
  38. // For each measured point
  39. for (int i = 2; i < TIME_POINTS; i++) {
  40. // Driver timing values
  41. long d1 = long(fProfileTable[i].fCurCycleBegin - fProfileTable[i - 1].fCurCycleBegin);
  42. long d2 = long(fProfileTable[i].fPrevCycleEnd - fProfileTable[i - 1].fCurCycleBegin);
  43. if (d1 <= 0 || fProfileTable[i].fAudioCycle <= 0)
  44. continue; // Skip non valid cycles
  45. // Print driver delta and end cycle
  46. fprintf(file, "%ld \t %ld \t", d1, d2);
  47. // For each measured client
  48. for (unsigned int j = 0; j < fMeasuredClient; j++) {
  49. int ref = fIntervalTable[j].fRefNum;
  50. // Is valid client cycle
  51. if (fProfileTable[i].fClientTable[ref].fStatus != NotTriggered) {
  52. long d5 = long(fProfileTable[i].fClientTable[ref].fSignaledAt - fProfileTable[i - 1].fCurCycleBegin);
  53. long d6 = long(fProfileTable[i].fClientTable[ref].fAwakeAt - fProfileTable[i - 1].fCurCycleBegin);
  54. long d7 = long(fProfileTable[i].fClientTable[ref].fFinishedAt - fProfileTable[i - 1].fCurCycleBegin);
  55. // Print ref, signal, start, end, scheduling, duration, status
  56. fprintf(file, "%d \t %ld \t %ld \t %ld \t %ld \t %ld \t %d \t",
  57. ref,
  58. ((d5 > 0) ? d5 : 0),
  59. ((d6 > 0) ? d6 : 0),
  60. ((d7 > 0) ? d7 : 0),
  61. ((d6 > 0 && d5 > 0) ? (d6 - d5) : 0),
  62. ((d7 > 0 && d6 > 0) ? (d7 - d6) : 0),
  63. fProfileTable[i].fClientTable[ref].fStatus);
  64. } else { // Print tabs
  65. fprintf(file, "\t \t \t \t \t \t \t");
  66. }
  67. }
  68. // Terminate line
  69. fprintf(file, "\n");
  70. }
  71. }
  72. // Driver period
  73. file = fopen("Timing1.plot", "w");
  74. if (file == NULL) {
  75. jack_error("JackEngineProfiling::Save cannot open Timing1.log file");
  76. } else {
  77. fprintf(file, "set grid\n");
  78. fprintf(file, "set title \"Audio driver timing\"\n");
  79. fprintf(file, "set xlabel \"audio cycles\"\n");
  80. fprintf(file, "set ylabel \"usec\"\n");
  81. fprintf(file, "plot \"JackEngineProfiling.log\" using 1 title \"Audio period\" with lines \n");
  82. fprintf(file, "set output 'Timing1.pdf\n");
  83. fprintf(file, "set terminal pdf\n");
  84. fprintf(file, "set grid\n");
  85. fprintf(file, "set title \"Audio driver timing\"\n");
  86. fprintf(file, "set xlabel \"audio cycles\"\n");
  87. fprintf(file, "set ylabel \"usec\"\n");
  88. fprintf(file, "plot \"JackEngineProfiling.log\" using 1 title \"Audio period\" with lines \n");
  89. fclose(file);
  90. }
  91. // Driver end date
  92. file = fopen("Timing2.plot", "w");
  93. if (file == NULL) {
  94. jack_error("JackEngineProfiling::Save cannot open Timing2.log file");
  95. } else {
  96. fprintf(file, "set grid\n");
  97. fprintf(file, "set title \"Driver end date\"\n");
  98. fprintf(file, "set xlabel \"audio cycles\"\n");
  99. fprintf(file, "set ylabel \"usec\"\n");
  100. fprintf(file, "plot \"JackEngineProfiling.log\" using 2 title \"Driver end date\" with lines \n");
  101. fprintf(file, "set output 'Timing2.pdf\n");
  102. fprintf(file, "set terminal pdf\n");
  103. fprintf(file, "set grid\n");
  104. fprintf(file, "set title \"Driver end date\"\n");
  105. fprintf(file, "set xlabel \"audio cycles\"\n");
  106. fprintf(file, "set ylabel \"usec\"\n");
  107. fprintf(file, "plot \"JackEngineProfiling.log\" using 2 title \"Driver end date\" with lines \n");
  108. fclose(file);
  109. }
  110. // Clients end date
  111. if (fMeasuredClient > 0) {
  112. file = fopen("Timing3.plot", "w");
  113. if (file == NULL) {
  114. jack_error("JackEngineProfiling::Save cannot open Timing3.log file");
  115. } else {
  116. fprintf(file, "set multiplot\n");
  117. fprintf(file, "set grid\n");
  118. fprintf(file, "set title \"Clients end date\"\n");
  119. fprintf(file, "set xlabel \"audio cycles\"\n");
  120. fprintf(file, "set ylabel \"usec\"\n");
  121. fprintf(file, "plot ");
  122. for (unsigned int i = 0; i < fMeasuredClient; i++) {
  123. if (i == 0) {
  124. if (i + 1 == fMeasuredClient) { // Last client
  125. sprintf(buffer, "\"JackEngineProfiling.log\" using 1 title \"Audio period\" with lines,\"JackEngineProfiling.log\" using %d title \"%s\" with lines",
  126. ((i + 1) * 7) - 1 , fIntervalTable[i].fName);
  127. } else {
  128. sprintf(buffer, "\"JackEngineProfiling.log\" using 1 title \"Audio period\" with lines,\"JackEngineProfiling.log\" using %d title \"%s\" with lines,",
  129. ((i + 1) * 7) - 1 , fIntervalTable[i].fName);
  130. }
  131. } else if (i + 1 == fMeasuredClient) { // Last client
  132. sprintf(buffer, "\"JackEngineProfiling.log\" using %d title \"%s\" with lines", ((i + 1) * 7) - 1 , fIntervalTable[i].fName);
  133. } else {
  134. sprintf(buffer, "\"JackEngineProfiling.log\" using %d title \"%s\" with lines,", ((i + 1) * 7) - 1, fIntervalTable[i].fName);
  135. }
  136. fprintf(file, buffer);
  137. }
  138. fprintf(file, "\n unset multiplot\n");
  139. fprintf(file, "set output 'Timing3.pdf\n");
  140. fprintf(file, "set terminal pdf\n");
  141. fprintf(file, "set multiplot\n");
  142. fprintf(file, "set grid\n");
  143. fprintf(file, "set title \"Clients end date\"\n");
  144. fprintf(file, "set xlabel \"audio cycles\"\n");
  145. fprintf(file, "set ylabel \"usec\"\n");
  146. fprintf(file, "plot ");
  147. for (unsigned int i = 0; i < fMeasuredClient; i++) {
  148. if (i == 0) {
  149. if ((i + 1) == fMeasuredClient) { // Last client
  150. sprintf(buffer, "\"JackEngineProfiling.log\" using 1 title \"Audio period\" with lines,\"JackEngineProfiling.log\" using %d title \"%s\" with lines",
  151. ((i + 1) * 7) - 1 , fIntervalTable[i].fName);
  152. } else {
  153. sprintf(buffer, "\"JackEngineProfiling.log\" using 1 title \"Audio period\" with lines,\"JackEngineProfiling.log\" using %d title \"%s\" with lines,",
  154. ((i + 1) * 7) - 1 , fIntervalTable[i].fName);
  155. }
  156. } else if ((i + 1) == fMeasuredClient) { // Last client
  157. sprintf(buffer, "\"JackEngineProfiling.log\" using %d title \"%s\" with lines", ((i + 1) * 7) - 1 , fIntervalTable[i].fName);
  158. } else {
  159. sprintf(buffer, "\"JackEngineProfiling.log\" using %d title \"%s\" with lines,", ((i + 1) * 7) - 1, fIntervalTable[i].fName);
  160. }
  161. fprintf(file, buffer);
  162. }
  163. fclose(file);
  164. }
  165. }
  166. // Clients scheduling
  167. if (fMeasuredClient > 0) {
  168. file = fopen("Timing4.plot", "w");
  169. if (file == NULL) {
  170. jack_error("JackEngineProfiling::Save cannot open Timing4.log file");
  171. } else {
  172. fprintf(file, "set multiplot\n");
  173. fprintf(file, "set grid\n");
  174. fprintf(file, "set title \"Clients scheduling latency\"\n");
  175. fprintf(file, "set xlabel \"audio cycles\"\n");
  176. fprintf(file, "set ylabel \"usec\"\n");
  177. fprintf(file, "plot ");
  178. for (unsigned int i = 0; i < fMeasuredClient; i++) {
  179. if ((i + 1) == fMeasuredClient) // Last client
  180. sprintf(buffer, "\"JackEngineProfiling.log\" using %d title \"%s\" with lines", ((i + 1) * 7), fIntervalTable[i].fName);
  181. else
  182. sprintf(buffer, "\"JackEngineProfiling.log\" using %d title \"%s\" with lines,", ((i + 1) * 7), fIntervalTable[i].fName);
  183. fprintf(file, buffer);
  184. }
  185. fprintf(file, "\n unset multiplot\n");
  186. fprintf(file, "set output 'Timing4.pdf\n");
  187. fprintf(file, "set terminal pdf\n");
  188. fprintf(file, "set multiplot\n");
  189. fprintf(file, "set grid\n");
  190. fprintf(file, "set title \"Clients scheduling latency\"\n");
  191. fprintf(file, "set xlabel \"audio cycles\"\n");
  192. fprintf(file, "set ylabel \"usec\"\n");
  193. fprintf(file, "plot ");
  194. for (unsigned int i = 0; i < fMeasuredClient; i++) {
  195. if ((i + 1) == fMeasuredClient) // Last client
  196. sprintf(buffer, "\"JackEngineProfiling.log\" using %d title \"%s\" with lines", ((i + 1) * 7), fIntervalTable[i].fName);
  197. else
  198. sprintf(buffer, "\"JackEngineProfiling.log\" using %d title \"%s\" with lines,", ((i + 1) * 7), fIntervalTable[i].fName);
  199. fprintf(file, buffer);
  200. }
  201. fclose(file);
  202. }
  203. }
  204. // Clients duration
  205. if (fMeasuredClient > 0) {
  206. file = fopen("Timing5.plot", "w");
  207. if (file == NULL) {
  208. jack_error("JackEngineProfiling::Save cannot open Timing5.log file");
  209. } else {
  210. fprintf(file, "set multiplot\n");
  211. fprintf(file, "set grid\n");
  212. fprintf(file, "set title \"Clients duration\"\n");
  213. fprintf(file, "set xlabel \"audio cycles\"\n");
  214. fprintf(file, "set ylabel \"usec\"\n");
  215. fprintf(file, "plot ");
  216. for (unsigned int i = 0; i < fMeasuredClient; i++) {
  217. if ((i + 1) == fMeasuredClient) // Last client
  218. sprintf(buffer, "\"JackEngineProfiling.log\" using %d title \"%s\" with lines", ((i + 1) * 7) + 1, fIntervalTable[i].fName);
  219. else
  220. sprintf(buffer, "\"JackEngineProfiling.log\" using %d title \"%s\" with lines,", ((i + 1) * 7) + 1, fIntervalTable[i].fName);
  221. fprintf(file, buffer);
  222. }
  223. fprintf(file, "\n unset multiplot\n");
  224. fprintf(file, "set output 'Timing5.pdf\n");
  225. fprintf(file, "set terminal pdf\n");
  226. fprintf(file, "set multiplot\n");
  227. fprintf(file, "set grid\n");
  228. fprintf(file, "set title \"Clients duration\"\n");
  229. fprintf(file, "set xlabel \"audio cycles\"\n");
  230. fprintf(file, "set ylabel \"usec\"\n");
  231. fprintf(file, "plot ");
  232. for (unsigned int i = 0; i < fMeasuredClient; i++) {
  233. if ((i + 1) == fMeasuredClient) // Last client
  234. sprintf(buffer, "\"JackEngineProfiling.log\" using %d title \"%s\" with lines", ((i + 1) * 7) + 1, fIntervalTable[i].fName);
  235. else
  236. sprintf(buffer, "\"JackEngineProfiling.log\" using %d title \"%s\" with lines,", ((i + 1) * 7) + 1, fIntervalTable[i].fName);
  237. fprintf(file, buffer);
  238. }
  239. fclose(file);
  240. }
  241. }
  242. }
  243. bool JackEngineProfiling::CheckClient(const char* name, int cur_point)
  244. {
  245. for (int i = 0; i < MEASURED_CLIENTS; i++) {
  246. if (strcmp(fIntervalTable[i].fName, name) == 0) {
  247. fIntervalTable[i].fEndInterval = cur_point;
  248. return true;
  249. }
  250. }
  251. return false;
  252. }
  253. void JackEngineProfiling::Profile(JackClientInterface** table,
  254. JackGraphManager* manager,
  255. jack_time_t period_usecs,
  256. jack_time_t cur_cycle_begin,
  257. jack_time_t prev_cycle_end)
  258. {
  259. fAudioCycle = (fAudioCycle + 1) % TIME_POINTS;
  260. // Keeps cycle data
  261. fProfileTable[fAudioCycle].fPeriodUsecs = period_usecs;
  262. fProfileTable[fAudioCycle].fCurCycleBegin = cur_cycle_begin;
  263. fProfileTable[fAudioCycle].fPrevCycleEnd = prev_cycle_end;
  264. fProfileTable[fAudioCycle].fAudioCycle = fAudioCycle;
  265. for (int i = GetEngineControl()->fDriverNum; i < CLIENT_NUM; i++) {
  266. JackClientInterface* client = table[i];
  267. JackClientTiming* timing = manager->GetClientTiming(i);
  268. if (client && client->GetClientControl()->fActive && client->GetClientControl()->fCallback[kRealTimeCallback]) {
  269. if (!CheckClient(client->GetClientControl()->fName, fAudioCycle)) {
  270. // Keep new measured client
  271. fIntervalTable[fMeasuredClient].fRefNum = i;
  272. strcpy(fIntervalTable[fMeasuredClient].fName, client->GetClientControl()->fName);
  273. fIntervalTable[fMeasuredClient].fBeginInterval = fAudioCycle;
  274. fIntervalTable[fMeasuredClient].fEndInterval = fAudioCycle;
  275. fMeasuredClient++;
  276. }
  277. fProfileTable[fAudioCycle].fClientTable[i].fRefNum = i;
  278. fProfileTable[fAudioCycle].fClientTable[i].fSignaledAt = timing->fSignaledAt;
  279. fProfileTable[fAudioCycle].fClientTable[i].fAwakeAt = timing->fAwakeAt;
  280. fProfileTable[fAudioCycle].fClientTable[i].fFinishedAt = timing->fFinishedAt;
  281. fProfileTable[fAudioCycle].fClientTable[i].fStatus = timing->fStatus;
  282. }
  283. }
  284. }
  285. JackTimingMeasure* JackEngineProfiling::GetCurMeasure()
  286. {
  287. return &fProfileTable[fAudioCycle];
  288. }
  289. } // end of namespace