From 6bd50b2444705dcafb0600360a96848080b5e16a Mon Sep 17 00:00:00 2001 From: Bill Somerville Date: Thu, 13 May 2021 12:44:32 +0100 Subject: [PATCH] Automatic FFTW3 wisdom handling for map65 GUI and shmem m65 runs --- lib/jt9.f90 | 2 +- map65/CMakeLists.txt | 2 +- map65/libm65/ftninit.f90 | 22 +++++++++------------- map65/libm65/ftnquit.f90 | 1 - map65/libm65/m65.f90 | 4 ---- map65/libm65/m65a.f90 | 11 ++++++++++- map65/main.cpp | 22 +++++++++++++++++++++- map65/mainwindow.cpp | 5 +++++ 8 files changed, 47 insertions(+), 22 deletions(-) diff --git a/lib/jt9.f90 b/lib/jt9.f90 index 4f018a8ce..3bfac6721 100644 --- a/lib/jt9.f90 +++ b/lib/jt9.f90 @@ -20,7 +20,7 @@ program jt9 real*8 TRperiod character c character(len=500) optarg, infile - character wisfile*80 + character wisfile*256 !### ndepth was defined as 60001. Why??? integer :: arglen,stat,offset,remain,mode=0,flow=200,fsplit=2700, & fhigh=4000,nrxfreq=1500,ndepth=1,nexp_decode=0,nQSOProg=0 diff --git a/map65/CMakeLists.txt b/map65/CMakeLists.txt index b222927fc..3f0064939 100644 --- a/map65/CMakeLists.txt +++ b/map65/CMakeLists.txt @@ -48,7 +48,7 @@ add_subdirectory (libm65) qt5_wrap_ui (map65_GENUISRCS ${map65_UISRCS}) add_executable (map65 ${map65_CXXSRCS} ${map65_CSRCS} ${map65_GENUISRCS} map65.rc) -target_include_directories (map65 PRIVATE ${CMAKE_SOURCE_DIR}) +target_include_directories (map65 PRIVATE ${CMAKE_SOURCE_DIR} ${FFTW3_INCLUDE_DIRS}) target_link_libraries (map65 wsjt_qt m65impl ${FFTW3_LIBRARIES} Qt5::Widgets Qt5::Network Portaudio::Portaudio Usb::Usb) install ( diff --git a/map65/libm65/ftninit.f90 b/map65/libm65/ftninit.f90 index 7a34288be..90468319c 100644 --- a/map65/libm65/ftninit.f90 +++ b/map65/libm65/ftninit.f90 @@ -1,9 +1,11 @@ subroutine ftninit(appd) use timer_module, only: timer + use, intrinsic :: iso_c_binding, only: C_NULL_CHAR + use FFTW3 character*(*) appd - character firstline*30 character addpfx*8 + character wisfile*256 common/pfxcom/addpfx addpfx=' ' @@ -14,20 +16,14 @@ subroutine ftninit(appd) open(26,file=appd//'/tmp26.txt',status='unknown') ! Import FFTW wisdom, if available: - open(28,file=appd//'/fftwf_wisdom.dat',status='old',err=30) - read(28,1000,err=30,end=30) firstline -1000 format(a30) - rewind 28 - call import_wisdom_from_file(isuccess,28) - close(28) - if(isuccess.ne.0) write(13,1010) firstline -1010 format('Imported FFTW wisdom: ',a30) - -30 flush(13) + iret=fftwf_init_threads() !Initialize FFTW threading +! Default to 1 thread, but use nthreads for the big ones + call fftwf_plan_with_nthreads(1) +! Import FFTW wisdom, if available + wisfile=trim(appd)//'/m65_wisdom.dat'// C_NULL_CHAR + iret=fftwf_import_wisdom_from_filename(wisfile) return -920 write(0,*) '!Error opening timer.out' - stop 950 write(0,*) '!Error opening ALL65.TXT' stop diff --git a/map65/libm65/ftnquit.f90 b/map65/libm65/ftnquit.f90 index edab1bb2d..b74e2b9e5 100644 --- a/map65/libm65/ftnquit.f90 +++ b/map65/libm65/ftnquit.f90 @@ -3,7 +3,6 @@ subroutine ftnquit ! Destroy the FFTW plans call four2a(a,-1,1,1,1) call filbig(id,-1,1,f0,newdat,nfsample,c4a,c4b,n4) - stop return end subroutine ftnquit diff --git a/map65/libm65/m65.f90 b/map65/libm65/m65.f90 index 0fc19fa86..b2f0af576 100644 --- a/map65/libm65/m65.f90 +++ b/map65/libm65/m65.f90 @@ -22,8 +22,6 @@ program m65 ! 24 ! 25 ! 26 tmp26.txt -! 27 -! 28 fftw_wisdom.dat use wideband_sync use timer_module, only: timer @@ -58,7 +56,6 @@ program m65 call getarg(1,arg) if(arg(1:2).eq.'-s') then call m65a - call ftnquit go to 999 endif n=1 @@ -181,6 +178,5 @@ program m65 print*,infile 999 call fini_timer() - call ftnquit end program m65 diff --git a/map65/libm65/m65a.f90 b/map65/libm65/m65a.f90 index 48729ea9f..a8c931192 100644 --- a/map65/libm65/m65a.f90 +++ b/map65/libm65/m65a.f90 @@ -2,6 +2,8 @@ subroutine m65a use timer_module, only: timer use timer_impl, only: init_timer !, limtrace + use, intrinsic :: iso_c_binding, only: C_NULL_CHAR + use FFTW3 interface function address_m65() @@ -13,6 +15,7 @@ subroutine m65a integer size_m65 integer*1, pointer :: p_m65 character*80 cwd + character wisfile*256 logical fileExists common/tracer/limtrace,lu @@ -33,8 +36,14 @@ subroutine m65a inquire(file=trim(cwd)//'/.quit',exist=fileExists) if(fileExists) then call timer('decode0 ',101) - call ftnquit i=detach_m65() + ! Save FFTW wisdom and free memory + wisfile=trim(cwd)//'/m65_wisdom.dat'// C_NULL_CHAR + if(len(trim(wisfile)).gt.0) iret=fftwf_export_wisdom_to_filename(wisfile) + call four2a(a,-1,1,1,1) + call filbig(a,-1,1,0.0,0,0,0,0,0) !used for FFT plans + call fftwf_cleanup_threads() + call fftwf_cleanup() go to 999 endif diff --git a/map65/main.cpp b/map65/main.cpp index 04deaca52..c1a420d0a 100644 --- a/map65/main.cpp +++ b/map65/main.cpp @@ -1,3 +1,4 @@ +#include #ifdef QT5 #include #else @@ -8,6 +9,11 @@ #include "revision_utils.hpp" #include "mainwindow.h" +extern "C" { + // Fortran procedures we need + void four2a_ (_Complex float *, int * nfft, int * ndim, int * isign, int * iform, int len); +} + static QtMessageHandler default_message_handler; void my_message_handler (QtMsgType type, QMessageLogContext const& context, QString const& msg) @@ -28,5 +34,19 @@ int main(int argc, char *argv[]) a.setApplicationVersion ("3.0.0-devel"); MainWindow w; w.show (); - return a.exec (); + auto result = a.exec (); + + // clean up lazily initialized FFTW3 resources + { + int nfft {-1}; + int ndim {1}; + int isign {1}; + int iform {1}; + // free FFT plan resources + four2a_ (nullptr, &nfft, &ndim, &isign, &iform, 0); + } + fftwf_forget_wisdom (); + fftwf_cleanup (); + + return result; } diff --git a/map65/mainwindow.cpp b/map65/mainwindow.cpp index fc83f3cd6..547e351b6 100644 --- a/map65/mainwindow.cpp +++ b/map65/mainwindow.cpp @@ -1,5 +1,7 @@ //------------------------------------------------------------------ MainWindow #include "mainwindow.h" +#include +#include #include "revision_utils.hpp" #include "widgets/MessageBox.hpp" #include "ui_mainwindow.h" @@ -193,6 +195,8 @@ MainWindow::MainWindow(QWidget *parent) : } memset(to,0,size); //Zero all decoding params in shared memory + fftwf_import_wisdom_from_filename (QDir {m_appDir}.absoluteFilePath ("map65_wisdom.dat").toLocal8Bit ()); + PaError paerr=Pa_Initialize(); //Initialize Portaudio if(paerr!=paNoError) { msgBox("Unable to initialize PortAudio."); @@ -312,6 +316,7 @@ MainWindow::~MainWindow() soundOutThread.wait(3000); } Pa_Terminate(); + fftwf_export_wisdom_to_filename (QDir {m_appDir}.absoluteFilePath ("map65_wisdom.dat").toLocal8Bit ()); if(!m_decoderBusy) { QFile lockFile(m_appDir + "/.lock"); lockFile.remove();