コード例 #1
0
void thorium_cfs_scheduler_print(struct thorium_scheduler *self)
{
    struct thorium_cfs_scheduler *concrete_self;
    struct core_red_black_tree_iterator iterator;
    uint64_t virtual_runtime;
    struct thorium_actor *actor;
    int i;
    struct core_timer timer;

    core_timer_init(&timer);
    concrete_self = self->concrete_self;

    core_red_black_tree_iterator_init(&iterator, &concrete_self->tree);

    printf("[cfs_scheduler] %" PRIu64 " ns, timeline contains %d actors\n",
                    core_timer_get_nanoseconds(&timer),
                    core_red_black_tree_size(&concrete_self->tree));

    i = 0;
    while (core_red_black_tree_iterator_get_next_key_and_value(&iterator, &virtual_runtime,
                            &actor)) {
        printf("[%d] virtual_runtime= %" PRIu64 " actor= %s/%d\n",
                        i, virtual_runtime,
                        thorium_actor_script_name(actor), thorium_actor_name(actor));
        ++i;
    }

    core_red_black_tree_iterator_destroy(&iterator);
    core_timer_destroy(&timer);
}
コード例 #2
0
ファイル: timer.c プロジェクト: bioparr/biosal
void core_timer_stop(struct core_timer *timer)
{

    timer->stop = core_timer_get_nanoseconds(timer);

    timer->stopped = 1;

#ifdef CORE_TIMER_DEBUG
    fprintf(stderr, "TIMER start %" PRIu64 " stop %" PRIu64 "\n", stop, timer->start);
#endif

}
コード例 #3
0
ファイル: worker.c プロジェクト: huyba/biosal
float thorium_worker_get_scheduling_epoch_load(struct thorium_worker *worker)
{
    uint64_t end_time;
    uint64_t period;

    end_time = core_timer_get_nanoseconds(&worker->timer);

    period = end_time - worker->scheduling_epoch_start_in_nanoseconds;

    if (period == 0) {
        return 0;
    }

    return (0.0 + worker->scheduling_epoch_used_nanoseconds) / period;
}
コード例 #4
0
ファイル: transport.c プロジェクト: huyba/biosal
void thorium_transport_print_event(struct thorium_transport *self, int type, struct thorium_message *message)
{
    char *description;
    int count;
    int source_rank;
    int destination_rank;
    uint64_t time;

    description = EVENT_STRING_SEND;

    if (type == EVENT_TYPE_RECEIVE)
        description = EVENT_STRING_RECEIVE;

    count = thorium_message_count(message);
    source_rank = thorium_message_source_node(message);
    destination_rank = thorium_message_destination_node(message);

    time = core_timer_get_nanoseconds(&self->timer);
    time -= self->start_time;
    printf("thorium_transport print_event time_nanoseconds= %" PRIu64 " type= %s source= %d destination= %d count= %d\n",
                    time, description,
                    source_rank, destination_rank, count);
}
コード例 #5
0
ファイル: worker.c プロジェクト: huyba/biosal
void thorium_worker_stop(struct thorium_worker *worker)
{

#ifdef THORIUM_WORKER_DEBUG
    thorium_worker_display(worker);
    printf("stopping worker!\n");
#endif

    /*
     * FLAG_DEAD is changed and will be read
     * by the running thread.
     *
     * Only one thread is changing this value, so no thread are needed.
     */
    core_bitmap_set_bit_uint32_t(&worker->flags, FLAG_DEAD);

    /* Make the change visible to other threads too
     */
    core_memory_fence();

    /* Wake the worker **after** killing it.
     * So basically, there is a case where the worker is killed
     * while sleeping. But since threads are cool, the worker will
     * wake up, and die for real this time.
     */
    if (worker->waiting_is_enabled) {
        /*
         * Wake up if necessary because the worker might be
         * waiting for something...
         */
        thorium_worker_signal(worker);
    }

    core_thread_join(&worker->thread);

    worker->loop_end_in_nanoseconds = core_timer_get_nanoseconds(&worker->timer);
}
コード例 #6
0
ファイル: transport.c プロジェクト: huyba/biosal
void thorium_transport_init(struct thorium_transport *self, struct thorium_node *node,
                int *argc, char ***argv,
                struct core_memory_pool *inbound_message_memory_pool,
                struct core_memory_pool *outbound_message_memory_pool)
{
    int actual_argc;
    char **actual_argv;

