/* StarPU --- Runtime system for heterogeneous multicore architectures. * * Copyright (C) 2009-2020 Université de Bordeaux, CNRS (LaBRI UMR 5800), Inria * Copyright (C) 2010 Mehdi Juhoor * * StarPU is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or (at * your option) any later version. * * StarPU 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 Lesser General Public License in COPYING.LGPL for more details. */ /* * This reads a wave file, splits it into chunks, and on each of them run a * task which performs an fft, drop some high and low frequencies, and performs * the inverse fft. It then writes the output to a wave file. */ #include #include #include #include #include #include #include #ifdef STARPU_USE_CUDA #include #include #endif /* #define SAVE_RAW 1 */ #define DEFAULTINPUTFILE "input.wav" #define DEFAULTOUTPUTFILE "output.wav" #define NSAMPLES (256*1024) #define SAMPLERATE 44100 static unsigned nsamples = NSAMPLES; /* This is a band filter, we want to stop everything that is not between LOWFREQ and HIGHFREQ*/ /* LOWFREQ < i * SAMPLERATE / NSAMPLE */ #define LOWFREQ 500U #define HIFREQ 800U static const size_t headersize = 37+9; static FILE *infile, *outfile; static FILE *infile_raw, *outfile_raw; static char *inputfilename = DEFAULTINPUTFILE; static char *outputfilename = DEFAULTOUTPUTFILE; static unsigned use_pin = 0; unsigned length_data; /* buffer containing input WAV data */ float *A; starpu_data_handle_t A_handle; /* For performance evaluation */ static double start; static double end; static unsigned task_per_worker[STARPU_NMAXWORKERS] = {0}; /* * Functions to Manipulate WAV files */ unsigned get_wav_data_bytes_length(FILE *file) { /* this is clearly suboptimal !! */ fseek(file, headersize, SEEK_SET); unsigned cnt = 0; while (fgetc(file) != EOF) cnt++; return cnt; } void copy_wav_header(FILE *srcfile, FILE *dstfile) { unsigned char buffer[128]; fseek(srcfile, 0, SEEK_SET); fseek(dstfile, 0, SEEK_SET); fread(buffer, 1, headersize, infile); fwrite(buffer, 1, headersize, outfile); } void read_16bit_wav(FILE *infile, unsigned size, float *arrayout, FILE *save_file) { int v; #if SAVE_RAW unsigned currentpos = 0; #endif /* we skip the header to only keep the data */ fseek(infile, headersize, SEEK_SET); for (v=0;vcl = &band_filter_cl; task->handles[0] = starpu_data_get_sub_data(A_handle, 1, iter); task->callback_func = callback; task->callback_arg = NULL; ret = starpu_task_submit(task); STARPU_CHECK_RETURN_VALUE(ret, "starpu_task_submit"); } static void init_problem(void) { infile = fopen(inputfilename, "r"); if (outputfilename) outfile = fopen(outputfilename, "w+"); #if SAVE_RAW infile_raw = fopen("input.raw", "w"); outfile_raw = fopen("output.raw", "w"); #endif /* copy input's header into output WAV */ if (outputfilename) copy_wav_header(infile, outfile); /* read length of input WAV's data */ /* each element is 2 bytes long (16bits)*/ length_data = get_wav_data_bytes_length(infile)/2; while (nsamples > length_data) nsamples /= 2; /* allocate a buffer to store the content of input file */ if (use_pin) { starpu_malloc((void **)&A, length_data*sizeof(float)); } else { A = malloc(length_data*sizeof(float)); } /* allocate working buffer (this could be done online, but we'll keep it simple) */ /* starpu_data_malloc_pinned_if_possible((void **)&outdata, length_data*sizeof(fftwf_complex)); */ /* read input data into buffer "A" */ read_16bit_wav(infile, length_data, A, infile_raw); } static void parse_args(int argc, char **argv) { int i; for (i = 1; i < argc; i++) { if (strcmp(argv[i], "-h") == 0) { fprintf(stderr, "Usage: %s [-pin] [-nsamples block_size] [-i input.wav] [-o output.wav | -no-output] [-h]\n", argv[0]); exit(-1); } if (strcmp(argv[i], "-i") == 0) { inputfilename = argv[++i]; } if (strcmp(argv[i], "-o") == 0) { outputfilename = argv[++i]; } if (strcmp(argv[i], "-no-output") == 0) { outputfilename = NULL; } /* block size */ if (strcmp(argv[i], "-nsamples") == 0) { char *argptr; nsamples = strtol(argv[++i], &argptr, 10); } if (strcmp(argv[i], "-pin") == 0) { use_pin = 1; } } } int main(int argc, char **argv) { unsigned iter; int ret; parse_args(argc, argv); fprintf(stderr, "Reading input data\n"); init_problem(); unsigned niter = length_data/nsamples; fprintf(stderr, "input: %s\noutput: %s\n#chunks %u\n", inputfilename, outputfilename, niter); /* launch StarPU */ ret = starpu_init(NULL); if (ret == -ENODEV) return 77; STARPU_CHECK_RETURN_VALUE(ret, "starpu_init"); starpu_cublas_init(); starpu_vector_data_register(&A_handle, STARPU_MAIN_RAM, (uintptr_t)A, niter*nsamples, sizeof(float)); struct starpu_data_filter f = { .filter_func = starpu_vector_filter_block, .nchildren = niter }; starpu_data_partition(A_handle, &f); for (iter = 0; iter < niter; iter++) starpu_data_set_wt_mask(starpu_data_get_sub_data(A_handle, 1, iter), 1<<0); start = starpu_timing_now(); for (iter = 0; iter < niter; iter++) { create_starpu_task(iter); } starpu_task_wait_for_all(); end = starpu_timing_now(); double timing = end - start; fprintf(stderr, "Computation took %2.2f ms\n", timing/1000); int worker; for (worker = 0; worker < STARPU_NMAXWORKERS; worker++) { if (task_per_worker[worker]) { char name[32]; starpu_worker_get_name(worker, name, 32); unsigned long bytes = nsamples*sizeof(float)*task_per_worker[worker]; fprintf(stderr, "\t%s -> %2.2f MB\t%2.2f\tMB/s\t%2.2f %%\n", name, (1.0*bytes)/(1024*1024), bytes/timing, (100.0*task_per_worker[worker])/niter); } } if (outputfilename) fprintf(stderr, "Writing output data\n"); /* make sure that the output is in RAM before quitting StarPU */ starpu_data_unpartition(A_handle, STARPU_MAIN_RAM); starpu_data_unregister(A_handle); starpu_cublas_shutdown(); /* we are done ! */ starpu_shutdown(); fclose(infile); if (outputfilename) { write_16bit_wav(outfile, length_data, A, outfile_raw); fclose(outfile); } #if SAVE_RAW fclose(infile_raw); fclose(outfile_raw); #endif return 0; }