diff mbox

simulate-thread tweaks and fixes

Message ID 4F47CB30.4070506@redhat.com
State New
Headers show

Commit Message

Andrew MacLeod Feb. 24, 2012, 5:38 p.m. UTC
I've been toying with the simulate-thread framework a bit.  With the 
timeout threshold is back to where it originally was, the spectre of 
huge log files when an infinite loop happens is back.

This patch has the following modifications:

1) An instruction count threshold has been added.
       This will truly prevent infinite loops which were the original 
issue.  If the count reaches the threshold value, the test case fails.   
I've set the current limit to 10,000, which I would expect to be 
sufficient. The highest Ive seen so far is 877, but I'm sure someone 
will find something higher :-).  A testcase can override this value if 
it wishes.  If we encounter targets where this is not high enough, we 
can raise it further.  The main point is to avoid generating 10's of 
gigabytes of log files when a fast machine hits an infinite loop and the 
time based timeout doesnt kick in quickly enough.
   If a test does fail for this reason, the log file will issue a FAIL 
message indicating the instruction count threshold was exceeded.

2) I tweaked the atomic-load-int128.c testcase to avoid an inadvertent 
hostile thread situation that was not intended.

3) The  speculative-store.c testcase had a bug in it where the verify 
function was not returning a value when successful. ThIs resulted in an 
UNSUPPORTED result occasionally because the testcase didn't run far 
enough to indicate GDB had successfully run, yet no FAIL was issued.

4) I lowered the hostile thread threshold by an order of magnitude so 
that if a hostile thread is encountered frequently, it wont rapidly 
approach the new instruction count threshold.  This could happen on 
compare_and_swap loop targets.

I've tried this on x86_64-unknown-linux-gnu and everything seems good.   
If anyone wants to try it on their more stressed arch, all you need to 
do is apply the patch to the testsuite and run 'make check-gcc 
RUNTESTFLAGS=simulate-thread.exp' to see if the results are as expected.

OK for mainline?

Andrew

Comments

Jack Howarth Feb. 24, 2012, 6:33 p.m. UTC | #1
On Fri, Feb 24, 2012 at 12:38:56PM -0500, Andrew MacLeod wrote:
> I've been toying with the simulate-thread framework a bit.  With the  
> timeout threshold is back to where it originally was, the spectre of  
> huge log files when an infinite loop happens is back.
>
> This patch has the following modifications:
>
> 1) An instruction count threshold has been added.
>       This will truly prevent infinite loops which were the original  
> issue.  If the count reaches the threshold value, the test case fails.    
> I've set the current limit to 10,000, which I would expect to be  
> sufficient. The highest Ive seen so far is 877, but I'm sure someone  
> will find something higher :-).  A testcase can override this value if  
> it wishes.  If we encounter targets where this is not high enough, we  
> can raise it further.  The main point is to avoid generating 10's of  
> gigabytes of log files when a fast machine hits an infinite loop and the  
> time based timeout doesnt kick in quickly enough.
>   If a test does fail for this reason, the log file will issue a FAIL  
> message indicating the instruction count threshold was exceeded.
>
> 2) I tweaked the atomic-load-int128.c testcase to avoid an inadvertent  
> hostile thread situation that was not intended.
>
> 3) The  speculative-store.c testcase had a bug in it where the verify  
> function was not returning a value when successful. ThIs resulted in an  
> UNSUPPORTED result occasionally because the testcase didn't run far  
> enough to indicate GDB had successfully run, yet no FAIL was issued.
>
> 4) I lowered the hostile thread threshold by an order of magnitude so  
> that if a hostile thread is encountered frequently, it wont rapidly  
> approach the new instruction count threshold.  This could happen on  
> compare_and_swap loop targets.
>
> I've tried this on x86_64-unknown-linux-gnu and everything seems good.    
> If anyone wants to try it on their more stressed arch, all you need to  
> do is apply the patch to the testsuite and run 'make check-gcc  
> RUNTESTFLAGS=simulate-thread.exp' to see if the results are as expected.