    self->active_request_count = 0;

    actual_argc = *argc;
    actual_argv = *argv;

    self->flags = 0;
    core_bitmap_clear_bit_uint32_t(&self->flags, FLAG_PROFILE);
    core_bitmap_clear_bit_uint32_t(&self->flags, FLAG_PRINT_TRANSPORT_EVENTS);

    self->transport_interface = NULL;
    self->concrete_transport = NULL;

    /*
    printf("DEBUG Initiating transport\n");
    */
    /* Select the transport layer
     */
    /*
     * Assign functions
     */
    thorium_transport_select_implementation(self, actual_argc, actual_argv);

    self->node = node;

    self->rank = -1;
    self->size = -1;

    if (self->transport_interface != NULL) {

        self->concrete_transport = core_memory_allocate(self->transport_interface->size, MEMORY_TRANSPORT);
        self->transport_interface->init(self, argc, argv);
    }

    CORE_DEBUGGER_ASSERT(self->rank >= 0);
    CORE_DEBUGGER_ASSERT(self->size >= 1);
    CORE_DEBUGGER_ASSERT(self->node != NULL);

    self->inbound_message_memory_pool = inbound_message_memory_pool;
    self->outbound_message_memory_pool = outbound_message_memory_pool;

    thorium_transport_profiler_init(&self->transport_profiler);

    if (core_command_has_argument(actual_argc, actual_argv, "-enable-transport-profiler")) {

        printf("Enable transport profiler\n");

        core_bitmap_set_bit_uint32_t(&self->flags, FLAG_PROFILE);
    }

    if (self->rank == 0) {
        printf("thorium_transport: type %s\n",
                    self->transport_interface->name);
    }

    if (core_command_has_argument(actual_argc, actual_argv, "-print-transport-events")) {
        core_bitmap_set_bit_uint32_t(&self->flags, FLAG_PRINT_TRANSPORT_EVENTS);
    }

    core_timer_init(&self->timer);
    self->start_time = core_timer_get_nanoseconds(&self->timer);
}
コード例 #7
0
ファイル: message_multiplexer.c プロジェクト: bioparr/biosal
void thorium_message_multiplexer_init(struct thorium_message_multiplexer *self,
                struct thorium_node *node, struct thorium_multiplexer_policy *policy)
{
    int size;
    int i;
    /*
    int bytes;
    */
    int position;
    struct thorium_multiplexed_buffer *multiplexed_buffer;
    int argc;
    char **argv;

    thorium_decision_maker_init(&self->decision_maker);

    self->policy = policy;
    self->original_message_count = 0;
    self->real_message_count = 0;

    CORE_BITMAP_CLEAR_FLAGS(self->flags);
    CORE_BITMAP_CLEAR_FLAG(self->flags, FLAG_DISABLED);

#ifdef THORIUM_MULTIPLEXER_TRACK_BUFFERS_WITH_CONTENT
    core_set_init(&self->buffers_with_content, sizeof(int));
#endif

    core_timer_init(&self->timer);

    self->buffer_size_in_bytes = thorium_multiplexer_policy_size_threshold(self->policy);

#ifdef CONFIG_MULTIPLEXER_USE_DECISION_MAKER
    self->timeout_in_nanoseconds = thorium_decision_maker_get_best_timeout(&self->decision_maker,
                    THORIUM_TIMEOUT_NO_VALUE);
#else
    self->timeout_in_nanoseconds = self->policy->threshold_time_in_nanoseconds;
#endif

    CORE_DEBUGGER_ASSERT(self->timeout_in_nanoseconds >= 0);

    self->node = node;

    core_vector_init(&self->buffers, sizeof(struct thorium_multiplexed_buffer));

    size = thorium_node_nodes(self->node);
    core_vector_resize(&self->buffers, size);

