/js/src/gc/Statistics.cpp

http://github.com/zpao/v8monkey · C++ · 337 lines · 246 code · 53 blank · 38 comment · 41 complexity · 9d0e179c0da6612259375a4afc895c04 MD5 · raw file

  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2. * vim: set ts=8 sw=4 et tw=78:
  3. *
  4. * ***** BEGIN LICENSE BLOCK *****
  5. * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  6. *
  7. * The contents of this file are subject to the Mozilla Public License Version
  8. * 1.1 (the "License"); you may not use this file except in compliance with
  9. * the License. You may obtain a copy of the License at
  10. * http://www.mozilla.org/MPL/
  11. *
  12. * Software distributed under the License is distributed on an "AS IS" basis,
  13. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  14. * for the specific language governing rights and limitations under the
  15. * License.
  16. *
  17. * The Original Code is SpiderMonkey JavaScript engine.
  18. *
  19. * The Initial Developer of the Original Code is
  20. * the Mozilla Foundation.
  21. * Portions created by the Initial Developer are Copyright (C) 2011
  22. * the Initial Developer. All Rights Reserved.
  23. *
  24. * Contributor(s):
  25. *
  26. * Alternatively, the contents of this file may be used under the terms of
  27. * either of the GNU General Public License Version 2 or later (the "GPL"),
  28. * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  29. * in which case the provisions of the GPL or the LGPL are applicable instead
  30. * of those above. If you wish to allow use of your version of this file only
  31. * under the terms of either the GPL or the LGPL, and not to allow others to
  32. * use your version of this file under the terms of the MPL, indicate your
  33. * decision by deleting the provisions above and replace them with the notice
  34. * and other provisions required by the GPL or the LGPL. If you do not delete
  35. * the provisions above, a recipient may use your version of this file under
  36. * the terms of any one of the MPL, the GPL or the LGPL.
  37. *
  38. * ***** END LICENSE BLOCK ***** */
  39. #include <stdio.h>
  40. #include <ctype.h>
  41. #include "jscntxt.h"
  42. #include "jscrashformat.h"
  43. #include "jscrashreport.h"
  44. #include "jsprf.h"
  45. #include "jsprobes.h"
  46. #include "jsutil.h"
  47. #include "prmjtime.h"
  48. #include "gc/Statistics.h"
  49. namespace js {
  50. namespace gcstats {
  51. static const char *
  52. ExplainReason(gcreason::Reason reason)
  53. {
  54. switch (reason) {
  55. #define SWITCH_REASON(name) \
  56. case gcreason::name: \
  57. return #name;
  58. GCREASONS(SWITCH_REASON)
  59. default:
  60. JS_NOT_REACHED("bad GC reason");
  61. return "?";
  62. #undef SWITCH_REASON
  63. }
  64. }
  65. Statistics::ColumnInfo::ColumnInfo(const char *title, double t, double total)
  66. : title(title)
  67. {
  68. JS_snprintf(str, sizeof(str), "%.1f", t);
  69. JS_snprintf(totalStr, sizeof(totalStr), "%.1f", total);
  70. width = 6;
  71. }
  72. Statistics::ColumnInfo::ColumnInfo(const char *title, double t)
  73. : title(title)
  74. {
  75. JS_snprintf(str, sizeof(str), "%.1f", t);
  76. strcpy(totalStr, "n/a");
  77. width = 6;
  78. }
  79. Statistics::ColumnInfo::ColumnInfo(const char *title, unsigned int data)
  80. : title(title)
  81. {
  82. JS_snprintf(str, sizeof(str), "%d", data);
  83. strcpy(totalStr, "n/a");
  84. width = 4;
  85. }
  86. Statistics::ColumnInfo::ColumnInfo(const char *title, const char *data)
  87. : title(title)
  88. {
  89. JS_ASSERT(strlen(data) < sizeof(str));
  90. strcpy(str, data);
  91. strcpy(totalStr, "n/a ");
  92. width = 0;
  93. }
  94. static const int NUM_COLUMNS = 17;
  95. void
  96. Statistics::makeTable(ColumnInfo *cols)
  97. {
  98. int i = 0;
  99. cols[i++] = ColumnInfo("Type", compartment ? "Comp" : "Glob");
  100. cols[i++] = ColumnInfo("Total", t(PHASE_GC), total(PHASE_GC));
  101. cols[i++] = ColumnInfo("Wait", beginDelay(PHASE_MARK, PHASE_GC));
  102. cols[i++] = ColumnInfo("Mark", t(PHASE_MARK), total(PHASE_MARK));
  103. cols[i++] = ColumnInfo("Sweep", t(PHASE_SWEEP), total(PHASE_SWEEP));
  104. cols[i++] = ColumnInfo("FinObj", t(PHASE_SWEEP_OBJECT), total(PHASE_SWEEP_OBJECT));
  105. cols[i++] = ColumnInfo("FinStr", t(PHASE_SWEEP_STRING), total(PHASE_SWEEP_STRING));
  106. cols[i++] = ColumnInfo("FinScr", t(PHASE_SWEEP_SCRIPT), total(PHASE_SWEEP_SCRIPT));
  107. cols[i++] = ColumnInfo("FinShp", t(PHASE_SWEEP_SHAPE), total(PHASE_SWEEP_SHAPE));
  108. cols[i++] = ColumnInfo("DisCod", t(PHASE_DISCARD_CODE), total(PHASE_DISCARD_CODE));
  109. cols[i++] = ColumnInfo("DisAnl", t(PHASE_DISCARD_ANALYSIS), total(PHASE_DISCARD_ANALYSIS));
  110. cols[i++] = ColumnInfo("XPCnct", t(PHASE_XPCONNECT), total(PHASE_XPCONNECT));
  111. cols[i++] = ColumnInfo("Destry", t(PHASE_DESTROY), total(PHASE_DESTROY));
  112. cols[i++] = ColumnInfo("End", endDelay(PHASE_GC, PHASE_DESTROY));
  113. cols[i++] = ColumnInfo("+Chu", counts[STAT_NEW_CHUNK]);
  114. cols[i++] = ColumnInfo("-Chu", counts[STAT_DESTROY_CHUNK]);
  115. cols[i++] = ColumnInfo("Reason", ExplainReason(triggerReason));
  116. JS_ASSERT(i == NUM_COLUMNS);
  117. }
  118. Statistics::Statistics(JSRuntime *rt)
  119. : runtime(rt),
  120. triggerReason(gcreason::NO_REASON)
  121. {
  122. PodArrayZero(counts);
  123. PodArrayZero(totals);
  124. startupTime = PRMJ_Now();
  125. char *env = getenv("MOZ_GCTIMER");
  126. if (!env || strcmp(env, "none") == 0) {
  127. fp = NULL;
  128. return;
  129. }
  130. if (strcmp(env, "stdout") == 0) {
  131. fullFormat = false;
  132. fp = stdout;
  133. } else if (strcmp(env, "stderr") == 0) {
  134. fullFormat = false;
  135. fp = stderr;
  136. } else {
  137. fullFormat = true;
  138. fp = fopen(env, "a");
  139. JS_ASSERT(fp);
  140. fprintf(fp, " AppTime");
  141. ColumnInfo cols[NUM_COLUMNS];
  142. makeTable(cols);
  143. for (int i = 0; i < NUM_COLUMNS; i++)
  144. fprintf(fp, ", %*s", cols[i].width, cols[i].title);
  145. fprintf(fp, "\n");
  146. }
  147. }
  148. Statistics::~Statistics()
  149. {
  150. if (fp) {
  151. if (fullFormat) {
  152. fprintf(fp, "------>TOTAL");
  153. ColumnInfo cols[NUM_COLUMNS];
  154. makeTable(cols);
  155. for (int i = 0; i < NUM_COLUMNS && cols[i].totalStr[0]; i++)
  156. fprintf(fp, ", %*s", cols[i].width, cols[i].totalStr);
  157. fprintf(fp, "\n");
  158. }
  159. if (fp != stdout && fp != stderr)
  160. fclose(fp);
  161. }
  162. }
  163. struct GCCrashData
  164. {
  165. int isRegen;
  166. int isCompartment;
  167. };
  168. void
  169. Statistics::beginGC(JSCompartment *comp, gcreason::Reason reason)
  170. {
  171. compartment = comp;
  172. PodArrayZero(phaseStarts);
  173. PodArrayZero(phaseEnds);
  174. PodArrayZero(phaseTimes);
  175. triggerReason = reason;
  176. beginPhase(PHASE_GC);
  177. Probes::GCStart();
  178. GCCrashData crashData;
  179. crashData.isCompartment = !!compartment;
  180. crash::SaveCrashData(crash::JS_CRASH_TAG_GC, &crashData, sizeof(crashData));
  181. }
  182. double
  183. Statistics::t(Phase phase)
  184. {
  185. return double(phaseTimes[phase]) / PRMJ_USEC_PER_MSEC;
  186. }
  187. double
  188. Statistics::total(Phase phase)
  189. {
  190. return double(totals[phase]) / PRMJ_USEC_PER_MSEC;
  191. }
  192. double
  193. Statistics::beginDelay(Phase phase1, Phase phase2)
  194. {
  195. return double(phaseStarts[phase1] - phaseStarts[phase2]) / PRMJ_USEC_PER_MSEC;
  196. }
  197. double
  198. Statistics::endDelay(Phase phase1, Phase phase2)
  199. {
  200. return double(phaseEnds[phase1] - phaseEnds[phase2]) / PRMJ_USEC_PER_MSEC;
  201. }
  202. void
  203. Statistics::statsToString(char *buffer, size_t size)
  204. {
  205. JS_ASSERT(size);
  206. buffer[0] = 0x00;
  207. ColumnInfo cols[NUM_COLUMNS];
  208. makeTable(cols);
  209. size_t pos = 0;
  210. for (int i = 0; i < NUM_COLUMNS; i++) {
  211. int len = strlen(cols[i].title) + 1 + strlen(cols[i].str);
  212. if (i > 0)
  213. len += 2;
  214. if (pos + len >= size)
  215. break;
  216. if (i > 0)
  217. strcat(buffer, ", ");
  218. strcat(buffer, cols[i].title);
  219. strcat(buffer, ":");
  220. strcat(buffer, cols[i].str);
  221. pos += len;
  222. }
  223. }
  224. void
  225. Statistics::printStats()
  226. {
  227. if (fullFormat) {
  228. fprintf(fp, "%12.0f", double(phaseStarts[PHASE_GC] - startupTime) / PRMJ_USEC_PER_MSEC);
  229. ColumnInfo cols[NUM_COLUMNS];
  230. makeTable(cols);
  231. for (int i = 0; i < NUM_COLUMNS; i++)
  232. fprintf(fp, ", %*s", cols[i].width, cols[i].str);
  233. fprintf(fp, "\n");
  234. } else {
  235. fprintf(fp, "%f %f %f\n",
  236. t(PHASE_GC), t(PHASE_MARK), t(PHASE_SWEEP));
  237. }
  238. fflush(fp);
  239. }
  240. void
  241. Statistics::endGC()
  242. {
  243. Probes::GCEnd();
  244. endPhase(PHASE_GC);
  245. crash::SnapshotGCStack();
  246. for (int i = 0; i < PHASE_LIMIT; i++)
  247. totals[i] += phaseTimes[i];
  248. if (JSAccumulateTelemetryDataCallback cb = runtime->telemetryCallback) {
  249. (*cb)(JS_TELEMETRY_GC_REASON, triggerReason);
  250. (*cb)(JS_TELEMETRY_GC_IS_COMPARTMENTAL, compartment ? 1 : 0);
  251. (*cb)(JS_TELEMETRY_GC_MS, t(PHASE_GC));
  252. (*cb)(JS_TELEMETRY_GC_MARK_MS, t(PHASE_MARK));
  253. (*cb)(JS_TELEMETRY_GC_SWEEP_MS, t(PHASE_SWEEP));
  254. }
  255. if (JSGCFinishedCallback cb = runtime->gcFinishedCallback) {
  256. char buffer[1024];
  257. statsToString(buffer, sizeof(buffer));
  258. (*cb)(runtime, compartment, buffer);
  259. }
  260. if (fp)
  261. printStats();
  262. PodArrayZero(counts);
  263. }
  264. void
  265. Statistics::beginPhase(Phase phase)
  266. {
  267. phaseStarts[phase] = PRMJ_Now();
  268. if (phase == gcstats::PHASE_MARK)
  269. Probes::GCStartMarkPhase();
  270. else if (phase == gcstats::PHASE_SWEEP)
  271. Probes::GCStartSweepPhase();
  272. }
  273. void
  274. Statistics::endPhase(Phase phase)
  275. {
  276. phaseEnds[phase] = PRMJ_Now();
  277. phaseTimes[phase] += phaseEnds[phase] - phaseStarts[phase];
  278. if (phase == gcstats::PHASE_MARK)
  279. Probes::GCEndMarkPhase();
  280. else if (phase == gcstats::PHASE_SWEEP)
  281. Probes::GCEndSweepPhase();
  282. }
  283. } /* namespace gcstats */
  284. } /* namespace js */