Andrew,
    Works fine on x86_64 darwin when applied to curren gcc trunk...

Native configuration is x86_64-apple-darwin11.3.0

		=== gcc tests ===

Schedule of variations:
    unix/-m32
    unix/-m64

Running target unix/-m32
Using /sw/share/dejagnu/baseboards/unix.exp as board description file for target.
Using /sw/share/dejagnu/config/unix.exp as generic interface file for target.
Using /sw/src/fink.build/gcc47-4.7.0-1/gcc-4.7-20120224/gcc/testsuite/config/default.exp as tool-and-target-specific interface file.
Running /sw/src/fink.build/gcc47-4.7.0-1/gcc-4.7-20120224/gcc/testsuite/gcc.dg/simulate-thread/simulate-thread.exp ...

		=== gcc Summary for unix/-m32 ===

# of expected passes		76
# of unsupported tests		8
Running target unix/-m64
Using /sw/share/dejagnu/baseboards/unix.exp as board description file for target.
Using /sw/share/dejagnu/config/unix.exp as generic interface file for target.
Using /sw/src/fink.build/gcc47-4.7.0-1/gcc-4.7-20120224/gcc/testsuite/config/default.exp as tool-and-target-specific interface file.
Running /sw/src/fink.build/gcc47-4.7.0-1/gcc-4.7-20120224/gcc/testsuite/gcc.dg/simulate-thread/simulate-thread.exp ...

		=== gcc Summary for unix/-m64 ===

# of expected passes		88
# of unsupported tests		2

		=== gcc Summary ===

