/*
* Copyright (c) 2010-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_gctimer(
PX(gctimer) ths);
static void fprint_average_gctimer(
MPI_Comm comm, FILE *file, PX(gcplan) ths, unsigned flags);
static void write_info_header(
MPI_Comm comm, FILE *file);
static void write_run_specific_infos(
MPI_Comm comm, FILE *file, PX(gcplan) ths);
static int get_matlab_index(
MPI_Comm comm);
static void fprint_average_gctimer_prefixed(
MPI_Comm comm, FILE *file, const char *prefix, PX(gctimer) 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(gcplan)
********************************************/
PX(gctimer) PX(get_gctimer_exg)(
const PX(gcplan) ths
)
{
return PX(copy_gctimer)(ths->timer_exg);
}
PX(gctimer) PX(get_gctimer_red)(
const PX(gcplan) ths
)
{
return PX(copy_gctimer)(ths->timer_red);
}
void PX(reset_gctimers)(
PX(gcplan) ths
)
{
reset_gctimer(ths->timer_exg);
reset_gctimer(ths->timer_red);
}
/*************************************
* Functions to operate on PX(gctimer)
************************************/
void PX(print_average_gctimer)(
const PX(gcplan) ths, MPI_Comm comm
)
{
write_info_header(comm, stdout);
write_run_specific_infos(comm, stdout, ths);
fprint_average_gctimer(comm, stdout, ths, PFFTI_PRINT_TIMER_BASIC);
}
void PX(print_average_gctimer_adv)(
const PX(gcplan) ths, MPI_Comm comm
)
{
PX(print_average_gctimer)(ths, comm);
fprint_average_gctimer(comm, stdout, ths, PFFTI_PRINT_TIMER_ADV);
}
void PX(write_average_gctimer)(
const PX(gcplan) 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_gctimer(comm, f, ths, PFFTI_PRINT_TIMER_BASIC);
fclose(f);
}
void PX(write_average_gctimer_adv)(
const PX(gcplan) ths, const char *name, MPI_Comm comm
)
{
FILE *f;
PX(write_average_gctimer)(ths, name, comm);
f = open_or_create_file_to_append(comm, name);
fprint_average_gctimer(comm, f, ths, PFFTI_PRINT_TIMER_ADV);
fclose(f);
}
static void fprint_average_gctimer(
MPI_Comm comm, FILE *file, PX(gcplan) ths, unsigned flags
)
{
fprint_average_gctimer_prefixed(comm, file, "gcells_exg", ths->timer_exg, flags);
fprint_average_gctimer_prefixed(comm, file, "gcells_red", ths->timer_red, 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, "%% index(i) = log(procs(i)) + 1\n");
}
static void write_run_specific_infos(
MPI_Comm comm, FILE *file, PX(gcplan) ths
)
{
int size;
int idx = get_matlab_index(comm);
MPI_Comm_size(comm, &size);
PX(fprintf)(comm, file, "\nindex(%d) = %d; ", idx, idx);
PX(fprintf)(comm, file, "procs(%d) = %d; ", idx, size);
PX(fprintf)(comm, file, "np_gc(%d, 1:3) = [%d %d %d];\n",
idx, ths->np[0], ths->np[1], ths->np[2]);
PX(fprintf)(comm, file, "n_gc(%d, 1:3) = [%td %td %td]; ",
idx, ths->n[0], ths->n[1], ths->n[2]);
PX(fprintf)(comm, file, "gc_below(%d, 1:3) = [%td %td %td]; ",
idx, ths->gc_below[0], ths->gc_below[1], ths->gc_below[2]);
PX(fprintf)(comm, file, "gc_above(%d, 1:3) = [%td %td %td];\n",
idx, ths->gc_above[0], ths->gc_above[1], ths->gc_above[2]);
}
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;
}
PX(gctimer) PX(copy_gctimer)(
const PX(gctimer) orig
)
{
PX(gctimer) ths = PX(gc_mktimer)();
ths->iter = orig->iter;
ths->whole = orig->whole;
ths->pad_zeros = orig->pad_zeros;
ths->exchange = orig->exchange;
return ths;
}
void PX(average_gctimer)(
PX(gctimer) ths
)
{
if(ths->iter <= 0)
return;
ths->whole /= ths->iter;
ths->pad_zeros /= ths->iter;
ths->exchange /= ths->iter;
ths->iter = 1;
}
PX(gctimer) PX(add_gctimers)(
const PX(gctimer) sum1, const PX(gctimer) sum2
)
{
PX(gctimer) ths = PX(copy_gctimer)(sum1);
ths->iter += sum2->iter;
ths->whole += sum2->whole;
ths->pad_zeros += sum2->pad_zeros;
ths->exchange += sum2->exchange;
return ths;
}
PX(gctimer) PX(reduce_max_gctimer)(
const PX(gctimer) ths, MPI_Comm comm
)
{
double times[4], times_max[4];
PX(convert_gctimer2vec)(ths, times);
MPI_Reduce(times, times_max, 4, MPI_DOUBLE, MPI_MAX, 0, comm);
return PX(convert_vec2gctimer)(times_max);
}
void PX(convert_gctimer2vec)(
const PX(gctimer) gctimer,
double *times
)
{
times[0] = (double) gctimer->iter;
times[1] = gctimer->whole;
times[2] = gctimer->pad_zeros;
times[3] = gctimer->exchange;
}
PX(gctimer) PX(convert_vec2gctimer)(
const double *times
)
{
PX(gctimer) ths = PX(gc_mktimer)();
ths->iter = (int) times[0];
ths->whole = times[1];
ths->pad_zeros = times[2];
ths->exchange = times[3];
return ths;
}
static void reset_gctimer(
PX(gctimer) ths
)
{
ths->iter = 0;
ths->whole = 0;
ths->pad_zeros = 0;
ths->exchange = 0;
}
PX(gctimer) PX(gc_mktimer)(
void
)
{
PX(gctimer) ths = (PX(gctimer)) malloc(sizeof(PX(gctimer_s)));
reset_gctimer(ths);
return ths;
}
void PX(destroy_gctimer)(
PX(gctimer) ths
)
{
if(ths==NULL)
return;
free(ths);
}
static void fprint_average_gctimer_prefixed(
MPI_Comm comm, FILE *file, const char *prefix, PX(gctimer) ths,
unsigned flags
)
{
int idx = get_matlab_index(comm);
PX(gctimer) mt;
mt = PX(reduce_max_gctimer)(ths, comm);
PX(average_gctimer)(mt);
if(flags & PFFTI_PRINT_TIMER_BASIC){
PX(fprintf)(comm, file, "%s_gc_iter(%d) = %d; ", prefix, idx, ths->iter);
PX(fprintf)(comm, file, "%s_gcells(%d) = %.3e;\n", prefix, idx, mt->whole);
} else if(flags & PFFTI_PRINT_TIMER_ADV){
PX(fprintf)(comm, file, "%s_gc_pad_zeros(%d) = %.3e; ", prefix, idx, mt->pad_zeros);
PX(fprintf)(comm, file, "%s_gc_exchange(%d) = %.3e;\n", prefix, idx, mt->exchange);
}
PX(destroy_gctimer)(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;
}