This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
RE: FW: [PATCH] Cilk Keywords (_Cilk_spawn and _Cilk_sync) for C
- From: "Tannenbaum, Barry M" <barry dot m dot tannenbaum at intel dot com>
- To: Thomas Schwinge <thomas at codesourcery dot com>, "Iyer, Balaji V" <balaji dot v dot iyer at intel dot com>, "Zamyatin, Igor" <igor dot zamyatin at intel dot com>
- Cc: "gcc-patches at gcc dot gnu dot org" <gcc-patches at gcc dot gnu dot org>
- Date: Mon, 29 Sep 2014 13:58:31 +0000
- Subject: RE: FW: [PATCH] Cilk Keywords (_Cilk_spawn and _Cilk_sync) for C
- Authentication-results: sourceware.org; auth=none
- References: <BF230D13CA30DD48930C31D4099330003A455EF0 at FMSMSX101 dot amr dot corp dot intel dot com> <52012923 dot 6030409 at redhat dot com> <BF230D13CA30DD48930C31D4099330003A457F85 at FMSMSX101 dot amr dot corp dot intel dot com> <5204C718 dot 9050402 at redhat dot com> <BF230D13CA30DD48930C31D4099330003A458F86 at FMSMSX101 dot amr dot corp dot intel dot com> <5214DD51 dot 9030709 at redhat dot com> <BF230D13CA30DD48930C31D4099330003A45AE69 at FMSMSX101 dot amr dot corp dot intel dot com> <521641C6 dot 6060807 at redhat dot com> <BF230D13CA30DD48930C31D4099330003A45D457 at FMSMSX101 dot amr dot corp dot intel dot com> <87vbof3gji dot fsf at kepler dot schwinge dot homeip dot net> <6B86B7F2A4026246AA81BA1ABF9756905C4FF96C at FMSMSX105 dot amr dot corp dot intel dot com> <8761g6g0je dot fsf at kepler dot schwinge dot homeip dot net>
In a nutshell, add the following code to main() before the call to f3():
int status = __cilkrts_set_param("nworkers", "2");
if (0 != status) {
// Failed to set the number of Cilk workers
return status;
}
Here's the details:
There are three sources of information the Cilk runtime uses to set the number of workers.
1) By default the Cilk runtime will query the operating system for the number of cores and create a worker for each core. Note that the operating system counts each hyperthread as a core.
2) You can set your own default by defining the CILK_NWORKERS environment variable. For example:
export CILK_NWORKERS=2
3) You can override the default programmatically by calling __cilkrts_set_param() before the first spawning function is called. For example, place the following call in main():
__cilkrts_set_param("nworkers", "2");
A "spawning function" is a function that contains a _Cilk_spawn. The Cilk runtime will be initialized the first time a spawning function is executed.
For this test to run correctly you must set the number of workers to at least 2, so the Cilk runtime will create at least one worker thread.
Please note that once the Cilk runtime has been initialized by the entry into the first spawning function, the number of workers cannot be changed (and the __cilkrts_set_param() call will return a non-zero value to indicate an error has occurred.) The first two values are evaluated lazily; the runtime will load its default values the first time one of the __cilkrts APIs defined in cilk_api.h is called [for example __cilkrts_get_nworkers()], or the first spawning function is entered. So for example, the following code will not do what you want:
if (1 == __cilkrts_get_nworkers())
setenv("CILK_NWORKERS=2");
The call to __cilkrts_get_nworkers() will cause the Cilk runtime to set its default. Setting the CILK_NWORKERS environment variable after the __cilkrts_get_nworkers() call will be too late.
It is possible to change the number of workers, but to do that you must return from all spawning functions and then call __cilkrts_end_cilk() to have the Cilk runtime shut down and then call __cilkrts_set_param(). When the Cilk runtime starts at the entry to the next spawning function, it will obey the new setting.
- Barry
-----Original Message-----
From: Thomas Schwinge [mailto:thomas@codesourcery.com]
Sent: Monday, September 29, 2014 6:54 AM
To: Tannenbaum, Barry M; Iyer, Balaji V; Zamyatin, Igor
Cc: gcc-patches@gcc.gnu.org
Subject: RE: FW: [PATCH] Cilk Keywords (_Cilk_spawn and _Cilk_sync) for C
Hi!
On Mon, 22 Sep 2014 19:21:33 +0000, "Tannenbaum, Barry M" <barry.m.tannenbaum@intel.com> wrote:
> That's exactly correct.
>
> There are two ways to implement a work-stealing scheduler. We refer to
> them as: [...]
Thanks for the explanation.
> Cilk implements Parent Stealing. Since you're running with 1 worker, there's no other worker to steal the continuation. So steal_flag will never be set to 1 and you'll never break out of the loop.
Remains the question about how to address that in the testsuite:
> -----Original Message-----
> From: Thomas Schwinge [mailto:thomas@codesourcery.com]
> Sent: Monday, September 22, 2014 9:56 AM
> To: Iyer, Balaji V
> Cc: gcc-patches@gcc.gnu.org
> Subject: Re: FW: [PATCH] Cilk Keywords (_Cilk_spawn and _Cilk_sync)
> for C
>
> Hi!
>
> On Tue, 27 Aug 2013 21:30:49 +0000, "Iyer, Balaji V" <balaji.v.iyer@intel.com> wrote:
> > --- /dev/null
> > +++ gcc/testsuite/c-c++-common/cilk-plus/CK/spawning_arg.c
> > @@ -0,0 +1,37 @@
> > +/* { dg-do run { target { i?86-*-* x86_64-*-* arm*-*-* } } } */
> > +/* { dg-options "-fcilkplus" } */
> > +/* { dg-options "-lcilkrts" { target { i?86-*-* x86_64-*-* arm*-*-*
> > +} } } */
> > +
> > +void f0(volatile int *steal_flag)
> > +{
> > + int i = 0;
> > + /* Wait for steal_flag to be set */
> > + while (!*steal_flag)
> > + ;
> > +}
> > +
> > +int f1()
> > +{
> > +
> > + volatile int steal_flag = 0;
> > + _Cilk_spawn f0(&steal_flag);
> > + steal_flag = 1; // Indicate stolen
> > + _Cilk_sync;
> > + return 0;
> > +}
> > +
> > +void f2(int q)
> > +{
> > + q = 5;
> > +}
> > +
> > +void f3()
> > +{
> > + _Cilk_spawn f2(f1());
> > +}
> > +
> > +int main()
> > +{
> > + f3();
> > + return 0;
> > +}
>
> Is this really well-formed Cilk Plus code? Running with CILK_NWORKERS=1, or -- the equivalent -- in a system with just one CPU (as per libcilkrts/runtime/os-unix.c:__cilkrts_hardware_cpu_count returning 1), I see this test busy-loop as follows:
>
> Breakpoint 1, __cilkrts_hardware_cpu_count () at ../../../source/libcilkrts/runtime/os-unix.c:358
> 358 {
> (gdb) return 1
> Make __cilkrts_hardware_cpu_count return now? (y or n) y
> #0 cilkg_get_user_settable_values () at ../../../source/libcilkrts/runtime/global_state.cpp:385
> 385 CILK_ASSERT(hardware_cpu_count > 0);
> (gdb) c
> Continuing.
> ^C
> Program received signal SIGINT, Interrupt.
> f0 (steal_flag=steal_flag@entry=0x7fffffffd03c) at [...]/source/gcc/testsuite/c-c++-common/cilk-plus/CK/spawning_arg.c:9
> 9 while (!*steal_flag)
> (gdb) info threads
> Id Target Id Frame
> * 1 Thread 0x7ffff7fcd780 (LWP 30816) "spawning_arg.ex" f0 (steal_flag=steal_flag@entry=0x7fffffffd03c) at [...]/source/gcc/testsuite/c-c++-common/cilk-plus/CK/spawning_arg.c:9
> (gdb) list
> 4
> 5 void f0(volatile int *steal_flag)
> 6 {
> 7 int i = 0;
> 8 /* Wait for steal_flag to be set */
> 9 while (!*steal_flag)
> 10 ;
> 11 }
> 12
> 13 int f1()
> (gdb) bt
> #0 f0 (steal_flag=steal_flag@entry=0x7fffffffd03c) at [...]/source/gcc/testsuite/c-c++-common/cilk-plus/CK/spawning_arg.c:9
> #1 0x00000000004009c8 in _cilk_spn_0 () at [...]/source/gcc/testsuite/c-c++-common/cilk-plus/CK/spawning_arg.c:17
> #2 0x0000000000400a4b in f1 () at [...]/source/gcc/testsuite/c-c++-common/cilk-plus/CK/spawning_arg.c:17
> #3 0x0000000000400d0e in _cilk_spn_1 () at [...]/source/gcc/testsuite/c-c++-common/cilk-plus/CK/spawning_arg.c:30
> #4 0x0000000000400d7a in f3 () at [...]/source/gcc/testsuite/c-c++-common/cilk-plus/CK/spawning_arg.c:30
> #5 0x0000000000400e33 in main () at
> [...]/source/gcc/testsuite/c-c++-common/cilk-plus/CK/spawning_arg.c:35
>
> No additional thread has been spawned by libcilkrts, and the one initial thread is stuck in f0, without being able to make progress. Should in f0's while loop, some function be called to "yield to libcilkrts scheduler", or should libcilkrts have spawned an additional thread, or is the test case just not valid Cilk Plus code?
Assuming the test cases are considered well-formed Cilk Plus code, I understand there is then a hard requirement to run them with more than one worker. OK to fix as follows?
commit ee7138e451d1f3284d6fa0f61fe517c82db94060
Author: Thomas Schwinge <thomas@codesourcery.com>
Date: Mon Sep 29 12:47:34 2014 +0200
Audit Cilk Plus tests for CILK_NWORKERS=1.
gcc/testsuite/
* c-c++-common/cilk-plus/CK/spawning_arg.c (main): Call
__cilkrts_set_param to set two workers.
* c-c++-common/cilk-plus/CK/steal_check.c (main): Likewise.
* g++.dg/cilk-plus/CK/catch_exc.cc (main): Likewise.
---
gcc/testsuite/c-c++-common/cilk-plus/CK/spawning_arg.c | 15 +++++++++++++++ gcc/testsuite/c-c++-common/cilk-plus/CK/steal_check.c | 17 ++++++++++++++---
gcc/testsuite/g++.dg/cilk-plus/CK/catch_exc.cc | 14 ++++++++++++++
3 files changed, 43 insertions(+), 3 deletions(-)
diff --git gcc/testsuite/c-c++-common/cilk-plus/CK/spawning_arg.c gcc/testsuite/c-c++-common/cilk-plus/CK/spawning_arg.c
index 95e6cab..138b82c 100644
--- gcc/testsuite/c-c++-common/cilk-plus/CK/spawning_arg.c
+++ gcc/testsuite/c-c++-common/cilk-plus/CK/spawning_arg.c
@@ -2,6 +2,17 @@
/* { dg-options "-fcilkplus" } */
/* { dg-additional-options "-lcilkrts" { target { i?86-*-* x86_64-*-* } } } */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int __cilkrts_set_param (const char *, const char *);
+
+#ifdef __cplusplus
+}
+#endif
+
+
void f0(volatile int *steal_flag)
{
int i = 0;
@@ -32,6 +43,10 @@ void f3()
int main()
{
+ /* Ensure more than one worker. */
+ if (__cilkrts_set_param("nworkers", "2") != 0)
+ __builtin_abort();
+
f3();
return 0;
}
diff --git gcc/testsuite/c-c++-common/cilk-plus/CK/steal_check.c gcc/testsuite/c-c++-common/cilk-plus/CK/steal_check.c
index 6e28765..6b41c7f 100644
--- gcc/testsuite/c-c++-common/cilk-plus/CK/steal_check.c
+++ gcc/testsuite/c-c++-common/cilk-plus/CK/steal_check.c
@@ -2,8 +2,16 @@
/* { dg-options "-fcilkplus" } */
/* { dg-additional-options "-lcilkrts" { target { i?86-*-* x86_64-*-* } } } */
-// #include <cilk/cilk_api.h>
-extern void __cilkrts_set_param (char *, char *);
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int __cilkrts_set_param (const char *, const char *);
+
+#ifdef __cplusplus
+}
+#endif
+
void foo(volatile int *);
@@ -11,7 +19,10 @@ void main2(void);
int main(void)
{
- // __cilkrts_set_param ((char *)"nworkers", (char *)"2");
+ /* Ensure more than one worker. */
+ if (__cilkrts_set_param("nworkers", "2") != 0)
+ __builtin_abort();
+
main2();
return 0;
}
diff --git gcc/testsuite/g++.dg/cilk-plus/CK/catch_exc.cc gcc/testsuite/g++.dg/cilk-plus/CK/catch_exc.cc
index 0633d19..09ddf8b 100644
--- gcc/testsuite/g++.dg/cilk-plus/CK/catch_exc.cc
+++ gcc/testsuite/g++.dg/cilk-plus/CK/catch_exc.cc
@@ -10,6 +10,16 @@
#endif
#include <cstdlib>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int __cilkrts_set_param (const char *, const char *);
+
+#ifdef __cplusplus
+}
+#endif
+
void func(int volatile* steal_me)
{
@@ -59,6 +69,10 @@ void my_test()
int main()
{
+ /* Ensure more than one worker. */
+ if (__cilkrts_set_param("nworkers", "2") != 0)
+ __builtin_abort();
+
my_test();
#if HAVE_IO
printf("PASSED\n");
GrÃÃe,
Thomas