CuPBoP/examples/btree/main.c

2193 lines
63 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; 2012.10; Ke
// Wang; Change it to non-interactive mode. Use command option read command from
// file. And also add output for easy verification among different platforms and
// devices.Merged into Rodinia main distribution 2.2.
//======================================================================================================================================================150
// DESCRIPTION
//======================================================================================================================================================150
// Description
//======================================================================================================================================================150
// USE
//======================================================================================================================================================150
// EXAMPLE:
// ./b+tree file ./input/mil.txt command ./command.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 <limits.h> // (in directory known to compiler) needed by INT_MIN, INT_MAX
#include <stdio.h> // (in directory known to compiler) needed by printf, stderr
// #include <sys/time.h> //
// (in directory known to compiler) needed by ???
#include <math.h> // (in directory known to compiler) needed by log, pow
#include <string.h> // (in directory known to compiler) needed by memset
//======================================================================================================================================================150
// COMMON
//======================================================================================================================================================150
#include "./common.h" // (in directory provided here)
//======================================================================================================================================================150
// DEFINE
//======================================================================================================================================================150
//======================================================================================================================================================150
// UTILITIES
//======================================================================================================================================================150
#include "./util/num/num.h" // (in directory provided here)
#include "./util/timer/timer.h" // (in directory provided here)
//======================================================================================================================================================150
// KERNEL HEADERS
//======================================================================================================================================================150
#include "./kernel/kernel_gpu_cuda_wrapper.h" // (in directory provided here)
#include "./kernel/kernel_gpu_cuda_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;
//========================================================================================================================================================================================================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 = %d, sizeof(record)=%d, total=%d\n", size,
sizeof(record), size * sizeof(record));
printf("Number of knodes = %d, sizeof(knode)=%d, total=%d\n", nodeindex,
sizeof(knode), (nodeindex) * sizeof(knode));
printf("\nDone Transformation. Mem used: %d\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("(%x)", n);
for (i = 0; i < n->num_keys; i++) {
if (verbose_output)
printf("%x ", 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("%x ", n->pointers[order - 1]);
else
printf("%x ", 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 & 2 = %d \n", DEFAULT_ORDER);
// ------------------------------------------------------------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
// set GPU
// ------------------------------------------------------------60
int device = 0;
cudaSetDevice(device);
printf("Selecting device %d\n", device);
// ------------------------------------------------------------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;
}
}
}
// 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);
}
// 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)
fputs("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;
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", input_file);
// 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) {
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;
}
// CUDA kernel
kernel_gpu_cuda_wrapper(records, records_mem, knodes, knodes_elem,
knodes_mem,
order, maxheight, count,
currKnode, offset, keys, ans);
/* printf("ans: \n"); */
/* for(i = 0; i < count; i++){ */
/* printf("%d ",ans[i].value); */
/* } */
/* printf(" \n"); */
pFile = fopen(output, "aw+");
if (pFile == NULL) {
fputs("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_cuda_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) {
fputs("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