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); }
/* * 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; }