# of expected passes		164
# of unsupported tests		10
/sw/src/fink.build/gcc47-4.7.0-1/darwin_objdir/gcc/xgcc  version 4.7.0 20120224 (experimental) (GCC

>
> OK for mainline?
>
> Andrew
>
>
>
>

> 
> 	* gcc.dg/simulate-thread/simulate-thread.gdb: Use return value from
> 	simulate_thread_wrapper_other_threads
> 	* gcc.dg/simulate-thread/atomic-load-int128.c (simulate_thread_main):
> 	Move initialization of 'value' to main().
> 	(main): Initialize 'value';
> 	* gcc.dg/simulate-thread/speculative-store.c
> 	(simulate_thread_step_verify): Return 0 when successful.
> 	* gcc.dg/simulate-thread/simulate-thread.h (HOSTILE_THREAD_THRESHOLD):
> 	Reduce threshold.
> 	(INSN_COUNT_THRESHOLD): New.  Instruction limit to terminate test.
> 	(simulate_thread_wrapper_other_threads): Return a success/fail value
> 	and issue an error if the instruction count threshold is exceeded.
> 
> Index: testsuite/gcc.dg/simulate-thread/simulate-thread.gdb
> ===================================================================
> *** testsuite/gcc.dg/simulate-thread/simulate-thread.gdb	(revision 184447)
> --- testsuite/gcc.dg/simulate-thread/simulate-thread.gdb	(working copy)
> *************** run
> *** 5,11 ****
>   
>   set $ret = 0
>   while (simulate_thread_fini != 1) && (! $ret)
> !   call simulate_thread_wrapper_other_threads()
>     stepi
>     set $ret |= simulate_thread_step_verify()
>   end
> --- 5,11 ----
>   
>   set $ret = 0
>   while (simulate_thread_fini != 1) && (! $ret)
> !   set $ret |= simulate_thread_wrapper_other_threads()
>     stepi
>     set $ret |= simulate_thread_step_verify()
>   end
> Index: testsuite/gcc.dg/simulate-thread/atomic-load-int128.c
> ===================================================================
> *** testsuite/gcc.dg/simulate-thread/atomic-load-int128.c	(revision 184447)
> --- testsuite/gcc.dg/simulate-thread/atomic-load-int128.c	(working copy)
> *************** void simulate_thread_main()
> *** 105,113 ****
>   {
>     int x;
>   
> -   /* Make sure value starts with an atomic value now.  */
> -   __atomic_store_n (&value, ret, __ATOMIC_SEQ_CST);
> - 
>     /* Execute loads with value changing at various cyclic values.  */
>     for (table_cycle_size = 16; table_cycle_size > 4 ; table_cycle_size--)
>       {
> --- 105,110 ----
> *************** void simulate_thread_main()
> *** 126,131 ****
> --- 123,132 ----
>   main()
>   {
>     fill_table ();
> + 
> +   /* Make sure value starts with an atomic value from the table.  */
> +   __atomic_store_n (&value, table[0], __ATOMIC_SEQ_CST);
> + 
>     simulate_thread_main ();
>     simulate_thread_done ();
>     return 0;
> Index: testsuite/gcc.dg/simulate-thread/speculative-store.c
> ===================================================================
> *** testsuite/gcc.dg/simulate-thread/speculative-store.c	(revision 184447)
> --- testsuite/gcc.dg/simulate-thread/speculative-store.c	(working copy)
> *************** int simulate_thread_step_verify()
> *** 24,29 ****
> --- 24,30 ----
>         printf("FAIL: global variable was assigned to.  \n");
>         return 1;
>       }
> +   return 0;
>   }
>   
>   int simulate_thread_final_verify()
> Index: testsuite/gcc.dg/simulate-thread/simulate-thread.h
> ===================================================================
> *** testsuite/gcc.dg/simulate-thread/simulate-thread.h	(revision 184447)
> --- testsuite/gcc.dg/simulate-thread/simulate-thread.h	(working copy)
> *************** simulate_thread_done ()
> *** 37,43 ****
>      infinite loop to be avoided.
>   
>      If the testcase defines HOSTILE_PAUSE_ERROR, then it will be
> !    considered an RUNTIME FAILURE if the hostile pause is triggered.
>      This will allow to test for guaranteed forward progress routines.
>   
>      If the default values for HOSTILE_THREAD_THRESHOLD or
> --- 37,43 ----
>      infinite loop to be avoided.
>   
>      If the testcase defines HOSTILE_PAUSE_ERROR, then it will be
> !    considered a RUNTIME FAILURE if the hostile pause is triggered.
>      This will allow to test for guaranteed forward progress routines.
>   
>      If the default values for HOSTILE_THREAD_THRESHOLD or
> *************** simulate_thread_done ()
> *** 50,66 ****
>      hostile condition is interferring.  */
>   
>     
> ! /* Define the threshold to start pausing the hostile thread.  */
>   #if !defined (HOSTILE_THREAD_THRESHOLD)
> ! #define HOSTILE_THREAD_THRESHOLD 	500
>   #endif
>   
>   /* Define the length of pause in cycles for the hostile thread to pause to
> !    allow forward progress to be made.  */
>   #if !defined (HOSTILE_THREAD_PAUSE)
>   #define HOSTILE_THREAD_PAUSE	20
>   #endif
>   
>   void simulate_thread_other_threads (void);
>   int simulate_thread_final_verify (void);
>   
> --- 50,78 ----
>      hostile condition is interferring.  */
>   
>     
> ! /* Define the threshold instruction count to start pausing the hostile 
> !    thread.  To avoid huge potential log files when things are not going well,
> !    set this number very low.  If a test specifically requires that the forward
> !    progress guarantee is made, this number should be raised by the testcase. */
>   #if !defined (HOSTILE_THREAD_THRESHOLD)
> ! #define HOSTILE_THREAD_THRESHOLD 	50
>   #endif
>   
>   /* Define the length of pause in cycles for the hostile thread to pause to
> !    allow forward progress to be made.  If this number is too low, a 
> !    compare_and_swap loop may not have time to finish, especially on a
> !    128 bit operation. */
>   #if !defined (HOSTILE_THREAD_PAUSE)
>   #define HOSTILE_THREAD_PAUSE	20
>   #endif
>   
> + /* Define the number of instructions which are allowed to be executed before
> +    the testcase is deemed to fail.  This is primarily to avoid huge log files
> +    when a testcase goes into an infinte loop.  */
> + #if !defined (INSN_COUNT_THRESHOLD)
> + #define INSN_COUNT_THRESHOLD	10000
> + #endif
> + 
>   void simulate_thread_other_threads (void);
>   int simulate_thread_final_verify (void);
>   
> *************** static int simulate_thread_hostile_pause
> *** 71,96 ****
>      is reached, the other_thread process is paused for
>      HOSTILE_THREAD_PAUSE cycles before resuming, and the counters start
>      again.  */
> ! void
>   simulate_thread_wrapper_other_threads()
>   {
> !   static int count = 0;
> !   static int pause = 0;
>   
> !   if (++count >= HOSTILE_THREAD_THRESHOLD)
>       {
>         if (!simulate_thread_hostile_pause)
>           simulate_thread_hostile_pause = 1;
>   
>         /* Count cycles before calling the hostile thread again.  */
> !       if (pause++ < HOSTILE_THREAD_PAUSE)
> ! 	return;
>   
>         /* Reset the pause counter, as well as the thread counter.  */
> !       pause = 0;
> !       count = 0;
>       }
>     simulate_thread_other_threads ();
>   }
>   
>   
> --- 83,116 ----
>      is reached, the other_thread process is paused for
>      HOSTILE_THREAD_PAUSE cycles before resuming, and the counters start
>      again.  */
> ! int
>   simulate_thread_wrapper_other_threads()
>   {
> !   static int insn_count = 0;
> !   static int hostile_count = 0;
> !   static int hostile_pause = 0;
> ! 
> !   if (++insn_count >= INSN_COUNT_THRESHOLD)
> !     {
> !       printf ("FAIL: Testcase exceeded maximum instruction count threshold\n");
> !       return 1;
> !     }
>   
> !   if (++hostile_count >= HOSTILE_THREAD_THRESHOLD)
>       {
>         if (!simulate_thread_hostile_pause)
>           simulate_thread_hostile_pause = 1;
>   
>         /* Count cycles before calling the hostile thread again.  */
> !       if (hostile_pause++ < HOSTILE_THREAD_PAUSE)
> ! 	return 0;
>   
>         /* Reset the pause counter, as well as the thread counter.  */
> !       hostile_pause = 0;
> !       hostile_count = 0;
>       }
>     simulate_thread_other_threads ();
> +   return 0;
>   }
>   
>
Mike Stump Feb. 24, 2012, 7:10 p.m. UTC | #2
On Feb 24, 2012, at 9:38 AM, Andrew MacLeod wrote:
> I've been toying with the simulate-thread framework a bit.

> OK for mainline?

Ok.

Don't know why you ask...  I'd ask you if I wanted to make a change to the file...  Anyway, I reviewed it, and didn't spot anything bad.
Andrew MacLeod Feb. 24, 2012, 7:14 p.m. UTC | #3
On 02/24/2012 02:10 PM, Mike Stump wrote:
> On Feb 24, 2012, at 9:38 AM, Andrew MacLeod wrote:
>> I've been toying with the simulate-thread framework a bit.
>> OK for mainline?
> Ok.
>
> Don't know why you ask...  I'd ask you if I wanted to make a change to the file...  Anyway, I reviewed it, and didn't spot anything bad.
Just dotting my i's :-)   I figured I'd give anyone who had issues 
earlier with these tests a bit of a chance to make sure it works if they 
wanted :-)

Thanks.
Andrew
diff mbox

Patch


	* gcc.dg/simulate-thread/simulate-thread.gdb: Use return value from
	simulate_thread_wrapper_other_threads
	* gcc.dg/simulate-thread/atomic-load-int128.c (simulate_thread_main):
	Move initialization of 'value' to main().
	(main): Initialize 'value';
	* gcc.dg/simulate-thread/speculative-store.c
	(simulate_thread_step_verify): Return 0 when successful.
	* gcc.dg/simulate-thread/simulate-thread.h (HOSTILE_THREAD_THRESHOLD):
	Reduce threshold.
	(INSN_COUNT_THRESHOLD): New.  Instruction limit to terminate test.
	(simulate_thread_wrapper_other_threads): Return a success/fail value
	and issue an error if the instruction count threshold is exceeded.

Index: testsuite/gcc.dg/simulate-thread/simulate-thread.gdb
===================================================================
*** testsuite/gcc.dg/simulate-thread/simulate-thread.gdb	(revision 184447)
--- testsuite/gcc.dg/simulate-thread/simulate-thread.gdb	(working copy)
*************** run
*** 5,11 ****
  
  set $ret = 0
  while (simulate_thread_fini != 1) && (! $ret)
!   call simulate_thread_wrapper_other_threads()
    stepi
    set $ret |= simulate_thread_step_verify()
  end
--- 5,11 ----
  
  set $ret = 0
  while (simulate_thread_fini != 1) && (! $ret)
!   set $ret |= simulate_thread_wrapper_other_threads()
    stepi
    set $ret |= simulate_thread_step_verify()
  end
Index: testsuite/gcc.dg/simulate-thread/atomic-load-int128.c
===================================================================
*** testsuite/gcc.dg/simulate-thread/atomic-load-int128.c	(revision 184447)
--- testsuite/gcc.dg/simulate-thread/atomic-load-int128.c	(working copy)
*************** void simulate_thread_main()
*** 105,113 ****
  {
    int x;
  
-   /* Make sure value starts with an atomic value now.  */
-   __atomic_store_n (&value, ret, __ATOMIC_SEQ_CST);
- 
    /* Execute loads with value changing at various cyclic values.  */
    for (table_cycle_size = 16; table_cycle_size > 4 ; table_cycle_size--)
      {
--- 105,110 ----
*************** void simulate_thread_main()
*** 126,131 ****
--- 123,132 ----
  main()
  {
    fill_table ();
+ 
+   /* Make sure value starts with an atomic value from the table.  */
+   __atomic_store_n (&value, table[0], __ATOMIC_SEQ_CST);
+ 
    simulate_thread_main ();
    simulate_thread_done ();
    return 0;
Index: testsuite/gcc.dg/simulate-thread/speculative-store.c
===================================================================
*** testsuite/gcc.dg/simulate-thread/speculative-store.c	(revision 184447)
--- testsuite/gcc.dg/simulate-thread/speculative-store.c	(working copy)
*************** int simulate_thread_step_verify()
*** 24,29 ****
--- 24,30 ----
        printf("FAIL: global variable was assigned to.  \n");
        return 1;
      }
+   return 0;
  }
  
  int simulate_thread_final_verify()
Index: testsuite/gcc.dg/simulate-thread/simulate-thread.h
===================================================================
*** testsuite/gcc.dg/simulate-thread/simulate-thread.h	(revision 184447)
--- testsuite/gcc.dg/simulate-thread/simulate-thread.h	(working copy)
*************** simulate_thread_done ()
*** 37,43 ****
     infinite loop to be avoided.
  
     If the testcase defines HOSTILE_PAUSE_ERROR, then it will be
!    considered an RUNTIME FAILURE if the hostile pause is triggered.
     This will allow to test for guaranteed forward progress routines.
  
     If the default values for HOSTILE_THREAD_THRESHOLD or
--- 37,43 ----
     infinite loop to be avoided.
  
     If the testcase defines HOSTILE_PAUSE_ERROR, then it will be
!    considered a RUNTIME FAILURE if the hostile pause is triggered.
     This will allow to test for guaranteed forward progress routines.
  
     If the default values for HOSTILE_THREAD_THRESHOLD or
*************** simulate_thread_done ()
*** 50,66 ****
     hostile condition is interferring.  */
  
    
! /* Define the threshold to start pausing the hostile thread.  */
  #if !defined (HOSTILE_THREAD_THRESHOLD)
! #define HOSTILE_THREAD_THRESHOLD 	500
  #endif
  
  /* Define the length of pause in cycles for the hostile thread to pause to
!    allow forward progress to be made.  */
  #if !defined (HOSTILE_THREAD_PAUSE)
  #define HOSTILE_THREAD_PAUSE	20
  #endif
  
  void simulate_thread_other_threads (void);
  int simulate_thread_final_verify (void);
  
--- 50,78 ----
     hostile condition is interferring.  */
  
    
! /* Define the threshold instruction count to start pausing the hostile 
!    thread.  To avoid huge potential log files when things are not going well,
!    set this number very low.  If a test specifically requires that the forward
!    progress guarantee is made, this number should be raised by the testcase. */
  #if !defined (HOSTILE_THREAD_THRESHOLD)
! #define HOSTILE_THREAD_THRESHOLD 	50
  #endif
  
  /* Define the length of pause in cycles for the hostile thread to pause to
!    allow forward progress to be made.  If this number is too low, a 
!    compare_and_swap loop may not have time to finish, especially on a
!    128 bit operation. */
  #if !defined (HOSTILE_THREAD_PAUSE)
  #define HOSTILE_THREAD_PAUSE	20
  #endif
  
+ /* Define the number of instructions which are allowed to be executed before
+    the testcase is deemed to fail.  This is primarily to avoid huge log files
+    when a testcase goes into an infinte loop.  */
+ #if !defined (INSN_COUNT_THRESHOLD)
+ #define INSN_COUNT_THRESHOLD	10000
+ #endif
+ 
  void simulate_thread_other_threads (void);
  int simulate_thread_final_verify (void);
  
*************** static int simulate_thread_hostile_pause
*** 71,96 ****
     is reached, the other_thread process is paused for
     HOSTILE_THREAD_PAUSE cycles before resuming, and the counters start
     again.  */
! void
  simulate_thread_wrapper_other_threads()
  {
!   static int count = 0;
!   static int pause = 0;
  
!   if (++count >= HOSTILE_THREAD_THRESHOLD)
      {
        if (!simulate_thread_hostile_pause)
          simulate_thread_hostile_pause = 1;
  
        /* Count cycles before calling the hostile thread again.  */
!       if (pause++ < HOSTILE_THREAD_PAUSE)
! 	return;
  
        /* Reset the pause counter, as well as the thread counter.  */
!       pause = 0;
!       count = 0;
      }
    simulate_thread_other_threads ();
  }
  
  
--- 83,116 ----
     is reached, the other_thread process is paused for
     HOSTILE_THREAD_PAUSE cycles before resuming, and the counters start
     again.  */
! int
  simulate_thread_wrapper_other_threads()
  {
!   static int insn_count = 0;
!   static int hostile_count = 0;
!   static int hostile_pause = 0;
! 
!   if (++insn_count >= INSN_COUNT_THRESHOLD)
!     {
!       printf ("FAIL: Testcase exceeded maximum instruction count threshold\n");
!       return 1;
!     }
  
!   if (++hostile_count >= HOSTILE_THREAD_THRESHOLD)
      {
        if (!simulate_thread_hostile_pause)
          simulate_thread_hostile_pause = 1;
  
        /* Count cycles before calling the hostile thread again.  */
!       if (hostile_pause++ < HOSTILE_THREAD_PAUSE)
! 	return 0;
  
        /* Reset the pause counter, as well as the thread counter.  */
!       hostile_pause = 0;
!       hostile_count = 0;
      }
    simulate_thread_other_threads ();
+   return 0;
  }