[m-rev.] for review: handle I/O errors when reporting statistics
Julien Fischer
jfischer at opturion.com
Mon Apr 5 03:38:39 AEST 2021
For review by anynone.
Handle I/O errors when reporting statistics.
Detect I/O errors that occur when reporting statistics and handle them them by
throwing io.error exceptions.
runtime/mercury_report_stats.[ch]:
Make MR_report_{standard,full_memory}_stats return zero on success
or errno if an I/O error occurs.
library/io.m:
Return a system_error indication from the report statistics predicates
and throw an io.error exception on an error.
library/benchmarking.m:
Implement report_stats/0 and report_full_memory_stats/0 by calling the
report statistics predicates from the io module rather then by using
foreign_procs. This ensures we get identical error handling behaviour
between the two modules.
Simplify the C# and Java statistics reporting methods.
Julien.
diff --git a/library/benchmarking.m b/library/benchmarking.m
index 0768d68c1..25097fd74 100644
--- a/library/benchmarking.m
+++ b/library/benchmarking.m
@@ -173,68 +173,18 @@
%---------------------%
report_stats :-
- impure do_report_stats(io.stderr_stream).
-
-:- impure pred do_report_stats(io.text_output_stream::in) is det.
-
-:- pragma foreign_proc("C",
- do_report_stats(S::in),
- [will_not_call_mercury],
-"
- MercuryFile mf = *(MR_unwrap_output_stream(S));
- MR_report_standard_stats(MR_file(mf), &MR_line_number(mf));
-").
-
-:- pragma foreign_proc("C#",
- do_report_stats(Stream::in),
- [may_call_mercury, terminates],
-"
- // The field F1 is the first field of io.output_stream/1
- // functor.
- ML_report_standard_stats(Stream.F1);
-").
-
-:- pragma foreign_proc("Java",
- do_report_stats(Stream::in),
- [may_call_mercury, terminates],
-"
- // The field F1 is the first field of io.output_stream/1
- // functor. The downcast is required because streams are
- // passed around as MR_MercuryFileStructs.
- ML_report_standard_stats((io.MR_TextOutputFile) Stream.F1);
-").
+ trace [io(!IO)] (
+ io.report_standard_stats(!IO)
+ ),
+ impure impure_true.
%---------------------%
report_full_memory_stats :-
- impure do_report_full_memory_stats(io.stderr_stream).
-
-:- impure pred do_report_full_memory_stats(io.text_output_stream::in) is det.
-
-:- pragma foreign_proc("C",
- do_report_full_memory_stats(Stream::in),
- [will_not_call_mercury],
-"
- MercuryFile mf = *(MR_unwrap_output_stream(Stream));
- MR_report_full_memory_stats(MR_file(mf), &MR_line_number(mf));
-").
-
-:- pragma foreign_proc("C#",
- do_report_full_memory_stats(Stream::in),
- [will_not_call_mercury],
-"
- // See above for an explanation of what F1 does.
- ML_report_full_memory_stats(Stream.F1);
-").
-
-:- pragma foreign_proc("Java",
- do_report_full_memory_stats(Stream::in),
- [will_not_call_mercury],
-"
- // See above for an explanation of what F1 does and why
- // the downcast is necessary here.
- ML_report_full_memory_stats((io.MR_TextOutputFile) Stream.F1);
-").
+ trace [io(!IO)] (
+ io.report_full_memory_stats(!IO)
+ ),
+ impure impure_true.
%---------------------------------------------------------------------------%
@@ -288,21 +238,17 @@ ML_report_standard_stats(io.MR_MercuryFileStruct stream)
long real_time_at_prev_stat = real_time_at_last_stat;
real_time_at_last_stat = System.DateTime.Now.Ticks;
- try {
- io.mercury_print_string(stream, System.String.Format(
- ""[User time: +{0:F2}s, {1:F2}s Real time: +{2:F2}s, {3:F2}s]\\n"",
- (user_time_at_last_stat - user_time_at_prev_stat),
- (user_time_at_last_stat - user_time_at_start),
- ((real_time_at_last_stat - real_time_at_prev_stat)
- / (double) System.TimeSpan.TicksPerSecond),
- ((real_time_at_last_stat - real_time_at_start)
- / (double) System.TimeSpan.TicksPerSecond)
- ));
- // XXX At this point there should be a whole bunch of memory usage
- // statistics.
- } catch (System.SystemException e) {
- // XXX how should we handle I/O errors when printing statistics?
- }
+ io.mercury_print_string(stream, System.String.Format(
+ ""[User time: +{0:F2}s, {1:F2}s Real time: +{2:F2}s, {3:F2}s]\\n"",
+ (user_time_at_last_stat - user_time_at_prev_stat),
+ (user_time_at_last_stat - user_time_at_start),
+ ((real_time_at_last_stat - real_time_at_prev_stat)
+ / (double) System.TimeSpan.TicksPerSecond),
+ ((real_time_at_last_stat - real_time_at_start)
+ / (double) System.TimeSpan.TicksPerSecond)
+ ));
+ // XXX At this point there should be a whole bunch of memory usage
+ // statistics.
}
public static void
@@ -311,14 +257,9 @@ ML_report_full_memory_stats(io.MR_MercuryFileStruct stream)
// XXX The support for this predicate is even worse. Since we don't have
// access to memory usage statistics, all you get here is an apology.
// But at least it doesn't just crash with an error.
-
- try {
- io.mercury_print_string(stream,
- ""Sorry, report_full_memory_stats is not yet "" +
+ io.mercury_print_string(stream,
+ ""Sorry, report_full_memory_stats is not yet "" +
""implemented for the C# back-end.\\n"");
- } catch (System.SystemException e) {
- // XXX how should we handle I/O errors when printing statistics?
- }
}
").
@@ -341,6 +282,7 @@ ML_initialise()
public static void
ML_report_standard_stats(jmercury.io.MR_TextOutputFile stream)
+ throws java.io.IOException
{
int user_time_at_prev_stat = user_time_at_last_stat;
user_time_at_last_stat = ML_get_user_cpu_milliseconds();
@@ -348,44 +290,35 @@ ML_report_standard_stats(jmercury.io.MR_TextOutputFile stream)
long real_time_at_prev_stat = real_time_at_last_stat;
real_time_at_last_stat = System.currentTimeMillis();
- try {
- stream.write(
- ""[User time: +"" +
- ((user_time_at_last_stat - user_time_at_prev_stat) / 1000.0) +
- ""s, "" +
- ((user_time_at_last_stat - user_time_at_start) / 1000.0) +
- ""s"");
-
- stream.write(
- "" Real time: +"" +
- ((real_time_at_last_stat - real_time_at_prev_stat) / 1000.0) +
- ""s, "" +
- ((real_time_at_last_stat - real_time_at_start) / 1000.0) +
- ""s"");
-
- // XXX At this point there should be a whole bunch of memory usage
- // statistics. Unfortunately the Java back-end does not yet support
- // this amount of profiling, so cpu time is all you get.
-
- stream.write(""]\\n"");
- } catch (java.io.IOException e) {
- // XXX how should we handle I/O errors when printing statistics?
- }
+ stream.write(
+ ""[User time: +"" +
+ ((user_time_at_last_stat - user_time_at_prev_stat) / 1000.0) +
+ ""s, "" +
+ ((user_time_at_last_stat - user_time_at_start) / 1000.0) +
+ ""s"");
+
+ stream.write(
+ "" Real time: +"" +
+ ((real_time_at_last_stat - real_time_at_prev_stat) / 1000.0) +
+ ""s, "" +
+ ((real_time_at_last_stat - real_time_at_start) / 1000.0) +
+ ""s"");
+
+ // XXX At this point there should be a whole bunch of memory usage
+ // statistics. Unfortunately the Java back-end does not yet support
+ // this amount of profiling, so cpu time is all you get.
}
public static void
ML_report_full_memory_stats(jmercury.io.MR_TextOutputFile stream)
+ throws java.io.IOException
{
// XXX The support for this predicate is even worse. Since we don't have
// access to memory usage statistics, all you get here is an apology.
// But at least it doesn't just crash with an error.
- try {
- stream.write(""Sorry, report_full_memory_stats is not yet "" +
- ""implemented for the Java back-end."");
- } catch (java.io.IOException e) {
- // XXX how should we handle I/O errors when printing statistics?
- }
+ stream.write(""Sorry, report_full_memory_stats is not yet "" +
+ ""implemented for the Java back-end."");
}
").
diff --git a/library/io.m b/library/io.m
index 7132df86f..8444a8979 100644
--- a/library/io.m
+++ b/library/io.m
@@ -12110,69 +12110,95 @@ report_stats(Selector, !IO) :-
%---------------------%
report_standard_stats(output_stream(Stream), !IO) :-
- report_standard_stats_2(Stream, !IO).
+ report_standard_stats_2(Stream, Error, !IO),
+ throw_on_output_error(Error, !IO).
report_standard_stats(!IO) :-
io.stderr_stream(StdErr, !IO),
report_standard_stats(StdErr, !IO).
-:- pred report_standard_stats_2(io.stream::in, io::di, io::uo) is det.
+:- pred report_standard_stats_2(io.stream::in, system_error::out,
+ io::di, io::uo) is det.
:- pragma foreign_proc("C",
- report_standard_stats_2(Stream::in, _IO0::di, _IO::uo),
+ report_standard_stats_2(Stream::in, Error::out, _IO0::di, _IO::uo),
[promise_pure, will_not_call_mercury, tabled_for_io,
does_not_affect_liveness],
"
- MR_report_standard_stats(MR_file(*Stream), &MR_line_number(*Stream));
+ Error = MR_report_standard_stats(MR_file(*Stream),
+ &MR_line_number(*Stream));
").
:- pragma foreign_proc("C#",
- report_standard_stats_2(Stream::in, _IO0::di, _IO::uo),
+ report_standard_stats_2(Stream::in, Error::out, _IO0::di, _IO::uo),
[promise_pure, will_not_call_mercury],
"
- benchmarking.ML_report_standard_stats(Stream);
+ try {
+ benchmarking.ML_report_standard_stats(Stream);
+ Error = null;
+ } catch (System.SystemException e) {
+ Error = e;
+ }
").
:- pragma foreign_proc("Java",
- report_standard_stats_2(Stream::in, _IO0::di, _IO::uo),
+ report_standard_stats_2(Stream::in, Error::out, _IO0::di, _IO::uo),
[promise_pure, will_not_call_mercury],
"
- jmercury.benchmarking.ML_report_standard_stats(
- (jmercury.io.MR_TextOutputFile) Stream);
+ try {
+ jmercury.benchmarking.ML_report_standard_stats(
+ (jmercury.io.MR_TextOutputFile) Stream);
+ Error = null;
+ } catch (java.io.IOException e) {
+ Error = e;
+ }
").
%---------------------%
report_full_memory_stats(output_stream(Stream), !IO) :-
- report_full_memory_stats_2(Stream, !IO).
+ report_full_memory_stats_2(Stream, Error, !IO),
+ throw_on_output_error(Error, !IO).
report_full_memory_stats(!IO) :-
io.stderr_stream(StdErr, !IO),
report_full_memory_stats(StdErr, !IO).
-:- pred report_full_memory_stats_2(io.stream::in, io::di, io::uo) is det.
+:- pred report_full_memory_stats_2(io.stream::in, system_error::out,
+ io::di, io::uo) is det.
:- pragma foreign_proc("C",
- report_full_memory_stats_2(Stream::in, _IO0::di, _IO::uo),
+ report_full_memory_stats_2(Stream::in, Error::out, _IO0::di, _IO::uo),
[promise_pure, will_not_call_mercury, tabled_for_io,
does_not_affect_liveness],
"
- MR_report_full_memory_stats(MR_file(*Stream), &MR_line_number(*Stream));
+ Error = MR_report_full_memory_stats(MR_file(*Stream),
+ &MR_line_number(*Stream));
").
:- pragma foreign_proc("C#",
- report_full_memory_stats_2(Stream::in, _IO0::di, _IO::uo),
+ report_full_memory_stats_2(Stream::in, Error::out, _IO0::di, _IO::uo),
[promise_pure, will_not_call_mercury],
"
- benchmarking.ML_report_full_memory_stats(Stream);
+ try {
+ benchmarking.ML_report_full_memory_stats(Stream);
+ Error = null;
+ } catch (System.SystemException e) {
+ Error = e;
+ }
").
:- pragma foreign_proc("Java",
- report_full_memory_stats_2(Stream::in, _IO0::di, _IO::uo),
+ report_full_memory_stats_2(Stream::in, Error::out, _IO0::di, _IO::uo),
[promise_pure, will_not_call_mercury],
"
- jmercury.benchmarking.ML_report_full_memory_stats(
- (jmercury.io.MR_TextOutputFile) Stream);
+ try {
+ jmercury.benchmarking.ML_report_full_memory_stats(
+ (jmercury.io.MR_TextOutputFile) Stream);
+ Error = null;
+ } catch (java.io.IOException e) {
+ Error = e;
+ }
").
%---------------------%
diff --git a/runtime/mercury_report_stats.c b/runtime/mercury_report_stats.c
index 0efa0bad1..73888f34f 100644
--- a/runtime/mercury_report_stats.c
+++ b/runtime/mercury_report_stats.c
@@ -10,6 +10,7 @@
////////////////////////////////////////////////////////////////////////////
#include <stdlib.h>
+#include <errno.h>
#include "mercury_prof_mem.h"
#include "mercury_heap_profile.h"
#include "mercury_wrapper.h" // for MR_user_time_at_last_stat
@@ -57,7 +58,7 @@
static int MR_memory_profile_fill_table(MR_memprof_record *node,
MR_memprof_report_entry *table, int next_slot);
- static void MR_memory_profile_report(FILE *fp, int *line_number,
+ static int MR_memory_profile_report(FILE *fp, int *line_number,
const MR_memprof_report_entry *,
int num_entries, MR_bool complete);
@@ -66,7 +67,7 @@
#endif // MR_MPROF_PROFILE_MEMORY
-void
+int
MR_report_standard_stats(FILE *fp, int *line_number)
{
int user_time_at_prev_stat;
@@ -78,6 +79,7 @@ MR_report_standard_stats(FILE *fp, int *line_number)
int num_table_entries;
MR_memprof_report_entry table[MEMORY_PROFILE_SIZE];
#endif
+ int profile_report_result;
// Print timing and stack usage information.
@@ -91,23 +93,35 @@ MR_report_standard_stats(FILE *fp, int *line_number)
eng = MR_get_engine();
#endif
- fprintf(fp, "[User time: +%.3fs, %.3fs,",
- (MR_user_time_at_last_stat - user_time_at_prev_stat) / 1000.0,
- (MR_user_time_at_last_stat - MR_user_time_at_start) / 1000.0
- );
+ if (
+ fprintf(fp, "[User time: +%.3fs, %.3fs,",
+ (MR_user_time_at_last_stat - user_time_at_prev_stat) / 1000.0,
+ (MR_user_time_at_last_stat - MR_user_time_at_start) / 1000.0
+ ) < 0
+ ) {
+ return errno;
+ }
- fprintf(fp, " Real time: +%.3fs, %.3fs,",
- (MR_real_time_at_last_stat - real_time_at_prev_stat) / 1000.0,
- (MR_real_time_at_last_stat - MR_real_time_at_start) / 1000.0
- );
+ if (
+ fprintf(fp, " Real time: +%.3fs, %.3fs,",
+ (MR_real_time_at_last_stat - real_time_at_prev_stat) / 1000.0,
+ (MR_real_time_at_last_stat - MR_real_time_at_start) / 1000.0
+ ) < 0
+ ) {
+ return errno;
+ }
#ifndef MR_HIGHLEVEL_CODE
- fprintf(fp, " D Stack: %.3fk, ND Stack: %.3fk,",
- ((char *) MR_sp - (char *)
- eng->MR_eng_context.MR_ctxt_detstack_zone->MR_zone_min) / 1024.0,
- ((char *) MR_maxfr - (char *)
- eng->MR_eng_context.MR_ctxt_nondetstack_zone->MR_zone_min) / 1024.0
- );
+ if (
+ fprintf(fp, " D Stack: %.3fk, ND Stack: %.3fk,",
+ ((char *) MR_sp - (char *)
+ eng->MR_eng_context.MR_ctxt_detstack_zone->MR_zone_min) / 1024.0,
+ ((char *) MR_maxfr - (char *)
+ eng->MR_eng_context.MR_ctxt_nondetstack_zone->MR_zone_min) / 1024.0
+ ) < 0
+ ) {
+ return errno;
+ }
#endif
#ifdef MR_BOEHM_GC
@@ -116,25 +130,39 @@ MR_report_standard_stats(FILE *fp, int *line_number)
struct GC_stack_base base;
if (GC_SUCCESS == GC_get_stack_base(&base)) {
- fprintf(fp, " C Stack: %.3fk,",
- labs(&local_var - (char *)base.mem_base) / 1024.0);
+ if (
+ fprintf(fp, " C Stack: %.3fk,",
+ labs(&local_var - (char *) base.mem_base) / 1024.0) < 0
+ ) {
+ return errno;
+ }
} else {
- fprintf(fp, " Cannot locate C stack base.");
+ if (fprintf(fp, " Cannot locate C stack base.") < 0) {
+ return errno;
+ }
}
}
#endif
#ifdef MR_USE_TRAIL
#ifdef MR_THREAD_SAFE
- fprintf(fp, ", Trail: %.3fk,",
- ((char *) MR_trail_ptr -
- (char *) MR_CONTEXT(MR_ctxt_trail_zone)->MR_zone_min) / 1024.0
- );
+ if (
+ fprintf(fp, ", Trail: %.3fk,",
+ ((char *) MR_trail_ptr -
+ (char *) MR_CONTEXT(MR_ctxt_trail_zone)->MR_zone_min) / 1024.0
+ ) < 0
+ ) {
+ return errno;
+ }
#else
- fprintf(fp, " Trail: %.3fk,",
- ((char *) MR_trail_ptr -
- (char *) MR_trail_zone->MR_zone_min) / 1024.0
- );
+ if (
+ fprintf(fp, " Trail: %.3fk,",
+ ((char *) MR_trail_ptr -
+ (char *) MR_trail_zone->MR_zone_min) / 1024.0
+ ) < 0
+ ) {
+ return errno;
+ }
#endif // !MR_THREAD_SAFE
#endif // !MR_USE_TRAIL
@@ -142,23 +170,35 @@ MR_report_standard_stats(FILE *fp, int *line_number)
#ifdef MR_CONSERVATIVE_GC
#ifdef MR_BOEHM_GC
- fprintf(fp, "\n#GCs: %lu, ",
- (unsigned long) GC_get_gc_no());
+ if (fprintf(fp, "\n#GCs: %lu, ", (unsigned long) GC_get_gc_no()) < 0) {
+ return errno;
+ }
if (GC_mercury_calc_gc_time) {
// Convert from unsigned long milliseconds to float seconds.
- fprintf(fp, "total GC time: %.2fs, ",
- (float) GC_total_gc_time / (float) 1000);
+ if (fprintf(fp, "total GC time: %.2fs, ",
+ (float) GC_total_gc_time / (float) 1000) < 0
+ ) {
+ return errno;
+ }
+ }
+ if (
+ fprintf(fp, "Heap used since last GC: %.3fk, Total used: %.3fk",
+ GC_get_bytes_since_gc() / 1024.0,
+ GC_get_heap_size() / 1024.0
+ ) < 0
+ ) {
+ return errno;
}
- fprintf(fp, "Heap used since last GC: %.3fk, Total used: %.3fk",
- GC_get_bytes_since_gc() / 1024.0,
- GC_get_heap_size() / 1024.0
- );
(*line_number)++;
#endif
#else // !MR_CONSERVATIVE_GC
- fprintf(fp, "\nHeap: %.3fk",
- ((char *) MR_hp - (char *) eng->MR_eng_heap_zone->MR_zone_min) / 1024.0
- );
+ if (
+ fprintf(fp, "\nHeap: %.3fk",
+ ((char *) MR_hp - (char *) eng->MR_eng_heap_zone->MR_zone_min) / 1024.0
+ ) < 0)
+ {
+ return errno;
+ }
(*line_number)++;
#endif // !MR_CONSERVATIVE_GC
@@ -171,45 +211,66 @@ MR_report_standard_stats(FILE *fp, int *line_number)
// Print out the per-procedure memory profile (top N entries).
num_table_entries = MR_memory_profile_top_table(MR_memprof_procs.root,
table, MEMORY_PROFILE_SIZE, 0);
- fprintf(fp, "\nMemory profile by procedure\n");
+ if (fprintf(fp, "\nMemory profile by procedure\n") < 0) {
+ return errno;
+ }
*line_number += 2;
- MR_memory_profile_report(fp, line_number, table, num_table_entries,
- MR_FALSE);
+ profile_report_result = MR_memory_profile_report(fp, line_number, table,
+ num_table_entries, MR_FALSE);
+ if (profile_report_result != 0) {
+ return profile_report_result;
+ }
// Print out the per-type memory profile (top N entries).
num_table_entries = MR_memory_profile_top_table(MR_memprof_types.root,
table, MEMORY_PROFILE_SIZE, 0);
- fprintf(fp, "\nMemory profile by type\n");
+ if (fprintf(fp, "\nMemory profile by type\n") < 0) {
+ return errno;
+ }
*line_number += 2;
- MR_memory_profile_report(fp, line_number, table, num_table_entries,
- MR_FALSE);
+ profile_report_result = MR_memory_profile_report(fp, line_number, table,
+ num_table_entries, MR_FALSE);
+ if (profile_report_result != 0) {
+ return profile_report_result;
+ }
// Print out the overall memory usage.
- fprintf(fp, "Overall memory usage:"
- "+%8.8g %8.8g cells, +%8.8g %8.8g words\n",
- MR_overall_memprof_counter.cells_since_period_start,
- MR_overall_memprof_counter.cells_at_period_end,
- MR_overall_memprof_counter.words_since_period_start,
- MR_overall_memprof_counter.words_at_period_end
- );
+ if (
+ fprintf(fp, "Overall memory usage:"
+ "+%8.8g %8.8g cells, +%8.8g %8.8g words\n",
+ MR_overall_memprof_counter.cells_since_period_start,
+ MR_overall_memprof_counter.cells_at_period_end,
+ MR_overall_memprof_counter.words_since_period_start,
+ MR_overall_memprof_counter.words_at_period_end
+ ) < 0
+ ) {
+ return errno;
+ }
(*line_number)++;
#endif // MR_MPROF_PROFILE_MEMORY
- fprintf(fp, "]\n");
+ if (fprintf(fp, "]\n") < 0) {
+ return errno;
+ }
(*line_number)++;
+
+ return 0;
}
-void
+int
MR_report_full_memory_stats(FILE *fp, int *line_number)
{
#ifndef MR_MPROF_PROFILE_MEMORY
- fprintf(fp, "\nMemory profiling is not enabled.\n");
+ if (fprintf(fp, "\nMemory profiling is not enabled.\n") < 0) {
+ return errno;
+ }
*line_number += 2;
#else
int num_table_entries;
int table_size;
MR_memprof_report_entry *table;
+ int profile_report_result;
// Update the overall counter (this needs to be done first,
// so that the percentages come out right).
@@ -228,37 +289,60 @@ MR_report_full_memory_stats(FILE *fp, int *line_number)
table, 0);
qsort(table, MR_memprof_procs.num_entries, sizeof(MR_memprof_report_entry),
MR_memory_profile_compare_final);
- fprintf(fp, "\nMemory profile by procedure\n");
+ if (fprintf(fp, "\nMemory profile by procedure\n") < 0) {
+ return errno;
+ }
*line_number += 2;
- fprintf(fp, "%14s %14s %s\n",
- "Cells", "Words", "Procedure label");
+ if (fprintf(fp, "%14s %14s %s\n",
+ "Cells", "Words", "Procedure label") < 0
+ ) {
+ return errno;
+ }
(*line_number)++;
- MR_memory_profile_report(fp, line_number, table, num_table_entries,
- MR_TRUE);
+ profile_report_result = MR_memory_profile_report(fp, line_number,
+ table, num_table_entries, MR_TRUE);
+ if (profile_report_result != 0) {
+ return profile_report_result;
+ }
// Print the by-type memory profile.
num_table_entries = MR_memory_profile_fill_table(MR_memprof_types.root,
table, 0);
qsort(table, MR_memprof_types.num_entries, sizeof(MR_memprof_report_entry),
MR_memory_profile_compare_final);
- fprintf(fp, "\nMemory profile by type\n");
+ if (fprintf(fp, "\nMemory profile by type\n") < 0) {
+ return errno;
+ }
*line_number += 2;
- fprintf(fp, "%14s %14s %s\n",
- "Cells", "Words", "Procedure label");
+ if (
+ fprintf(fp, "%14s %14s %s\n",
+ "Cells", "Words", "Procedure label") < 0
+ ) {
+ return errno;
+ }
(*line_number)++;
- MR_memory_profile_report(fp, line_number, table, num_table_entries,
- MR_TRUE);
+ profile_report_result = MR_memory_profile_report(fp, line_number, table,
+ num_table_entries, MR_TRUE);
+ if (profile_report_result != 0) {
+ return profile_report_result;
+ }
// Deallocate space for the table.
MR_GC_free(table);
// Print the overall memory usage.
- fprintf(fp, "\nOverall memory usage: %8.8g cells, %8.8g words\n",
- MR_overall_memprof_counter.cells_at_period_end,
- MR_overall_memprof_counter.words_at_period_end
- );
+ if (
+ fprintf(fp, "\nOverall memory usage: %8.8g cells, %8.8g words\n",
+ MR_overall_memprof_counter.cells_at_period_end,
+ MR_overall_memprof_counter.words_at_period_end
+ ) < 0
+ ) {
+ return errno;
+ }
*line_number += 2;
#endif // MR_MPROF_PROFILE_MEMORY
+
+ return 0;
}
#ifdef MR_MPROF_PROFILE_MEMORY
@@ -413,8 +497,9 @@ MR_memory_profile_fill_table(MR_memprof_record *node,
// MR_memory_profile_report(fp, line_number, table, num_entries, complete):
//
// Print out a profiling report for the specified table.
+// Returns zero on success, or errno if an error occurs.
-static void
+static int
MR_memory_profile_report(FILE *fp, int *line_number,
const MR_memprof_report_entry *table, int num_entries, MR_bool complete)
{
@@ -425,17 +510,21 @@ MR_memory_profile_report(FILE *fp, int *line_number,
if (MR_overall_memprof_counter.cells_at_period_end < 1.0
|| MR_overall_memprof_counter.words_at_period_end < 1.0)
{
- fprintf(fp, "no allocations to report\n");
+ if (fprintf(fp, "no allocations to report\n") < 0) {
+ return errno;
+ }
(*line_number)++;
- return;
+ return 0;
}
} else {
if (MR_overall_memprof_counter.cells_since_period_start < 1.0
|| MR_overall_memprof_counter.words_since_period_start < 1.0)
{
- fprintf(fp, "no allocations to report\n");
+ if (fprintf(fp, "no allocations to report\n") < 0) {
+ return errno;
+ }
(*line_number)++;
- return;
+ return 0;
}
}
@@ -445,29 +534,39 @@ MR_memory_profile_report(FILE *fp, int *line_number,
for (i = 0; i < num_entries; i++) {
if (complete) {
- fprintf(fp, "%8.8g/%4.1f%% %8.8g/%4.1f%% %s\n",
- table[i].counter.cells_at_period_end,
- 100 * table[i].counter.cells_at_period_end /
- MR_overall_memprof_counter.cells_at_period_end,
- table[i].counter.words_at_period_end,
- 100 * table[i].counter.words_at_period_end /
- MR_overall_memprof_counter.words_at_period_end,
- table[i].name
- );
+ if (
+ fprintf(fp, "%8.8g/%4.1f%% %8.8g/%4.1f%% %s\n",
+ table[i].counter.cells_at_period_end,
+ 100 * table[i].counter.cells_at_period_end /
+ MR_overall_memprof_counter.cells_at_period_end,
+ table[i].counter.words_at_period_end,
+ 100 * table[i].counter.words_at_period_end /
+ MR_overall_memprof_counter.words_at_period_end,
+ table[i].name
+ ) < 0
+ ) {
+ return errno;
+ }
(*line_number)++;
} else {
- fprintf(fp, "%8.8g/%4.1f%% %8.8g/%4.1f%% %s\n",
- table[i].counter.cells_since_period_start,
- 100 * table[i].counter.cells_since_period_start /
- MR_overall_memprof_counter.cells_since_period_start,
- table[i].counter.words_since_period_start,
- 100 * table[i].counter.words_since_period_start /
- MR_overall_memprof_counter.words_since_period_start,
- table[i].name
- );
+ if (
+ fprintf(fp, "%8.8g/%4.1f%% %8.8g/%4.1f%% %s\n",
+ table[i].counter.cells_since_period_start,
+ 100 * table[i].counter.cells_since_period_start /
+ MR_overall_memprof_counter.cells_since_period_start,
+ table[i].counter.words_since_period_start,
+ 100 * table[i].counter.words_since_period_start /
+ MR_overall_memprof_counter.words_since_period_start,
+ table[i].name
+ ) < 0
+ ) {
+ return errno;
+ }
(*line_number)++;
}
}
+
+ return 0;
}
// Comparison routine used for qsort().
diff --git a/runtime/mercury_report_stats.h b/runtime/mercury_report_stats.h
index 3ffdcbdfc..a1773a452 100644
--- a/runtime/mercury_report_stats.h
+++ b/runtime/mercury_report_stats.h
@@ -13,8 +13,8 @@
#include "mercury_timing.h"
#include "mercury_heap.h"
-extern void MR_report_standard_stats(FILE *fp, int *line_number);
+extern int MR_report_standard_stats(FILE *fp, int *line_number);
-extern void MR_report_full_memory_stats(FILE *fp, int *line_number);
+extern int MR_report_full_memory_stats(FILE *fp, int *line_number);
#endif // not MERCURY_REPORT_STATS_H
More information about the reviews
mailing list