1
// This file is part of BOINC.
2
// http://boinc.berkeley.edu
3
// Copyright (C) 2008 University of California
5
// BOINC is free software; you can redistribute it and/or modify it
6
// under the terms of the GNU Lesser General Public License
7
// as published by the Free Software Foundation,
8
// either version 3 of the License, or (at your option) any later version.
10
// BOINC is distributed in the hope that it will be useful,
11
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13
// See the GNU Lesser General Public License for more details.
15
// You should have received a copy of the GNU Lesser General Public License
16
// along with BOINC. If not, see <http://www.gnu.org/licenses/>.
18
// This program serves as both
19
// - An example BOINC-CUDA application, illustrating the use of the BOINC API
21
// - A program for testing various features of BOINC.
23
// The program reads the input nxn matrix from the "input" file, inverts the
24
// matrix NUM_ITERATIONS times and write to "output" file.
26
// command line options
27
// -run_slow: sleep 1 second after each character
28
// -cpu_time N: use about N CPU seconds after copying files
29
// -early_exit: exit(10) after 30 chars
30
// -early_crash: crash after 30 chars
32
// See http://boinc.berkeley.edu/trac/wiki/GPUApp for any compiling issues
33
// Contributor: Tuan Le (tuanle86@berkeley.edu)
36
#include "cuda_config.h"
41
bool run_slow = false;
42
bool early_exit = false;
43
bool early_crash = false;
44
bool early_sleep = false;
45
double cpu_time = 20, comp_result;
47
int main(int argc, char** argv) {
48
int i, retval, lastInversion=0, checkpointExists=0, dimension=0;
50
char input_path[512], output_path[512], chkpt_path[512], buf[256];
55
generate_random_input_file(MATRIX_SIZE); //call this if you don't want to
56
//construct the input file manually
58
for (i=0; i<argc; i++) {
59
if (!strcmp(argv[i], "-early_exit")) early_exit = true;
60
if (!strcmp(argv[i], "-early_crash")) early_crash = true;
61
if (!strcmp(argv[i], "-early_sleep")) early_sleep = true;
62
if (!strcmp(argv[i], "-run_slow")) run_slow = true;
63
if (!strcmp(argv[i], "-cpu_time")) {
64
cpu_time = atof(argv[++i]);
68
retval = boinc_init();
71
"%s boinc_init returned %d\n",
72
boinc_msg_prefix(buf, sizeof(buf)), retval
77
// open the input file (resolve logical name first)
79
boinc_resolve_filename(INPUT_FILENAME, input_path, sizeof(input_path));
80
infile = boinc_fopen(input_path, "r");
83
"%s Couldn't find input file, resolved name %s.\n",
84
boinc_msg_prefix(buf, sizeof(buf)), input_path
90
boinc_resolve_filename(OUTPUT_FILENAME, output_path, sizeof(output_path));
92
// See if there's a valid checkpoint file.
93
// If so retrieve the current matrix and inversion number
95
boinc_resolve_filename(CHECKPOINT_FILE, chkpt_path, sizeof(chkpt_path));
96
state = boinc_fopen(chkpt_path, "r");
98
printf("Checkpoint file is detected. Read from checkpoint file ... \n");
99
checkpointExists=fscanf(state, "%d", &lastInversion);
100
if (checkpointExists == 1) {
101
printf("Last inversion # is : %d\n",lastInversion);
102
fscanf(state,"%d",&dimension);
103
cudaMallocHost((void **)&h_idata,dimension*dimension*sizeof(REAL));
104
for (int i=0;i<dimension*dimension;++i) {
105
fscanf(state, "%f", &h_idata[i]);
110
printf("There's no valid checkpoint file!\n");
113
retval = out.open(output_path, "wb");
117
"%s APP: matrix_inversion output open failed:\n",
118
boinc_msg_prefix(buf, sizeof(buf))
121
"%s resolved name %s, retval %d\n",
122
boinc_msg_prefix(buf, sizeof(buf)), output_path, retval
129
// create shared mem segment for graphics, and arrange to update it
131
shmem = (UC_SHMEM*)boinc_graphics_make_shmem("matrix_inversion", sizeof(UC_SHMEM));
134
"%s failed to create shared mem segment\n",
135
boinc_msg_prefix(buf, sizeof(buf))
139
boinc_register_timer_callback(update_shmem);
142
if (checkpointExists != 1) {
143
dimension=get_matrix_dimension(infile);
144
printf("Matrix dimension: %d\n",dimension);
145
cudaMallocHost((void **)&h_idata,dimension*dimension*sizeof(REAL));
146
fetch_elements_into_host_memory(infile,h_idata);
147
out.printf("\n----------------- Before being inversed ----------------\n\n");
148
printf("Computation is running ... Inverse the matrix %d times. Start at inversion #1\n",
151
out.printf("\n----------------- Last checkpointed inversion #%d ----------------\n\n",
153
printf("Computation is resumed ... Inverse the matrix %d more times. Start at inversion #%d\n",
154
NUM_ITERATIONS-lastInversion,lastInversion+1);
156
print_to_file(&out,h_idata,dimension);
158
for (int i=lastInversion+1;i<=NUM_ITERATIONS;++i) {
159
invert(h_idata,dimension);
160
printf("Finish inversion #%d\n",i);
164
if (early_exit && i>30) {
167
if (early_crash && i>30) {
170
if (early_sleep && i>30) {
172
while (1) boinc_sleep(1);
175
if (boinc_time_to_checkpoint()) {
177
printf("Perform checkpointing at inversion # %d\n",i);
178
//we'll need to write the current matrix to the state file.
179
retval = do_checkpoint(out, i, h_idata, dimension);
182
"%s APP: matrix_inversion checkpoint failed %d\n",
183
boinc_msg_prefix(buf, sizeof(buf)), retval
187
boinc_checkpoint_completed();
190
fd = i/NUM_ITERATIONS;
191
if (cpu_time) fd /= 2;
192
boinc_fraction_done(fd);
195
out.printf("\n\n----------------- Final inversion #%d----------------\n\n",
197
print_to_file(&out,h_idata,dimension);
198
cudaFreeHost( h_idata );
199
retval = out.flush(); //force the output file to be closed.
202
"%s APP: matrix_inversion flush failed %d\n",
203
boinc_msg_prefix(buf, sizeof(buf)), retval
208
// burn up some CPU time if needed
211
printf("\nBurning up some CPU time ... \n");
212
double start = dtime();
213
for (int i=0; ; i++) {
214
double e = dtime()-start;
215
if (e > cpu_time) break;
216
fd = .5 + .5*(e/cpu_time);
217
boinc_fraction_done(fd);
219
if (boinc_time_to_checkpoint()) {
220
retval = do_checkpoint(out, NUM_ITERATIONS, h_idata, dimension);
223
"%s APP: maxtrix_inversion checkpoint failed %d\n",
224
boinc_msg_prefix(buf, sizeof(buf)), retval
228
boinc_checkpoint_completed();
230
comp_result = do_a_giga_flop(i);
233
boinc_fraction_done(1);
238
printf("\nDone! Please press ENTER to exit. ");
244
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR Args, int WinMode) {
249
command_line = GetCommandLine();
250
argc = parse_command_line( command_line, argv );
251
return main(argc, argv);
255
/*** BOINC FUNCTION DEFINITIONS ***/
257
/* Do a billion floating-point ops */
258
static double do_a_giga_flop(int foo) {
259
double x = 3.14159*foo;
261
for (i=0; i<500000000; i++) {
268
/* Save the computation state into checkpoint file */
269
int do_checkpoint(MFILE& mf, int n, REAL *h_idata, int dimension) {
271
string resolved_name;
273
FILE* f = fopen("temp", "w");
277
fprintf(f, "%d", n); //write inversion number
279
fprintf(f, "%d", dimension); //write dimension
281
for (int i=0;i<dimension*dimension;++i) {
283
fprintf(f, "%f", h_idata[i]);
290
boinc_resolve_filename_s(CHECKPOINT_FILE, resolved_name);
291
retval = boinc_rename("temp", resolved_name.c_str());
296
return 0; //return 0 to indicate success.
299
/*** FUNCTION DEFINITIONS ***/
301
/* Create an input file filled with random data of type cl_float. */
302
void generate_random_input_file(int n) {
304
infile=fopen(INPUT_FILENAME,"w");
305
REAL *h_idata = (REAL *)malloc(sizeof(REAL)*n*n);
307
for( int i = 0; i < n; i++ ) {
308
for (int j = 0; j < n; j++) {
309
h_idata[i*n+j] = 2.0*(rand()%32768)/32768.0 - 1.0;
311
h_idata[i*n+i] += sqrt((float)n);
314
for (int i=0;i<n*n;++i) {
315
fprintf(infile,"%15f",h_idata[i]);
317
fprintf(infile,"\n");
328
* Parse the input file and determine the size of the matrix.
329
* This is an nxn matrix. Note: if width <> height, the matrix is
332
int get_matrix_dimension(FILE *infile) {
336
fseek(infile,0,SEEK_SET);
340
if (c == EOF || c == '\n') {
343
} while (isspace(c));
345
if (isdigit(c) || c=='.' || c=='-') {
351
if (c == EOF || c == '\n') {
354
} while (isdigit(c) || c=='.' || c=='-');
356
if (c==EOF || c == '\n') {
364
/* Read the REAL values from input file into host array. */
365
void fetch_elements_into_host_memory(FILE *infile, REAL *h_idata) {
368
fseek(infile,0,SEEK_SET);
369
while (fscanf(infile,"%f",&num)==1) {
375
/* Write the result to output file */
376
void print_to_file(MFILE *out, float *h_odata, int dimension) {
379
int num_elements=dimension*dimension;
380
while (num_elements>0) {
381
out->printf("%15f ",h_odata[move]);
384
if (count==dimension) {