This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

RFC [testsuite] Obey --load-average


I'm working on a patch to modify the testsuite to obey the
--load-average value if one is passed to make.  It seems to work pretty
well, except for libstdc++ which doesn't load gcc/libs/gcc-defs.exp
since it defines it's own ${tool}_functions.  I haven't dug too deeply
into libstdc++'s testsuite yet, but how does it manage parallelization
if it isn't using the routines in gcc-defs.exp?  I'm thinking I will
need a separate load-limit.exp file or some such.

This feature would be very helpful since you cannot interrupt a test run
and restart from where you left off.  Also, if you suspend the job, then
you will get timeouts.  So it would be helpful to have a way to have it
yield when you need to do something else on your machine, or if you're
using a shared test machine and you want to use all available CPU, but
not crowd out other users.

Due to not having actual interprocess communication, the check_cpu_load
procedure uses an algo that gives lower numbered jobs slightly more
priority than higher numbered jobs.  When the load average is exceeded,
the job sleeps an amount of time based upon the "priority" (lower
numbered jobs sleep less) and a random number - this helps prevent feast
or famine cycles where all jobs stop when the load is too high and then
all jobs start again and saturate the CPUs, bouncing back and forth.

gcc/testsuite/ChangeLog

	* gcc/Makefile.in (check-parallel-%): Export job number to environment.
	* gcc/testsuite/lib/gcc-defs.exp (num_jobs, load_max, getloadavg_exe):
	New global variables.
	(check_cpu_load): New proc to check speed limit.
	(gcc_parallel_test_run_p): Modify to call check_cpu_load before
	acquiring a new lock file.

Thanks,
Daniel
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index efca9169671..f26ff3840b8 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -4039,6 +4039,7 @@ check-parallel-% : site.exp
 	@test -d $(TESTSUITEDIR)/$(check_p_subdir) || mkdir $(TESTSUITEDIR)/$(check_p_subdir)
 	-$(if $(check_p_subno),@)(rootme=`${PWD_COMMAND}`; export rootme; \
 	srcdir=`cd ${srcdir}; ${PWD_COMMAND}` ; export srcdir ; \
+	GCC_RUNTEST_JOBNO=$(check_p_subno) ; export GCC_RUNTEST_JOBNO ; \
 	if [ -n "$(check_p_subno)" ] \
 	   && [ -n "$$GCC_RUNTEST_PARALLELIZE_DIR" ] \
 	   && [ -f $(TESTSUITEDIR)/$(check_p_tool)-parallel/finished ]; then \
diff --git a/gcc/testsuite/lib/gcc-defs.exp b/gcc/testsuite/lib/gcc-defs.exp
index d5fde7ce5e3..e18025018d2 100644
--- a/gcc/testsuite/lib/gcc-defs.exp
+++ b/gcc/testsuite/lib/gcc-defs.exp
@@ -20,6 +20,8 @@ load_lib wrapper.exp
 
 load_lib target-utils.exp
 
+global num_jobs load_max getloadavg_exe
+
 #
 # ${tool}_check_compile -- Reports and returns pass/fail for a compilation
 #
@@ -148,6 +150,107 @@ proc ${tool}_exit { } {
     }
 }
 
+if { [info exists env(MAKEFLAGS)] } then {
+    # Attempt to get the --load-average from make
+    set load_max [regsub "^(?:|.*? -)l(\\d+(\\.\\d+)?).*?$" \
+						      $env(MAKEFLAGS) "\\1" ]
+    if [regexp "^\\d+(\\.\\d+)?$" $load_max match] then {
+        verbose "load_max = $load_max" 0
+    } else {
+        unset load_max
+    }
+
+    # Attempt to get the number of make -j<jobs>
+    set num_jobs [regsub "^(?:|.*? -)?j(\\d+).*?$" $env(MAKEFLAGS) "\\1" ]
+    if [regexp "^\\d+$" $num_jobs match] then {
+        verbose "num_jobs = $num_jobs" 0
+    } else {
+	set num_jobs 1
+    }
+}
+
+# If a --load-average was specified, try to build getloadavg_exe.
+if [info exists load_max] then {
+    set src "$tmpdir/getloadavg.[pid].c"
+    set getloadavg_exe "$tmpdir/getloadavg.exe"
+    set f [open $src "w"]
+    puts $f {
+	#include <stdlib.h>
+	#include <stdio.h>
+
+	int main (int argc, char *argv[])
+	{
+	  double load;
+	  if (getloadavg (&load, 1) == -1)
+	    return -1;
+
+	  printf ("%f", load);
+	  return 0;
+	}
+    }
+    close $f
+
+    # Temporarily switch to the environment for the host compiler.
+    #restore_ld_library_path_env_vars
+    set cc "$HOSTCC $HOSTCFLAGS $TEST_ALWAYS_FLAGS -O2"
+    set status [remote_exec host "$cc -O2 -o $getloadavg_exe  $src"]
+    #set_ld_library_path_env_vars
+    file delete $src
+    if [lindex $status 0] {
+	verbose "Failed to build $src, will not attempt to enforce CPU load limit." 0
+        unset getloadavg_exe
+    }
+    verbose "$getloadavg_exe and appears to be working..." 0
+}
+
+#
+# check_cpu_load -- If make was passed --load-average and and libc supports
+#		    getloadavg, then check CPU load and regulate job execution.
+#
+
+proc check_cpu_load {} {
+    global num_jobs load_max getloadavg_exe load_last_checked
+    
+    # Only recheck CPU load every 4 seconds.
+    set now [clock seconds]
+    if {[info exists load_last_checked] && \
+			$now < [expr {$load_last_checked + 4}]} then {
+	return;
+    }
+    set load_last_checked $now
+    set jobno [getenv GCC_RUNTEST_JOBNO]
+    
+    # First job always runs
+    if {$jobno == 0 || $jobno == ""} then {
+	return
+    }
+
+    set sleep_time [expr {rand() * 8 * $jobno / $num_jobs + 1}]
+    while true {
+        set status [remote_exec host "$getloadavg_exe"]
+        if [lindex $status 0]  {
+	    warning "$getloadavg_exe failed, disabling CPU load limit."
+            unset getloadavg_exe
+            unset check_cpu_load
+            proc check_cpu_load {} {
+            }
+            return
+        }
+        set load [lindex $status 1]
+
+	# Allow lower job numbers slightly more tollerance of over loading.
+        # This avoids a feast and famine cycle of bouncing between all jobs
+        # running and all jobs sleeping.
+        set tollerance [expr {0.75 - 0.75 * $jobno / $num_jobs}]        
+        
+        if { $load <= [expr {$load_max + $tollerance}] } then {
+	    return
+        }
+
+        sleep $sleep_time
+    }
+}
+
 #
 # runtest_file_p -- Provide a definition for older dejagnu releases
 # 		    and assume the old syntax: foo1.exp bar1.c foo2.exp bar2.c.
@@ -205,6 +308,7 @@ if { [info exists env(GCC_RUNTEST_PARALLELIZE_DIR)] \
 
 	set path $gcc_runtest_parallelize_dir/$gcc_runtest_parallelize_counter
 
+	check_cpu_load
 	if {![catch {open $path {RDWR CREAT EXCL} 0600} fd]} {
 	    close $fd
 	    set gcc_runtest_parallelize_last 1

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]