    /*
    bytes = size * self->buffer_size_in_bytes;
    */

#ifdef DEBUG_MULTIPLEXER
    thorium_printf("DEBUG_MULTIPLEXER size %d bytes %d\n", size, bytes);
#endif

    position = 0;

    for (i = 0; i < size; ++i) {
        multiplexed_buffer = core_vector_at(&self->buffers, i);

        CORE_DEBUGGER_ASSERT(multiplexed_buffer != NULL);

        /*
         * Initially, these multiplexed buffers have a NULL buffer.
         * It is only allocated when needed because each worker is an exporter
         * of small messages for a subset of all the destination nodes.
         */
        thorium_multiplexed_buffer_init(multiplexed_buffer, self->buffer_size_in_bytes,
                        self->timeout_in_nanoseconds);

        position += self->buffer_size_in_bytes;

#ifdef DEBUG_MULTIPLEXER1
        thorium_printf("DEBUG_MULTIPLEXER thorium_message_multiplexer_init index %d buffer %p\n", i, buffer);
#endif

#ifdef DEBUG_MULTIPLEXER
        thorium_printf("DEBUG_MULTIPLEXER thorium_message_multiplexer_init (after) index %d buffer %p\n", i,
                        core_vector_at(&self->buffers, i));
#endif
    }

    if (thorium_multiplexer_policy_is_disabled(self->policy)) {
        CORE_BITMAP_SET_FLAG(self->flags, FLAG_DISABLED);
    }

    if (thorium_node_nodes(self->node) < thorium_multiplexer_policy_minimum_node_count(self->policy)) {
        CORE_BITMAP_SET_FLAG(self->flags, FLAG_DISABLED);
    }

    self->worker = NULL;

    argc = node->argc;
    argv = node->argv;

    /*
     * Aside from the policy, the end user can also disable the multiplexer code path
     */
    if (core_command_has_argument(argc, argv, OPTION_DISABLE_MULTIPLEXER)) {
        CORE_BITMAP_SET_FLAG(self->flags, FLAG_DISABLED);
    }

    self->last_send_event_count = 0;
    self->last_time = core_timer_get_nanoseconds(&self->timer);
    self->last_update_time = time(NULL);

    self->degree_of_aggregation_limit = self->policy->degree_of_aggregation_limit;

    thorium_router_init(&self->router, self->node->nodes,
                    TOPOLOGY_POLYTOPE);

    if (thorium_node_must_print_data(self->node)) {
        thorium_router_print(&self->router);
    }
}
コード例 #8
0
ファイル: message_multiplexer.c プロジェクト: bioparr/biosal
/*
 * Returns 1 if the message was multiplexed.
 *
 * This is O(1) in regard to the number of thorium nodes.
 */
int thorium_message_multiplexer_multiplex(struct thorium_message_multiplexer *self,
                struct thorium_message *message)
{
    /*
     * If buffer is full, use thorium_node_send_with_transport
     *
     * get count
     *
     * if count is below or equal to the threshold
     *      multiplex the message.
     *      return 1
     *
     * return 0
     */

    int count;
    int current_size;
    int maximum_size;
    int action;
    struct core_memory_pool *pool;
    void *new_buffer;
    int new_count;
    void *buffer;
    int destination_node;
    int destination_actor;
    int new_size;
    int required_size;
    struct thorium_multiplexed_buffer *real_multiplexed_buffer;
    uint64_t time;
    int next_node_in_route;
    int source_node;
    int current_node;

#ifdef DEBUG_MULTIPLEXER
    thorium_printf("multiplex\n");
    thorium_message_print(message);
#endif

    if (CORE_BITMAP_GET_FLAG(self->flags, FLAG_DISABLED)) {
        return 0;
    }

    action = thorium_message_action(message);

    CORE_DEBUGGER_ASSERT(action != ACTION_INVALID);

#ifdef THORIUM_MULTIPLEXER_USE_ACTIONS_TO_SKIP
    /*
     * Don't multiplex already-multiplexed messages.
     */
    if (thorium_multiplexer_policy_is_action_to_skip(self->policy, action)) {
        return 0;
    }
#endif

#ifdef CONFIG_MULTIPLEXER_USE_DECISION_MAKER
    thorium_message_multiplexer_update_timeout(self);
#endif

