<commit_before>diff --git a/src/kmp.h b/src/kmp.h
index 4e7dec0..8e675fd 100644
--- a/src/kmp.h
+++ b/src/kmp.h
@@ -273,7 +273,8 @@ enum dynamic_mode {
 #endif /* USE_LOAD_BALANCE */
     dynamic_random,
     dynamic_thread_limit,
-    dynamic_max
+    dynamic_max,
+    dynamic_scaf
 };
 
 /* external schedule constants, duplicate enum omp_sched in omp.h in order to not include it here */
diff --git a/src/kmp_csupport.c b/src/kmp_csupport.c
index 0fcf09b..64801c0 100644
--- a/src/kmp_csupport.c
+++ b/src/kmp_csupport.c
@@ -40,6 +40,12 @@
 #include "kmp_itt.h"
 #include "kmp_error.h"
 
+extern "C"
+{
+#include <scaf.h>
+}
+extern int scaf_last_allocation;
+
 #define MAX_MESSAGE 512
 
 /* ------------------------------------------------------------------------ */
@@ -301,6 +307,56 @@ __kmpc_fork_call(ident_t *loc, kmp_int32 argc, kmpc_micro microtask, ...)
     va_list     ap;
     va_start(   ap, microtask );
 
+    //SCAF: set up an ad-hoc structure to convert our functor to accept a
+    //single void pointer argument
+    struct squishedargs {
+      int argc;
+      void **args;
+      microtask_t microtask;
+      int gtid;
+      ident_t *loc;
+    };
+
+    //SCAF: collect arguments for the section/task itself
+    void* args[argc];
+    {
+       va_list ap_l;
+       va_start(ap_l, microtask);
+       void** argv = args;
+       int i;
+       for( i=argc-1; i >= 0; --i )
+          *argv++ = va_arg( ap_l, void * );
+    }
+
+    //SCAF: store all arguments for the functor into a single blob
+    struct squishedargs funcdata;
+    funcdata.argc = argc;
+    funcdata.args = args;
+    funcdata.microtask = microtask;
+    funcdata.gtid = gtid;
+    funcdata.loc = loc;
+
+    //SCAF: now describe a functor for passing to libscaf, which will
+    //eventually run the serialized section as local::serialexecute(&funcdata).
+    //Note that the entire experimental process will always just stop after
+    //this runs, so we needn't make any attempt to clean up afterward.
+    struct local
+    {
+       static void serialexecute(void *data){
+          struct squishedargs *fd = (struct squishedargs*)data;
+          __kmpc_serialized_parallel(fd->loc, fd->gtid);
+          __kmp_invoke_microtask(fd->microtask, fd->gtid, 0, fd->argc, fd->args);
+       }
+    };
+
+    //SCAF: Just to be clear, collect our usual fn, data pair.
+    void (*fn) (void*) = local::serialexecute;
+    void *data = &funcdata;
+
+    //SCAF: Re-using the GOMP port's create function, launch the experiment.
+    scaf_last_allocation = scaf_section_start((void*)microtask);
+    scaf_gomp_training_create(fn, data);
+
     __kmp_fork_call( loc, gtid, TRUE,
             argc,
             VOLATILE_CAST(microtask_t) microtask,
@@ -314,6 +370,11 @@ __kmpc_fork_call(ident_t *loc, kmp_int32 argc, kmpc_micro microtask, ...)
             );
     __kmp_join_call( loc, gtid );
 
+    //SCAF: Record the section as ended and collect experiment results if
+    //necessary.
+    scaf_section_end();
+    scaf_gomp_training_destroy();
+
     va_end( ap );
   }
 }
diff --git a/src/kmp_runtime.c b/src/kmp_runtime.c
index 659fe76..9145a76 100644
--- a/src/kmp_runtime.c
+++ b/src/kmp_runtime.c
@@ -45,6 +45,12 @@
 #include "kmp_io.h"
 #include "kmp_error.h"
 
+extern "C"
+{
+#include <scaf.h>
+}
+int scaf_last_allocation = 0;
+
 /* these are temporary issues to be dealt with */
 #define KMP_USE_PRCTL 0
 #define KMP_USE_POOLED_ALLOC 0
