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.

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