    ++self->original_message_count;

    count = thorium_message_count(message);

    destination_node = thorium_message_destination_node(message);

    source_node = message->routing_source;
    current_node = self->node->name;
    next_node_in_route = thorium_router_get_next_rank_in_route(&self->router,
                    source_node, current_node, destination_node);

    /*
    thorium_message_print(message);
    thorium_printf("router: source_node %d current_node %d next_node_in_route %d"
                    " destination_node %d\n",
                    source_node, current_node,
                    next_node_in_route, destination_node);
                    */

#ifdef CONFIG_USE_TOPOLOGY_AWARE_AGGREGATION
    /*
     * The next node in the route for this message is
     * next_node_in_route.
     */
    destination_node = next_node_in_route;
#endif

    CORE_DEBUGGER_ASSERT(source_node >= 0);

    real_multiplexed_buffer = core_vector_at(&self->buffers, destination_node);

    CORE_DEBUGGER_ASSERT(real_multiplexed_buffer != NULL);

    required_size = thorium_multiplexed_buffer_required_size(real_multiplexed_buffer, count);

    buffer = thorium_message_buffer(message);
    destination_actor = thorium_message_destination(message);

#ifdef DEBUG_MULTIPLEXER
    thorium_printf("DEBUG multiplex count %d required_size %d action %x\n",
                    count, required_size, action);
#endif

    /*
     * Don't multiplex non-actor messages.
     */
    if (destination_actor == THORIUM_ACTOR_NOBODY) {
        return 0;
    }

#ifdef CORE_DEBUGGER_ASSERT
    if (real_multiplexed_buffer == NULL) {
        thorium_printf("Error action %d destination_node %d destination_actor %d\n", action, destination_node,
                        destination_actor);
    }
#endif

    current_size = thorium_multiplexed_buffer_current_size(real_multiplexed_buffer);
    maximum_size = thorium_multiplexed_buffer_maximum_size(real_multiplexed_buffer);

    /*
     * Don't multiplex large messages.
     */
    if (required_size > maximum_size) {

#ifdef DEBUG_MULTIPLEXER
        thorium_printf("too large required_size %d maximum_size %d\n", required_size, maximum_size);
#endif
        return 0;
    }

    /*
    thorium_printf("MULTIPLEX_MESSAGE\n");
    */

    new_size = current_size + required_size;

    /*
     * Flush now if there is no space left for the <required_size> bytes
     */
    if (new_size > maximum_size) {

#ifdef DEBUG_MULTIPLEXER
        thorium_printf("thorium_message_multiplexer: must FLUSH thorium_message_multiplexer_multiplex required_size %d new_size %d maximum_size %d\n",
                    required_size, new_size, maximum_size);
#endif

        thorium_message_multiplexer_flush(self, destination_node, FORCE_YES_SIZE);
        current_size = thorium_multiplexed_buffer_current_size(real_multiplexed_buffer);

        CORE_DEBUGGER_ASSERT(current_size == 0);
    }

    time = core_timer_get_nanoseconds(&self->timer);

    /*
     * If the buffer is empty before adding the data, it means that it is not
     * in the list of buffers with content and it must be added.
     */
    if (current_size == 0) {

        thorium_multiplexed_buffer_set_time(real_multiplexed_buffer, time);

#ifdef THORIUM_MULTIPLEXER_TRACK_BUFFERS_WITH_CONTENT
        core_set_add(&self->buffers_with_content, &destination_node);
#endif

        /*
         * Add it to the timeline.
         */

#ifdef THORIUM_MULTIPLEXER_USE_TREE
        core_red_black_tree_add_key_and_value(&self->timeline, &time, &destination_node);

#elif defined(THORIUM_MULTIPLEXER_USE_HEAP)
        core_binary_heap_insert(&self->timeline, &time, &destination_node);
#elif defined(THORIUM_MULTIPLEXER_USE_QUEUE)
        core_queue_enqueue(&self->timeline, &destination_node);
#endif

    }

