void core_vector_print_int(struct core_vector *self) { int64_t i; int64_t size; size = core_vector_size(self); i = 0; /* printf("["); */ while (i < size) { /* if (i > 0) { printf(", "); } */ printf("%d: %d\n", (int)i, core_vector_at_as_int(self, i)); i++; } /* printf("]"); */ }
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); } }
void biosal_input_stream_spawn_reply(struct thorium_actor *self, struct thorium_message *message) { int stream; struct biosal_input_stream *concrete_self; int i; int size; uint64_t start_offset; uint64_t end_offset; concrete_self = (struct biosal_input_stream *)thorium_actor_concrete_actor(self); thorium_message_unpack_int(message, 0, &stream); core_vector_push_back_int(&concrete_self->parallel_streams, stream); #ifdef DEBUG_ISSUE_594 printf("DEBUG biosal_input_stream_spawn_reply %d/%d\n", (int)core_vector_size(&concrete_self->parallel_streams), (int)core_vector_size(&concrete_self->start_offsets)); #endif if (core_vector_size(&concrete_self->parallel_streams) == core_vector_size(&concrete_self->start_offsets)) { /* Set offsets */ thorium_actor_add_action(self, ACTION_INPUT_STREAM_SET_START_OFFSET_REPLY, biosal_input_stream_set_offset_reply); thorium_actor_add_action(self, ACTION_INPUT_STREAM_SET_END_OFFSET_REPLY, biosal_input_stream_set_offset_reply); concrete_self->finished_parallel_stream_count = 0; size = core_vector_size(&concrete_self->parallel_streams); for (i = 0; i < size; i++) { start_offset = core_vector_at_as_uint64_t(&concrete_self->start_offsets, i); end_offset = core_vector_at_as_uint64_t(&concrete_self->end_offsets, i); stream = core_vector_at_as_int(&concrete_self->parallel_streams, i); #ifdef DEBUG_ISSUE_594 printf("actor %d send ACTION_INPUT_STREAM_SET_START_OFFSET to %d\n", name, stream); printf("actor %d send ACTION_INPUT_STREAM_SET_END_OFFSET to %d\n", name, stream); #endif thorium_actor_send_uint64_t(self, stream, ACTION_INPUT_STREAM_SET_START_OFFSET, start_offset); thorium_actor_send_uint64_t(self, stream, ACTION_INPUT_STREAM_SET_END_OFFSET, end_offset); } } }
void biosal_input_controller_verify_requests(struct thorium_actor *self, struct thorium_message *message) { struct biosal_input_controller *concrete_actor; int i; int active; active = 0; concrete_actor = (struct biosal_input_controller *)thorium_actor_concrete_actor(self); for (i = 0; i < core_vector_size(&concrete_actor->consumer_active_requests); i++) { if (core_vector_at_as_int(&concrete_actor->consumer_active_requests, i) != 0) { active++; } } if (active == 0) { } }
void process_send_ping(struct thorium_actor *self) { struct process *concrete_self; int destination; int size; int index; int buffer_size; int range; uint64_t checksum; int count; char *buffer; int i; uint64_t *bucket; concrete_self = thorium_actor_concrete_actor(self); range = concrete_self->maximum_buffer_size - concrete_self->minimum_buffer_size; buffer_size = rand() % range; buffer_size += concrete_self->minimum_buffer_size; count = buffer_size + sizeof(checksum); buffer = thorium_actor_allocate(self, count); /* * Generate content; */ for (i = 0; i < buffer_size; ++i) { buffer[i] = i % 256; } checksum = core_hash_data_uint64_t(buffer, buffer_size, SEED); bucket = (uint64_t *)(buffer + buffer_size); *bucket = checksum; size = core_vector_size(&concrete_self->actors); index = rand() % size; destination = core_vector_at_as_int(&concrete_self->actors, index); thorium_actor_send_buffer(self, destination, ACTION_PING, count, buffer); ++concrete_self->active_messages; }
void process_ping_reply(struct thorium_actor *self, struct thorium_message *message) { struct process *concrete_self; int destination; concrete_self = (struct process *)thorium_actor_concrete_actor(self); ++concrete_self->events; --concrete_self->active_messages; if (concrete_self->events % 1000 == 0) { printf("PROGRESS %d/%d\n", concrete_self->events, concrete_self->event_count); } if (concrete_self->events < concrete_self->event_count) { process_send_ping(self); } else { destination = core_vector_at_as_int(&concrete_self->actors, 0); thorium_actor_send_empty(self, destination, ACTION_NOTIFY); } }
void framr_hello_reply(actor_t *actor, message_t *message) { message_t new_message; int name; int source; int boss; framr_t *self; struct core_vector *spawners; self = thorium_actor_concrete_actor(actor); name = thorium_actor_name(actor); source = thorium_message_source(message); spawners = &self->spawners; pm("Actor %d is satisfied with a reply from the neighbor %d.\n", name, source); boss = core_vector_at_as_int(spawners, 0); thorium_message_init(&new_message, ACTION_NOTIFY, 0, NULL); thorium_actor_send(actor, boss, &new_message); thorium_message_destroy(&new_message); }
void framr_start(actor_t *actor, message_t *message) { int name; int rank; int size; int neighbor_rank; int neighbor_name; void * buffer; framr_t *self; struct core_vector *spawners; framr_process_args(actor); self = thorium_actor_concrete_actor(actor); name = thorium_actor_name(actor); buffer = thorium_message_buffer(message); spawners = &self->spawners; size = core_vector_size(spawners); pm("received ACTION_START\n"); core_vector_unpack(spawners, buffer); size = core_vector_size(spawners); rank = core_vector_index_of(spawners, &name); neighbor_rank = (rank + 1) % size; neighbor_name = core_vector_at_as_int(spawners, neighbor_rank); pm("Spawner world size = %d\n", size); pm("Spawner %d about to send hello to neighbor %d\n", rank, neighbor_rank); thorium_actor_send_empty(actor, neighbor_name, ACTION_FRAMR_HELLO); /* thorium_message_init(&new_message, ACTION_FRAMR_HELLO, 0, NULL); */ /* thorium_actor_send(actor, neighbor_name, &new_message); */ /* thorium_message_destroy(&new_message); */ }
static void source_send_ping(struct thorium_actor *self) { int target; struct source *concrete_self; concrete_self = thorium_actor_concrete_actor(self); CORE_DEBUGGER_ASSERT(!core_vector_empty(&concrete_self->targets)); if (concrete_self->target == -1) concrete_self->target = thorium_actor_get_random_number(self) % core_vector_size(&concrete_self->targets); target = concrete_self->target; ++concrete_self->target; concrete_self->target %= core_vector_size(&concrete_self->targets); target = core_vector_at_as_int(&concrete_self->targets, target); /* printf("%d sends ACTION_PING to %d\n", thorium_actor_name(self), target); */ thorium_actor_send_empty(self, target, ACTION_PING); }
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 biosal_input_controller_create_stores(struct thorium_actor *actor, struct thorium_message *message) { int tag; int source; void *buffer; int count; int i; struct biosal_input_controller *concrete_actor; int value; int spawner; uint64_t total; int block_size; int blocks; uint64_t entries; char *local_file; int name; concrete_actor = (struct biosal_input_controller *)thorium_actor_concrete_actor(actor); thorium_message_get_all(message, &tag, &count, &buffer, &source); /* printf("DEBUG biosal_input_controller_create_stores\n"); */ for (i = 0; i < core_vector_size(&concrete_actor->stores_per_spawner); i++) { value = core_vector_at_as_int(&concrete_actor->stores_per_spawner, i); if (value == -1) { /* printf("DEBUG need more information about spawner at %i\n", i); */ spawner = core_vector_at_as_int(&concrete_actor->spawners, i); thorium_actor_send_empty(actor, spawner, ACTION_GET_NODE_NAME); return; } } concrete_actor->state = BIOSAL_INPUT_CONTROLLER_STATE_SPAWN_STORES; /* at this point, we know the worker count of every node corresponding * to each spawner */ for (i = 0; i < core_vector_size(&concrete_actor->stores_per_spawner); i++) { /* printf("DEBUG polling spawner %i/%d\n", i, core_vector_size(&concrete_actor->stores_per_spawner)); */ value = core_vector_at_as_int(&concrete_actor->stores_per_spawner, i); if (value != 0) { spawner = core_vector_at_as_int(&concrete_actor->spawners, i); /* printf("DEBUG spawner %d is %d\n", i, spawner); */ thorium_actor_send_int(actor, spawner, ACTION_SPAWN, SCRIPT_SEQUENCE_STORE); return; } /* printf("DEBUG spawner %i spawned all its stores\n", i); */ } printf("DEBUG controller %d: consumers are ready (%d)\n", thorium_actor_name(actor), (int)core_vector_size(&concrete_actor->consumers)); for (i = 0; i < core_vector_size(&concrete_actor->consumers); i++) { value = core_vector_at_as_int(&concrete_actor->consumers, i); printf("DEBUG controller %d: consumer %i is %d\n", thorium_actor_name(actor), i, value); } printf("DEBUG controller %d: streams are\n", thorium_actor_name(actor)); total = 0; block_size = concrete_actor->block_size; for (i = 0; i < core_vector_size(&concrete_actor->files); i++) { entries = *(uint64_t*)core_vector_at(&concrete_actor->counts, i); local_file = core_vector_at_as_char_pointer(&concrete_actor->files, i); name = *(int *)core_vector_at(&concrete_actor->counting_streams, i); printf("stream %d, %d/%d %s %" PRIu64 "\n", name, i, (int)core_vector_size(&concrete_actor->files), local_file, entries); total += entries; } blocks = total / block_size; if (total % block_size != 0) { blocks++; } core_timer_stop(&concrete_actor->counting_timer); core_timer_start(&concrete_actor->distribution_timer); core_timer_print_with_description(&concrete_actor->counting_timer, "Load input / Count input data"); printf("DEBUG controller %d: Partition Total: %" PRIu64 ", block_size: %d, blocks: %d\n", thorium_actor_name(actor), total, block_size, blocks); #ifdef BIOSAL_INPUT_CONTROLLER_DEBUG_10355 printf("DEBUG send ACTION_INPUT_CONTROLLER_CREATE_STORES to self %d\n", thorium_actor_name(actor)); #endif #ifdef BIOSAL_INPUT_CONTROLLER_DEBUG printf("DEBUG biosal_input_controller_create_stores send ACTION_INPUT_CONTROLLER_CREATE_PARTITION\n"); #endif /* no sequences at all ! */ if (total == 0) { printf("Error, total is 0, can not distribute\n"); thorium_actor_send_to_supervisor_empty(actor, ACTION_INPUT_DISTRIBUTE_REPLY); return; } else { thorium_actor_send_to_self_empty(actor, ACTION_INPUT_CONTROLLER_CREATE_PARTITION); } /* thorium_actor_send_to_self_empty(actor, ACTION_STOP); */ }
void biosal_input_controller_receive(struct thorium_actor *actor, struct thorium_message *message) { int tag; int count; char *file; void *buffer; struct biosal_input_controller *controller; struct biosal_input_controller *concrete_actor; int destination; int script; int stream; char *local_file; int i; int name; int source; int destination_index; struct thorium_message new_message; int error; int stream_index; int64_t entries; int64_t *bucket; int *int_bucket; int spawner; int command_name; int stream_name; int consumer; int consumer_index; int *bucket_for_requests; char *new_buffer; int new_count; int file_index; struct core_vector mega_blocks; struct core_vector_iterator vector_iterator; struct biosal_mega_block *mega_block; struct core_vector *vector_bucket; struct core_vector block_counts; uint64_t block_entries; int mega_block_index; uint64_t offset; struct biosal_mega_block *block; int acquaintance_index; if (thorium_actor_take_action(actor, message)) { return; } thorium_message_get_all(message, &tag, &count, &buffer, &source); name = thorium_actor_name(actor); controller = (struct biosal_input_controller *)thorium_actor_concrete_actor(actor); concrete_actor = controller; if (tag == ACTION_START) { core_vector_init(&concrete_actor->spawners, 0); core_vector_unpack(&concrete_actor->spawners, buffer); core_vector_resize(&concrete_actor->stores_per_spawner, core_vector_size(&concrete_actor->spawners)); for (i = 0; i < core_vector_size(&concrete_actor->spawners); i++) { int_bucket = (int *)core_vector_at(&concrete_actor->stores_per_spawner, i); *int_bucket = 0; spawner = core_vector_at_as_int(&concrete_actor->spawners, i); core_queue_enqueue(&concrete_actor->unprepared_spawners, &spawner); } concrete_actor->state = BIOSAL_INPUT_CONTROLLER_STATE_PREPARE_SPAWNERS; #ifdef BIOSAL_INPUT_CONTROLLER_DEBUG_LEVEL printf("DEBUG preparing first spawner\n"); #endif thorium_actor_send_to_self_empty(actor, ACTION_INPUT_CONTROLLER_PREPARE_SPAWNERS); /* thorium_dispatcher_print(thorium_actor_dispatcher(actor)); */ } else if (tag == ACTION_ADD_FILE) { file = (char *)buffer; local_file = core_memory_allocate(strlen(file) + 1, MEMORY_CONTROLLER); strcpy(local_file, file); printf("controller %d ACTION_ADD_FILE %s\n", thorium_actor_name(actor), local_file); core_vector_push_back(&concrete_actor->files, &local_file); bucket = core_vector_at(&concrete_actor->files, core_vector_size(&concrete_actor->files) - 1); local_file = *(char **)bucket; #ifdef BIOSAL_INPUT_CONTROLLER_DEBUG_LEVEL_2 printf("DEBUG11 ACTION_ADD_FILE %s %p bucket %p index %d\n", local_file, local_file, (void *)bucket, core_vector_size(&concrete_actor->files) - 1); #endif thorium_actor_send_reply_empty(actor, ACTION_ADD_FILE_REPLY); } else if (tag == ACTION_SPAWN_REPLY) { if (concrete_actor->state == BIOSAL_INPUT_CONTROLLER_STATE_SPAWN_STORES) { biosal_input_controller_add_store(actor, message); return; } else if (concrete_actor->state == BIOSAL_INPUT_CONTROLLER_STATE_PREPARE_SPAWNERS) { concrete_actor->ready_spawners++; thorium_message_unpack_int(message, 0, &name); thorium_actor_send_empty(actor, name, ACTION_ASK_TO_STOP); thorium_actor_send_to_self_empty(actor, ACTION_INPUT_CONTROLLER_PREPARE_SPAWNERS); if (concrete_actor->ready_spawners == (int)core_vector_size(&concrete_actor->spawners)) { #ifdef BIOSAL_INPUT_CONTROLLER_DEBUG printf("DEBUG all spawners are prepared\n"); #endif thorium_actor_send_to_supervisor_empty(actor, ACTION_START_REPLY); } return; } else if (concrete_actor->state == BIOSAL_INPUT_CONTROLLER_STATE_SPAWN_PARTITIONER) { #ifdef BIOSAL_INPUT_CONTROLLER_DEBUG printf("DEBUG received spawn reply, state is spawn_partitioner\n"); #endif thorium_message_unpack_int(message, 0, &concrete_actor->partitioner); /* configure the partitioner */ destination = concrete_actor->partitioner; thorium_actor_send_int(actor, destination, ACTION_SEQUENCE_PARTITIONER_SET_BLOCK_SIZE, concrete_actor->block_size); thorium_actor_send_int(actor, destination, ACTION_SEQUENCE_PARTITIONER_SET_ACTOR_COUNT, core_vector_size(&concrete_actor->consumers)); core_vector_init(&block_counts, sizeof(uint64_t)); for (i = 0; i < core_vector_size(&concrete_actor->mega_block_vector); i++) { block = (struct biosal_mega_block *)core_vector_at(&concrete_actor->mega_block_vector, i); block_entries = biosal_mega_block_get_entries(block); core_vector_push_back_uint64_t(&block_counts, block_entries); } new_count = core_vector_pack_size(&block_counts); new_buffer = thorium_actor_allocate(actor, new_count); #ifdef BIOSAL_INPUT_CONTROLLER_DEBUG printf("DEBUG packed counts, %d bytes\n", count); #endif core_vector_pack(&block_counts, new_buffer); thorium_message_init(&new_message, ACTION_SEQUENCE_PARTITIONER_SET_ENTRY_VECTOR, new_count, new_buffer); thorium_actor_send(actor, destination, &new_message); core_vector_destroy(&block_counts); return; } else if (concrete_actor->state == BIOSAL_INPUT_CONTROLLER_STATE_SPAWN_READING_STREAMS) { thorium_message_unpack_int(message, 0, &stream); stream_index = stream; mega_block_index = core_vector_size(&concrete_actor->reading_streams); core_vector_push_back_int(&concrete_actor->reading_streams, stream_index); core_vector_push_back_int(&concrete_actor->partition_commands, -1); core_vector_push_back_int(&concrete_actor->stream_consumers, -1); stream_index = core_vector_size(&concrete_actor->reading_streams) - 1; mega_block = (struct biosal_mega_block *)core_vector_at(&concrete_actor->mega_block_vector, mega_block_index); offset = biosal_mega_block_get_offset(mega_block); core_map_add_value(&concrete_actor->assigned_blocks, &stream_index, &mega_block_index); #ifdef BIOSAL_INPUT_CONTROLLER_DEBUG_READING_STREAMS printf("DEBUG setting offset to %" PRIu64 " for stream/%d\n", offset, stream); #endif thorium_actor_send_uint64_t(actor, stream, ACTION_INPUT_STREAM_SET_START_OFFSET, offset); return; } stream = *(int *)buffer; file_index = core_vector_size(&concrete_actor->counting_streams); local_file = *(char **)core_vector_at(&concrete_actor->files, file_index); #ifdef BIOSAL_INPUT_CONTROLLER_DEBUG_READING_STREAMS printf("DEBUG actor %d receives stream %d from spawner %d for file %s\n", name, stream, source, local_file); #endif core_vector_push_back(&concrete_actor->counting_streams, &stream); #ifdef BIOSAL_INPUT_CONTROLLER_DEBUG_READING_STREAMS printf("asking stream/%d to open %s\n", stream, local_file); #endif thorium_message_init(&new_message, ACTION_INPUT_OPEN, strlen(local_file) + 1, local_file); #ifdef DEBUG_ISSUE_594 thorium_message_print(&new_message); printf("SEND Buffer %s\n", local_file); #endif thorium_actor_send(actor, stream, &new_message); thorium_message_destroy(&new_message); if (core_vector_size(&concrete_actor->counting_streams) != core_vector_size(&concrete_actor->files)) { thorium_actor_send_to_self_empty(actor, ACTION_INPUT_SPAWN); } #ifdef DEBUG_ISSUE_594 printf("EXIT Buffer %s\n", local_file); #endif } else if (tag == ACTION_INPUT_OPEN_REPLY) { if (concrete_actor->state == BIOSAL_INPUT_CONTROLLER_STATE_SPAWN_READING_STREAMS) { #ifdef BIOSAL_INPUT_CONTROLLER_DEBUG_READING_STREAMS printf("DEBUG receives open.reply for reading stream/%d\n", source); #endif concrete_actor->opened_streams++; if (concrete_actor->opened_streams == core_vector_size(&concrete_actor->mega_block_vector)) { thorium_actor_send_to_self_empty(actor, ACTION_INPUT_CONTROLLER_CREATE_STORES); } return; } concrete_actor->opened_streams++; stream = source; thorium_message_unpack_int(message, 0, &error); if (error == BIOSAL_INPUT_ERROR_NO_ERROR) { #ifdef BIOSAL_INPUT_CONTROLLER_DEBUG_LEVEL_2 printf("DEBUG actor %d asks %d ACTION_INPUT_COUNT_IN_PARALLEL\n", name, stream); #endif thorium_actor_send_vector(actor, stream, ACTION_INPUT_COUNT_IN_PARALLEL, &concrete_actor->spawners); } else { #ifdef BIOSAL_INPUT_CONTROLLER_DEBUG_LEVEL_2 printf("DEBUG actor %d received error %d from %d\n", name, error, stream); #endif concrete_actor->counted++; } /* if all streams failed, notice supervisor */ if (concrete_actor->counted == core_vector_size(&concrete_actor->files)) { #ifdef BIOSAL_INPUT_CONTROLLER_DEBUG_LEVEL_2 #endif printf("DEBUG %d: Error all streams failed.\n", thorium_actor_name(actor)); thorium_actor_send_to_supervisor_empty(actor, ACTION_INPUT_DISTRIBUTE_REPLY); } /* if (concrete_actor->opened_streams == core_vector_size(&concrete_actor->files)) { #ifdef BIOSAL_INPUT_CONTROLLER_DEBUG printf("DEBUG controller %d sends ACTION_INPUT_DISTRIBUTE_REPLY to supervisor %d [%d/%d]\n", name, thorium_actor_supervisor(actor), concrete_actor->opened_streams, core_vector_size(&concrete_actor->files)); #endif } */ } else if (tag == ACTION_INPUT_COUNT_PROGRESS) { stream_index = core_vector_index_of(&concrete_actor->counting_streams, &source); local_file = core_vector_at_as_char_pointer(&concrete_actor->files, stream_index); thorium_message_unpack_int64_t(message, 0, &entries); bucket = (int64_t *)core_vector_at(&concrete_actor->counts, stream_index); printf("controller/%d receives progress from stream/%d file %s %" PRIu64 " entries so far\n", name, source, local_file, entries); *bucket = entries; } else if (tag == ACTION_INPUT_COUNT_IN_PARALLEL_REPLY) { stream_index = core_vector_index_of(&concrete_actor->counting_streams, &source); local_file = core_vector_at_as_char_pointer(&concrete_actor->files, stream_index); core_vector_init(&mega_blocks, 0); core_vector_unpack(&mega_blocks, buffer); printf("DEBUG receive mega blocks from %d\n", source); /* * Update the file index for every mega block. */ core_vector_iterator_init(&vector_iterator, &mega_blocks); bucket = (int64_t*)core_vector_at(&concrete_actor->counts, stream_index); (*bucket) = 0; while (core_vector_iterator_has_next(&vector_iterator)) { core_vector_iterator_next(&vector_iterator, (void **)&mega_block); printf("SETTING setting file to %d for mega block\n", stream_index); biosal_mega_block_set_file(mega_block, stream_index); entries = biosal_mega_block_get_entries_from_start(mega_block); printf("Cataloging %d ENTRIES\n", (int)entries); (*bucket) = entries; biosal_mega_block_print(mega_block); } core_vector_iterator_destroy(&vector_iterator); vector_bucket = (struct core_vector *)core_map_add(&concrete_actor->mega_blocks, &stream_index); core_vector_init_copy(vector_bucket, &mega_blocks); core_vector_destroy(&mega_blocks); concrete_actor->counted++; printf("controller/%d received from stream/%d for file %s %" PRIu64 " entries (final) %d/%d\n", name, source, local_file, entries, concrete_actor->counted, (int)core_vector_size(&concrete_actor->files)); thorium_actor_send_reply_empty(actor, ACTION_INPUT_CLOSE); /* continue work here, tell supervisor about it */ if (concrete_actor->counted == core_vector_size(&concrete_actor->files)) { thorium_actor_send_to_self_empty(actor, ACTION_INPUT_CONTROLLER_SPAWN_READING_STREAMS); } } else if (tag == ACTION_INPUT_DISTRIBUTE) { core_timer_start(&concrete_actor->input_timer); core_timer_start(&concrete_actor->counting_timer); /* for each file, spawn a stream to count */ /* no files, return immediately */ if (core_vector_size(&concrete_actor->files) == 0) { printf("Error: no file to distribute...\n"); thorium_actor_send_reply_empty(actor, ACTION_INPUT_DISTRIBUTE_REPLY); return; } #ifdef BIOSAL_INPUT_CONTROLLER_DEBUG_LEVEL_2 printf("DEBUG actor %d receives ACTION_INPUT_DISTRIBUTE\n", name); #endif #ifdef BIOSAL_INPUT_CONTROLLER_DEBUG_LEVEL_2 printf("DEBUG send ACTION_INPUT_SPAWN to self\n"); #endif thorium_actor_send_to_self_empty(actor, ACTION_INPUT_SPAWN); #ifdef BIOSAL_INPUT_CONTROLLER_DEBUG_LEVEL_2 printf("DEBUG resizing counts to %d\n", core_vector_size(&concrete_actor->files)); #endif core_vector_resize(&concrete_actor->counts, core_vector_size(&concrete_actor->files)); for (i = 0; i < core_vector_size(&concrete_actor->counts); i++) { bucket = (int64_t*)core_vector_at(&concrete_actor->counts, i); *bucket = 0; } } else if (tag == ACTION_INPUT_SPAWN && source == name) { #ifdef BIOSAL_INPUT_CONTROLLER_DEBUG_LEVEL_2 printf("DEBUG ACTION_INPUT_SPAWN\n"); #endif script = SCRIPT_INPUT_STREAM; concrete_actor->state = BIOSAL_INPUT_CONTROLLER_STATE_SPAWN_STREAMS; /* the next file name to send is the current number of streams */ i = core_vector_size(&concrete_actor->counting_streams); destination_index = i % core_vector_size(&concrete_actor->spawners); destination = *(int *)core_vector_at(&concrete_actor->spawners, destination_index); thorium_message_init(message, ACTION_SPAWN, sizeof(script), &script); thorium_actor_send(actor, destination, message); bucket = core_vector_at(&concrete_actor->files, i); local_file = *(char **)core_vector_at(&concrete_actor->files, i); #ifdef BIOSAL_INPUT_CONTROLLER_DEBUG_LEVEL_2 printf("DEBUG890 local_file %p bucket %p index %d\n", local_file, (void *)bucket, i); #endif #ifdef BIOSAL_INPUT_CONTROLLER_DEBUG printf("DEBUG actor %d spawns a stream for file %d/%d via spawner %d\n", name, i, core_vector_size(&concrete_actor->files), destination); #endif /* also, spawn 4 stores on each node */ } else if (tag == ACTION_ASK_TO_STOP && ( source == thorium_actor_supervisor(actor) || source == thorium_actor_name(actor))) { #ifdef BIOSAL_INPUT_CONTROLLER_DEBUG_LEVEL_2 #endif /* stop streams */ for (i = 0; i < core_vector_size(&concrete_actor->counting_streams); i++) { stream = *(int *)core_vector_at(&concrete_actor->counting_streams, i); thorium_actor_send_empty(actor, stream, ACTION_ASK_TO_STOP); } for (i = 0; i < core_vector_size(&concrete_actor->reading_streams); i++) { stream = *(int *)core_vector_at(&concrete_actor->reading_streams, i); thorium_actor_send_empty(actor, stream, ACTION_ASK_TO_STOP); } #if 0 /* stop data stores */ for (i = 0; i < core_vector_size(&concrete_actor->consumers); i++) { store = core_vector_at_as_int(&concrete_actor->consumers, i); thorium_actor_send_empty(actor, store, ACTION_ASK_TO_STOP); } #endif /* stop partitioner */ if (concrete_actor->partitioner != THORIUM_ACTOR_NOBODY) { thorium_actor_send_empty(actor, concrete_actor->partitioner, ACTION_ASK_TO_STOP); #ifdef BIOSAL_INPUT_CONTROLLER_DEBUG printf("DEBUG controller %d sends ACTION_ASK_TO_STOP_REPLY to %d\n", thorium_actor_name(actor), thorium_message_source(message)); #endif } thorium_actor_send_reply_empty(actor, ACTION_ASK_TO_STOP_REPLY); /* stop self */ thorium_actor_send_to_self_empty(actor, ACTION_STOP); thorium_actor_ask_to_stop(actor, message); printf("DEBUG controller %d dies\n", name); #ifdef BIOSAL_INPUT_CONTROLLER_DEBUG #endif } else if (tag == ACTION_INPUT_CONTROLLER_CREATE_PARTITION && source == name) { spawner = *(int *)core_vector_at(&concrete_actor->spawners, core_vector_size(&concrete_actor->spawners) / 2); thorium_actor_send_int(actor, spawner, ACTION_SPAWN, SCRIPT_SEQUENCE_PARTITIONER); concrete_actor->state = BIOSAL_INPUT_CONTROLLER_STATE_SPAWN_PARTITIONER; #ifdef BIOSAL_INPUT_CONTROLLER_DEBUG printf("DEBUG input controller %d spawns a partitioner via spawner %d\n", name, spawner); #endif } else if (tag == ACTION_SEQUENCE_PARTITIONER_COMMAND_IS_READY) { #ifdef BIOSAL_INPUT_CONTROLLER_DEBUG printf("DEBUG controller receives ACTION_SEQUENCE_PARTITIONER_COMMAND_IS_READY, asks for command\n"); #endif thorium_actor_send_reply_empty(actor, ACTION_SEQUENCE_PARTITIONER_GET_COMMAND); } else if (tag == ACTION_SEQUENCE_PARTITIONER_GET_COMMAND_REPLY) { biosal_input_controller_receive_command(actor, message); } else if (tag == ACTION_SEQUENCE_PARTITIONER_FINISHED) { thorium_actor_send_empty(actor, concrete_actor->partitioner, ACTION_ASK_TO_STOP); biosal_input_controller_verify_requests(actor, message); } else if (tag == ACTION_SEQUENCE_PARTITIONER_PROVIDE_STORE_ENTRY_COUNTS) { biosal_input_controller_receive_store_entry_counts(actor, message); } else if (tag == ACTION_RESERVE_REPLY) { concrete_actor->ready_consumers++; printf("DEBUG marker ACTION_RESERVE_REPLY %d/%d\n", concrete_actor->ready_consumers, (int)core_vector_size(&concrete_actor->consumers)); if (concrete_actor->ready_consumers == core_vector_size(&concrete_actor->consumers)) { concrete_actor->ready_consumers = 0; printf("DEBUG all consumers are ready\n"); thorium_actor_send_empty(actor, concrete_actor->partitioner, ACTION_SEQUENCE_PARTITIONER_PROVIDE_STORE_ENTRY_COUNTS_REPLY); } } else if (tag == ACTION_INPUT_PUSH_SEQUENCES_READY) { #ifdef BIOSAL_INPUT_CONTROLLER_DEBUG printf("DEBUG biosal_input_controller_receive received ACTION_INPUT_PUSH_SEQUENCES_READY\n"); #endif stream_name = source; acquaintance_index = stream_name; stream_index = core_vector_index_of(&concrete_actor->reading_streams, &acquaintance_index); command_name = *(int *)core_vector_at(&concrete_actor->partition_commands, stream_index); thorium_actor_send_int(actor, concrete_actor->partitioner, ACTION_SEQUENCE_PARTITIONER_GET_COMMAND_REPLY_REPLY, command_name); } else if (tag == ACTION_INPUT_PUSH_SEQUENCES_REPLY) { stream_name = source; thorium_message_unpack_int(message, 0, &consumer); consumer_index = core_vector_index_of(&concrete_actor->consumers, &consumer); bucket_for_requests = (int *)core_vector_at(&concrete_actor->consumer_active_requests, consumer_index); (*bucket_for_requests)--; biosal_input_controller_verify_requests(actor, message); #ifdef BIOSAL_INPUT_CONTROLLER_DEBUG_CONSUMERS printf("DEBUG consumer # %d has %d active requests\n", consumer_index, *bucket_for_requests); #endif } else if (tag == ACTION_SET_CONSUMERS) { core_vector_init(&concrete_actor->consumers, 0); core_vector_unpack(&concrete_actor->consumers, buffer); printf("controller %d receives %d consumers\n", thorium_actor_name(actor), (int)core_vector_size(&concrete_actor->consumers)); for (i = 0; i < core_vector_size(&concrete_actor->consumers); i++) { core_vector_push_back_int(&concrete_actor->consumer_active_requests, 0); } #ifdef BIOSAL_INPUT_CONTROLLER_DEBUG core_vector_print_int(&concrete_actor->consumers); printf("\n"); #endif thorium_actor_send_reply_empty(actor, ACTION_SET_CONSUMERS_REPLY); } else if (tag == ACTION_SET_BLOCK_SIZE) { thorium_message_unpack_int(message, 0, &concrete_actor->block_size); thorium_actor_send_reply_empty(actor, ACTION_SET_BLOCK_SIZE_REPLY); } else if (tag == ACTION_SEQUENCE_STORE_READY) { concrete_actor->filled_consumers++; #ifdef BIOSAL_INPUT_CONTROLLER_DEBUG printf("DEBUG ACTION_SEQUENCE_STORE_READY %d/%d\n", concrete_actor->filled_consumers, (int)core_vector_size(&concrete_actor->consumers)); #endif if (concrete_actor->filled_consumers == core_vector_size(&concrete_actor->consumers)) { concrete_actor->filled_consumers = 0; printf("DEBUG: all consumers are filled, sending ACTION_INPUT_DISTRIBUTE_REPLY\n"); core_timer_stop(&concrete_actor->input_timer); core_timer_stop(&concrete_actor->distribution_timer); core_timer_print_with_description(&concrete_actor->distribution_timer, "Load input / Distribute input data"); core_timer_print_with_description(&concrete_actor->input_timer, "Load input"); thorium_actor_send_to_supervisor_empty(actor, ACTION_INPUT_DISTRIBUTE_REPLY); } } }
void biosal_input_controller_spawn_streams(struct thorium_actor *actor, struct thorium_message *message) { int spawner; struct biosal_input_controller *concrete_actor; struct core_vector_iterator iterator; int i; int j; int block_index; struct core_vector *vector; struct biosal_mega_block *block; #ifdef BIOSAL_INPUT_CONTROLLER_DEBUG_READING_STREAMS printf("DEBUG biosal_input_controller_spawn_streams\n"); #endif concrete_actor = (struct biosal_input_controller *)thorium_actor_concrete_actor(actor); concrete_actor->opened_streams = 0; concrete_actor->spawner = 0; /* gather mega blocks */ block_index = 0; printf("DEBUG received MEGA BLOCKS\n"); for (i = 0; i < core_vector_size(&concrete_actor->files); i++) { vector = (struct core_vector *)core_map_get(&concrete_actor->mega_blocks, &i); if (vector == NULL) { continue; } for (j = 0; j < core_vector_size(vector); j++) { block = (struct biosal_mega_block *)core_vector_at(vector, j); printf("BLOCK # %d ", block_index); block_index++; biosal_mega_block_print(block); core_vector_push_back(&concrete_actor->mega_block_vector, block); } } printf("DEBUG MEGA BLOCKS (total: %d)\n", block_index); core_vector_iterator_init(&iterator, &concrete_actor->mega_block_vector); while (core_vector_iterator_has_next(&iterator)) { core_vector_iterator_next(&iterator, NULL); spawner = core_vector_at_as_int(&concrete_actor->spawners, concrete_actor->spawner); concrete_actor->spawner++; concrete_actor->spawner %= core_vector_size(&concrete_actor->spawners); #ifdef BIOSAL_INPUT_CONTROLLER_DEBUG_READING_STREAMS printf("DEBUG asking %d to spawn script %d\n", spawner, SCRIPT_INPUT_STREAM); #endif thorium_actor_send_int(actor, spawner, ACTION_SPAWN, SCRIPT_INPUT_STREAM); } core_vector_iterator_destroy(&iterator); concrete_actor->state = BIOSAL_INPUT_CONTROLLER_STATE_SPAWN_READING_STREAMS; }
void biosal_input_controller_receive_command(struct thorium_actor *actor, struct thorium_message *message) { struct biosal_partition_command command; void *buffer; int stream_index; int store_index; int store_name; uint64_t store_first; uint64_t store_last; int command_name; int stream_name; int *bucket_for_command_name; int bytes; struct biosal_input_command input_command; void *new_buffer; struct thorium_message new_message; struct biosal_input_controller *concrete_actor; int *bucket; int *bucket_for_consumer; int consumer_index; concrete_actor = (struct biosal_input_controller *)thorium_actor_concrete_actor(actor); buffer = thorium_message_buffer(message); biosal_partition_command_unpack(&command, buffer); stream_index = biosal_partition_command_stream_index(&command); #ifdef BIOSAL_INPUT_CONTROLLER_DEBUG_COMMANDS printf("DEBUG biosal_input_controller_receive_command controller receives command for stream %d\n", stream_index); biosal_partition_command_print(&command); #endif store_index = biosal_partition_command_store_index(&command); bucket_for_command_name = (int *)core_vector_at(&concrete_actor->partition_commands, stream_index); bucket_for_consumer = (int *)core_vector_at(&concrete_actor->stream_consumers, stream_index); stream_name = core_vector_at_as_int(&concrete_actor->reading_streams, stream_index); #ifdef BIOSAL_INPUT_CONTROLLER_DEBUG_COMMANDS printf("DEBUG stream_index %d stream_name %d\n", stream_index, stream_name); #endif store_name = *(int *)core_vector_at(&concrete_actor->consumers, store_index); store_first = biosal_partition_command_store_first(&command); store_last = biosal_partition_command_store_last(&command); biosal_input_command_init(&input_command, store_name, store_first, store_last); bytes = biosal_input_command_pack_size(&input_command, &concrete_actor->codec); #ifdef BIOSAL_INPUT_CONTROLLER_DEBUG_COMMANDS printf("DEBUG input command\n"); biosal_input_command_print(&input_command); printf("DEBUG biosal_input_controller_receive_command bytes %d\n", bytes); #endif new_buffer = thorium_actor_allocate(actor, bytes); biosal_input_command_pack(&input_command, new_buffer, &concrete_actor->codec); thorium_message_init(&new_message, ACTION_INPUT_PUSH_SEQUENCES, bytes, new_buffer); #ifdef BIOSAL_INPUT_CONTROLLER_DEBUG_COMMANDS printf("DEBUG biosal_input_controller_receive_command sending ACTION_INPUT_PUSH_SEQUENCES to %d (index %d)\n", stream_name, stream_index); biosal_input_command_print(&input_command); printf("SENDING COMMAND TO stream/%d\n", stream_name); #endif thorium_actor_send(actor, stream_name, &new_message); command_name = biosal_partition_command_name(&command); #ifdef BIOSAL_INPUT_CONTROLLER_DEBUG_COMMANDS printf("controller/%d processed input command %d %p\n", thorium_actor_name(actor), command_name, (void *)bucket_for_command_name); #endif *bucket_for_command_name = command_name; consumer_index = store_index; *bucket_for_consumer = consumer_index; bucket = (int *)core_vector_at(&concrete_actor->consumer_active_requests, consumer_index); (*bucket)++; #ifdef BIOSAL_INPUT_CONTROLLER_DEBUG_CONSUMERS printf("DEBUG consumer # %d has %d active requests\n", consumer_index, *bucket); #endif }
void biosal_assembly_arc_classifier_push_arc_block(struct thorium_actor *self, struct thorium_message *message) { struct biosal_assembly_arc_classifier *concrete_self; int source; struct biosal_assembly_arc_block input_block; struct biosal_assembly_arc_block *output_block; struct core_vector output_blocks; struct core_memory_pool *ephemeral_memory; int consumer_count; struct core_vector *input_arcs; struct core_vector *output_arcs; int size; int i; struct biosal_assembly_arc *arc; void *buffer; int count; struct biosal_dna_kmer *kmer; int consumer_index; int arc_count; int consumer; struct thorium_message new_message; int new_count; void *new_buffer; int *bucket; int maximum_pending_requests; int maximum_buffer_length; int reservation; count = thorium_message_count(message); buffer = thorium_message_buffer(message); if (count == 0) { printf("Error, count is 0 (classifier_push_arc_block)\n"); return; } concrete_self = (struct biosal_assembly_arc_classifier *)thorium_actor_concrete_actor(self); source = thorium_message_source(message); consumer_count = core_vector_size(&concrete_self->consumers); ephemeral_memory = thorium_actor_get_ephemeral_memory(self); CORE_DEBUGGER_LEAK_DETECTION_BEGIN(ephemeral_memory, classify_arcs); core_vector_init(&output_blocks, sizeof(struct biosal_assembly_arc_block)); core_vector_set_memory_pool(&output_blocks, ephemeral_memory); biosal_assembly_arc_block_init(&input_block, ephemeral_memory, concrete_self->kmer_length, &concrete_self->codec); #ifdef BIOSAL_ASSEMBLY_ARC_CLASSIFIER_DEBUG printf("UNPACKING\n"); #endif biosal_assembly_arc_block_unpack(&input_block, buffer, concrete_self->kmer_length, &concrete_self->codec, ephemeral_memory); #ifdef BIOSAL_ASSEMBLY_ARC_CLASSIFIER_DEBUG printf("OK\n"); #endif input_arcs = biosal_assembly_arc_block_get_arcs(&input_block); /* * Configure the ephemeral memory reservation. */ arc_count = core_vector_size(input_arcs); reservation = (arc_count / consumer_count) * 2; core_vector_resize(&output_blocks, consumer_count); CORE_DEBUGGER_ASSERT(!core_memory_pool_has_double_free(ephemeral_memory)); /* * Initialize output blocks. * There is one for each destination. */ for (i = 0; i < consumer_count; i++) { output_block = core_vector_at(&output_blocks, i); biosal_assembly_arc_block_init(output_block, ephemeral_memory, concrete_self->kmer_length, &concrete_self->codec); biosal_assembly_arc_block_reserve(output_block, reservation); } size = core_vector_size(input_arcs); /* * Classify every arc in the input block * and put them in output blocks. */ #ifdef BIOSAL_ASSEMBLY_ARC_CLASSIFIER_DEBUG printf("ClassifyArcs arc_count= %d\n", size); #endif CORE_DEBUGGER_ASSERT(!core_memory_pool_has_double_free(ephemeral_memory)); for (i = 0; i < size; i++) { arc = core_vector_at(input_arcs, i); kmer = biosal_assembly_arc_source(arc); consumer_index = biosal_dna_kmer_store_index(kmer, consumer_count, concrete_self->kmer_length, &concrete_self->codec, ephemeral_memory); output_block = core_vector_at(&output_blocks, consumer_index); /* * Make a copy of the arc and copy it. * It will be freed */ biosal_assembly_arc_block_add_arc_copy(output_block, arc, concrete_self->kmer_length, &concrete_self->codec, ephemeral_memory); } /* * Input arcs are not needed anymore. */ biosal_assembly_arc_block_destroy(&input_block, ephemeral_memory); CORE_DEBUGGER_ASSERT(!core_memory_pool_has_double_free(ephemeral_memory)); /* * Finally, send these output blocks to consumers. */ maximum_pending_requests = 0; maximum_buffer_length = 0; /* * Figure out the maximum buffer length tor * messages. */ for (i = 0; i < consumer_count; i++) { output_block = core_vector_at(&output_blocks, i); new_count = biosal_assembly_arc_block_pack_size(output_block, concrete_self->kmer_length, &concrete_self->codec); if (new_count > maximum_buffer_length) { maximum_buffer_length = new_count; } } #if 0 printf("POOL_BALANCE %d\n", core_memory_pool_profile_balance_count(ephemeral_memory)); #endif for (i = 0; i < consumer_count; i++) { output_block = core_vector_at(&output_blocks, i); output_arcs = biosal_assembly_arc_block_get_arcs(output_block); arc_count = core_vector_size(output_arcs); /* * Don't send an empty message. */ if (arc_count > 0) { /* * Allocation is not required because new_count <= maximum_buffer_length */ new_count = biosal_assembly_arc_block_pack_size(output_block, concrete_self->kmer_length, &concrete_self->codec); new_buffer = thorium_actor_allocate(self, maximum_buffer_length); CORE_DEBUGGER_ASSERT(new_count <= maximum_buffer_length); biosal_assembly_arc_block_pack(output_block, new_buffer, concrete_self->kmer_length, &concrete_self->codec); thorium_message_init(&new_message, ACTION_ASSEMBLY_PUSH_ARC_BLOCK, new_count, new_buffer); consumer = core_vector_at_as_int(&concrete_self->consumers, i); /* * Send the message. */ thorium_actor_send(self, consumer, &new_message); thorium_message_destroy(&new_message); /* update event counters for control. */ bucket = core_vector_at(&concrete_self->pending_requests, i); ++(*bucket); ++concrete_self->active_requests; if (*bucket > maximum_pending_requests) { maximum_pending_requests = *bucket; } if (*bucket > concrete_self->maximum_pending_request_count) { ++concrete_self->consumer_count_above_threshold; } } CORE_DEBUGGER_ASSERT(!core_memory_pool_has_double_free(ephemeral_memory)); #if 0 printf("i = %d\n", i); #endif /* * Destroy output block. */ biosal_assembly_arc_block_destroy(output_block, ephemeral_memory); CORE_DEBUGGER_LEAK_CHECK_DOUBLE_FREE(ephemeral_memory); CORE_DEBUGGER_ASSERT(!core_memory_pool_has_double_free(ephemeral_memory)); } core_vector_destroy(&output_blocks); CORE_DEBUGGER_ASSERT(!core_memory_pool_has_double_free(ephemeral_memory)); CORE_DEBUGGER_LEAK_CHECK_DOUBLE_FREE(ephemeral_memory); /* * Check if a response must be sent now. */ ++concrete_self->received_blocks; concrete_self->source = source; /* * Only send a direct reply if there is enough memory. * * As long as maximum_pending_requests is lower than maximum_pending_request_count, * there is still space for at least one additional request. */ if (maximum_pending_requests < concrete_self->maximum_pending_request_count && core_memory_has_enough_bytes()) { thorium_actor_send_empty(self, concrete_self->source, ACTION_ASSEMBLY_PUSH_ARC_BLOCK_REPLY); } else { concrete_self->producer_is_waiting = 1; } CORE_DEBUGGER_LEAK_DETECTION_END(ephemeral_memory, classify_arcs); }
void thorium_balancer_balance(struct thorium_balancer *self) { /* * The 95th percentile is useful: * \see http://en.wikipedia.org/wiki/Burstable_billing * \see http://www.init7.net/en/backbone/95-percent-rule */ int load_percentile_50; struct core_timer timer; int i; struct core_vector loads; struct core_vector loads_unsorted; struct core_vector burdened_workers; struct core_vector stalled_workers; struct thorium_worker *worker; struct thorium_node *node; /*struct core_set *set;*/ struct core_pair pair; struct core_vector_iterator vector_iterator; int old_worker; int actor_name; int messages; int maximum; int with_maximum; struct core_map *set; struct core_map_iterator set_iterator; int stalled_index; int stalled_count; int new_worker_index; struct core_vector migrations; struct thorium_migration migration; struct thorium_migration *migration_to_do; struct thorium_actor *actor; int candidates; int load_value; int remaining_load; int projected_load; struct core_vector actors_to_migrate; int total; int with_messages; int stalled_percentile; int burdened_percentile; int old_total; int old_load; int new_load; int predicted_new_load; struct core_pair *pair_pointer; struct thorium_worker *new_worker; /*int new_total;*/ int actor_load; int test_stalled_index; int tests; int found_match; int spawned_actors; int killed_actors; int perfect; #ifdef THORIUM_SCHEDULER_ENABLE_SYMMETRIC_SCHEDULING struct core_map symmetric_actor_scripts; int script; #endif node = thorium_worker_pool_get_node(self->pool); spawned_actors = thorium_node_get_counter(node, CORE_COUNTER_SPAWNED_ACTORS); /* There is nothing to balance... */ if (spawned_actors == 0) { return; } killed_actors = thorium_node_get_counter(node, CORE_COUNTER_KILLED_ACTORS); /* * The system can probably not be balanced to get in * a better shape anyway. */ if (spawned_actors == self->last_spawned_actors && killed_actors == self->last_killed_actors && self->last_migrations == 0) { printf("SCHEDULER: balance can not be improved because nothing changed.\n"); return; } /* Check if we have perfection */ perfect = 1; for (i = 0; i < thorium_worker_pool_worker_count(self->pool); i++) { worker = thorium_worker_pool_get_worker(self->pool, i); load_value = thorium_worker_get_epoch_load(worker) * 100; if (load_value != 100) { perfect = 0; break; } } if (perfect) { printf("SCHEDULER: perfect balance can not be improved.\n"); return; } /* update counters */ self->last_spawned_actors = spawned_actors; self->last_killed_actors = killed_actors; /* Otherwise, try to balance things */ core_timer_init(&timer); core_timer_start(&timer); #ifdef THORIUM_SCHEDULER_ENABLE_SYMMETRIC_SCHEDULING core_map_init(&symmetric_actor_scripts, sizeof(int), sizeof(int)); thorium_balancer_detect_symmetric_scripts(self, &symmetric_actor_scripts); #endif #ifdef THORIUM_WORKER_ENABLE_LOCK /* Lock all workers first */ for (i = 0; i < thorium_worker_pool_worker_count(self->pool); i++) { worker = thorium_worker_pool_get_worker(self->pool, i); thorium_worker_lock(worker); } #endif core_vector_init(&migrations, sizeof(struct thorium_migration)); #ifdef THORIUM_SCHEDULER_ENABLE_VERBOSITY printf("BALANCING\n"); #endif core_vector_init(&loads, sizeof(int)); core_vector_init(&loads_unsorted, sizeof(int)); core_vector_init(&burdened_workers, sizeof(struct core_pair)); core_vector_init(&stalled_workers, sizeof(struct core_pair)); core_vector_init(&actors_to_migrate, sizeof(struct core_pair)); for (i = 0; i < thorium_worker_pool_worker_count(self->pool); i++) { worker = thorium_worker_pool_get_worker(self->pool, i); load_value = thorium_worker_get_scheduling_epoch_load(worker) * SCHEDULER_PRECISION; #if 0 printf("DEBUG LOAD %d %d\n", i, load_value); #endif core_vector_push_back(&loads, &load_value); core_vector_push_back(&loads_unsorted, &load_value); } core_vector_sort_int(&loads); stalled_percentile = core_statistics_get_percentile_int(&loads, SCHEDULER_WINDOW); /*load_percentile_25 = core_statistics_get_percentile_int(&loads, 25);*/ load_percentile_50 = core_statistics_get_percentile_int(&loads, 50); /*load_percentile_75 = core_statistics_get_percentile_int(&loads, 75);*/ burdened_percentile = core_statistics_get_percentile_int(&loads, 100 - SCHEDULER_WINDOW); #ifdef THORIUM_SCHEDULER_ENABLE_VERBOSITY printf("Percentiles for epoch loads: "); core_statistics_print_percentiles_int(&loads); #endif for (i = 0; i < thorium_worker_pool_worker_count(self->pool); i++) { worker = thorium_worker_pool_get_worker(self->pool, i); load_value = core_vector_at_as_int(&loads_unsorted, i); set = thorium_worker_get_actors(worker); if (stalled_percentile == burdened_percentile) { #ifdef THORIUM_SCHEDULER_ENABLE_VERBOSITY printf("scheduling_class:%s ", THORIUM_CLASS_NORMAL_STRING); #endif } else if (load_value <= stalled_percentile) { #ifdef THORIUM_SCHEDULER_ENABLE_VERBOSITY printf("scheduling_class:%s ", THORIUM_CLASS_STALLED_STRING); #endif core_pair_init(&pair, load_value, i); core_vector_push_back(&stalled_workers, &pair); } else if (load_value >= burdened_percentile) { #ifdef THORIUM_SCHEDULER_ENABLE_VERBOSITY printf("scheduling_class:%s ", THORIUM_CLASS_BURDENED_STRING); #endif core_pair_init(&pair, load_value, i); core_vector_push_back(&burdened_workers, &pair); } else { #ifdef THORIUM_SCHEDULER_ENABLE_VERBOSITY printf("scheduling_class:%s ", THORIUM_CLASS_NORMAL_STRING); #endif } #ifdef THORIUM_SCHEDULER_ENABLE_VERBOSITY thorium_worker_print_actors(worker, self); #endif } core_vector_sort_int_reverse(&burdened_workers); core_vector_sort_int(&stalled_workers); stalled_count = core_vector_size(&stalled_workers); #ifdef THORIUM_SCHEDULER_ENABLE_VERBOSITY printf("MIGRATIONS (stalled: %d, burdened: %d)\n", (int)core_vector_size(&stalled_workers), (int)core_vector_size(&burdened_workers)); #endif stalled_index = 0; core_vector_iterator_init(&vector_iterator, &burdened_workers); while (stalled_count > 0 && core_vector_iterator_get_next_value(&vector_iterator, &pair)) { old_worker = core_pair_get_second(&pair); worker = thorium_worker_pool_get_worker(self->pool, old_worker); set = thorium_worker_get_actors(worker); /* thorium_worker_print_actors(worker); printf("\n"); */ /* * Lock the worker and try to select actors for migration */ core_map_iterator_init(&set_iterator, set); maximum = -1; with_maximum = 0; total = 0; with_messages = 0; while (core_map_iterator_get_next_key_and_value(&set_iterator, &actor_name, NULL)) { actor = thorium_node_get_actor_from_name(thorium_worker_pool_get_node(self->pool), actor_name); messages = thorium_balancer_get_actor_production(self, actor); if (maximum == -1 || messages > maximum) { maximum = messages; with_maximum = 1; } else if (messages == maximum) { with_maximum++; } if (messages > 0) { ++with_messages; } total += messages; } core_map_iterator_destroy(&set_iterator); core_map_iterator_init(&set_iterator, set); --with_maximum; candidates = 0; load_value = thorium_worker_get_scheduling_epoch_load(worker) * SCHEDULER_PRECISION; remaining_load = load_value; #if 0 printf("maximum %d with_maximum %d\n", maximum, with_maximum); #endif while (core_map_iterator_get_next_key_and_value(&set_iterator, &actor_name, NULL)) { actor = thorium_node_get_actor_from_name(thorium_worker_pool_get_node(self->pool), actor_name); if (actor == NULL) { continue; } messages = thorium_balancer_get_actor_production(self, actor); #ifdef THORIUM_SCHEDULER_ENABLE_SYMMETRIC_SCHEDULING script = thorium_actor_script(actor); /* symmetric actors are migrated elsewhere. */ if (core_map_get_value(&symmetric_actor_scripts, &script, NULL)) { continue; } #endif /* Simulate the remaining load */ projected_load = remaining_load; projected_load -= ((0.0 + messages) / total) * load_value; #ifdef THORIUM_SCHEDULER_DEBUG printf(" TESTING actor %d, production was %d, projected_load is %d (- %d * (1 - %d/%d)\n", actor_name, messages, projected_load, load_value, messages, total); #endif /* An actor without any queued messages should not be migrated */ if (messages > 0 && ((with_maximum > 0 && messages == maximum) || messages < maximum) /* * Avoid removing too many actors because * generating a stalled one is not desired */ && (projected_load >= load_percentile_50 /* * The previous rule does not apply when there * are 2 actors. */ || with_messages == 2) ) { remaining_load = projected_load; candidates++; if (messages == maximum) { --with_maximum; } core_pair_init(&pair, messages, actor_name); core_vector_push_back(&actors_to_migrate, &pair); #ifdef THORIUM_SCHEDULER_DEBUG printf("early CANDIDATE for migration: actor %d, worker %d\n", actor_name, old_worker); #endif } } core_map_iterator_destroy(&set_iterator); } core_vector_iterator_destroy(&vector_iterator); /* Sort the candidates */ /* core_vector_sort_int(&actors_to_migrate); printf("Percentiles for production: "); core_statistics_print_percentiles_int(&actors_to_migrate); */ /* Sort them in reverse order. */ core_vector_sort_int_reverse(&actors_to_migrate); core_vector_iterator_init(&vector_iterator, &actors_to_migrate); /* For each highly active actor, * try to match it with a stalled worker */ while (core_vector_iterator_get_next_value(&vector_iterator, &pair)) { actor_name = core_pair_get_second(&pair); actor = thorium_node_get_actor_from_name(thorium_worker_pool_get_node(self->pool), actor_name); if (actor == NULL) { continue; } messages = thorium_balancer_get_actor_production(self, actor); old_worker = thorium_actor_assigned_worker(actor); worker = thorium_worker_pool_get_worker(self->pool, old_worker); /* old_total can not be 0 because otherwise the would not * be burdened. */ old_total = thorium_worker_get_production(worker, self); with_messages = thorium_worker_get_producer_count(worker, self); old_load = thorium_worker_get_scheduling_epoch_load(worker) * SCHEDULER_PRECISION; actor_load = ((0.0 + messages) / old_total) * old_load; /* Try to find a stalled worker that can take it. */ test_stalled_index = stalled_index; tests = 0; predicted_new_load = 0; found_match = 0; while (tests < stalled_count) { core_vector_get_value(&stalled_workers, test_stalled_index, &pair); new_worker_index = core_pair_get_second(&pair); new_worker = thorium_worker_pool_get_worker(self->pool, new_worker_index); new_load = thorium_worker_get_scheduling_epoch_load(new_worker) * SCHEDULER_PRECISION; /*new_total = thorium_worker_get_production(new_worker);*/ predicted_new_load = new_load + actor_load; if (predicted_new_load > SCHEDULER_PRECISION /* && with_messages != 2 */) { #ifdef THORIUM_SCHEDULER_DEBUG printf("Scheduler: skipping actor %d, predicted load is %d >= 100\n", actor_name, predicted_new_load); #endif ++tests; ++test_stalled_index; if (test_stalled_index == stalled_count) { test_stalled_index = 0; } continue; } /* Otherwise, this stalled worker is fine... */ stalled_index = test_stalled_index; found_match = 1; break; } /* This actor can not be migrated to any stalled worker. */ if (!found_match) { continue; } /* Otherwise, update the load of the stalled one and go forward with the change. */ pair_pointer = (struct core_pair *)core_vector_at(&stalled_workers, stalled_index); core_pair_set_first(pair_pointer, predicted_new_load); ++stalled_index; if (stalled_index == stalled_count) { stalled_index = 0; } #if 0 new_worker = thorium_worker_pool_get_worker(pool, new_worker_index); printf(" CANDIDATE: actor %d old worker %d (%d - %d = %d) new worker %d (%d + %d = %d)\n", actor_name, old_worker, value, messages, 2new_score, new_worker_index, new_worker_old_score, messages, new_worker_new_score); #endif thorium_migration_init(&migration, actor_name, old_worker, new_worker_index); core_vector_push_back(&migrations, &migration); thorium_migration_destroy(&migration); } core_vector_iterator_destroy(&vector_iterator); core_vector_destroy(&stalled_workers); core_vector_destroy(&burdened_workers); core_vector_destroy(&loads); core_vector_destroy(&loads_unsorted); core_vector_destroy(&actors_to_migrate); /* Update the last values */ for (i = 0; i < thorium_worker_pool_worker_count(self->pool); i++) { worker = thorium_worker_pool_get_worker(self->pool, i); set = thorium_worker_get_actors(worker); core_map_iterator_init(&set_iterator, set); while (core_map_iterator_get_next_key_and_value(&set_iterator, &actor_name, NULL)) { actor = thorium_node_get_actor_from_name(thorium_worker_pool_get_node(self->pool), actor_name); thorium_balancer_update_actor_production(self, actor); } core_map_iterator_destroy(&set_iterator); thorium_worker_reset_scheduling_epoch(worker); } #ifdef THORIUM_SCHEDULER_ENABLE_SYMMETRIC_SCHEDULING /* Generate migrations for symmetric actors. */ thorium_balancer_generate_symmetric_migrations(self, &symmetric_actor_scripts, &migrations); #endif /* Actually do the migrations */ core_vector_iterator_init(&vector_iterator, &migrations); while (core_vector_iterator_next(&vector_iterator, (void **)&migration_to_do)) { thorium_balancer_migrate(self, migration_to_do); } core_vector_iterator_destroy(&vector_iterator); self->last_migrations = core_vector_size(&migrations); core_vector_destroy(&migrations); #ifdef THORIUM_WORKER_ENABLE_LOCK /* Unlock all workers */ for (i = 0; i < thorium_worker_pool_worker_count(self->pool); i++) { worker = thorium_worker_pool_get_worker(self->pool, i); thorium_worker_unlock(worker); } #endif #ifdef THORIUM_SCHEDULER_ENABLE_SYMMETRIC_SCHEDULING core_map_destroy(&symmetric_actor_scripts); #endif core_timer_stop(&timer); printf("SCHEDULER: elapsed time for balancing: %d us, %d migrations performed\n", (int)(core_timer_get_elapsed_nanoseconds(&timer) / 1000), self->last_migrations); }