Files
mercury/trace/mercury_trace_cmd_exp.c
Mark Brown d465fa53cb Update the COPYING.LIB file and references to it.
Discussion of these changes can be found on the Mercury developers
mailing list archives from June 2018.

COPYING.LIB:
    Add a special linking exception to the LGPL.

*:
    Update references to COPYING.LIB.

    Clean up some minor errors that have accumulated in copyright
    messages.
2018-06-09 17:43:12 +10:00

356 lines
11 KiB
C

// vim: ts=4 sw=4 expandtab ft=c
// Copyright (C) 1998-2007 The University of Melbourne.
// Copyright (C) 2014, 2016, 2018 The Mercury team.
// This file is distributed under the terms specified in COPYING.LIB.
// This module implements the mdb commands in the "exp" category.
//
// The structure of these files is:
//
// - all the #includes
// - local macros and declarations of local static functions
// - one function for each command in the category
// - any auxiliary functions
// - any command argument strings
// - option processing functions.
#include "mercury_std.h"
#include "mercury_getopt.h"
#include "mercury_runtime_util.h"
#include "mercury_trace_internal.h"
#include "mercury_trace_cmds.h"
#include "mercury_trace_cmd_exp.h"
#include "mercury_trace_cmd_parameter.h"
#include "mercury_trace_util.h"
#include "mdbcomp.slice_and_dice.mh"
#include <stdio.h>
////////////////////////////////////////////////////////////////////////////
// The default number of lines to display for a dice.
#define MR_DEFAULT_DICE_LINES 50
static void MR_trace_print_dice(char *pass_trace_counts_file,
char *fail_trace_counts_file, char *sort_str,
int number_of_lines, char *out_str, char *module);
static MR_bool MR_trace_options_dice(char **pass_trace_counts_file,
char **fail_trace_count_file, char **sort_str,
MR_Unsigned *number_of_lines, char **out_file,
char **module, char ***words, int *word_count);
////////////////////////////////////////////////////////////////////////////
MR_Next
MR_trace_cmd_histogram_all(char **words, int word_count,
MR_TraceCmdInfo *cmd, MR_EventInfo *event_info, MR_Code **jumpaddr)
{
#ifdef MR_TRACE_HISTOGRAM
if (word_count == 2) {
FILE *fp;
fp = fopen(words[1], "w");
if (fp == NULL) {
fflush(MR_mdb_out);
fprintf(MR_mdb_err, "mdb: cannot open file `%s' for output: %s.\n",
words[1], MR_strerror(errno, errbuf, sizeof(errbuf)));
} else {
MR_trace_print_histogram(fp, "All-inclusive",
MR_trace_histogram_all,
MR_trace_histogram_hwm);
if (fclose(fp) != 0) {
fflush(MR_mdb_out);
fprintf(MR_mdb_err, "mdb: error closing file `%s': %s.\n",
words[1], MR_strerror(errno, errbuf, sizeof(errbuf)));
}
}
} else {
MR_trace_usage_cur_cmd();
}
#else // MR_TRACE_HISTOGRAM
fprintf(MR_mdb_out, "mdb: the `histogram_all' command is available "
"only when histogram gathering is enabled.\n");
#endif // MR_TRACE_HISTOGRAM
return KEEP_INTERACTING;
}
MR_Next
MR_trace_cmd_histogram_exp(char **words, int word_count,
MR_TraceCmdInfo *cmd, MR_EventInfo *event_info, MR_Code **jumpaddr)
{
#ifdef MR_TRACE_HISTOGRAM
if (word_count == 2) {
FILE *fp;
fp = fopen(words[1], "w");
if (fp == NULL) {
fflush(MR_mdb_out);
fprintf(MR_mdb_err, "mdb: cannot open file `%s' for output: %s.\n",
words[1], MR_strerror(errno, errbuf, sizeof(errbuf)));
} else {
MR_trace_print_histogram(fp, "Experimental",
MR_trace_histogram_exp,
MR_trace_histogram_hwm);
if (fclose(fp) != 0) {
fflush(MR_mdb_out);
fprintf(MR_mdb_err, "mdb: error closing file `%s': %s.\n",
words[1], MR_strerror(errno, errbuf, sizeof(errbuf)));
}
}
} else {
MR_trace_usage_cur_cmd();
}
#else // MR_TRACE_HISTOGRAM
fprintf(MR_mdb_out, "mdb: the `histogram_exp' command is available "
"only when histogram gathering is enabled.\n");
#endif // MR_TRACE_HISTOGRAM
return KEEP_INTERACTING;
}
MR_Next
MR_trace_cmd_clear_histogram(char **words, int word_count,
MR_TraceCmdInfo *cmd, MR_EventInfo *event_info, MR_Code **jumpaddr)
{
#ifdef MR_TRACE_HISTOGRAM
if (word_count == 1) {
int i;
for (i = 0; i <= MR_trace_histogram_hwm; i++) {
MR_trace_histogram_exp[i] = 0;
}
} else {
MR_trace_usage_cur_cmd();
}
#else // MR_TRACE_HISTOGRAM
fprintf(MR_mdb_out, "mdb: the `clear_histogram' command is available "
"only when histogram gathering is enabled.\n");
#endif // MR_TRACE_HISTOGRAM
return KEEP_INTERACTING;
}
MR_Next
MR_trace_cmd_dice(char **words, int word_count, MR_TraceCmdInfo *cmd,
MR_EventInfo *event_info, MR_Code **jumpaddr)
{
char *pass_trace_counts_file;
char *fail_trace_counts_file;
char *sort_str;
char *out_file;
char *module;
MR_Unsigned number_of_lines;
sort_str = NULL;
out_file = NULL;
module = NULL;
number_of_lines = MR_DEFAULT_DICE_LINES;
pass_trace_counts_file = MR_dice_pass_trace_counts_file;
fail_trace_counts_file = MR_dice_fail_trace_counts_file;
if (! MR_trace_options_dice(&pass_trace_counts_file,
&fail_trace_counts_file, &sort_str, &number_of_lines, &out_file,
&module, &words, &word_count))
{
// The usage message has already been printed.
;
} else if (word_count == 1) {
if (pass_trace_counts_file == NULL) {
fflush(MR_mdb_out);
fprintf(MR_mdb_err, "mdb: No passing trace counts file specified."
"\nmdb: Specify one with the -p option or using the `set' "
"command.\n");
} else if (fail_trace_counts_file == NULL) {
fflush(MR_mdb_out);
fprintf(MR_mdb_err, "mdb: No failing trace counts file specified."
"\nmdb: Specify one with the -f option or using the `set' "
"command.\n");
} else {
if (sort_str == NULL) {
sort_str = MR_copy_string("");
}
if (module == NULL) {
module = MR_copy_string("");
}
MR_trace_print_dice(pass_trace_counts_file, fail_trace_counts_file,
sort_str, number_of_lines, out_file, module);
}
} else {
MR_trace_usage_cur_cmd();
}
if (out_file != NULL) {
free(out_file);
}
if (sort_str != NULL) {
free(sort_str);
}
if (module != NULL) {
free(module);
}
return KEEP_INTERACTING;
}
////////////////////////////////////////////////////////////////////////////
static void
MR_trace_print_dice(char *pass_trace_counts_file,
char *fail_trace_count_file, char *sort_str, int number_of_lines,
char *out_file, char *module)
{
MR_String dice;
MR_String problem;
MR_String aligned_pass_trace_counts_file;
MR_String aligned_fail_trace_count_file;
MR_String aligned_sort_str;
MR_String aligned_module;
FILE *fp;
char errbuf[MR_STRERROR_BUF_SIZE];
MR_TRACE_USE_HP(
MR_make_aligned_string(aligned_pass_trace_counts_file,
(MR_String) pass_trace_counts_file);
MR_make_aligned_string(aligned_fail_trace_count_file,
(MR_String) fail_trace_count_file);
MR_make_aligned_string(aligned_sort_str, (MR_String) sort_str);
if (module == NULL) {
MR_make_aligned_string(aligned_module, (MR_String) "");
} else {
MR_make_aligned_string(aligned_module, (MR_String) module);
}
);
MR_TRACE_CALL_MERCURY(
MR_MDBCOMP_read_dice_to_string(aligned_pass_trace_counts_file,
aligned_fail_trace_count_file, aligned_sort_str,
number_of_lines, aligned_module, &dice, &problem);
);
// The string in dice is a sequence of complete lines.
if (MR_streq(problem, "")) {
if (out_file == NULL) {
fprintf(MR_mdb_out, "%s", dice);
} else {
fp = fopen(out_file, "w");
if (fp != NULL) {
fprintf(fp, "%s", dice);
if (fclose(fp) != 0) {
fflush(MR_mdb_out);
fprintf(MR_mdb_err, "mdb: Error closing file `%s': %s\n",
out_file, MR_strerror(errno, errbuf, sizeof(errbuf)));
}
} else {
fflush(MR_mdb_out);
fprintf(MR_mdb_err, "mdb: Error opening file `%s': %s\n",
out_file, MR_strerror(errno, errbuf, sizeof(errbuf)));
}
}
} else {
fflush(MR_mdb_out);
fprintf(MR_mdb_err, "mdb: %s\n", problem);
}
}
////////////////////////////////////////////////////////////////////////////
static struct MR_option MR_trace_dice_opts[] =
{
{ "pass-trace-counts", MR_required_argument, NULL, 'p' },
{ "pass-trace-count", MR_required_argument, NULL, 'p' },
{ "fail-trace-counts", MR_required_argument, NULL, 'f' },
{ "fail-trace-count", MR_required_argument, NULL, 'f' },
{ "sort", MR_required_argument, NULL, 's' },
{ "top", MR_required_argument, NULL, 'n' },
{ "output-to-file", MR_required_argument, NULL, 'o' },
{ "module", MR_required_argument, NULL, 'm' },
{ NULL, MR_no_argument, NULL, 0 }
};
static MR_bool
MR_trace_options_dice(char **pass_trace_counts_file,
char **fail_trace_counts_file, char **sort_str, MR_Unsigned *n,
char **out_file, char **module, char ***words, int *word_count)
{
int c;
MR_optind = 0;
while ((c = MR_getopt_long(*word_count, *words, "p:f:s:n:o:m:",
MR_trace_dice_opts, NULL)) != EOF)
{
switch (c) {
case 'p':
// Don't free *pass_trace_counts_file even if non-NULL,
// since its initial value comes from a global variable,
// and thus will still be used after the dice command.
// The waste of not freeing of the string allocated by
// MR_copy_string if this option is duplicated can be
// easily lived with.
*pass_trace_counts_file = MR_copy_string(MR_optarg);
break;
case 'f':
// Don't free *fail_trace_counts_file even if non-NULL,
// since its initial value comes from a global variable,
// and thus will still be used after the dice command.
// The waste of not freeing of the string allocated by
// MR_copy_string if this option is duplicated can be
// easily lived with.
*fail_trace_counts_file = MR_copy_string(MR_optarg);
break;
case 's':
*sort_str = MR_copy_string(MR_optarg);
break;
case 'n':
if (! MR_trace_is_natural_number(MR_optarg, n)) {
MR_trace_usage_cur_cmd();
return MR_FALSE;
}
break;
case 'o':
*out_file = MR_copy_string(MR_optarg);
break;
case 'm':
*module = MR_copy_string(MR_optarg);
break;
default:
MR_trace_usage_cur_cmd();
return MR_FALSE;
}
}
*words = *words + MR_optind - 1;
*word_count = *word_count - MR_optind + 1;
return MR_TRUE;
}