@@ -2152,7 +2158,7 @@ __kmp_end_split_barrier( enum barrier_type bt, int gtid )
  */
 static int
 __kmp_reserve_threads( kmp_root_t *root, kmp_team_t *parent_team,
-   int master_tid, int set_nthreads
+   int master_tid, int set_nthreads, microtask_t microtask
 #if OMP_40_ENABLED
   , int enter_teams
 #endif /* OMP_40_ENABLED */
@@ -2236,6 +2242,23 @@ __kmp_reserve_threads( kmp_root_t *root, kmp_team_t *parent_team,
             }
         }
     }
+    else if ( __kmp_global.g.g_dynamic_mode == dynamic_scaf ) {
+        new_nthreads = scaf_last_allocation - __kmp_nth + (root->r.r_active ? 1
+          : root->r.r_hot_team->t.t_nproc);
+        if ( new_nthreads <= 1 ) {
+            KC_TRACE( 10, ( "__kmp_reserve_threads: T#%d thread limit reduced reservation to 1 thread\n",
+              master_tid ));
+            return 1;
+        }
+        if ( new_nthreads < set_nthreads ) {
+            KC_TRACE( 10, ( "__kmp_reserve_threads: T#%d thread limit reduced reservation to %d threads\n",
+              master_tid, new_nthreads ));
+        }
+        else if ( new_nthreads > set_nthreads ) {
+            KC_TRACE( 10, ( "__kmp_reserve_threads: T#%d thread limit increased reservation to %d threads\n",
+              master_tid, new_nthreads ));
+        }
+    }
     else {
         KMP_ASSERT( 0 );
     }
