vortex/tests/opencl/b+tree/main.cc
2024-04-23 00:12:51 -04:00

2457 lines
62 KiB
C++

// # ifdef __cplusplus
// extern "C" {
// # endif
//========================================================================================================================================================================================================200
//======================================================================================================================================================150
//====================================================================================================100
//==================================================50
//========================================================================================================================================================================================================200
// INFORMATION
//========================================================================================================================================================================================================200
//======================================================================================================================================================150
// UPDATE
//======================================================================================================================================================150
// 2009; Amittai Aviram; entire code written in C;
// 2010; Jordan Fix and Andrew Wilkes; code converted to CUDA;
// 2011.10; Lukasz G. Szafaryn; code converted to portable form, to C, OpenMP, CUDA, PGI versions;
// 2011.12; Lukasz G. Szafaryn; Split different versions for Rodinia.
// 2011.12; Lukasz G. Szafaryn; code converted to OpenCL;
//======================================================================================================================================================150
// DESCRIPTION
//======================================================================================================================================================150
// Description
//======================================================================================================================================================150
// USE
//======================================================================================================================================================150
// EXAMPLE:
// ./a.out -file ./input/mil.txt
// ...then enter any of the following commands after the prompt > :
// f <x> -- Find the value under key <x>
// p <x> -- Print the path from the root to key k and its associated value
// t -- Print the B+ tree
// l -- Print the keys of the leaves (bottom row of the tree)
// v -- Toggle output of pointer addresses ("verbose") in tree and leaves.
// k <x> -- Run <x> bundled queries on the CPU and GPU (B+Tree) (Selects random values for each search)
// j <x> <y> -- Run a range search of <x> bundled queries on the CPU and GPU (B+Tree) with the range of each search of size <y>
// x <z> -- Run a single search for value z on the GPU and CPU
// y <a> <b> -- Run a single range search for range a-b on the GPU and CPU
// q -- Quit. (Or use Ctl-D.)
//======================================================================================================================================================150
// END
//======================================================================================================================================================150
//========================================================================================================================================================================================================200
// DEFINE/INCLUDE
//========================================================================================================================================================================================================200
//======================================================================================================================================================150
// LIBRARIES
//======================================================================================================================================================150
#include <stdio.h> // (in directory known to compiler) needed by printf, stderr
#include <limits.h> // (in directory known to compiler) needed by INT_MIN, INT_MAX
#include <sys/time.h> // (in directory known to compiler) needed by gettimeofday
#include <math.h> // (in directory known to compiler) needed by log, pow
#include <string.h> // (in directory known to compiler) needed by memset
#include <CL/cl.h>
//======================================================================================================================================================150
// COMMON
//======================================================================================================================================================150
#include "common.h" // (in directory provided here)
//======================================================================================================================================================150
// DEFINE
//======================================================================================================================================================150
//======================================================================================================================================================150
// UTILITIES
//======================================================================================================================================================150
#include "timer.h" // (in directory provided here)
#include "num.h" // (in directory provided here)
//======================================================================================================================================================150
// KERNEL HEADERS
//======================================================================================================================================================150
#include "kernel_gpu_opencl_wrapper.h" // (in directory provided here)
#include "kernel_gpu_opencl_wrapper_2.h" // (in directory provided here)
//======================================================================================================================================================150
// HEADER
//======================================================================================================================================================150
#include "./main.h" // (in directory provided here)
//======================================================================================================================================================150
// END
//======================================================================================================================================================150
//========================================================================================================================================================================================================200
// VARIABLES
//========================================================================================================================================================================================================200
// general variables
knode *knodes;
record *krecords;
char *mem;
long freeptr;
long malloc_size;
long size;
long maxheight;
/* The order determines the maximum and minimum
* number of entries (keys and pointers) in any
* node. Every node has at most order - 1 keys and
* at least (roughly speaking) half that number.
* Every leaf has as many pointers to data as keys,
* and every internal node has one more pointer
* to a subtree than the number of keys.
* This global variable is initialized to the
* default value.
*/
int order = DEFAULT_ORDER;
/* The queue is used to print the tree in
* level order, starting from the root
* printing each entire rank on a separate
* line, finishing with the leaves.
*/
node *queue = NULL;
/* The user can toggle on and off the "verbose"
* property, which causes the pointer addresses
* to be printed out in hexadecimal notation
* next to their corresponding keys.
*/
bool verbose_output = false;
/* OpenCL configurations.
* Declared in common.h
*/
int platform_id_inuse = 0; // platform id in use (default: 0)
int device_id_inuse = 0; //device id in use (default : 0)
cl_device_type device_type;
//========================================================================================================================================================================================================200
// FUNCTIONS
//========================================================================================================================================================================================================200
//======================================================================================================================================================150
// Components
//======================================================================================================================================================150
void
list_init( list_t *l,
int32_t (*compare)(const void *key,
const void *with),
void (*datum_delete)(void *))
{
l->head = l->tail = NULL;
l->length = 0;
l->compare = compare;
l->datum_delete = datum_delete;
}
void
list_delete(list_t *l)
{
list_item_t *li, *del;
for (li = l->head; li;) {
del = li;
li = li->next;
list_item_delete(del, l->datum_delete);
}
l->head = l->tail = NULL;
l->length = 0;
}
void
list_reset(list_t *l)
{
list_delete(l);
}
void
list_insert_item_head( list_t *l,
list_item_t *i)
{
if (l->head) {
i->next = l->head;
l->head->pred = i;
l->head = i;
l->head->pred = NULL;
} else {
l->head = l->tail = i;
i->next = i->pred = NULL;
}
l->length++;
}
void
list_insert_item_tail( list_t *l,
list_item_t *i)
{
if (l->head) {
l->tail->next = i;
i->pred = l->tail;
i->next = NULL;
l->tail = i;
} else {
l->head = l->tail = i;
i->next = i->pred = NULL;
}
l->length++;
}
void
list_insert_item_before(list_t *l,
list_item_t *next,
list_item_t *i)
{
/* Assume next is actually in the list! */
/* If it's not, we may lose the list. */
if (l->head == next) {
i->next = next;
i->pred = NULL;
l->head = i;
next->pred = i;
} else {
i->next = next;
i->pred = next->pred;
next->pred->next = i;
next->pred = i;
}
l->length++;
}
void
list_insert_item_after( list_t *l,
list_item_t *pred,
list_item_t *i)
{
/* Assume pred is actually in the list! */
/* If it's not, we may lose the list. */
if (l->tail == pred) {
i->pred = pred;
i->next = NULL;
l->tail = i;
pred->next = i;
} else {
i->pred = pred;
i->next = pred->next;
pred->next->pred = i;
pred->next = i;
}
l->length++;
}
void
list_insert_item_sorted(list_t *l,
list_item_t *i)
{
list_item_t *itr;
if (l->head) {
for (itr = l->head; itr && l->compare(list_item_get_datum(i),
list_item_get_datum(itr)) < 0;
itr = itr->next)
;
if (itr) {
i->next = itr;
i->pred = itr->pred;
itr->pred = i;
i->pred->next = i;
} else {
l->tail->next = i;
i->pred = l->tail;
i->next = NULL;
l->tail = i;
}
} else {
l->head = l->tail = i;
i->pred = i->next = NULL;
}
l->length++;
}
void
list_insert_head( list_t *l,
void *v)
{
list_item_t *i;
i = (list_item_t *)malloc(sizeof (*i));
list_item_init(i, v);
if (l->head) {
i->next = l->head;
l->head->pred = i;
l->head = i;
l->head->pred = NULL;
} else {
l->head = l->tail = i;
i->next = i->pred = NULL;
}
l->length++;
}
void
list_insert_tail( list_t *l,
void *v)
{
list_item_t *i;
i = (list_item_t *)malloc(sizeof (*i));
list_item_init(i, v);
if (l->head) {
l->tail->next = i;
i->pred = l->tail;
i->next = NULL;
l->tail = i;
} else {
l->head = l->tail = i;
i->next = i->pred = NULL;
}
l->length++;
}
void
list_insert_before( list_t *l,
list_item_t *next,
void *v)
{
list_item_t *i;
i = (list_item_t *)malloc(sizeof (*i));
list_item_init(i, v);
/* Assume next is actually in the list! */
/* If it's not, we may lose the list. */
if (l->head == next) {
i->next = next;
i->pred = NULL;
l->head = i;
next->pred = i;
} else {
i->next = next;
i->pred = next->pred;
next->pred->next = i;
next->pred = i;
}
l->length++;
}
void
list_insert_after( list_t *l,
list_item_t *pred,
void *v)
{
list_item_t *i;
i = (list_item_t *)malloc(sizeof (*i));
list_item_init(i, v);
/* Assume pred is actually in the list! */
/* If it's not, we may lose the list. */
if (l->tail == pred) {
i->pred = pred;
i->next = NULL;
l->tail = i;
pred->next = i;
} else {
i->pred = pred;
i->next = pred->next;
pred->next->pred = i;
pred->next = i;
}
l->length++;
}
void
list_insert_sorted( list_t *l,
void *v)
{
list_item_t *itr;
list_item_t *i;
i = (list_item_t *)malloc(sizeof (*i));
list_item_init(i, v);
if (l->head) {
for (itr = l->head; itr && l->compare(list_item_get_datum(i),
list_item_get_datum(itr)) < 0;
itr = itr->next)
;
if (itr) {
i->next = itr;
i->pred = itr->pred;
itr->pred = i;
i->pred->next = i;
} else {
l->tail->next = i;
i->pred = l->tail;
i->next = NULL;
l->tail = i;
}
} else {
l->head = l->tail = i;
i->pred = i->next = NULL;
}
l->length++;
}
void
list_remove_item( list_t *l,
list_item_t *i)
{
if (i == l->head) {
l->head = l->head->next;
if (l->head)
l->head->pred = NULL;
else
l->tail = NULL;
} else if (i == l->tail) {
l->tail = l->tail->pred;
l->tail->next = NULL;
} else {
i->pred->next = i->next;
i->next->pred = i->pred;
}
l->length--;
list_item_delete(i, l->datum_delete);
}
void
list_remove_head(list_t *l)
{
list_remove_item(l, l->head);
}
void
list_remove_tail(list_t *l)
{
list_remove_item(l, l->tail);
}
list_item_t*
list_find_item( list_t *l,
void *datum)
{
list_item_t *li;
for (li = l->head; li && l->compare(datum, list_item_get_datum(li));
li = li->next)
;
return li;
}
list_item_t*
list_get_head_item(list_t *l)
{
return l->head;
}
list_item_t*
list_get_tail_item(list_t *l)
{
return l->tail;
}
void*
list_find( list_t *l,
void *datum)
{
list_item_t *li;
for (li = l->head; li && l->compare(datum, list_item_get_datum(li));
li = li->next)
;
return li ? li->datum : NULL;
}
void*
list_get_head(list_t *l)
{
return l->head ? l->head->datum : NULL;
}
void*
list_get_tail(list_t *l)
{
return l->tail ? l->tail->datum : NULL;
}
uint32_t
list_get_length(list_t *l)
{
return l->length;
}
bool
list_is_empty(list_t *l)
{
return (l->length == 0);
}
bool
list_not_empty(list_t *l)
{
return (l->length != 0);
}
void
list_visit_items( list_t *l,
void (*visitor)(void *v))
{
list_item_t *li;
for (li = l->head; li; li = li->next)
visitor(list_item_get_datum(li));
}
void
list_item_init( list_item_t *li,
void *datum)
{
li->pred = li->next = NULL;
li->datum = datum;
}
void
list_item_delete( list_item_t *li,
void (*datum_delete)(void *datum))
{
if (datum_delete) {
datum_delete(li->datum);
}
free(li);
}
void *
list_item_get_datum(list_item_t *li)
{
return li->datum;
}
void
list_iterator_init( list_t *l,
list_iterator_t *li)
{
*li = l ? l->head : NULL;
}
void
list_iterator_delete(list_iterator_t *li)
{
*li = NULL;
}
void
list_iterator_next(list_iterator_t *li)
{
if (*li)
*li = (*li)->next;
}
void
list_iterator_prev(list_iterator_t *li)
{
if (*li)
*li = (*li)->pred;
}
void *
list_iterator_get_datum(list_iterator_t *li)
{
return *li ? (*li)->datum : NULL;
}
bool
list_iterator_is_valid(list_iterator_t *li)
{
return (*li != NULL);
}
void
list_reverse_iterator_init( list_t *l,
list_reverse_iterator_t *li)
{
*li = l ? l->tail : NULL;
}
void
list_reverse_iterator_delete(list_reverse_iterator_t *li)
{
*li = NULL;
}
void
list_reverse_iterator_next(list_reverse_iterator_t *li)
{
if (*li)
*li = (*li)->pred;
}
void
list_reverse_iterator_prev(list_reverse_iterator_t *li)
{
if (*li)
*li = (*li)->next;
}
void *
list_reverse_iterator_get_datum(list_reverse_iterator_t *li)
{
return *li ? (*li)->datum : NULL;
}
bool
list_reverse_iterator_is_valid(list_reverse_iterator_t *li)
{
return (li != NULL);
}
//======================================================================================================================================================150
// OUTPUT AND UTILITIES
//======================================================================================================================================================150
/* */
void *
kmalloc(int size)
{
//printf("size: %d, current offset: %p\n",size,freeptr);
void * r = (void *)freeptr;
freeptr+=size;
if(freeptr > malloc_size+(long)mem){
printf("Memory Overflow\n");
exit(1);
}
return r;
}
//transforms the current B+ Tree into a single, contiguous block of memory to be used on the GPU
long
transform_to_cuda( node * root,
bool verbose)
{
struct timeval one,two;
double time;
gettimeofday (&one, NULL);
long max_nodes = (long)(pow(order,log(size)/log(order/2.0)-1) + 1);
malloc_size = size*sizeof(record) + max_nodes*sizeof(knode);
mem = (char*)malloc(malloc_size);
if(mem==NULL){
printf("Initial malloc error\n");
exit(1);
}
freeptr = (long)mem;
krecords = (record * )kmalloc(size*sizeof(record));
// printf("%d records\n", size);
knodes = (knode *)kmalloc(max_nodes*sizeof(knode));
// printf("%d knodes\n", max_nodes);
queue = NULL;
enqueue(root);
node * n;
knode * k;
int i;
long nodeindex = 0;
long recordindex = 0;
long queueindex = 0;
knodes[0].location = nodeindex++;
while( queue != NULL ) {
n = dequeue();
k = &knodes[queueindex];
k->location = queueindex++;
k->is_leaf = n->is_leaf;
k->num_keys = n->num_keys+2;
//start at 1 because 0 is set to INT_MIN
k->keys[0]=INT_MIN;
k->keys[k->num_keys-1]=INT_MAX;
for(i=k->num_keys; i < order; i++)k->keys[i]=INT_MAX;
if(!k->is_leaf){
k->indices[0]=nodeindex++;
// if(k->indices[0]>3953){
// printf("ERROR: %d\n", k->indices[0]);
// }
for(i=1;i<k->num_keys-1;i++){
k->keys[i] = n->keys[i-1];
enqueue((node * )n->pointers[i-1]);
k->indices[i] = nodeindex++;
// if(k->indices[i]>3953){
// printf("ERROR 1: %d\n", k->indices[i]);
// }
//knodes[nodeindex].location = nodeindex++;
}
//for final point of n
enqueue((node * )n->pointers[i-1]);
}
else{
k->indices[0]=0;
for(i=1;i<k->num_keys-1;i++){
k->keys[i] = n->keys[i-1];
krecords[recordindex].value=((record *)n->pointers[i-1])->value;
k->indices[i] = recordindex++;
// if(k->indices[i]>3953){
// printf("ERROR 2: %d\n", k->indices[i]);
// }
}
}
k->indices[k->num_keys-1]=queueindex;
// if(k->indices[k->num_keys-1]>3953){
// printf("ERROR 3: %d\n", k->indices[k->num_keys-1]);
// }
if(verbose){
printf("Successfully created knode with index %d\n", k->location);
printf("Is Leaf: %d, Num Keys: %d\n", k->is_leaf, k->num_keys);
printf("Pointers: ");
for(i=0;i<k->num_keys;i++)
printf("%d | ", k->indices[i]);
printf("\nKeys: ");
for(i=0;i<k->num_keys;i++)
printf("%d | ", k->keys[i]);
printf("\n\n");
}
}
long mem_used = size*sizeof(record)+(nodeindex)*sizeof(knode);
if(verbose){
for(i = 0; i < size; i++)
printf("%d ", krecords[i].value);
printf("\nNumber of records = %lu, sizeof(record)=%lu, total=%lu\n",size,sizeof(record),size*sizeof(record));
printf("Number of knodes = %lu, sizeof(knode)=%lu, total=%lu\n",nodeindex,sizeof(knode),(nodeindex)*sizeof(knode));
printf("\nDone Transformation. Mem used: %ld\n", mem_used);
}
gettimeofday (&two, NULL);
double oneD = one.tv_sec + (double)one.tv_usec * .000001;
double twoD = two.tv_sec + (double)two.tv_usec * .000001;
time = twoD-oneD;
printf("Tree transformation took %f\n", time);
return mem_used;
}
/* */
list_t *
findRange( node * root,
int start,
int end)
{
int i;
node * c = find_leaf( root, start, false );
if (c == NULL) return NULL;
list_t * retList = (list_t *)malloc(sizeof(list_t));
list_init(retList,NULL,NULL);
int counter = 0;
bool cont = true;
while(cont && c!=0){
cont = false;
for(i = 0;i < c->num_keys;i++){
if(c->keys[i] >= start && c->keys[i] <= end){
//list_insert_tail(retList,(record *)c->pointers[i]);
counter++;
cont = true;
}else{
cont = false;
break;
}
}
c = (node *)c->pointers[order-1];
}
return retList;
}
/* First message to the user. */
void
usage_1( void )
{
printf("B+ Tree of Order %d.\n", order);
printf("\tAmittai Aviram -- amittai.aviram@yale.edu Version %s\n", Version);
printf("\tfollowing Silberschatz, Korth, Sidarshan, Database Concepts, 5th ed.\n\n");
printf("To build a B+ tree of a different order, start again and enter the order\n");
printf("as an integer argument: bpt <order>. ");
printf("3 <= order <=20\n");
printf("To start with input from a file of newline-delimited integers, start again and enter\n");
printf("the order followed by the filename: bpt <order> <inputfile>.\n");
}
/* Second message to the user. */
void
usage_2( void )
{
printf("Enter any of the following commands after the prompt > :\n");
printf("\ti <k> -- Insert <k> (an integer) as both key and value).\n");
printf("\tf <k> -- Find the value under key <k>.\n");
printf("\tp <k> -- Print the path from the root to key k and its associated value.\n");
printf("\td <k> -- Delete key <k> and its associated value.\n");
printf("\tx -- Destroy the whole tree. Start again with an empty tree of the same order.\n");
printf("\tt -- Print the B+ tree.\n");
printf("\tl -- Print the keys of the leaves (bottom row of the tree).\n");
printf("\tv -- Toggle output of pointer addresses (\"verbose\") in tree and leaves.\n");
printf("\tq -- Quit. (Or use Ctl-D.)\n");
printf("\t? -- Print this help message.\n");
}
/* Helper function for printing the tree out. See print_tree. */
void
enqueue( node* new_node )
{
node * c;
if (queue == NULL) {
queue = new_node;
queue->next = NULL;
}
else {
c = queue;
while(c->next != NULL) {
c = c->next;
}
c->next = new_node;
new_node->next = NULL;
}
}
/* Helper function for printing the tree out. See print_tree. */
node *
dequeue( void )
{
node * n = queue;
queue = queue->next;
n->next = NULL;
return n;
}
/* Prints the bottom row of keys of the tree (with their respective pointers, if the verbose_output flag is set. */
void
print_leaves( node* root )
{
int i;
node * c = root;
if (root == NULL) {
printf("Empty tree.\n");
return;
}
while (!c->is_leaf)
c = (node *) c->pointers[0];
while (true) {
for (i = 0; i < c->num_keys; i++) {
if (verbose_output)
//printf("%x ", (unsigned int)c->pointers[i]);
printf("%d ", c->keys[i]);
}
if (verbose_output)
//printf("%x ", (unsigned int)c->pointers[order - 1]);
if (c->pointers[order - 1] != NULL) {
printf(" | ");
c = (node *) c->pointers[order - 1];
}
else
break;
}
printf("\n");
}
/* Utility function to give the height of the tree, which length in number of edges of the path from the root to any leaf. */
int
height( node* root )
{
int h = 0;
node * c = root;
while (!c->is_leaf) {
c = (node *) c->pointers[0];
h++;
}
return h;
}
/* Utility function to give the length in edges of the path from any node to the root. */
int
path_to_root( node* root, node* child )
{
int length = 0;
node * c = child;
while (c != root) {
c = c->parent;
length++;
}
return length;
}
/* Prints the B+ tree in the command line in level (rank) order, with the keys in each node and the '|' symbol to separate nodes. With the verbose_output flag set. the values of the pointers corresponding to the keys also appear next to their respective keys, in hexadecimal notation. */
void
print_tree( node* root )
{
node * n = NULL;
int i = 0;
int rank = 0;
int new_rank = 0;
if (root == NULL) {
printf("Empty tree.\n");
return;
}
queue = NULL;
enqueue(root);
while( queue != NULL ) {
n = dequeue();
if (n->parent != NULL && n == n->parent->pointers[0]) {
new_rank = path_to_root( root, n );
if (new_rank != rank) {
rank = new_rank;
printf("\n");
}
}
if (verbose_output)
printf("(%p)", n);
for (i = 0; i < n->num_keys; i++) {
if (verbose_output)
printf("%p ", n->pointers[i]);
printf("%d ", n->keys[i]);
}
if (!n->is_leaf)
for (i = 0; i <= n->num_keys; i++)
enqueue((node *) n->pointers[i]);
if (verbose_output) {
if (n->is_leaf)
printf("%p ", n->pointers[order - 1]);
else
printf("%p ", n->pointers[n->num_keys]);
}
printf("| ");
}
printf("\n");
}
/* Traces the path from the root to a leaf, searching by key. Displays information about the path if the verbose flag is set. Returns the leaf containing the given key. */
node *
find_leaf( node* root, int key, bool verbose )
{
int i = 0;
node * c = root;
if (c == NULL) {
if (verbose)
printf("Empty tree.\n");
return c;
}
while (!c->is_leaf) {
if (verbose) {
printf("[");
for (i = 0; i < c->num_keys - 1; i++)
printf("%d ", c->keys[i]);
printf("%d] ", c->keys[i]);
}
i = 0;
while (i < c->num_keys) {
if (key >= c->keys[i])
i++;
else
break;
}
if (verbose)
printf("%d ->\n", i);
c = (node *)c->pointers[i];
}
if (verbose) {
printf("Leaf [");
for (i = 0; i < c->num_keys - 1; i++)
printf("%d ", c->keys[i]);
printf("%d] ->\n", c->keys[i]);
}
return c;
}
/* Finds and returns the record to which a key refers. */
record *
find( node* root, int key, bool verbose )
{
int i = 0;
node * c = find_leaf( root, key, verbose );
if (c == NULL)
return NULL;
for (i = 0; i < c->num_keys; i++)
if (c->keys[i] == key)
break;
if (i == c->num_keys)
return NULL;
else
return (record *)c->pointers[i];
}
/* Finds the appropriate place to split a node that is too big into two. */
int
cut( int length )
{
if (length % 2 == 0)
return length/2;
else
return length/2 + 1;
}
//======================================================================================================================================================150
// INSERTION
//======================================================================================================================================================150
/* Creates a new record to hold the value to which a key refers. */
record *
make_record(int value)
{
record * new_record = (record *)malloc(sizeof(record));
if (new_record == NULL) {
perror("Record creation.");
exit(EXIT_FAILURE);
}
else {
new_record->value = value;
}
return new_record;
}
/* Creates a new general node, which can be adapted to serve as either a leaf or an internal node. */
node *
make_node( void )
{
node * new_node;
new_node = (node *) malloc(sizeof(node));
if (new_node == NULL) {
perror("Node creation.");
exit(EXIT_FAILURE);
}
new_node->keys = (int *) malloc( (order - 1) * sizeof(int) );
if (new_node->keys == NULL) {
perror("New node keys array.");
exit(EXIT_FAILURE);
}
new_node->pointers = (void **) malloc( order * sizeof(void *) );
if (new_node->pointers == NULL) {
perror("New node pointers array.");
exit(EXIT_FAILURE);
}
new_node->is_leaf = false;
new_node->num_keys = 0;
new_node->parent = NULL;
new_node->next = NULL;
return new_node;
}
/* Creates a new leaf by creating a node and then adapting it appropriately. */
node *
make_leaf( void )
{
node* leaf = make_node();
leaf->is_leaf = true;
return leaf;
}
/* Helper function used in insert_into_parent to find the index of the parent's pointer to the node to the left of the key to be inserted. */
int
get_left_index(node* parent, node* left)
{
int left_index = 0;
while (left_index <= parent->num_keys &&
parent->pointers[left_index] != left)
left_index++;
return left_index;
}
/* Inserts a new pointer to a record and its corresponding key into a leaf. Returns the altered leaf. */
node *
insert_into_leaf( node* leaf, int key, record* pointer )
{
int i, insertion_point;
insertion_point = 0;
while (insertion_point < leaf->num_keys && leaf->keys[insertion_point] < key)
insertion_point++;
for (i = leaf->num_keys; i > insertion_point; i--) {
leaf->keys[i] = leaf->keys[i - 1];
leaf->pointers[i] = leaf->pointers[i - 1];
}
leaf->keys[insertion_point] = key;
leaf->pointers[insertion_point] = pointer;
leaf->num_keys++;
return leaf;
}
/* Inserts a new key and pointer to a new record into a leaf so as to exceed the tree's order, causing the leaf to be split in half. */
node *
insert_into_leaf_after_splitting( node* root,
node* leaf,
int key,
record* pointer)
{
node * new_leaf;
int * temp_keys;
void ** temp_pointers;
int insertion_index, split, new_key, i, j;
new_leaf = make_leaf();
temp_keys = (int *) malloc( order * sizeof(int) );
if (temp_keys == NULL) {
perror("Temporary keys array.");
exit(EXIT_FAILURE);
}
temp_pointers = (void **) malloc( order * sizeof(void *) );
if (temp_pointers == NULL) {
perror("Temporary pointers array.");
exit(EXIT_FAILURE);
}
insertion_index = 0;
while (leaf->keys[insertion_index] < key && insertion_index < order - 1)
insertion_index++;
for (i = 0, j = 0; i < leaf->num_keys; i++, j++) {
if (j == insertion_index) j++;
temp_keys[j] = leaf->keys[i];
temp_pointers[j] = leaf->pointers[i];
}
temp_keys[insertion_index] = key;
temp_pointers[insertion_index] = pointer;
leaf->num_keys = 0;
split = cut(order - 1);
for (i = 0; i < split; i++) {
leaf->pointers[i] = temp_pointers[i];
leaf->keys[i] = temp_keys[i];
leaf->num_keys++;
}
for (i = split, j = 0; i < order; i++, j++) {
new_leaf->pointers[j] = temp_pointers[i];
new_leaf->keys[j] = temp_keys[i];
new_leaf->num_keys++;
}
free(temp_pointers);
free(temp_keys);
new_leaf->pointers[order - 1] = leaf->pointers[order - 1];
leaf->pointers[order - 1] = new_leaf;
for (i = leaf->num_keys; i < order - 1; i++)
leaf->pointers[i] = NULL;
for (i = new_leaf->num_keys; i < order - 1; i++)
new_leaf->pointers[i] = NULL;
new_leaf->parent = leaf->parent;
new_key = new_leaf->keys[0];
return insert_into_parent(root, leaf, new_key, new_leaf);
}
/* Inserts a new key and pointer to a node into a node into which these can fit without violating the B+ tree properties. */
node *
insert_into_node( node* root,
node* n,
int left_index,
int key,
node* right)
{
int i;
for (i = n->num_keys; i > left_index; i--) {
n->pointers[i + 1] = n->pointers[i];
n->keys[i] = n->keys[i - 1];
}
n->pointers[left_index + 1] = right;
n->keys[left_index] = key;
n->num_keys++;
return root;
}
/* Inserts a new key and pointer to a node into a node, causing the node's size to exceed the order, and causing the node to split into two. */
node *
insert_into_node_after_splitting( node* root,
node* old_node,
int left_index,
int key,
node * right)
{
int i, j, split, k_prime;
node * new_node, * child;
int * temp_keys;
node ** temp_pointers;
/* First create a temporary set of keys and pointers
* to hold everything in order, including
* the new key and pointer, inserted in their
* correct places.
* Then create a new node and copy half of the
* keys and pointers to the old node and
* the other half to the new.
*/
temp_pointers = (node **) malloc( (order + 1) * sizeof(node *) );
if (temp_pointers == NULL) {
perror("Temporary pointers array for splitting nodes.");
exit(EXIT_FAILURE);
}
temp_keys = (int *) malloc( order * sizeof(int) );
if (temp_keys == NULL) {
perror("Temporary keys array for splitting nodes.");
exit(EXIT_FAILURE);
}
for (i = 0, j = 0; i < old_node->num_keys + 1; i++, j++) {
if (j == left_index + 1) j++;
temp_pointers[j] = (node *) old_node->pointers[i];
}
for (i = 0, j = 0; i < old_node->num_keys; i++, j++) {
if (j == left_index) j++;
temp_keys[j] = old_node->keys[i];
}
temp_pointers[left_index + 1] = right;
temp_keys[left_index] = key;
/* Create the new node and copy
* half the keys and pointers to the
* old and half to the new.
*/
split = cut(order);
new_node = make_node();
old_node->num_keys = 0;
for (i = 0; i < split - 1; i++) {
old_node->pointers[i] = temp_pointers[i];
old_node->keys[i] = temp_keys[i];
old_node->num_keys++;
}
old_node->pointers[i] = temp_pointers[i];
k_prime = temp_keys[split - 1];
for (++i, j = 0; i < order; i++, j++) {
new_node->pointers[j] = temp_pointers[i];
new_node->keys[j] = temp_keys[i];
new_node->num_keys++;
}
new_node->pointers[j] = temp_pointers[i];
free(temp_pointers);
free(temp_keys);
new_node->parent = old_node->parent;
for (i = 0; i <= new_node->num_keys; i++) {
child = (node *) new_node->pointers[i];
child->parent = new_node;
}
/* Insert a new key into the parent of the two
* nodes resulting from the split, with
* the old node to the left and the new to the right.
*/
return insert_into_parent(root, old_node, k_prime, new_node);
}
/* Inserts a new node (leaf or internal node) into the B+ tree. Returns the root of the tree after insertion. */
node *
insert_into_parent( node* root,
node* left,
int key,
node* right)
{
int left_index;
node * parent;
parent = left->parent;
/* Case: new root. */
if (parent == NULL)
return insert_into_new_root(left, key, right);
/* Case: leaf or node. (Remainder of
* function body.)
*/
/* Find the parent's pointer to the left
* node.
*/
left_index = get_left_index(parent, left);
/* Simple case: the new key fits into the node.
*/
if (parent->num_keys < order - 1)
return insert_into_node(root, parent, left_index, key, right);
/* Harder case: split a node in order
* to preserve the B+ tree properties.
*/
return insert_into_node_after_splitting(root, parent, left_index, key, right);
}
/* Creates a new root for two subtrees and inserts the appropriate key into the new root. */
node *
insert_into_new_root( node* left,
int key,
node* right)
{
node * root = make_node();
root->keys[0] = key;
root->pointers[0] = left;
root->pointers[1] = right;
root->num_keys++;
root->parent = NULL;
left->parent = root;
right->parent = root;
return root;
}
/* First insertion: start a new tree. */
node *
start_new_tree( int key,
record* pointer)
{
node * root = make_leaf();
root->keys[0] = key;
root->pointers[0] = pointer;
root->pointers[order - 1] = NULL;
root->parent = NULL;
root->num_keys++;
return root;
}
/* Master insertion function. Inserts a key and an associated value into the B+ tree, causing the tree to be adjusted however necessary to maintain the B+ tree properties. */
node *
insert( node* root,
int key,
int value )
{
record* pointer;
node* leaf;
/* The current implementation ignores duplicates. */
if (find(root, key, false) != NULL)
return root;
/* Create a new record for the value. */
pointer = make_record(value);
/* Case: the tree does not exist yet. Start a new tree. */
if (root == NULL)
return start_new_tree(key, pointer);
/* Case: the tree already exists. (Rest of function body.) */
leaf = find_leaf(root, key, false);
/* Case: leaf has room for key and pointer. */
if (leaf->num_keys < order - 1) {
leaf = insert_into_leaf(leaf, key, pointer);
return root;
}
/* Case: leaf must be split. */
return insert_into_leaf_after_splitting(root, leaf, key, pointer);
}
//======================================================================================================================================================150
// DELETION
//======================================================================================================================================================150
/* Utility function for deletion. Retrieves the index of a node's nearest neighbor (sibling) to the left if one exists. If not (the node is the leftmost child), returns -1 to signify this special case. */
int
get_neighbor_index( node* n )
{
int i;
/* Return the index of the key to the left
* of the pointer in the parent pointing
* to n.
* If n is the leftmost child, this means
* return -1.
*/
for (i = 0; i <= n->parent->num_keys; i++)
if (n->parent->pointers[i] == n)
return i - 1;
// Error state.
printf("Search for nonexistent pointer to node in parent.\n");
//printf("Node: %#x\n", (unsigned int)n);
exit(EXIT_FAILURE);
}
/* */
node*
remove_entry_from_node( node* n,
int key,
node * pointer)
{
int i, num_pointers;
// Remove the key and shift other keys accordingly.
i = 0;
while (n->keys[i] != key)
i++;
for (++i; i < n->num_keys; i++)
n->keys[i - 1] = n->keys[i];
// Remove the pointer and shift other pointers accordingly.
// First determine number of pointers.
num_pointers = n->is_leaf ? n->num_keys : n->num_keys + 1;
i = 0;
while (n->pointers[i] != pointer)
i++;
for (++i; i < num_pointers; i++)
n->pointers[i - 1] = n->pointers[i];
// One key fewer.
n->num_keys--;
// Set the other pointers to NULL for tidiness.
// A leaf uses the last pointer to point to the next leaf.
if (n->is_leaf)
for (i = n->num_keys; i < order - 1; i++)
n->pointers[i] = NULL;
else
for (i = n->num_keys + 1; i < order; i++)
n->pointers[i] = NULL;
return n;
}
/* */
node*
adjust_root(node* root)
{
node * new_root;
/* Case: nonempty root.
* Key and pointer have already been deleted,
* so nothing to be done.
*/
if (root->num_keys > 0)
return root;
/* Case: empty root.
*/
// If it has a child, promote
// the first (only) child
// as the new root.
if (!root->is_leaf) {
new_root = (node *) root->pointers[0];
new_root->parent = NULL;
}
// If it is a leaf (has no children),
// then the whole tree is empty.
else
new_root = NULL;
free(root->keys);
free(root->pointers);
free(root);
return new_root;
}
/* Coalesces a node that has become too small after deletion with a neighboring node that can accept the additional entries without exceeding the maximum. */
node*
coalesce_nodes( node* root,
node* n,
node* neighbor,
int neighbor_index,
int k_prime)
{
int i, j, neighbor_insertion_index, n_start, n_end, new_k_prime;
node * tmp;
bool split;
/* Swap neighbor with node if node is on the
* extreme left and neighbor is to its right.
*/
if (neighbor_index == -1) {
tmp = n;
n = neighbor;
neighbor = tmp;
}
/* Starting point in the neighbor for copying
* keys and pointers from n.
* Recall that n and neighbor have swapped places
* in the special case of n being a leftmost child.
*/
neighbor_insertion_index = neighbor->num_keys;
/*
* Nonleaf nodes may sometimes need to remain split,
* if the insertion of k_prime would cause the resulting
* single coalesced node to exceed the limit order - 1.
* The variable split is always false for leaf nodes
* and only sometimes set to true for nonleaf nodes.
*/
split = false;
/* Case: nonleaf node.
* Append k_prime and the following pointer.
* If there is room in the neighbor, append
* all pointers and keys from the neighbor.
* Otherwise, append only cut(order) - 2 keys and
* cut(order) - 1 pointers.
*/
if (!n->is_leaf) {
/* Append k_prime.
*/
neighbor->keys[neighbor_insertion_index] = k_prime;
neighbor->num_keys++;
/* Case (default): there is room for all of n's keys and pointers
* in the neighbor after appending k_prime.
*/
n_end = n->num_keys;
/* Case (special): k cannot fit with all the other keys and pointers
* into one coalesced node.
*/
n_start = 0; // Only used in this special case.
if (n->num_keys + neighbor->num_keys >= order) {
split = true;
n_end = cut(order) - 2;
}
for (i = neighbor_insertion_index + 1, j = 0; j < n_end; i++, j++) {
neighbor->keys[i] = n->keys[j];
neighbor->pointers[i] = n->pointers[j];
neighbor->num_keys++;
n->num_keys--;
n_start++;
}
/* The number of pointers is always
* one more than the number of keys.
*/
neighbor->pointers[i] = n->pointers[j];
/* If the nodes are still split, remove the first key from
* n.
*/
if (split) {
new_k_prime = n->keys[n_start];
for (i = 0, j = n_start + 1; i < n->num_keys; i++, j++) {
n->keys[i] = n->keys[j];
n->pointers[i] = n->pointers[j];
}
n->pointers[i] = n->pointers[j];
n->num_keys--;
}
/* All children must now point up to the same parent.
*/
for (i = 0; i < neighbor->num_keys + 1; i++) {
tmp = (node *)neighbor->pointers[i];
tmp->parent = neighbor;
}
}
/* In a leaf, append the keys and pointers of
* n to the neighbor.
* Set the neighbor's last pointer to point to
* what had been n's right neighbor.
*/
else {
for (i = neighbor_insertion_index, j = 0; j < n->num_keys; i++, j++) {
neighbor->keys[i] = n->keys[j];
neighbor->pointers[i] = n->pointers[j];
neighbor->num_keys++;
}
neighbor->pointers[order - 1] = n->pointers[order - 1];
}
if (!split) {
root = delete_entry(root, n->parent, k_prime, n);
free(n->keys);
free(n->pointers);
free(n);
}
else
for (i = 0; i < n->parent->num_keys; i++)
if (n->parent->pointers[i + 1] == n) {
n->parent->keys[i] = new_k_prime;
break;
}
return root;
}
/* Redistributes entries between two nodes when one has become too small after deletion but its neighbor is too big to append the small node's entries without exceeding the maximum */
node*
redistribute_nodes( node* root,
node* n,
node* neighbor,
int neighbor_index,
int k_prime_index,
int k_prime)
{
int i;
node * tmp;
/* Case: n has a neighbor to the left.
* Pull the neighbor's last key-pointer pair over
* from the neighbor's right end to n's left end.
*/
if (neighbor_index != -1) {
if (!n->is_leaf)
n->pointers[n->num_keys + 1] = n->pointers[n->num_keys];
for (i = n->num_keys; i > 0; i--) {
n->keys[i] = n->keys[i - 1];
n->pointers[i] = n->pointers[i - 1];
}
if (!n->is_leaf) {
n->pointers[0] = neighbor->pointers[neighbor->num_keys];
tmp = (node *)n->pointers[0];
tmp->parent = n;
neighbor->pointers[neighbor->num_keys] = NULL;
n->keys[0] = k_prime;
n->parent->keys[k_prime_index] = neighbor->keys[neighbor->num_keys - 1];
}
else {
n->pointers[0] = neighbor->pointers[neighbor->num_keys - 1];
neighbor->pointers[neighbor->num_keys - 1] = NULL;
n->keys[0] = neighbor->keys[neighbor->num_keys - 1];
n->parent->keys[k_prime_index] = n->keys[0];
}
}
/* Case: n is the leftmost child.
* Take a key-pointer pair from the neighbor to the right.
* Move the neighbor's leftmost key-pointer pair
* to n's rightmost position.
*/
else {
if (n->is_leaf) {
n->keys[n->num_keys] = neighbor->keys[0];
n->pointers[n->num_keys] = neighbor->pointers[0];
n->parent->keys[k_prime_index] = neighbor->keys[1];
}
else {
n->keys[n->num_keys] = k_prime;
n->pointers[n->num_keys + 1] = neighbor->pointers[0];
tmp = (node *)n->pointers[n->num_keys + 1];
tmp->parent = n;
n->parent->keys[k_prime_index] = neighbor->keys[0];
}
for (i = 0; i < neighbor->num_keys; i++) {
neighbor->keys[i] = neighbor->keys[i + 1];
neighbor->pointers[i] = neighbor->pointers[i + 1];
}
if (!n->is_leaf)
neighbor->pointers[i] = neighbor->pointers[i + 1];
}
/* n now has one more key and one more pointer;
* the neighbor has one fewer of each.
*/
n->num_keys++;
neighbor->num_keys--;
return root;
}
/* Deletes an entry from the B+ tree. Removes the record and its key and pointer from the leaf, and then makes all appropriate changes to preserve the B+ tree properties. */
node*
delete_entry( node* root,
node* n,
int key,
void* pointer )
{
int min_keys;
node * neighbor;
int neighbor_index;
int k_prime_index, k_prime;
int capacity;
// Remove key and pointer from node.
n = remove_entry_from_node(n, key, (node *) pointer);
/* Case: deletion from the root.
*/
if (n == root)
return adjust_root(root);
/* Case: deletion from a node below the root.
* (Rest of function body.)
*/
/* Determine minimum allowable size of node,
* to be preserved after deletion.
*/
min_keys = n->is_leaf ? cut(order - 1) : cut(order) - 1;
/* Case: node stays at or above minimum.
* (The simple case.)
*/
if (n->num_keys >= min_keys)
return root;
/* Case: node falls below minimum.
* Either coalescence or redistribution
* is needed.
*/
/* Find the appropriate neighbor node with which
* to coalesce.
* Also find the key (k_prime) in the parent
* between the pointer to node n and the pointer
* to the neighbor.
*/
neighbor_index = get_neighbor_index( n );
k_prime_index = neighbor_index == -1 ? 0 : neighbor_index;
k_prime = n->parent->keys[k_prime_index];
neighbor = neighbor_index == -1 ? (node *) n->parent->pointers[1] :
(node *)n->parent->pointers[neighbor_index];
capacity = n->is_leaf ? order : order - 1;
/* Coalescence. */
if (neighbor->num_keys + n->num_keys < capacity)
return coalesce_nodes(root, n, neighbor, neighbor_index, k_prime);
/* Redistribution. */
else
return redistribute_nodes(root, n, neighbor, neighbor_index, k_prime_index, k_prime);
}
/* Master deletion function. */
node*
deleteVal( node* root,
int key)
{
node * key_leaf;
record * key_record;
key_record = find(root, key, false);
key_leaf = find_leaf(root, key, false);
if (key_record != NULL && key_leaf != NULL) {
free(key_record);
root = delete_entry(root, key_leaf, key, key_record);
}
return root;
}
/* */
void
destroy_tree_nodes(node* root)
{
int i;
if (root->is_leaf)
for (i = 0; i < root->num_keys; i++)
free(root->pointers[i]);
else
for (i = 0; i < root->num_keys + 1; i++)
destroy_tree_nodes((node *) root->pointers[i]);
free(root->pointers);
free(root->keys);
free(root);
}
/* */
node*
destroy_tree(node* root)
{
destroy_tree_nodes(root);
return NULL;
}
//======================================================================================================================================================150
// END
//======================================================================================================================================================150
//========================================================================================================================================================================================================200
// MAIN FUNCTION
//========================================================================================================================================================================================================200
int
main( int argc,
char** argv )
{
printf("WG size of kernel 1 = %d WG size of kernel 2 = %d \n", DEFAULT_ORDER, DEFAULT_ORDER_2);
// ------------------------------------------------------------60
// figure out and display whether 32-bit or 64-bit architecture
// ------------------------------------------------------------60
// if(sizeof(int *)==8){
// printf("64 bit machine\n");
// }
// else if(sizeof(int *)==4){
// printf("32 bit machine\n");
// }
// ------------------------------------------------------------60
// read inputs
// ------------------------------------------------------------60
// assing default values
int cur_arg;
int arch_arg;
arch_arg = 0;
int cores_arg;
cores_arg = 1;
char *input_file = NULL;
char *command_file = NULL;
char *output="output.txt";
FILE * pFile;
// go through arguments
for(cur_arg=1; cur_arg<argc; cur_arg++){
// check if -file
if(strcmp(argv[cur_arg], "file")==0){
// check if value provided
if(argc>=cur_arg+1){
input_file = argv[cur_arg+1];
cur_arg = cur_arg+1;
// value is not a number
}
// value not provided
else{
printf("ERROR: Missing value to -file parameter\n");
return -1;
}
}
else if(strcmp(argv[cur_arg], "command")==0){
// check if value provided
if(argc>=cur_arg+1){
command_file = argv[cur_arg+1];
cur_arg = cur_arg+1;
// value is not a number
}
// value not provided
else{
printf("ERROR: Missing value to command parameter\n");
return -1;
}
}
else if (strcmp(argv[cur_arg], "-p") == 0) {
// check if value provided
if (argc >= cur_arg + 1) {
platform_id_inuse = atoi(argv[cur_arg + 1]);
cur_arg = cur_arg + 1;
}
else {
printf("ERROR: Missing value to platform parameter\n");
return -1;
}
}
else if (strcmp(argv[cur_arg], "-d") == 0) {
// check if value provided
if (argc >= cur_arg + 1) {
device_id_inuse = atoi(argv[cur_arg + 1]);
cur_arg = cur_arg + 1;
}
else {
printf("ERROR: Missing value to device parameter\n");
return -1;
}
}
/*
else if (strcmp(argv[cur_arg], "-t") == 0) {
// check if value provided
if (argc >= cur_arg + 1) {
device_type = atoi(argv[cur_arg + 1]);
device_type = (device_type == 0) ? CL_DEVICE_TYPE_GPU
: CL_DEVICE_TYPE_CPU;
cur_arg = cur_arg + 1;
}
else {
printf("ERROR: Missing value to device type parameter\n");
return -1;
}
}
*/
}
// Print configuration
if((input_file==NULL)||(command_file==NULL))
printf("Usage: ./b+tree file input_file command command_list\n");
// For debug
printf("Input File: %s \n", input_file);
printf("Command File: %s \n", command_file);
FILE * commandFile;
long lSize;
char * commandBuffer;
size_t result;
commandFile = fopen ( command_file, "rb" );
if (commandFile==NULL) {fputs ("Command File error",stderr); exit (1);}
// obtain file size:
fseek (commandFile , 0 , SEEK_END);
lSize = ftell (commandFile);
rewind (commandFile);
// allocate memory to contain the whole file:
commandBuffer = (char*) malloc (sizeof(char)*lSize);
if (commandBuffer == NULL) {fputs ("Command Buffer memory error",stderr); exit (2);}
commandBuffer[lSize] = '\0';
// copy the file into the buffer:
result = fread (commandBuffer,1,lSize,commandFile);
if (result != lSize) {fputs ("Command file reading error",stderr); exit (3);}
/* the whole file is now loaded in the memory buffer. */
// terminate
fclose (commandFile);
// For Debug
char *sPointer=commandBuffer;
printf("Command Buffer: \n");
printf("%s",commandBuffer);
pFile = fopen (output,"w+");
if (pFile==NULL)
printf ("Fail to open %s !\n",output);
fprintf(pFile,"******starting******\n");
fclose(pFile);
// ------------------------------------------------------------60
// general variables
// ------------------------------------------------------------60
FILE *file_pointer;
node *root;
root = NULL;
record *r;
int input;
char instruction;
order = DEFAULT_ORDER_2;
verbose_output = false;
//usage_1();
//usage_2();
// ------------------------------------------------------------60
// get input from file, if file provided
// ------------------------------------------------------------60
if (input_file != NULL) {
printf("Getting input from file %s...\n", argv[1]);
// open input file
file_pointer = fopen(input_file, "r");
if (file_pointer == NULL) {
perror("Failure to open input file.");
exit(EXIT_FAILURE);
}
// get # of numbers in the file
fscanf(file_pointer, "%d\n", &input);
size = input;
// save all numbers
while (!feof(file_pointer)) {
fscanf(file_pointer, "%d\n", &input);
root = insert(root, input, input);
}
// close file
fclose(file_pointer);
//print_tree(root);
//printf("Height of tree = %d\n", height(root));
}
else{
printf("ERROR: Argument -file missing\n");
return 0;
}
// ------------------------------------------------------------60
// get tree statistics
// ------------------------------------------------------------60
printf("Transforming data to a GPU suitable structure...\n");
long mem_used = transform_to_cuda(root,0);
maxheight = height(root);
long rootLoc = (long)knodes - (long)mem;
// ------------------------------------------------------------60
// process commands
// ------------------------------------------------------------60
char *commandPointer=commandBuffer;
printf("Waiting for command\n");
printf("> ");
while (sscanf(commandPointer, "%c", &instruction) != EOF && instruction != '\0') {
commandPointer++;
switch (instruction) {
// ----------------------------------------40
// Insert
// ----------------------------------------40
case 'i':
{
scanf("%d", &input);
while (getchar() != (int)'\n');
root = insert(root, input, input);
print_tree(root);
break;
}
// ----------------------------------------40
// n/a
// ----------------------------------------40
case 'f':
{
}
// ----------------------------------------40
// find
// ----------------------------------------40
case 'p':
{
scanf("%d", &input);
while (getchar() != (int)'\n');
r = find(root, input, instruction == 'p');
if (r == NULL)
printf("Record not found under key %d.\n", input);
else
printf("Record found: %d\n",r->value);
break;
}
// ----------------------------------------40
// delete value
// ----------------------------------------40
case 'd':
{
scanf("%d", &input);
while (getchar() != (int)'\n');
root = (node *) deleteVal(root, input);
print_tree(root);
break;
}
// ----------------------------------------40
// destroy tree
// ----------------------------------------40
case 'x':
{
while (getchar() != (int)'\n');
root = destroy_tree(root);
print_tree(root);
break;
}
// ----------------------------------------40
// print leaves
// ----------------------------------------40
case 'l':
{
while (getchar() != (int)'\n');
print_leaves(root);
break;
}
// ----------------------------------------40
// print tree
// ----------------------------------------40
case 't':
{
while (getchar() != (int)'\n');
print_tree(root);
break;
}
// ----------------------------------------40
// toggle verbose output
// ----------------------------------------40
case 'v':
{
while (getchar() != (int)'\n');
verbose_output = !verbose_output;
break;
}
// ----------------------------------------40
// quit
// ----------------------------------------40
case 'q':
{
while (getchar() != (int)'\n');
return EXIT_SUCCESS;
}
// ----------------------------------------40
// [GPU] find K (initK, findK)
// ----------------------------------------40
case 'k':
{
// get # of queries from user
int count;
sscanf(commandPointer, "%d", &count);
while(*commandPointer!=32 && *commandPointer!='\n')
commandPointer++;
printf("\n ******command: k count=%d \n",count);
if(count > 65535){
printf("ERROR: Number of requested querries should be 65,535 at most. (limited by # of CUDA blocks)\n");
exit(0);
}
// INPUT: records CPU allocation (setting pointer in mem variable)
record *records = (record *)mem;
long records_elem = (long)rootLoc / sizeof(record);
long records_mem = (long)rootLoc;
printf("records_elem=%d, records_unit_mem=%d, records_mem=%d\n", (int)records_elem, (int)sizeof(record), (int)records_mem);
// INPUT: knodes CPU allocation (setting pointer in mem variable)
knode *knodes = (knode *)((long)mem + (long)rootLoc);
long knodes_elem = ((long)(mem_used) - (long)rootLoc) / sizeof(knode);
long knodes_mem = (long)(mem_used) - (long)rootLoc;
printf("knodes_elem=%d, knodes_unit_mem=%d, knodes_mem=%d\n", (int)knodes_elem, (int)sizeof(knode), (int)knodes_mem);
// INPUT: currKnode CPU allocation
long *currKnode;
currKnode = (long *)malloc(count*sizeof(long));
// INPUT: offset CPU initialization
memset(currKnode, 0, count*sizeof(long));
// INPUT: offset CPU allocation
long *offset;
offset = (long *)malloc(count*sizeof(long));
// INPUT: offset CPU initialization
memset(offset, 0, count*sizeof(long));
// INPUT: keys CPU allocation
int *keys;
keys = (int *)malloc(count*sizeof(int));
// INPUT: keys CPU initialization
int i;
for(i = 0; i < count; i++){
keys[i] = (rand()/(float)RAND_MAX)*size;
}
// OUTPUT: ans CPU allocation
record *ans = (record *)malloc(sizeof(record)*count);
// OUTPUT: ans CPU initialization
for(i = 0; i < count; i++){
ans[i].value = -1;
}
// OpenCL kernel
kernel_gpu_opencl_wrapper( records,
records_mem,
knodes,
knodes_elem,
knodes_mem,
order,
maxheight,
count,
currKnode,
offset,
keys,
ans);
pFile = fopen (output,"aw+");
if (pFile==NULL)
{
printf("Fail to open %s !\n",output);
}
fprintf(pFile,"\n ******command: k count=%d \n",count);
for(i = 0; i < count; i++){
fprintf(pFile, "%d %d\n",i, ans[i].value);
}
fprintf(pFile, " \n");
fclose(pFile);
// free memory
free(currKnode);
free(offset);
free(keys);
free(ans);
// break out of case
break;
}
// ----------------------------------------40
// find range
// ----------------------------------------40
case 'r':
{
int start, end;
scanf("%d", &start);
scanf("%d", &end);
if(start > end){
input = start;
start = end;
end = input;
}
printf("For range %d to %d, ",start,end);
list_t * ansList;
ansList = findRange(root, start, end);
printf("%d records found\n", list_get_length(ansList));
//list_iterator_t iter;
free(ansList);
break;
}
// ----------------------------------------40
// [GPU] find Range K (initK, findRangeK)
// ----------------------------------------40
case 'j':
{
// get # of queries from user
int count;
sscanf(commandPointer, "%d", &count);
while(*commandPointer!=32 && *commandPointer!='\n')
commandPointer++;
int rSize;
sscanf(commandPointer, "%d", &rSize);
while(*commandPointer!=32 && *commandPointer!='\n')
commandPointer++;
printf("\n******command: j count=%d, rSize=%d \n",count, rSize);
if(rSize > size || rSize < 0) {
printf("Search range size is larger than data set size %d.\n", (int)size);
exit(0);
}
// INPUT: knodes CPU allocation (setting pointer in mem variable)
knode *knodes = (knode *)((long)mem + (long)rootLoc);
long knodes_elem = ((long)(mem_used) - (long)rootLoc) / sizeof(knode);
long knodes_mem = (long)(mem_used) - (long)rootLoc;
printf("knodes_elem=%d, knodes_unit_mem=%d, knodes_mem=%d\n", (int)knodes_elem, (int)sizeof(knode), (int)knodes_mem);
// INPUT: currKnode CPU allocation
long *currKnode;
currKnode = (long *)malloc(count*sizeof(long));
// INPUT: offset CPU initialization
memset (currKnode, 0, count*sizeof(long));
// INPUT: offset CPU allocation
long *offset;
offset = (long *)malloc(count*sizeof(long));
// INPUT: offset CPU initialization
memset (offset, 0, count*sizeof(long));
// INPUT: lastKnode CPU allocation
long *lastKnode;
lastKnode = (long *)malloc(count*sizeof(long));
// INPUT: offset CPU initialization
memset (lastKnode, 0, count*sizeof(long));
// INPUT: offset_2 CPU allocation
long *offset_2;
offset_2 = (long *)malloc(count*sizeof(long));
// INPUT: offset CPU initialization
memset (offset_2, 0, count*sizeof(long));
// INPUT: start, end CPU allocation
int *start;
start = (int *)malloc(count*sizeof(int));
int *end;
end = (int *)malloc(count*sizeof(int));
// INPUT: start, end CPU initialization
int i;
for(i = 0; i < count; i++){
start[i] = (rand()/(float)RAND_MAX)*size;
end[i] = start[i]+rSize;
if(end[i] >= size){
start[i] = start[i] - (end[i] - size);
end[i]= size-1;
}
}
// INPUT: recstart, reclenght CPU allocation
int *recstart;
recstart = (int *)malloc(count*sizeof(int));
int *reclength;
reclength = (int *)malloc(count*sizeof(int));
// OUTPUT: ans CPU initialization
for(i = 0; i < count; i++){
recstart[i] = 0;
reclength[i] = 0;
}
// CUDA kernel
kernel_gpu_opencl_wrapper_2(knodes,
knodes_elem,
knodes_mem,
order,
maxheight,
count,
currKnode,
offset,
lastKnode,
offset_2,
start,
end,
recstart,
reclength);
pFile = fopen (output,"aw+");
if (pFile==NULL)
{
printf("Fail to open %s !\n",output);
}
fprintf(pFile,"\n******command: j count=%d, rSize=%d \n",count, rSize);
for(i = 0; i < count; i++){
fprintf(pFile, "%d %d %d\n",i, recstart[i],reclength[i]);
}
fprintf(pFile, " \n");
fclose(pFile);
// free memory
free(currKnode);
free(offset);
free(lastKnode);
free(offset_2);
free(start);
free(end);
free(recstart);
free(reclength);
// break out of case
break;
}
// ----------------------------------------40
// default
// ----------------------------------------40
default:
{
//usage_2();
break;
}
}
printf("> ");
}
printf("\n");
// ------------------------------------------------------------60
// free remaining memory and exit
// ------------------------------------------------------------60
free(mem);
return EXIT_SUCCESS;
}
//========================================================================================================================================================================================================200
// END
//========================================================================================================================================================================================================200
// # ifdef __cplusplus
// }
// # endif