    /*
     * The allocation of buffer is lazy.
     * The current worker is an exporter of small message for the destination
     * "destination_node".
     */
    if (thorium_multiplexed_buffer_buffer(real_multiplexed_buffer) == NULL) {
        pool = thorium_worker_get_outbound_message_memory_pool(self->worker);

        new_count = self->buffer_size_in_bytes + THORIUM_MESSAGE_METADATA_SIZE;
        new_buffer = core_memory_pool_allocate(pool, new_count);

        thorium_multiplexed_buffer_set_buffer(real_multiplexed_buffer, new_buffer);
    }

    /*
    thorium_printf("DEBUG worker_latency %d ns\n",
                    thorium_worker_latency(self->worker));
                    */

    thorium_multiplexed_buffer_append(real_multiplexed_buffer, count, buffer, time);

    /*
     * Try to flush. This only flushes something if the buffer is full.
     */

    if (thorium_message_multiplexer_buffer_is_ready(self, real_multiplexed_buffer)) {

        /*
         * Try to flush here too. This is required in order to satisfy the
         * technical requirement of a DOA limit.
         *
         * Obviously, don't flush if there is some outbound traffic congestion.
         * Otherwise, there will be too many messages on the network.
         */
        if (!thorium_worker_has_outbound_traffic_congestion(self->worker)) {
            thorium_message_multiplexer_flush(self, destination_node, FORCE_YES_SIZE);
        }
    }

    /*
     * Verify invariant.
     */
    CORE_DEBUGGER_ASSERT(thorium_multiplexed_buffer_current_size(real_multiplexed_buffer)<= maximum_size);

    /*
     * Inject the buffer into the worker too.
     */
    return 1;
}
コード例 #9
0
ファイル: message_multiplexer.c プロジェクト: bioparr/biosal
int thorium_message_multiplexer_buffer_is_ready(struct thorium_message_multiplexer *self,
                struct thorium_multiplexed_buffer *multiplexed_buffer)
{
    uint64_t buffer_time;
    int timeout;
#ifdef CHECK_PREDICTED_TRAFFIC_REDUCTION
    double acceptable_traffic_reduction;
    double traffic_reduction;
#endif
    int message_count;
    uint64_t time;
    int duration;

    /*
    * Flush only the buffers with a elapsed time that is greater or equal to the
    * timeout.
    */
    time = core_timer_get_nanoseconds(&self->timer);

    buffer_time = thorium_multiplexed_buffer_time(multiplexed_buffer);
    message_count = multiplexed_buffer->message_count_;

    /*
    * Get the current time. This current time will be compared
    * with the virtual time of each item in the timeline.
    */
    duration = time - buffer_time;

    timeout = self->timeout_in_nanoseconds;

#ifdef CHECK_PREDICTED_TRAFFIC_REDUCTION
    traffic_reduction = thorium_multiplexed_buffer_get_traffic_reduction(multiplexed_buffer);
#endif

    /*
     * Flush if the timeout is 0. This means that no aggregation will
     * take place anyway.
     */
    if (timeout == 0) {
        return 1;
    }

    /*
     * Flush if DOA (degree of aggregation) is large enough.
     */
    if (message_count >= self->degree_of_aggregation_limit) {
        return 1;
    }

    /*
     * Flush if the age of the buffer is large enough.
     */
    if (duration >= timeout) {
        return 1;
    }

#ifdef CHECK_PREDICTED_TRAFFIC_REDUCTION
    if (traffic_reduction >= acceptable_traffic_reduction) {
        return 1;
    }
#endif

