From eed0cf6cc39f1ed7d35922ead2fbfbb06379c883 Mon Sep 17 00:00:00 2001 From: Rene Rivera Date: Mon, 3 Oct 2005 00:47:36 +0000 Subject: [PATCH] Variety of performance improvements. * bjam; bump to version 3.1.12 * bjam; make it possible to build in MinGW/MSYS shell * bjam; move profile code to debug.h/c to make it available for use everywhere * bjam; cache all filesystem query operations, Unix and Windows only, include PWD and scanning * bjam; add memory profile info, and sprinkle throught code * bbv2; rewrite some while() loops into for() loops to reduce time and memory * bbv2; keep a single instance counter instead of one per type to reduce memory use * bjam+bbv2; change NORMALIZE_PATH builtin to join path parts to reduce memory use [SVN r31177] --- src/build/generators.jam | 14 +-- src/build/toolset.jam | 21 ++-- src/engine/boost-jam.spec | 3 +- src/engine/build.bat | 2 +- src/engine/build.jam | 8 +- src/engine/build.sh | 19 ++- src/engine/builtins.c | 24 +++- src/engine/command.c | 7 ++ src/engine/compile.c | 95 +-------------- src/engine/compile.h | 2 - src/engine/debian/changelog | 6 + src/engine/debian/copyright | 1 + src/engine/debug.c | 127 ++++++++++++++++++++ src/engine/debug.h | 53 +++++++++ src/engine/execnt.c | 11 ++ src/engine/execunix.c | 4 + src/engine/filent.c | 225 ++++++++++++++++++++++-------------- src/engine/filesys.c | 31 +++++ src/engine/filesys.h | 18 +++ src/engine/fileunix.c | 154 +++++++++++++++--------- src/engine/hash.c | 38 +++++- src/engine/hash.h | 5 + src/engine/index.html | 4 +- src/engine/jam.c | 24 ++-- src/engine/lists.c | 5 +- src/engine/make1.c | 2 + src/engine/modules.c | 17 ++- src/engine/modules/order.c | 7 ++ src/engine/newstr.c | 21 ++++ src/engine/parse.c | 3 + src/engine/patchlevel.h | 8 +- src/engine/pwd.c | 28 +++-- src/engine/regexp.c | 3 + src/engine/rules.c | 15 +++ src/engine/scan.c | 3 + src/engine/strings.c | 3 + src/engine/timestamp.c | 10 +- src/kernel/class.jam | 12 +- src/util/path.jam | 2 +- src/util/print.jam | 7 +- 40 files changed, 738 insertions(+), 304 deletions(-) create mode 100644 src/engine/debug.c create mode 100644 src/engine/debug.h diff --git a/src/build/generators.jam b/src/build/generators.jam index 6b3be2f5b..219a3c58c 100644 --- a/src/build/generators.jam +++ b/src/build/generators.jam @@ -541,28 +541,20 @@ class generator { # We process each source one-by-one, trying to convert it to # a usable type. - local failed ; - while $(sources) && ! $(failed) + for local source in $(sources) { local _c ; local _b ; # TODO: need to check for failure on each source. convert-to-consumable-types $(project) : $(property-set) - : $(sources[1]) : true : _c _b ; + : $(source) : true : _c _b ; if ! $(_c) { - generators.dout [ indent ] " failed to convert " $(sources[1]) ; - # failed = true ; + generators.dout [ indent ] " failed to convert " $(source) ; } $(consumed-var) += $(_c) ; $(bypassed-var) += $(_b) ; - sources = $(sources[2-]) ; } - if $(failed) - { - $(consumed-var) = ; - $(bypassed-var) = ; - } } rule consume-directly ( source : consumed-var : missing-types-var ) diff --git a/src/build/toolset.jam b/src/build/toolset.jam index aa81a1f32..0841b0fe1 100644 --- a/src/build/toolset.jam +++ b/src/build/toolset.jam @@ -293,17 +293,22 @@ rule set-target-variables ( rule-or-module targets + : property-set ) } .stv.$(key) = $(settings) ; } - + if $(settings) != none { - while $(settings) + local var-name = ; + for local name-or-value in $(settings) { - # Here, $(settings[1]) is the name of variable to assign - # and $(settings[2]) is the value. - - $(settings[1]) on $(targets) += $(settings[2]) ; - settings = $(settings[3-]) ; - } + if $(var-name) + { + $(var-name) on $(targets) += $(name-or-value) ; + var-name = ; + } + else + { + var-name = $(name-or-value) ; + } + } } } diff --git a/src/engine/boost-jam.spec b/src/engine/boost-jam.spec index 2cdbc20aa..80549d1fc 100644 --- a/src/engine/boost-jam.spec +++ b/src/engine/boost-jam.spec @@ -1,5 +1,5 @@ Name: boost-jam -Version: 3.1.11 +Version: 3.1.12 Summary: Build tool Release: 1 Source: %{name}-%{version}.tgz @@ -33,6 +33,7 @@ Copyright: Also: Copyright 2001-2004 David Abrahams. Copyright 2002-2005 Rene Rivera. + Copyright 2003-2005 Vladimir Prus. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) diff --git a/src/engine/build.bat b/src/engine/build.bat index 71fb25ae7..28d978b24 100644 --- a/src/engine/build.bat +++ b/src/engine/build.bat @@ -312,7 +312,7 @@ echo ### set YYACC_SOURCES=yyacc.c set MKJAMBASE_SOURCES=mkjambase.c set BJAM_SOURCES= -set BJAM_SOURCES=%BJAM_SOURCES% command.c compile.c execnt.c expand.c filent.c glob.c hash.c +set BJAM_SOURCES=%BJAM_SOURCES% command.c compile.c debug.c execnt.c expand.c filent.c glob.c hash.c set BJAM_SOURCES=%BJAM_SOURCES% hdrmacro.c headers.c jam.c jambase.c jamgram.c lists.c make.c make1.c set BJAM_SOURCES=%BJAM_SOURCES% newstr.c option.c parse.c pathunix.c regexp.c set BJAM_SOURCES=%BJAM_SOURCES% rules.c scan.c search.c subst.c timestamp.c variable.c modules.c diff --git a/src/engine/build.jam b/src/engine/build.jam index 8a28a4674..3a7001ae7 100644 --- a/src/engine/build.jam +++ b/src/engine/build.jam @@ -13,7 +13,7 @@ else { . = "." ; } # Info about what we are building. NAME = boost-jam ; -VERSION = 3$(.)1$(.)11 ; +VERSION = 3$(.)1$(.)12 ; RELEASE = 1 ; LICENSE = 1_0 ; @@ -98,10 +98,10 @@ toolset darwin cc : "-o " : -D : [ opt --release : -Wl,-x -O3 -finline-functions ] [ opt --debug : -g -O0 -fno-inline -pg ] ; -## GCC 2.x, 3.x +## GCC 2.x, 3.x, 4.x toolset gcc gcc : "-o " : -D : -pedantic - [ opt --release : [ opt --symbols : -g : -s ] -O3 -finline-functions ] + [ opt --release : [ opt --symbols : -g : -s ] -O3 ] [ opt --debug : -g -O0 -fno-inline ] ; ## GCC 2.x, 3.x on CYGWIN but without cygwin1.dll toolset gcc-nocygwin gcc : "-o " : -D @@ -277,7 +277,7 @@ else # We have some different files for UNIX, VMS, and NT. jam.source = - command.c compile.c expand.c glob.c + command.c compile.c debug.c expand.c glob.c hash.c hcache.c headers.c hdrmacro.c jam.c jambase.c jamgram.c lists.c make.c make1.c newstr.c diff --git a/src/engine/build.sh b/src/engine/build.sh index 048080ed0..732d7985e 100755 --- a/src/engine/build.sh +++ b/src/engine/build.sh @@ -30,7 +30,7 @@ error_exit () echo "###" echo "### Toolsets supported by this script are:" echo "### acc, como, darwin, gcc, intel-linux, kcc, kylix, mipspro," - echo "### sunpro, tru64cxx, vacpp" + echo "### sunpro, tru64cxx, vacpp, mingw(msys)" echo "###" echo "### A special toolset; cc, is available which is used as a fallback" echo "### when a more specific toolset is not found and the cc command is" @@ -61,7 +61,10 @@ test_uname () # Try and guess the toolset to bootstrap the build with... Guess_Toolset () { - if test_uname Darwin ; then BOOST_JAM_TOOLSET=darwin + if test -r /mingw/bin/gcc ; then + BOOST_JAM_TOOLSET=mingw + BOOST_JAM_TOOLSET_ROOT=/mingw/ + elif test_uname Darwin ; then BOOST_JAM_TOOLSET=darwin elif test_uname IRIX ; then BOOST_JAM_TOOLSET=mipspro elif test_uname IRIX64 ; then BOOST_JAM_TOOLSET=mipspro elif test_uname OSF1 ; then BOOST_JAM_TOOLSET=tru64cxx @@ -108,6 +111,13 @@ BOOST_JAM_OPT_JAM="-o bootstrap/jam0" BOOST_JAM_OPT_MKJAMBASE="-o bootstrap/mkjambase0" BOOST_JAM_OPT_YYACC="-o bootstrap/yyacc0" case $BOOST_JAM_TOOLSET in + mingw) + if test -r ${BOOST_JAM_TOOLSET_ROOT}bin/gcc -r ; then + export PATH=${BOOST_JAM_TOOLSET_ROOT}bin:$PATH + fi + BOOST_JAM_CC="gcc -DNT" + ;; + gcc) BOOST_JAM_CC=gcc ;; @@ -188,13 +198,14 @@ echo "###" YYACC_SOURCES="yyacc.c" MKJAMBASE_SOURCES="mkjambase.c" BJAM_SOURCES="\ - command.c compile.c execunix.c expand.c fileunix.c glob.c hash.c\ + command.c compile.c debug.c execunix.c expand.c fileunix.c glob.c hash.c\ hdrmacro.c headers.c jam.c jambase.c jamgram.c lists.c make.c make1.c\ newstr.c option.c parse.c pathunix.c pathvms.c regexp.c\ rules.c scan.c search.c subst.c timestamp.c variable.c modules.c\ strings.c filesys.c builtins.c pwd.c class.c native.c w32_getreg.c\ modules/set.c modules/path.c modules/regex.c modules/property-set.c\ - modules/sequence.c modules/order.c" + modules/sequence.c modules/order.c\ + execnt.c filent.c" BJAM_UPDATE= if test "$1" = "--update" -o "$2" = "--update" -o "$3" = "--update" -o "$4" = "--update" ; then diff --git a/src/engine/builtins.c b/src/engine/builtins.c index 5f392ff3c..a0c39f5aa 100644 --- a/src/engine/builtins.c +++ b/src/engine/builtins.c @@ -5,6 +5,7 @@ */ # include "jam.h" +# include "debug.h" # include "lists.h" # include "parse.h" @@ -266,7 +267,7 @@ load_builtins() } { - char * args[] = { "path", 0 }; + char * args[] = { "path_parts", "*", 0 }; bind_builtin( "NORMALIZE_PATH", builtin_normalize_path, 0, args ); } @@ -547,11 +548,13 @@ builtin_glob_back( int status, time_t time ) { + PROFILE_ENTER(BUILTIN_GLOB_BACK); + struct globbing *globbing = (struct globbing *)closure; LIST *l; PATHNAME f; string buf[1]; - + /* Null out directory for matching. */ /* We wish we had file_dirscan() pass up a PATHNAME. */ @@ -565,7 +568,10 @@ builtin_glob_back( "." and ".." won't work anywhere. */ if (strcmp(f.f_base.ptr, ".") == 0 || strcmp(f.f_base.ptr, "..") == 0) + { + PROFILE_EXIT(BUILTIN_GLOB_BACK); return; + } string_new( buf ); path_build( &f, buf, 0 ); @@ -584,6 +590,8 @@ builtin_glob_back( } string_free( buf ); + + PROFILE_EXIT(BUILTIN_GLOB_BACK); } static LIST* downcase_list( LIST *in ) @@ -1263,7 +1271,7 @@ builtin_sort( PARSE *parse, FRAME *frame ) LIST *builtin_normalize_path( PARSE *parse, FRAME *frame ) { - LIST* arg1 = lol_get( frame->args, 0 ); + LIST* arg = lol_get( frame->args, 0 ); /* First, we iterate over all '/'-separated elements, starting from the end of string. If we see '..', we remove previous path elements. @@ -1276,14 +1284,20 @@ LIST *builtin_normalize_path( PARSE *parse, FRAME *frame ) char* end; /* Last character of the part of string still to be processed. */ char* current; /* Working pointer. */ int dotdots = 0; /* Number of '..' elements seen and not processed yet. */ - int rooted = arg1->string[0] == '/'; + int rooted = arg->string[0] == '/'; char* result; /* Make a copy of input: we should not change it. */ string_new(in); if (!rooted) string_push_back(in, '/'); - string_append(in, arg1->string); + while (arg) + { + string_append(in, arg->string); + arg = list_next(arg); + if (arg) + string_append(in, "/"); + } end = in->value + in->size - 1; diff --git a/src/engine/command.c b/src/engine/command.c index bcb7fcbc9..727a3278c 100644 --- a/src/engine/command.c +++ b/src/engine/command.c @@ -20,6 +20,7 @@ # include "parse.h" # include "variable.h" # include "rules.h" +# include "debug.h" # include "command.h" # include @@ -42,6 +43,9 @@ cmd_new( int max_line = MAXLINE; int allocated = -1; + if ( DEBUG_PROFILE ) + profile_memory( sizeof( CMD ) ); + cmd->rule = rule; cmd->shell = shell; cmd->next = 0; @@ -56,6 +60,9 @@ cmd_new( free(cmd->buf); /* free any buffer from previous iteration */ cmd->buf = (char*)malloc(max_line + 1); + + if ( DEBUG_PROFILE ) + profile_memory( max_line + 1 ); if (cmd->buf == 0) break; diff --git a/src/engine/compile.c b/src/engine/compile.c index 8bea9b5c7..75464cf75 100644 --- a/src/engine/compile.c +++ b/src/engine/compile.c @@ -11,6 +11,7 @@ */ # include "jam.h" +# include "debug.h" # include "lists.h" # include "parse.h" @@ -28,7 +29,6 @@ # include "builtins.h" # include "class.h" -# include # include # include # include @@ -799,96 +799,6 @@ collect_arguments( RULE* rule, FRAME* frame ) return locals; } -struct profile_info -{ - char* name; /* name of rule being called */ - clock_t cumulative; /* cumulative time spent in rule */ - clock_t net; /* time spent in rule proper */ - unsigned long num_entries; /* number of time rule was entered */ - unsigned long stack_count; /* number of the times this function is present in stack */ -}; -typedef struct profile_info profile_info; - -struct profile_frame -{ - profile_info* info; /* permanent storage where data accumulates */ - clock_t overhead; /* overhead for profiling in this call */ - clock_t entry_time; /* time of last entry to rule */ - struct profile_frame* caller; /* stack frame of caller */ - clock_t subrules; /* time spent in subrules */ -}; -typedef struct profile_frame profile_frame; - -static profile_frame* profile_stack = 0; -static struct hash* profile_hash = 0; - -static void profile_enter( char* rulename, profile_frame* frame ) -{ - clock_t start = clock(); - profile_info info, *p = &info; - - if ( !profile_hash ) - profile_hash = hashinit(sizeof(profile_info), "profile"); - - info.name = rulename; - - if ( hashenter( profile_hash, (HASHDATA **)&p ) ) - p->cumulative = p->net = p->num_entries = p->stack_count = 0; - - ++(p->num_entries); - ++(p->stack_count); - - frame->info = p; - - frame->caller = profile_stack; - profile_stack = frame; - - frame->entry_time = clock(); - frame->overhead = 0; - frame->subrules = 0; - - /* caller pays for the time it takes to play with the hash table */ - if ( frame->caller ) - frame->caller->overhead += frame->entry_time - start; -} - -static void profile_exit(profile_frame* frame) -{ - /* cumulative time for this call */ - clock_t t = clock() - frame->entry_time - frame->overhead; - /* If this rule is already present on the stack, don't add the time for - this instance. */ - if (frame->info->stack_count == 1) - frame->info->cumulative += t; - /* Net time does not depend on presense of the same rule in call stack. */ - frame->info->net += t - frame->subrules; - - if (frame->caller) - { - /* caller's cumulative time must account for this overhead */ - frame->caller->overhead += frame->overhead; - frame->caller->subrules += t; - } - /* pop this stack frame */ - --frame->info->stack_count; - profile_stack = frame->caller; -} - -static void dump_profile_entry(void* p_, void* ignored) -{ - profile_info* p = (profile_info*)p_; - printf("%10d %10d %10d %s\n", p->cumulative, p->net, p->num_entries, p->name); -} - -void profile_dump() -{ - if ( profile_hash ) - { - printf("%10s %10s %10s %s\n", "gross", "net", "# entries", "name"); - hashenumerate( profile_hash, dump_profile_entry, 0 ); - } -} - static int python_instance_number = 0; RULE * @@ -1100,6 +1010,9 @@ evaluate_rule( action = (ACTION *)malloc( sizeof( ACTION ) ); memset( (char *)action, '\0', sizeof( *action ) ); + if ( DEBUG_PROFILE ) + profile_memory( sizeof( ACTION ) ); + action->rule = rule; action->targets = targetlist( (TARGETS *)0, lol_get( frame->args, 0 ) ); action->sources = targetlist( (TARGETS *)0, lol_get( frame->args, 1 ) ); diff --git a/src/engine/compile.h b/src/engine/compile.h index eb548bde3..f44e51ef4 100644 --- a/src/engine/compile.h +++ b/src/engine/compile.h @@ -48,8 +48,6 @@ LIST *call_rule( char *rulename, FRAME* caller_frame, ...); regexp* regex_compile( const char* pattern ); -void profile_dump(); - /* Flags for compile_set(), etc */ # define ASSIGN_SET 0x00 /* = assign variable */ diff --git a/src/engine/debian/changelog b/src/engine/debian/changelog index 4bea9bdb5..29084289c 100644 --- a/src/engine/debian/changelog +++ b/src/engine/debian/changelog @@ -1,3 +1,9 @@ +bjam (3.1.12-1) unstable; urgency=low + + * New upstream release. + + -- Rene Rivera Sat, 01 Oct 2005 00:00:00 +0000 + bjam (3.1.11-1) unstable; urgency=low * New upstream release. diff --git a/src/engine/debian/copyright b/src/engine/debian/copyright index af42cefb7..4b4dcbfc8 100644 --- a/src/engine/debian/copyright +++ b/src/engine/debian/copyright @@ -19,6 +19,7 @@ Some portions are also: Copyright 2001-2004 David Abrahams. Copyright 2002-2005 Rene Rivera. + Copyright 2003-2005 Vladimir Prus. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) diff --git a/src/engine/debug.c b/src/engine/debug.c new file mode 100644 index 000000000..d3f5ef04f --- /dev/null +++ b/src/engine/debug.c @@ -0,0 +1,127 @@ +/* + Copyright Rene Rivera 2005. + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) +*/ + +# include "jam.h" +# include "debug.h" + +# include "hash.h" + +# include +# include + +static profile_frame* profile_stack = 0; +static struct hash* profile_hash = 0; +static profile_info profile_other = { "[OTHER]", 0, 0, 0, 0, 0 }; +static profile_info profile_total = { "[TOTAL]", 0, 0, 0, 0, 0 }; + +profile_frame* profile_init( char* rulename, profile_frame* frame ) +{ + if ( DEBUG_PROFILE ) profile_enter(rulename,frame); + return frame; +} + +void profile_enter( char* rulename, profile_frame* frame ) +{ + if ( DEBUG_PROFILE ) + { + clock_t start = clock(); + profile_info info, *p = &info; + + if ( !rulename ) p = &profile_other; + + if ( !profile_hash ) + { + if ( rulename ) profile_hash = hashinit(sizeof(profile_info), "profile"); + } + + info.name = rulename; + + if ( rulename && hashenter( profile_hash, (HASHDATA **)&p ) ) + p->cumulative = p->net = p->num_entries = p->stack_count = p->memory = 0; + + ++(p->num_entries); + ++(p->stack_count); + + frame->info = p; + + frame->caller = profile_stack; + profile_stack = frame; + + frame->entry_time = clock(); + frame->overhead = 0; + frame->subrules = 0; + + /* caller pays for the time it takes to play with the hash table */ + if ( frame->caller ) + frame->caller->overhead += frame->entry_time - start; + } +} + +void profile_memory( long mem ) +{ + if ( DEBUG_PROFILE ) + { + if ( profile_stack && profile_stack->info ) + { + profile_stack->info->memory += mem; + } + } +} + +void profile_exit(profile_frame* frame) +{ + if ( DEBUG_PROFILE ) + { + /* cumulative time for this call */ + clock_t t = clock() - frame->entry_time - frame->overhead; + /* If this rule is already present on the stack, don't add the time for + this instance. */ + if (frame->info->stack_count == 1) + frame->info->cumulative += t; + /* Net time does not depend on presense of the same rule in call stack. */ + frame->info->net += t - frame->subrules; + + if (frame->caller) + { + /* caller's cumulative time must account for this overhead */ + frame->caller->overhead += frame->overhead; + frame->caller->subrules += t; + } + /* pop this stack frame */ + --frame->info->stack_count; + profile_stack = frame->caller; + } +} + +static void dump_profile_entry(void* p_, void* ignored) +{ + profile_info* p = (profile_info*)p_; + unsigned long mem_each = (p->memory/(p->num_entries ? p->num_entries : 1)); + double q = p->net; q /= (p->num_entries ? p->num_entries : 1); + if (!ignored) + { + profile_total.cumulative += p->net; + profile_total.memory += p->memory; + } + printf("%10d %10d %10d %12.6f %10d %10d %s\n", + p->num_entries, p->cumulative, p->net, q, + p->memory, mem_each, + p->name); +} + +void profile_dump() +{ + if ( profile_hash ) + { + printf("%10s %10s %10s %12s %10s %10s %s\n", + "--count--", "--gross--", "--net--", "--each--", + "--mem--", "--each--", + "--name--"); + hashenumerate( profile_hash, dump_profile_entry, 0 ); + dump_profile_entry(&profile_other,0); + dump_profile_entry(&profile_total,(void*)1); + } +} diff --git a/src/engine/debug.h b/src/engine/debug.h new file mode 100644 index 000000000..b417c1618 --- /dev/null +++ b/src/engine/debug.h @@ -0,0 +1,53 @@ +/* + Copyright Rene Rivera 2005. + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) +*/ +#ifndef BJAM_DEBUG_H +#define BJAM_DEBUG_H + +# include "jam.h" +# include + +struct profile_info +{ + /* name of rule being called */ + char* name; + /* cumulative time spent in rule */ + clock_t cumulative; + /* time spent in rule proper */ + clock_t net; + /* number of time rule was entered */ + unsigned long num_entries; + /* number of the times this function is present in stack */ + unsigned long stack_count; + /* bytes of memory allocated by the call */ + unsigned long memory; +}; +typedef struct profile_info profile_info; + +struct profile_frame +{ + /* permanent storage where data accumulates */ + profile_info* info; + /* overhead for profiling in this call */ + clock_t overhead; + /* time of last entry to rule */ + clock_t entry_time; + /* stack frame of caller */ + struct profile_frame* caller; + /* time spent in subrules */ + clock_t subrules; +}; +typedef struct profile_frame profile_frame; + +profile_frame * profile_init( char* rulename, profile_frame* frame ); +void profile_enter( char* rulename, profile_frame* frame ); +void profile_memory( long mem ); +void profile_exit(profile_frame* frame); +void profile_dump(); + +#define PROFILE_ENTER(scope) profile_frame PROF_ ## scope, *PROF_ ## scope ## _p = profile_init(#scope,&PROF_ ## scope) +#define PROFILE_EXIT(scope) profile_exit(PROF_ ## scope ## _p) + +#endif diff --git a/src/engine/execnt.c b/src/engine/execnt.c index 639bf1987..27f962f72 100644 --- a/src/engine/execnt.c +++ b/src/engine/execnt.c @@ -13,6 +13,7 @@ # include "jam.h" # include "lists.h" # include "execcmd.h" +# include "debug.h" # include # include # include @@ -149,6 +150,9 @@ string_to_args( const char* string ) if (!line) return 0; + if ( DEBUG_PROFILE ) + profile_memory( src_len+1 ); + /* allocate the argv array. * element 0: stores the path to the executable * element 1: stores the command-line arguments to the executable @@ -160,6 +164,9 @@ string_to_args( const char* string ) free( line ); return 0; } + + if ( DEBUG_PROFILE ) + profile_memory( 3 * sizeof(char*) ); /* Strip quotes from the first command-line argument and find * where it ends. Quotes are illegal in Win32 pathnames, so we @@ -279,6 +286,8 @@ process_del( char* command ) line = (char*)malloc( len+4+1 ); if (!line) return 1; + if ( DEBUG_PROFILE ) + profile_memory( len+4+1 ); strncpy( line, "del ", 4 ); strncpy( line+4, q, len ); @@ -572,6 +581,8 @@ execcmd( /* SVA - allocate 64 other just to be safe */ cmdtab[ slot ].tempfile = malloc( strlen( tempdir ) + 64 ); + if ( DEBUG_PROFILE ) + profile_memory( strlen( tempdir ) + 64 ); procID = GetCurrentProcessId(); diff --git a/src/engine/execunix.c b/src/engine/execunix.c index 592f22835..af2a52b87 100644 --- a/src/engine/execunix.c +++ b/src/engine/execunix.c @@ -255,7 +255,11 @@ my_wait( int *status ) static HANDLE *active_handles = 0; if (!active_handles) + { active_handles = (HANDLE *)malloc(globs.jobs * sizeof(HANDLE) ); + if ( DEBUG_PROFILE ) + profile_memory( globs.jobs * sizeof(HANDLE) ); + } /* first see if any non-waited-for processes are dead, * and return if so. diff --git a/src/engine/filent.c b/src/engine/filent.c index 53d507f82..170a992d4 100644 --- a/src/engine/filent.c +++ b/src/engine/filent.c @@ -6,14 +6,18 @@ /* This file is ALSO: * Copyright 2001-2004 David Abrahams. + * Copyright 2005 Rene Rivera. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) */ # include "jam.h" +# include "debug.h" + # include "filesys.h" # include "pathsys.h" # include "strings.h" +# include "newstr.h" # ifdef OS_NT @@ -59,89 +63,152 @@ file_dirscan( scanback func, void *closure ) { - PATHNAME f; - string filespec[1]; - string filename[1]; - long handle; - int ret; - struct _finddata_t finfo[1]; + PROFILE_ENTER(FILE_DIRSCAN); + + file_info_t * d = 0; dir = short_path_to_long_path( dir ); /* First enter directory itself */ - memset( (char *)&f, '\0', sizeof( f ) ); + d = file_query( dir ); + + if ( ! d || ! d->is_dir ) + { + PROFILE_EXIT(FILE_DIRSCAN); + return; + } - f.f_dir.ptr = dir; - f.f_dir.len = strlen(dir); + if ( ! d->files ) + { + PATHNAME f; + string filespec[1]; + string filename[1]; + long handle; + int ret; + struct _finddata_t finfo[1]; + LIST* files = L0; - dir = *dir ? dir : "."; + memset( (char *)&f, '\0', sizeof( f ) ); + + f.f_dir.ptr = d->name; + f.f_dir.len = strlen(d->name); + + /* Now enter contents of directory */ + + string_copy( filespec, *d->name ? d->name : "." ); + string_append( filespec, "/*" ); + + if( DEBUG_BINDSCAN ) + printf( "scan directory %s\n", dir ); + + # if defined(__BORLANDC__) && __BORLANDC__ < 0x550 + if ( ret = findfirst( filespec->value, finfo, FA_NORMAL | FA_DIREC ) ) + { + string_free( filespec ); + PROFILE_EXIT(FILE_DIRSCAN); + return; + } + + string_new( filename ); + while( !ret ) + { + file_info_t * ff = 0; + + f.f_base.ptr = finfo->ff_name; + f.f_base.len = strlen( finfo->ff_name ); + + string_truncate( filename, 0 ); + path_build( &f, filename ); + + files = list_new( files, newstr(filename->value) ); + ff = file_info( filename->value ); + ff->is_file = finfo->ff_attrib & FA_DIREC ? 0 : 1; + ff->is_dir = finfo->ff_attrib & FA_DIREC ? 1 : 0; + ff->size = finfo->ff_fsize; + ff->time = (finfo->ff_ftime << 16) | finfo->ff_ftime; + + ret = findnext( finfo ); + } + # else + handle = _findfirst( filespec->value, finfo ); + + if( ret = ( handle < 0L ) ) + { + string_free( filespec ); + PROFILE_EXIT(FILE_DIRSCAN); + return; + } + + string_new( filename ); + while( !ret ) + { + file_info_t * ff = 0; + + f.f_base.ptr = finfo->name; + f.f_base.len = strlen( finfo->name ); + + string_truncate( filename, 0 ); + path_build( &f, filename, 0 ); + + files = list_new( files, newstr(filename->value) ); + ff = file_info( filename->value ); + ff->is_file = finfo->attrib & _A_SUBDIR ? 0 : 1; + ff->is_dir = finfo->attrib & _A_SUBDIR ? 1 : 0; + ff->size = finfo->size; + ff->time = finfo->time_write; + + ret = _findnext( handle, finfo ); + } + + _findclose( handle ); + # endif + string_free( filename ); + string_free( filespec ); + + d->files = files; + } /* Special case \ or d:\ : enter it */ - - if( f.f_dir.len == 1 && f.f_dir.ptr[0] == '\\' ) - (*func)( closure, dir, 0 /* not stat()'ed */, (time_t)0 ); - else if( f.f_dir.len == 3 && f.f_dir.ptr[1] == ':' ) - (*func)( closure, dir, 0 /* not stat()'ed */, (time_t)0 ); + { + unsigned long len = strlen(d->name); + if( len == 1 && d->name[0] == '\\' ) + (*func)( closure, d->name, 1 /* stat()'ed */, d->time ); + else if( len == 3 && d->name[1] == ':' ) + (*func)( closure, d->name, 1 /* stat()'ed */, d->time ); + } /* Now enter contents of directory */ - - string_copy( filespec, dir ); - string_append( filespec, "/*" ); - - if( DEBUG_BINDSCAN ) - printf( "scan directory %s\n", dir ); - -# if defined(__BORLANDC__) && __BORLANDC__ < 0x550 - if ( ret = findfirst( filespec->value, finfo, FA_NORMAL | FA_DIREC ) ) + if ( d->files ) { - string_free( filespec ); - return; + LIST * files = d->files; + while ( files ) + { + file_info_t * ff = file_info( files->string ); + (*func)( closure, ff->name, 1 /* stat()'ed */, ff->time ); + files = list_next( files ); + } } + + PROFILE_EXIT(FILE_DIRSCAN); +} - string_new( filename ); - while( !ret ) +file_info_t * file_query( char * filename ) +{ + file_info_t * ff = file_info( filename ); + if ( ! ff->time ) { - time_t time_write = finfo->ff_fdate; + struct stat statbuf; - time_write = (time_write << 16) | finfo->ff_ftime; - f.f_base.ptr = finfo->ff_name; - f.f_base.len = strlen( finfo->ff_name ); + if( stat( *filename ? filename : ".", &statbuf ) < 0 ) + return 0; - string_truncate( filename, 0 ); - path_build( &f, filename ); - - (*func)( closure, filename->value, 1 /* stat()'ed */, time_write ); - - ret = findnext( finfo ); + ff->is_file = statbuf.st_mode & S_IFREG ? 1 : 0; + ff->is_dir = statbuf.st_mode & S_IFDIR ? 1 : 0; + ff->size = statbuf.st_size; + ff->time = statbuf.st_mtime ? statbuf.st_mtime : 1; } -# else - handle = _findfirst( filespec->value, finfo ); - - if( ret = ( handle < 0L ) ) - { - string_free( filespec ); - return; - } - - string_new( filename ); - while( !ret ) - { - f.f_base.ptr = finfo->name; - f.f_base.len = strlen( finfo->name ); - - string_truncate( filename, 0 ); - path_build( &f, filename, 0 ); - - (*func)( closure, filename->value, 1 /* stat()'ed */, finfo->time_write ); - - ret = _findnext( handle, finfo ); - } - - _findclose( handle ); -# endif - string_free( filename ); - string_free( filespec ); + return ff; } /* @@ -153,29 +220,17 @@ file_time( char *filename, time_t *time ) { - /* On NT this is called only for C:/ */ - - struct stat statbuf; - - if( stat( filename, &statbuf ) < 0 ) - return -1; - - *time = statbuf.st_mtime; - - return 0; + file_info_t * ff = file_query( filename ); + if ( !ff ) return -1; + *time = ff->time; + return 0; } int file_is_file(char* filename) { - struct stat statbuf; - - if( stat( filename, &statbuf ) < 0 ) - return -1; - - if (statbuf.st_mode & S_IFREG) - return 1; - else - return 0; + file_info_t * ff = file_query( filename ); + if ( !ff ) return -1; + return ff->is_file; } @@ -252,6 +307,8 @@ file_archscan( */ string_table = malloc(lar_size+1); + if ( DEBUG_PROFILE ) + profile_memory( lar_size+1 ); if (read(fd, string_table, lar_size) != lar_size) printf("error reading string table\n"); string_table[lar_size] = '\0'; diff --git a/src/engine/filesys.c b/src/engine/filesys.c index 597aa98bd..bec1d8fc3 100644 --- a/src/engine/filesys.c +++ b/src/engine/filesys.c @@ -1,6 +1,8 @@ # include "jam.h" # include "pathsys.h" # include "strings.h" +# include "newstr.h" +# include "filesys.h" void file_build1( @@ -31,3 +33,32 @@ file_build1( string_push_back( file, '>' ); } } + +static struct hash * filecache_hash = 0; + +file_info_t * file_info(char * filename) +{ + file_info_t finfo_, *finfo = &finfo_; + + if ( !filecache_hash ) + filecache_hash = hashinit( sizeof( file_info_t ), "file_info" ); + + finfo->name = filename; + if ( hashenter( filecache_hash, (HASHDATA**)&finfo ) ) + { + /* printf( "file_info: %s\n", filename ); */ + finfo->name = newstr( finfo->name ); + finfo->is_file = 0; + finfo->is_dir = 0; + finfo->size = 0; + finfo->time = 0; + finfo->files = 0; + } + + return finfo; +} + +void file_done() +{ + hashdone( filecache_hash ); +} diff --git a/src/engine/filesys.h b/src/engine/filesys.h index 91f077b82..c48b28bf4 100644 --- a/src/engine/filesys.h +++ b/src/engine/filesys.h @@ -18,6 +18,8 @@ # define FILESYS_DWA20011025_H # include "pathsys.h" +#include "hash.h" +#include "lists.h" typedef void (*scanback)( void *closure, char *file, int found, time_t t ); @@ -29,4 +31,20 @@ int file_time( char *filename, time_t *time ); void file_build1(PATHNAME *f, string* file) ; int file_is_file(char* filename); +struct file_info_t { + char * name; + short is_file; + short is_dir; + unsigned long size; + time_t time; + LIST * files; +} ; +typedef struct file_info_t file_info_t ; + +file_info_t * file_info(char * filename); + +file_info_t * file_query(char * filename); + +void file_done(); + #endif diff --git a/src/engine/fileunix.c b/src/engine/fileunix.c index 69bf0f17d..a57e830ca 100644 --- a/src/engine/fileunix.c +++ b/src/engine/fileunix.c @@ -6,14 +6,17 @@ /* This file is ALSO: * Copyright 2001-2004 David Abrahams. + * Copyright 2005 Rene Rivera. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) */ # include "jam.h" +# include "debug.h" # include "filesys.h" # include "strings.h" # include "pathsys.h" +# include "newstr.h" # include #if defined(sun) || defined(__sun) @@ -127,52 +130,110 @@ file_dirscan( scanback func, void *closure ) { - PATHNAME f; - DIR *d; - STRUCT_DIRENT *dirent; + PROFILE_ENTER(FILE_DIRSCAN); + + file_info_t * d = 0; + + d = file_query( dir ); + + if ( ! d || ! d->is_dir ) + { + PROFILE_EXIT(FILE_DIRSCAN); + return; + } + + if ( ! d->files ) + { + LIST* files = L0; + PATHNAME f; + DIR *dd; + STRUCT_DIRENT *dirent; string filename[1]; - /* First enter directory itself */ + /* First enter directory itself */ - memset( (char *)&f, '\0', sizeof( f ) ); + memset( (char *)&f, '\0', sizeof( f ) ); - f.f_dir.ptr = dir; - f.f_dir.len = strlen(dir); + f.f_dir.ptr = dir; + f.f_dir.len = strlen(dir); - dir = *dir ? dir : "."; + dir = *dir ? dir : "."; - /* Special case / : enter it */ + /* Now enter contents of directory */ - if( f.f_dir.len == 1 && f.f_dir.ptr[0] == '/' ) - (*func)( closure, dir, 0 /* not stat()'ed */, (time_t)0 ); + if( !( dd = opendir( dir ) ) ) + { + PROFILE_EXIT(FILE_DIRSCAN); + return; + } - /* Now enter contents of directory */ - - if( !( d = opendir( dir ) ) ) - return; - - if( DEBUG_BINDSCAN ) - printf( "scan directory %s\n", dir ); + if( DEBUG_BINDSCAN ) + printf( "scan directory %s\n", dir ); string_new( filename ); - while( dirent = readdir( d ) ) - { -# ifdef old_sinix - /* Broken structure definition on sinix. */ - f.f_base.ptr = dirent->d_name - 2; -# else - f.f_base.ptr = dirent->d_name; -# endif - f.f_base.len = strlen( f.f_base.ptr ); + while( dirent = readdir( dd ) ) + { + file_info_t * ff = 0; + + # ifdef old_sinix + /* Broken structure definition on sinix. */ + f.f_base.ptr = dirent->d_name - 2; + # else + f.f_base.ptr = dirent->d_name; + # endif + f.f_base.len = strlen( f.f_base.ptr ); string_truncate( filename, 0 ); - path_build( &f, filename, 0 ); + path_build( &f, filename, 0 ); - (*func)( closure, filename->value, 0 /* not stat()'ed */, (time_t)0 ); - } + files = list_new( files, newstr(filename->value) ); + file_query( filename->value ); + } string_free( filename ); - closedir( d ); + closedir( dd ); + + d->files = files; + } + + /* Special case / : enter it */ + { + unsigned long len = strlen(d->name); + if( len == 1 && d->name[0] == '/' ) + (*func)( closure, d->name, 1 /* stat()'ed */, d->time ); + } + + /* Now enter contents of directory */ + if ( d->files ) + { + LIST * files = d->files; + while ( files ) + { + file_info_t * ff = file_info( files->string ); + (*func)( closure, ff->name, 1 /* stat()'ed */, ff->time ); + files = list_next( files ); + } + } + + PROFILE_EXIT(FILE_DIRSCAN); +} + +file_info_t * file_query( char * filename ) +{ + file_info_t * ff = file_info( filename ); + if ( ! ff->time ) + { + struct stat statbuf; + + if( stat( *filename ? filename : ".", &statbuf ) < 0 ) + return 0; + + ff->is_file = statbuf.st_mode & S_IFREG ? 1 : 0; + ff->is_dir = statbuf.st_mode & S_IFDIR ? 1 : 0; + ff->size = statbuf.st_size; + ff->time = statbuf.st_mtime ? statbuf.st_mtime : 1; + } + return ff; } /* @@ -184,32 +245,17 @@ file_time( char *filename, time_t *time ) { - struct stat statbuf; - - if( stat( filename, &statbuf ) < 0 ) - return -1; - - /* Technically, existing files can have 0 as statbuf.st_mtime - --- in particular, the /cygdrive directory under cygwin. However, - though all the code jam assumes that timestamp of 0 means - "does not exist" and will try to create the "missing" target, causing - problems. Work around this problem by chanding 0 to 1. - */ - *time = statbuf.st_mtime ? statbuf.st_mtime : 1 ; - return 0; + file_info_t * ff = file_query( filename ); + if ( !ff ) return -1; + *time = ff->time; + return 0; } int file_is_file(char* filename) { - struct stat statbuf; - - if( stat( filename, &statbuf ) < 0 ) - return -1; - - if (S_ISREG(statbuf.st_mode)) - return 1; - else - return 0; + file_info_t * ff = file_query( filename ); + if ( !ff ) return -1; + return ff->is_file; } @@ -281,6 +327,8 @@ file_archscan( */ string_table = (char *)malloc(lar_size); + if ( DEBUG_PROFILE ) + profile_memory( lar_size ); lseek(fd, offset + SARHDR, 0); if (read(fd, string_table, lar_size) != lar_size) printf("error reading string table\n"); diff --git a/src/engine/hash.c b/src/engine/hash.c index 50572f6f4..dda649381 100644 --- a/src/engine/hash.c +++ b/src/engine/hash.c @@ -6,6 +6,8 @@ # include "jam.h" # include "hash.h" +# include "compile.h" +#include "debug.h" # include /* @@ -24,6 +26,10 @@ * 4/29/93 - ensure ITEM's are aligned */ +/* */ +#define HASH_DEBUG_PROFILE 1 +/* */ + char *hashsccssid="@(#)hash.c 1.14 () 6/20/88"; /* Header attached to all data items entered into a hash table. */ @@ -144,12 +150,24 @@ hashitem( register ITEM *i; unsigned char *b = (unsigned char*)(*data)->key; unsigned int keyval; + + #ifdef HASH_DEBUG_PROFILE + profile_frame prof[1]; + if ( DEBUG_PROFILE ) + profile_enter( 0, prof ); + #endif if( enter && !hp->items.more ) hashrehash( hp ); if( !enter && !hp->items.nel ) + { + #ifdef HASH_DEBUG_PROFILE + if ( DEBUG_PROFILE ) + profile_exit( prof ); + #endif return 0; + } keyval = *b; @@ -163,6 +181,10 @@ hashitem( !strcmp( i->data.key, (*data)->key ) ) { *data = &i->data; + #ifdef HASH_DEBUG_PROFILE + if ( DEBUG_PROFILE ) + profile_exit( prof ); + #endif return !0; } @@ -188,6 +210,10 @@ hashitem( *data = &i->data; } + #ifdef HASH_DEBUG_PROFILE + if ( DEBUG_PROFILE ) + profile_exit( prof ); + #endif return 0; } @@ -198,10 +224,12 @@ hashitem( static void hashrehash( register struct hash *hp ) { int i = ++hp->items.list; - hp->items.more = i ? 2 * hp->items.nel : hp->inel; hp->items.next = (char *)malloc( hp->items.more * hp->items.size ); hp->items.free = 0; + + if ( DEBUG_PROFILE ) + profile_memory( hp->items.more * hp->items.size ); hp->items.lists[i].nel = hp->items.more; hp->items.lists[i].base = hp->items.next; @@ -213,6 +241,9 @@ static void hashrehash( register struct hash *hp ) hp->tab.nel = hp->items.nel * hp->bloat; hp->tab.base = (ITEM **)malloc( hp->tab.nel * sizeof(ITEM **) ); + if ( DEBUG_PROFILE ) + profile_memory( hp->tab.nel * sizeof(ITEM **) ); + memset( (char *)hp->tab.base, '\0', hp->tab.nel * sizeof( ITEM * ) ); for( i = 0; i < hp->items.list; i++ ) @@ -268,6 +299,9 @@ hashinit( { struct hash *hp = (struct hash *)malloc( sizeof( *hp ) ); + if ( DEBUG_PROFILE ) + profile_memory( sizeof( *hp ) ); + hp->bloat = 3; hp->tab.nel = 0; hp->tab.base = (ITEM **)0; @@ -277,7 +311,7 @@ hashinit( hp->items.size = sizeof( struct hashhdr ) + ALIGNED( datalen ); hp->items.list = -1; hp->items.nel = 0; - hp->inel = 11; + hp->inel = /* */ 11 /*/ 47 /* */; hp->name = name; return hp; diff --git a/src/engine/hash.h b/src/engine/hash.h index ad43abbb2..11f0e7b3c 100644 --- a/src/engine/hash.h +++ b/src/engine/hash.h @@ -7,6 +7,9 @@ /* * hash.h - simple in-memory hashing routines */ + +#ifndef BOOST_JAM_HASH_H +#define BOOST_JAM_HASH_H typedef struct hashdata HASHDATA; @@ -18,3 +21,5 @@ int hash_free( struct hash *hp, HASHDATA *data); # define hashenter( hp, data ) (!hashitem( hp, data, !0 )) # define hashcheck( hp, data ) hashitem( hp, data, 0 ) + +#endif diff --git a/src/engine/index.html b/src/engine/index.html index 9b300b03f..417f9d6f5 100644 --- a/src/engine/index.html +++ b/src/engine/index.html @@ -138,7 +138,7 @@ facilitate its use in the Boost Build System, but should be backward compatible with Perforce Jam.

-

This is version 3.1.10 of BJam and is based on version 2.4 of +

This is version 3.1.12 of BJam and is based on version 2.4 of Jam/MR:

 /+\
@@ -1254,7 +1254,7 @@ if $(MESSAGE) { ECHO The message is: $(MESSAGE) ; }
    18 November, 2004 
   

-

Copyright 2003-2004 Rene Rivera, David Abrahams, Vladimir Prus.

+

Copyright 2003-2005 Rene Rivera, David Abrahams, Vladimir Prus.

Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or string; @@ -485,9 +488,13 @@ int main( int argc, char **argv, char **arg_environ ) status |= make( targets_count, targets2, anyhow ); free(targets); } + + PROFILE_EXIT(MAIN_MAKE); } + PROFILE_EXIT(MAIN); } + if ( DEBUG_PROFILE ) profile_dump(); @@ -497,6 +504,7 @@ int main( int argc, char **argv, char **arg_environ ) donerules(); donestamps(); donestr(); + file_done(); /* close cmdout */ diff --git a/src/engine/lists.c b/src/engine/lists.c index 2b527c396..92440288c 100644 --- a/src/engine/lists.c +++ b/src/engine/lists.c @@ -7,6 +7,7 @@ # include "jam.h" # include "newstr.h" # include "lists.h" +# include "debug.h" /* * lists.c - maintain lists of strings @@ -80,7 +81,9 @@ list_new( } else { - l = (LIST *)malloc( sizeof( *l ) ); + l = (LIST *)malloc( sizeof( LIST ) ); + if ( DEBUG_PROFILE ) + profile_memory( sizeof( LIST ) ); } /* If first on chain, head points here. */ diff --git a/src/engine/make1.c b/src/engine/make1.c index 91ee208cb..030009e78 100644 --- a/src/engine/make1.c +++ b/src/engine/make1.c @@ -127,6 +127,8 @@ static state *alloc_state() } else { + if ( DEBUG_PROFILE ) + profile_memory( sizeof(state) ); return (state *)malloc(sizeof(state)); } } diff --git a/src/engine/modules.c b/src/engine/modules.c index aa8f2c8d9..ea874b640 100644 --- a/src/engine/modules.c +++ b/src/engine/modules.c @@ -3,8 +3,10 @@ * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) */ -#include "modules.h" #include "jam.h" +#include "debug.h" + +#include "modules.h" #include "string.h" #include "hash.h" #include "newstr.h" @@ -30,6 +32,8 @@ static char* new_module_str( module_t* m, char* suffix ) module_t* bindmodule( char* name ) { + PROFILE_ENTER(BINDMODULE); + string s; module_t m_, *m = &m_; @@ -56,6 +60,9 @@ module_t* bindmodule( char* name ) m->user_module = 0; } string_free( &s ); + + PROFILE_EXIT(BINDMODULE); + return m; } @@ -115,9 +122,11 @@ void exit_module( module_t* m ) } void import_module(LIST* module_names, module_t* target_module) -{ +{ + PROFILE_ENTER(IMPORT_MODULE); + struct hash* h; - + if (!target_module->imported_modules) target_module->imported_modules = hashinit( sizeof(char*), "imported"); h = target_module->imported_modules; @@ -129,6 +138,8 @@ void import_module(LIST* module_names, module_t* target_module) hashenter(h, (HASHDATA**)&ss); } + + PROFILE_EXIT(IMPORT_MODULE); } static void add_module_name( void* r_, void* result_ ) diff --git a/src/engine/modules/order.c b/src/engine/modules/order.c index a435d9cc5..848c35ee1 100644 --- a/src/engine/modules/order.c +++ b/src/engine/modules/order.c @@ -7,6 +7,7 @@ #include "../strings.h" #include "../newstr.h" #include "../variable.h" +#include "../debug.h" /* Use quite klugy approach: when we add order dependency from 'a' to 'b', @@ -62,6 +63,8 @@ void topological_sort(int** graph, int num_vertices, int* result) { int i; int* colors = (int*)calloc(num_vertices, sizeof(int)); + if ( DEBUG_PROFILE ) + profile_memory( num_vertices*sizeof(int) ); for (i = 0; i < num_vertices; ++i) colors[i] = white; @@ -86,6 +89,8 @@ LIST *order( PARSE *parse, FRAME *frame ) int length = list_length(arg); int** graph = (int**)calloc(length, sizeof(int*)); int* order = (int*)malloc((length+1)*sizeof(int)); + if ( DEBUG_PROFILE ) + profile_memory( length*sizeof(int*) + (length+1)*sizeof(int) ); for(tmp = arg, src = 0; tmp; tmp = tmp->next, ++src) { /* For all object this one depend upon, add elements @@ -94,6 +99,8 @@ LIST *order( PARSE *parse, FRAME *frame ) int index = 0; graph[src] = (int*)calloc(list_length(dependencies)+1, sizeof(int)); + if ( DEBUG_PROFILE ) + profile_memory( (list_length(dependencies)+1)*sizeof(int) ); for(; dependencies; dependencies = dependencies->next) { int dst = list_index(arg, dependencies->string); if (dst != -1) diff --git a/src/engine/newstr.c b/src/engine/newstr.c index 117dfb9ab..670cee504 100644 --- a/src/engine/newstr.c +++ b/src/engine/newstr.c @@ -7,6 +7,7 @@ # include "jam.h" # include "newstr.h" # include "hash.h" +# include "compile.h" # include # include @@ -34,6 +35,8 @@ typedef char *STRING; static struct hash *strhash = 0; static int strtotal = 0; +static int strcount_in = 0; +static int strcount_out = 0; /* * Immortal string allocator implementation speeds string allocation @@ -53,11 +56,20 @@ static strblock* strblock_chain = 0; static char* storage_start = 0; static char* storage_finish = 0; +/* */ +#define SIMPLE_ALLOC 0 +/*/ +#define SIMPLE_ALLOC 1 +/* */ + /* * allocate() - Allocate n bytes of immortal string storage */ static char* allocate(size_t n) { + #if SIMPLE_ALLOC + return (char*)malloc(n); + #else /* See if we can grab storage from an existing block */ size_t remaining = storage_finish - storage_start; if ( remaining >= n ) @@ -88,6 +100,7 @@ static char* allocate(size_t n) } return new_block->data; } + #endif } /* @@ -112,8 +125,12 @@ newstr( char *string ) strtotal += l + 1; memcpy( m, string, l + 1 ); *s = m; + + if ( DEBUG_PROFILE ) + profile_memory( l+1 ); } + strcount_in += 1; return *s; } @@ -124,6 +141,7 @@ newstr( char *string ) char * copystr( char *s ) { + strcount_in += 1; return s; } @@ -134,6 +152,7 @@ copystr( char *s ) void freestr( char *s ) { + strcount_out += 1; } /* @@ -155,4 +174,6 @@ donestr() if( DEBUG_MEM ) printf( "%dK in strings\n", strtotal / 1024 ); + + /* printf( "--- %d strings of %d dangling\n", strcount_in-strcount_out, strcount_in ); */ } diff --git a/src/engine/parse.c b/src/engine/parse.c index c630ee77a..606112ec8 100644 --- a/src/engine/parse.c +++ b/src/engine/parse.c @@ -17,6 +17,7 @@ # include "newstr.h" # include "modules.h" # include "frames.h" +# include "debug.h" /* * parse.c - make and destroy parse trees as driven by the parser @@ -78,6 +79,8 @@ parse_make( int num ) { PARSE *p = (PARSE *)malloc( sizeof( PARSE ) ); + if ( DEBUG_PROFILE ) + profile_memory( sizeof( PARSE ) ); p->func = func; p->left = left; diff --git a/src/engine/patchlevel.h b/src/engine/patchlevel.h index f93eb2a3f..a1a6df001 100644 --- a/src/engine/patchlevel.h +++ b/src/engine/patchlevel.h @@ -7,5 +7,11 @@ /* Keep JAMVERSYM in sync with VERSION. */ /* It can be accessed as $(JAMVERSION) in the Jamfile. */ -#define VERSION "3.1.11" +#define VERSION_MAJOR 3 +#define VERSION_MINOR 1 +#define VERSION_PATCH 12 +#define VERSION_MAJOR_SYM "03" +#define VERSION_MINOR_SYM "1" +#define VERSION_PATCH_SYM "12" +#define VERSION "3.1.12" #define JAMVERSYM "JAMVERSION=3.1" diff --git a/src/engine/pwd.c b/src/engine/pwd.c index 7bf8c5c31..896524820 100644 --- a/src/engine/pwd.c +++ b/src/engine/pwd.c @@ -1,4 +1,4 @@ -/* Copyright Vladimir Prus 2002. Distributed under the Boost */ +/* Copyright Vladimir Prus 2002, Rene Rivera 2005. Distributed under the Boost */ /* Software License, Version 1.0. (See accompanying */ /* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ @@ -21,24 +21,32 @@ #endif #endif +/* The current directory can't change in bjam, so optimize this to cache +** the result. +*/ +static char pwd_buffer[PATH_MAX]; +static char * pwd_result = NULL; LIST* pwd(void) { - char buffer[PATH_MAX]; - if (getcwd(buffer, sizeof(buffer)) == NULL) - { - perror("can not get current directory"); - return L0; - } - else + if (!pwd_result) { + if (getcwd(pwd_buffer, sizeof(pwd_buffer)) == NULL) + { + perror("can not get current directory"); + return L0; + } + else + { #ifdef NT - return list_new(L0, short_path_to_long_path(buffer)); + pwd_result = short_path_to_long_path(pwd_buffer); #else - return list_new(L0, newstr(buffer)); + pwd_result = newstr(pwd_buffer); #endif + } } + return list_new(L0, pwd_result); } diff --git a/src/engine/regexp.c b/src/engine/regexp.c index 92ee8efd8..33cd9f968 100644 --- a/src/engine/regexp.c +++ b/src/engine/regexp.c @@ -42,6 +42,7 @@ * regular-expression syntax might require a total rethink. */ #include "regexp.h" +#include "debug.h" #include #include #ifndef ultrix @@ -241,6 +242,8 @@ regcomp( char *exp ) r = (regexp *)malloc(sizeof(regexp) + (unsigned)regsize); if (r == NULL) FAIL("out of space"); + if ( DEBUG_PROFILE ) + profile_memory( sizeof(regexp) + (unsigned)regsize ); /* Second pass: emit code. */ regparse = (char *)exp; diff --git a/src/engine/rules.c b/src/engine/rules.c index 69bb56734..2902995c3 100644 --- a/src/engine/rules.c +++ b/src/engine/rules.c @@ -16,6 +16,7 @@ # include "lists.h" # include "pathsys.h" # include "timestamp.h" +# include "debug.h" /* This file is ALSO: * Copyright 2001-2004 David Abrahams. @@ -265,6 +266,8 @@ copytarget( const TARGET *ot ) TARGET *t; t = (TARGET *)malloc( sizeof( *t ) ); + if ( DEBUG_PROFILE ) + profile_memory( sizeof( *t ) ); memset( (char *)t, '\0', sizeof( *t ) ); t->name = copystr( ot->name ); t->boundname = t->name; @@ -319,6 +322,8 @@ targetentry( TARGETS *c; c = (TARGETS *)malloc( sizeof( TARGETS ) ); + if ( DEBUG_PROFILE ) + profile_memory( sizeof( TARGETS ) ); c->target = target; if( !chain ) chain = c; @@ -365,6 +370,8 @@ actionlist( ACTION *action ) { ACTIONS *actions = (ACTIONS *)malloc( sizeof( ACTIONS ) ); + if ( DEBUG_PROFILE ) + profile_memory( sizeof( ACTIONS ) ); actions->action = action; @@ -413,7 +420,11 @@ addsettings( if ( v ) settings_freelist = v->next; else + { v = (SETTINGS *)malloc( sizeof( *v ) ); + if ( DEBUG_PROFILE ) + profile_memory( sizeof( *v ) ); + } v->symbol = newstr( symbol ); v->value = value; @@ -553,6 +564,8 @@ donerules() argument_list* args_new() { argument_list* r = (argument_list*)malloc( sizeof(argument_list) ); + if ( DEBUG_PROFILE ) + profile_memory( sizeof(argument_list) ); r->reference_count = 0; lol_init(r->data); return r; @@ -690,6 +703,8 @@ static void set_rule_actions( RULE* rule, rule_actions* actions ) static rule_actions* actions_new( char* command, LIST* bindlist, int flags ) { rule_actions* result = (rule_actions*)malloc(sizeof(rule_actions)); + if ( DEBUG_PROFILE ) + profile_memory( sizeof(rule_actions) ); result->command = copystr( command ); result->bindlist = bindlist; result->flags = flags; diff --git a/src/engine/scan.c b/src/engine/scan.c index b6943228c..1145ac858 100644 --- a/src/engine/scan.c +++ b/src/engine/scan.c @@ -11,6 +11,7 @@ # include "jamgram.h" # include "jambase.h" # include "newstr.h" +# include "debug.h" /* * scan.c - the jam yacc scanner @@ -82,6 +83,8 @@ void yyfparse( char *s ) { struct include *i = (struct include *)malloc( sizeof( *i ) ); + if ( DEBUG_PROFILE ) + profile_memory( sizeof( *i ) ); /* Push this onto the incp chain. */ diff --git a/src/engine/strings.c b/src/engine/strings.c index b578c7901..6c093c6b7 100644 --- a/src/engine/strings.c +++ b/src/engine/strings.c @@ -3,6 +3,7 @@ /* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ #include "strings.h" +#include "debug.h" #include #include #include @@ -55,6 +56,8 @@ static void string_reserve_internal( string* self, size_t capacity ) if ( self->value == self->opt ) { self->value = (char*)malloc( capacity + JAM_STRING_MAGIC_SIZE ); + if ( DEBUG_PROFILE ) + profile_memory( capacity + JAM_STRING_MAGIC_SIZE ); self->value[0] = 0; strncat( self->value, self->opt, sizeof(self->opt) ); assert( strlen( self->value ) <= self->capacity ); /* This is a regression test */ diff --git a/src/engine/timestamp.c b/src/engine/timestamp.c index f7c412808..3c5643108 100644 --- a/src/engine/timestamp.c +++ b/src/engine/timestamp.c @@ -11,6 +11,8 @@ */ # include "jam.h" +# include "debug.h" + # include "hash.h" # include "filesys.h" # include "pathsys.h" @@ -69,13 +71,15 @@ timestamp( char *target, time_t *time ) { + PROFILE_ENTER(timestamp); + PATHNAME f1, f2; BINDING binding, *b = &binding; string buf[1]; + string path; + char *p; # ifdef DOWNSHIFT_PATHS - string path; - char *p; string_copy( &path, target ); p = path.value; @@ -181,6 +185,8 @@ timestamp( # ifdef DOWNSHIFT_PATHS string_free( &path ); #endif + + PROFILE_EXIT(timestamp); } static void diff --git a/src/kernel/class.jam b/src/kernel/class.jam index 188f0e8ff..92b970ad8 100644 --- a/src/kernel/class.jam +++ b/src/kernel/class.jam @@ -82,17 +82,17 @@ rule xinit ( instance : class ) rule new ( class args * : * ) { - .next-instance.$(class) ?= 1 ; - local id = object($(class))@$(.next-instance.$(class)) ; + .next-instance ?= 1 ; + local id = object($(class))@$(.next-instance) ; + + xinit $(id) : $(class) ; - xinit $(id) : $(class) ; - INSTANCE $(id) : class@$(class) ; IMPORT_MODULE $(id) : ; $(id).__init__ $(args) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ; - + # bump the next unique object name - .next-instance.$(class) = [ numbers.increment $(.next-instance.$(class)) ] ; + .next-instance = [ numbers.increment $(.next-instance) ] ; # Return the name of the new instance. return $(id) ; diff --git a/src/util/path.jam b/src/util/path.jam index 6fe0dad1f..5d1c0c546 100644 --- a/src/util/path.jam +++ b/src/util/path.jam @@ -140,7 +140,7 @@ rule reverse ( path ) # local rule join-imp ( elements + ) { - return [ NORMALIZE_PATH $(elements:J="/") ] ; + return [ NORMALIZE_PATH $(elements) ] ; } # diff --git a/src/util/print.jam b/src/util/print.jam index 0ef4ca3c0..e776beffb 100644 --- a/src/util/print.jam +++ b/src/util/print.jam @@ -342,7 +342,7 @@ rule text ( text-body on $(output-target) = ; text-suffix on $(output-target) = ; text-action $(output-target) ; - text-front-section.$(soutput-target) = ; + text-front-section.$(output-target) = ; } if $(overwrite) { @@ -368,10 +368,9 @@ rule text ( text-front-section.$(output-target) = $(prefix-body-suffix) ; strings = $(strings[2-]) ; } - while $(strings) + for local string-n in $(strings) { - text-$(prefix-body-suffix) on $(output-target) += [ echo-cmd $(strings[1]) ] ; - strings = $(strings[2-]) ; + text-$(prefix-body-suffix) on $(output-target) += [ echo-cmd $(string-n) ] ; } } }