diff options
author | Ben Gamari <bgamari.foss@gmail.com> | 2017-02-23 13:22:48 -0500 |
---|---|---|
committer | Ben Gamari <ben@smart-cactus.org> | 2017-02-23 17:26:44 -0500 |
commit | a20433326eabd759502d9c170c3cc44ce6128a04 (patch) | |
tree | 72ba807d45f05460dcfad02d437d9b79c0518481 /rts/ProfilerReportJson.c | |
parent | 0a77cedb914a67b8bd7c4af1f87714dc497fec3e (diff) | |
download | haskell-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.c | 127 |
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 */ |