Exemple #1
0
void fun() {
    __cilkrts_ivar* iv = malloc(sizeof(__cilkrts_ivar)); // Presently never freed.
    __cilkrts_ivar_clear(iv);

    printf("   Spawn to write ivar:\n");
    cilk_spawn writer(iv);
    printf("   After spawn, wrote or stolen successfully, now read:\n");

    volatile uintptr_t* tmp = (uintptr_t*)iv;
    printf("   Peeking[1/3] IVar (%p) before read: header %lu, payload %lu\n",  iv, tmp[0], tmp[1]);

    unsigned long val = (unsigned long)__cilkrts_ivar_read(iv);

    struct __cilkrts_worker* w_ = __cilkrts_get_tls_worker();
    printf("   Peeking[2/3] IVar (%p): header %lu, payload %lu\n",  iv, tmp[0], tmp[1]);
    printf("   Ivar (%p) read successfully: %lu w=%d\n",  iv, val, w_->self);
    printf("   Peeking[3/3] IVar (%p): header %lu, payload %lu\n",  iv, tmp[0], tmp[1]);

    unsigned long val2 = (unsigned long)__cilkrts_ivar_read(iv);
    struct __cilkrts_worker* w2 = __cilkrts_get_tls_worker();
    printf("   Here is a reread of IVar (%p): %lu  w=%d\n",  iv, val2, w2->self);

    struct __cilkrts_worker* w = __cilkrts_get_tls_worker();
    printf("fun(): Going to attempt Sync.  Current Cilk worker = %d\n", w->self);

#ifdef DELAY_READER
    __cilkrts_usleep(DELAY);   printf("fun(): Reader done sleeping, now sync\n");
#endif
    cilk_sync;
    printf("   fun(): reached position AFTER cilk_sync\n");

    if (val != 39) { printf("TEST ERROR - BAD VALUE, %ld, EXPECTED 39 - ABORTING!\n", val); abort(); }
}
Exemple #2
0
CILK_EXPORT void __CILKRTS_STRAND_STALE(
    __cilkrts_hyper_destroy(__cilkrts_hyperobject_base *hb))
{
    // Disable Cilkscreen for the duration of this call.  The destructor for
    // this class will re-enable Cilkscreen when the method returns.  This
    // will prevent Cilkscreen from reporting apparent races in reducers
    DisableCilkscreen x;

    __cilkrts_worker* w = __cilkrts_get_tls_worker();
    if (! w) {
        // If no worker, then Cilk is not running and there is no reducer
        // map.  Do nothing.  The reducer's destructor will take care of
        // destroying the leftmost view.
        return;
    }

const char *UNSYNCED_REDUCER_MSG =
    "Destroying a reducer while it is visible to unsynced child tasks, or\n"
    "calling CILK_C_UNREGISTER_REDUCER() on an unregistered reducer.\n"
    "Did you forget a _Cilk_sync or CILK_C_REGISTER_REDUCER()?";

    cilkred_map* h = w->reducer_map;
    if (NULL == h)
	cilkos_error(UNSYNCED_REDUCER_MSG); // Does not return

    if (h->merging) {
	verify_current_wkr(w);
	__cilkrts_bug("User error: hyperobject used by another hyperobject");
    }

    void* key = get_hyperobject_key(hb);
    elem *el = h->lookup(key);

    // Verify that the reducer is being destroyed from the leftmost strand for
    // which the reducer is defined.
    if (! (el && el->is_leftmost()))
	cilkos_error(UNSYNCED_REDUCER_MSG);

#if REDPAR_DEBUG >= 3
    fprintf(stderr, "[W=%d, key=%p, lookup in map %p, found el=%p, about to destroy]\n",
            w->self, key, h, el);
#endif
	
    // Remove the element from the hash bucket.  Do not bother shrinking
    // the bucket. Note that the destroy() function does not actually
    // call the destructor for the leftmost view.
    el->destroy();
    do {
        el[0] = el[1];
        ++el;
    } while (el->key);
    --h->nelem;

#if REDPAR_DEBUG >= 2
    fprintf(stderr, "[W=%d, desc=hyper_destroy_finish, key=%p, w->reducer_map=%p]\n",
	    w->self, key, w->reducer_map);
#endif 
}
Exemple #3
0
void writer(__cilkrts_ivar* iv) 
{
    int val = 39;
    long long result = 5;

    printf("     Inside spawned writer... spawn spurious work\n");

    result = cilk_spawn parfib(FIBINP);

    printf("   spurious work finished or parent stolen (w=%d)\n", __cilkrts_get_tls_worker()->self); 

    __cilkrts_usleep(DELAY); // microseconds   
    __cilkrts_ivar_write(iv, (ivar_payload_t)val);
    printf("     Inside spawned writer... WRITE OF %d DONE (w=%d).\n", val, __cilkrts_get_tls_worker()->self);

    cilk_sync;
    printf("     Writer sync complete, fib result = %ld.\n", result);
}
Exemple #4
0
static inline int my_deque_size() {
#if defined(__PASL_CILK_EXT)
  return __cilkrts_get_deque_size(__cilkrts_get_tls_worker());
#elif defined(USE_CILK_RUNTIME)
  util::atomic::die("bogus version of cilk runtime");
  return 0;
#else
  scheduler_p sched = threaddag::my_sched();
  return (int)sched->nb_threads();
#endif
}
// Check that w is the currently executing worker.  This method is a
// no-op unless the debug level is set high enough.
static inline void verify_current_wkr(__cilkrts_worker *w)
{
#if REDPAR_DEBUG >= 5
    __cilkrts_worker* tmp = __cilkrts_get_tls_worker();
    if (w != tmp) {
        fprintf(stderr, "W=%d, actual=%d... missing a refresh....\n",
                w->self,
                tmp->self);
    }
    CILK_ASSERT(w == tmp); // __cilkrts_get_tls_worker());
#endif
}
Exemple #6
0
CILK_EXPORT
void __cilkrts_hyper_create(__cilkrts_hyperobject_base *hb)
{
    // This function registers the specified hyperobject in the current
    // reducer map and registers the initial value of the hyperobject as the
    // leftmost view of the reducer.
    __cilkrts_worker *w = __cilkrts_get_tls_worker();
    if (! w) {
        // If there is no worker, then there is nothing to do: The iniitial
        // value will automatically be used as the left-most view when we
        // enter Cilk.
        return;
    }

    // Disable Cilkscreen for the duration of this call.  The destructor for
    // this class will re-enable Cilkscreen when the method returns.  This
    // will prevent Cilkscreen from reporting apparent races in reducers
    DisableCilkscreen x;

    void* key = get_hyperobject_key(hb);
    void* view = get_leftmost_view(key);
    cilkred_map *h = w->reducer_map;

    if (__builtin_expect(!h, 0)) {
	h = install_new_reducer_map(w);
#if REDPAR_DEBUG >= 2
	fprintf(stderr, "[W=%d, hb=%p, hyper_create, isntalled new map %p, view=%p]\n",
		w->self, hb, h, view);
#endif
    }

    /* Must not exist. */
    CILK_ASSERT(h->lookup(key) == NULL);

#if REDPAR_DEBUG >= 3
    verify_current_wkr(w);
    fprintf(stderr, "[W=%d, hb=%p, lookup in map %p of view %p, should be null]\n",
	    w->self, hb, h, view);
    fprintf(stderr, "W=%d, h=%p, inserting key %p, view%p\n",
	    w->self,
	    h,
	    &(hb->__c_monoid),
	    view);
#endif    

    if (h->merging)
        __cilkrts_bug("User error: hyperobject used by another hyperobject");

    CILK_ASSERT(w->reducer_map == h);
    // The address of the leftmost value is the same as the key for lookup.
    (void) h->rehash_and_insert(w, view, hb, view);
}
CILK_EXPORT void __CILKRTS_STRAND_STALE(
    __cilkrts_hyper_destroy(__cilkrts_hyperobject_base *hb))
{
    // Disable Cilkscreen for the duration of this call.  The destructor for
    // this class will re-enable Cilkscreen when the method returns.  This
    // will prevent Cilkscreen from reporting apparent races in reducers
    DisableCilkscreen x;

    __cilkrts_worker* w = __cilkrts_get_tls_worker();
    if (! w) {
        // If no worker, then Cilk is not running and there is no reducer
        // map.  Do nothing.  The reducer's destructor will take care of
        // destroying the leftmost view.
        return;
    }

    cilkred_map* h = w->reducer_map;
    CILK_ASSERT(h);

    if (h->merging) {
	verify_current_wkr(w);
	__cilkrts_bug("User error: hyperobject used by another hyperobject");
    }

    void* key = get_leftmost_view(hb);
    elem *el = h->lookup(key);
    if (el) {
        /* found. */

#if REDPAR_DEBUG >= 3
	fprintf(stderr, "[W=%d, key=%p, lookup in map %p, found el=%p, about to destroy]\n",
		w->self, key, h, el);
#endif
	
        /* Destroy view and remove element from bucket. */
        el->destroy();

        /* Shift all subsequent elements.  Do not bother
           shrinking the bucket */
        do {
            el[0] = el[1];
            ++el;
        } while (el->key);
        --h->nelem;
    }

#if REDPAR_DEBUG >= 2
    fprintf(stderr, "[W=%d, desc=hyper_destroy_finish, key=%p, w->reducer_map=%p]\n",
	    w->self, key, w->reducer_map);
#endif 
}
NORETURN
cilk_fiber_remove_reference_from_self_and_resume_other(cilk_fiber*      self,
                                                       cilk_fiber_pool* self_pool,
                                                       cilk_fiber*      other)
{
#if FIBER_DEBUG >= 3
    __cilkrts_worker* w = __cilkrts_get_tls_worker();
    fprintf(stderr, "W=%d: cilk_fiber_deactivate_self_and_resume_other: self=%p, other=%p\n",
            w->self,
            self, other);
#endif
    CILK_ASSERT(cilk_fiber_pool_sanity_check(self_pool, "remove_reference_from_self_resume_other"));
    self->remove_reference_from_self_and_resume_other(self_pool, other);
    
    // We should never return here. 
}
Exemple #9
0
CILK_API_VOID __cilkrts_end_cilk(void)
{
    // Take out the global OS mutex while we do this to protect against
    // another thread attempting to bind while we do this
    global_os_mutex_lock();

    if (cilkg_is_published()) {
        global_state_t *g = cilkg_get_global_state();
        if (g->Q || __cilkrts_get_tls_worker())
            __cilkrts_bug("Attempt to shut down Cilk while Cilk is still "
                          "running");
        __cilkrts_stop_workers(g);
        __cilkrts_deinit_internal(g);
    }

    global_os_mutex_unlock();
}
Exemple #10
0
/* Return a small integer indicating which Cilk worker the function is
 * currently running on.  Each thread started by the Cilk runtime library
 * (system worker) has a unique worker number in the range 1..P-1, where P is
 * the valued returned by __cilkrts_get_nworkers().  All threads started by
 * the user or by other libraries (user workers) share the worker number 0.
 * Therefore, the worker number is not unique across multiple user threads.
 *
 * Implementor's note: The value returned from this function is different from
 * the value, w->self, used in most debug messages.
 */
