IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Fortran Discussion :

Comment éviter que mon code soit très lent avec 16 child processes et plusieurs variables?


Sujet :

Fortran

  1. #1
    Nouveau Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Juillet 2021
    Messages
    2
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 26
    Localisation : France, Cher (Centre)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juillet 2021
    Messages : 2
    Points : 1
    Points
    1
    Par défaut Comment éviter que mon code soit très lent avec 16 child processes et plusieurs variables?
    Bonjour,

    J'écris ma question en anglais vu que je me trouve plus à l'aise avec cette langue. (C'est la première discussion que j'ouvre sur ce site).
    I wrote this small code in order to adapt it to my main code and to use the `fork/wait` method to execute tasks stored in an `array` of 16 tasks (`defined type` : `function pointer` pointing to the subroutine to execute + `integer` for the state of the task).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
     ! fork.f90
        program main
          use :: unix
          implicit none
          integer :: i, pid, STATUS,any_child
          integer :: sum=0,product=5
          pid = c_fork()
     
          if (pid < 0) then
             ! Fork failed.
             call perror('fork()' // c_null_char)
          else if (pid == 0) then
             print '(a)', '>>> child process running ...'
             do i = 1, 3
                ! Sleep for 1 second.
                print '(">>> step ", i0, " ...")', i
                sum=sum+1
                product=product*2 
                open(1, file = 'variables.dat')
                write(1,*) sum,product
                close(1)
             end do
             print '(a)', '>>> child process done.'
             call exit(STATUS)
          else
             ! Parent process.
             print*,'habibi'
             any_child=c_wait(STATUS)
             print*,'ya nour 3in'
             open(2,file='variables.dat')
             read(2,*) sum,product
             close(2)
             print*,'The sum is equal to : ',sum
             print*,'The product is equal to : ',product
          end if
     
     
        end program main
    As you can see here (if I understood well..), we have one child process executing the computations and the parent process waiting and printing some stuff.
    The problem I encountred is that the values of "sum" and "product" printed by the parent process aren't correct. For the sum, I get 0 as a value as if the computations done by the child process didn't even happen.
    I thought about writing the values computed by the child process in a file which will be read by the parent process. And it works ! But in order to adapt this to my code, I need to take many things into consideration :
    First, I spawned 16 child processes not only 1.
    Second, I have more than 15 variables not only 2 (sum and product).
    Finally, each child process will read and write in the file which makes the program very very very slow especially with 16 child processes.

    I'll show you a part of my code:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    number_children=16
                  do ff =5,number_children+4
                     if (tasks_ready_master(ff)%state==STATE_READY) then
                        tasks_ready_master(ff)%state=STATE_RUNNING      
                        pid=c_fork() !< spawn a child process 
                        if (pid < 0) then 
                           call perror('fork()' // c_null_char) !< Error 
                        else if  (pid == 0) then !< Child process              
                           call tasks_ready_master(ff)%f_ptr(self,var) !< execute the task
                           open(1, file = 'variables.dat')
                           write(1,*) var%pas_t
                           write(1,*) var%cpt_t
                           write(1,*) var%cpt1_t
                           write(1,*) var%nb_element_t
                           write(1,*) var%ww_t
                           write(1,*) var%dt_t
                           write(1,*) var%dx_t
                           write(1,*) var%p_element_t
                           write(1,*) var%u_prime_t
                           write(1,*) var%u_prime_moins_t
                           write(1,*) var%u_prime_plus_t
                           write(1,*) var%taux_t
                           write(1,*) var%grad_x_u_t
                           write(1,*) var%grad_t_u_t
                           write(1,*) var%grad_t_f_t
                           write(1,*) var%grad_x_f_t
                           write(1,*) var%flux_t
                           write(1,*) var%sm_t
                           write(1,*) var%ax_plus_t
                           write(1,*) var%ax_moins_t
                           write(1,*) var%ux_moins_t
                           write(1,*) var%ux_plus_t
                           write(1,*) var%tab0_t
                           write(1,*) var%tab_t
                           close(1)
                           tasks_ready_master(ff)%state=STATE_INACTIVE 
                           call exit(STATUS)
                        else
                           any_child=c_wait(STATUS) !< wait for the child process 
                           if (any_child<0) then
                              stop 'error' !< Error 
                           end if
     
                        end if
                        open(2,file='variables.dat')
                        read(2,*) var%pas_t
                        read(2,*) var%cpt_t
                        read(2,*) var%cpt1_t
                        read(2,*) var%nb_element_t
                        read(2,*) var%ww_t
                        read(2,*) var%dt_t
                        read(2,*) var%dx_t
                        read(2,*) var%p_element_t
                        read(2,*) var%u_prime_t
                        read(2,*) var%u_prime_moins_t
                        read(2,*) var%u_prime_plus_t
                        read(2,*) var%taux_t
                        read(2,*) var%grad_x_u_t
                        read(2,*) var%grad_t_u_t
                        read(2,*) var%grad_t_f_t
                        read(2,*) var%grad_x_f_t
                        read(2,*) var%flux_t
                        read(2,*) var%sm_t
                        read(2,*) var%ax_plus_t
                        read(2,*) var%ax_moins_t
                        read(2,*) var%ux_moins_t
                        read(2,*) var%ux_plus_t
                        read(2,*) var%tab0_t
                        read(2,*) var%tab_t
                        close(2)
                     end if
                  end do
               end if
    As you can see, I wrote and read multiple variables.
    In order to understand what var is, here is its declaration:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
        type(variables)::var !< the variables
    with:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     type::variables 
             INTEGER,pointer::pas_t,cpt_t,cpt1_t,nb_element_t,ww_t
             real(kind=REAL64),pointer :: dt_t,dx_t
             integer ,dimension(:),pointer::p_element_t
             real(kind=REAL64), dimension(:),pointer ::u_prime_t,u_prime_moins_t, u_prime_plus_t,taux_t,grad_x_u_t,&
                  &grad_t_u_t,grad_t_f_t,grad_x_f_t,flux_t,sm_t
             real(kind=REAL64),dimension(:),pointer:: ax_plus_t,ax_moins_t,ux_moins_t,ux_plus_t
             real(kind=REAL64),dimension(:,:),pointer::tab0_t,tab_t
          end type variables
    Simply, it stores all the variables I need in my computations and in the execution of the tasks.

    Is the small code efficient ? I want to avoid using pipe.
    What should I do in this case? How can I avoid my program getting very slow? Should I parellize using OpenMP ? I want to mention that only one thread execute the part of code I showed before.

  2. #2
    Membre confirmé
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    488
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2007
    Messages : 488
    Points : 593
    Points
    593
    Par défaut
    Hi,

    I don't know of the "UNIX" module you use; not sure this is standard...

    Anyways, it really looks like you want to create Unix processes etc. and handle them from the Fortran code.
    Why is that? To me the most obvious way to do (and manage efficiently) parallelization is to use OpenMP or MPI within the code itself.

  3. #3
    Nouveau Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Juillet 2021
    Messages
    2
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 26
    Localisation : France, Cher (Centre)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juillet 2021
    Messages : 2
    Points : 1
    Points
    1
    Par défaut
    I have an array of 20 tasks that I want to execute in a parallel way.
    Instead of using OMP Tasking at the Master thread level, I decided to create 4 child processes using `c_fork` and to use `!$OMP TASK` at the child process level so that each CP uses a number of threads in order to execute a block of 4 tasks. (4 child processes*4 tasks =16 tasks).
    Here is the declaration of the variables:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    INTEGER ::ff !< the counter
            type(tcb)::self !< self
            type(variables),intent(inout)::var !< the variables 
            integer::STATUS !< STATUS
            integer::any_child !< child process
            integer::rc !< return code 
            !OpenMP variables
            integer::num_thread !< the rank of the thread
            integer::num_thread_cp !< the rank of a thread in the child process 
            integer::nthreads !< the number of threads
            integer:: OMP_GET_THREAD_NUM !< function to get the rank of the thread
            integer::OMP_GET_NUM_THREADS !< function to get the number of threads    
        !!$    type(tcb),dimension(20)::tasklist_GRAD !< the array of tasks
            type(tcb),dimension(20),intent(inout)::tasks_ready_master !< the master array of tasks 
            !Variables pour gestion des threads 
        !!$    INTEGER(KIND=omp_lock_kind), SAVE :: lock
            integer::number_children !< the number of child processes 
            integer::pid !< the pid
    Here is the code I implemented:



    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
       !=======================================================================================================================================================
           !$OMP PARALLEL PRIVATE(num_thread,nthreads,ff) &
           !$OMP SHARED(tasks_ready_master)
           num_thread=OMP_GET_THREAD_NUM() ! le rang du thread 
           nthreads=OMP_GET_NUM_THREADS() ! le nombre de threads
     
        if (num_thread==0) then !< Thread Master (number 0) 
                  number_children=4
                  do ff =5,20,number_children
                        pid=c_fork() !< spawn a child process 
                        if (pid < 0) then 
                           call perror('fork()' // c_null_char) !< Error 
                        else if  (pid == 0) then !< Child process
                           !$OMP TASK SHARED(tasks_ready_master)  IF ((num_thread .ne. 0) .and. (num_thread .ne. 1))
                              call tasks_ready_master(ff)%f_ptr(self,var) !< execute the task
                           !$OMP END TASK
                           call exit(STATUS)
     
                        else
                           any_child=c_wait(STATUS) !< wait for the child process 
                           if (any_child<0) then
                              stop 'error' !< Error 
                           end if
                        end if
                  end do
        end if
    My problem is at this line :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    call tasks_ready_master(ff)%f_ptr(self,var) !< execute the task
    .
    Suppose that we have 4 threads. Only 2 workers are available.
    How can I be sure that each worker will execute a task in a block of 4 tasks then go to the next task (if not executed yet) ?
    I hope that you understood my question. All I want is to parallelize the `fork/wait` method.

    PS: Don't worry about the `tcb` and `variables` types.

  4. #4
    Membre confirmé
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    488
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2007
    Messages : 488
    Points : 593
    Points
    593
    Par défaut
    Again, why do you want to use/monitor tasks at system level rather than within the program with plain OpenMP?
    To me this looks like seting up lots of complications to at best do what OpenMP (and/or MPI) already offers.

    Suppose that we have 4 threads. Only 2 workers are available.
    How can I be sure that each worker will execute a task in a block of 4 tasks then go to the next task (if not executed yet) ?
    I hope that you understood my question. All I want is to parallelize the `fork/wait` method.
    Looks like you want to use more cores than available. There's no miracle there: your program should split up and organize the work (sequentialy) on these cores (e.g you have 20 things to do but only 4 cores then your program should make task 0 do things 1-5, task 1 do things 5-10, etc.).

Discussions similaires

  1. Réponses: 1
    Dernier message: 22/01/2019, 15h40
  2. Réponses: 15
    Dernier message: 29/09/2013, 11h47
  3. Comment éviter que mon annimation rame
    Par arnaudperfect dans le forum ActionScript 1 & ActionScript 2
    Réponses: 0
    Dernier message: 08/02/2009, 21h54
  4. Pourquoi mon code est plus lent que Arrays.sort
    Par alexis779 dans le forum Collection et Stream
    Réponses: 3
    Dernier message: 12/12/2006, 12h44

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo