int thorium_transport_receive(struct thorium_transport *self, struct thorium_message *message) { int value; if (self->transport_interface == NULL) { return 0; } value = self->transport_interface->receive(self, message); if (value) { #ifdef THORIUM_TRANSPORT_DEBUG printf("TRANSPORT RECEIVE Source %d Destination %d Tag %d Count %d\n", thorium_message_source_node(message), thorium_message_destination_node(message), thorium_message_action(message), thorium_message_count(message)); #endif if (core_bitmap_get_bit_uint32_t(&self->flags, FLAG_PRINT_TRANSPORT_EVENTS)) { thorium_transport_print_event(self, EVENT_TYPE_RECEIVE, message); } } return value; }
void thorium_actor_pack_proxy_message(struct thorium_actor *self, struct thorium_message *message, int real_source) { int real_tag; int count; int new_count; void *buffer; void *new_buffer; int offset; struct core_memory_pool *ephemeral_memory; /* * pack data in this order: * * - data (count bytes) * - real_source * - real_tag */ ephemeral_memory = thorium_actor_get_ephemeral_memory(self); real_tag = thorium_message_action(message); buffer = thorium_message_buffer(message); count = thorium_message_count(message); #ifdef DEBUG_BINOMIAL_TREE printf("DEBUG_BINOMIAL_TREE pack_proxy_message count %d source %d action %x\n", count, thorium_actor_name(self), real_tag); thorium_message_print(message); #endif new_count = count + sizeof(real_source) + sizeof(real_tag); /* use slab allocator */ new_buffer = core_memory_pool_allocate(ephemeral_memory, new_count); #ifdef THORIUM_ACTOR_DEBUG printf("DEBUG12 core_memory_pool_allocate %p (pack proxy message)\n", new_buffer); #endif if (count > 0) core_memory_copy(new_buffer, buffer, count); offset = count; core_memory_copy((char *)new_buffer + offset, &real_source, sizeof(real_source)); offset += sizeof(real_source); core_memory_copy((char *)new_buffer + offset, &real_tag, sizeof(real_tag)); offset += sizeof(real_tag); thorium_message_init(message, ACTION_PROXY_MESSAGE, new_count, new_buffer); thorium_message_set_source(message, real_source); #if 0 /* free the old buffer */ core_memory_free(buffer); buffer = NULL; #endif }
void thorium_actor_send_range_loop(struct thorium_actor *actor, struct core_vector *actors, int first, int last, struct thorium_message *message) { int i; int the_actor; #ifdef THORIUM_ACTOR_DEBUG1 printf("DEBUG thorium_actor_send_range_default%i-%i\n", first, last); #endif i = first; while (i <= last) { #ifdef THORIUM_ACTOR_DEBUG_20140601_1 printf("DEBUG sending %d to %d\n", thorium_message_action(message), i); #endif the_actor = *(int *)core_vector_at(actors, i); #ifdef DEBUG_BINOMIAL_TREE printf("send_range_loop, sending to %d\n", the_actor); thorium_message_print(message); #endif thorium_actor_send(actor, the_actor, message); i++; } }
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; }
void thorium_message_get_all(struct thorium_message *message, int *tag, int *count, void **buffer, int *source) { *tag = thorium_message_action(message); *count = thorium_message_count(message); *buffer = thorium_message_buffer(message); *source = thorium_message_source(message); }
void systolic_receive(struct thorium_actor *actor, struct thorium_message *message) { int tag; int name; void *buffer; struct systolic *systolic1; int i; systolic1 = (struct systolic *)thorium_actor_concrete_actor(actor); tag = thorium_message_action(message); name = thorium_actor_name(actor); buffer = thorium_message_buffer(message); if (tag == ACTION_START) { core_vector_unpack(&systolic1->initial_data, buffer); printf("Hello world ! my name is actor:%d and I have %d acquaintances:", name, (int)core_vector_size(&systolic1->initial_data)); for (i = 0; i < core_vector_size(&systolic1->initial_data); i++) { printf(" actor:%d", core_vector_at_as_int(&systolic1->initial_data, i)); } printf("\n"); thorium_actor_send_to_self_empty(actor, ACTION_STOP); } }
int thorium_transport_send(struct thorium_transport *self, struct thorium_message *message) { int value; if (self->transport_interface == NULL) { return 0; } /* * Send the message through the mock transport which is * a transport profiler. */ if (core_bitmap_get_bit_uint32_t(&self->flags, FLAG_PROFILE)) { thorium_transport_profiler_send_mock(&self->transport_profiler, message); } value = self->transport_interface->send(self, message); if (value) { #ifdef THORIUM_TRANSPORT_DEBUG printf("TRANSPORT SEND Source %d Destination %d Tag %d Count %d\n", thorium_message_source_node(message), thorium_message_destination_node(message), thorium_message_action(message), thorium_message_count(message)); #endif ++self->active_request_count; if (core_bitmap_get_bit_uint32_t(&self->flags, FLAG_PRINT_TRANSPORT_EVENTS)) { thorium_transport_print_event(self, EVENT_TYPE_SEND, message); } } return value; }
void thorium_actor_send_range_default(struct thorium_actor *actor, struct core_vector *actors, int first, int last, struct thorium_message *message) { int use_binomial_tree; struct core_vector destinations; struct core_memory_pool *ephemeral_memory; int name; int action; action = thorium_message_action(message); use_binomial_tree = 0; #ifdef USE_BINOMIAL_TREE /* * ACTION_ASK_TO_STOP basically kills actors (if they agree to). * It is a bad idea to use a binomial tree to send this death signal * since intermediate actors can die before acting as relays. */ if (action != ACTION_ASK_TO_STOP) use_binomial_tree = 1; #endif if (!use_binomial_tree) { thorium_actor_send_range_loop(actor, actors, first, last, message); return; } tracepoint(thorium_binomial_tree, send_range, message, (int)core_vector_size(actors)); /* * Otherwise, use the binomial tree code path. This algorithm is better since it distributed * the sending operations intot a binomial tree where there are a lot of intermediate * actors (to be exact, the number of intermediate actors is close to log2(actors.size)). */ ephemeral_memory = thorium_actor_get_ephemeral_memory(actor); core_vector_init(&destinations, sizeof(int)); core_vector_set_memory_pool(&destinations, ephemeral_memory); CORE_DEBUGGER_ASSERT(core_vector_empty(&destinations)); core_vector_copy_range(actors, first, last, &destinations); /* * Set the source now. */ name = thorium_actor_name(actor); thorium_message_set_source(message, name); thorium_actor_send_range_binomial_tree(actor, &destinations, message); core_vector_destroy(&destinations); }
void biosal_assembly_arc_classifier_receive(struct thorium_actor *self, struct thorium_message *message) { int tag; void *buffer; struct biosal_assembly_arc_classifier *concrete_self; int size; int i; int *bucket; int source; int source_index; if (thorium_actor_take_action(self, message)) { return; } concrete_self = (struct biosal_assembly_arc_classifier *)thorium_actor_concrete_actor(self); tag = thorium_message_action(message); buffer = thorium_message_buffer(message); source = thorium_message_source(message); if (tag == ACTION_SET_CONSUMERS) { core_vector_unpack(&concrete_self->consumers, buffer); size = core_vector_size(&concrete_self->consumers); core_vector_resize(&concrete_self->pending_requests, size); for (i = 0; i < size; i++) { core_vector_set_int(&concrete_self->pending_requests, i, 0); } thorium_actor_send_reply_empty(self, ACTION_SET_CONSUMERS_REPLY); } else if (tag == ACTION_ASSEMBLY_PUSH_ARC_BLOCK_REPLY){ /* * Decrease counter now. */ source_index = core_vector_index_of(&concrete_self->consumers, &source); bucket = core_vector_at(&concrete_self->pending_requests, source_index); --(*bucket); --concrete_self->active_requests; /* * The previous value was maximum_pending_request_count + 1 */ if (*bucket == concrete_self->maximum_pending_request_count) { --concrete_self->consumer_count_above_threshold; } biosal_assembly_arc_classifier_verify_counters(self); } }
void thorium_message_init_copy(struct thorium_message *self, struct thorium_message *old_message) { thorium_message_init(self, thorium_message_action(old_message), thorium_message_count(old_message), thorium_message_buffer(old_message)); thorium_message_set_source(self, thorium_message_source(old_message)); thorium_message_set_destination(self, thorium_message_destination(old_message)); }
void buddy_receive(struct thorium_actor *actor, struct thorium_message *message) { int tag; int source; int name; name = thorium_actor_name(actor); source = thorium_message_source(message); tag = thorium_message_action(message); if (tag == ACTION_BUDDY_BOOT) { printf("ACTION_BUDDY_BOOT\n"); thorium_actor_print(actor); thorium_message_init(message, ACTION_BUDDY_BOOT_REPLY, 0, NULL); thorium_actor_send(actor, source, message); } else if (tag == ACTION_BUDDY_HELLO) { printf("ACTION_BUDDY_HELLO\n"); /* pin the actor to the worker for no reason ! */ /* thorium_actor_send_to_self_empty(actor, ACTION_PIN_TO_WORKER); */ thorium_message_init(message, ACTION_BUDDY_HELLO_REPLY, 0, NULL); thorium_actor_send(actor, source, message); } else if (tag == ACTION_ASK_TO_STOP) { printf("BUDDY_DIE\n"); printf("buddy_receive Actor %i received a message (%i BUDDY_DIE) from actor %i\n", name, tag, source); /* thorium_actor_send_to_self_empty(actor, ACTION_UNPIN_FROM_WORKER); */ thorium_message_init(message, ACTION_STOP, 0, NULL); thorium_actor_send(actor, name, message); } }
/* hello-hello_receive */ void hello_receive(struct thorium_actor *self, struct thorium_message *message) { int tag; int name; void *buffer; struct hello *concrete_self; struct core_vector data_vector; int i; int action = thorium_message_action(message); concrete_self = thorium_actor_concrete_actor(self); name = thorium_actor_name(self); buffer = thorium_message_buffer(message); thorium_actor_log(self, "received action %d\n", action); if (action == ACTION_START) { thorium_message_print(message); printf("\n"); /* * Send a ping message to self. */ thorium_actor_send_reply_empty(self, ACTION_MY_PING); } if (action == ACTION_MY_PING) { thorium_actor_send_reply_empty(self, ACTION_MY_PONG); } if (action == ACTION_MY_PONG) { thorium_actor_send_reply_empty(self, ACTION_ASK_TO_STOP); } if (action == ACTION_ASK_TO_STOP) { thorium_actor_send_reply_empty(self, ACTION_STOP); } }
void ring_receive(struct thorium_actor *actor, struct thorium_message *message) { int tag; int new_actor; int previous; int name; struct ring *concrete_actor; int messages; int previous_actor; char *buffer; int destination; concrete_actor = (struct ring *)thorium_actor_concrete_actor(actor); tag = thorium_message_action(message); buffer = thorium_message_buffer(message); name = thorium_actor_name(actor); if (tag == ACTION_START) { core_vector_init(&concrete_actor->spawners, 0); core_vector_unpack(&concrete_actor->spawners, buffer); printf("actor %d ACTION_START, %d spawners\n", name, (int)core_vector_size(&concrete_actor->spawners)); destination = *(int *)core_vector_at(&concrete_actor->spawners, 0); thorium_actor_send_empty(actor, destination, ACTION_RING_READY); } else if (tag == ACTION_RING_READY && concrete_actor->step == RING_STEP_RECEIVE_SPAWNERS) { concrete_actor->ready_rings++; if (concrete_actor->ready_rings == (int)core_vector_size(&concrete_actor->spawners)) { thorium_actor_send_range_empty(actor, &concrete_actor->spawners, ACTION_RING_SPAWN); concrete_actor->step = RING_STEP_SPAWN; concrete_actor->ready_rings = 0; } } else if (tag == ACTION_RING_SPAWN) { printf("actor/%d is spawning %d senders\n", thorium_actor_name(actor), concrete_actor->senders); concrete_actor->step = RING_STEP_SPAWN; new_actor = thorium_actor_spawn(actor, SCRIPT_SENDER); concrete_actor->first = new_actor; previous = new_actor; new_actor = thorium_actor_spawn(actor, SCRIPT_SENDER); concrete_actor->previous = new_actor; thorium_message_init(message, ACTION_SENDER_SET_NEXT, sizeof(new_actor), &new_actor); thorium_actor_send(actor, previous, message); ++concrete_actor->spawned_senders; ++concrete_actor->spawned_senders; } else if (tag == ACTION_RING_READY && concrete_actor->step == RING_STEP_SPAWN) { concrete_actor->ready_rings++; #if 0 printf("READY: %d/%d\n", concrete_actor->ready_rings, (int)core_vector_size(&concrete_actor->spawners)); #endif if (concrete_actor->ready_rings == core_vector_size(&concrete_actor->spawners)) { thorium_actor_send_range_empty(actor, &concrete_actor->spawners, ACTION_RING_PUSH_NEXT); concrete_actor->ready_rings = 0; concrete_actor->step = RING_STEP_PUSH_NEXT; } } else if (tag == ACTION_RING_PUSH_NEXT) { previous_actor = core_vector_index_of(&concrete_actor->spawners, &name) - 1; if (previous_actor < 0) { previous_actor = core_vector_size(&concrete_actor->spawners)- 1; } printf("%d received ACTION_RING_PUSH_NEXT\n", name); thorium_message_init(message, ACTION_RING_SET_NEXT, sizeof(concrete_actor->first), &concrete_actor->first); thorium_actor_send(actor, *(int *)core_vector_at(&concrete_actor->spawners, previous_actor), message); } else if (tag == ACTION_RING_SET_NEXT) { concrete_actor->step = RING_STEP_PUSH_NEXT; thorium_message_set_action(message, ACTION_SENDER_SET_NEXT); thorium_actor_send(actor, concrete_actor->last, message); } else if (tag == ACTION_SENDER_SET_NEXT_REPLY && concrete_actor->step == RING_STEP_SPAWN) { #if 0 printf("ready senders %d/%d\n", concrete_actor->ready_senders, concrete_actor->senders); #endif if (concrete_actor->spawned_senders % 10000 == 0) { printf("spawned %d/%d\n", concrete_actor->spawned_senders, concrete_actor->senders); } if (concrete_actor->spawned_senders == concrete_actor->senders) { printf("RING_STEP_SPAWN completed.\n"); thorium_actor_send_empty(actor, *(int *)core_vector_at(&concrete_actor->spawners, 0), ACTION_RING_READY); concrete_actor->ready_senders = 0; concrete_actor->last = concrete_actor->previous; } else { new_actor = thorium_actor_spawn(actor, SCRIPT_SENDER); ++concrete_actor->spawned_senders; previous = concrete_actor->previous; thorium_message_init(message, ACTION_SENDER_SET_NEXT, sizeof(new_actor), &new_actor); thorium_actor_send(actor, previous, message); concrete_actor->previous = new_actor; } } else if (tag == ACTION_SENDER_SET_NEXT_REPLY && concrete_actor->step == RING_STEP_PUSH_NEXT) { concrete_actor->ready_senders++; printf("ACTION_SENDER_SET_NEXT_REPLY %d/%d\n", concrete_actor->ready_senders, 1); if (concrete_actor->ready_senders == 1) { thorium_actor_send_empty(actor, *(int *)core_vector_at(&concrete_actor->spawners, 0), ACTION_RING_READY); printf("RING_STEP_PUSH_NEXT completed.\n"); concrete_actor->ready_senders = 0; } } else if (tag == ACTION_RING_READY && concrete_actor->step == RING_STEP_PUSH_NEXT) { concrete_actor->ready_rings++; if (concrete_actor->ready_rings == core_vector_size(&concrete_actor->spawners)) { printf("system is ready...\n"); messages = 2000007; thorium_message_init(message, ACTION_SENDER_HELLO, sizeof(messages), &messages); thorium_actor_send(actor, concrete_actor->first, message); concrete_actor->ready_rings = 0; } } else if (tag == ACTION_SENDER_HELLO_REPLY) { thorium_actor_send_range_empty(actor, &concrete_actor->spawners, ACTION_RING_KILL); thorium_actor_send_empty(actor, concrete_actor->first, ACTION_SENDER_KILL); } else if (tag == ACTION_RING_KILL) { thorium_actor_send_to_self_empty(actor, ACTION_STOP); } }
static void source_receive(struct thorium_actor *self, struct thorium_message *message) { int action; void *buffer; int leader; int source; int count; struct source *concrete_self; int name; concrete_self = (struct source *)thorium_actor_concrete_actor(self); action = thorium_message_action(message); buffer = thorium_message_buffer(message); source = thorium_message_source(message); name = thorium_actor_name(self); count = thorium_message_count(message); if (action == ACTION_ASK_TO_STOP) { thorium_actor_log(self, "sent %d ACTION_PING messages\n", concrete_self->message_count); thorium_actor_send_to_self_empty(self, ACTION_STOP); } else if (action == ACTION_NOTIFY) { #ifdef LATENCY_PROBE_USE_MULTIPLEXER thorium_actor_send_to_self_empty(self, ACTION_ENABLE_MULTIPLEXER); #endif CORE_DEBUGGER_ASSERT(core_vector_empty(&concrete_self->targets)); core_vector_unpack(&concrete_self->targets, buffer); if (source_is_important(self)) { printf("%d (node %d worker %d) has %d targets\n", thorium_actor_name(self), thorium_actor_node_name(self), thorium_actor_worker_name(self), (int)core_vector_size(&concrete_self->targets)); } concrete_self->leader = source; source_send_ping(self); } else if (action == ACTION_PING_REPLY) { CORE_DEBUGGER_ASSERT(count == 0); ++concrete_self->message_count; CORE_DEBUGGER_ASSERT_IS_EQUAL_INT(count, 0); CORE_DEBUGGER_ASSERT_IS_NULL(buffer); if (concrete_self->message_count % PERIOD == 0 || concrete_self->event_count < 500) { if (source_is_important(self)) { printf("progress %d %d/%d\n", name, concrete_self->message_count, concrete_self->event_count); } } if (concrete_self->message_count == concrete_self->event_count) { leader = concrete_self->leader; thorium_actor_send_empty(self, leader, ACTION_NOTIFY_REPLY); if (source_is_important(self)) printf("%d (ACTION_PING sent: %d)" " sends ACTION_NOTIFY_REPLY to %d\n", thorium_actor_name(self), concrete_self->message_count, leader); } else { source_send_ping(self); } } }
void table_receive(struct thorium_actor *actor, struct thorium_message *message) { int tag; int source; int name; int remote; struct thorium_message spawn_message; int script; int new_actor; void *buffer; struct table *table1; table1 = (struct table *)thorium_actor_concrete_actor(actor); source = thorium_message_source(message); tag = thorium_message_action(message); name = thorium_actor_name(actor); buffer = thorium_message_buffer(message); if (tag == ACTION_START) { printf("Actor %i receives ACTION_START from actor %i\n", name, source); core_vector_init(&table1->spawners, 0); core_vector_unpack(&table1->spawners, buffer); remote = core_vector_index_of(&table1->spawners, &name) + 1; remote %= core_vector_size(&table1->spawners); script = SCRIPT_TABLE; thorium_message_init(&spawn_message, ACTION_SPAWN, sizeof(script), &script); thorium_actor_send(actor, *(int *)core_vector_at(&table1->spawners, remote), &spawn_message); /* printf("sending notification\n"); thorium_message_init(message, ACTION_TABLE_NOTIFY, 0, NULL); thorium_actor_send(actor, 0, message); */ } else if (tag == ACTION_SPAWN_REPLY) { new_actor= *(int *)buffer; printf("Actor %i receives ACTION_SPAWN_REPLY from actor %i," " new actor is %d\n", name, source, new_actor); thorium_message_init(message, ACTION_TABLE_DIE2, 0, NULL); thorium_actor_send(actor, new_actor, message); thorium_message_init(message, ACTION_TABLE_NOTIFY, 0, NULL); thorium_actor_send(actor, core_vector_at_as_int(&table1->spawners, 0), message); } else if (tag == ACTION_TABLE_DIE2) { printf("Actor %i receives ACTION_TABLE_DIE2 from actor %i\n", name, source); if (name < core_vector_size(&table1->spawners)) { return; } thorium_message_init(message, ACTION_STOP, 0, NULL); thorium_actor_send(actor, name, message); } else if (tag == ACTION_TABLE_DIE) { printf("Actor %i receives ACTION_TABLE_DIE from actor %i\n", name, source); thorium_message_init(message, ACTION_STOP, 0, NULL); thorium_actor_send(actor, name, message); } else if (tag == ACTION_TABLE_NOTIFY) { printf("Actor %i receives ACTION_TABLE_NOTIFY from actor %i\n", name, source); table1->done++; if (table1->done == core_vector_size(&table1->spawners)) { printf("actor %d kills %d to %d\n", name, 0, (int)core_vector_size(&table1->spawners) - 1); thorium_message_init(message, ACTION_TABLE_DIE, 0, NULL); thorium_actor_send_range(actor, &table1->spawners, message); } } }
void frame_receive(struct thorium_actor *actor, struct thorium_message *message) { int tag; int name; void *buffer; struct frame *concrete_actor; int other; struct core_vector initial_actors; struct core_vector *acquaintance_vector; int source; source = thorium_message_source(message); concrete_actor = (struct frame *)thorium_actor_concrete_actor(actor); tag = thorium_message_action(message); name = thorium_actor_name(actor); buffer = thorium_message_buffer(message); acquaintance_vector = &concrete_actor->acquaintance_vector; if (tag == ACTION_START) { core_vector_init(&initial_actors, sizeof(int)); core_vector_unpack(&initial_actors, buffer); core_vector_push_back_vector(acquaintance_vector, &initial_actors); core_vector_destroy(&initial_actors); other = thorium_actor_spawn(actor, thorium_actor_script(actor)); core_vector_push_back_int(acquaintance_vector, other); thorium_actor_send_empty(actor, other, ACTION_PING); printf("actor %d sends ACTION_PING to new actor %d\n", name, other); } else if (tag == ACTION_PING) { /* new acquaintance */ core_vector_push_back(acquaintance_vector, &source); printf("actor %d (value %d) receives ACTION_PING from actor %d\n", name, concrete_actor->value, source); printf("Acquaintances of actor %d: ", name); core_vector_print_int(acquaintance_vector); printf("\n"); thorium_actor_send_reply_empty(actor, ACTION_PING_REPLY); } else if (tag == ACTION_PING_REPLY) { concrete_actor->pings++; printf("actor %d receives ACTION_PING_REPLY from actor %d\n", name, source); /* kill the system */ if (concrete_actor->migrated_other && concrete_actor->pings == 2) { thorium_actor_send_reply_empty(actor, ACTION_ASK_TO_STOP); thorium_actor_send_to_self_empty(actor, ACTION_ASK_TO_STOP); return; } /* migrate other actor */ printf("actor %d asks actor %d to migrate using actor %d as spawner\n", name, source, name); printf("Acquaintances of actor %d: ", name); core_vector_print_int(acquaintance_vector); printf("\n"); thorium_actor_send_reply_int(actor, ACTION_MIGRATE, name); /* send a message to other while it is migrating. * this is supposed to work ! */ printf("actor %d sends ACTION_PING to %d while it is migrating\n", name, source); thorium_actor_send_reply_empty(actor, ACTION_PING); concrete_actor->migrated_other = 1; } else if (tag == ACTION_MIGRATE_REPLY) { thorium_message_unpack_int(message, 0, &other); printf("actor %d received migrated actor %d\n", name, other); printf("Acquaintances of actor %d: ", name); core_vector_print_int(acquaintance_vector); printf("\n"); /* it is possible that the ACTION_PING went through * before the migration */ if (concrete_actor->pings == 2) { thorium_actor_send_reply_empty(actor, ACTION_ASK_TO_STOP); thorium_actor_send_to_self_empty(actor, ACTION_ASK_TO_STOP); } } else if (tag == ACTION_PACK) { thorium_actor_send_reply_int(actor, ACTION_PACK_REPLY, concrete_actor->value); } else if (tag == ACTION_UNPACK) { thorium_message_unpack_int(message, 0, &concrete_actor->value); thorium_actor_send_reply_empty(actor, ACTION_UNPACK_REPLY); } else if (tag == ACTION_ASK_TO_STOP) { printf("actor %d received ACTION_ASK_TO_STOP, value: %d ", name, concrete_actor->value); printf("acquaintance vector: "); core_vector_print_int(acquaintance_vector); printf("\n"); thorium_actor_send_to_self_empty(actor, ACTION_STOP); } }
void reader_receive(struct thorium_actor *actor, struct thorium_message *message) { int tag; int argc; char **argv; /*int i;*/ int name; struct reader *reader1; int source; uint64_t count; void *buffer; int sequences; int script; int sequence_index; char *received_sequence; int error; reader1 = (struct reader *)thorium_actor_concrete_actor(actor); tag = thorium_message_action(message); source = thorium_message_source(message); buffer = thorium_message_buffer(message); name = thorium_actor_name(actor); if (tag == ACTION_START) { core_vector_init(&reader1->spawners, 0); core_vector_unpack(&reader1->spawners, buffer); argc = thorium_actor_argc(actor); argv = thorium_actor_argv(actor); name = thorium_actor_name(actor); reader1->last_report = 0; /* printf("actor %i received %i arguments\n", name, argc); for (i = 0; i < argc ;i++) { printf(" argument %i : %s\n", i, argv[i]); } */ if (core_vector_index_of(&reader1->spawners, &name) != 0) { thorium_message_init(message, ACTION_STOP, 0, NULL); thorium_actor_send(actor, name, message); return; } if (argc == 1) { thorium_message_init(message, ACTION_STOP, 0, NULL); thorium_actor_send(actor, name, message); return; } reader1->sequence_reader = thorium_actor_spawn(actor, SCRIPT_INPUT_STREAM); reader1->file = argv[argc - 1]; thorium_message_init(message, ACTION_INPUT_OPEN, strlen(reader1->file) + 1, reader1->file); printf("actor %i: asking actor %i to count entries in %s\n", name, reader1->sequence_reader, reader1->file); thorium_actor_send(actor, reader1->sequence_reader, message); } else if (tag == ACTION_INPUT_COUNT_PROGRESS) { sequences = *(int64_t *)buffer; if (sequences < reader1->last_report + 10000000) { return; } printf("Actor %i received a progress report from actor %i: %i\n", name, source, sequences); reader1->last_report = sequences; } else if (tag == ACTION_INPUT_OPEN_REPLY && !reader1->counted) { thorium_message_unpack_int(message, 0, &error); if (error == BIOSAL_INPUT_ERROR_NO_ERROR) { printf("Successfully opened file.\n"); thorium_actor_send_reply_empty(actor, ACTION_INPUT_COUNT); } else if (error == BIOSAL_INPUT_ERROR_FILE_NOT_FOUND) { printf("Error, file not found! \n"); thorium_actor_send_to_self_empty(actor, ACTION_STOP); } else if (error == BIOSAL_INPUT_ERROR_FORMAT_NOT_SUPPORTED) { printf("Error, format not supported! \n"); thorium_actor_send_to_self_empty(actor, ACTION_STOP); } } else if (tag == ACTION_INPUT_COUNT_REPLY) { count = *(int64_t*)thorium_message_buffer(message); printf("actor %i: file has %" PRIu64 " items\n", name, count); thorium_message_init(message, ACTION_INPUT_CLOSE, 0, NULL); thorium_actor_send(actor, source, message); reader1->counted = 1; } else if (tag == ACTION_INPUT_CLOSE_REPLY && !reader1->pulled) { /* not necessary, it is already dead. */ thorium_actor_send_reply_empty(actor, ACTION_ASK_TO_STOP); printf("actor %d received ACTION_INPUT_CLOSE_REPLY from actor %d, asking it to stop" " with ACTION_ASK_TO_STOP\n", name, source); /* thorium_message_init(message, ACTION_STOP, 0, NULL); thorium_actor_send(actor, name, message); return; */ script = SCRIPT_INPUT_STREAM; thorium_message_init(message, ACTION_SPAWN, sizeof(script), &script); thorium_actor_send(actor, name, message); } else if (tag == ACTION_INPUT_CLOSE_REPLY && reader1->pulled) { thorium_actor_send_reply_empty(actor, ACTION_ASK_TO_STOP); thorium_actor_send_to_self_empty(actor, ACTION_STOP); } else if (tag == ACTION_ASK_TO_STOP_REPLY && reader1->pulled) { /* this tag will never arrive here */ thorium_message_init(message, ACTION_STOP, 0, NULL); thorium_actor_send(actor, name, message); } else if (tag == ACTION_SPAWN_REPLY && source == name) { reader1->sequence_reader = *(int *)buffer; printf("actor %d tells actor %d to open %s to pull sequences from the file\n", name, reader1->sequence_reader, reader1->file); thorium_message_init(message, ACTION_INPUT_OPEN, strlen(reader1->file) + 1, reader1->file); thorium_actor_send(actor, reader1->sequence_reader, message); } else if (tag == ACTION_INPUT_OPEN_REPLY && reader1->counted) { thorium_message_init(message, ACTION_INPUT_GET_SEQUENCE, 0, NULL); thorium_actor_send(actor, source, message); } else if (tag == ACTION_INPUT_GET_SEQUENCE_REPLY) { sequence_index = *(int *)buffer; received_sequence = (char*)buffer + sizeof(sequence_index); /* printf("DEBUG %d %s\n", sequence_index, received_sequence); */ if (sequence_index == 123456) { printf("actor %d says that sequence %d is %s.\n", name, sequence_index, received_sequence); } else if (sequence_index % 100000 == 0) { printf("actor %d is pulling sequences from fellow local actor %d," " %d sequences pulled so far !\n", name, reader1->sequence_reader, sequence_index); } if (sequence_index < 1000000) { thorium_message_init(message, ACTION_INPUT_GET_SEQUENCE, 0, NULL); thorium_actor_send(actor, source, message); } else { thorium_message_init(message, ACTION_INPUT_CLOSE, 0, NULL); thorium_actor_send(actor, source, message); reader1->pulled = 1; } } else if (tag == ACTION_INPUT_GET_SEQUENCE_END) { printf("actor %d: reached the end...\n", name); thorium_message_init(message, ACTION_INPUT_CLOSE, 0, NULL); thorium_actor_send(actor, source, message); reader1->pulled = 1; } }
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 }
int thorium_balancer_select_worker_least_busy( struct thorium_balancer *self, int *worker_score) { int to_check; int score; int best_score; struct thorium_worker *worker; struct thorium_worker *best_worker; int selected_worker; #if 0 int last_worker_score; #endif #ifdef THORIUM_WORKER_DEBUG int tag; int destination; struct thorium_message *message; #endif best_worker = NULL; best_score = 99; to_check = THORIUM_SCHEDULER_WORK_SCHEDULING_WINDOW; while (to_check--) { /* * get the worker to test for this iteration. */ worker = thorium_worker_pool_get_worker(self->pool, self->worker_for_work); score = thorium_worker_get_epoch_load(worker); #ifdef THORIUM_WORKER_POOL_DEBUG_ISSUE_334 if (score >= THORIUM_WORKER_WARNING_THRESHOLD && (self->last_scheduling_warning == 0 || score >= self->last_scheduling_warning + THORIUM_WORKER_WARNING_THRESHOLD_STRIDE)) { printf("Warning: node %d worker %d has a scheduling score of %d\n", thorium_node_name(thorium_worker_pool_get_node(self->pool)), self->worker_for_work, score); self->last_scheduling_warning = score; } #endif /* if the worker is not busy and it has no work to do, * select it right away... */ if (score == 0) { best_worker = worker; best_score = 0; break; } /* Otherwise, test the worker */ if (best_worker == NULL || score < best_score) { best_worker = worker; best_score = score; } /* * assign the next worker */ self->worker_for_work = thorium_worker_pool_next_worker(self->pool, self->worker_for_work); } #ifdef THORIUM_WORKER_POOL_DEBUG message = biosal_work_message(work); tag = thorium_message_action(message); destination = thorium_message_destination(message); if (tag == ACTION_ASK_TO_STOP) { printf("DEBUG dispatching ACTION_ASK_TO_STOP for actor %d to worker %d\n", destination, *start); } #endif selected_worker = self->worker_for_work; /* * assign the next worker */ self->worker_for_work = thorium_worker_pool_next_worker(self->pool, self->worker_for_work); *worker_score = best_score; /* This is a best effort algorithm */ return selected_worker; }
void biosal_input_stream_receive(struct thorium_actor *actor, struct thorium_message *message) { int tag; int source; uint64_t count; struct biosal_input_stream *concrete_self; int i; int has_sequence; int sequences; int sequence_index; int buffer_size; char *buffer; char *read_buffer; struct biosal_mega_block mega_block; char *file_name_in_buffer; if (thorium_actor_take_action(actor, message)) { return; } concrete_self = thorium_actor_concrete_actor(actor); tag = thorium_message_action(message); source = thorium_message_source(message); buffer = (char *)thorium_message_buffer(message); /* Do nothing if there is an error. * has_error returns the error to the source. */ /* if (biosal_input_stream_has_error(actor, message)) { return; } */ if (tag == ACTION_INPUT_OPEN) { #ifdef BIOSAL_INPUT_STREAM_DEBUG printf("DEBUG ACTION_INPUT_OPEN\n"); #endif if (concrete_self->open) { concrete_self->error = BIOSAL_INPUT_ERROR_ALREADY_OPEN; thorium_actor_send_reply_int(actor, ACTION_INPUT_OPEN_REPLY, concrete_self->error); thorium_actor_send_to_self_empty(actor, ACTION_ASK_TO_STOP); return; } concrete_self->open = 1; /* TODO: find out the maximum read length in some way */ concrete_self->maximum_sequence_length = BIOSAL_INPUT_MAXIMUM_SEQUENCE_LENGTH; concrete_self->buffer_for_sequence = (char *)core_memory_allocate(concrete_self->maximum_sequence_length, MEMORY_INPUT_STREAM); /*biosal_input_stream_init(actor);*/ #ifdef BIOSAL_INPUT_STREAM_DEBUG printf("DEBUG biosal_input_stream_receive open %s\n", buffer); #endif /*core_memory_copy(&concrete_self->file_index, buffer, sizeof(concrete_self->file_index));*/ file_name_in_buffer = buffer; printf("stream/%d (node/%d) opens file %s offset %" PRIu64 "\n", thorium_actor_name(actor), thorium_actor_node_name(actor), file_name_in_buffer, concrete_self->starting_offset); #ifdef DEBUG_ISSUE_594 thorium_message_print(message); printf("Buffer %s\n", buffer); #endif concrete_self->file_name = core_memory_allocate(strlen(file_name_in_buffer) + 1, MEMORY_INPUT_STREAM); strcpy(concrete_self->file_name, file_name_in_buffer); biosal_input_proxy_init(&concrete_self->proxy, concrete_self->file_name, concrete_self->starting_offset, concrete_self->ending_offset); concrete_self->proxy_ready = 1; /* Die if there is an error... */ if (biosal_input_stream_has_error(actor, message)) { #ifdef BIOSAL_INPUT_STREAM_DEBUG printf("DEBUG has error\n"); #endif thorium_actor_send_reply_int(actor, ACTION_INPUT_OPEN_REPLY, concrete_self->error); thorium_actor_send_to_self_empty(actor, ACTION_ASK_TO_STOP); return; } concrete_self->controller = source; /* no error here... */ thorium_actor_send_reply_int(actor, ACTION_INPUT_OPEN_REPLY, concrete_self->error); } else if (tag == ACTION_INPUT_COUNT) { /* count a little bit and yield the worker */ if (concrete_self->count_customer == THORIUM_ACTOR_NOBODY) { concrete_self->count_customer = source; } if (biosal_input_stream_check_open_error(actor, message)) { thorium_actor_send_reply_int64_t(actor, ACTION_INPUT_COUNT_REPLY, concrete_self->error); thorium_actor_send_to_self_empty(actor, ACTION_ASK_TO_STOP); return; } #ifdef BIOSAL_INPUT_STREAM_DEBUG printf("DEBUG ACTION_INPUT_COUNT received...\n"); #endif i = 0; /* continue counting ... */ has_sequence = 1; while (i < concrete_self->granularity && has_sequence) { has_sequence = biosal_input_proxy_get_sequence(&concrete_self->proxy, concrete_self->buffer_for_sequence); #if 0 printf("Sequence= %s\n", concrete_self->buffer_for_sequence); #endif i++; } sequences = biosal_input_proxy_size(&concrete_self->proxy); #ifdef BIOSAL_INPUT_STREAM_DEBUG printf("DEBUG ACTION_INPUT_COUNT sequences %d...\n", sequences); #endif if (!has_sequence || sequences % concrete_self->mega_block_size == 0) { biosal_mega_block_init(&mega_block, -1, concrete_self->last_offset, sequences - concrete_self->last_entries, sequences); core_vector_push_back(&concrete_self->mega_blocks, &mega_block); concrete_self->last_entries = sequences; concrete_self->last_offset = biosal_input_proxy_offset(&concrete_self->proxy); thorium_actor_send_int64_t(actor, concrete_self->controller, ACTION_INPUT_COUNT_PROGRESS, sequences); } if (has_sequence) { /*printf("DEBUG yield\n");*/ thorium_actor_send_to_self_empty(actor, ACTION_YIELD); /* notify the controller of our progress... */ } else { thorium_actor_send_to_self_empty(actor, ACTION_INPUT_COUNT_READY); } } else if (tag == ACTION_YIELD_REPLY) { if (biosal_input_stream_check_open_error(actor, message)) { /* * it is not clear that there can be an error when receiving YIELD. error = concrete_self->error; thorium_actor_send_reply_int(actor, ACTION_INPUT_COUNT_REPLY, error); thorium_actor_send_to_self(actor, ACTION_ASK_TO_STOP); */ return; } thorium_actor_send_to_self_empty(actor, ACTION_INPUT_COUNT); } else if (tag == ACTION_INPUT_COUNT_READY) { if (biosal_input_stream_check_open_error(actor, message)) { return; } count = biosal_input_proxy_size(&concrete_self->proxy); thorium_actor_send_vector(actor, concrete_self->count_customer, ACTION_INPUT_COUNT_REPLY, &concrete_self->mega_blocks); printf("input_stream/%d on node/%d counted entries in %s, %" PRIu64 "\n", thorium_actor_name(actor), thorium_actor_node_name(actor), concrete_self->file_name, count); } else if (tag == ACTION_INPUT_CLOSE) { #ifdef BIOSAL_INPUT_STREAM_DEBUG printf("DEBUG destroy proxy\n"); #endif concrete_self->error = BIOSAL_INPUT_ERROR_NO_ERROR; if (biosal_input_stream_check_open_error(actor, message)) { concrete_self->error = BIOSAL_INPUT_ERROR_FILE_NOT_OPEN; thorium_message_init(message, ACTION_INPUT_CLOSE_REPLY, sizeof(concrete_self->error), &concrete_self->error); thorium_actor_send(actor, source, message); thorium_actor_send_to_self_empty(actor, ACTION_ASK_TO_STOP); return; } thorium_message_init(message, ACTION_INPUT_CLOSE_REPLY, sizeof(concrete_self->error), &concrete_self->error); thorium_actor_send(actor, source, message); thorium_actor_send_to_self_empty(actor, ACTION_ASK_TO_STOP); #ifdef BIOSAL_INPUT_STREAM_DEBUG printf("actor %d sending ACTION_INPUT_CLOSE_REPLY to %d\n", thorium_actor_name(actor), source); #endif } else if (tag == ACTION_INPUT_GET_SEQUENCE) { if (biosal_input_stream_check_open_error(actor, message)) { /* the error management could be better. */ concrete_self->error = BIOSAL_INPUT_ERROR_FILE_NOT_OPEN; thorium_message_init(message, ACTION_INPUT_GET_SEQUENCE_REPLY, sizeof(concrete_self->error), &concrete_self->error); thorium_actor_send(actor, source, message); return; } sequence_index = biosal_input_proxy_size(&concrete_self->proxy); /* TODO it would be clearer to use a struct to pack a int and a char [] * then to use the code below. */ read_buffer = concrete_self->buffer_for_sequence + sizeof(sequence_index); has_sequence = biosal_input_proxy_get_sequence(&concrete_self->proxy, read_buffer); if (!has_sequence) { thorium_message_init(message, ACTION_INPUT_GET_SEQUENCE_END, 0, NULL); thorium_actor_send(actor, source, message); return; } buffer_size = sizeof(sequence_index) + strlen(read_buffer) + 1; core_memory_copy(concrete_self->buffer_for_sequence, &sequence_index, sizeof(sequence_index)); thorium_message_init(message, ACTION_INPUT_GET_SEQUENCE_REPLY, buffer_size, concrete_self->buffer_for_sequence); thorium_actor_send(actor, source, message); } else if (tag == ACTION_INPUT_PUSH_SEQUENCES) { biosal_input_stream_push_sequences(actor, message); } else if (tag == ACTION_ASK_TO_STOP) { thorium_actor_send_to_self_empty(actor, ACTION_STOP); thorium_actor_send_range_empty(actor, &concrete_self->parallel_streams, ACTION_ASK_TO_STOP); thorium_actor_send_reply_empty(actor, ACTION_ASK_TO_STOP_REPLY); } else if (tag == ACTION_INPUT_STREAM_RESET) { /* fail silently */ if (!concrete_self->open) { thorium_actor_send_reply_empty(actor, ACTION_INPUT_STREAM_RESET_REPLY); return; } #ifdef BIOSAL_INPUT_STREAM_DEBUG printf("DEBUG ACTION_INPUT_STREAM_RESET\n"); #endif biosal_input_proxy_destroy(&concrete_self->proxy); biosal_input_proxy_init(&concrete_self->proxy, concrete_self->file_name, concrete_self->starting_offset, concrete_self->ending_offset); thorium_actor_send_reply_empty(actor, ACTION_INPUT_STREAM_RESET_REPLY); } else if (tag == ACTION_PUSH_SEQUENCE_DATA_BLOCK_REPLY) { thorium_actor_send_to_supervisor_int(actor, ACTION_INPUT_PUSH_SEQUENCES_REPLY, source); } }
void thorium_worker_work(struct thorium_worker *worker, struct thorium_actor *actor) { int dead; int actor_name; #ifdef THORIUM_WORKER_DEBUG int tag; int destination; #endif actor_name = thorium_actor_name(actor); #ifdef THORIUM_WORKER_DEBUG_SCHEDULER printf("WORK actor %d\n", actor_name); #endif /* the actor died while the work was queued. */ if (thorium_actor_dead(actor)) { printf("NOTICE actor is dead already (thorium_worker_work)\n"); return; } #ifdef THORIUM_DISABLE_LOCKLESS_ACTORS /* lock the actor to prevent another worker from making work * on the same actor at the same time */ if (thorium_actor_trylock(actor) != CORE_LOCK_SUCCESS) { #ifdef SHOW_FULL_RING_WARNINGS printf("Warning: CONTENTION worker %d could not lock actor %d, returning the message...\n", thorium_worker_name(worker), actor_name); #endif return; } #endif /* the actor died while this worker was waiting for the lock */ if (thorium_actor_dead(actor)) { printf("DEBUG thorium_worker_work actor died while the worker was waiting for the lock.\n"); #ifdef THORIUM_WORKER_DEBUG #endif /*thorium_actor_unlock(actor);*/ return; } /* call the actor receive code */ thorium_actor_set_worker(actor, worker); thorium_actor_work(actor); /* Free ephemeral memory */ core_memory_pool_free_all(&worker->ephemeral_memory); dead = thorium_actor_dead(actor); if (dead) { core_map_delete(&worker->actors, &actor_name); if (core_bitmap_get_bit_uint32_t(&worker->flags, FLAG_ENABLE_ACTOR_LOAD_PROFILER)) { thorium_actor_write_profile(actor, &worker->load_profile_writer); } thorium_node_notify_death(worker->node, actor); } thorium_actor_set_worker(actor, NULL); #ifdef THORIUM_WORKER_DEBUG_20140601 if (core_bitmap_get_bit_uint32_t(&worker->flags, FLAG_DEBUG)) { printf("DEBUG worker/%d after dead call\n", thorium_worker_name(worker)); } #endif #ifdef THORIUM_DISABLE_LOCKLESS_ACTORS /* Unlock the actor. * This does not do anything if a death notification * was sent to the node */ thorium_actor_unlock(actor); #endif #ifdef THORIUM_WORKER_DEBUG printf("thorium_worker_work Freeing buffer %p %i tag %i\n", buffer, thorium_message_count(message), thorium_message_action(message)); #endif #ifdef THORIUM_WORKER_DEBUG_20140601 if (core_bitmap_get_bit_uint32_t(&worker->flags, FLAG_DEBUG)) { printf("DEBUG worker/%d exiting thorium_worker_work\n", thorium_worker_name(worker)); } #endif }
/* * Basically, this actor does this: * - spawn visitors * - let them visit stuff * - kill them. * - spawn walkers * - let them walk * - kill the walkers * - return OK */ void biosal_unitig_manager_receive(struct thorium_actor *self, struct thorium_message *message) { struct biosal_unitig_manager *concrete_self; int tag; void *buffer; int spawner; int expected; int script; int actor_count; int source; struct core_string file_name; char *directory; int argc; char **argv; char *path; tag = thorium_message_action(message); source = thorium_message_source(message); buffer = thorium_message_buffer(message); concrete_self = (struct biosal_unitig_manager *)thorium_actor_concrete_actor(self); if (tag == ACTION_START) { core_vector_unpack(&concrete_self->spawners, buffer); spawner = thorium_actor_get_random_spawner(self, &concrete_self->spawners); concrete_self->state = STATE_SPAWN_WRITER; thorium_actor_send_int(self, spawner, ACTION_SPAWN, SCRIPT_WRITER_PROCESS); } else if (tag == ACTION_SPAWN_REPLY && concrete_self->state == STATE_SPAWN_WRITER) { thorium_message_unpack_int(message, 0, &concrete_self->writer_process); /* * open the file now. */ argc = thorium_actor_argc(self); argv = thorium_actor_argv(self); directory = core_command_get_output_directory(argc, argv); core_string_init(&file_name, directory); core_string_append(&file_name, "/"); core_string_append(&file_name, "unitigs.fasta"); path = core_string_get(&file_name); thorium_actor_send_buffer(self, concrete_self->writer_process, ACTION_OPEN, strlen(path) + 1, path); core_string_destroy(&file_name); } else if (tag == ACTION_OPEN_REPLY && source == concrete_self->writer_process) { /* * Spawn visitors. */ concrete_self->state = STATE_VISITORS; thorium_actor_send_to_self_empty(self, ACTION_PING); } else if (tag == ACTION_PING) { spawner = thorium_actor_get_random_spawner(self, &concrete_self->spawners); thorium_actor_send_int(self, spawner, ACTION_SPAWN, SCRIPT_MANAGER); } else if (tag == ACTION_SPAWN_REPLY) { thorium_message_unpack_int(message, 0, &concrete_self->manager); script = SCRIPT_UNITIG_VISITOR; if (concrete_self->state == STATE_WALKERS) { script = SCRIPT_UNITIG_WALKER; } thorium_actor_send_int(self, concrete_self->manager, ACTION_MANAGER_SET_SCRIPT, script); } else if (tag == ACTION_ASK_TO_STOP) { thorium_actor_send_empty(self, concrete_self->writer_process, ACTION_ASK_TO_STOP); thorium_actor_send_empty(self, concrete_self->manager, ACTION_ASK_TO_STOP); thorium_actor_send_to_self_empty(self, ACTION_STOP); thorium_actor_send_reply_empty(self, ACTION_ASK_TO_STOP_REPLY); } else if (tag == ACTION_MANAGER_SET_SCRIPT_REPLY) { actor_count = UNITIG_VISITOR_COUNT_PER_WORKER; if (concrete_self->state == STATE_WALKERS) actor_count = UNITIG_WALKER_COUNT_PER_WORKER; thorium_actor_send_reply_int(self, ACTION_MANAGER_SET_ACTORS_PER_WORKER, actor_count); } else if (tag == ACTION_MANAGER_SET_ACTORS_PER_WORKER_REPLY) { thorium_actor_send_reply_vector(self, ACTION_START, &concrete_self->spawners); } else if (tag == ACTION_START_REPLY && concrete_self->state == STATE_VISITORS && core_vector_size(&concrete_self->visitors) == 0) { core_vector_unpack(&concrete_self->visitors, buffer); printf("DEBUG the system has %d visitors\n", (int)core_vector_size(&concrete_self->visitors)); thorium_actor_send_to_supervisor_empty(self, ACTION_START_REPLY); } else if (tag == ACTION_START_REPLY && concrete_self->state == STATE_WALKERS && core_vector_size(&concrete_self->walkers) == 0) { core_vector_unpack(&concrete_self->walkers, buffer); printf("DEBUG the system has %d walkers\n", (int)core_vector_size(&concrete_self->walkers)); core_timer_start(&concrete_self->timer); concrete_self->completed = 0; thorium_actor_send_range_int(self, &concrete_self->walkers, ACTION_SET_CONSUMER, concrete_self->writer_process); thorium_actor_send_range_vector(self, &concrete_self->walkers, ACTION_START, &concrete_self->graph_stores); } else if (tag == ACTION_SET_PRODUCERS) { core_vector_unpack(&concrete_self->graph_stores, buffer); core_timer_start(&concrete_self->timer); concrete_self->completed = 0; thorium_actor_send_range_vector(self, &concrete_self->visitors, ACTION_START, &concrete_self->graph_stores); } else if (tag == ACTION_START_REPLY && concrete_self->state == STATE_VISITORS) { ++concrete_self->completed; expected = core_vector_size(&concrete_self->visitors); if (concrete_self->completed % UNITIG_VISITOR_COUNT_PER_WORKER == 0 || concrete_self->completed == expected) { printf("PROGRESS unitig visitors %d/%d\n", concrete_self->completed, expected); } if (concrete_self->completed == expected) { core_timer_stop(&concrete_self->timer); core_timer_print_with_description(&concrete_self->timer, "Visit vertices for unitigs"); /* * Stop the visitor manager and all visitors too. */ thorium_actor_send_empty(self, concrete_self->manager, ACTION_ASK_TO_STOP); /* * Reset graph stores. */ thorium_actor_send_range_empty(self, &concrete_self->graph_stores, ACTION_RESET); concrete_self->completed = 0; } } else if (tag == ACTION_RESET_REPLY) { ++concrete_self->completed; expected = core_vector_size(&concrete_self->graph_stores); if (concrete_self->completed == expected) { concrete_self->completed = 0; concrete_self->state = STATE_WALKERS; /* * Go back at the beginning. */ thorium_actor_send_to_self_empty(self, ACTION_PING); } } else if (tag == ACTION_START_REPLY && concrete_self->state == STATE_WALKERS) { ++concrete_self->completed; expected = core_vector_size(&concrete_self->walkers); if (concrete_self->completed % UNITIG_WALKER_COUNT_PER_WORKER == 0 || concrete_self->completed == expected) { printf("PROGRESS unitig walkers %d/%d\n", concrete_self->completed, expected); } if (concrete_self->completed == expected) { core_timer_stop(&concrete_self->timer); core_timer_print_with_description(&concrete_self->timer, "Walk for unitigs"); thorium_actor_send_to_supervisor_empty(self, ACTION_SET_PRODUCERS_REPLY); } } }
void thorium_worker_send(struct thorium_worker *worker, struct thorium_message *message) { void *buffer; int count; void *old_buffer; old_buffer = thorium_message_buffer(message); /* * Allocate a buffer if the actor provided a NULL buffer or if it * provided its own buffer. */ if (old_buffer == NULL || old_buffer != worker->zero_copy_buffer) { count = thorium_message_count(message); /* use slab allocator */ buffer = thorium_worker_allocate(worker, count); /* according to * http://stackoverflow.com/questions/3751797/can-i-call-core_memory_copy-and-core_memory_move-with-number-of-bytes-set-to-zero * memcpy works with a count of 0, but the addresses must be valid * nonetheless * * Copy the message data. */ if (count > 0) { #ifdef DISPLAY_COPY_WARNING printf("thorium_worker: Warning, not using zero-copy path, action %x count %d source %d destination %d\n", thorium_message_action(message), count, thorium_message_source(message), thorium_message_destination(message)); #endif core_memory_copy(buffer, old_buffer, count); } thorium_message_set_buffer(message, buffer); } /* * Always write metadata. */ thorium_message_write_metadata(message); #ifdef THORIUM_WORKER_DEBUG_INJECTION ++worker->counter_allocated_outbound_buffers; #endif #ifdef THORIUM_WORKER_DEBUG_MEMORY printf("ALLOCATE %p\n", buffer); #endif #ifdef THORIUM_WORKER_DEBUG printf("[thorium_worker_send] allocated %i bytes (%i + %i) for buffer %p\n", all, count, metadata_size, buffer); printf("thorium_worker_send old buffer: %p\n", thorium_message_buffer(message)); #endif #ifdef THORIUM_BUG_594 if (thorium_message_action(©) == 30202) { printf("DEBUG-594 thorium_worker_send\n"); thorium_message_print(©); } #endif #ifdef THORIUM_WORKER_DEBUG_20140601 if (thorium_message_action(message) == 1100) { printf("DEBUG thorium_worker_send 1100\n"); } #endif /* if the destination is on the same node, * handle that directly here to avoid locking things * with the node. */ thorium_worker_enqueue_message(worker, message); worker->zero_copy_buffer = NULL; }
void biosal_assembly_graph_store_receive(struct thorium_actor *self, struct thorium_message *message) { int tag; /*void *buffer;*/ struct biosal_assembly_graph_store *concrete_self; double value; struct biosal_dna_kmer kmer; /*struct core_memory_pool *ephemeral_memory;*/ int customer; int big_key_size; int big_value_size; if (thorium_actor_take_action(self, message)) { return; } /*ephemeral_memory = thorium_actor_get_ephemeral_memory(self);*/ concrete_self = thorium_actor_concrete_actor(self); tag = thorium_message_action(message); /*buffer = thorium_message_buffer(message);*/ if (tag == ACTION_SET_KMER_LENGTH) { thorium_message_unpack_int(message, 0, &concrete_self->kmer_length); biosal_dna_kmer_init_mock(&kmer, concrete_self->kmer_length, &concrete_self->storage_codec, thorium_actor_get_ephemeral_memory(self)); concrete_self->key_length_in_bytes = biosal_dna_kmer_pack_size(&kmer, concrete_self->kmer_length, &concrete_self->storage_codec); biosal_dna_kmer_destroy(&kmer, thorium_actor_get_ephemeral_memory(self)); big_key_size = concrete_self->key_length_in_bytes; big_value_size = sizeof(struct biosal_assembly_vertex); core_map_init(&concrete_self->table, big_key_size, big_value_size); core_map_set_memory_pool(&concrete_self->table, &concrete_self->persistent_memory); printf("DEBUG big_key_size %d big_value_size %d\n", big_key_size, big_value_size); /* * Configure the map for better performance. */ core_map_disable_deletion_support(&concrete_self->table); /* * The threshold of the map is not very important because * requests that hit the map have to first arrive as messages, * which are slow. */ core_map_set_threshold(&concrete_self->table, 0.95); thorium_actor_send_reply_empty(self, ACTION_SET_KMER_LENGTH_REPLY); } else if (tag == ACTION_ASSEMBLY_GET_KMER_LENGTH) { thorium_actor_send_reply_int(self, ACTION_ASSEMBLY_GET_KMER_LENGTH_REPLY, concrete_self->kmer_length); } else if (tag == ACTION_RESET) { /* * Reset the iterator. */ core_map_iterator_init(&concrete_self->iterator, &concrete_self->table); printf("DEBUG unitig_vertex_count %d\n", concrete_self->unitig_vertex_count); thorium_actor_send_reply_empty(self, ACTION_RESET_REPLY); } else if (tag == ACTION_SEQUENCE_STORE_REQUEST_PROGRESS_REPLY) { thorium_message_unpack_double(message, 0, &value); core_map_set_current_size_estimate(&concrete_self->table, value); } else if (tag == ACTION_ASK_TO_STOP) { printf("%s/%d received %d arc blocks\n", thorium_actor_script_name(self), thorium_actor_name(self), concrete_self->received_arc_block_count); thorium_actor_ask_to_stop(self, message); } else if (tag == ACTION_SET_CONSUMER) { thorium_message_unpack_int(message, 0, &customer); printf("%s/%d will use coverage distribution %d\n", thorium_actor_script_name(self), thorium_actor_name(self), customer); concrete_self->customer = customer; thorium_actor_send_reply_empty(self, ACTION_SET_CONSUMER_REPLY); } else if (tag == ACTION_PUSH_DATA) { printf("%s/%d receives ACTION_PUSH_DATA\n", thorium_actor_script_name(self), thorium_actor_name(self)); biosal_assembly_graph_store_push_data(self, message); } else if (tag == ACTION_STORE_GET_ENTRY_COUNT) { thorium_actor_send_reply_uint64_t(self, ACTION_STORE_GET_ENTRY_COUNT_REPLY, concrete_self->received); } else if (tag == ACTION_GET_RECEIVED_ARC_COUNT) { thorium_actor_send_reply_uint64_t(self, ACTION_GET_RECEIVED_ARC_COUNT_REPLY, concrete_self->received_arc_count); } }
void biosal_coverage_distribution_receive(struct thorium_actor *self, struct thorium_message *message) { int tag; struct core_map map; struct core_map_iterator iterator; int *coverage_from_message; uint64_t *count_from_message; uint64_t *frequency; int count; void *buffer; struct biosal_coverage_distribution *concrete_actor; int name; int source; struct core_memory_pool *ephemeral_memory; ephemeral_memory = thorium_actor_get_ephemeral_memory(self); name = thorium_actor_name(self); source = thorium_message_source(message); concrete_actor = (struct biosal_coverage_distribution *)thorium_actor_concrete_actor(self); tag = thorium_message_action(message); count = thorium_message_count(message); buffer = thorium_message_buffer(message); if (tag == ACTION_PUSH_DATA) { core_map_init(&map, 0, 0); core_map_set_memory_pool(&map, ephemeral_memory); core_map_unpack(&map, buffer); core_map_iterator_init(&iterator, &map); while (core_map_iterator_has_next(&iterator)) { core_map_iterator_next(&iterator, (void **)&coverage_from_message, (void **)&count_from_message); #ifdef BIOSAL_COVERAGE_DISTRIBUTION_DEBUG thorium_actor_log(self, "DEBUG DATA %d %d\n", (int)*coverage_from_message, (int)*count_from_message); #endif frequency = core_map_get(&concrete_actor->distribution, coverage_from_message); if (frequency == NULL) { frequency = core_map_add(&concrete_actor->distribution, coverage_from_message); (*frequency) = 0; } (*frequency) += (*count_from_message); } core_map_iterator_destroy(&iterator); thorium_actor_send_reply_empty(self, ACTION_PUSH_DATA_REPLY); concrete_actor->actual++; thorium_actor_log(self, "distribution/%d receives coverage data from producer/%d, %d entries / %d bytes %d/%d\n", name, source, (int)core_map_size(&map), count, concrete_actor->actual, concrete_actor->expected); if (concrete_actor->expected != 0 && concrete_actor->expected == concrete_actor->actual) { thorium_actor_log(self, "received everything %d/%d\n", concrete_actor->actual, concrete_actor->expected); biosal_coverage_distribution_write_distribution(self); thorium_actor_send_empty(self, concrete_actor->source, ACTION_NOTIFY); } core_map_destroy(&map); } else if (tag == ACTION_ASK_TO_STOP) { biosal_coverage_distribution_ask_to_stop(self, message); } else if (tag == ACTION_SET_EXPECTED_MESSAGE_COUNT) { concrete_actor->source = source; thorium_message_unpack_int(message, 0, &concrete_actor->expected); thorium_actor_log(self, "distribution %d expects %d messages\n", thorium_actor_name(self), concrete_actor->expected); thorium_actor_send_reply_empty(self, ACTION_SET_EXPECTED_MESSAGE_COUNT_REPLY); } }
void core_writer_process_receive(struct thorium_actor *self, struct thorium_message *message) { int action; int count; int source; char *buffer; char *file_name; struct core_writer_process *concrete_self; concrete_self = thorium_actor_concrete_actor(self); action = thorium_message_action(message); count = thorium_message_count(message); buffer = thorium_message_buffer(message); source = thorium_message_source(message); if (action == ACTION_OPEN) { if (concrete_self->has_file) { thorium_actor_log(self, "actor error, already open, can not open\n"); return; } file_name = buffer; core_buffered_file_writer_init(&concrete_self->writer, file_name); concrete_self->has_file = 1; thorium_actor_send_reply_empty(self, ACTION_OPEN_REPLY); } else if (action == ACTION_WRITE) { core_buffered_file_writer_write(&concrete_self->writer, buffer, count); thorium_actor_send_reply_empty(self, ACTION_WRITE_REPLY); } else if (action == ACTION_CLOSE) { if (!concrete_self->has_file) { thorium_actor_log(self, "Error, can not close a file that is not open\n"); return; } core_buffered_file_writer_destroy(&concrete_self->writer); concrete_self->has_file = 0; thorium_actor_send_reply_empty(self, ACTION_CLOSE_REPLY); } else if (action == ACTION_ASK_TO_STOP && source == thorium_actor_supervisor(self)) { /* * Close the file if it is open * right now. */ if (concrete_self->has_file) { core_buffered_file_writer_destroy(&concrete_self->writer); concrete_self->has_file = 0; } thorium_actor_send_to_self_empty(self, ACTION_STOP); thorium_actor_send_reply_empty(self, ACTION_ASK_TO_STOP_REPLY); } }
/* * Returns 1 if the message was demultiplexed. * * This is O(1) in regard to the number of thorium nodes. */ int thorium_message_multiplexer_demultiplex(struct thorium_message_multiplexer *self, struct thorium_message *message) { /* * Algorithm: * * get tag. * if tag is ACTION_MULTIPLEXER_MESSAGE * for every enclosed message * call thorium_node_prepare_received_message * call thorium_node_dispatch_message() * return 1 * * return 0 */ int count; char *buffer; struct thorium_message new_message; int new_count; void *new_buffer; int position; struct core_memory_pool *pool; int messages; int tag; int source_node; int destination_node; int current_node; int routing_destination; #ifdef DEBUG_MULTIPLEXER thorium_printf("demultiplex message\n"); thorium_message_print(message); #endif if (CORE_BITMAP_GET_FLAG(self->flags, FLAG_DISABLED)) { return 0; } tag = thorium_message_action(message); if (tag != ACTION_MULTIPLEXER_MESSAGE) { return 0; } /* thorium_printf("MULTIPLEXER demultiplex\n"); */ messages = 0; tracepoint(thorium_node, demultiplex_enter, self->node->name, self->node->tick, messages); source_node = thorium_message_source_node(message); destination_node = thorium_message_destination_node(message); /* * Remove the metadata from the count. */ thorium_message_remove_metadata_from_count(message); count = thorium_message_count(message); buffer = thorium_message_buffer(message); pool = thorium_worker_get_outbound_message_memory_pool(self->worker); position = 0; /* * Inject a message for each enclosed message. */ while (position < count) { core_memory_copy(&new_count, buffer + position, sizeof(new_count)); position += sizeof(new_count); new_buffer = core_memory_pool_allocate(pool, new_count); core_memory_copy(new_buffer, buffer + position, new_count); thorium_message_init_with_nodes(&new_message, new_count, new_buffer, source_node, destination_node); thorium_node_prepare_received_message(self->node, &new_message); /* * For these demultiplexed messages, there are 2 outcomes: * * 1) the message must be delivered locally; * 2) the message must be forward because this is a middle node in * the route. */ /* thorium_printf("demultiplex: \n"); thorium_message_print(&new_message); thorium_printf("\n"); */ /* * Mark the message for recycling. */ thorium_message_set_worker(&new_message, thorium_worker_name(self->worker)); #ifdef CORE_DEBUGGER_ASSERT_ENABLED if (thorium_message_action(&new_message) == ACTION_INVALID) { thorium_printf("Error invalid action DEMUL Multiplexer position %d count %d new_count %d\n", position, count, new_count); thorium_message_print(&new_message); } #endif CORE_DEBUGGER_ASSERT(thorium_message_action(&new_message) != ACTION_INVALID); /* thorium_printf("DEMULTIPLEX_MESSAGE\n"); */ /* thorium_printf("demultiplex, local delivery: \n"); thorium_message_print(&new_message); */ current_node = self->node->name; routing_destination = new_message.routing_destination; CORE_DEBUGGER_ASSERT(routing_destination >= 0); /* * This is a local delivery, nothing to see here. */ if (routing_destination == current_node) { thorium_worker_send_local_delivery(self->worker, &new_message); /* * Otherwise, get the next node in the route and send the * payload there since we can not do anything with it here. */ } else { /* * Export the message to another node. * To do this, use an exporter worker. */ thorium_worker_send_for_multiplexer(self->worker, &new_message); } /* thorium_message_destroy(&new_message); */ position += new_count; ++messages; } CORE_DEBUGGER_ASSERT(messages > 0); #ifdef DEBUG_MULTIPLEXER thorium_printf("thorium_message_multiplexer_demultiplex %d messages\n", messages); #endif tracepoint(thorium_node, demultiplex_exit, self->node->name, self->node->tick, messages); return 1; }
/* * 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; }