summaryrefslogtreecommitdiff
path: root/rts/ProfilerReportJson.c
diff options
context:
space:
mode:
authorBen Gamari <bgamari.foss@gmail.com>2017-02-23 13:22:48 -0500
committerBen Gamari <ben@smart-cactus.org>2017-02-23 17:26:44 -0500
commita20433326eabd759502d9c170c3cc44ce6128a04 (patch)
tree72ba807d45f05460dcfad02d437d9b79c0518481 /rts/ProfilerReportJson.c
parent0a77cedb914a67b8bd7c4af1f87714dc497fec3e (diff)
downloadhaskell-a20433326eabd759502d9c170c3cc44ce6128a04.tar.gz
JSON profiler reports
This introduces a JSON output format for cost-centre profiler reports. It's not clear whether this is really something we want to introduce given that we may also move to a more Haskell-driven output pipeline in the future, but I nevertheless found this helpful, so I thought I would put it up. Test Plan: Compile a program with `-prof -fprof-auto`; run with `+RTS -pj` Reviewers: austin, erikd, simonmar Reviewed By: simonmar Subscribers: duncan, maoe, thomie, simonmar Differential Revision: https://phabricator.haskell.org/D3132
Diffstat (limited to 'rts/ProfilerReportJson.c')
-rw-r--r--rts/ProfilerReportJson.c127
1 files changed, 127 insertions, 0 deletions
diff --git a/rts/ProfilerReportJson.c b/rts/ProfilerReportJson.c
new file mode 100644
index 0000000000..b4c77042d7
--- /dev/null
+++ b/rts/ProfilerReportJson.c
@@ -0,0 +1,127 @@
+/* -----------------------------------------------------------------------------
+ *
+ * (c) The GHC Team, 1998-2017
+ *
+ * Generating cost-centre profiler JSON report
+ *
+ * ---------------------------------------------------------------------------*/
+
+#ifdef PROFILING
+
+#include "PosixSource.h"
+#include "Rts.h"
+
+#include "RtsUtils.h"
+#include "ProfilerReportJson.h"
+#include "Profiling.h"
+
+// This only handles characters that you might see in a Haskell cost-centre
+// name.
+static void escapeString(char const* str, char *out, int len)
+{
+ len--; // reserve character in output for terminating NUL
+ for (; str != '\0' && len > 0; str++) {
+ char c = *str;
+ if (c == '\\') {
+ if (len < 2) break;
+ *out = '\\'; out++; len--;
+ *out = '\\'; out++; len--;
+ } else if (c == '\n') {
+ if (len < 2) break;
+ *out = '\\'; out++; len--;
+ *out = 'n'; out++; len--;
+ } else {
+ *out = c; out++; len--;
+ }
+ }
+ *out = '\0';
+}
+
+static void
+logCostCentres(FILE *prof_file)
+{
+ char tmp[256];
+ bool needs_comma = false;
+ fprintf(prof_file, "[\n");
+ for (CostCentre *cc = CC_LIST; cc != NULL; cc = cc->link) {
+ escapeString(cc->label, tmp, sizeof(tmp));
+ fprintf(prof_file,
+ "%s"
+ "{\"id\": %" FMT_Int ", "
+ "\"label\": \"%s\", "
+ "\"module\": \"%s\", "
+ "\"src_loc\": \"%s\", "
+ "\"is_caf\": %s}",
+ needs_comma ? ", " : "",
+ cc->ccID, tmp, cc->module, cc->srcloc,
+ cc->is_caf ? "true" : "false");
+ needs_comma = true;
+ }
+ fprintf(prof_file, "]\n");
+}
+
+static void
+logCostCentreStack(FILE *prof_file, CostCentreStack const *ccs)
+{
+ fprintf(prof_file,
+ "{\"id\": %" FMT_Int ", "
+ "\"entries\": %" FMT_Word64 ", "
+ "\"alloc\": %" FMT_Word ", "
+ "\"ticks\": %" FMT_Word ", ",
+ ccs->cc->ccID,
+ ccs->scc_count,
+ ccs->mem_alloc * sizeof(W_),
+ ccs->time_ticks);
+
+ bool need_comma = false;
+ fprintf(prof_file, "\"children\": [");
+ for (IndexTable *i = ccs->indexTable; i != 0; i = i->next) {
+ if (!i->back_edge) {
+ if (need_comma) {
+ fprintf(prof_file, ",");
+ }
+ logCostCentreStack(prof_file, i->ccs);
+ need_comma = true;
+ }
+ }
+ fprintf(prof_file, "]}\n");
+}
+
+void
+writeCCSReportJson(FILE *prof_file,
+ CostCentreStack const *stack,
+ ProfilerTotals totals)
+{
+ fprintf(prof_file, "{\n\"program\": \"%s\",\n", prog_name);
+ fprintf(prof_file, "\"arguments\": [");
+ for (int count = 0; prog_argv[count]; count++)
+ fprintf(prof_file, "%s\"%s\"",
+ count == 0 ? "" : ", ", prog_argv[count]);
+ fprintf(prof_file, "],\n\"rts_arguments\": [");
+ for (int count = 0; rts_argv[count]; count++)
+ fprintf(prof_file, "%s\"%s\"",
+ count == 0 ? "" : ", ", rts_argv[count]);
+ fprintf(prof_file, "],\n");
+
+ fprintf(prof_file, "\"end_time\": \"%s\",\n", time_str());
+ fprintf(prof_file, "\"initial_capabilities\": %d,\n",
+ RtsFlags.ParFlags.nCapabilities);
+ fprintf(prof_file, "\"total_time\": %11.2f,\n",
+ ((double) totals.total_prof_ticks *
+ (double) RtsFlags.MiscFlags.tickInterval) / (TIME_RESOLUTION * n_capabilities));
+ fprintf(prof_file, "\"total_ticks\": %lu,\n",
+ (unsigned long) totals.total_prof_ticks);
+ fprintf(prof_file, "\"tick_interval\": %d,\n",
+ (int) TimeToUS(RtsFlags.MiscFlags.tickInterval));
+ fprintf(prof_file, "\"total_alloc\":%" FMT_Word64 ",\n",
+ totals.total_alloc * sizeof(W_));
+
+ fprintf(prof_file, "\"cost_centres\": ");
+ logCostCentres(prof_file);
+ fprintf(prof_file, ",\n\"profile\": ");
+ logCostCentreStack(prof_file, stack);
+ fprintf(prof_file, "}\n");
+}
+
+
+#endif /* PROFILING */