CILK_API_INT
__cilkrts_get_worker_number(void)
{
    __cilkrts_worker *w = __cilkrts_get_tls_worker();

    if (0 == w)
        /* A non-worker always has a worker number of zero. */
        return 0;
    else if (WORKER_USER == w->l->type)
        /* User worker was once a non-worker, so its number should still be
         * zero. */
        return 0;
    else
        /* w->self for a system worker is in range 0..(P-1); adjust to 1..P
         * to avoid conflicting with the user thread's worker number. */
        return w->self + 1;
}
Exemple #11
0
CILK_API_INT
__cilkrts_get_pedigree_info(__cilkrts_pedigree_context_t *external_context,
                            uint64_t *sf_birthrank)
{
    pedigree_context_t *context = (pedigree_context_t *)external_context;

    CILK_ASSERT(sizeof(__cilkrts_pedigree_context_t) ==
                sizeof(pedigree_context_t));
    if (context->size != sizeof(pedigree_context_t))
        return -3;  // Invalid size

    // If the pointer to the last __cilkrts_pedigree is -1, we've
    // finished the walk.  We're still done.
    if (PEDIGREE_WALK_COMPLETE == context->pedigree)
        return 1;

    // The passed in context value contains a pointer to the last
    // __cilkrts_pedigree returned, or NULL if we're starting a
    // new walk
    if (NULL == context->pedigree)
    {
        __cilkrts_worker *w = __cilkrts_get_tls_worker();
        __cilkrts_pedigree* pedigree_node;
        if (NULL != w) {
            pedigree_node = &w->pedigree;
        }
        else {
            pedigree_node = __cilkrts_get_tls_pedigree_leaf(1);
        }
        context->pedigree = pedigree_node->parent;
    }
    else
        context->pedigree = context->pedigree->parent;

    // Note: If we want to omit the user root node,
    // stop at context->pedigree->parent instead.
    if (NULL == context->pedigree)
    {
        context->pedigree = PEDIGREE_WALK_COMPLETE;
        return 1;
    }

    *sf_birthrank = context->pedigree->rank;
    return 0;
}
static void cilk_for_root(F body, void *data, count_t count, int grain)
{
    // Cilkscreen should not report this call in a stack trace
    NOTIFY_ZC_INTRINSIC((char *)"cilkscreen_hide_call", 0);

    // Pedigree computation:
    //
    //    If the last pedigree node on entry to the _Cilk_for has value X,
    //    then at the start of each iteration of the loop body, the value of
    //    the last pedigree node should be 0, the value of the second-to-last
    //    node should equal the loop counter, and the value of the
    //    third-to-last node should be X.  On return from the _Cilk_for, the
    //    value of the last pedigree should be incremented to X+2. The
    //    pedigree within the loop is thus flattened, such that the depth of
    //    recursion does not affect the results either inside or outside of
    //    the loop.  Note that the pedigree after the loop exists is the same
    //    as if a single spawn and sync were executed within this function.

    // TBD: Since the shrink-wrap optimization was turned on in the compiler,
    // it is not possible to get the current stack frame without actually
    // forcing a call to bind-thread.  This spurious spawn is a temporary
    // stopgap until the correct intrinsics are added to give us total control
    // over frame initialization.
    _Cilk_spawn noop();

    // Fetch the current worker.  From that we can get the current stack frame
    // which will be constant even if we're stolen
    __cilkrts_worker *w = __cilkrts_get_tls_worker();
    __cilkrts_stack_frame *sf = w->current_stack_frame;

    // Decrement the rank by one to undo the pedigree change from the
    // _Cilk_spawn
    --w->pedigree.rank;

    // Save the current worker pedigree into loop_root_pedigree, which will be
    // the root node for our flattened pedigree.
    __cilkrts_pedigree loop_root_pedigree = w->pedigree;

    // Don't splice the loop_root node in yet.  It will be done when we
    // call the loop body lambda function
//    w->pedigree.rank = 0;
//    w->pedigree.next = &loop_root_pedigree;

    /* Spawn is necessary at top-level to force runtime to start up.
     * Runtime must be started in order to call the grainsize() function.
     */
    int gs = grainsize(grain, count);
    cilk_for_recursive((count_t) 0, count, body, data, gs, w,
                       &loop_root_pedigree);

    // Need to refetch the worker after calling a spawning function.
    w = sf->worker;

    // Restore the pedigree in the worker.
    w->pedigree = loop_root_pedigree;

    // Bump the worker pedigree.
    ++w->pedigree.rank;

    // Implicit sync will increment the pedigree leaf rank again, for a total
    // of two increments.  If the noop spawn above is removed, then we'll need
    // to re-enable the following code:
//     // If this is an optimized build, then the compiler will have optimized
//     // out the increment of the worker's pedigree in the implied sync.  We
//     // need to add one to make the pedigree_loop test work correctly.
// #if CILKRTS_OPTIMIZED
//     ++sf->worker->pedigree.rank;
// #endif
}