int thorium_cfs_scheduler_dequeue(struct thorium_scheduler *self, struct thorium_actor **actor) { struct thorium_cfs_scheduler *concrete_self; void *key; void *value; uint64_t virtual_runtime; int size; key = NULL; value = NULL; virtual_runtime = 0; concrete_self = self->concrete_self; size = core_red_black_tree_size(&concrete_self->tree); if (size == 0) { return 0; } #ifdef SHOW_TIMELINE if (size >= 10 && self->node == 0 && self->worker == 1) { /* printf("[cfs_scheduler] %d actor are in the timeline\n", size); */ thorium_cfs_scheduler_print(self); } #endif /* * This is O(N) */ key = core_red_black_tree_get_lowest_key(&concrete_self->tree); /* * This is O(1) because the tree always keep a cache of the last node. */ value = core_red_black_tree_get(&concrete_self->tree, key); /* * This is also O(1) because the tree keeps a cache of the last node. */ core_red_black_tree_delete(&concrete_self->tree, key); core_memory_copy(&virtual_runtime, key, sizeof(virtual_runtime)); core_memory_copy(actor, value, sizeof(struct thorium_actor *)); #if 0 printf("CFS dequeue -> virtual_runtime= %" PRIu64 " actor= %d\n", virtual_runtime, thorium_actor_name(*actor)); #endif return 1; }
/* * This is O(n), that is if all thorium nodes have a buffer to flush. */ void thorium_message_multiplexer_test(struct thorium_message_multiplexer *self) { /* * Check if the multiplexer has waited enough. */ int index; struct thorium_multiplexed_buffer *multiplexed_buffer; int buffer_is_ready; #if defined(THORIUM_MULTIPLEXER_USE_TREE) || defined(THORIUM_MULTIPLEXER_USE_HEAP) uint64_t *lowest_key; int *index_bucket; #endif if (CORE_BITMAP_GET_FLAG(self->flags, FLAG_DISABLED)) { return; } #ifdef THORIUM_MULTIPLEXER_TRACK_BUFFERS_WITH_CONTENT /* * Nothing to do, there is nothing to flush * in the system. */ if (core_set_empty(&self->buffers_with_content)) { return; } #endif #if 1 /* * Don't flush anything if the outbound ring is full, * which means there is congestion. * * This means that the throughput is at its maximum value. In that case, * it is better to generate even larger messages. */ if (thorium_worker_has_outbound_traffic_congestion(self->worker)) { return; } #endif #ifdef DEBUG_MULTIPLEXER_TEST if (size >= DEBUG_MINIMUM_COUNT) thorium_printf("DEBUG multiplexer_test buffers with content: %d\n", size); #endif #ifdef CHECK_PREDICTED_TRAFFIC_REDUCTION /* * 0.95 corresponds to 20 actor messages in 1 network message. * 0.90 corresponds to 10 actor messages in 1 network message. */ acceptable_traffic_reduction = 0.90; #endif /* * Get the destination with the oldest buffer. * If this one has not waited enough, then any other more recent * buffer has not waited enough neither. */ while (1) { #ifdef THORIUM_MULTIPLEXER_USE_TREE lowest_key = core_red_black_tree_get_lowest_key(&self->timeline); /* * The timeline is empty. */ if (lowest_key == NULL) return; #elif defined(THORIUM_MULTIPLEXER_USE_HEAP) lowest_key = NULL; core_binary_heap_get_root(&self->timeline, (void **)&lowest_key, (void **)&index_bucket); /* * The timeline is empty. */ if (lowest_key == NULL) return; #elif defined(THORIUM_MULTIPLEXER_USE_QUEUE) if (!core_queue_dequeue(&self->timeline, &index)) { return; } #endif /* * Get the index. * The index is the destination. */ #ifdef THORIUM_MULTIPLEXER_USE_TREE index_bucket = core_red_black_tree_get(&self->timeline, lowest_key); index = *index_bucket; #endif multiplexed_buffer = core_vector_at(&self->buffers, index); buffer_is_ready = thorium_message_multiplexer_buffer_is_ready(self, multiplexed_buffer); /* * The oldest item is too recent. * Therefore, all the others are too recent too * because the timeline is ordered. */ if (!buffer_is_ready) { #ifdef THORIUM_MULTIPLEXER_USE_QUEUE core_queue_enqueue(&self->timeline, &index); #endif return; } #ifdef CHECK_OUTBOUND_THROUGHPUT /* * Don't flush now since the transport layer has already reached its maximum * throughput. */ if (thorium_worker_has_reached_maximum_outbound_throughput(self->worker) && traffic_reduction < acceptable_traffic_reduction) { #ifdef THORIUM_MULTIPLEXER_USE_QUEUE core_queue_enqueue(&self->timeline, &index); #endif return; } #endif /* * Remove the object from the timeline. */ #ifdef THORIUM_MULTIPLEXER_USE_TREE core_red_black_tree_delete(&self->timeline, lowest_key); #elif defined(THORIUM_MULTIPLEXER_USE_HEAP) core_binary_heap_delete_root(&self->timeline); #endif #ifdef VERIFY_TARGET /* * Verify if the buffer can grow more. */ if (!thorium_multiplexed_buffer_has_reached_target(multiplexed_buffer)) { thorium_multiplexed_buffer_set_time(multiplexed_buffer, time); core_red_black_tree_add_key_and_value(&self->timeline, &time, &index); return; } #endif /* * The item won't have content in the case were _flush() * was called elsewhere with FORCE_YES_SIZE. */ #ifdef THORIUM_MULTIPLEXER_TRACK_BUFFERS_WITH_CONTENT if (core_set_find(&self->buffers_with_content, &index)) { #endif thorium_message_multiplexer_flush(self, index, FORCE_YES_TIME); #ifdef THORIUM_MULTIPLEXER_TRACK_BUFFERS_WITH_CONTENT } #endif /* * Otherwise, keep flushing stuff. * This will eventually end anyway. */ } }