!*********************************************************************** !* GNU Lesser General Public License !* !* This file is part of the GFDL Flexible Modeling System (FMS). !* !* FMS 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 3 of the License, or (at !* your option) any later version. !* !* FMS 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 Lesser General Public !* License along with FMS. If not, see . !*********************************************************************** module fms_affinity_mod !--- standard system modules use iso_c_binding, only: c_int, c_bool use omp_lib !--- FMS modules use mpp_mod, only: input_nml_file, mpp_pe, stdlog use fms_mod, only: fms_init, check_nml_error, write_version_number, & error_mesg, FATAL, NOTE !--- default scoping implicit none private !--- namelist parameters logical:: affinity = .true. logical:: strict = .true. logical:: debug_affinity = .false. logical(c_bool):: debug_cpuset = .false. namelist /fms_affinity_nml/ affinity, strict, debug_affinity, debug_cpuset public fms_affinity_init, fms_affinity_get, fms_affinity_set !---- version number ! Include variable "version" to be written to log file. #include logical :: module_is_initialized = .FALSE. contains !--- initialization routine for affinity handling subroutine fms_affinity_init() !--- local variables integer:: io_stat integer:: ierr integer:: unit !--- return if module is initialized if (module_is_initialized) return !--- ensure fms/mpp has been initialized call fms_init() !--- read in namelist read(input_nml_file, fms_affinity_nml, iostat=io_stat) ierr = check_nml_error(io_stat,'fms_affinity_nml') !--- output information to logfile call write_version_number("fms_affinity_mod", version) unit = stdlog() write(unit,nml=fms_affinity_nml) module_is_initialized = .TRUE. end subroutine fms_affinity_init !--- function to get affinity function fms_affinity_get () result(affinity) !--- local declarations for Fortran/C affinity interoperability integer(c_int):: get_cpu_affinity !--- local variables integer:: affinity affinity = get_cpu_affinity() end function fms_affinity_get !--- routine to set affinity subroutine fms_affinity_set (component, use_hyper_thread, nthreads) !--- interface variables character(len=*), intent(in):: component logical, intent(in):: use_hyper_thread integer, intent(in):: nthreads !--- local declarations for Fortran/C affinity interoperability integer(c_int):: get_cpuset integer(c_int):: get_cpu_affinity integer(c_int):: set_cpu_affinity integer(c_int):: cpuset_sz integer(c_int), dimension(:), allocatable:: cpu_set integer(c_int):: retcode !--- local variables character(len=32):: h_name integer:: MSG_TYPE integer:: th_num integer:: indx if (.not. affinity) return if (strict) then MSG_TYPE = FATAL else MSG_TYPE = NOTE endif h_name = 'generic ' !--- allocate storage for cpuset if (use_hyper_thread) then cpuset_sz = nthreads else cpuset_sz = nthreads * 2 endif allocate (cpu_set(0:cpuset_sz-1)) !--- get cpuset for this MPI-rank retcode = get_cpuset(cpuset_sz, cpu_set, mpp_pe(), debug_cpuset) if (retcode == -1) then call error_mesg('fms_affinity_set',trim(component)//' cpu_set size > allocated storage',FATAL) elseif ( (retcode == cpuset_sz/2) .and. (retcode == nthreads) ) then call error_mesg('fms_affinity_set',trim(component)//' affinity assumes hyper-threading hardware disabled',NOTE) elseif (retcode < cpuset_sz) then call error_mesg('fms_affinity_set',trim(component)//' cpu_set size smaller than expected',MSG_TYPE) endif !--- set the affinity for the MPI-rank retcode = set_cpu_affinity(cpu_set(0)) if (retcode == -1) then call error_mesg('fms_affinity_set',trim(component)//': issue setting cpu affinity', FATAL) endif !--- set affinity for threads associated with this MPI-rank !$OMP PARALLEL NUM_THREADS (nthreads) & !$OMP& DEFAULT (none) & !$OMP& SHARED (use_hyper_thread, cpuset_sz, component, cpu_set, debug_affinity) & !$OMP& PRIVATE (th_num, indx, retcode, h_name) !$ th_num = omp_get_thread_num() !--- handle hyper threading case by alternating threads between logical and virtual cores !$ if (use_hyper_thread) then !$ if (mod(th_num,2) == 0 ) then !$ indx = th_num/2 !$ else !$ indx = (cpuset_sz - 1) - ((cpuset_sz - 1) - th_num)/2 !$ endif !$ else !$ indx = th_num !$ endif !$ retcode = set_cpu_affinity(cpu_set(indx)) !$ if (retcode == -1) then !$ call error_mesg('fms_affinity_set',trim(component)//': issue setting cpu affinity', FATAL) !$ endif !--- output affinity placement !$ if (debug_affinity) then !$ call hostnm(h_name) !$ print *, 'DEBUG:',mpp_pe(),trim(component),' ',trim(h_name),get_cpu_affinity(),th_num !$ endif !$OMP END PARALLEL end subroutine fms_affinity_set end module fms_affinity_mod