    /*
     * Delay the flush function call a bit longer.
     */
    return 0;
}
コード例 #10
0
ファイル: message_multiplexer.c プロジェクト: bioparr/biosal
void thorium_message_multiplexer_update_timeout(struct thorium_message_multiplexer *self)
{
    time_t now;
    uint64_t elapsed;
    int period;
    uint64_t throughput;
    int timeout;
    uint64_t now_nanoseconds;
    uint64_t event_count;
    int new_timeout;

#ifdef MULTIPLEXER_IS_VERBOSE
    int print = 0;
    if (thorium_node_must_print_data(self->worker->node)
        && self->worker->node->name == 0 && self->worker->name == 1)
        print = 1;
#endif

    period = 1;
    now = time(NULL);

    elapsed = now - self->last_update_time;

    if ((int)elapsed < period)
        return;

    timeout = self->timeout_in_nanoseconds;

    CORE_DEBUGGER_ASSERT(timeout >= 0);
    now_nanoseconds = core_timer_get_nanoseconds(&self->timer);

    elapsed = now_nanoseconds - self->last_time;
    event_count = thorium_worker_get_event_counter(self->worker,
                    THORIUM_EVENT_ACTOR_SEND);

    throughput = event_count;
    throughput -= self->last_send_event_count;
    throughput *= (1000 * 1000 * 1000);
    throughput /= elapsed;

#ifdef MULTIPLEXER_IS_VERBOSE
    if (print)
        thorium_printf("event_count %" PRIu64 " last %" PRIu64 " elapsed %" PRIu64 " = %" PRIu64 " MPS\n",
                    event_count, self->last_send_event_count, elapsed, throughput);
#endif

    thorium_decision_maker_add_data_point(&self->decision_maker, timeout,
                    (int)throughput);

#ifdef MULTIPLEXER_IS_VERBOSE
    if (print)
        thorium_decision_maker_print(&self->decision_maker, timeout);
#endif

    new_timeout = thorium_decision_maker_get_best_timeout(&self->decision_maker,
                    self->timeout_in_nanoseconds);

    if (new_timeout != THORIUM_TIMEOUT_NO_VALUE) {
#ifdef MULTIPLEXER_IS_VERBOSE
        if (print)
            thorium_printf("TIMEOUT -> old value %d new value %d\n",
                            self->timeout_in_nanoseconds,
                            new_timeout);
#endif

        self->timeout_in_nanoseconds = new_timeout;
    }

    self->last_update_time = now;
    self->last_time = now_nanoseconds;
    self->last_send_event_count = event_count;
}
コード例 #11
0
ファイル: timer.c プロジェクト: bioparr/biosal
void core_timer_start(struct core_timer *timer)
{
    timer->start = core_timer_get_nanoseconds(timer);
    timer->started = 1;
}
コード例 #12
0
ファイル: worker.c プロジェクト: huyba/biosal
void thorium_worker_init(struct thorium_worker *worker, int name, struct thorium_node *node)
{
    int capacity;
    int ephemeral_memory_block_size;
    int injected_buffer_ring_size;
    int argc;
    char **argv;

    worker->tick_count = 0;

    thorium_load_profiler_init(&worker->profiler);

    argc = thorium_node_argc(node);
    argv = thorium_node_argv(node);

#ifdef THORIUM_WORKER_DEBUG_INJECTION
    worker->counter_allocated_outbound_buffers = 0;
    worker->counter_freed_outbound_buffers_from_self = 0;
    worker->counter_freed_outbound_buffers_from_other_workers = 0;
    worker->counter_injected_outbound_buffers_other_local_workers= 0;
    worker->counter_injected_inbound_buffers_from_thorium_core = 0;
#endif

    core_map_init(&worker->actor_received_messages, sizeof(int), sizeof(int));

    worker->waiting_is_enabled = 0;
    worker->waiting_start_time = 0;

    core_timer_init(&worker->timer);
    capacity = THORIUM_WORKER_RING_CAPACITY;
    /*worker->work_queue = work_queue;*/
    worker->node = node;
    worker->name = name;
    core_bitmap_clear_bit_uint32_t(&worker->flags, FLAG_DEAD);
    worker->last_warning = 0;

    worker->last_wake_up_count = 0;

    /*worker->work_queue = &worker->works;*/

    /* There are two options:
     * 1. enable atomic operations for change visibility
     * 2. Use volatile head and tail.
     */
    core_fast_ring_init(&worker->actors_to_schedule, capacity, sizeof(struct thorium_actor *));

#ifdef THORIUM_NODE_INJECT_CLEAN_WORKER_BUFFERS
    injected_buffer_ring_size = capacity;
    core_fast_ring_init(&worker->injected_clean_outbound_buffers,
                    injected_buffer_ring_size, sizeof(void *));

    core_fast_ring_init(&worker->clean_message_ring_for_triage,
                    injected_buffer_ring_size,
                    sizeof(struct thorium_message));

    core_fast_queue_init(&worker->clean_message_queue_for_triage,
                    sizeof(struct thorium_message));
#endif

    thorium_scheduler_init(&worker->scheduler, thorium_node_name(worker->node),
                    worker->name);
    core_map_init(&worker->actors, sizeof(int), sizeof(int));
    core_map_iterator_init(&worker->actor_iterator, &worker->actors);

    core_fast_ring_init(&worker->outbound_message_queue, capacity, sizeof(struct thorium_message));

    core_fast_queue_init(&worker->outbound_message_queue_buffer, sizeof(struct thorium_message));

    core_bitmap_clear_bit_uint32_t(&worker->flags, FLAG_DEBUG);
    core_bitmap_clear_bit_uint32_t(&worker->flags, FLAG_BUSY);
    core_bitmap_clear_bit_uint32_t(&node->flags, FLAG_ENABLE_ACTOR_LOAD_PROFILER);

    worker->flags = 0;
    core_bitmap_clear_bit_uint32_t(&worker->flags, FLAG_DEBUG_ACTORS);

    if (core_command_has_argument(argc, argv, DEBUG_WORKER_OPTION)) {

#if 0
        printf("DEBUG has option %s\n", DEBUG_WORKER_OPTION);
#endif

        if (thorium_node_name(worker->node) == 0
                    && thorium_worker_name(worker) == 0) {

#if 0
            printf("DEBUG setting bit FLAG_DEBUG_ACTORS because %s\n", DEBUG_WORKER_OPTION);
#endif
            core_bitmap_set_bit_uint32_t(&worker->flags, FLAG_DEBUG_ACTORS);
        }
    }

    worker->epoch_used_nanoseconds = 0;
    worker->loop_used_nanoseconds = 0;
    worker->scheduling_epoch_used_nanoseconds = 0;

    worker->started_in_thread = 0;

/* 2 MiB is the default size for Linux huge pages.
 * \see https://wiki.debian.org/Hugepages
 * \see http://lwn.net/Articles/376606/
 */

    /*
     * 8 MiB
     */
    ephemeral_memory_block_size = 8388608;
    /*ephemeral_memory_block_size = 16777216;*/
    core_memory_pool_init(&worker->ephemeral_memory, ephemeral_memory_block_size,
                    MEMORY_POOL_NAME_WORKER_EPHEMERAL);

    core_memory_pool_disable_tracking(&worker->ephemeral_memory);
    core_memory_pool_enable_ephemeral_mode(&worker->ephemeral_memory);

#ifdef THORIUM_WORKER_ENABLE_LOCK
    core_lock_init(&worker->lock);
#endif

    core_set_init(&worker->evicted_actors, sizeof(int));

    core_memory_pool_init(&worker->outbound_message_memory_pool,
                    CORE_MEMORY_POOL_MESSAGE_BUFFER_BLOCK_SIZE, MEMORY_POOL_NAME_WORKER_OUTBOUND);

    /*
     * Disable the pool so that it uses allocate and free
     * directly.
     */

#ifdef CORE_MEMORY_POOL_DISABLE_MESSAGE_BUFFER_POOL
    core_memory_pool_disable(&worker->outbound_message_memory_pool);
#endif

    /*
     * Transport message buffers are fancy objects.
     */
    core_memory_pool_enable_normalization(&worker->outbound_message_memory_pool);
    core_memory_pool_enable_alignment(&worker->outbound_message_memory_pool);

    worker->ticks_without_production = 0;

    thorium_priority_assigner_init(&worker->assigner, thorium_worker_name(worker));

    /*
     * This variables should be set in
     * thorium_worker_start, but when running on 1 process with 1 thread,
     * thorium_worker_start is never called...
     */
    worker->last_report = time(NULL);
    worker->epoch_start_in_nanoseconds = core_timer_get_nanoseconds(&worker->timer);
    worker->loop_start_in_nanoseconds = worker->epoch_start_in_nanoseconds;
    worker->loop_end_in_nanoseconds = worker->loop_start_in_nanoseconds;
    worker->scheduling_epoch_start_in_nanoseconds = worker->epoch_start_in_nanoseconds;

    /*
     * Avoid valgrind warnings.
     */
    worker->epoch_load = 0;
}
コード例 #13
0
ファイル: worker.c プロジェクト: huyba/biosal
void thorium_worker_check_production(struct thorium_worker *worker, int value, int name)
{
    uint64_t time;
    uint64_t elapsed;
    struct thorium_actor *other_actor;
    int mailbox_size;
    int status;
    uint64_t threshold;

    /*
     * If no actor is scheduled to run, things are getting out of hand
     * and this is bad for business.
     *
     * So, here, an actor is poked for inactivity
     */
    if (!value) {
        ++worker->ticks_without_production;
    } else {
        worker->ticks_without_production = 0;
    }

    /*
     * If too many cycles were spent doing nothing,
     * check the fast ring since there could be issue in the
     * cache coherency of the CPU, even with the memory fences.
     *
     * This should not happen theoretically.
     *
     */
    if (worker->ticks_without_production >= THORIUM_WORKER_UNPRODUCTIVE_TICK_LIMIT) {

        if (core_map_iterator_get_next_key_and_value(&worker->actor_iterator, &name, NULL)) {

            other_actor = thorium_node_get_actor_from_name(worker->node, name);

            mailbox_size = 0;
            if (other_actor != NULL) {
                mailbox_size = thorium_actor_get_mailbox_size(other_actor);
            }

            if (mailbox_size > 0) {
                thorium_scheduler_enqueue(&worker->scheduler, other_actor);

                status = STATUS_QUEUED;
                core_map_update_value(&worker->actors, &name, &status);
            }
        } else {

            /* Rewind the iterator.
             */
            core_map_iterator_destroy(&worker->actor_iterator);
            core_map_iterator_init(&worker->actor_iterator, &worker->actors);

            /*worker->ticks_without_production = 0;*/
        }

    /*
     * If there is still nothing, tell the operating system that the thread
     * needs to sleep.
     *
     * The operating system is:
     * - Linux on Cray XE6,
     * - Linux on Cray XC30,
     * - IBM Compute Node Kernel (CNK) on IBM Blue Gene/Q),
     */
        if (worker->waiting_is_enabled) {

            /* This is a first warning
             */
            if (worker->waiting_start_time == 0) {
                worker->waiting_start_time = core_timer_get_nanoseconds(&worker->timer);

            } else {

                time = core_timer_get_nanoseconds(&worker->timer);

                elapsed = time - worker->waiting_start_time;

                threshold = THORIUM_WORKER_UNPRODUCTIVE_MICROSECONDS_FOR_WAIT;

                /* Convert microseconds to nanoseconds
                 */
                threshold *= 1000;

                /* Verify the elapsed time.
                 * There are 1000 nanoseconds in 1 microsecond.
                 */
                if (elapsed >= threshold) {
                    /*
                     * Here, the worker will wait until it receives a signal.
                     * Such a signal will mean that something is ready to be consumed.
                     */

                    /* Reset the time
                     */
                    worker->waiting_start_time = 0;

#ifdef THORIUM_WORKER_DEBUG_WAIT_SIGNAL
                    printf("DEBUG worker/%d will wait, elapsed %d\n",
                                    worker->name, (int)elapsed);
#endif

                    /*
                     */
                    thorium_worker_wait(worker);
                }
            }
        }
    }
}
コード例 #14
0
ファイル: worker.c プロジェクト: huyba/biosal
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
}
コード例 #15
0
ファイル: worker.c プロジェクト: huyba/biosal
void thorium_worker_reset_scheduling_epoch(struct thorium_worker *worker)
{
    worker->scheduling_epoch_start_in_nanoseconds = core_timer_get_nanoseconds(&worker->timer);

    worker->scheduling_epoch_used_nanoseconds = 0;
}