#include #include /* sysconf() */ #include /* rand(), srand() */ #include /* time() */ #include #include /* gettimeofday() */ #include #include #include #include "Scene.h" #include "distrib/distrib.h" #include "BMP.h" using namespace std; void usage(const char * progname) { cout << "Usage: " << progname << " [options] " << endl; cout << " Options:" << endl; cout << " -o|--output-file " << endl; cout << " -w|--width " << endl; cout << " -h|--height " << endl; cout << " -m|--multisample " << endl; cout << " -f|--field-of-view " << endl; cout << " -d|--max-depth " << endl; cout << " --hosts " << endl; exit(42); } void startChildren(const string & servername, int serverport, const vector options) { char server_port_str[15]; sprintf(server_port_str, "%d", serverport); vector args; args.push_back("fart"); args.push_back("--child"); args.push_back("--host"); args.push_back(servername); args.push_back("--port"); args.push_back(server_port_str); for (int i = 0, sz = options.size(); i < sz; i++) args.push_back(options[i]); const char * char_star_args[args.size() + 1]; for (int i = 0, sz = args.size(); i < sz; i++) char_star_args[i] = args[i].c_str(); char_star_args[args.size()] = (char *) NULL; int num_children = sysconf(_SC_NPROCESSORS_CONF); num_children--; #if 0 /* debug */ cout << "executing: 'fart', "; for (int i = 0, sz = args.size(); i < sz; i++) cout << "'" << char_star_args[i] << "', "; cout << endl; #endif for (int i = 0; i < num_children; i++) { int id = fork(); if (id == 0) { /* child process */ execvp("fart", (char * const *) char_star_args); } } } int main(int argc, char * argv[]) { int opt; int option_index; map scene_options; vector client_options; bool server = true; bool distributed = false; const char * hosts_file = NULL; const char * server_name = NULL; int server_port = 0; unsigned char * data = NULL; const char * output_file_name = "fart.bmp"; bool child = false; static const struct option long_options[] = { { "output-file", required_argument, NULL, 'o' }, { "width", required_argument, NULL, 'w' }, { "height", required_argument, NULL, 'h' }, { "multisample", required_argument, NULL, 'm' }, { "field-of-view", required_argument, NULL, 'f' }, { "max-depth", required_argument, NULL, 'd' }, { "help", no_argument, NULL, 256 }, { "host", required_argument, NULL, 257 }, { "port", required_argument, NULL, 258 }, { "hosts", required_argument, NULL, 259 }, { "child", no_argument, NULL, 260 }, { NULL, 0, NULL, 0 } }; while ((opt = getopt_long(argc, argv, "o:w:h:m:f:d:", long_options, &option_index)) != -1) { switch (opt) { case 'o': output_file_name = optarg; break; case 'w': scene_options["width"] = optarg; client_options.push_back("--width"); client_options.push_back(optarg); break; case 'h': scene_options["height"] = optarg; client_options.push_back("--height"); client_options.push_back(optarg); break; case 'm': scene_options["multisample"] = optarg; client_options.push_back("--multisample"); client_options.push_back(optarg); break; case 'f': scene_options["field-of-view"] = optarg; client_options.push_back("--field-of-view"); client_options.push_back(optarg); break; case 'd': scene_options["max-depth"] = optarg; client_options.push_back("--max-depth"); client_options.push_back(optarg); break; case 256: usage(argv[0]); break; case 257: server_name = optarg; server = false; distributed = true; break; case 258: server_port = atoi(optarg); distributed = true; break; case 259: hosts_file = optarg; distributed = true; break; case 260: child = true; break; default: usage(argv[0]); break; } } if (optind >= argc) { usage(argv[0]); } srand(time(NULL)); const char * filename = argv[optind]; client_options.push_back(filename); Scene scene(scene_options, filename); const int width = scene.getWidth(); const int height = scene.getHeight(); if (server) { /* allocate data for the image */ data = new unsigned char[3 * width * height]; cout << " *** Beginning scene render ***" << endl; cout << "Parameters:" << endl; cout << "----------------------------------------" << endl; cout << " Width: " << width << endl; cout << " Height: " << height << endl; cout << " Multisample Level: " << scene.getMultisampleLevel() << endl; cout << " Ambient Occlusion Level: " << scene.getAmbientOcclusionLevel() << endl; cout << " Vertical Field of View: " << scene.getVFOV() << endl; cout << "----------------------------------------" << endl; } distrib the_distrib; struct timeval before, after; gettimeofday(&before, NULL); /* start timing */ if (distributed) { /* start the distribution infrastructure */ if (server) { if (strcmp(hosts_file, "")) the_distrib.readHostFile(hosts_file); int num_tasks = (width * height + (UNIT_TASK_SIZE - 1)) / UNIT_TASK_SIZE; the_distrib.set_num_tasks(num_tasks); the_distrib.set_data(data, 3 * width * height); the_distrib.startServer(); the_distrib.startClients(client_options); /* wait until all tasks are complete */ the_distrib.waitAllTasks(); } else { if (!child) { startChildren(server_name, server_port, client_options); } the_distrib.startClient(server_name, server_port); unsigned char data[3 * UNIT_TASK_SIZE]; for (;;) { int task_id = the_distrib.getTask(); if (task_id < 0) break; int pixel = task_id * UNIT_TASK_SIZE; int i = pixel / width; int j = pixel % width; for (int t = 0; t < UNIT_TASK_SIZE; t++) { scene.renderPixel(j, i, &data[3 * t]); j++; if (j >= width) { j = 0; i++; if (i >= height) break; } } int ret = the_distrib.send_data(task_id, &data[0], 3 * UNIT_TASK_SIZE); if (ret != 0) break; } } } else { /* "sequential" version */ for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { int pixel = i * width + j; scene.renderPixel(j, i, &data[3 * pixel]); } } } gettimeofday(&after, NULL); /* stop timing */ if (server) { cout << " *** Ending scene render ***" << endl; cout << "Writing output file '" << output_file_name << '\'' << endl; /* write the image */ BMP outputImage(output_file_name, width, height, data); /* print how much time has elapsed */ double time_before = before.tv_sec + before.tv_usec / 1000000.0; double time_after = after.tv_sec + after.tv_usec / 1000000.0; double total_seconds = time_after - time_before; cout << "Elapsed time: " << total_seconds << " seconds"; double seconds = total_seconds; int days = (int) (seconds / (60.0 * 60.0 * 24.0)); seconds -= days * 60.0 * 60.0 * 24.0; int hours = (int) (seconds / (60.0 * 60.0)); seconds -= hours * 60.0 * 60.0; int minutes = (int) (seconds / 60.0); seconds -= minutes * 60.0; if (days || hours || minutes) { cout << " ("; if (days) cout << days << (days == 1 ? " day, " : " days, "); if (days || hours) cout << hours << (hours == 1 ? " hour, " : " hours, "); cout << minutes << (minutes == 1 ? " minute, " : " minutes, "); cout << seconds << (seconds == 1 ? " second)" : " seconds)"); } cout << endl; } exit(0); return 0; }