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.

385 lines
17KB

  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. #include <iostream>
  23. #include <fstream>
  24. namespace Jack
  25. {
  26. JackEngineProfiling::JackEngineProfiling():fAudioCycle(0),fMeasuredClient(0)
  27. {
  28. jack_info("Engine profiling activated, beware %ld MBytes are needed to record profiling points...", sizeof(fProfileTable) / (1024 * 1024));
  29. // Force memory page in
  30. memset(fProfileTable, 0, sizeof(fProfileTable));
  31. }
  32. JackEngineProfiling::~JackEngineProfiling()
  33. {
  34. std::ofstream fStream("JackEngineProfiling.log", std::ios_base::ate);
  35. jack_info("Write server and clients timing data...");
  36. if (!fStream.is_open()) {
  37. jack_error("JackEngineProfiling::Save cannot open JackEngineProfiling.log file");
  38. } else {
  39. // For each measured point
  40. for (int i = 2; i < TIME_POINTS; i++) {
  41. // Driver timing values
  42. long d1 = long(fProfileTable[i].fCurCycleBegin - fProfileTable[i - 1].fCurCycleBegin);
  43. long d2 = long(fProfileTable[i].fPrevCycleEnd - fProfileTable[i - 1].fCurCycleBegin);
  44. if (d1 <= 0 || fProfileTable[i].fAudioCycle <= 0)
  45. continue; // Skip non valid cycles
  46. // Print driver delta and end cycle
  47. fStream << d1 << "\t" << d2 << "\t";
  48. // For each measured client
  49. for (unsigned int j = 0; j < fMeasuredClient; j++) {
  50. int ref = fIntervalTable[j].fRefNum;
  51. // Is valid client cycle
  52. if (fProfileTable[i].fClientTable[ref].fStatus != NotTriggered) {
  53. long d5 = long(fProfileTable[i].fClientTable[ref].fSignaledAt - fProfileTable[i - 1].fCurCycleBegin);
  54. long d6 = long(fProfileTable[i].fClientTable[ref].fAwakeAt - fProfileTable[i - 1].fCurCycleBegin);
  55. long d7 = long(fProfileTable[i].fClientTable[ref].fFinishedAt - fProfileTable[i - 1].fCurCycleBegin);
  56. fStream << ref << "\t" ;
  57. fStream << ((d5 > 0) ? d5 : 0) << "\t";
  58. fStream << ((d6 > 0) ? d6 : 0) << "\t" ;
  59. fStream << ((d7 > 0) ? d7 : 0) << "\t";
  60. fStream << ((d6 > 0 && d5 > 0) ? (d6 - d5) : 0) << "\t" ;
  61. fStream << ((d7 > 0 && d6 > 0) ? (d7 - d6) : 0) << "\t" ;
  62. fStream << fProfileTable[i].fClientTable[ref].fStatus << "\t" ;;
  63. } else { // Print tabs
  64. fStream << "\t \t \t \t \t \t \t";
  65. }
  66. }
  67. // Terminate line
  68. fStream << std::endl;
  69. }
  70. }
  71. // Driver period
  72. std::ofstream fStream1("Timing1.plot", std::ios_base::ate);
  73. if (!fStream1.is_open()) {
  74. jack_error("JackEngineProfiling::Save cannot open Timing1.plot file");
  75. } else {
  76. fStream1 << "set grid\n";
  77. fStream1 << "set title \"Audio driver timing\"\n";
  78. fStream1 << "set xlabel \"audio cycles\"\n";
  79. fStream1 << "set ylabel \"usec\"\n";
  80. fStream1 << "plot \"JackEngineProfiling.log\" using 1 title \"Audio period\" with lines \n";
  81. fStream1 << "set output 'Timing1.svg\n";
  82. fStream1 << "set terminal svg\n";
  83. fStream1 << "set grid\n";
  84. fStream1 << "set title \"Audio driver timing\"\n";
  85. fStream1 << "set xlabel \"audio cycles\"\n";
  86. fStream1 << "set ylabel \"usec\"\n";
  87. fStream1 << "plot \"JackEngineProfiling.log\" using 1 title \"Audio period\" with lines \n";
  88. fStream1 << "unset output\n";
  89. }
  90. // Driver end date
  91. std::ofstream fStream2("Timing2.plot", std::ios_base::ate);
  92. if (!fStream2.is_open()) {
  93. jack_error("JackEngineProfiling::Save cannot open Timing2.plot file");
  94. } else {
  95. fStream2 << "set grid\n";
  96. fStream2 << "set title \"Driver end date\"\n";
  97. fStream2 << "set xlabel \"audio cycles\"\n";
  98. fStream2 << "set ylabel \"usec\"\n";
  99. fStream2 << "plot \"JackEngineProfiling.log\" using 2 title \"Driver end date\" with lines \n";
  100. fStream2 << "set output 'Timing2.svg\n";
  101. fStream2 << "set terminal svg\n";
  102. fStream2 << "set grid\n";
  103. fStream2 << "set title \"Driver end date\"\n";
  104. fStream2 << "set xlabel \"audio cycles\"\n";
  105. fStream2 << "set ylabel \"usec\"\n";
  106. fStream2 << "plot \"JackEngineProfiling.log\" using 2 title \"Driver end date\" with lines \n";
  107. fStream2 << "unset output\n";
  108. }
  109. // Clients end date
  110. if (fMeasuredClient > 0) {
  111. std::ofstream fStream3("Timing3.plot", std::ios_base::ate);
  112. if (!fStream3.is_open()) {
  113. jack_error("JackEngineProfiling::Save cannot open Timing3.plot file");
  114. } else {
  115. fStream3 << "set multiplot\n";
  116. fStream3 << "set grid\n";
  117. fStream3 << "set title \"Clients end date\"\n";
  118. fStream3 << "set xlabel \"audio cycles\"\n";
  119. fStream3 << "set ylabel \"usec\"\n";
  120. fStream3 << "plot ";
  121. for (unsigned int i = 0; i < fMeasuredClient; i++) {
  122. if (i == 0) {
  123. if (i + 1 == fMeasuredClient) { // Last client
  124. fStream3 << "\"JackEngineProfiling.log\" using 1 title \"Audio period\" with lines,\"JackEngineProfiling.log\" using ";
  125. fStream3 << ((i + 1) * 7) - 1;
  126. fStream3 << " title \"" << fIntervalTable[i].fName << "\"with lines";
  127. } else {
  128. fStream3 << "\"JackEngineProfiling.log\" using 1 title \"Audio period\" with lines,\"JackEngineProfiling.log\" using ";
  129. fStream3 << ((i + 1) * 7) - 1;
  130. fStream3 << " title \"" << fIntervalTable[i].fName << "\"with lines,";
  131. }
  132. } else if (i + 1 == fMeasuredClient) { // Last client
  133. fStream3 << "\"JackEngineProfiling.log\" using " << ((i + 1) * 7) - 1 << " title \"" << fIntervalTable[i].fName << "\" with lines";
  134. } else {
  135. fStream3 << "\"JackEngineProfiling.log\" using " << ((i + 1) * 7) - 1 << " title \"" << fIntervalTable[i].fName << "\" with lines,";
  136. }
  137. }
  138. fStream3 << "\n unset multiplot\n";
  139. fStream3 << "set output 'Timing3.svg\n";
  140. fStream3 << "set terminal svg\n";
  141. fStream3 << "set multiplot\n";
  142. fStream3 << "set grid\n";
  143. fStream3 << "set title \"Clients end date\"\n";
  144. fStream3 << "set xlabel \"audio cycles\"\n";
  145. fStream3 << "set ylabel \"usec\"\n";
  146. fStream3 << "plot ";
  147. for (unsigned int i = 0; i < fMeasuredClient; i++) {
  148. if (i == 0) {
  149. if ((i + 1) == fMeasuredClient) { // Last client
  150. fStream3 << "\"JackEngineProfiling.log\" using 1 title \"Audio period\" with lines,\"JackEngineProfiling.log\" using ";
  151. fStream3 << ((i + 1) * 7) - 1;
  152. fStream3 << " title \"" << fIntervalTable[i].fName << "\"with lines";
  153. } else {
  154. fStream3 << "\"JackEngineProfiling.log\" using 1 title \"Audio period\" with lines,\"JackEngineProfiling.log\" using ";
  155. fStream3 << ((i + 1) * 7) - 1;
  156. fStream3 << " title \"" << fIntervalTable[i].fName << "\"with lines,";
  157. }
  158. } else if ((i + 1) == fMeasuredClient) { // Last client
  159. fStream3 << "\"JackEngineProfiling.log\" using " << ((i + 1) * 7) - 1 << " title \"" << fIntervalTable[i].fName << "\" with lines";
  160. } else {
  161. fStream3 << "\"JackEngineProfiling.log\" using " << ((i + 1) * 7) - 1 << " title \"" << fIntervalTable[i].fName << "\" with lines,";
  162. }
  163. }
  164. fStream3 << "\nunset multiplot\n";
  165. fStream3 << "unset output\n";
  166. }
  167. }
  168. // Clients scheduling
  169. if (fMeasuredClient > 0) {
  170. std::ofstream fStream4("Timing4.plot", std::ios_base::ate);
  171. if (!fStream4.is_open()) {
  172. jack_error("JackEngineProfiling::Save cannot open Timing4.plot file");
  173. } else {
  174. fStream4 << "set multiplot\n";
  175. fStream4 << "set grid\n";
  176. fStream4 << "set title \"Clients scheduling latency\"\n";
  177. fStream4 << "set xlabel \"audio cycles\"\n";
  178. fStream4 << "set ylabel \"usec\"\n";
  179. fStream4 << "plot ";
  180. for (unsigned int i = 0; i < fMeasuredClient; i++) {
  181. if ((i + 1) == fMeasuredClient) { // Last client
  182. fStream4 << "\"JackEngineProfiling.log\" using " << ((i + 1) * 7) << " title \"" << fIntervalTable[i].fName << "\" with lines";
  183. } else {
  184. fStream4 << "\"JackEngineProfiling.log\" using " << ((i + 1) * 7) << " title \"" << fIntervalTable[i].fName << "\" with lines,";
  185. }
  186. }
  187. fStream4 << "\n unset multiplot\n";
  188. fStream4 << "set output 'Timing4.svg\n";
  189. fStream4 << "set terminal svg\n";
  190. fStream4 << "set multiplot\n";
  191. fStream4 << "set grid\n";
  192. fStream4 << "set title \"Clients scheduling latency\"\n";
  193. fStream4 << "set xlabel \"audio cycles\"\n";
  194. fStream4 << "set ylabel \"usec\"\n";
  195. fStream4 << "plot ";
  196. for (unsigned int i = 0; i < fMeasuredClient; i++) {
  197. if ((i + 1) == fMeasuredClient) { // Last client
  198. fStream4 << "\"JackEngineProfiling.log\" using " << ((i + 1) * 7) << " title \"" << fIntervalTable[i].fName << "\" with lines";
  199. } else {
  200. fStream4 << "\"JackEngineProfiling.log\" using " << ((i + 1) * 7) << " title \"" << fIntervalTable[i].fName << "\" with lines,";
  201. }
  202. }
  203. fStream4 << "\nunset multiplot\n";
  204. fStream4 << "unset output\n";
  205. }
  206. }
  207. // Clients duration
  208. if (fMeasuredClient > 0) {
  209. std::ofstream fStream5("Timing5.plot", std::ios_base::ate);
  210. if (!fStream5.is_open()) {
  211. jack_error("JackEngineProfiling::Save cannot open Timing5.plot file");
  212. } else {
  213. fStream5 << "set multiplot\n";
  214. fStream5 << "set grid\n";
  215. fStream5 << "set title \"Clients duration\"\n";
  216. fStream5 << "set xlabel \"audio cycles\"\n";
  217. fStream5 << "set ylabel \"usec\"\n";
  218. fStream5 << "plot ";
  219. for (unsigned int i = 0; i < fMeasuredClient; i++) {
  220. if ((i + 1) == fMeasuredClient) { // Last client
  221. fStream5 << "\"JackEngineProfiling.log\" using " << ((i + 1) * 7) + 1 << " title \"" << fIntervalTable[i].fName << "\" with lines";
  222. } else {
  223. fStream5 << "\"JackEngineProfiling.log\" using " << ((i + 1) * 7) + 1 << " title \"" << fIntervalTable[i].fName << "\" with lines,";
  224. }
  225. }
  226. fStream5 << "\n unset multiplot\n";
  227. fStream5 << "set output 'Timing5.svg\n";
  228. fStream5 << "set terminal svg\n";
  229. fStream5 << "set multiplot\n";
  230. fStream5 << "set grid\n";
  231. fStream5 << "set title \"Clients duration\"\n";
  232. fStream5 << "set xlabel \"audio cycles\"\n";
  233. fStream5 << "set ylabel \"usec\"\n";
  234. fStream5 << "plot ";
  235. for (unsigned int i = 0; i < fMeasuredClient; i++) {
  236. if ((i + 1) == fMeasuredClient) {// Last client
  237. fStream5 << "\"JackEngineProfiling.log\" using " << ((i + 1) * 7) + 1 << " title \"" << fIntervalTable[i].fName << "\" with lines";
  238. } else {
  239. fStream5 << "\"JackEngineProfiling.log\" using " << ((i + 1) * 7) + 1 << " title \"" << fIntervalTable[i].fName << "\" with lines,";
  240. }
  241. }
  242. fStream5 << "\nunset multiplot\n";
  243. fStream5 << "unset output\n";
  244. }
  245. }
  246. std::ofstream fStream6("Timings.html", std::ios_base::ate);
  247. if (!fStream6.is_open()) {
  248. jack_error("JackEngineProfiling::Save cannot open Timings.html file");
  249. } else {
  250. fStream6 << "<?xml version='1.0' encoding='utf-8'?>\n";
  251. fStream6 << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n";
  252. fStream6 << "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n";
  253. fStream6 << "<html xmlns='http://www.w3.org/1999/xhtml' lang='en'>\n";
  254. fStream6 << " <head>\n";
  255. fStream6 << " <title>JACK engine profiling</title>\n";
  256. fStream6 << " <!-- assuming that images are 600px wide -->\n";
  257. fStream6 << " <style media='all' type='text/css'>\n";
  258. fStream6 << " .center { margin-left:auto ; margin-right: auto; width: 650px; height: 550px }\n";
  259. fStream6 << " </style>\n";
  260. fStream6 << " </head>\n";
  261. fStream6 << " <body>\n";
  262. fStream6 << " <h2 style='text-align:center'>JACK engine profiling</h2>\n";
  263. fStream6 << " <div class='center'><object class='center' type='image/svg+xml' data='Timing1.svg'>Timing1</object></div>";
  264. fStream6 << " <div class='center'><object class='center' type='image/svg+xml' data='Timing2.svg'>Timing2</object></div>";
  265. fStream6 << " <div class='center'><object class='center' type='image/svg+xml' data='Timing3.svg'>Timing3</object></div>";
  266. fStream6 << " <div class='center'><object class='center' type='image/svg+xml' data='Timing4.svg'>Timing4</object></div>";
  267. fStream6 << " <div class='center'><object class='center' type='image/svg+xml' data='Timing5.svg'>Timing5</object></div>";
  268. fStream6 << " </body>\n";
  269. fStream6 << "</html>\n";
  270. }
  271. std::ofstream fStream7("generate_timings", std::ios_base::ate);
  272. if (!fStream7.is_open()) {
  273. jack_error("JackEngineProfiling::Save cannot open generate_timings file");
  274. } else {
  275. fStream7 << "gnuplot -persist Timing1.plot \n";
  276. fStream7 << "gnuplot -persist Timing2.plot\n";
  277. fStream7 << "gnuplot -persist Timing3.plot\n";
  278. fStream7 << "gnuplot -persist Timing4.plot\n";
  279. fStream7 << "gnuplot -persist Timing5.plot\n";
  280. }
  281. }
  282. bool JackEngineProfiling::CheckClient(const char* name, int cur_point)
  283. {
  284. for (int i = 0; i < MEASURED_CLIENTS; i++) {
  285. if (strcmp(fIntervalTable[i].fName, name) == 0) {
  286. fIntervalTable[i].fEndInterval = cur_point;
  287. return true;
  288. }
  289. }
  290. return false;
  291. }
  292. void JackEngineProfiling::Profile(JackClientInterface** table,
  293. JackGraphManager* manager,
  294. jack_time_t period_usecs,
  295. jack_time_t cur_cycle_begin,
  296. jack_time_t prev_cycle_end)
  297. {
  298. fAudioCycle = (fAudioCycle + 1) % TIME_POINTS;
  299. // Keeps cycle data
  300. fProfileTable[fAudioCycle].fPeriodUsecs = period_usecs;
  301. fProfileTable[fAudioCycle].fCurCycleBegin = cur_cycle_begin;
  302. fProfileTable[fAudioCycle].fPrevCycleEnd = prev_cycle_end;
  303. fProfileTable[fAudioCycle].fAudioCycle = fAudioCycle;
  304. for (int i = GetEngineControl()->fDriverNum; i < CLIENT_NUM; i++) {
  305. JackClientInterface* client = table[i];
  306. JackClientTiming* timing = manager->GetClientTiming(i);
  307. if (client && client->GetClientControl()->fActive && client->GetClientControl()->fCallback[kRealTimeCallback]) {
  308. if (!CheckClient(client->GetClientControl()->fName, fAudioCycle)) {
  309. // Keep new measured client
  310. fIntervalTable[fMeasuredClient].fRefNum = i;
  311. strcpy(fIntervalTable[fMeasuredClient].fName, client->GetClientControl()->fName);
  312. fIntervalTable[fMeasuredClient].fBeginInterval = fAudioCycle;
  313. fIntervalTable[fMeasuredClient].fEndInterval = fAudioCycle;
  314. fMeasuredClient++;
  315. }
  316. fProfileTable[fAudioCycle].fClientTable[i].fRefNum = i;
  317. fProfileTable[fAudioCycle].fClientTable[i].fSignaledAt = timing->fSignaledAt;
  318. fProfileTable[fAudioCycle].fClientTable[i].fAwakeAt = timing->fAwakeAt;
  319. fProfileTable[fAudioCycle].fClientTable[i].fFinishedAt = timing->fFinishedAt;
  320. fProfileTable[fAudioCycle].fClientTable[i].fStatus = timing->fStatus;
  321. }
  322. }
  323. }
  324. JackTimingMeasure* JackEngineProfiling::GetCurMeasure()
  325. {
  326. return &fProfileTable[fAudioCycle];
  327. }
  328. } // end of namespace