diff options
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 */ |