blob: 9b8926d775a3075dbe1d001fcce7e80c2bc225ee [file] [log] [blame]
/* AUTORIGHTS
Copyright (C) 2007 Princeton University
Copyright (C) 2010 Christian Fensch
TBB version of ferret written by Christian Fensch.
Ferret Toolkit is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <stdio.h>
#include <math.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
#include <pthread.h>
#include "../include/cass.h"
#include "../include/cass_timer.h"
#include "../image/image.h"
#include "ferret-tbb.h"
#ifdef ENABLE_PARSEC_HOOKS
#include <hooks.h>
#endif
#define DEFAULT_DEPTH 25
#define MAXR 100
#define IMAGE_DIM 14
/* Backwards compatability hack for TBB 2.1 (which ships with Parsec)
TBB 2.2 changes the modes for filter in a pipeline.
*/
#ifndef TBB_INTERFACE_VERSION
#error TBB_INTERFACE_VERSION is not defined. Cannot determine correct interface
#endif
#if TBB_INTERFACE_VERSION < 4001
/* earlier version than TBB 2.2 */
#define SERIAL_IN_ORDER_FILTER serial
#define SERIAL_OUT_OF_ORDER_FILTER serial
#include <tbb/task_scheduler_init.h>
#else
/* TBB 2.2 or later */
#define SERIAL_IN_ORDER_FILTER serial_in_order
#define SERIAL_OUT_OF_ORDER_FILTER serial_out_of_order
#endif
const char *db_dir = NULL;
const char *table_name = NULL;
const char *query_dir = NULL;
const char *output_path = NULL;
FILE *fout;
int TOKEN_IN_FLIGHT = 1;
int top_K = 10;
const char *extra_params = "-L 8 - T 20";
int input_end, output_end;
pthread_cond_t done;
pthread_mutex_t done_mutex;
cass_env_t *env;
cass_table_t *table;
cass_table_t *query_table;
int vec_dist_id = 0;
int vecset_dist_id = 0;
struct load_data
{
int width, height;
char *name;
unsigned char *HSV, *RGB;
};
struct seg_data
{
int width, height, nrgn;
char *name;
unsigned char *mask;
unsigned char *HSV;
};
struct extract_data
{
cass_dataset_t ds;
char *name;
};
struct vec_query_data
{
char *name;
cass_dataset_t *ds;
cass_result_t result;
};
struct rank_data
{
char *name;
cass_dataset_t *ds;
cass_result_t result;
};
struct all_data {
union {
struct load_data load;
struct rank_data rank;
} first;
union {
struct seg_data seg;
struct vec_query_data vec;
} second;
struct extract_data extract;
};
/* ------- The Helper Functions ------- */
int cnt_enqueue;
int cnt_dequeue;
/* the whole path to the file */
struct all_data *file_helper (const char *file)
{
int r;
struct all_data *data;
data = (struct all_data *)malloc(sizeof(struct all_data));
assert(data != NULL);
data->first.load.name = strdup(file);
r = image_read_rgb_hsv(file,
&data->first.load.width,
&data->first.load.height,
&data->first.load.RGB,
&data->first.load.HSV);
assert(r == 0);
cnt_enqueue++;
return data;
}
/* ------ The Stages ------ */
filter_load::filter_load(const char * dir) :
tbb::filter(SERIAL_IN_ORDER_FILTER)
{
m_path[0] = 0;
if (strcmp(dir, ".") == 0) {
m_single_file = NULL;
push_dir(".");
}
else if (strcmp(dir, "..") == 0) {
m_single_file = NULL;
}
else {
int ret;
struct stat st;
ret = stat(dir, &st);
if (ret != 0)
{
perror("Error:");
m_single_file = NULL;
}
if (S_ISREG(st.st_mode))
m_single_file = dir;
else if (S_ISDIR(st.st_mode)) {
m_single_file = NULL;
push_dir(dir);
}
}
}
void filter_load::push_dir(const char * dir) {
int path_len = strlen(m_path);
DIR *pd = NULL;
strcat(m_path, dir);
pd = opendir(m_path);
if (pd != NULL) {
strcat(m_path, "/");
m_dir_stack.push(pd);
m_path_stack.push(path_len);
} else {
m_path[path_len] = 0;
}
}
void *filter_load::operator()( void* item ){
if(m_single_file) {
struct all_data *ret;
ret = file_helper(m_single_file);
m_single_file = NULL;
return ret;
}
if(m_dir_stack.empty())
return NULL;
for(;;) {
DIR *pd = m_dir_stack.top();
struct dirent *ent = NULL;
int res = 0;
struct stat st;
int path_len = strlen(m_path);
ent = readdir(pd);
if (ent == NULL) {
closedir(pd);
m_path[m_path_stack.top()] = 0;
m_path_stack.pop();
m_dir_stack.pop();
if(m_dir_stack.empty())
return NULL;
}
if((ent->d_name[0] == '.') &&
((ent->d_name[1] == 0) || ((ent->d_name[1] == '.') &&
(ent->d_name[2] == 0)) ) )
continue;
strcat(m_path, ent->d_name);
res = stat(m_path, &st);
if (res != 0)
{
perror("Error:");
return NULL;
}
if (S_ISREG(st.st_mode)) {
struct all_data *ret;
ret = file_helper(m_path);
m_path[path_len]=0;
return ret;
} else if (S_ISDIR(st.st_mode)) {
m_path[path_len]=0;
push_dir(ent->d_name);
} else
m_path[path_len]=0;
}
}
filter_seg::filter_seg() :
tbb::filter(parallel)
{}
void *filter_seg::operator()( void* item ) {
struct all_data *data = (struct all_data*)item;
data->second.seg.name = data->first.load.name;
data->second.seg.width = data->first.load.width;
data->second.seg.height = data->first.load.height;
data->second.seg.HSV = data->first.load.HSV;
image_segment(&data->second.seg.mask,
&data->second.seg.nrgn,
data->first.load.RGB,
data->first.load.width,
data->first.load.height);
free(data->first.load.RGB);
return item;
}
filter_extract::filter_extract() :
tbb::filter(parallel)
{}
void *filter_extract::operator()( void* item ) {
struct all_data *data = (struct all_data *)item;
data->extract.name = data->second.seg.name;
image_extract_helper(data->second.seg.HSV,
data->second.seg.mask,
data->second.seg.width,
data->second.seg.height,
data->second.seg.nrgn,
&data->extract.ds);
free(data->second.seg.mask);
free(data->second.seg.HSV);
return item;
}
filter_vec::filter_vec() :
tbb::filter(parallel)
{}
void *filter_vec::operator()(void* item) {
struct all_data *data = (struct all_data *) item;
cass_query_t query;
data->second.vec.name = data->extract.name;
memset(&query, 0, sizeof query);
query.flags = CASS_RESULT_LISTS | CASS_RESULT_USERMEM;
data->second.vec.ds = query.dataset = &data->extract.ds;
query.vecset_id = 0;
query.vec_dist_id = vec_dist_id;
query.vecset_dist_id = vecset_dist_id;
query.topk = 2*top_K;
query.extra_params = extra_params;
cass_result_alloc_list(&data->second.vec.result,
data->second.vec.ds->vecset[0].num_regions,
query.topk);
cass_table_query(table, &query, &data->second.vec.result);
return item;
}
filter_rank::filter_rank() :
tbb::filter(parallel)
{}
void *filter_rank::operator()(void* item) {
struct all_data *data = (struct all_data*) item;
cass_result_t *candidate;
cass_query_t query;
data->first.rank.name = data->second.vec.name;
query.flags = CASS_RESULT_LIST | CASS_RESULT_USERMEM | CASS_RESULT_SORT;
query.dataset = data->second.vec.ds;
query.vecset_id = 0;
query.vec_dist_id = vec_dist_id;
query.vecset_dist_id = vecset_dist_id;
query.topk = top_K;
query.extra_params = NULL;
candidate = cass_result_merge_lists(&data->second.vec.result,
(cass_dataset_t *)query_table->__private,
0);
query.candidate = candidate;
cass_result_alloc_list(&data->first.rank.result,
0, top_K);
cass_table_query(query_table, &query,
&data->first.rank.result);
cass_result_free(&data->second.vec.result);
cass_result_free(candidate);
free(candidate);
cass_dataset_release(data->second.vec.ds);
return item;
}
filter_out::filter_out() :
tbb::filter(SERIAL_OUT_OF_ORDER_FILTER)
{}
void *filter_out::operator()(void* item) {
struct all_data *data = (struct all_data *) item;
fprintf(fout, "%s", data->first.rank.name);
ARRAY_BEGIN_FOREACH(data->first.rank.result.u.list, cass_list_entry_t p)
{
char *obj = NULL;
if (p.dist == HUGE_VAL) continue;
cass_map_id_to_dataobj(query_table->map, p.id, &obj);
assert(obj != NULL);
fprintf(fout, "\t%s:%g", obj, p.dist);
} ARRAY_END_FOREACH;
fprintf(fout, "\n");
cass_result_free(&data->first.rank.result);
free(data->first.rank.name);
free(data);
cnt_dequeue++;
fprintf(stderr, "(%d,%d)\n", cnt_enqueue, cnt_dequeue);
return NULL;
}
int main (int argc, char *argv[])
{
stimer_t tmr;
tbb::pipeline ferret_pipeline;
int ret, i;
#ifdef PARSEC_VERSION
#define __PARSEC_STRING(x) #x
#define __PARSEC_XSTRING(x) __PARSEC_STRING(x)
printf("PARSEC Benchmark Suite Version "__PARSEC_XSTRING(PARSEC_VERSION)"\n");
fflush(NULL);
#else
printf("PARSEC Benchmark Suite\n");
fflush(NULL);
#endif //PARSEC_VERSION
#ifdef ENABLE_PARSEC_HOOKS
__parsec_bench_begin(__parsec_ferret);
#endif
if (argc < 8)
{
printf("%s <database> <table> <query dir> <top K> <ignored> <n> <out>\n", argv[0]);
return 0;
}
db_dir = argv[1];
table_name = argv[2];
query_dir = argv[3];
top_K = atoi(argv[4]);
TOKEN_IN_FLIGHT = atoi(argv[6]);
output_path = argv[7];
fout = fopen(output_path, "w");
assert(fout != NULL);
cass_init();
ret = cass_env_open(&env, db_dir, 0);
if (ret != 0) { printf("ERROR: %s\n", cass_strerror(ret)); return 0; }
vec_dist_id = cass_reg_lookup(&env->vec_dist, "L2_float");
assert(vec_dist_id >= 0);
vecset_dist_id = cass_reg_lookup(&env->vecset_dist, "emd");
assert(vecset_dist_id >= 0);
i = cass_reg_lookup(&env->table, table_name);
table = query_table = cass_reg_get(&env->table, i);
i = table->parent_id;
if (i >= 0)
{
query_table = cass_reg_get(&env->table, i);
}
if (query_table != table) cass_table_load(query_table);
cass_map_load(query_table->map);
cass_table_load(table);
image_init(argv[0]);
stimer_tick(&tmr);
filter_load my_load_filter(query_dir);
filter_seg my_seg_filter;
filter_extract my_extract_filter;
filter_vec my_vec_filter;
filter_rank my_rank_filter;
filter_out my_out_filter;
ferret_pipeline.add_filter(my_load_filter);
ferret_pipeline.add_filter(my_seg_filter);
ferret_pipeline.add_filter(my_extract_filter);
ferret_pipeline.add_filter(my_vec_filter);
ferret_pipeline.add_filter(my_rank_filter);
ferret_pipeline.add_filter(my_out_filter);
input_end = output_end = 0;
cnt_enqueue = cnt_dequeue = 0;
#ifdef ENABLE_PARSEC_HOOKS
__parsec_roi_begin();
#endif
#if TBB_INTERFACE_VERSION < 4001
/* in TBB versions before 2.2 this call is mandatory */
tbb::task_scheduler_init init(TOKEN_IN_FLIGHT);
#endif
ferret_pipeline.run(TOKEN_IN_FLIGHT);
#ifdef ENABLE_PARSEC_HOOKS
__parsec_roi_end();
#endif
stimer_tuck(&tmr, "QUERY TIME");
ret = cass_env_close(env, 0);
if (ret != 0) { printf("ERROR: %s\n", cass_strerror(ret)); return 0; }
cass_cleanup();
image_cleanup();
fclose(fout);
#ifdef ENABLE_PARSEC_HOOKS
__parsec_bench_end();
#endif
return 0;
}