LCOV - code coverage report
Current view: top level - src/78_effpot - m_mpi_scheduler.F90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 50.5 % 101 51
Test Date: 2026-11-11 11:17:02 Functions: 26.7 % 15 4
Branches: 37.3 % 126 47

             Branch data     Line data    Source code
       1                 :             : !!****m* ABINIT/m_mpi_scheduler
       2                 :             : !! NAME
       3                 :             : !! m_mpi_scheduler
       4                 :             : !!
       5                 :             : !! FUNCTION
       6                 :             : !! This module contains the mpi scheduler for spin dynamics
       7                 :             : !! It provide the function to assign site to mpi nodes, and methods for scattering (TODO),
       8                 :             : !! and gathering data from nodes.
       9                 :             : !!
      10                 :             : !! Datatypes:
      11                 :             : !!
      12                 :             : !! * mpi_scheduler_t
      13                 :             : !!
      14                 :             : !! Subroutines:
      15                 :             : !! TODO: add this when F2003 doc style is determined.
      16                 :             : !!
      17                 :             : !!
      18                 :             : !! COPYRIGHT
      19                 :             : !! Copyright (C) 2001-2026 ABINIT group (hexu)
      20                 :             : !! This file is distributed under the terms of the
      21                 :             : !! GNU General Public License, see ~abinit/COPYING
      22                 :             : !! or http://www.gnu.org/copyleft/gpl.txt .
      23                 :             : !! For the initials of contributors, see ~abinit/doc/developers/contributors.txt .
      24                 :             : !!
      25                 :             : !! SOURCE
      26                 :             : 
      27                 :             : #if defined HAVE_CONFIG_H
      28                 :             : #include "config.h"
      29                 :             : #endif
      30                 :             : #include "abi_common.h"
      31                 :             : 
      32                 :             : 
      33                 :             : module m_mpi_scheduler
      34                 :             :   use defs_basis
      35                 :             :   use m_xmpi
      36                 :             :   use m_errors
      37                 :             :   use m_abicore
      38                 :             : 
      39                 :             :   implicit none
      40                 :             : !!***
      41                 :             : 
      42                 :             : 
      43                 :             :   private
      44                 :             : 
      45                 :             :   type, public :: mb_mpi_info_t
      46                 :             :      integer :: master =0
      47                 :             :      logical :: iam_master =.False.
      48                 :             :      integer :: my_rank, comm, nproc, ierr
      49                 :             :    contains
      50                 :             :      procedure :: initialize => mb_mpi_info_t_initialize
      51                 :             :   end type mb_mpi_info_t
      52                 :             : 
      53                 :             :   type, public :: mpi_scheduler_t
      54                 :             :      integer :: nproc, ntasks, irank,master, comm, istart, iend, ntask, nblock
      55                 :             :      ! ntasks:  total number of tasks
      56                 :             :      ! istart: first task id in this proc
      57                 :             :      ! iend: last task id in this proc
      58                 :             :      ! ntask: number of tasks in this proc
      59                 :             :      ! nblock: sometimes it is useful to group task into blocks(eg. each spin has 3 components and its better to put them together.)
      60                 :             :      integer,  allocatable :: istart_list(:), iend_list(:), ntask_list(:)
      61                 :             :      ! istart_list: istart for all nodes
      62                 :             :      ! iend_list: iend for all nodes
      63                 :             :      ! ntask_list: ntast for all nodes
      64                 :             :    contains
      65                 :             :      procedure :: initialize => mpi_scheduler_t_initialize
      66                 :             :      procedure :: finalize => mpi_scheduler_t_finalize
      67                 :             :      procedure :: get_iproc => mpi_scheduler_t_get_iproc
      68                 :             :      procedure :: get_istart
      69                 :             :      procedure :: get_iend
      70                 :             :      procedure :: get_ntask
      71                 :             :      procedure :: gatherv_dp1d ! helper function to gather 1d real(dp) array from nodes.
      72                 :             :      procedure :: gatherv_dp2d ! helper function to gather 2d real(dp) array from nodes.
      73                 :             :      procedure :: allgatherv_dp1d ! helper function to gather 1d real(dp) array from nodes.
      74                 :             :      procedure :: allgatherv_dp2d ! helper function to gather 2d real(dp) array from nodes.
      75                 :             :     ! procedure :: allgatherv_dp2d_inplace ! helper function to gather 2d real(dp) array from nodes.
      76                 :             :     ! disabled because an openmpi I tried does not support this.
      77                 :             : 
      78                 :             :   end type mpi_scheduler_t
      79                 :             : 
      80                 :             :   public :: init_mpi_info
      81                 :             : 
      82                 :             : contains
      83                 :             :   ! logical :: iam_master
      84                 :             :   ! iam_master=xmpi_comm_rank(xmpi_world)==0
      85                 :             : 
      86                 :             :   !integer :: master, my_rank, comm, nproc, ierr
      87                 :             :   !logical :: iam_master
      88                 :             :   !call init_mpi_info(master, iam_master, my_rank, comm, nproc)
      89                 :     1149777 :   subroutine init_mpi_info(master, iam_master, my_rank, comm, nproc)
      90                 :             :    integer, intent(inout) :: master
      91                 :             :    logical, intent(inout) :: iam_master
      92                 :             :    integer, intent(inout) :: my_rank, comm, nproc
      93                 :     1149777 :    master=0
      94                 :     1149777 :    comm = xmpi_world
      95                 :     1149777 :    nproc = xmpi_comm_size(comm)
      96                 :     1149777 :    my_rank = xmpi_comm_rank(comm)
      97                 :     1149777 :    iam_master = (my_rank == master)
      98                 :     1149777 :   end subroutine init_mpi_info
      99                 :             : 
     100                 :             : 
     101                 :             :   !----------------------------------------------------------------------
     102                 :             :   !> @brief initialize mpi info type
     103                 :             :   !----------------------------------------------------------------------
     104                 :           0 :   subroutine mb_mpi_info_t_initialize(self)
     105                 :             :     class (mb_mpi_info_t):: self
     106                 :           0 :     self%master = 0
     107                 :           0 :     self%comm = xmpi_world
     108                 :           0 :     self%nproc = xmpi_comm_size(self%comm)
     109                 :           0 :     self%my_rank = xmpi_comm_rank(self%comm)
     110                 :           0 :     self%iam_master = (self%my_rank == self%master)
     111                 :           0 :   end subroutine mb_mpi_info_t_initialize
     112                 :             : 
     113                 :             : 
     114                 :             :   !----------------------------------------------------------------------
     115                 :             :   !> @brief assign ntasks to ranks in mpi comm.
     116                 :             :   !> @param[in]  ntasks: number of tasks to be done. e.g. number of spins to be moved.
     117                 :             :   !> @param[in]  master: the id of master node
     118                 :             :   !> @param[in]  comm: the communicator
     119                 :             :   !> @param[in]  nblock: the task should be divided so that nblock are together.
     120                 :             :   !>              e.g. for 3*nspin tasks, nblock=3 will assure that the 3 direction of one
     121                 :             :   !>               spin is together.
     122                 :             :   !----------------------------------------------------------------------
     123                 :             : 
     124                 :          30 :   subroutine mpi_scheduler_t_initialize(self, ntasks, master, comm, nblock)
     125                 :             :     !
     126                 :             :     ! ntask: number of tasks
     127                 :             :     ! nblock: number of subtask per task. TODO: should improve the naming.
     128                 :             :     class(mpi_scheduler_t), intent(inout) :: self
     129                 :             :     integer, intent(in) :: ntasks
     130                 :             :     integer, intent(in) :: master, comm
     131                 :             :     integer, optional, intent(in):: nblock
     132                 :             :     integer :: i,nmore, n, ierr
     133                 :             : 
     134         [ +  + ]:          10 :     if( present(nblock)) then
     135                 :           2 :        self%nblock=nblock
     136                 :             :     else
     137                 :           8 :        self%nblock=1
     138                 :             :     end if
     139                 :          10 :     call xmpi_bcast(self%nblock, master, comm, ierr)
     140                 :             : 
     141                 :          10 :     self%master=master
     142                 :             :     !call MPI_COMM_SIZE(comm, self%nproc, ierr)
     143                 :          10 :     self%nproc = xmpi_comm_size(comm)
     144                 :             :     !call MPI_COMM_RANK(comm, self%iproc, ierr)
     145                 :          10 :     self%irank=xmpi_comm_rank(comm)
     146                 :          10 :     self%comm=comm
     147                 :          10 :     self%ntasks = ntasks
     148                 :          10 :     call xmpi_bcast(self%ntasks, self%master, comm, ierr )
     149         [ +  - ]:          10 :     if (.not. allocated(self%istart_list)) then
     150   [ -  +  +  -  :          30 :        ABI_MALLOC(self%istart_list, (self%nproc))
          +  -  +  -  -  
             +  -  +  -  
                      + ]
     151                 :             :     end if
     152                 :             : 
     153         [ +  - ]:          10 :     if (.not. allocated(self%iend_list)) then
     154   [ -  +  +  -  :          30 :        ABI_MALLOC(self%iend_list, (self%nproc) )
          +  -  +  -  -  
             +  -  +  -  
                      + ]
     155                 :             :     end if
     156                 :             : 
     157         [ +  - ]:          10 :     if (.not. allocated(self%ntask_list)) then
     158   [ -  +  +  -  :          30 :        ABI_MALLOC(self%ntask_list, (self%nproc))
          +  -  +  -  -  
             +  -  +  -  
                      + ]
     159                 :             :     endif
     160                 :             : 
     161                 :             :     ! number of procs which has one more
     162                 :          10 :     nmore=mod(self%ntasks, self%nproc)
     163                 :             : 
     164         [ +  - ]:          10 :     if(nmore==0) then
     165                 :          10 :        n=(self%ntasks-nmore)/self%nproc
     166         [ +  + ]:          20 :        do i = 1, self%nproc
     167                 :          10 :           self%istart_list(i)= 1+(i-1)*n
     168                 :          10 :           self%iend_list(i)=i*n
     169                 :          20 :           self%ntask_list(i)=n
     170                 :             :        end do
     171                 :             :     else
     172                 :           0 :        n=(self%ntasks-nmore)/self%nproc
     173         [ #  # ]:           0 :        do i = 1, nmore
     174                 :           0 :           self%ntask_list(i)=n+1
     175                 :           0 :           self%istart_list(i)= 1+(i-1) *(n+1)
     176                 :           0 :           self%iend_list(i)=self%istart_list(i)+self%ntask_list(i)-1
     177                 :             :        end do
     178                 :             : 
     179         [ #  # ]:           0 :        do i = nmore+1, self%nproc
     180                 :           0 :           self%ntask_list(i)=n
     181                 :           0 :           self%istart_list(i)= self%iend_list(i-1)+1
     182                 :           0 :           self%iend_list(i)=self%istart_list(i)+self%ntask_list(i)-1
     183                 :             :        end do
     184                 :             :     end if
     185                 :             : 
     186         [ +  + ]:          20 :     do i=1, self%nproc
     187                 :          10 :        self%ntask_list(i)=self%ntask_list(i) * self%nblock
     188                 :          10 :        self%istart_list(i) = (self%istart_list(i)-1) *self%nblock + 1
     189                 :          20 :        self%iend_list(i) = self%iend_list(i)*self%nblock
     190                 :             :     end do
     191                 :             : 
     192                 :          10 :     self%istart=self%istart_list(self%irank  + 1)
     193                 :          10 :     self%iend=self%iend_list(self%irank  + 1)
     194                 :          10 :     self%ntask=self%ntask_list(self%irank  + 1)
     195                 :             : 
     196                 :          10 :   end subroutine mpi_scheduler_t_initialize
     197                 :             : 
     198                 :             : 
     199                 :             : 
     200                 :             :   !----------------------------------------------------------------------
     201                 :             :   !> @brief find the proc id of which the index of task belong to
     202                 :             :   !>
     203                 :             :   !> @param[in]  i: the index of task
     204                 :             :   !> @param[out] iproc: the id of process which is in charge of the task
     205                 :             :   !----------------------------------------------------------------------
     206                 :           0 :   function mpi_scheduler_t_get_iproc(self, i) result(iproc)
     207                 :             :     class(mpi_scheduler_t), intent(in) :: self
     208                 :             :     integer, intent(in) :: i
     209                 :             :     integer :: iproc
     210                 :           0 :     iproc=i/(self%ntasks/self%nproc)
     211                 :           0 :   end function mpi_scheduler_t_get_iproc
     212                 :             : 
     213                 :             :   !----------------------------------------------------------------------
     214                 :             :   !> @brief get the start of the id of work for the rank
     215                 :             :   !>
     216                 :             :   !> @param[in]  rank: the id of the rank
     217                 :             :   !> @param[out] i: the starting id of work
     218                 :             :   !----------------------------------------------------------------------
     219                 :           0 :   function get_istart(self, rank) result(i)
     220                 :             :     class(mpi_scheduler_t), intent(in) :: self
     221                 :             :     integer, optional, intent(in):: rank
     222                 :             :     integer :: i, r
     223         [ #  # ]:           0 :     if (present(rank)) then
     224                 :           0 :        r=rank
     225                 :             :     else
     226                 :           0 :        r=self%irank
     227                 :             :     end if
     228                 :           0 :     i=self%istart_list(r+1)
     229                 :           0 :   end function get_istart
     230                 :             : 
     231                 :             :   !----------------------------------------------------------------------
     232                 :             :   !> @brief get the end of the id of work for the rank
     233                 :             :   !>
     234                 :             :   !> @param[in]  rank: the id of the rank
     235                 :             :   !> @param[out] i: the end id of work
     236                 :             :   !----------------------------------------------------------------------
     237                 :           0 :   function get_iend(self, rank) result(i)
     238                 :             :     class(mpi_scheduler_t), intent(in) :: self
     239                 :             :     integer, optional, intent(in):: rank
     240                 :             :     integer :: i, r
     241         [ #  # ]:           0 :     if (present(rank)) then
     242                 :           0 :        r=rank
     243                 :             :     else
     244                 :           0 :        r=self%irank
     245                 :             :     end if
     246                 :           0 :     i=self%iend_list(r+1)
     247                 :           0 :   end function get_iend
     248                 :             : 
     249                 :             :   !----------------------------------------------------------------------
     250                 :             :   !> @brief get the number of work for the rank
     251                 :             :   !>
     252                 :             :   !> @param[in]  rank: the id of the rank
     253                 :             :   !> @param[out] i: the number of works assigned to this rank
     254                 :             :   !----------------------------------------------------------------------
     255                 :           0 :   function get_ntask(self, rank) result(i)
     256                 :             :     class(mpi_scheduler_t), intent(in) :: self
     257                 :             :     integer, optional, intent(in):: rank
     258                 :             :     integer :: i, r
     259         [ #  # ]:           0 :     if (present(rank)) then
     260                 :           0 :        r=rank
     261                 :             :     else
     262                 :           0 :        r=self%irank
     263                 :             :     end if
     264                 :           0 :     i=self%ntask_list(r+1)
     265                 :           0 :   end function get_ntask
     266                 :             : 
     267                 :             :   !----------------------------------------------------------------------
     268                 :             :   !> @brief helper function to gather real(dp) 1D array to  master node
     269                 :             :   !>
     270                 :             :   !> @param[in]  data: the data array to be gathered
     271                 :             :   !> @param[out] buffer: a buffer to be used for the gathering.
     272                 :             :   !----------------------------------------------------------------------
     273                 :           0 :   subroutine gatherv_dp1d(self, data, buffer)
     274                 :             :     class(mpi_scheduler_t), intent(inout) :: self
     275                 :             :     real(dp), intent(inout) :: data(self%ntasks)
     276                 :             :     real(dp), intent(inout) :: buffer(self%ntasks)
     277                 :             :     integer :: ierr
     278                 :             :     call xmpi_gatherv(data(self%istart: self%iend), &
     279                 :             :          & self%ntask, &
     280                 :             :          & buffer,&
     281                 :             :          & self%ntask_list, &
     282                 :             :          & self%istart_list-1, &
     283   [ #  #  #  # ]:           0 :          & self%master, self%comm, ierr )
     284         [ #  # ]:           0 :   data(:)=buffer(:)
     285                 :           0 :   end subroutine gatherv_dp1d
     286                 :             : 
     287                 :             :   !----------------------------------------------------------------------
     288                 :             :   !> @brief helper function to gather real(dp) 2D array to  master node
     289                 :             :   !>
     290                 :             :   !> @param[in]  data: the data array to be gathered
     291                 :             :   !> @param[out] buffer: a buffer to be used for the gathering.
     292                 :             :   !----------------------------------------------------------------------
     293                 :           0 :   subroutine gatherv_dp2d(self, data, nrow, buffer)
     294                 :             :     class(mpi_scheduler_t), intent(inout) :: self
     295                 :             :     integer, intent(in) :: nrow
     296                 :             :     real(dp), intent(inout) :: data(nrow,self%ntasks), buffer(nrow, self%ntasks)
     297                 :             :     integer :: ierr
     298                 :             :     call xmpi_gatherv(data(:,self%istart:self%iend), &
     299                 :             :          & self%ntask*nrow, &
     300                 :             :          & buffer, &
     301                 :             :          & self%ntask_list*nrow, &
     302                 :             :          & (self%istart_list-1)*nrow, &
     303   [ #  #  #  #  :           0 :          & self%master, self%comm, ierr)
             #  #  #  # ]
     304   [ #  #  #  # ]:           0 :     data(:,:)=buffer(:,:)
     305                 :           0 :   end subroutine gatherv_dp2d
     306                 :             : 
     307                 :             :   !----------------------------------------------------------------------
     308                 :             :   !> @brief helper function to gather real(dp) 1D array to  master node
     309                 :             :   !>    and bcast to every node
     310                 :             :   !> @param[in]  data: the data array to be gathered
     311                 :             :   !> @param[out] buffer: a buffer to be used for the gathering.
     312                 :             :   !----------------------------------------------------------------------
     313                 :           0 :   subroutine allgatherv_dp1d(self, data, buffer)
     314                 :             :     class(mpi_scheduler_t), intent(inout) :: self
     315                 :             :     real(dp), intent(inout) :: data(self%ntasks)
     316                 :             :     real(dp), intent(inout) :: buffer(self%ntasks)
     317                 :             :     integer :: ierr
     318                 :             :     call xmpi_allgatherv(data(self%istart: self%iend), &
     319                 :             :          & self%ntask, &
     320                 :             :          & buffer,&
     321                 :             :          & self%ntask_list, &
     322                 :             :          & self%istart_list-1, &
     323   [ #  #  #  # ]:           0 :          & self%comm, ierr )
     324         [ #  # ]:           0 :   data(:)=buffer(:)
     325                 :           0 :   end subroutine allgatherv_dp1d
     326                 :             : 
     327                 :             : 
     328                 :             :   !----------------------------------------------------------------------
     329                 :             :   !> @brief helper function to gather real(dp) 2D array to  master node
     330                 :             :   !>    and bcast to every node
     331                 :             :   !> @param[in]  data: the data array to be gathered
     332                 :             :   !> @param[out] buffer: a buffer to be used for the gathering.
     333                 :             :   !----------------------------------------------------------------------
     334                 :        4004 :   subroutine allgatherv_dp2d(self, data, nrow, buffer)
     335                 :             :     class(mpi_scheduler_t), intent(inout) :: self
     336                 :             :     integer, intent(in) :: nrow
     337                 :             :     real(dp), intent(inout) :: data(nrow,self%ntasks), buffer(nrow, self%ntasks)
     338                 :             :     integer :: ierr
     339                 :             : 
     340                 :             :     !xmpi_allgatherv_int2d(xval,nelem,recvbuf,recvcounts,displs,spaceComm,ier)
     341                 :             :     call xmpi_allgatherv(data(:,self%istart:self%iend), &
     342                 :             :          & self%ntask*nrow, &
     343                 :             :          & buffer, &
     344                 :             :          & self%ntask_list*nrow, &
     345                 :             :          & (self%istart_list-1)*nrow, &
     346   [ +  -  +  +  :       12012 :          & self%comm, ierr)
             +  -  +  + ]
     347   [ +  +  +  + ]:     3463460 :     data(:,:)=buffer(:,:)
     348                 :        4004 :   end subroutine allgatherv_dp2d
     349                 :             : 
     350                 :             : 
     351                 :             : !  subroutine allgatherv_dp2d_inplace(self, data, nrow)
     352                 :             : !    class(mpi_scheduler_t), intent(inout) :: self
     353                 :             : !    integer, intent(in) :: nrow
     354                 :             : !    real(dp), intent(inout) :: data(nrow,self%ntasks)
     355                 :             : !    integer :: ierr
     356                 :             : !
     357                 :             : !    !xmpi_allgatherv_int2d(xval,nelem,recvbuf,recvcounts,displs,spaceComm,ier)
     358                 :             : !    call xmpi_allgatherv(xmpi_in_place, &
     359                 :             : !         & self%ntask*nrow, &
     360                 :             : !         & data, &
     361                 :             : !         & self%ntask_list*nrow, &
     362                 :             : !         & (self%istart_list-1)*nrow, &
     363                 :             : !         & self%comm, ierr)
     364                 :             : !  end subroutine allgatherv_dp2d_inplace
     365                 :             : 
     366                 :             :   !----------------------------------------------------------------------
     367                 :             :   !> @brief free memory used
     368                 :             :   !----------------------------------------------------------------------
     369                 :          11 :   subroutine mpi_scheduler_t_finalize(self)
     370                 :             :     class(mpi_scheduler_t), intent(inout) :: self
     371         [ +  + ]:          11 :     if (allocated(self%istart_list)) then
     372                 :          10 :        ABI_FREE(self%istart_list)
     373                 :             :     endif
     374         [ +  + ]:          11 :     if (allocated(self%iend_list)) then
     375                 :          10 :        ABI_FREE(self%iend_list)
     376                 :             :     endif
     377         [ +  + ]:          11 :     if (allocated(self%ntask_list)) then
     378                 :          10 :        ABI_FREE(self%ntask_list)
     379                 :             :     endif
     380                 :          11 :   end subroutine mpi_scheduler_t_finalize
     381                 :             : 
     382                 :             : 
     383   [ #  #  #  #  :           0 : end module m_mpi_scheduler
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
        

Generated by: LCOV version 2.3-1