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.

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