bucket_t* bucket_init(unsigned int node_capacity) { bucket_t* bucket; bool error = false; /* Capacity must strictly be a positive number */ if(node_capacity == 0) { fprintf(stderr, "bucket_init: Invalid capacity"); error = true; } /* Allocate memory for the bucket */ if(!error && (bucket = malloc(sizeof(struct bucket_struct))) == NULL) { perror("bucket_init"); error = true; } /* Initialize all bucket's fields */ if(!error) { bucket->size = 0; bucket->last_node_size = 0; bucket->node_capacity = node_capacity; bucket->chain = NULL; } /* If an error occured, free any allocated memory */ if(error) bucket_destroy(&bucket); return bucket; }
/* * Bucket-sort algorithm. */ extern void bucketsort(int *array, int n) { int max; /* Maximum number. */ int i, j; /* Loop indexes. */ int range; /* Bucket range. */ struct minibucket *minib; /* Working mini-bucket. */ struct message *msg; /* Working message. */ struct bucket **todo; /* Todo buckets. */ struct bucket **done; /* Done buckets. */ uint64_t start, end; /* Timers. */ /* Setup slaves. */ open_noc_connectors(); spawn_slaves(); sync_slaves(); todo = smalloc(NUM_BUCKETS*sizeof(struct bucket *)); done = smalloc(NUM_BUCKETS*sizeof(struct bucket *)); for (i = 0; i < NUM_BUCKETS; i++) { done[i] = bucket_create(); todo[i] = bucket_create(); } /* Find max number in the array. */ start = timer_get(); max = INT_MIN; for (i = 0; i < n; i++) { /* Found. */ if (array[i] > max) max = array[i]; } /* Distribute numbers. */ range = max/NUM_BUCKETS; for (i = 0; i < n; i++) { j = array[i]/range; if (j >= NUM_BUCKETS) j = NUM_BUCKETS - 1; bucket_insert(&todo[j], array[i]); } end = timer_get(); master += timer_diff(start, end); /* Sort buckets. */ j = 0; for (i = 0; i < NUM_BUCKETS; i++) { while (bucket_size(todo[i]) > 0) { minib = bucket_pop(todo[i]); /* Send message. */ msg = message_create(SORTWORK, i, minib->size); message_send(outfd[j], msg); message_destroy(msg); /* Send data. */ communication += data_send(outfd[j], minib->elements, minib->size*sizeof(int)); minibucket_destroy(minib); j++; /* * Slave processes are busy. * So let's wait for results. */ if (j == nclusters) { /* Receive results. */ for (/* NOOP */ ; j > 0; j--) { /* Receive message. */ msg = message_receive(infd[nclusters - j]); /* Receive mini-bucket. */ minib = minibucket_create(); minib->size = msg->u.sortresult.size; communication += data_receive(infd[nclusters -j], minib->elements, minib->size*sizeof(int)); bucket_push(done[msg->u.sortresult.id], minib); message_destroy(msg); } } } } /* Receive results. */ for (/* NOOP */ ; j > 0; j--) { /* Receive message. */ msg = message_receive(infd[j - 1]); /* Receive bucket. */ minib = minibucket_create(); minib->size = msg->u.sortresult.size; communication += data_receive(infd[j - 1], minib->elements, minib->size*sizeof(int)); bucket_push(done[msg->u.sortresult.id], minib); message_destroy(msg); } start = timer_get(); rebuild_array(done, array); end = timer_get(); master += timer_diff(start, end); /* House keeping. */ for (i = 0; i < NUM_BUCKETS; i++) { bucket_destroy(todo[i]); bucket_destroy(done[i]); } free(done); free(todo); join_slaves(); close_noc_connectors(); }
bucket_t* bucket_split(bucket_t* bucket1, bool (*split_funct)(void* data, unsigned int key), void* data) { assert(bucket1 != NULL && split_funct != NULL); unsigned int i; unsigned int curr_node_size; bool error = false; bucket_t* bucket2 = NULL; bucket_t** dst_bucket_ptr = NULL; bucket_t* src_bucket = NULL; bucket_node_t* src_bucket_node = NULL; /* Allocate memory for the new bucket */ if(!error && (bucket2 = bucket_init(bucket1->node_capacity)) == NULL) error = true; /* Make a copy of the old bucket's head */ if((src_bucket = bucket_init(bucket1->node_capacity)) == NULL) error = true; if(!error) { /* Move internal data from the old bucket' head to the new bucket head. No deep copy is done, the chain is moved too. */ *src_bucket = *bucket1; /* Reset the given bucket's head */ *bucket1 = *bucket2; /* Initialize src_bucket_node */ src_bucket_node = src_bucket->chain; } /* For every bucket_node in the chain... */ while(!error && src_bucket_node != NULL) { /* Get the current bucket_node's size */ curr_node_size = bucket_node_size(src_bucket, src_bucket_node); /* For every entry in the bucket_node... */ for(i=0; !error && i < curr_node_size; i++) { /* Call split_funct to get the target bucket */ if(!(*split_funct)(data, src_bucket_node->key[i])) dst_bucket_ptr = &bucket1; else dst_bucket_ptr = &bucket2; /* Append to the appropriate new bucket (entries are already sorted) */ if(!bucket_node_insert(*dst_bucket_ptr, bucket_size(*dst_bucket_ptr), src_bucket_node->key[i], src_bucket_node->value[i])) error = true; } src_bucket_node = src_bucket_node->overflow; } if(error) { /* Restore the old bucket in its original condition */ *bucket1 = *src_bucket; /* Free allocated memory */ bucket_destroy(&bucket2); /* Prevent old bucket chain from being destroyed */ src_bucket->chain = NULL; } /* Destroy the old bucket */ bucket_destroy(&src_bucket); return bucket2; }
int vos_process_create(struct Stmt *create) { int i = 0; int s = 0; int n_in = 0; int n_done = 0; int n_bucket = 1; struct File *F = 0; struct StmtMeta *pin = create->in; struct ProcCreate *cproc = 0; struct Bucket *buckets = 0; struct Field *fld = 0; /* how many input ? */ while (pin) { n_in++; pin = pin->next; } /* how many field output (bucket) ? */ fld = create->out->fields; while (fld) { n_bucket++; fld = fld->next; } s = file_open(&F, create->out->filename, FOPEN_WO); if (s) goto err; cproc = (struct ProcCreate *) calloc(n_in, sizeof(struct ProcCreate)); if (! cproc) { s = E_MEM; goto err; } buckets = (struct Bucket *) calloc(n_bucket, sizeof(struct Bucket)); if (! buckets) { s = E_MEM; goto err; } pin = create->in; for (i = 0; i < n_in; i++) { stmt_update_meta(create->prev, pin); cproc[i].in = pin; cproc[i].status = CPROC_START; cproc[i].buckets = buckets; pthread_create(&cproc[i].tid, 0, create_process, (void *) &cproc[i]); pin = pin->next; } /* phase 1: create & fill bucket */ for (i = 0; i < n_in; i++) { /* wait until child fill the buckets */ while (cproc[i].status == CPROC_START) sleep(THREAD_TIME_WAIT); if (cproc[i].status == CPROC_DONE) { pthread_join(cproc[i].tid, 0); if (cproc[i].retval) { s = cproc[i].retval; goto err; } n_done++; cproc[i].status = CPROC_END; } } if (_vos.debug & DBG_CREATE) { printf("parent: writing bucket\n"); } s = bucket_write(buckets, n_bucket, F, create->out->fields); if (s) goto err; /* phase 2: fill the buckets */ while (n_done < n_in) { for (i = 0; i < n_in; i++) { /* restart threads */ if (cproc[i].status == CPROC_BUCKETS_FULL) cproc[i].status = CPROC_START; } for (i = 0; i < n_in; i++) { /* wait until child fill the buckets */ while (cproc[i].status == CPROC_START) sleep(THREAD_TIME_WAIT); if (cproc[i].status == CPROC_DONE) { pthread_join(cproc[i].tid, 0); /* catch error here */ if (cproc[i].retval) { s = cproc[i].retval; goto err; } n_done++; cproc[i].status = CPROC_END; } } if (_vos.debug & DBG_CREATE) { printf("parent: writing bucket\n"); } s = bucket_write(buckets, n_bucket, F, create->out->fields); if (s) goto err; } err: if (s && cproc) { /* cancel all thread */ for (i = 0; i < n_in; i++) { if (cproc[i].status == CPROC_BUCKETS_FULL) { cproc[i].status = CPROC_DONE; pthread_join(cproc[i].tid, (void *) &cproc[i].retval); } } } bucket_destroy(buckets, n_bucket); if (buckets) free(buckets); if (cproc) free(cproc); if (F) file_close(&F); return s; }