/* * Copyright (c) 2011-2013 Michael Pippig * * This file is part of PFFT. * * PFFT 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 3 of the License, or * (at your option) any later version. * * PFFT 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 PFFT. If not, see . * */ #include "pfft.h" #include "ipfft.h" #include /* strcmp */ static void reset_timer( PX(timer) ths); static size_t length( const PX(timer) ths); static void fprint_average_timer( MPI_Comm comm, FILE *file, const PX(plan) ths, unsigned flags); static void write_info_header( MPI_Comm comm, FILE *file); static void write_run_specific_infos( MPI_Comm comm, FILE *file, const PX(plan) ths); static int get_matlab_index( MPI_Comm comm); static void fprint_average_timer_prefixed( MPI_Comm comm, FILE *file, const char *prefix, const PX(timer) ths, unsigned flags); static int file_exists( const char *name); static FILE* open_or_create_file_to_append( MPI_Comm comm, const char *name); /********************************************* * Functions to operate on timer in PX(plan) ********************************************/ PX(timer) PX(get_timer)( const PX(plan) ths ) { return PX(copy_timer)(ths->timer); } void PX(reset_timer)( PX(plan) ths ) { reset_timer(ths->timer); } void PX(print_average_timer)( const PX(plan) ths, MPI_Comm comm ) { write_info_header(comm, stdout); write_run_specific_infos(comm, stdout, ths); fprint_average_timer(comm, stdout, ths, PFFTI_PRINT_TIMER_BASIC); } void PX(print_average_timer_adv)( const PX(plan) ths, MPI_Comm comm ) { PX(print_average_timer)(ths, comm); fprint_average_timer(comm, stdout, ths, PFFTI_PRINT_TIMER_ADV); } void PX(write_average_timer)( const PX(plan) ths, const char *name, MPI_Comm comm ) { int newfile; FILE *f; newfile = !file_exists(name); f = open_or_create_file_to_append(comm, name); if( newfile ) write_info_header(comm, f); write_run_specific_infos(comm, f, ths); fprint_average_timer(comm, f, ths, PFFTI_PRINT_TIMER_BASIC); fclose(f); } void PX(write_average_timer_adv)( const PX(plan) ths, const char *name, MPI_Comm comm ) { FILE *f; PX(write_average_timer)(ths, name, comm); f = open_or_create_file_to_append(comm, name); fprint_average_timer(comm, f, ths, PFFTI_PRINT_TIMER_ADV); fclose(f); } static void fprint_average_timer( MPI_Comm comm, FILE *file, const PX(plan) ths, unsigned flags ) { if(ths->sign == FFTW_FORWARD) fprint_average_timer_prefixed(comm, file, "pfft_forw", ths->timer, flags); else fprint_average_timer_prefixed(comm, file, "pfft_back", ths->timer, flags); } static void write_info_header( MPI_Comm comm, FILE *file ) { PX(fprintf)(comm, file, "\n%% n - FFT size\n"); PX(fprintf)(comm, file, "%% np - process grid\n"); PX(fprintf)(comm, file, "%% procs - number of processes\n"); PX(fprintf)(comm, file, "%% pfft - PFFT runtime\n"); PX(fprintf)(comm, file, "%% index(i) = log(procs(i)) + 1\n"); } static void write_run_specific_infos( MPI_Comm comm, FILE *file, const PX(plan) ths ) { int size, idx = get_matlab_index(comm); MPI_Comm_size(comm, &size); if(ths->pfft_flags & PFFT_ESTIMATE) PX(fprintf)(comm, file, "%% pfft_flags == PFFT_ESTIMATE"); else if(ths->pfft_flags & PFFT_PATIENT) PX(fprintf)(comm, file, "%% pfft_flags == PFFT_PATIENT"); else if(ths->pfft_flags & PFFT_EXHAUSTIVE) PX(fprintf)(comm, file, "%% pfft_flags == PFFT_EXHAUSTIVE"); else PX(fprintf)(comm, file, "%% pfft_flags == PFFT_MEASURE"); if(ths->pfft_flags & PFFT_TRANSPOSED_IN) PX(fprintf)(comm, file, " | PFFT_TRANSPOSED_IN"); if(ths->pfft_flags & PFFT_TRANSPOSED_OUT) PX(fprintf)(comm, file, " | PFFT_TRANSPOSED_OUT"); if(ths->pfft_flags & PFFT_SHIFTED_IN) PX(fprintf)(comm, file, " | PFFT_SHIFTED_IN"); if(ths->pfft_flags & PFFT_SHIFTED_OUT) PX(fprintf)(comm, file, " | PFFT_SHIFTED_OUT"); if(ths->pfft_flags & PFFT_TUNE) PX(fprintf)(comm, file, " | PFFT_TUNE"); else PX(fprintf)(comm, file, " | PFFT_NO_TUNE"); if(ths->pfft_flags & PFFT_PRESERVE_INPUT) PX(fprintf)(comm, file, " | PFFT_PRESERVE_INPUT"); if(ths->pfft_flags & PFFT_DESTROY_INPUT) PX(fprintf)(comm, file, " | PFFT_DESTROY_INPUT"); if(ths->pfft_flags & PFFT_BUFFERED_INPLACE) PX(fprintf)(comm, file, " | PFFT_BUFFERED_INPLACE"); PX(fprintf)(comm, file, "\n"); if(ths->fftw_flags & FFTW_ESTIMATE) PX(fprintf)(comm, file, "%% fftw_flags == FFTW_ESTIMATE\n"); else if(ths->fftw_flags & FFTW_PATIENT) PX(fprintf)(comm, file, "%% fftw_flags == FFTW_PATIENT\n"); else if(ths->fftw_flags & FFTW_EXHAUSTIVE) PX(fprintf)(comm, file, "%% fftw_flags == FFTW_EXHAUSTIVE\n"); else PX(fprintf)(comm, file, "%% fftw_flags == FFTW_MEASURE\n"); PX(fprintf)(comm, file, "index(%d) = %d; ", idx, idx); PX(fprintf)(comm, file, "procs(%d) = %d; ", idx, size); PX(fprintf)(comm, file, "np_pfft(%d, 1:%d) = [", idx, ths->rnk_pm); for(int t=0; trnk_pm; t++) PX(fprintf)(comm, file, "%td ", ths->np[t]); PX(fprintf)(comm, file, "];\n"); PX(fprintf)(comm, file, "n_pfft(%d, 1:%d) = [", idx, ths->rnk_n); for(int t=0; trnk_n; t++) PX(fprintf)(comm, file, "%td ", ths->n[t]); PX(fprintf)(comm, file, "]; "); PX(fprintf)(comm, file, "ni_pfft(%d, 1:%d) = [", idx, ths->rnk_n); for(int t=0; trnk_n; t++) PX(fprintf)(comm, file, "%td ", ths->ni[t]); PX(fprintf)(comm, file, "]; "); PX(fprintf)(comm, file, "no_pfft(%d, 1:%d) = [", idx, ths->rnk_n); for(int t=0; trnk_n; t++) PX(fprintf)(comm, file, "%td ", ths->no[t]); PX(fprintf)(comm, file, "];\n"); } static int get_matlab_index( MPI_Comm comm ) { int size; R idx; MPI_Comm_size(comm, &size); idx = pfft_log2((R) size)+1; return (int) idx; } /************************************* * Functions to operate on PX(timer) ************************************/ PX(timer) PX(copy_timer)( const PX(timer) orig ) { PX(timer) copy = PX(mktimer)(orig->rnk_pm); copy->iter = orig->iter; copy->whole = orig->whole; for(int t=0; trnk_trafo; t++) copy->trafo[t] = orig->trafo[t]; for(int t=0; trnk_remap; t++) copy->remap[t] = orig->remap[t]; for(int t=0; t<2; t++) copy->remap_3dto2d[t] = orig->remap_3dto2d[t]; copy->itwiddle = orig->itwiddle; copy->otwiddle = orig->otwiddle; return copy; } void PX(average_timer)( PX(timer) ths ) { if(ths->iter <= 0) return; ths->whole /= ths->iter; for(int t=0; trnk_trafo; t++) ths->trafo[t] /= ths->iter; for(int t=0; trnk_remap; t++) ths->remap[t] /= ths->iter; for(int t=0; t<2; t++) ths->remap_3dto2d[t] /= ths->iter; ths->itwiddle /= ths->iter; ths->otwiddle /= ths->iter; ths->iter = 1; } PX(timer) PX(add_timers)( const PX(timer) sum1, const PX(timer) sum2 ) { PX(timer) res = PX(copy_timer)(sum1); res->iter += sum2->iter; res->whole += sum2->whole; for(int t=0; trnk_trafo; t++) res->trafo[t] += sum2->trafo[t]; for(int t=0; trnk_remap; t++) res->remap[t] += sum2->remap[t]; for(int t=0; t<2; t++) res->remap_3dto2d[t] += sum2->remap_3dto2d[t]; res->itwiddle += sum2->itwiddle; res->otwiddle += sum1->otwiddle; return res; } PX(timer) PX(reduce_max_timer)( const PX(timer) ths, MPI_Comm comm ) { PX(timer) ths_max; double *times = PX(convert_timer2vec)(ths); double *times_max = (double*) malloc(sizeof(double) * length(ths)); MPI_Reduce(times, times_max, length(ths), MPI_DOUBLE, MPI_MAX, 0, comm); ths_max = PX(convert_vec2timer)(times_max); free(times); free(times_max); return ths_max; } double* PX(convert_timer2vec)( const PX(timer) ths ) { int m=0; double *times = (double*) malloc(sizeof(double) * length(ths)); times[m++] = (double) ths->rnk_pm; times[m++] = (double) ths->rnk_trafo; times[m++] = (double) ths->rnk_remap; times[m++] = (double) ths->iter; times[m++] = ths->whole; for(int t=0; trnk_trafo; t++) times[m++] = ths->trafo[t]; for(int t=0; trnk_remap; t++) times[m++] = ths->remap[t]; for(int t=0; t<2; t++) times[m++] = ths->remap_3dto2d[t]; times[m++] = ths->itwiddle; times[m++] = ths->otwiddle; return times; } PX(timer) PX(convert_vec2timer)( const double *times ) { int m=3; PX(timer) ths = PX(mktimer)((int) times[0]); ths->iter = (int) times[m++]; ths->whole = times[m++]; for(int t=0; trnk_trafo; t++) ths->trafo[t] = times[m++]; for(int t=0; trnk_remap; t++) ths->remap[t] = times[m++]; for(int t=0; t<2; t++) ths->remap_3dto2d[t] = times[m++]; ths->itwiddle = times[m++]; ths->otwiddle = times[m++]; return ths; } static void reset_timer( PX(timer) ths ) { ths->iter = 0; ths->whole = 0; for(int t=0; trnk_trafo; t++) ths->trafo[t] = 0; for(int t=0; trnk_remap; t++) ths->remap[t] = 0; for(int t=0; t<2; t++) ths->remap_3dto2d[t] = 0; ths->itwiddle = 0; ths->otwiddle = 0; } PX(timer) PX(mktimer)( int rnk_pm ) { PX(timer) ths = (PX(timer)) malloc(sizeof(PX(timer_s))); ths->rnk_pm = rnk_pm; ths->rnk_trafo = 2*rnk_pm+2; ths->rnk_remap = 2*rnk_pm; ths->trafo = (double*) malloc(sizeof(double) * (size_t) ths->rnk_trafo); ths->remap = (double*) malloc(sizeof(double) * (size_t) ths->rnk_remap); reset_timer(ths); return ths; } static size_t length( const PX(timer) ths ) { /* +3 for rnk_pm, rnk_trafo, rnk_remap */ /* +1 for number of iterations */ /* +1 for whole trafo timer */ /* +2 for remap_3dto2d[2] */ /* +2 for itwiddle, otwiddle */ return (size_t) (ths->rnk_trafo + ths->rnk_remap + 9); } void PX(destroy_timer)( PX(timer) ths ) { if(ths==NULL) return; if(ths->trafo != NULL) free(ths->trafo); if(ths->remap != NULL) free(ths->remap); free(ths); } static void fprint_average_timer_prefixed( MPI_Comm comm, FILE *file, const char *prefix, const PX(timer) ths, unsigned flags ) { int k=0, l=0; int idx = get_matlab_index(comm); PX(timer) mt = PX(reduce_max_timer)(ths, comm); PX(average_timer)(mt); if(flags & PFFTI_PRINT_TIMER_BASIC){ PX(fprintf)(comm, file, "%s_iter(%d) = %d; ", prefix, idx, ths->iter); PX(fprintf)(comm, file, "%s(%d) = %.3e;\n", prefix, idx, mt->whole); } else if(flags & PFFTI_PRINT_TIMER_ADV){ /* print times of transposed out step */ PX(fprintf)(comm, file, "%s_itwiddle(%d) = %.3e;\n", prefix, idx, mt->itwiddle); PX(fprintf)(comm, file, "%s_remap_3dto2d(%d, 2) = %.3e;\n", prefix, idx, mt->remap_3dto2d[0]); for(int t=0; trnk_pm; t++, k++, l++){ PX(fprintf)(comm, file, "%s_trafo%d(%d, 2) = %.3e; ", prefix, k+1, idx, mt->trafo[k]); PX(fprintf)(comm, file, "%s_remap%d(%d, 1) = %.3e;\n", prefix, l+1, idx, mt->remap[l]); } PX(fprintf)(comm, file, "%s_trafo%d(%d, 2) = %.3e;\n", prefix, k+1, idx, mt->trafo[k]); k++; /* print times of transposed in step */ for(int t=0; trnk_pm; t++, k++, l++){ PX(fprintf)(comm, file, "%s_trafo%d(%d, 2) = %.3e; ", prefix, k+1, idx, mt->trafo[k]); PX(fprintf)(comm, file, "%s_remap%d(%d, 1) = %.3e;\n", prefix, l+1, idx, mt->remap[l]); } PX(fprintf)(comm, file, "%s_trafo%d(%d, 2) = %.3e;\n", prefix, k+1, idx, mt->trafo[k]); PX(fprintf)(comm, file, "%s_remap_2dto3d(%d, 2) = %.3e;\n", prefix, idx, mt->remap_3dto2d[1]); PX(fprintf)(comm, file, "%s_otwiddle(%d) = %.3e;\n", prefix, idx, mt->otwiddle); } PX(destroy_timer)(mt); } /**************************************** * Functions to operate with files ***************************************/ static int file_exists( const char *name ) { FILE *f; f=fopen(name, "r"); if(f != NULL) fclose(f); return (f != NULL); } static FILE* open_or_create_file_to_append( MPI_Comm comm, const char *name ) { FILE *f=fopen(name, "a+"); if(f==NULL){ PX(fprintf)(comm, stderr, "Error: Cannot open file %s.\n", name); exit(1); } return f; }