23#include "../../base/base_uses.f90"
48 CHARACTER(len=*),
PARAMETER,
PRIVATE :: moduleN =
'dbt_tas_split'
56 MODULE PROCEDURE dbt_tas_mp_comm_from_matrix_sizes
74 INTEGER,
INTENT(INOUT) :: ngroup
75 INTEGER,
INTENT(IN) :: igroup, split_rowcol
76 LOGICAL,
INTENT(IN),
OPTIONAL :: own_comm
78 CHARACTER(LEN=*),
PARAMETER :: routinen =
'dbt_tas_create_split_rows_or_cols'
80 INTEGER :: handle, igroup_check, iproc, &
81 iproc_group, iproc_group_check, &
83 INTEGER,
DIMENSION(2) :: pdims, pdims_group
84 LOGICAL :: own_comm_prv, to_assert
87 CALL timeset(routinen, handle)
89 IF (
PRESENT(own_comm))
THEN
90 own_comm_prv = own_comm
92 own_comm_prv = .false.
95 IF (own_comm_prv)
THEN
96 split_info%mp_comm = mp_comm
98 CALL split_info%mp_comm%from_dup(mp_comm)
101 split_info%igroup = igroup
102 split_info%split_rowcol = split_rowcol
104 CALL mp_comm_group%from_split(mp_comm, igroup)
106 iproc = mp_comm%mepos
107 pdims = mp_comm%num_pe_cart
108 split_info%pdims = pdims
110 numproc_group = mp_comm_group%num_pe
111 iproc_group = mp_comm_group%mepos
114 to_assert = mod(numproc_group, pdims(mod(split_rowcol, 2) + 1)) == 0
116 split_info%pgrid_split_size = numproc_group/pdims(mod(split_rowcol, 2) + 1)
118 CALL split_info%mp_comm%bcast(split_info%pgrid_split_size, 0)
120 ngroup = (pdims(split_rowcol) + split_info%pgrid_split_size - 1)/split_info%pgrid_split_size
121 split_info%ngroup = ngroup
122 split_info%group_size = split_info%pgrid_split_size*pdims(mod(split_rowcol, 2) + 1)
124 CALL world_to_group_proc_map(iproc, pdims, split_rowcol, split_info%pgrid_split_size, igroup_check, pdims_group, iproc_group)
126 IF (igroup_check .NE. split_info%igroup)
THEN
127 cpabort(
'inconsistent subgroups')
130 CALL split_info%mp_comm_group%create(mp_comm_group, 2, pdims_group)
132 iproc_group_check = split_info%mp_comm_group%mepos
134 cpassert(iproc_group_check .EQ. iproc_group)
136 CALL mp_comm_group%free()
138 ALLOCATE (split_info%refcount)
139 split_info%refcount = 1
141 CALL timestop(handle)
156 INTEGER,
INTENT(IN) :: split_rowcol, nsplit
159 CHARACTER(LEN=*),
PARAMETER :: routinen =
'dbt_tas_mp_comm'
161 INTEGER :: handle, numproc
162 INTEGER,
DIMENSION(2) :: npdims
164 CALL timeset(routinen, handle)
166 numproc = mp_comm%num_pe
172 CALL timestop(handle)
184 INTEGER,
INTENT(IN) :: numproc, split_rowcol, nsplit
187 INTEGER :: group_size, nsplit_opt
188 INTEGER,
DIMENSION(2) :: group_dims
190 nsplit_opt = get_opt_nsplit(numproc, nsplit, split_pgrid=.false.)
192 group_size = numproc/nsplit_opt
199 SELECT CASE (split_rowcol)
201 group_dims = [minval(group_dims), maxval(group_dims)]
203 group_dims = [maxval(group_dims), minval(group_dims)]
206 SELECT CASE (split_rowcol)
225 FUNCTION get_opt_nsplit(numproc, nsplit, split_pgrid, pdim_nonsplit)
226 INTEGER,
INTENT(IN) :: numproc, nsplit
227 LOGICAL,
INTENT(IN) :: split_pgrid
228 INTEGER,
INTENT(IN),
OPTIONAL :: pdim_nonsplit
229 INTEGER :: get_opt_nsplit
231 INTEGER :: count, count_accept, count_square, lb, &
233 INTEGER,
ALLOCATABLE,
DIMENSION(:) :: nsplit_list, nsplit_list_accept, &
235 INTEGER,
DIMENSION(2) :: dims_sub
239 IF (split_pgrid)
THEN
240 cpassert(
PRESENT(pdim_nonsplit))
248 ALLOCATE (nsplit_list(1:ub - lb + 1), nsplit_list_square(1:ub - lb + 1), nsplit_list_accept(1:ub - lb + 1))
253 IF (mod(numproc, split) == 0)
THEN
255 nsplit_list(count) = split
258 IF (.NOT. split_pgrid)
THEN
261 dims_sub = [numproc/split, pdim_nonsplit]
264 IF (dims_sub(1) == dims_sub(2))
THEN
265 count_square = count_square + 1
266 nsplit_list_square(count_square) = split
267 count_accept = count_accept + 1
268 nsplit_list_accept(count_accept) = split
270 count_accept = count_accept + 1
271 nsplit_list_accept(count_accept) = split
277 IF (count_square > 0)
THEN
278 minpos = minloc(abs(nsplit_list_square(1:count_square) - nsplit), dim=1)
279 get_opt_nsplit = nsplit_list_square(minpos)
280 ELSEIF (count_accept > 0)
THEN
281 minpos = minloc(abs(nsplit_list_accept(1:count_accept) - nsplit), dim=1)
282 get_opt_nsplit = nsplit_list_accept(minpos)
283 ELSEIF (count > 0)
THEN
284 minpos = minloc(abs(nsplit_list(1:count) - nsplit), dim=1)
285 get_opt_nsplit = nsplit_list(minpos)
287 get_opt_nsplit = nsplit
288 DO WHILE (mod(numproc, get_opt_nsplit) .NE. 0)
289 get_opt_nsplit = get_opt_nsplit - 1
304 FUNCTION dbt_tas_mp_comm_from_matrix_sizes(mp_comm, nblkrows, nblkcols)
RESULT(mp_comm_new)
306 INTEGER(KIND=int_8),
INTENT(IN) :: nblkrows, nblkcols
309 INTEGER :: nsplit, split_rowcol
311 IF (nblkrows >= nblkcols)
THEN
313 nsplit = int((nblkrows - 1)/nblkcols + 1)
316 nsplit = int((nblkcols - 1)/nblkrows + 1)
304 FUNCTION dbt_tas_mp_comm_from_matrix_sizes(mp_comm, nblkrows, nblkcols)
RESULT(mp_comm_new)
…
335 INTEGER,
INTENT(IN) :: split_rowcol, nsplit
336 LOGICAL,
INTENT(IN),
OPTIONAL :: own_comm, opt_nsplit
338 CHARACTER(LEN=*),
PARAMETER :: routinen =
'dbt_tas_create_split'
340 INTEGER :: handle, igroup, iproc, nsplit_opt, &
341 pdim_nonsplit, pdim_split
342 INTEGER,
DIMENSION(2) :: pcoord, pdims, pdims_group
343 LOGICAL :: opt_nsplit_prv
345 CALL timeset(routinen, handle)
347 IF (
PRESENT(opt_nsplit))
THEN
348 opt_nsplit_prv = opt_nsplit
350 opt_nsplit_prv = .true.
355 iproc = mp_comm%mepos
356 pdims = mp_comm%num_pe_cart
357 pcoord = mp_comm%mepos_cart
359 SELECT CASE (split_rowcol)
361 pdim_split = pdims(1)
362 pdim_nonsplit = pdims(2)
364 pdim_split = pdims(2)
365 pdim_nonsplit = pdims(1)
368 IF (opt_nsplit_prv)
THEN
369 nsplit_opt = get_opt_nsplit(pdim_split, nsplit, split_pgrid=.true., pdim_nonsplit=pdim_nonsplit)
371 IF (mod(pdims(split_rowcol), nsplit) .NE. 0)
THEN
372 cpabort(
"Split factor does not divide process grid dimension")
378 pdims_group(split_rowcol) = pdims_group(split_rowcol)/nsplit_opt
380 igroup = pcoord(split_rowcol)/pdims_group(split_rowcol)
385 ALLOCATE (split_info%ngroup_opt, source=nsplit)
388 CALL timestop(handle)
400 INTEGER,
DIMENSION(2),
INTENT(IN) :: dims
401 LOGICAL,
INTENT(IN) :: relative
404 INTEGER,
DIMENSION(2) :: dims_opt
429 INTEGER,
INTENT(OUT),
OPTIONAL :: nsplit, igroup
430 TYPE(
mp_cart_type),
INTENT(OUT),
OPTIONAL :: mp_comm_group
431 INTEGER,
INTENT(OUT),
OPTIONAL :: split_rowcol
432 INTEGER,
DIMENSION(2),
INTENT(OUT),
OPTIONAL :: pgrid_offset
434 IF (
PRESENT(mp_comm)) mp_comm = info%mp_comm
435 IF (
PRESENT(mp_comm_group)) mp_comm_group = info%mp_comm_group
436 IF (
PRESENT(split_rowcol)) split_rowcol = info%split_rowcol
437 IF (
PRESENT(igroup)) igroup = info%igroup
438 IF (
PRESENT(nsplit)) nsplit = info%ngroup
440 IF (
PRESENT(pgrid_offset))
THEN
441 SELECT CASE (info%split_rowcol)
443 pgrid_offset(:) = [info%igroup*info%pgrid_split_size, 0]
445 pgrid_offset(:) = [0, info%igroup*info%pgrid_split_size]
463 IF (.NOT.
ASSOCIATED(split_info%refcount))
THEN
465 ELSEIF (split_info%refcount < 1)
THEN
470 cpabort(
"can not destroy non-existing split_info")
473 split_info%refcount = split_info%refcount - 1
475 IF (split_info%refcount == 0)
THEN
476 CALL split_info%mp_comm_group%free()
477 CALL split_info%mp_comm%free()
478 DEALLOCATE (split_info%refcount)
483 IF (
ALLOCATED(split_info%ngroup_opt))
DEALLOCATE (split_info%ngroup_opt)
494 INTEGER,
POINTER :: ref
496 IF (split_info%refcount < 1)
THEN
497 cpabort(
"can not hold non-existing split_info")
499 ref => split_info%refcount
515 pdims_group, iproc_group)
516 INTEGER,
INTENT(IN) :: iproc
517 INTEGER,
DIMENSION(2),
INTENT(IN) :: pdims
518 INTEGER,
INTENT(IN) :: split_rowcol, pgrid_split_size
519 INTEGER,
INTENT(OUT) :: igroup
520 INTEGER,
DIMENSION(2),
INTENT(OUT),
OPTIONAL :: pdims_group
521 INTEGER,
INTENT(OUT),
OPTIONAL :: iproc_group
523 INTEGER,
DIMENSION(2) :: pcoord, pcoord_group
525 IF (
PRESENT(iproc_group))
THEN
526 cpassert(
PRESENT(pdims_group))
529 pcoord = [iproc/pdims(2), mod(iproc, pdims(2))]
531 igroup = pcoord(split_rowcol)/pgrid_split_size
533 SELECT CASE (split_rowcol)
535 IF (
PRESENT(pdims_group)) pdims_group = [pgrid_split_size, pdims(2)]
536 IF (
PRESENT(iproc_group)) pcoord_group = [mod(pcoord(1), pgrid_split_size), pcoord(2)]
538 IF (
PRESENT(pdims_group)) pdims_group = [pdims(1), pgrid_split_size]
539 IF (
PRESENT(iproc_group)) pcoord_group = [pcoord(1), mod(pcoord(2), pgrid_split_size)]
541 IF (
PRESENT(iproc_group)) iproc_group = pcoord_group(1)*pdims_group(2) + pcoord_group(2)
556 INTEGER,
INTENT(OUT) :: iproc
557 INTEGER,
DIMENSION(2),
INTENT(IN) :: pdims
558 INTEGER,
INTENT(IN) :: split_rowcol, pgrid_split_size, igroup, &
561 INTEGER,
DIMENSION(2) :: pcoord, pcoord_group, pdims_group
563 SELECT CASE (split_rowcol)
565 pdims_group = [pgrid_split_size, pdims(2)]
567 pdims_group = [pdims(1), pgrid_split_size]
570 pcoord_group = [iproc_group/pdims_group(2), mod(iproc_group, pdims_group(2))]
572 SELECT CASE (split_rowcol)
574 pcoord = [igroup*pgrid_split_size + pcoord_group(1), pcoord_group(2)]
576 pcoord = [pcoord_group(1), igroup*pgrid_split_size + pcoord_group(2)]
578 iproc = pcoord(1)*pdims(2) + pcoord(2)
594 INTEGER,
INTENT(IN),
OPTIONAL :: row_group, column_group
595 INTEGER(KIND=int_8),
INTENT(OUT),
OPTIONAL :: row, column
597 SELECT CASE (info%split_rowcol)
599 associate(rows => dist%local_rowcols)
600 IF (
PRESENT(row)) row = rows(row_group)
601 IF (
PRESENT(column)) column = column_group
604 associate(cols => dist%local_rowcols)
605 IF (
PRESENT(row)) row = row_group
606 IF (
PRESENT(column)) column = cols(column_group)
622 TYPE(dbt_tas_split_info),
INTENT(IN) :: info
623 TYPE(dbt_tas_distribution_type),
INTENT(IN) :: dist
624 INTEGER(KIND=int_8),
INTENT(IN),
OPTIONAL :: row, column
625 INTEGER,
INTENT(OUT),
OPTIONAL :: row_group, column_group
627 SELECT CASE (info%split_rowcol)
629 IF (
PRESENT(row_group)) row_group = i8_bsearch(dist%local_rowcols, row)
630 IF (
PRESENT(column_group)) column_group = int(column)
632 IF (
PRESENT(row_group)) row_group = int(row)
633 IF (
PRESENT(column_group)) column_group = i8_bsearch(dist%local_rowcols, column)
647 FUNCTION i8_bsearch(array, el, l_index, u_index)
RESULT(res)
648 INTEGER(KIND=int_8),
INTENT(in) :: array(:), el
649 INTEGER,
INTENT(in),
OPTIONAL :: l_index, u_index
652 INTEGER :: aindex, lindex, uindex
656 IF (
PRESENT(l_index)) lindex = l_index
657 IF (
PRESENT(u_index)) uindex = u_index
658 DO WHILE (lindex <= uindex)
659 aindex = (lindex + uindex)/2
660 IF (array(aindex) < el)
THEN
678 TYPE(dbt_tas_split_info),
INTENT(IN) :: info
680 CLASS(dbt_tas_distribution),
INTENT(IN) :: rowcol_dist
681 INTEGER,
INTENT(IN) :: igroup
682 INTEGER(KIND=int_8),
DIMENSION(:),
ALLOCATABLE,
INTENT(OUT) :: rowcols
683 INTEGER,
DIMENSION(0:info%pgrid_split_size - 1) :: nrowcols_group
684 INTEGER :: pcoord, nrowcols, count, pcoord_group
685 INTEGER,
DIMENSION(:),
ALLOCATABLE :: sort_indices
687 nrowcols_group(:) = 0
688 DO pcoord = igroup*info%pgrid_split_size, (igroup + 1)*info%pgrid_split_size - 1
689 pcoord_group = pcoord - igroup*info%pgrid_split_size
690 nrowcols_group(pcoord_group) =
SIZE(rowcol_dist%rowcols(pcoord))
692 nrowcols = sum(nrowcols_group)
694 ALLOCATE (rowcols(nrowcols))
697 DO pcoord = igroup*info%pgrid_split_size, (igroup + 1)*info%pgrid_split_size - 1
698 pcoord_group = pcoord - igroup*info%pgrid_split_size
699 rowcols(count + 1:count + nrowcols_group(pcoord_group)) = rowcol_dist%rowcols(pcoord)
700 count = count + nrowcols_group(pcoord_group)
703 ALLOCATE (sort_indices(nrowcols))
704 CALL sort(rowcols, nrowcols, sort_indices)
713 TYPE(dbt_tas_split_info),
INTENT(INOUT) :: info
715 info%strict_split = [.true., .true.]
Global data (distribution and block sizes) for tall-and-skinny matrices For very sparse matrices with...
methods to split tall-and-skinny matrices along longest dimension. Basically, we are splitting proces...
subroutine, public dbt_index_global_to_local(info, dist, row, column, row_group, column_group)
map global block index to group local index
integer function, dimension(2), public dbt_tas_mp_dims(numproc, split_rowcol, nsplit)
Get optimal process grid dimensions consistent with dbt_tas_create_split.
subroutine, public group_to_mrowcol(info, rowcol_dist, igroup, rowcols)
maps a process subgroup to matrix rows/columns
subroutine, public dbt_tas_release_info(split_info)
...
subroutine, public dbt_index_local_to_global(info, dist, row_group, column_group, row, column)
map group local block index to global matrix index
integer, parameter, public rowsplit
subroutine, public dbt_tas_get_split_info(info, mp_comm, nsplit, igroup, mp_comm_group, split_rowcol, pgrid_offset)
Get info on split.
integer, parameter, public colsplit
subroutine, public dbt_tas_create_split(split_info, mp_comm, split_rowcol, nsplit, own_comm, opt_nsplit)
Split Cartesian process grid using a default split heuristic.
subroutine, public dbt_tas_create_split_rows_or_cols(split_info, mp_comm, ngroup, igroup, split_rowcol, own_comm)
split mpi grid by rows or columns
real(dp), parameter, public default_nsplit_accept_ratio
subroutine, public world_to_group_proc_map(iproc, pdims, split_rowcol, pgrid_split_size, igroup, pdims_group, iproc_group)
map global process info to group
real(dp), parameter, public default_pdims_accept_ratio
subroutine, public dbt_tas_info_hold(split_info)
...
subroutine, public dbt_tas_set_strict_split(info)
freeze current split factor such that it is never changed during multiplication
subroutine, public group_to_world_proc_map(iproc, pdims, split_rowcol, pgrid_split_size, igroup, iproc_group)
map local process info to global info
logical function, public accept_pgrid_dims(dims, relative)
Whether to accept proposed process grid dimensions (based on ratio of dimensions)
DBT tall-and-skinny base types. Mostly wrappers around existing DBM routines.
Defines the basic variable types.
integer, parameter, public int_8
integer, parameter, public dp
Interface to the message passing library MPI.
subroutine, public mp_dims_create(nodes, dims)
wrapper to MPI_Dims_create
All kind of helpful little routines.