Beispiel #1
0
/* This can only be called from the PRODUCER
 */
int thorium_worker_enqueue_actor(struct thorium_worker *worker, struct thorium_actor *actor)
{
    int value;

    CORE_DEBUGGER_ASSERT(actor != NULL);

    value = core_fast_ring_push_from_producer(&worker->actors_to_schedule, &actor);

#ifdef SHOW_FULL_RING_WARNINGS
    if (!value) {
        printf("thorium_worker: Warning: ring is full, actors_to_schedule\n");
    }
#endif

    /*
     * Do a wake up if necessary when scheduling an actor in
     * the scheduling queue.
     */
    if (value && worker->waiting_is_enabled) {

        /*
         * This call checks if the thread is currently waiting.
         * If it is currently waiting, then a signal is sent
         * to tell the operating system to wake up the thread so that
         * it continues its good work for the actor computation in thorium.
         */
        thorium_worker_signal(worker);
    }

    return value;
}
Beispiel #2
0
int thorium_worker_enqueue_message_for_triage(struct thorium_worker *worker, struct thorium_message *message)
{
#ifdef THORIUM_WORKER_DEBUG_INJECTION
    int worker_name;
#endif

    CORE_DEBUGGER_ASSERT(thorium_message_buffer(message) != NULL);

    if (!core_fast_ring_push_from_producer(&worker->clean_message_ring_for_triage, message)) {

#ifdef SHOW_FULL_RING_WARNINGS
        printf("thorium_worker: Warning: ring is full, clean_message_ring_for_triage action= %x\n",
                        thorium_message_action(message));
#endif

        core_fast_queue_enqueue(&worker->clean_message_queue_for_triage, message);

#ifdef THORIUM_WORKER_DEBUG_INJECTION
    } else {
        /*
         * Update software counters.
         */
        worker_name = thorium_message_worker(message);

        if (worker_name >= 0) {
            ++worker->counter_injected_outbound_buffers_other_local_workers;
        } else {
            ++worker->counter_injected_inbound_buffers_from_thorium_core;
        }
#endif
    }

    return 1;
}
Beispiel #3
0
void thorium_worker_evict_actor(struct thorium_worker *worker, int actor_name)
{
    struct thorium_actor *actor;
    int name;
    struct core_fast_queue saved_actors;
    int count;
    int value;

    core_set_add(&worker->evicted_actors, &actor_name);
    core_map_delete(&worker->actors, &actor_name);
    core_fast_queue_init(&saved_actors, sizeof(struct thorium_actor *));

    /* evict the actor from the scheduling queue
     */
    while (thorium_scheduler_dequeue(&worker->scheduler, &actor)) {

        name = thorium_actor_name(actor);

        if (name != actor_name) {

            core_fast_queue_enqueue(&saved_actors,
                            &actor);
        }
    }

    while (core_fast_queue_dequeue(&saved_actors, &actor)) {
        thorium_scheduler_enqueue(&worker->scheduler, actor);
    }

    core_fast_queue_destroy(&saved_actors);

    /* Evict the actor from the ring
     */

    count = core_fast_ring_size_from_consumer(&worker->actors_to_schedule);

    while (count-- && core_fast_ring_pop_from_consumer(&worker->actors_to_schedule,
                            &actor)) {

        name = thorium_actor_name(actor);

        if (name != actor_name) {

            /*
             * This can not fail logically.
             */
            value = core_fast_ring_push_from_producer(&worker->actors_to_schedule,
                            &actor);

            CORE_DEBUGGER_ASSERT(value);
        }
    }

    core_map_iterator_destroy(&worker->actor_iterator);
    core_map_iterator_init(&worker->actor_iterator, &worker->actors);
}
Beispiel #4
0
int thorium_worker_inject_clean_outbound_buffer(struct thorium_worker *self, void *buffer)
{
    int value;

    value = core_fast_ring_push_from_producer(&self->injected_clean_outbound_buffers,
                    &buffer);

#ifdef SHOW_FULL_RING_WARNINGS
    if (!value) {
        printf("thorium_worker: Warning: ring is full, injected_clean_outbound_buffers\n");
    }
#endif

    return value;
}
Beispiel #5
0
int thorium_worker_enqueue_message(struct thorium_worker *worker, struct thorium_message *message)
{

    /* Try to push the message in the output ring
     */
    if (!core_fast_ring_push_from_producer(&worker->outbound_message_queue, message)) {

#ifdef SHOW_FULL_RING_WARNINGS
        printf("thorium_worker: Warning: ring is full, outbound_message_queue\n");
#endif
        /* If that does not work, push the message in the queue buffer.
         */
        core_fast_queue_enqueue(&worker->outbound_message_queue_buffer, message);

    }

    return 1;
}
Beispiel #6
0
int main(int argc, char **argv)
{
    BEGIN_TESTS();

    struct core_fast_ring ring;
    int capacity = 64;
    int i;
    int value;
    int elements;

    elements = 0;

#if 0
    printf("Required %d\n", capacity);
#endif
    core_fast_ring_init(&ring, capacity, sizeof(int));

    capacity = core_fast_ring_capacity(&ring);

#if 0
    printf("Provided %d\n", capacity);
#endif

    TEST_BOOLEAN_EQUALS(core_fast_ring_is_empty_from_consumer(&ring), 1);

    for (i = 0; i < capacity; i++) {
        TEST_BOOLEAN_EQUALS(core_fast_ring_push_from_producer(&ring, &i), 1);
        elements++;

        TEST_INT_EQUALS(core_fast_ring_size_from_producer(&ring), elements);
        TEST_INT_EQUALS(core_fast_ring_size_from_consumer(&ring), elements);
    }

    TEST_BOOLEAN_EQUALS(core_fast_ring_is_full_from_producer(&ring), 1);

    for (i = 0; i < capacity; i++) {
        TEST_BOOLEAN_EQUALS(core_fast_ring_pop_from_consumer(&ring, &value), 1);
        elements--;
        TEST_INT_EQUALS(value, i);
        TEST_INT_EQUALS(core_fast_ring_size_from_producer(&ring), elements);
        TEST_INT_EQUALS(core_fast_ring_size_from_consumer(&ring), elements);
    }
    core_fast_ring_destroy(&ring);

    {
        struct core_fast_ring ring;
        int capacity = 64;
        struct thorium_message message;
        int action;
        int count;
        void *buffer;
        int inserted;
        int pulled;

        action = 1234;
        count = 0;
        buffer = NULL;

        thorium_message_init(&message, action, count, buffer);

        core_fast_ring_init(&ring, capacity, sizeof(struct thorium_message));
        core_fast_ring_use_multiple_producers(&ring);

        inserted = 0;

        while (core_fast_ring_push_from_producer(&ring, &message)) {
            ++inserted;
        }

        /*
         * 64 + 1 = 65, 128 is the next power of 2 for the mask.
         */
        /*
        TEST_INT_EQUALS(inserted, capacity);
        */

        pulled = 0;

        while (core_fast_ring_pop_from_consumer(&ring, &message)) {
            ++pulled;
        }

        TEST_INT_EQUALS(inserted, pulled);

        core_fast_ring_destroy(&ring);

        thorium_message_destroy(&message);
    }

    END_TESTS();

    return 0;
}
Beispiel #7
0
void thorium_worker_run(struct thorium_worker *worker)
{
    struct thorium_actor *actor;
    struct thorium_message other_message;

#ifdef THORIUM_NODE_INJECT_CLEAN_WORKER_BUFFERS
    void *buffer;
#endif

#ifdef THORIUM_NODE_ENABLE_INSTRUMENTATION
    time_t current_time;
    int elapsed;
    int period;
    uint64_t current_nanoseconds;
    uint64_t elapsed_nanoseconds;
#endif

#ifdef THORIUM_WORKER_DEBUG
    int tag;
    int destination;
    struct thorium_message *message;
#endif

#ifdef THORIUM_WORKER_ENABLE_LOCK
    thorium_worker_lock(worker);
#endif

#ifdef THORIUM_NODE_ENABLE_INSTRUMENTATION
    period = THORIUM_NODE_LOAD_PERIOD;
    current_time = time(NULL);

    elapsed = current_time - worker->last_report;

    if (elapsed >= period) {

        current_nanoseconds = core_timer_get_nanoseconds(&worker->timer);

#ifdef THORIUM_WORKER_DEBUG_LOAD
        printf("DEBUG Updating load report\n");
#endif
        elapsed_nanoseconds = current_nanoseconds - worker->epoch_start_in_nanoseconds;

        if (elapsed_nanoseconds > 0) {
            worker->epoch_load = (0.0 + worker->epoch_used_nanoseconds) / elapsed_nanoseconds;
            worker->epoch_used_nanoseconds = 0;
            worker->last_wake_up_count = core_thread_get_wake_up_count(&worker->thread);

            /* \see http://stackoverflow.com/questions/9657993/negative-zero-in-c
             */
            if (worker->epoch_load == 0) {
                worker->epoch_load = 0;
            }

            worker->epoch_start_in_nanoseconds = current_nanoseconds;
            worker->last_report = current_time;
        }

#ifdef THORIUM_WORKER_PRINT_SCHEDULING_QUEUE

        /*
        if (thorium_node_name(worker->node) == 0
                        && worker->name == 0) {
                        */

        thorium_scheduler_print(&worker->scheduler,
                        thorium_node_name(worker->node),
                        worker->name);
            /*
        }
        */
#endif

        if (core_bitmap_get_bit_uint32_t(&worker->flags, FLAG_DEBUG_ACTORS)) {
            thorium_worker_print_actors(worker, NULL);
        }
    }
#endif

#ifdef THORIUM_WORKER_DEBUG
    if (core_bitmap_get_bit_uint32_t(&worker->flags, FLAG_DEBUG)) {
        printf("DEBUG worker/%d thorium_worker_run\n",
                        thorium_worker_name(worker));
    }
#endif

    /* check for messages in inbound FIFO */
    if (thorium_worker_dequeue_actor(worker, &actor)) {

#ifdef THORIUM_WORKER_DEBUG
        message = biosal_work_message(&work);
        tag = thorium_message_action(message);
        destination = thorium_message_destination(message);

        if (tag == ACTION_ASK_TO_STOP) {
            printf("DEBUG pulled ACTION_ASK_TO_STOP for %d\n",
                            destination);
        }
#endif

        /*
         * Update the priority of the actor
         * before starting the timer because this is part of the
         * runtime system (RTS).
         */

#ifdef THORIUM_UPDATE_SCHEDULING_PRIORITIES
        thorium_priority_assigner_update(&worker->scheduler, actor);
#endif

#ifdef THORIUM_NODE_ENABLE_INSTRUMENTATION
        core_timer_start(&worker->timer);
#endif

        core_bitmap_set_bit_uint32_t(&worker->flags, FLAG_BUSY);

        /*
         * Dispatch message to a worker
         */
        thorium_worker_work(worker, actor);

        core_bitmap_clear_bit_uint32_t(&worker->flags, FLAG_BUSY);

#ifdef THORIUM_NODE_ENABLE_INSTRUMENTATION
        core_timer_stop(&worker->timer);

        elapsed_nanoseconds = core_timer_get_elapsed_nanoseconds(&worker->timer);

        if (elapsed_nanoseconds >= THORIUM_GRANULARITY_WARNING_THRESHOLD) {
        }

        worker->epoch_used_nanoseconds += elapsed_nanoseconds;
        worker->loop_used_nanoseconds += elapsed_nanoseconds;
        worker->scheduling_epoch_used_nanoseconds += elapsed_nanoseconds;

        worker->last_elapsed_nanoseconds = elapsed_nanoseconds;
#endif
    }

    /* queue buffered message
     */
    if (core_fast_queue_dequeue(&worker->outbound_message_queue_buffer, &other_message)) {

        if (!core_fast_ring_push_from_producer(&worker->outbound_message_queue, &other_message)) {

#ifdef SHOW_FULL_RING_WARNINGS
            printf("thorium_worker: Warning: ring is full => outbound_message_queue\n");
#endif

            core_fast_queue_enqueue(&worker->outbound_message_queue_buffer, &other_message);
        }
    }

#ifdef THORIUM_NODE_INJECT_CLEAN_WORKER_BUFFERS
    /*
     * Free outbound buffers, if any
     */

    if (thorium_worker_fetch_clean_outbound_buffer(worker, &buffer)) {
        core_memory_pool_free(&worker->outbound_message_memory_pool, buffer);

#ifdef THORIUM_WORKER_DEBUG_INJECTION
        ++worker->counter_freed_outbound_buffers_from_other_workers;
#endif
    }
#endif

    /*
     * Transfer messages for triage
     */

    if (core_fast_queue_dequeue(&worker->clean_message_queue_for_triage, &other_message)) {

        CORE_DEBUGGER_ASSERT(thorium_message_buffer(&other_message) != NULL);
        thorium_worker_enqueue_message_for_triage(worker, &other_message);
    }

#ifdef THORIUM_WORKER_ENABLE_LOCK
    thorium_worker_unlock(worker);
#endif
}