8136695: Automatic build comparison with COMPARE_BUILD

Reviewed-by: erikj
This commit is contained in:
Magnus Ihse Bursie 2015-09-21 09:32:07 +02:00
parent 2a12715485
commit 19b025dd98
5 changed files with 297 additions and 16 deletions

View File

@ -935,6 +935,7 @@ AC_DEFUN_ONCE([BASIC_SETUP_COMPLEX_TOOLS],
BASIC_PATH_PROGS(HG, hg)
BASIC_PATH_PROGS(STAT, stat)
BASIC_PATH_PROGS(TIME, time)
BASIC_PATH_PROGS(PATCH, [gpatch patch])
# Check if it's GNU time
IS_GNU_TIME=`$TIME --version 2>&1 | $GREP 'GNU time'`
if test "x$IS_GNU_TIME" != x; then

View File

@ -859,6 +859,7 @@ CODESIGN
XATTR
DSYMUTIL
IS_GNU_TIME
PATCH
TIME
STAT
HG
@ -1174,6 +1175,7 @@ READELF
HG
STAT
TIME
PATCH
DSYMUTIL
XATTR
CODESIGN
@ -2053,6 +2055,7 @@ Some influential environment variables:
HG Override default value for HG
STAT Override default value for STAT
TIME Override default value for TIME
PATCH Override default value for PATCH
DSYMUTIL Override default value for DSYMUTIL
XATTR Override default value for XATTR
CODESIGN Override default value for CODESIGN
@ -4359,7 +4362,7 @@ VS_SDK_PLATFORM_NAME_2013=
#CUSTOM_AUTOCONF_INCLUDE
# Do not change or remove the following line, it is needed for consistency checks:
DATE_WHEN_GENERATED=1441958217
DATE_WHEN_GENERATED=1442820670
###############################################################################
#
@ -18865,6 +18868,192 @@ $as_echo "$tool_specified" >&6; }
fi
# Publish this variable in the help.
if test "x$PATCH" = x; then
# The variable is not set by user, try to locate tool using the code snippet
for ac_prog in gpatch patch
do
# Extract the first word of "$ac_prog", so it can be a program name with args.
set dummy $ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if ${ac_cv_path_PATCH+:} false; then :
$as_echo_n "(cached) " >&6
else
case $PATCH in
[\\/]* | ?:[\\/]*)
ac_cv_path_PATCH="$PATCH" # Let the user override the test with a path.
;;
*)
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_path_PATCH="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
;;
esac
fi
PATCH=$ac_cv_path_PATCH
if test -n "$PATCH"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $PATCH" >&5
$as_echo "$PATCH" >&6; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
test -n "$PATCH" && break
done
else
# The variable is set, but is it from the command line or the environment?
# Try to remove the string !PATCH! from our list.
try_remove_var=${CONFIGURE_OVERRIDDEN_VARIABLES//!PATCH!/}
if test "x$try_remove_var" = "x$CONFIGURE_OVERRIDDEN_VARIABLES"; then
# If it failed, the variable was not from the command line. Ignore it,
# but warn the user (except for BASH, which is always set by the calling BASH).
if test "xPATCH" != xBASH; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Ignoring value of PATCH from the environment. Use command line variables instead." >&5
$as_echo "$as_me: WARNING: Ignoring value of PATCH from the environment. Use command line variables instead." >&2;}
fi
# Try to locate tool using the code snippet
for ac_prog in gpatch patch
do
# Extract the first word of "$ac_prog", so it can be a program name with args.
set dummy $ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if ${ac_cv_path_PATCH+:} false; then :
$as_echo_n "(cached) " >&6
else
case $PATCH in
[\\/]* | ?:[\\/]*)
ac_cv_path_PATCH="$PATCH" # Let the user override the test with a path.
;;
*)
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_path_PATCH="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
;;
esac
fi
PATCH=$ac_cv_path_PATCH
if test -n "$PATCH"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $PATCH" >&5
$as_echo "$PATCH" >&6; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
test -n "$PATCH" && break
done
else
# If it succeeded, then it was overridden by the user. We will use it
# for the tool.
# First remove it from the list of overridden variables, so we can test
# for unknown variables in the end.
CONFIGURE_OVERRIDDEN_VARIABLES="$try_remove_var"
# Check if the provided tool contains a complete path.
tool_specified="$PATCH"
tool_basename="${tool_specified##*/}"
if test "x$tool_basename" = "x$tool_specified"; then
# A command without a complete path is provided, search $PATH.
{ $as_echo "$as_me:${as_lineno-$LINENO}: Will search for user supplied tool PATCH=$tool_basename" >&5
$as_echo "$as_me: Will search for user supplied tool PATCH=$tool_basename" >&6;}
# Extract the first word of "$tool_basename", so it can be a program name with args.
set dummy $tool_basename; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if ${ac_cv_path_PATCH+:} false; then :
$as_echo_n "(cached) " >&6
else
case $PATCH in
[\\/]* | ?:[\\/]*)
ac_cv_path_PATCH="$PATCH" # Let the user override the test with a path.
;;
*)
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_path_PATCH="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
;;
esac
fi
PATCH=$ac_cv_path_PATCH
if test -n "$PATCH"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $PATCH" >&5
$as_echo "$PATCH" >&6; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
if test "x$PATCH" = x; then
as_fn_error $? "User supplied tool $tool_basename could not be found" "$LINENO" 5
fi
else
# Otherwise we believe it is a complete path. Use it as it is.
{ $as_echo "$as_me:${as_lineno-$LINENO}: Will use user supplied tool PATCH=$tool_specified" >&5
$as_echo "$as_me: Will use user supplied tool PATCH=$tool_specified" >&6;}
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for PATCH" >&5
$as_echo_n "checking for PATCH... " >&6; }
if test ! -x "$tool_specified"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
$as_echo "not found" >&6; }
as_fn_error $? "User supplied tool PATCH=$tool_specified does not exist or is not executable" "$LINENO" 5
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $tool_specified" >&5
$as_echo "$tool_specified" >&6; }
fi
fi
fi
# Check if it's GNU time
IS_GNU_TIME=`$TIME --version 2>&1 | $GREP 'GNU time'`
if test "x$IS_GNU_TIME" != x; then

