mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-10 19:33:11 +00:00
Branches: main
Implement a type representation optimisation ("direct argument functors"),
where a functor with exactly one argument can be represented by a tagged
pointer to the argument value, which itself does not require the tag bits,
e.g.
:- type maybe_foo ---> yes(foo) ; no.
:- type foo ---> foo(int, int). % aligned pointer
To ensure that all modules which could construct or deconstruct the functor
agree on the type representation, I had planned to automatically output
extra information to .int files to notify importing modules about functors
using the optimised representation:
:- type maybe_foo ---> yes(foo) ; no
where direct_arg is [yes/1].
However, the compiler does not perform enough (or any) semantic analysis
while making interface files. The fallback solution is to only use the
optimised representation when all importing modules can be guaranteed to
import both the top-level type and the argument type, namely, when both
types are exported from the same module. We also allow certain built-in
argument types; currently this only includes tuples.
Non-exported types may use the optimised representation, but when
intermodule optimisation is enabled, they may be written out to .opt files.
Then, we *do* add direct_arg attributes to .opt files to ensure that importing
modules agree on the type representation. The attributes may also be added by
Mercury programmers to source files, which will be copied directly into .int
files without analysis. They will be checked when the module is actually
compiled.
This patch includes work by Zoltan, who independently implemented a version
of this change.
compiler/hlds_data.m:
Record the direct arg functors in hlds_du_type.
Add a new option to cons_tag.
Fix some comments.
compiler/prog_data.m:
compiler/prog_io_type_defn.m:
Parse and record `direct_arg' attributes on type definitions.
compiler/prog_io_pragma.m:
Issue an error if the `direct_arg' attribute is used with a foreign
type.
compiler/make_tags.m:
compiler/mercury_compile_front_end.m:
Add a pass to convert suitable functors to use the direct argument
representation. The argument type must have been added to the type
table, so we do this after all type definitions have been added.
Move code to compute cheaper_tag_test here.
compiler/ml_unify_gen.m:
compiler/unify_gen.m:
Generate different code to construct/deconstruct direct argument
functors.
compiler/intermod.m:
Write `direct_arg' attributes to .opt files for functors
using the direct argument representation.
compiler/mercury_to_mercury.m:
Write out `direct_arg' attributes.
compiler/rtti.m:
compiler/rtti_out.m:
compiler/rtti_to_mlds.m:
Add an option to the types which describe the location of secondary
tag options. The functors which can use the optimised representation
are a subset of those which require no secondary tag.
Output "MR_SECTAG_NONE_DIRECT_ARG" instead of "MR_SECTAG_NONE" in
RTTI structures when applicable.
compiler/add_pragma.m:
compiler/add_type.m:
compiler/bytecode_gen.m:
compiler/check_typeclass.m
compiler/code_info.m:
compiler/equiv_type.m:
compiler/export.m:
compiler/foreign.m:
compiler/hlds_code_util.m:
compiler/hlds_out_module.m:
compiler/inst_check.m:
compiler/ml_proc_gen.m:
compiler/ml_switch_gen.m:
compiler/ml_tag_switch.m:
compiler/ml_type_gen.m:
compiler/module_qual.m:
compiler/modules.m:
compiler/post_term_analysis.m:
compiler/post_typecheck.m:
compiler/recompilation.check.m:
compiler/recompilation.usage.m:
compiler/recompilation.version.m:
compiler/simplify.m:
compiler/structure_reuse.direct.choose_reuse.m:
compiler/switch_gen.m:
compiler/switch_util.m:
compiler/tag_switch.m:
compiler/term_norm.m:
compiler/type_ctor_info.m:
compiler/type_util.m:
compiler/unify_proc.m:
compiler/unused_imports.m:
compiler/xml_documentation.m:
Conform to changes.
Bump RTTI version number.
doc/reference_manual.texi:
Add commented out documentation for `direct_arg' attributes.
library/construct.m:
Handle MR_SECTAG_NONE_DIRECT_ARG in construct.construct/3.
library/private_builtin.m:
Add MR_SECTAG_NONE_DIRECT_ARG constant for Java for consistency,
though it won't be used.
runtime/mercury_grade.h:
Bump binary compatibility version number.
runtime/mercury_type_info.h:
Bump RTTI version number.
Add MR_SECTAG_NONE_DIRECT_ARG.
runtime/mercury_deconstruct.c:
runtime/mercury_deep_copy_body.h:
runtime/mercury_ml_expand_body.h:
runtime/mercury_table_type_body.h:
runtime/mercury_term_size.c:
runtime/mercury_unify_compare_body.h:
Handle MR_SECTAG_NONE_DIRECT_ARG in RTTI code.
tests/debugger/Mmakefile:
tests/debugger/chooser_tag_test.exp:
tests/debugger/chooser_tag_test.inp:
tests/debugger/chooser_tag_test.m:
tests/hard_coded/Mercury.options:
tests/hard_coded/Mmakefile:
tests/hard_coded/construct_test.exp:
tests/hard_coded/construct_test.m:
tests/hard_coded/direct_arg_cyclic1.exp:
tests/hard_coded/direct_arg_cyclic1.m:
tests/hard_coded/direct_arg_cyclic2.m:
tests/hard_coded/direct_arg_cyclic3.m:
tests/hard_coded/direct_arg_intermod1.exp:
tests/hard_coded/direct_arg_intermod1.m:
tests/hard_coded/direct_arg_intermod2.m:
tests/hard_coded/direct_arg_intermod3.m:
tests/hard_coded/direct_arg_parent.exp:
tests/hard_coded/direct_arg_parent.m:
tests/hard_coded/direct_arg_sub.m:
tests/invalid/Mmakefile:
tests/invalid/where_direct_arg.err_exp:
tests/invalid/where_direct_arg.m:
tests/invalid/where_direct_arg2.err_exp:
tests/invalid/where_direct_arg2.m:
Add test cases.
tests/invalid/ee_invalid.err_exp:
Update expected output.
740 lines
24 KiB
C
740 lines
24 KiB
C
/*
|
|
** vim:ts=4 sw=4 expandtab
|
|
*/
|
|
/*
|
|
** Copyright (C) 2003-2005, 2007, 2009, 2011 The University of Melbourne.
|
|
** This file may only be copied under the terms of the GNU Library General
|
|
** Public License - see the file COPYING.LIB in the Mercury distribution.
|
|
*/
|
|
|
|
/*
|
|
** mercury_term_size.c
|
|
**
|
|
** This module defines a function for measuring the sizes of terms.
|
|
*/
|
|
|
|
#include "mercury_imp.h"
|
|
#include <stdio.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <stdlib.h>
|
|
#ifdef MR_HAVE_UNISTD_H
|
|
#include <unistd.h>
|
|
#endif
|
|
#include <string.h>
|
|
|
|
#ifdef MR_RECORD_TERM_SIZES
|
|
|
|
MR_ComplexityCounter MR_complexity_word_counter = 0;
|
|
MR_ComplexityCounter MR_complexity_cell_counter = 0;
|
|
MR_ComplexityCounter MR_complexity_tick_counter = 0;
|
|
|
|
static void MR_write_complexity_proc(MR_ComplexityProc *proc);
|
|
static void MR_complexity_output_args_desc(FILE *fp,
|
|
MR_ComplexityProc *proc);
|
|
|
|
MR_Unsigned
|
|
MR_term_size(MR_TypeInfo type_info, MR_Word term)
|
|
{
|
|
MR_TypeCtorInfo type_ctor_info;
|
|
MR_DuTypeLayout du_type_layout;
|
|
const MR_DuPtagLayout *ptag_layout;
|
|
int ptag;
|
|
int sectag;
|
|
int arity;
|
|
int size;
|
|
|
|
try_again:
|
|
type_ctor_info = MR_TYPEINFO_GET_TYPE_CTOR_INFO(type_info);
|
|
|
|
if (! MR_type_ctor_has_valid_rep(type_ctor_info)) {
|
|
MR_fatal_error("MR_term_size: term of unknown representation");
|
|
}
|
|
|
|
switch (MR_type_ctor_rep(type_ctor_info)) {
|
|
case MR_TYPECTOR_REP_RESERVED_ADDR:
|
|
case MR_TYPECTOR_REP_RESERVED_ADDR_USEREQ:
|
|
/* XXX the code to handle these cases hasn't been written yet */
|
|
MR_fatal_error("MR_term_size: RESERVED_ADDR");
|
|
|
|
case MR_TYPECTOR_REP_DU:
|
|
case MR_TYPECTOR_REP_DU_USEREQ:
|
|
du_type_layout = MR_type_ctor_layout(type_ctor_info).MR_layout_du;
|
|
ptag = MR_tag(term);
|
|
ptag_layout = &du_type_layout[ptag];
|
|
|
|
switch (ptag_layout->MR_sectag_locn) {
|
|
case MR_SECTAG_NONE:
|
|
#ifdef MR_DEBUG_TERM_SIZES
|
|
if (ptag_layout->MR_sectag_alternatives[0]->
|
|
MR_du_functor_orig_arity <= 0)
|
|
{
|
|
MR_fatal_error("MR_term_size: zero arity ptag none");
|
|
}
|
|
|
|
if (MR_heapdebug && MR_lld_print_enabled) {
|
|
printf("MR_term_size: du sectag none %p -> %d\n",
|
|
(void *) term,
|
|
(int) MR_field(MR_mktag(ptag), term, -1));
|
|
printf("type %s.%s/%d, functor %s\n",
|
|
type_ctor_info->MR_type_ctor_module_name,
|
|
type_ctor_info->MR_type_ctor_name,
|
|
type_ctor_info->MR_type_ctor_arity,
|
|
ptag_layout->MR_sectag_alternatives[0]->
|
|
MR_du_functor_name);
|
|
}
|
|
#endif
|
|
return MR_field(MR_mktag(ptag), term, -1);
|
|
|
|
case MR_SECTAG_NONE_DIRECT_ARG:
|
|
/*
|
|
** The compiler should not generate direct arg tags
|
|
** in term size recording grades.
|
|
*/
|
|
MR_fatal_error("MR_term_size: DIRECT_ARG");
|
|
|
|
case MR_SECTAG_LOCAL:
|
|
#ifdef MR_DEBUG_TERM_SIZES
|
|
if (MR_heapdebug && MR_lld_print_enabled) {
|
|
printf("MR_term_size: du sectag local %p\n",
|
|
(void *) term);
|
|
}
|
|
#endif
|
|
return 0;
|
|
|
|
case MR_SECTAG_REMOTE:
|
|
#ifdef MR_DEBUG_TERM_SIZES
|
|
sectag = MR_field(MR_mktag(ptag), term, 0);
|
|
|
|
if (ptag_layout->MR_sectag_alternatives[sectag]->
|
|
MR_du_functor_orig_arity <= 0)
|
|
{
|
|
MR_fatal_error("MR_term_size: zero arity ptag remote");
|
|
}
|
|
|
|
if (MR_heapdebug && MR_lld_print_enabled) {
|
|
printf("MR_term_size: du sectag remote %p -> %d\n",
|
|
(void *) term,
|
|
(int) MR_field(MR_mktag(ptag), term, -1));
|
|
printf("type %s.%s/%d, functor %s\n",
|
|
type_ctor_info->MR_type_ctor_module_name,
|
|
type_ctor_info->MR_type_ctor_name,
|
|
type_ctor_info->MR_type_ctor_arity,
|
|
ptag_layout->MR_sectag_alternatives[sectag]->
|
|
MR_du_functor_name);
|
|
}
|
|
#endif
|
|
return MR_field(MR_mktag(ptag), term, -1);
|
|
|
|
case MR_SECTAG_VARIABLE:
|
|
MR_fatal_error("MR_term_size: VARIABLE");
|
|
|
|
default:
|
|
fprintf(stderr, "sectag_locn: %d\n",
|
|
(int) ptag_layout->MR_sectag_locn);
|
|
MR_fatal_error("MR_term_size: sectag_locn");
|
|
}
|
|
|
|
case MR_TYPECTOR_REP_EQUIV:
|
|
#ifdef MR_DEBUG_TERM_SIZES
|
|
if (MR_heapdebug && MR_lld_print_enabled) {
|
|
printf("MR_term_size: equiv %p\n", (void *) term);
|
|
}
|
|
#endif
|
|
type_info = MR_create_type_info(
|
|
MR_TYPEINFO_GET_FIXED_ARITY_ARG_VECTOR(type_info),
|
|
MR_type_ctor_layout(type_ctor_info).MR_layout_equiv);
|
|
goto try_again;
|
|
|
|
case MR_TYPECTOR_REP_EQUIV_GROUND:
|
|
#ifdef MR_DEBUG_TERM_SIZES
|
|
if (MR_heapdebug && MR_lld_print_enabled) {
|
|
printf("MR_term_size: equiv ground %p\n", (void *) term);
|
|
}
|
|
#endif
|
|
type_info = MR_pseudo_type_info_is_ground(
|
|
MR_type_ctor_layout(type_ctor_info).MR_layout_equiv);
|
|
goto try_again;
|
|
|
|
case MR_TYPECTOR_REP_NOTAG:
|
|
case MR_TYPECTOR_REP_NOTAG_USEREQ:
|
|
#ifdef MR_DEBUG_TERM_SIZES
|
|
if (MR_heapdebug && MR_lld_print_enabled) {
|
|
printf("MR_term_size: notag (usereq) %p\n", (void *) term);
|
|
}
|
|
#endif
|
|
MR_save_transient_hp();
|
|
type_info = MR_create_type_info(
|
|
MR_TYPEINFO_GET_FIXED_ARITY_ARG_VECTOR(type_info),
|
|
MR_type_ctor_layout(type_ctor_info).MR_layout_notag->
|
|
MR_notag_functor_arg_type);
|
|
MR_restore_transient_hp();
|
|
goto try_again;
|
|
|
|
case MR_TYPECTOR_REP_NOTAG_GROUND:
|
|
case MR_TYPECTOR_REP_NOTAG_GROUND_USEREQ:
|
|
#ifdef MR_DEBUG_TERM_SIZES
|
|
if (MR_heapdebug && MR_lld_print_enabled) {
|
|
printf("MR_term_size: notag ground (usereq) %p\n",
|
|
(void *) term);
|
|
}
|
|
#endif
|
|
type_info = MR_pseudo_type_info_is_ground(
|
|
MR_type_ctor_layout(type_ctor_info).MR_layout_notag
|
|
->MR_notag_functor_arg_type);
|
|
goto try_again;
|
|
|
|
case MR_TYPECTOR_REP_TUPLE:
|
|
arity = MR_TYPEINFO_GET_VAR_ARITY_ARITY(type_info);
|
|
if (arity == 0) {
|
|
/* term may be a NULL pointer, so don't follow it */
|
|
size = 0;
|
|
} else {
|
|
size = MR_field(MR_mktag(0), term, -1);
|
|
}
|
|
|
|
#ifdef MR_DEBUG_TERM_SIZES
|
|
if (MR_heapdebug && MR_lld_print_enabled) {
|
|
printf("MR_term_size: tuple %p -> %d\n",
|
|
(void *) term, size);
|
|
}
|
|
#endif
|
|
return size;
|
|
|
|
case MR_TYPECTOR_REP_PRED:
|
|
case MR_TYPECTOR_REP_FUNC:
|
|
#ifdef MR_DEBUG_TERM_SIZES
|
|
if (MR_heapdebug && MR_lld_print_enabled) {
|
|
printf("MR_term_size: pred/func %p\n", (void *) term);
|
|
}
|
|
#endif
|
|
/* currently we don't collect stats on closure sizes */
|
|
return 0;
|
|
|
|
case MR_TYPECTOR_REP_ARRAY:
|
|
/* currently we don't collect stats on array sizes */
|
|
#ifdef MR_DEBUG_TERM_SIZES
|
|
if (MR_heapdebug && MR_lld_print_enabled) {
|
|
printf("MR_term_size: array %p\n", (void *) term);
|
|
}
|
|
#endif
|
|
return 0;
|
|
|
|
case MR_TYPECTOR_REP_BITMAP:
|
|
#ifdef MR_DEBUG_TERM_SIZES
|
|
if (MR_heapdebug && MR_lld_print_enabled) {
|
|
printf("MR_term_size: bitmap %p\n", (void *) term);
|
|
}
|
|
#endif
|
|
return 0;
|
|
|
|
case MR_TYPECTOR_REP_ENUM:
|
|
case MR_TYPECTOR_REP_ENUM_USEREQ:
|
|
#ifdef MR_DEBUG_TERM_SIZES
|
|
if (MR_heapdebug && MR_lld_print_enabled) {
|
|
printf("MR_term_size: enum (usereq) %p\n", (void *) term);
|
|
}
|
|
#endif
|
|
return 0;
|
|
|
|
case MR_TYPECTOR_REP_FOREIGN_ENUM:
|
|
case MR_TYPECTOR_REP_FOREIGN_ENUM_USEREQ:
|
|
#ifdef MR_DEBUG_TERMSIZES
|
|
if (MR_heapdebug && MR_lld_print_enabled) {
|
|
printf("MR_term_size: foreign enum (usereq) %p\n",
|
|
(void *) term);
|
|
}
|
|
#endif
|
|
return 0;
|
|
|
|
case MR_TYPECTOR_REP_INT:
|
|
#ifdef MR_DEBUG_TERM_SIZES
|
|
if (MR_heapdebug && MR_lld_print_enabled) {
|
|
printf("MR_term_size: int %p %ld\n",
|
|
(void *) term, (long) term);
|
|
}
|
|
#endif
|
|
return 0;
|
|
|
|
case MR_TYPECTOR_REP_CHAR:
|
|
#ifdef MR_DEBUG_TERM_SIZES
|
|
if (MR_heapdebug && MR_lld_print_enabled) {
|
|
printf("MR_term_size: char %p %c\n",
|
|
(void *) term, (char) term);
|
|
}
|
|
#endif
|
|
return 0;
|
|
|
|
case MR_TYPECTOR_REP_FLOAT:
|
|
#ifdef MR_DEBUG_TERM_SIZES
|
|
if (MR_heapdebug && MR_lld_print_enabled) {
|
|
printf("MR_term_size: float %p\n", (void *) term);
|
|
}
|
|
#endif
|
|
return 0;
|
|
|
|
case MR_TYPECTOR_REP_STRING:
|
|
#ifdef MR_DEBUG_TERM_SIZES
|
|
if (MR_heapdebug && MR_lld_print_enabled) {
|
|
printf("MR_term_size: string %p '%s'\n",
|
|
(void *) term, (char *) term);
|
|
}
|
|
#endif
|
|
return 0;
|
|
|
|
case MR_TYPECTOR_REP_SUCCIP:
|
|
case MR_TYPECTOR_REP_HP:
|
|
case MR_TYPECTOR_REP_CURFR:
|
|
case MR_TYPECTOR_REP_MAXFR:
|
|
case MR_TYPECTOR_REP_REDOFR:
|
|
case MR_TYPECTOR_REP_REDOIP:
|
|
case MR_TYPECTOR_REP_TRAIL_PTR:
|
|
case MR_TYPECTOR_REP_TICKET:
|
|
#ifdef MR_DEBUG_TERM_SIZES
|
|
if (MR_heapdebug && MR_lld_print_enabled) {
|
|
printf("MR_term_size: impl artifact type %p\n", (void *) term);
|
|
}
|
|
#endif
|
|
return 0;
|
|
|
|
case MR_TYPECTOR_REP_TYPEINFO:
|
|
case MR_TYPECTOR_REP_TYPECLASSINFO:
|
|
case MR_TYPECTOR_REP_TYPECTORINFO:
|
|
case MR_TYPECTOR_REP_BASETYPECLASSINFO:
|
|
case MR_TYPECTOR_REP_TYPEDESC:
|
|
case MR_TYPECTOR_REP_TYPECTORDESC:
|
|
case MR_TYPECTOR_REP_PSEUDOTYPEDESC:
|
|
#ifdef MR_DEBUG_TERM_SIZES
|
|
if (MR_heapdebug && MR_lld_print_enabled) {
|
|
printf("MR_term_size: type_info etc %p\n", (void *) term);
|
|
}
|
|
#endif
|
|
return 0;
|
|
|
|
case MR_TYPECTOR_REP_SUBGOAL:
|
|
#ifdef MR_DEBUG_TERM_SIZES
|
|
if (MR_heapdebug && MR_lld_print_enabled) {
|
|
printf("MR_term_size: subgoal %p\n", (void *) term);
|
|
}
|
|
#endif
|
|
return 0;
|
|
|
|
case MR_TYPECTOR_REP_C_POINTER:
|
|
case MR_TYPECTOR_REP_STABLE_C_POINTER:
|
|
case MR_TYPECTOR_REP_FOREIGN:
|
|
case MR_TYPECTOR_REP_STABLE_FOREIGN:
|
|
#ifdef MR_DEBUG_TERM_SIZES
|
|
if (MR_heapdebug && MR_lld_print_enabled) {
|
|
printf("MR_term_size: c_pointer/foreign %p\n", (void *) term);
|
|
}
|
|
#endif
|
|
return 0;
|
|
|
|
case MR_TYPECTOR_REP_REFERENCE:
|
|
#ifdef MR_DEBUG_TERM_SIZES
|
|
if (MR_heapdebug && MR_lld_print_enabled) {
|
|
printf("MR_term_size: reference %p\n", (void *) term);
|
|
}
|
|
#endif
|
|
return 1;
|
|
|
|
case MR_TYPECTOR_REP_DUMMY:
|
|
#ifdef MR_DEBUG_TERM_SIZES
|
|
if (MR_heapdebug && MR_lld_print_enabled) {
|
|
printf("MR_term_size: dummy %p\n",
|
|
(void *) term);
|
|
}
|
|
#endif
|
|
return 0;
|
|
|
|
case MR_TYPECTOR_REP_VOID:
|
|
MR_fatal_error("MR_term_size: VOID");
|
|
|
|
case MR_TYPECTOR_REP_UNKNOWN:
|
|
MR_fatal_error("MR_term_size: UNKNOWN");
|
|
|
|
default:
|
|
fprintf(stderr, "default rep: %d\n",
|
|
(int) MR_type_ctor_rep(type_ctor_info));
|
|
MR_fatal_error("MR_term_size: default");
|
|
}
|
|
|
|
MR_fatal_error("MR_term_size: unexpected fallthrough");
|
|
}
|
|
|
|
void
|
|
MR_write_complexity_procs(void)
|
|
{
|
|
int proc_num;
|
|
MR_ComplexityProc *proc;
|
|
|
|
for (proc_num = 0; proc_num < MR_num_complexity_procs; proc_num++) {
|
|
proc = &MR_complexity_procs[proc_num];
|
|
if (proc->MR_clp_num_profiled_args >= 0) {
|
|
MR_write_complexity_proc(proc);
|
|
}
|
|
}
|
|
}
|
|
|
|
#define MR_COMPLEXITY_ARGS_DIR "ComplexityArgs"
|
|
#define MR_COMPLEXITY_DATA_DIR "ComplexityData"
|
|
|
|
static MR_bool MR_have_created_complexity_dirs = MR_FALSE;
|
|
static MR_bool MR_have_printed_complexity_dirs_error = MR_FALSE;
|
|
|
|
static void
|
|
MR_write_complexity_proc(MR_ComplexityProc *proc)
|
|
{
|
|
char *full_proc_name;
|
|
int full_proc_name_len;
|
|
FILE *fp;
|
|
char *args_filename;
|
|
char *data_filename;
|
|
const char *data_filemode;
|
|
struct stat statbuf;
|
|
char *slash;
|
|
MR_ComplexityMetrics *metrics;
|
|
int num_profiled_args;
|
|
int *sizes;
|
|
int num_slots;
|
|
MR_ComplexityPastSlots *past_slots;
|
|
char *cmd_buf;
|
|
|
|
full_proc_name_len = strlen(proc->MR_clp_full_proc_name);
|
|
full_proc_name = MR_malloc(100 + full_proc_name_len);
|
|
strcpy(full_proc_name, proc->MR_clp_full_proc_name);
|
|
|
|
/*
|
|
** We can't have slash characters in the filenames we construct from
|
|
** full_proc_name.
|
|
*/
|
|
while ((slash = strchr(full_proc_name, '/')) != NULL) {
|
|
*slash = ':';
|
|
}
|
|
|
|
cmd_buf = MR_malloc(100 + 2 * full_proc_name_len);
|
|
/* will be big enough */
|
|
|
|
if (! MR_have_created_complexity_dirs) {
|
|
sprintf(cmd_buf, "mkdir -p %s %s",
|
|
MR_COMPLEXITY_ARGS_DIR, MR_COMPLEXITY_DATA_DIR);
|
|
if (system(cmd_buf) != 0) {
|
|
if (! MR_have_printed_complexity_dirs_error) {
|
|
fprintf(stderr, "%s: cannot create %s and %s: %s\n",
|
|
MR_progname, MR_COMPLEXITY_ARGS_DIR,
|
|
MR_COMPLEXITY_DATA_DIR, strerror(errno));
|
|
/* there is no point in aborting */
|
|
MR_have_printed_complexity_dirs_error = MR_TRUE;
|
|
return;
|
|
}
|
|
}
|
|
MR_have_created_complexity_dirs = MR_TRUE;
|
|
}
|
|
|
|
args_filename = MR_malloc(100 + full_proc_name_len);
|
|
/* will be big enough */
|
|
sprintf(args_filename, "%s/%s", MR_COMPLEXITY_ARGS_DIR, full_proc_name);
|
|
|
|
if (stat(args_filename, &statbuf) != 0) {
|
|
/* args_filename does not exist */
|
|
fp = fopen(args_filename, "w");
|
|
if (fp == NULL) {
|
|
fprintf(stderr, "%s: cannot open %s: %s\n",
|
|
MR_progname, args_filename, strerror(errno));
|
|
/* there is no point in aborting */
|
|
return;
|
|
}
|
|
|
|
MR_complexity_output_args_desc(fp, proc);
|
|
fclose(fp);
|
|
data_filemode = "w";
|
|
} else {
|
|
/* args_filename does exist */
|
|
char *tmp_filename;
|
|
|
|
tmp_filename = MR_malloc(100 + full_proc_name_len);
|
|
sprintf(tmp_filename, "%s/%s.tmp",
|
|
MR_COMPLEXITY_ARGS_DIR, full_proc_name);
|
|
fp = fopen(tmp_filename, "w");
|
|
if (fp == NULL) {
|
|
fprintf(stderr, "%s: cannot open %s: %s\n",
|
|
MR_progname, tmp_filename, strerror(errno));
|
|
/* there is no point in aborting */
|
|
return;
|
|
}
|
|
|
|
MR_complexity_output_args_desc(fp, proc);
|
|
fclose(fp);
|
|
|
|
sprintf(cmd_buf, "cmp -s %s %s", args_filename, tmp_filename);
|
|
if (system(cmd_buf) == 0) {
|
|
/* the files are identical */
|
|
(void) unlink(tmp_filename);
|
|
data_filemode = "a";
|
|
} else {
|
|
/* the files are different */
|
|
rename(tmp_filename, args_filename);
|
|
data_filemode = "w";
|
|
}
|
|
}
|
|
|
|
data_filename = MR_malloc(100 + full_proc_name_len);
|
|
sprintf(data_filename, "%s/%s", MR_COMPLEXITY_DATA_DIR, full_proc_name);
|
|
|
|
fp = fopen(data_filename, data_filemode);
|
|
if (fp == NULL) {
|
|
fprintf(stderr, "%s: cannot open %s: %s\n",
|
|
MR_progname, data_filename, strerror(errno));
|
|
/* there is no point in aborting */
|
|
return;
|
|
}
|
|
|
|
num_profiled_args = proc->MR_clp_num_profiled_args;
|
|
|
|
metrics = proc->MR_clp_metrics;
|
|
sizes = proc->MR_clp_sizes;
|
|
num_slots = proc->MR_clp_next_slot_num;
|
|
past_slots = proc->MR_clp_past_slots;
|
|
|
|
do {
|
|
int slot, arg;
|
|
|
|
for (slot = num_slots - 1; slot >= 0; slot--) {
|
|
fprintf(fp, "%d %d %d",
|
|
metrics[slot].MR_clpm_num_words,
|
|
metrics[slot].MR_clpm_num_cells,
|
|
metrics[slot].MR_clpm_num_ticks);
|
|
|
|
for (arg = 0; arg < num_profiled_args; arg++) {
|
|
fprintf(fp, " %d", sizes[slot * num_profiled_args + arg]);
|
|
}
|
|
|
|
fprintf(fp, "\n");
|
|
}
|
|
|
|
if (past_slots == NULL) {
|
|
break;
|
|
}
|
|
|
|
metrics = past_slots->MR_clpps_metrics;
|
|
sizes = past_slots->MR_clpps_sizes;
|
|
num_slots = MR_COMPLEXITY_SLOTS_PER_CHUNK;
|
|
past_slots = past_slots->MR_clpps_previous;
|
|
} while (MR_TRUE);
|
|
|
|
(void) fclose(fp);
|
|
}
|
|
|
|
static void
|
|
MR_complexity_output_args_desc(FILE *fp, MR_ComplexityProc *proc)
|
|
{
|
|
int arg;
|
|
int num_args;
|
|
MR_ComplexityArgInfo *arg_infos;
|
|
|
|
arg_infos = proc->MR_clp_arg_infos;
|
|
num_args = proc->MR_clp_num_args;
|
|
|
|
for (arg = 0; arg < num_args; arg++) {
|
|
if (arg_infos[arg].MR_clpai_maybe_name != NULL) {
|
|
fprintf(fp, "%s ", arg_infos[arg].MR_clpai_maybe_name);
|
|
} else {
|
|
fprintf(fp, "_ ");
|
|
}
|
|
|
|
switch (arg_infos[arg].MR_clpai_kind) {
|
|
case MR_COMPLEXITY_INPUT_VAR_SIZE:
|
|
fprintf(fp, "profiled_input\n");
|
|
break;
|
|
case MR_COMPLEXITY_INPUT_FIX_SIZE:
|
|
fprintf(fp, "unprofiled_input\n");
|
|
break;
|
|
case MR_COMPLEXITY_OUTPUT:
|
|
fprintf(fp, "output\n");
|
|
break;
|
|
default:
|
|
fprintf(fp, "unknown\n");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
MR_init_complexity_proc(int proc_num, const char *fullname,
|
|
int num_profiled_args, int num_args, MR_ComplexityArgInfo *arg_infos)
|
|
{
|
|
MR_ComplexityProc *proc;
|
|
|
|
if (MR_complexity_procs == NULL) {
|
|
fprintf(stderr, "%s: executable wasn't fully prepared "
|
|
"for complexity experiment\n", MR_progname);
|
|
exit(1);
|
|
}
|
|
|
|
proc = &MR_complexity_procs[proc_num];
|
|
if (! MR_streq(fullname, proc->MR_clp_full_proc_name)) {
|
|
fprintf(stderr, "%s: proc_num %d is %s: expected %s\n",
|
|
MR_progname, proc_num, proc->MR_clp_full_proc_name, fullname);
|
|
exit(1);
|
|
}
|
|
|
|
if (proc->MR_clp_num_profiled_args >= 0) {
|
|
fprintf(stderr, "%s: proc_num %d: duplicate initialization\n",
|
|
MR_progname, proc_num);
|
|
exit(1);
|
|
}
|
|
|
|
if (num_profiled_args < 0) {
|
|
fprintf(stderr, "%s: proc_num %d: bad num_profiled_args\n",
|
|
MR_progname, proc_num);
|
|
exit(1);
|
|
}
|
|
|
|
proc->MR_clp_num_profiled_args = num_profiled_args;
|
|
proc->MR_clp_num_args = num_args;
|
|
proc->MR_clp_arg_infos = arg_infos;
|
|
|
|
proc->MR_clp_metrics = MR_NEW_ARRAY(MR_ComplexityMetrics,
|
|
MR_COMPLEXITY_SLOTS_PER_CHUNK);
|
|
proc->MR_clp_sizes = MR_NEW_ARRAY(int,
|
|
MR_COMPLEXITY_SLOTS_PER_CHUNK * num_profiled_args);
|
|
}
|
|
|
|
void
|
|
MR_check_complexity_init(void)
|
|
{
|
|
int proc_num;
|
|
MR_bool printed_heading;
|
|
MR_ComplexityProc *proc;
|
|
|
|
printed_heading = MR_FALSE;
|
|
for (proc_num = 0; proc_num < MR_num_complexity_procs; proc_num++) {
|
|
proc = &MR_complexity_procs[proc_num];
|
|
|
|
if (proc->MR_clp_num_profiled_args < 0) {
|
|
if (! printed_heading) {
|
|
fprintf(stderr, "%s: the following procedures are "
|
|
"not available for complexity experiment:\n",
|
|
MR_progname);
|
|
printed_heading = MR_TRUE;
|
|
}
|
|
|
|
fprintf(stderr, "%s\n", proc->MR_clp_full_proc_name);
|
|
}
|
|
}
|
|
|
|
if (printed_heading) {
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
MR_ComplexityIsActive
|
|
MR_complexity_is_active_func(int num_procs, int proc_num, const char *name,
|
|
int num_profiled_inputs)
|
|
{
|
|
MR_ComplexityProc *proc;
|
|
|
|
if (num_procs != MR_num_complexity_procs || MR_complexity_procs == NULL) {
|
|
fprintf(stderr, "%s: executable wasn't fully prepared "
|
|
"for complexity experiment\n", MR_progname);
|
|
exit(1);
|
|
}
|
|
|
|
if (proc_num >= num_procs) {
|
|
fprintf(stderr, "%s: proc_num %d >= num_procs %d\n",
|
|
MR_progname, proc_num, num_procs);
|
|
exit(1);
|
|
}
|
|
|
|
proc = &MR_complexity_procs[proc_num];
|
|
if (! MR_streq(name, proc->MR_clp_full_proc_name)) {
|
|
fprintf(stderr, "%s: proc_num %d is %s: expected %s\n",
|
|
MR_progname, proc_num, proc->MR_clp_full_proc_name, name);
|
|
exit(1);
|
|
}
|
|
|
|
if (proc->MR_clp_num_profiled_args != num_profiled_inputs) {
|
|
fprintf(stderr, "%s: proc_num %d: bad num_profiled_inputs\n",
|
|
MR_progname, proc_num);
|
|
exit(1);
|
|
}
|
|
|
|
return proc->MR_clp_is_active;
|
|
}
|
|
|
|
int
|
|
MR_complexity_call_func(int procnum)
|
|
{
|
|
MR_ComplexityProc *proc;
|
|
MR_ComplexityMetrics *metrics;
|
|
int slot;
|
|
|
|
proc = &MR_complexity_procs[procnum];
|
|
slot = proc->MR_clp_next_slot_num;
|
|
if (slot < MR_COMPLEXITY_SLOTS_PER_CHUNK) {
|
|
proc->MR_clp_next_slot_num++;
|
|
} else {
|
|
MR_ComplexityPastSlots *past_slots;
|
|
|
|
past_slots = MR_NEW(MR_ComplexityPastSlots);
|
|
past_slots->MR_clpps_metrics = proc->MR_clp_metrics;
|
|
past_slots->MR_clpps_sizes = proc->MR_clp_sizes;
|
|
past_slots->MR_clpps_previous = proc->MR_clp_past_slots;
|
|
proc->MR_clp_past_slots = past_slots;
|
|
|
|
proc->MR_clp_metrics = MR_NEW_ARRAY(MR_ComplexityMetrics,
|
|
MR_COMPLEXITY_SLOTS_PER_CHUNK);
|
|
proc->MR_clp_sizes = MR_NEW_ARRAY(int,
|
|
MR_COMPLEXITY_SLOTS_PER_CHUNK * proc->MR_clp_num_profiled_args);
|
|
proc->MR_clp_next_slot_num = 1;
|
|
slot = 0;
|
|
}
|
|
metrics = &proc->MR_clp_metrics[slot];
|
|
metrics->MR_clpm_num_words -= MR_complexity_word_counter;
|
|
metrics->MR_clpm_num_cells -= MR_complexity_cell_counter;
|
|
metrics->MR_clpm_num_ticks -= MR_complexity_tick_counter;
|
|
proc->MR_clp_is_active = MR_COMPLEXITY_IS_ACTIVE;
|
|
|
|
return slot;
|
|
}
|
|
|
|
void
|
|
MR_complexity_fill_size_slot(MR_ComplexityProc *proc, int slot,
|
|
int num_profiled_args, int argnum, int size)
|
|
{
|
|
MR_ComplexityCounter *sizes;
|
|
|
|
sizes = proc->MR_clp_sizes;
|
|
sizes[(slot * proc->MR_clp_num_profiled_args) + argnum] = size;
|
|
}
|
|
|
|
void
|
|
MR_complexity_leave_func(int procnum, int slot)
|
|
{
|
|
MR_ComplexityProc *proc;
|
|
MR_ComplexityMetrics *metrics;
|
|
|
|
proc = &MR_complexity_procs[procnum];
|
|
metrics = &proc->MR_clp_metrics[slot];
|
|
metrics->MR_clpm_num_words += MR_complexity_word_counter;
|
|
metrics->MR_clpm_num_cells += MR_complexity_cell_counter;
|
|
metrics->MR_clpm_num_ticks += MR_complexity_tick_counter;
|
|
proc->MR_clp_is_active = MR_COMPLEXITY_IS_INACTIVE;
|
|
}
|
|
|
|
void
|
|
MR_complexity_redo_func(int procnum, int slot)
|
|
{
|
|
MR_ComplexityProc *proc;
|
|
MR_ComplexityMetrics *metrics;
|
|
|
|
proc = &MR_complexity_procs[procnum];
|
|
metrics = &proc->MR_clp_metrics[slot];
|
|
metrics->MR_clpm_num_words -= MR_complexity_word_counter;
|
|
metrics->MR_clpm_num_cells -= MR_complexity_cell_counter;
|
|
metrics->MR_clpm_num_ticks -= MR_complexity_tick_counter;
|
|
proc->MR_clp_is_active = MR_COMPLEXITY_IS_ACTIVE;
|
|
}
|
|
|
|
#endif /* MR_RECORD_TERM_SIZES */
|