@@ -2567,7 +2590,7 @@ __kmp_fork_call(
     {
         nthreads = master_set_numthreads ?
             master_set_numthreads : get__nproc_2( parent_team, master_tid );
-        nthreads = __kmp_reserve_threads( root, parent_team, master_tid, nthreads
+        nthreads = __kmp_reserve_threads( root, parent_team, master_tid, nthreads, microtask
 #if OMP_40_ENABLED
         // AC: If we execute teams from parallel region (on host), then teams
         //     should be created but each can only have 1 thread if nesting is disabled.
diff --git a/src/kmp_settings.c b/src/kmp_settings.c
index 40c0499..00788d4 100644
--- a/src/kmp_settings.c
+++ b/src/kmp_settings.c
@@ -3357,6 +3357,9 @@ __kmp_stg_parse_kmp_dynamic_mode( char const * name, char const * value, void *
     else if ( __kmp_str_match( "random", 1, value ) ) {
         __kmp_global.g.g_dynamic_mode = dynamic_random;
     }
+    else if ( __kmp_str_match( "scaf", 0, value ) ) {
+        __kmp_global.g.g_dynamic_mode = dynamic_scaf;
+    }
     else {
         KMP_WARNING( StgInvalidValue, name, value );
     }
<commit_msg>update libiomp patch to call scaf_not_malleable()<commit_after>diff --git a/src/kmp.h b/src/kmp.h
index 4e7dec0..8e675fd 100644
--- a/src/kmp.h
+++ b/src/kmp.h
@@ -273,7 +273,8 @@ enum dynamic_mode {
 #endif /* USE_LOAD_BALANCE */
     dynamic_random,
     dynamic_thread_limit,
-    dynamic_max
+    dynamic_max,
+    dynamic_scaf
 };
 
 /* external schedule constants, duplicate enum omp_sched in omp.h in order to not include it here */
diff --git a/src/kmp_csupport.c b/src/kmp_csupport.c
index 0fcf09b..cfb9c19 100644
--- a/src/kmp_csupport.c
+++ b/src/kmp_csupport.c
@@ -40,6 +40,12 @@
 #include "kmp_itt.h"
 #include "kmp_error.h"
 
+extern "C"
+{
+#include <scaf.h>
+}
+extern int scaf_last_allocation;
+
 #define MAX_MESSAGE 512
 
 /* ------------------------------------------------------------------------ */
@@ -301,6 +307,56 @@ __kmpc_fork_call(ident_t *loc, kmp_int32 argc, kmpc_micro microtask, ...)
     va_list     ap;
     va_start(   ap, microtask );
 
+    //SCAF: set up an ad-hoc structure to convert our functor to accept a
+    //single void pointer argument
+    struct squishedargs {
+      int argc;
+      void **args;
+      microtask_t microtask;
+      int gtid;
+      ident_t *loc;
+    };
+
+    //SCAF: collect arguments for the section/task itself
+    void* args[argc];
+    {
+       va_list ap_l;
+       va_start(ap_l, microtask);
+       void** argv = args;
+       int i;
+       for( i=argc-1; i >= 0; --i )
+          *argv++ = va_arg( ap_l, void * );
+    }
+
+    //SCAF: store all arguments for the functor into a single blob
+    struct squishedargs funcdata;
+    funcdata.argc = argc;
+    funcdata.args = args;
+    funcdata.microtask = microtask;
+    funcdata.gtid = gtid;
+    funcdata.loc = loc;
+
+    //SCAF: now describe a functor for passing to libscaf, which will
+    //eventually run the serialized section as local::serialexecute(&funcdata).
+    //Note that the entire experimental process will always just stop after
+    //this runs, so we needn't make any attempt to clean up afterward.
+    struct local
+    {
+       static void serialexecute(void *data){
+          struct squishedargs *fd = (struct squishedargs*)data;
+          __kmpc_serialized_parallel(fd->loc, fd->gtid);
+          __kmp_invoke_microtask(fd->microtask, fd->gtid, 0, fd->argc, fd->args);
+       }
+    };
+
+    //SCAF: Just to be clear, collect our usual fn, data pair.
+    void (*fn) (void*) = local::serialexecute;
+    void *data = &funcdata;
+
+    //SCAF: Re-using the GOMP port's create function, launch the experiment.
+    scaf_last_allocation = scaf_section_start((void*)microtask);
+    scaf_gomp_training_create(fn, data);
+
     __kmp_fork_call( loc, gtid, TRUE,
             argc,
             VOLATILE_CAST(microtask_t) microtask,
@@ -314,6 +370,11 @@ __kmpc_fork_call(ident_t *loc, kmp_int32 argc, kmpc_micro microtask, ...)
             );
     __kmp_join_call( loc, gtid );
 
+    //SCAF: Record the section as ended and collect experiment results if
+    //necessary.
+    scaf_section_end();
+    scaf_gomp_training_destroy();
+
     va_end( ap );
   }
 }
@@ -1343,6 +1404,8 @@ ompc_set_dynamic( int flag )
 
     __kmp_save_internal_controls( thread );
 
+    if(!flag && __kmp_global.g.g_dynamic_mode == dynamic_scaf)
+       scaf_not_malleable();
     set__dynamic( thread, flag ? TRUE : FALSE );
 }
 
diff --git a/src/kmp_ftn_entry.h b/src/kmp_ftn_entry.h
index e7827bf..431cbbf 100644
--- a/src/kmp_ftn_entry.h
+++ b/src/kmp_ftn_entry.h
@@ -44,6 +44,11 @@
 
 #include "kmp_i18n.h"
 
+extern "C"
+{
+#include <scaf.h>
+}
+
 #ifdef __cplusplus
     extern "C" {
 #endif // __cplusplus
@@ -530,6 +535,8 @@ xexpand(FTN_SET_DYNAMIC)( int KMP_DEREF flag )
         __kmp_save_internal_controls( thread );
         set__dynamic( thread, KMP_DEREF flag ? TRUE : FALSE );
     #endif
+        if(!(KMP_DEREF flag) && __kmp_global.g.g_dynamic_mode == dynamic_scaf)
+           scaf_not_malleable();
 }
 
 
diff --git a/src/kmp_runtime.c b/src/kmp_runtime.c
index 659fe76..9145a76 100644
--- a/src/kmp_runtime.c
+++ b/src/kmp_runtime.c
@@ -45,6 +45,12 @@
 #include "kmp_io.h"
 #include "kmp_error.h"
 
+extern "C"
+{
+#include <scaf.h>
+}
+int scaf_last_allocation = 0;
+
 /* these are temporary issues to be dealt with */
 #define KMP_USE_PRCTL 0
 #define KMP_USE_POOLED_ALLOC 0
@@ -2152,7 +2158,7 @@ __kmp_end_split_barrier( enum barrier_type bt, int gtid )
  */
 static int
 __kmp_reserve_threads( kmp_root_t *root, kmp_team_t *parent_team,
-   int master_tid, int set_nthreads
+   int master_tid, int set_nthreads, microtask_t microtask
 #if OMP_40_ENABLED
   , int enter_teams
 #endif /* OMP_40_ENABLED */
@@ -2236,6 +2242,23 @@ __kmp_reserve_threads( kmp_root_t *root, kmp_team_t *parent_team,
             }
         }
     }
+    else if ( __kmp_global.g.g_dynamic_mode == dynamic_scaf ) {
+        new_nthreads = scaf_last_allocation - __kmp_nth + (root->r.r_active ? 1
+          : root->r.r_hot_team->t.t_nproc);
+        if ( new_nthreads <= 1 ) {
+            KC_TRACE( 10, ( "__kmp_reserve_threads: T#%d thread limit reduced reservation to 1 thread\n",
+              master_tid ));
+            return 1;
+        }
+        if ( new_nthreads < set_nthreads ) {
+            KC_TRACE( 10, ( "__kmp_reserve_threads: T#%d thread limit reduced reservation to %d threads\n",
+              master_tid, new_nthreads ));
+        }
+        else if ( new_nthreads > set_nthreads ) {
+            KC_TRACE( 10, ( "__kmp_reserve_threads: T#%d thread limit increased reservation to %d threads\n",
+              master_tid, new_nthreads ));
+        }
+    }
     else {
         KMP_ASSERT( 0 );
     }
@@ -2567,7 +2590,7 @@ __kmp_fork_call(
     {
         nthreads = master_set_numthreads ?
             master_set_numthreads : get__nproc_2( parent_team, master_tid );
-        nthreads = __kmp_reserve_threads( root, parent_team, master_tid, nthreads
+        nthreads = __kmp_reserve_threads( root, parent_team, master_tid, nthreads, microtask
 #if OMP_40_ENABLED
         // AC: If we execute teams from parallel region (on host), then teams
         //     should be created but each can only have 1 thread if nesting is disabled.
diff --git a/src/kmp_settings.c b/src/kmp_settings.c
index 40c0499..1dac6f9 100644
--- a/src/kmp_settings.c
+++ b/src/kmp_settings.c
@@ -44,6 +44,10 @@
 #include "kmp_i18n.h"
 #include "kmp_io.h"
 
+extern "C"
+{
+#include <scaf.h>
+}
 
 static int __kmp_env_isDefined( char const * name );
 static int __kmp_env_toPrint( char const * name, int flag );
@@ -367,6 +371,8 @@ typedef struct __kmp_stg_fr_data    kmp_stg_fr_data_t;
 typedef void ( * kmp_stg_parse_func_t )( char const * name, char const * value, void * data );
 typedef void ( * kmp_stg_print_func_t )( kmp_str_buf_t * buffer, char const * name, void * data );
 
+static kmp_setting_t * __kmp_stg_find( char const * name );
+
 struct __kmp_setting {
     char const *         name;        // Name of setting (environment variable).
     kmp_stg_parse_func_t parse;       // Parser function.
@@ -3357,6 +3363,17 @@ __kmp_stg_parse_kmp_dynamic_mode( char const * name, char const * value, void *
     else if ( __kmp_str_match( "random", 1, value ) ) {
         __kmp_global.g.g_dynamic_mode = dynamic_random;
     }
+    else if ( __kmp_str_match( "scaf", 0, value ) ) {
+        __kmp_global.g.g_dynamic_mode = dynamic_scaf;
+        if(__kmp_stg_find("OMP_DYNAMIC")->set){
+           // If specified to "false", inform the SCAF daemon right away.
+           if(__kmp_global.g.g_dynamic == FALSE)
+              scaf_not_malleable();
+        } else {
+           // Change the default (if unspecified) to "true".
+           __kmp_global.g.g_dynamic = TRUE;
+        }
+    }
     else {
         KMP_WARNING( StgInvalidValue, name, value );
     }

{'fraction_non_alphanumeric': 0.13661601402688486, 'fraction_numerical': 0.029807130333138514, 'mean_word_length': 2.668006430868167, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 32, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1347923', 'n_tokens_mistral': 5358, 'n_tokens_neox': 5027, 'n_words': 1169}