blob: 9c0fb7434b1d61d822d1e9d8569a140d004d079e [file] [log] [blame]
/*************************************************************************/
/* */
/* Copyright (c) 1994 Stanford University */
/* */
/* All rights reserved. */
/* */
/* Permission is given to use, copy, and modify this software for any */
/* non-commercial purpose as long as this copyright notice is not */
/* removed. All other uses, including redistribution in whole or in */
/* part, are forbidden without prior written permission. */
/* */
/* This software is provided with absolutely no warranty and no */
/* support. */
/* */
/*************************************************************************/
/**************************************************************
*
* Parallel Hierarchical Radiosity
*
* Main program
*
***************************************************************/
#include <stdio.h>
#include <string.h>
#if defined(SGI_GL)
#include <gl.h>
#if defined(GL_NASA)
#include <panel.h>
#endif
#endif
/* ANL macro initialization */
#ifdef ENABLE_PARSEC_HOOKS
#include <hooks.h>
#endif
MAIN_ENV;
include(radiosity.h)
/***************************************
*
* Global shared variables
*
****************************************/
Global *global;
Timing **timing;
long MAX_ELEMENTS = 100000;
long MAX_INTERACTIONS = 1000000;
long MAX_ELEMVERTICES = 100000;
long MAX_EDGES = 100000;
/***************************************
*
* Global variables (not shared)
*
****************************************/
long n_processors = DEFAULT_N_PROCESSORS ;
long n_taskqueues = DEFAULT_N_TASKQUEUES ;
long n_tasks_per_queue = DEFAULT_N_TASKS_PER_QUEUE ;
long N_inter_parallel_bf_refine= DEFAULT_N_INTER_PARALLEL_BF_REFINEMENT ;
long N_visibility_per_task = DEFAULT_N_VISIBILITY_PER_TASK ;
float Area_epsilon = DEFAULT_AREA_EPSILON ;
float Energy_epsilon = DEFAULT_ENERGY_EPSILON ;
float BFepsilon = DEFAULT_BFEPSILON ;
long batch_mode = 0 ;
long verbose_mode = 0 ;
/*
in converting from a fork process model to an sproc (threads) model,
taskqueue_id and time_process_start are converted to individual arrays
without worrying about false sharing. This is because taskqueue_id is
read-only once written by the parent process, and time_process_start
is written only once by each process.
*/
long taskqueue_id[MAX_PROCESSORS] ; /* Task queue ID */
long time_rad_start, time_rad_end, time_process_start[MAX_PROCESSORS] ;
/*********************************************************
*
* Global variables (used only by the master process)
*
**********************************************************/
#define N_SLIDERS (5)
slider sliders[N_SLIDERS] = {
{ "View(X) deg ", -100, 100, (long)DFLT_VIEW_ROT_X, 5, change_view_x },
{ "View(Y) deg ", -100, 100, (long)DFLT_VIEW_ROT_Y, 5, change_view_y },
{ "View(Zoom) ", 0, 50, (long)DFLT_VIEW_ZOOM*10,6, change_view_zoom },
{ "BF-e 0.1%", 0, 50, (long)(DEFAULT_BFEPSILON *1000.0),
11, change_BFepsilon },
{ "Area-e ", 0, 5000, (long)DEFAULT_AREA_EPSILON,
11, change_area_epsilon },
} ;
#define N_CHOICES (4)
#define CHOICE_RAD_RUN (0)
#define CHOICE_RAD_STEP (1)
#define CHOICE_RAD_RESET (2)
#define CHOICE_DISP_RADIOSITY (0)
#define CHOICE_DISP_SHADED (1)
#define CHOICE_DISP_PATCH (2)
#define CHOICE_DISP_MESH (3)
#define CHOICE_DISP_INTERACTION (4)
#define CHOICE_UTIL_PS (0)
#define CHOICE_UTIL_STAT_CRT (1)
#define CHOICE_UTIL_STAT_FILE (2)
#define CHOICE_UTIL_CLEAR_RAD (3)
choice choices[N_CHOICES] = {
{ "Run",
{ "Run", "Step", "Reset", 0 },
0, start_radiosity },
{ "Display",
{ "Filled", "Smooth shading", "Show polygon edges",
"Show element edges", "Show interactions", 0 },
0, change_display },
{ "Models",
{ "Test", "Room", "LargeRoom", 0 },
0, select_model },
{ "Tools",
{ "HardCopy(PS)", "Statistics", "Statistics(file)",
"Clear Radiosity Value", 0 },
0, utility_tools },
} ;
/***************************************
*
* Main function.
*
****************************************/
static void change_view(void);
static void expose_callback(void);
static void _init_radavg_tasks(Patch *p, long mode, long process_id);
static void parse_args(int argc, char *argv[]);
static long dostats = 0;
int main(int argc, char *argv[])
{
#ifdef ENABLE_PARSEC_HOOKS
__parsec_bench_begin (__splash2_radiosity);
#endif
long i;
long total_rad_time, max_rad_time, min_rad_time;
long total_refine_time, max_refine_time, min_refine_time;
long total_wait_time, max_wait_time, min_wait_time;
long total_vertex_time, max_vertex_time, min_vertex_time;
/* Parse arguments */
parse_args(argc, argv) ;
choices[2].init_value = model_selector ;
/* Initialize graphic device */
if( batch_mode == 0 )
{
g_init(argc, argv) ;
setup_view( DFLT_VIEW_ROT_X, DFLT_VIEW_ROT_Y,
DFLT_VIEW_DIST, DFLT_VIEW_ZOOM,0 ) ;
}
/* Initialize ANL macro */
MAIN_INITENV(,60000000) ;
/* Allocate global shared memory and initialize */
if(BFepsilon <= 0.00002){
MAX_ELEMENTS *= 30;
MAX_INTERACTIONS *= 50;
MAX_ELEMVERTICES *= 30;
MAX_EDGES *= 30;
}else if(BFepsilon <= 0.0002){
MAX_ELEMENTS *= 20;
MAX_INTERACTIONS *= 30;
MAX_ELEMVERTICES *= 20;
MAX_EDGES *= 20;
}else if(BFepsilon <= 0.002){
MAX_ELEMENTS *= 10;
MAX_INTERACTIONS *= 20;
MAX_ELEMVERTICES *= 10;
MAX_EDGES *= 10;
}
global = (Global *) G_MALLOC(sizeof(Global)) ;
if( global == 0 )
{
printf( "Can't allocate memory\n" ) ;
exit(1) ;
}
init_global(0) ;
timing = (Timing **) G_MALLOC(n_processors * sizeof(Timing *));
for (i = 0; i < n_processors; i++)
timing[i] = (Timing *) G_MALLOC(sizeof(Timing));
/* Initialize shared lock */
init_sharedlock(0) ;
/* Initial random testing rays array for visibility test. */
init_visibility_module(0) ;
/* POSSIBLE ENHANCEMENT: Here is where one might distribute the
sobj_struct, task_struct, and vis_struct data structures across
physically distributed memories as desired.
One way to place data is as follows:
long i;
for (i=0;i<n_processors;i++) {
Place all addresses x such that
&(sobj_struct[i]) <= x < &(sobj_struct[i+1]) on node i
Place all addresses x such that
&(task_struct[i]) <= x < &(task_struct[i+1]) on node i
Place all addresses x such that
&(vis_struct[i]) <= x < &(vis_struct[i+1]) on node i
}
*/
if( batch_mode )
{
/* In batch mode, create child processes and start immediately */
/* Time stamp */
CLOCK( time_rad_start );
global->index = 0;
for( i = 0 ; i < n_processors ; i++ )
{
taskqueue_id[i] = assign_taskq(0) ;
}
/* And start processing */
#ifdef ENABLE_PARSEC_HOOKS
__parsec_roi_begin();
#endif
CREATE(radiosity, n_processors);
WAIT_FOR_END(n_processors);
#ifdef ENABLE_PARSEC_HOOKS
__parsec_roi_end();
#endif
/* Time stamp */
CLOCK( time_rad_end );
/* Print out running time */
printf("TIMING STATISTICS MEASURED BY MAIN PROCESS:\n");
print_running_time(0);
if (dostats) {
printf("\n\n\nPER-PROCESS STATISTICS:\n");
printf("%8s%20s%20s%12s%12s\n","Proc","Total","Refine","Wait","Smooth");
printf("%8s%20s%20s%12s%12s\n\n","","Time","Time","Time","Time");
for (i = 0; i < n_processors; i++)
printf("%8ld%20lu%20lu%12lu%12lu\n",i,timing[i]->rad_time, timing[i]->refine_time, timing[i]->wait_time, timing[i]->vertex_time);
total_rad_time = timing[0]->rad_time;
max_rad_time = timing[0]->rad_time;
min_rad_time = timing[0]->rad_time;
total_refine_time = timing[0]->refine_time;
max_refine_time = timing[0]->refine_time;
min_refine_time = timing[0]->refine_time;
total_wait_time = timing[0]->wait_time;
max_wait_time = timing[0]->wait_time;
min_wait_time = timing[0]->wait_time;
total_vertex_time = timing[0]->vertex_time;
max_vertex_time = timing[0]->vertex_time;
min_vertex_time = timing[0]->vertex_time;
for (i = 1; i < n_processors; i++) {
total_rad_time += timing[i]->rad_time;
if (timing[i]->rad_time > max_rad_time)
max_rad_time = timing[i]->rad_time;
if (timing[i]->rad_time < min_rad_time)
min_rad_time = timing[i]->rad_time;
total_refine_time += timing[i]->refine_time;
if (timing[i]->refine_time > max_refine_time)
max_refine_time = timing[i]->refine_time;
if (timing[i]->refine_time < min_refine_time)
min_refine_time = timing[i]->refine_time;
total_wait_time += timing[i]->wait_time;
if (timing[i]->wait_time > max_wait_time)
max_wait_time = timing[i]->wait_time;
if (timing[i]->wait_time < min_wait_time)
min_wait_time = timing[i]->wait_time;
total_vertex_time += timing[i]->vertex_time;
if (timing[i]->vertex_time > max_vertex_time)
max_vertex_time = timing[i]->vertex_time;
if (timing[i]->vertex_time < min_vertex_time)
min_vertex_time = timing[i]->vertex_time;
}
printf("\n\n%8s%20lu%20lu%12lu%12lu\n","Max", max_rad_time, max_refine_time, max_wait_time, max_vertex_time);
printf("\n%8s%20lu%20lu%12lu%12lu\n","Min", min_rad_time, min_refine_time, min_wait_time, min_vertex_time);
printf("\n%8s%20lu%20lu%12lu%12lu\n","Avg", (long) (((double) total_rad_time) / ((double) (1.0 * n_processors))), (long) (((double) total_refine_time) / ((double) (1.0 * n_processors))), (long) (((double) total_wait_time) / ((double) (1.0 * n_processors))), (long) (((double) total_vertex_time) / ((double) (1.0 * n_processors))));
printf("\n\n");
}
/* print_fork_time(0) ; */
print_statistics( stdout, 0 ) ;
}
else
{
/* In interactive mode, start workers, and the master starts
notification loop */
/* Start notification loop */
g_start( expose_callback,
N_SLIDERS, sliders, N_CHOICES, choices ) ;
}
MAIN_END;
#ifdef ENABLE_PARSEC_HOOKS
__parsec_bench_end();
#endif
exit(0) ;
}
/***************************************
*
* PANEL call back routine
*
* start_radiosity() (MASTER only)
*
****************************************/
static long disp_fill_switch = 1 ;
static long disp_shade_switch = 0 ;
static long disp_fill_mode = 1 ;
static long disp_patch_switch = 0 ;
static long disp_mesh_switch = 0 ;
static long disp_interaction_switch = 0 ;
static long disp_crnt_view_x = (long)DFLT_VIEW_ROT_X ;
static long disp_crnt_view_y = (long)DFLT_VIEW_ROT_Y ;
static float disp_crnt_zoom = DFLT_VIEW_ZOOM ;
#if defined(SGI_GL) && defined(GL_NASA)
void start_radiosity(Actuator *ap)
#else
void start_radiosity(long val)
#endif
{
static long state = 0 ;
long i;
long total_rad_time, max_rad_time, min_rad_time;
long total_refine_time, max_refine_time, min_refine_time;
long total_wait_time, max_wait_time, min_wait_time;
long total_vertex_time, max_vertex_time, min_vertex_time;
#if defined(SGI_GL) && defined(GL_NASA)
long val ;
val = g_get_choice_val( ap, &choices[0] ) ;
#endif
if( val == CHOICE_RAD_RUN )
{
if( state == -1 )
{
printf( "Please reset first\007\n" ) ;
return ;
}
/* Time stamp */
CLOCK( time_rad_start ) ;
global->index = 0;
/* Create slave processes */
for (i = 0 ; i < n_processors ; i++ )
{
taskqueue_id[i] = assign_taskq(0) ;
}
/* And start processing */
#ifdef ENABLE_PARSEC_HOOKS
__parsec_roi_begin();
#endif
CREATE(radiosity, n_processors);
WAIT_FOR_END(n_processors);
#ifdef ENABLE_PARSEC_HOOKS
__parsec_roi_end();
#endif
/* Time stamp */
CLOCK( time_rad_end );
/* Print out running time */
/* Print out running time */
printf("TIMING STATISTICS MEASURED BY MAIN PROCESS:\n");
print_running_time(0);
if (dostats) {
printf("\n\n\nPER-PROCESS STATISTICS:\n");
printf("%8s%20s%20s%12s%12s\n","Proc","Total","Refine","Wait","Smooth");
printf("%8s%20s%20s%12s%12s\n\n","","Time","Time","Time","Time")
;
for (i = 0; i < n_processors; i++)
printf("%8ld%20lu%20lu%12lu%12lu\n",i,timing[i]->rad_time, timing[i]->refine_time, timing[i]->wait_time, timing[i]->vertex_time);
total_rad_time = timing[0]->rad_time;
max_rad_time = timing[0]->rad_time;
min_rad_time = timing[0]->rad_time;
total_refine_time = timing[0]->refine_time;
max_refine_time = timing[0]->refine_time;
min_refine_time = timing[0]->refine_time;
total_wait_time = timing[0]->wait_time;
max_wait_time = timing[0]->wait_time;
min_wait_time = timing[0]->wait_time;
total_vertex_time = timing[0]->vertex_time;
max_vertex_time = timing[0]->vertex_time;
min_vertex_time = timing[0]->vertex_time;
for (i = 1; i < n_processors; i++) {
total_rad_time += timing[i]->rad_time;
if (timing[i]->rad_time > max_rad_time)
max_rad_time = timing[i]->rad_time;
if (timing[i]->rad_time < min_rad_time)
min_rad_time = timing[i]->rad_time;
total_refine_time += timing[i]->refine_time;
if (timing[i]->refine_time > max_refine_time)
max_refine_time = timing[i]->refine_time;
if (timing[i]->refine_time < min_refine_time)
min_refine_time = timing[i]->refine_time;
total_wait_time += timing[i]->wait_time;
if (timing[i]->wait_time > max_wait_time)
max_wait_time = timing[i]->wait_time;
if (timing[i]->wait_time < min_wait_time)
min_wait_time = timing[i]->wait_time;
total_vertex_time += timing[i]->vertex_time;
if (timing[i]->vertex_time > max_vertex_time)
max_vertex_time = timing[i]->vertex_time;
if (timing[i]->vertex_time < min_vertex_time)
min_vertex_time = timing[i]->vertex_time;
}
printf("\n\n%8s%20lu%20lu%12lu%12lu\n","Max", max_rad_time, max_refine_time, max_wait_time, max_vertex_time);
printf("\n%8s%20lu%20lu%12lu%12lu\n","Min", min_rad_time, min_refine_time, min_wait_time, min_vertex_time);
printf("\n%8s%20lu%20lu%12lu%12lu\n","Avg", (long) (((double) total_rad_time) / ((double) (1.0 * n_processors))), (long) (((double) total_refine_time) / ((double) (1.0 * n_processors))), (long) (((double) total_wait_time) / ((double) (1.0 * n_processors))), (long) (((double) total_vertex_time) / ((double) (1.0 * n_processors))));
printf("\n\n");
}
/* print_fork_time(0) ; */
print_statistics( stdout, 0 ) ;
/* Display image */
display_scene( disp_fill_mode, disp_patch_switch,
disp_mesh_switch, disp_interaction_switch, 0) ;
state = -1 ;
}
else if( val == CHOICE_RAD_STEP )
{
if( state == -1 )
{
printf( "Please reset first\007\n" ) ;
return ;
}
/* Step execution */
switch( state )
{
case 0:
/* Step execute as a single process */
global->index = 1;
/* Create slave processes */
for ( i = 0 ; i < n_processors ; i++ )
{
taskqueue_id[i] = assign_taskq(0) ;
}
#ifdef ENABLE_PARSEC_HOOKS
__parsec_roi_begin();
#endif
CREATE(radiosity, n_processors/* - 1*/);
/* Decompose model objects into patches and build
the BSP tree */
/* Create the first tasks (MASTER only) */
init_modeling_tasks(0) ;
process_tasks(0) ;
state ++ ;
break ;
case 1:
if( init_ray_tasks(0) )
{
BARRIER(global->barrier, n_processors);
process_tasks(0) ;
}
else
state++ ;
break ;
default:
BARRIER(global->barrier, n_processors);
init_radavg_tasks( RAD_AVERAGING_MODE, 0 ) ;
process_tasks(0) ;
init_radavg_tasks( RAD_NORMALIZING_MODE, 0 ) ;
process_tasks(0) ;
WAIT_FOR_END(n_processors/* - 1*/)
#ifdef ENABLE_PARSEC_HOOKS
__parsec_roi_end();
#endif
state = -1 ;
}
/* Display image */
display_scene( disp_fill_mode, disp_patch_switch,
disp_mesh_switch, disp_interaction_switch, 0) ;
}
else if( val == CHOICE_RAD_RESET )
{
/* Initialize global variables again */
init_global(0) ;
init_visibility_module(0) ;
g_clear() ;
state = 0 ;
}
}
/***************************************
*
* PANEL call back routine
*
* change_display() (MASTER only)
*
****************************************/
#if defined(SGI_GL) && defined(GL_NASA)
void change_display(Actuator *ap)
#else
void change_display(long val)
#endif
{
#if defined(SGI_GL) && defined(GL_NASA)
long val ;
val = g_get_choice_val( ap, &choices[1] ) ;
#endif
/* Display image */
switch( val )
{
case CHOICE_DISP_RADIOSITY:
disp_fill_switch = (! disp_fill_switch) ;
break ;
case CHOICE_DISP_SHADED:
disp_shade_switch = (! disp_shade_switch) ;
break ;
case CHOICE_DISP_PATCH:
disp_patch_switch = (! disp_patch_switch) ;
break ;
case CHOICE_DISP_MESH:
disp_mesh_switch = (! disp_mesh_switch) ;
break ;
case CHOICE_DISP_INTERACTION:
disp_interaction_switch = (! disp_interaction_switch) ;
break ;
default:
return ;
}
if( disp_fill_switch == 0 )
disp_fill_mode = 0 ;
else
{
if( disp_shade_switch == 0 )
disp_fill_mode = 1 ;
else
disp_fill_mode = 2 ;
}
/* Display image */
display_scene( disp_fill_mode, disp_patch_switch,
disp_mesh_switch, disp_interaction_switch, 0 ) ;
}
/*****************************************************
*
* PANEL call back routine
*
* change_view_y() (MASTER only)
* change_BFepsilon()
* change_area_epsilon()
*
******************************************************/
static void change_view()
{
/* Change the view */
setup_view( (float)disp_crnt_view_x, (float)disp_crnt_view_y,
DFLT_VIEW_DIST, disp_crnt_zoom, 0 ) ;
/* And redraw */
display_scene( disp_fill_mode, disp_patch_switch,
disp_mesh_switch, disp_interaction_switch, 0 ) ;
}
#if defined(SGI_GL) && defined(GL_NASA)
void change_view_x(Actuator *ap)
#else
void change_view_x(long val)
#endif
{
#if defined(SGI_GL) && defined(GL_NASA)
long val = g_get_slide_val( ap ) ;
#endif
/* Save current rot-X value */
disp_crnt_view_x = val ;
change_view() ;
}
#if defined(SGI_GL) && defined(GL_NASA)
void change_view_y(Actuator *ap)
#else
void change_view_y(long val )
#endif
{
#if defined(SGI_GL) && defined(GL_NASA)
long val = g_get_slide_val( ap ) ;
#endif
/* Save current rot-Y value */
disp_crnt_view_y = val ;
change_view() ;
}
#if defined(SGI_GL) && defined(GL_NASA)
void change_view_zoom(Actuator *ap)
#else
void change_view_zoom(long val)
#endif
{
#if defined(SGI_GL) && defined(GL_NASA)
long val = g_get_slide_val( ap ) ;
#endif
/* Save current zoom value */
disp_crnt_zoom = (float)val / 10.0 ;
change_view() ;
}
#if defined(SGI_GL) && defined(GL_NASA)
void change_BFepsilon(Actuator *ap)
#else
void change_BFepsilon(long val)
#endif
{
#if defined(SGI_GL) && defined(GL_NASA)
long val = g_get_slide_val( ap ) ;
#endif
BFepsilon = (float)val / 1000.0 ;
}
#if defined(SGI_GL) && defined(GL_NASA)
void change_area_epsilon(Actuator *ap)
#else
void change_area_epsilon(long val)
#endif
{
#if defined(SGI_GL) && defined(GL_NASA)
long val = g_get_slide_val( ap ) ;
#endif
Area_epsilon = (float)val ;
}
/***************************************
*
* PANEL call back routine
*
* select_model() (MASTER only)
*
****************************************/
#if defined(SGI_GL) && defined(GL_NASA)
void select_model(Actuator *ap)
#else
void select_model(long val)
#endif
{
#if defined(SGI_GL) && defined(GL_NASA)
long val = g_get_choice_val( ap, &choices[2] ) ;
#endif
switch( val )
{
case MODEL_TEST_DATA:
model_selector = MODEL_TEST_DATA ;
break ;
case MODEL_ROOM_DATA:
model_selector = MODEL_ROOM_DATA ;
break ;
case MODEL_LARGEROOM_DATA:
model_selector = MODEL_LARGEROOM_DATA ;
break ;
}
}
/***************************************
*
* PANEL call back routine
*
* utility_tools() (MASTER only)
*
****************************************/
#if defined(SGI_GL) && defined(GL_NASA)
void utility_tools(Actuator *ap)
#else
void utility_tools(long val)
#endif
{
FILE *fd ;
#if defined(SGI_GL) && defined(GL_NASA)
long val = g_get_choice_val( ap, &choices[3] ) ;
#endif
switch( val )
{
case CHOICE_UTIL_PS:
/* Open PS file */
ps_open( "radiosity.ps" ) ;
/* Change the view */
ps_setup_view( DFLT_VIEW_ROT_X, (float)disp_crnt_view_y,
DFLT_VIEW_DIST, DFLT_VIEW_ZOOM) ;
/* And redraw */
ps_display_scene( disp_fill_mode, disp_patch_switch,
disp_mesh_switch, disp_interaction_switch, 0 ) ;
/* Close */
ps_close() ;
break ;
case CHOICE_UTIL_STAT_CRT:
print_statistics( stdout, 0 ) ;
break ;
case CHOICE_UTIL_STAT_FILE:
if( (fd = fopen( "radiosity_stat", "w" )) == 0 )
{
perror( "radiosity_stat" ) ;
break ;
}
print_statistics( fd, 0 ) ;
fclose( fd ) ;
break ;
case CHOICE_UTIL_CLEAR_RAD:
clear_radiosity(0) ;
}
}
/***************************************
*
* Exposure call back
*
****************************************/
static void expose_callback()
{
/* Display image */
display_scene( disp_fill_mode, disp_patch_switch,
disp_mesh_switch, disp_interaction_switch, 0 ) ;
}
/***************************************
*
* radiosity() Radiosity task main
*
****************************************/
void radiosity()
{
long process_id;
long rad_start, refine_done, vertex_start, vertex_done;
LOCK(global->index_lock);
process_id = global->index++;
UNLOCK(global->index_lock);
process_id = process_id % n_processors;
BARINCLUDE(global->barrier);
if ((process_id == 0) || (dostats))
CLOCK(rad_start);
/* POSSIBLE ENHANCEMENT: Here is where one might pin processes to
processors to avoid migration */
/* POSSIBLE ENHANCEMENT: Here is where one might reset the
statistics that one is measuring about the parallel execution */
/* Decompose model objects into patches and build the BSP tree */
/* Create the initial tasks */
init_modeling_tasks(process_id) ;
process_tasks(process_id) ;
/* Gather rays & do BF refinement */
while( init_ray_tasks(process_id) )
{
/* Wait till tasks are put in the queue */
BARRIER(global->barrier, n_processors);
/* Then perform ray-gathering and BF-refinement till the
solution converges */
process_tasks(process_id) ;
}
if ((process_id == 0) || (dostats))
CLOCK(refine_done);
BARRIER(global->barrier, n_processors);
if ((process_id == 0) || (dostats))
CLOCK(vertex_start);
/* Compute area-weighted radiosity value at each vertex */
init_radavg_tasks( RAD_AVERAGING_MODE, process_id ) ;
process_tasks(process_id) ;
/* Then normalize the radiosity at vertices */
init_radavg_tasks( RAD_NORMALIZING_MODE, process_id ) ;
process_tasks(process_id) ;
if ((process_id == 0) || (dostats))
CLOCK(vertex_done);
if ((process_id == 0) || (dostats)) {
timing[process_id]->rad_start = rad_start;
timing[process_id]->rad_time = vertex_done - rad_start;
timing[process_id]->refine_time = refine_done - rad_start;
timing[process_id]->vertex_time = vertex_done - vertex_start;
timing[process_id]->wait_time = vertex_start - refine_done;
}
}
/***************************************************************************
*
* init_ray_tasks()
*
* Create initial tasks to perform ray gathering.
*
****************************************************************************/
#if PATCH_ASSIGNMENT == PATCH_ASSIGNMENT_STATIC
static void _init_ray_tasks_static(Patch *p, long dummy, long process_id);
#define _INIT_RAY_TASK _init_ray_tasks_static
#endif
#if PATCH_ASSIGNMENT == PATCH_ASSIGNMENT_COSTBASED
static long avg_cost_of_q ;
static long avg_cost_of_patch ;
static long queue_cost[MAX_TASKQUEUES] ;
static void _init_ray_tasks_cost2(Patch *p, long layer, long process_id);
#define _INIT_RAY_TASK _init_ray_tasks_cost2
#endif
long init_ray_tasks(long process_id)
{
long conv ;
/* If this is not the first process to initialize, then return */
LOCK(global->avg_radiosity_lock);
if( ! check_task_counter() )
{
conv = global->converged ;
UNLOCK(global->avg_radiosity_lock);
return( conv == 0 ) ;
}
/* Check radiosity convergence */
conv = radiosity_converged(process_id) ;
global->converged = conv ;
/* Reset total energy variable */
global->prev_total_energy = global->total_energy ;
global->total_energy.r = 0.0 ;
global->total_energy.g = 0.0 ;
global->total_energy.b = 0.0 ;
global->total_patch_area = 0.0 ;
/* Increment iteration counter */
global->iteration_count++ ;
UNLOCK(global->avg_radiosity_lock);
/* If radiosity converged, then return 0 */
if( conv )
return( 0 ) ;
#if PATCH_ASSIGNMENT == PATCH_ASSIGNMENT_COSTBASED
/* Compute average cost per queue. Also reset the cost variable.
The 'cost_sum' is not locked since no one is processing rays
at this moment */
for( crnt_qid = 0 ; crnt_qid < n_taskqueues ; crnt_qid++ )
queue_cost[ crnt_qid ] = 0 ;
avg_cost_of_q = global->cost_estimate_sum / n_taskqueues ;
avg_cost_of_patch = global->cost_estimate_sum / global->n_total_patches ;
cost_of_this_q = 0 ;
crnt_qid = 0 ;
global->cost_sum = 0 ;
global->cost_estimate_sum = 0 ;
/* layered selection of tasks */
foreach_patch_in_bsp( _INIT_RAY_TASK, 2, process_id ) ;
foreach_patch_in_bsp( _INIT_RAY_TASK, 1, process_id ) ;
#endif
/* Create BF refinement tasks */
foreach_patch_in_bsp( _INIT_RAY_TASK, 0, process_id ) ;
return( 1 ) ;
}
static void _init_ray_tasks_static(Patch *p, long dummy, long process_id)
{
/* Clear incoming energy variable */
p->el_root->rad_in.r = 0.0 ;
p->el_root->rad_in.g = 0.0 ;
p->el_root->rad_in.b = 0.0 ;
enqueue_ray_task( (p->seq_no >> 2) % n_taskqueues, p->el_root,
TASK_APPEND, process_id ) ;
}
#if PATCH_ASSIGNMENT == PATCH_ASSIGNMENT_COSTBASED
static void _init_ray_tasks_cost2(Patch *p, long layer, long process_id)
{
Patch_Cost *pc ;
long c_est ;
long qid ;
long min_cost_q, min_cost ;
pc = &global->patch_cost[ p->seq_no ] ;
c_est = pc->cost_estimate ;
if( c_est < 0 )
/* Already processed */
return ;
if( c_est < avg_cost_of_patch * layer )
return ;
/* Find the first available queue */
min_cost_q = 0 ;
min_cost = queue_cost[ 0 ] ;
for( qid = 0 ; qid < n_taskqueues ; qid++ )
{
if( (c_est + queue_cost[ qid ]) <= avg_cost_of_q )
break ;
if( min_cost > queue_cost[ qid ] )
{
min_cost_q = qid ;
min_cost = queue_cost[ qid ] ;
}
}
if( qid >= n_taskqueues )
{
/* All queues are nearly full. Put to min-cost queue */
qid = min_cost_q ;
}
/* Update queue cost */
queue_cost[ qid ] += c_est ;
/* Clear incoming energy variable */
p->el_root->rad_in.r = 0.0 ;
p->el_root->rad_in.g = 0.0 ;
p->el_root->rad_in.b = 0.0 ;
/* Clear cost value */
pc->cost_estimate = -1 ;
pc->n_bsp_node = 0 ;
/* Enqueue */
enqueue_ray_task( qid, p->el_root, TASK_APPEND, process_id ) ;
}
#endif
/***************************************************************************
*
* init_radavg_tasks()
*
* Create initial tasks to perform radiosity averaging.
*
****************************************************************************/
void init_radavg_tasks(long mode, long process_id)
{
/* If this is not the first process to initialize, then return */
if( ! check_task_counter() )
return ;
/* Create RadAvg tasks */
foreach_patch_in_bsp( _init_radavg_tasks, mode, process_id ) ;
}
static void _init_radavg_tasks(Patch *p, long mode, long process_id)
{
enqueue_radavg_task( p->seq_no % n_taskqueues, p->el_root, mode, process_id ) ;
}
/***************************************
*
* init_global()
*
****************************************/
void init_global(long process_id)
{
/* Clear BSP root pointer */
global->index = 1; /* ****** */
global->bsp_root = 0 ;
LOCKINIT(global->index_lock);
LOCKINIT(global->bsp_tree_lock);
/* Initialize radiosity statistics variables */
LOCKINIT(global->avg_radiosity_lock);
global->converged = 0 ;
global->prev_total_energy.r = 0.0 ;
global->prev_total_energy.g = 0.0 ;
global->prev_total_energy.b = 0.0 ;
global->total_energy.r = 1.0 ;
global->total_energy.g = 1.0 ;
global->total_energy.b = 1.0 ;
global->total_patch_area = 1.0 ;
global->iteration_count = -1 ; /* init_ray_task() increments to 0 */
/* Initialize the cost sum */
LOCKINIT(global->cost_sum_lock);
global->cost_sum = 0 ;
global->cost_estimate_sum = 0 ;
/* Initialize the barrier */
BARINIT(global->barrier, n_processors);
LOCKINIT(global->pbar_lock);
global->pbar_count = 0 ;
/* Initialize task counter */
global->task_counter = 0 ;
LOCKINIT(global->task_counter_lock);
/* Initialize task queue */
init_taskq(process_id) ;
/* Initialize Patch, Element, Interaction free lists */
init_patchlist(process_id) ;
init_elemlist(process_id) ;
init_interactionlist(process_id) ;
init_elemvertex(process_id) ;
init_edge(process_id) ;
/* Initialize statistical info */
init_stat_info(process_id) ;
}
/*************************************************************
*
* parse_args() Parse arguments
*
**************************************************************/
static void parse_args(int argc, char *argv[])
{
long cnt ;
/* Parse arguments */
for( cnt = 1 ; cnt < argc ; cnt++ )
{
if( strcmp( argv[cnt], "-p" ) == 0 ) {
sscanf( argv[++cnt], "%ld", &n_processors ) ;
n_taskqueues = n_processors;
}
else if( strcmp( argv[cnt], "-tq" ) == 0 )
sscanf( argv[++cnt], "%ld", &n_tasks_per_queue ) ;
else if( strcmp( argv[cnt], "-ae" ) == 0 )
sscanf( argv[++cnt], "%f", &Area_epsilon ) ;
else if( strcmp( argv[cnt], "-pr" ) == 0 )
sscanf( argv[++cnt], "%ld", &N_inter_parallel_bf_refine ) ;
else if( strcmp( argv[cnt], "-pv" ) == 0 )
sscanf( argv[++cnt], "%ld", &N_visibility_per_task ) ;
else if( strcmp( argv[cnt], "-bf" ) == 0 )
sscanf( argv[++cnt], "%f", &BFepsilon ) ;
else if( strcmp( argv[cnt], "-en" ) == 0 )
sscanf( argv[++cnt], "%f", &Energy_epsilon ) ;
else if( strcmp( argv[cnt], "-batch" ) == 0 )
batch_mode = 1 ;
else if( strcmp( argv[cnt], "-verbose" ) == 0 )
verbose_mode = 1 ;
else if( strcmp( argv[cnt], "-s" ) == 0 )
dostats = 1 ;
else if( strcmp( argv[cnt], "-room" ) == 0 )
model_selector = MODEL_ROOM_DATA ;
else if( strcmp( argv[cnt], "-largeroom" ) == 0 )
model_selector = MODEL_LARGEROOM_DATA ;
else if(( strcmp( argv[cnt], "-help" ) == 0 ) || ( strcmp( argv[cnt], "-h" ) == 0 ) || ( strcmp( argv[cnt], "-H" ) == 0 )) {
print_usage() ;
exit(0) ;
}
}
/* Then check the arguments */
if( (n_processors < 1) || (MAX_PROCESSORS < n_processors) )
{
fprintf( stderr, "Bad number of processors: %ld\n",
n_processors ) ;
exit(1) ;
}
if( (n_taskqueues < 1) || (MAX_TASKQUEUES < n_taskqueues) )
{
fprintf( stderr, "Bad number of task queues: %ld\n",
n_taskqueues ) ;
exit(1) ;
}
/* Check epsilon values */
if( Area_epsilon < 0.0 )
{
fprintf( stderr, "Area epsilon must be positive\n" ) ;
exit(1) ;
}
if( BFepsilon < 0.0 )
{
fprintf( stderr, "BFepsilon must be within [0,1]\n" ) ;
exit(1) ;
}
}
/*************************************************************
*
* print_usage()
*
**************************************************************/
void print_usage()
{
fprintf( stderr, "Usage: RADIOSITY [options..]\n\n" ) ;
fprintf( stderr, "\tNote: Must have a space between option label and numeric value, if any\n\n");
fprintf( stderr, " -p (d) # of processes\n" ) ;
fprintf( stderr, " -tq (d) # of tasks per queue: default (200) in code for SPLASH\n" ) ;
fprintf( stderr, " -ae (f) Area epsilon: default (2000.0) in code for SPLASH\n" ) ;
fprintf( stderr, " -pr (d) # of inter for parallel refinement: default (5) in code for SPLASH\n") ;
fprintf( stderr, " -pv (d) # of visibility comp in a task: default (4) in code for SPLASH\n") ;
fprintf( stderr, " -bf (f) BFepsilon (BF refinement): default (0.015) in code for SPLASH\n" ) ;
fprintf( stderr, " -en (f) Energy epsilon (convergence): default (0.005) in code for SPLASH\n" ) ;
fprintf( stderr, " -room Use room model (default=test)\n" ) ;
fprintf( stderr, " -largeroom Use large room model\n" ) ;
fprintf( stderr, " -batch Batch mode (use for SPLASH)\n" ) ;
fprintf( stderr, " -verbose Verbose mode (don't use for SPLASH)\n" ) ;
fprintf( stderr, " -s Measure per-process timing (don't use for SPLASH)\n" ) ;
}