View File

@ -495,6 +495,7 @@ LN:=@LN@
MKDIR:=@MKDIR@
MV:=@MV@
NAWK:=@NAWK@
PATCH:=@PATCH@
PRINTF:=@PRINTF@
PWD:=@THEPWDCMD@
RM:=@RM@

View File

@ -50,7 +50,8 @@ ifeq ($(HAS_SPEC),)
include $(topdir)/make/Help.gmk
# Targets provided by Init.gmk.
ALL_INIT_TARGETS := print-modules print-targets print-configuration reconfigure
ALL_INIT_TARGETS := print-modules print-targets print-configuration \
reconfigure pre-compare-build post-compare-build
# CALLED_TARGETS is the list of targets that the user provided,
# or "default" if unspecified.
@ -163,25 +164,39 @@ ifeq ($(HAS_SPEC),)
$(COMMAND_LINE_VARIABLES) $(MAKECMDGOALS))')
endif
MAKE_INIT_WITH_SPEC_ARGUMENTS := ACTUAL_TOPDIR=$(topdir) \
USER_MAKE_VARS="$(USER_MAKE_VARS)" MAKE_LOG_FLAGS=$(MAKE_LOG_FLAGS) \
LOG_LEVEL=$(LOG_LEVEL) LOG_NOFILE=$(LOG_NOFILE) \
INIT_TARGETS="$(INIT_TARGETS)" \
SEQUENTIAL_TARGETS="$(SEQUENTIAL_TARGETS)" \
PARALLEL_TARGETS="$(PARALLEL_TARGETS)"
# Now the init and main targets will be called, once for each SPEC. The
# recipe will be run once for every target specified, but we only want to
# execute the recipe a single time, hence the TARGET_DONE with a dummy
# command if true.
# The COMPARE_BUILD part implements special support for makefile development.
$(ALL_INIT_TARGETS) $(ALL_MAIN_TARGETS): make-info
@$(if $(TARGET_DONE), \
true \
, \
( cd $(topdir) && \
$(foreach spec, $(SPECS), \
( cd $(topdir) && \
$(MAKE) $(MFLAGS) $(MAKE_LOG_FLAGS) -r -R -j 1 -f $(topdir)/make/Init.gmk \
SPEC=$(spec) HAS_SPEC=true ACTUAL_TOPDIR=$(topdir) \
USER_MAKE_VARS="$(USER_MAKE_VARS)" MAKE_LOG_FLAGS=$(MAKE_LOG_FLAGS) \
LOG_LEVEL=$(LOG_LEVEL) LOG_NOFILE=$(LOG_NOFILE) \
INIT_TARGETS="$(INIT_TARGETS)" \
SEQUENTIAL_TARGETS="$(SEQUENTIAL_TARGETS)" \
PARALLEL_TARGETS="$(PARALLEL_TARGETS)" \
main ) && \
) true \
SPEC=$(spec) HAS_SPEC=true $(MAKE_INIT_WITH_SPEC_ARGUMENTS) \
main && \
$(if $(and $(COMPARE_BUILD), $(PARALLEL_TARGETS)), \
$(MAKE) $(MFLAGS) $(MAKE_LOG_FLAGS) -r -R -f $(topdir)/make/Init.gmk \
SPEC=$(spec) HAS_SPEC=true ACTUAL_TOPDIR=$(topdir) \
COMPARE_BUILD="$(COMPARE_BUILD)" pre-compare-build && \
$(MAKE) $(MFLAGS) $(MAKE_LOG_FLAGS) -r -R -j 1 -f $(topdir)/make/Init.gmk \
SPEC=$(spec) HAS_SPEC=true $(MAKE_INIT_WITH_SPEC_ARGUMENTS) \
COMPARE_BUILD="$(COMPARE_BUILD)" main && \
$(MAKE) $(MFLAGS) $(MAKE_LOG_FLAGS) -r -R -f $(topdir)/make/Init.gmk \
SPEC=$(spec) HAS_SPEC=true ACTUAL_TOPDIR=$(topdir) \
COMPARE_BUILD="$(COMPARE_BUILD)" post-compare-build && \
) \
) true ) \
$(eval TARGET_DONE=true) \
)
@ -205,6 +220,9 @@ else # HAS_SPEC=true
# Verify that the spec file we included seems okay.
$(eval $(call CheckSpecSanity))
# Parse COMPARE_BUILD (for makefile development)
$(eval $(call ParseCompareBuild))
ifeq ($(LOG_NOFILE), true)
# Disable log wrapper if LOG=[level,]nofile was given
override BUILD_LOG_WRAPPER :=
@ -244,7 +262,7 @@ else # HAS_SPEC=true
# The main target, for delegating into Main.gmk
##############################################################################
MAIN_TARGETS := $(SEQUENTIAL_TARGETS) $(PARALLEL_TARGETS)
MAIN_TARGETS := $(SEQUENTIAL_TARGETS) $(PARALLEL_TARGETS) $(COMPARE_BUILD_MAKE)
TARGET_DESCRIPTION := target$(if $(word 2, $(MAIN_TARGETS)),s) \
'$(strip $(MAIN_TARGETS))' in configuration '$(CONF_NAME)'
@ -271,7 +289,7 @@ else # HAS_SPEC=true
( cd $(TOPDIR) && \
$(BUILD_LOG_WRAPPER) $(MAKE) $(MAKE_ARGS) $(OUTPUT_SYNC_FLAG) \
-j $(JOBS) -f make/Main.gmk $(USER_MAKE_VARS) \
$(PARALLEL_TARGETS) || \
$(PARALLEL_TARGETS) $(COMPARE_BUILD_MAKE) || \
( exitcode=$$? && $(BUILD_LOG_WRAPPER) \
$(PRINTF) "\nERROR: Build failed for $(TARGET_DESCRIPTION) (exit code $$exitcode) \n" && \
cd $(TOPDIR) && $(MAKE) $(MAKE_ARGS) -j 1 -f make/Init.gmk \
@ -304,5 +322,26 @@ else # HAS_SPEC=true
fi
$(PRINTF) "Hint: If caused by a warning, try configure --disable-warnings-as-errors.\n\n"
# Support targets for COMPARE_BUILD, used for makefile development
pre-compare-build:
$(ECHO) "Preparing for comparison rebuild"
# Apply patch, if any
ifneq ($(COMPARE_BUILD_PATCH), )
$(PATCH) -p1 < $(COMPARE_BUILD_PATCH)
endif
# Move the first build away and re-create the output directory
( cd $(TOPDIR) && \
$(MV) $(OUTPUT_ROOT) $(OUTPUT_ROOT).OLD && \
$(MKDIR) -p $(OUTPUT_ROOT) )
# Re-run configure with the same arguments (and possibly some additional),
# must be done after patching.
( cd $(OUTPUT_ROOT) && PATH="$(ORIGINAL_PATH)" \
$(BASH) $(TOPDIR)/configure $(CONFIGURE_COMMAND_LINE) $(COMPARE_BUILD_CONF))
post-compare-build:
# Compare first and second build. Ignore any error code from compare.sh.
$(ECHO) "Comparing between comparison rebuild (this/new) and baseline (other/old)"
+(cd $(OUTPUT_ROOT) && ./compare.sh $(COMPARE_BUILD_COMP_OPTS) -o $(OUTPUT_ROOT).OLD || true)
.PHONY: print-targets print-modules reconfigure main on-failure
endif

View File

@ -40,7 +40,7 @@ ifeq ($(HAS_SPEC),)
##############################################################################
# Make control variables, handled by Init.gmk
INIT_CONTROL_VARIABLES := LOG CONF SPEC JOBS CONF_CHECK
INIT_CONTROL_VARIABLES := LOG CONF SPEC JOBS CONF_CHECK COMPARE_BUILD
# All known make control variables
MAKE_CONTROL_VARIABLES := $(INIT_CONTROL_VARIABLES) TEST JDK_FILTER
@ -53,12 +53,14 @@ ifeq ($(HAS_SPEC),)
# The variable MAKEOVERRIDES contains variable assignments from the command
# line, but in reverse order to what the user entered.
# The '\#' <=> '\ 'dance is needed to keep values with space in them connected.
COMMAND_LINE_VARIABLES := $(subst \#,\ , $(call reverse, $(subst \ ,\#,$(MAKEOVERRIDES))))
# A list like FOO="val1" BAR="val2" containing all user-supplied make
# variables that we should propagate.
USER_MAKE_VARS := $(filter-out $(addsuffix =%, $(INIT_CONTROL_VARIABLES)), \
$(MAKEOVERRIDES))
# The '\#' <=> '\ 'dance is needed to keep values with space in them connected.
USER_MAKE_VARS := $(subst \#,\ , $(filter-out $(addsuffix =%, $(INIT_CONTROL_VARIABLES)), \
$(subst \ ,\#,$(MAKEOVERRIDES))))
# Setup information about available configurations, if any.
build_dir=$(topdir)/build
@ -309,6 +311,55 @@ else # $(HAS_SPEC)=true
endif
endef
# Parse COMPARE_BUILD into COMPARE_BUILD_*
# Syntax: COMPARE_BUILD=CONF=<configure options>:PATCH=<patch file>:
# MAKE=<make targets>:COMP_OPTS=<compare script options>|<default>
# If neither CONF or PATCH is given, assume <default> means CONF if it
# begins with "--", otherwise assume it means PATCH.
# MAKE and COMP_OPTS can only be used with CONF and/or PATCH specified.
# If any value contains "+", it will be replaced by space.
define ParseCompareBuild
ifneq ($$(COMPARE_BUILD), )
ifneq ($$(findstring :, $$(COMPARE_BUILD)), )
$$(foreach part, $$(subst :, , $$(COMPARE_BUILD)), \
$$(if $$(filter PATCH=%, $$(part)), \
$$(eval COMPARE_BUILD_PATCH=$$(strip $$(patsubst PATCH=%, %, $$(part)))) \
) \
$$(if $$(filter CONF=%, $$(part)), \
$$(eval COMPARE_BUILD_CONF=$$(strip $$(subst +, , $$(patsubst CONF=%, %, $$(part))))) \
) \
$$(if $$(filter MAKE=%, $$(part)), \
$$(eval COMPARE_BUILD_MAKE=$$(strip $$(subst +, , $$(patsubst MAKE=%, %, $$(part))))) \
) \
$$(if $$(filter COMP_OPTS=%, $$(part)), \
$$(eval COMPARE_BUILD_COMP_OPTS=$$(strip $$(subst +, , $$(patsubst COMP_OPTS=%, %, $$(part))))) \
) \
)
else
# Separate handling for single field case, to allow for spaces in values.
ifneq ($$(filter PATCH=%, $$(COMPARE_BUILD)), )
COMPARE_BUILD_PATCH=$$(strip $$(patsubst PATCH=%, %, $$(COMPARE_BUILD)))
else ifneq ($$(filter CONF=%, $$(COMPARE_BUILD)), )
COMPARE_BUILD_CONF=$$(strip $$(subst +, , $$(patsubst CONF=%, %, $$(COMPARE_BUILD))))
else ifneq ($$(filter --%, $$(COMPARE_BUILD)), )
# Assume CONF if value begins with --
COMPARE_BUILD_CONF=$$(strip $$(subst +, , $$(COMPARE_BUILD)))
else
# Otherwise assume patch file
COMPARE_BUILD_PATCH=$$(strip $$(COMPARE_BUILD))
endif
endif
ifneq ($$(COMPARE_BUILD_PATCH), )
ifneq ($$(wildcard $$(TOPDIR)/$$(COMPARE_BUILD_PATCH)), )
# Assume relative path, if file exists
COMPARE_BUILD_PATCH := $$(wildcard $$(TOPDIR)/$$(COMPARE_BUILD_PATCH))
else ifeq ($$(wildcard $$(COMPARE_BUILD_PATCH)), )
$$(error Patch file $$(COMPARE_BUILD_PATCH) does not exist)
endif
endif
endif
endef
define RotateLogFiles
$(RM) $(BUILD_LOG).old 2> /dev/null
$(MV) $(BUILD_LOG) $(BUILD_LOG).old 2> /dev/null || true