Code coverage tests

This page documents the degree to which the PARI/GP source code is tested by our public test suite, distributed with the source distribution in directory src/test/. This is measured by the gcov utility; we then process gcov output using the lcov frond-end.

We test a few variants depending on Configure flags on the pari.math.u-bordeaux.fr machine (x86_64 architecture), and agregate them in the final report:

The target is 90% coverage for all mathematical modules (given that branches depending on DEBUGLEVEL or DEBUGMEM are not covered). This script is run to produce the results below.

LCOV - code coverage report
Current view: top level - mt - pthread.c (source / functions) Hit Total Coverage
Test: PARI/GP v2.8.0 lcov report (development 18948-dd2a64a) Lines: 159 166 95.8 %
Date: 2016-05-27 Functions: 14 15 93.3 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 57 74 77.0 %

           Branch data     Line data    Source code
       1                 :            : /* Copyright (C) 2013  The PARI group.
       2                 :            : 
       3                 :            : This file is part of the PARI/GP package.
       4                 :            : 
       5                 :            : PARI/GP is free software; you can redistribute it and/or modify it under the
       6                 :            : terms of the GNU General Public License as published by the Free Software
       7                 :            : Foundation. It is distributed in the hope that it will be useful, but WITHOUT
       8                 :            : ANY WARRANTY WHATSOEVER.
       9                 :            : 
      10                 :            : Check the License for details. You should have received a copy of it, along
      11                 :            : with the package; see the file 'COPYING'. If not, write to the Free Software
      12                 :            : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
      13                 :            : #include <pthread.h>
      14                 :            : #include "pari.h"
      15                 :            : #include "paripriv.h"
      16                 :            : #include "mt.h"
      17                 :            : #if defined(_WIN32)
      18                 :            : #  include "../systems/mingw/mingw.h"
      19                 :            : #endif
      20                 :            : 
      21                 :            : struct mt_queue
      22                 :            : {
      23                 :            :   long no;
      24                 :            :   pari_sp avma;
      25                 :            :   GEN input, output;
      26                 :            :   GEN worker;
      27                 :            :   long workid;
      28                 :            :   pthread_cond_t cond;
      29                 :            :   pthread_mutex_t mut;
      30                 :            :   pthread_cond_t *pcond;
      31                 :            :   pthread_mutex_t *pmut;
      32                 :            : };
      33                 :            : 
      34                 :            : struct mt_pstate
      35                 :            : {
      36                 :            :   pthread_t *th;
      37                 :            :   struct pari_thread *pth;
      38                 :            :   struct mt_queue *mq;
      39                 :            :   long n, nbint, last;
      40                 :            :   long pending;
      41                 :            :   pthread_cond_t pcond;
      42                 :            :   pthread_mutex_t pmut;
      43                 :            : };
      44                 :            : 
      45                 :            : static THREAD long mt_thread_no = -1;
      46                 :            : static struct mt_pstate *pari_mt;
      47                 :            : 
      48                 :            : #define LOCK(x) pthread_mutex_lock(x); do
      49                 :            : #define UNLOCK(x) while(0); pthread_mutex_unlock(x)
      50                 :            : 
      51                 :            : void
      52                 :   74938778 : mt_sigint_block(void)
      53                 :            : {
      54         [ +  + ]:   74938778 :   if (mt_thread_no>=0)
      55                 :    4121807 :     pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,NULL);
      56                 :   75632396 : }
      57                 :            : 
      58                 :            : void
      59                 :   75152653 : mt_sigint_unblock(void)
      60                 :            : {
      61         [ +  + ]:   75152653 :   if (mt_thread_no>=0)
      62                 :    4298384 :     pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL);
      63                 :   75738135 : }
      64                 :            : 
      65                 :            : void
      66                 :        986 : mt_err_recover(long er)
      67                 :            : {
      68                 :            :   (void) er;
      69         [ +  + ]:        986 :   if (mt_thread_no>=0)
      70                 :            :   {
      71                 :          2 :     struct mt_pstate *mt = pari_mt;
      72                 :          2 :     struct mt_queue *mq = mt->mq+mt_thread_no;
      73                 :          2 :     LOCK(mq->pmut)
      74                 :            :     {
      75                 :          2 :       mq->output = pari_err_last();
      76                 :          2 :       pthread_cond_signal(mq->pcond);
      77                 :          2 :     } UNLOCK(mq->pmut);
      78                 :          2 :     pthread_exit((void*)1);
      79                 :            :   }
      80                 :        984 : }
      81                 :            : 
      82                 :            : void
      83                 :          0 : mt_sigint(void)
      84                 :            : {
      85         [ #  # ]:          0 :   if (pari_mt) pthread_cond_broadcast(&pari_mt->pcond);
      86                 :          0 : }
      87                 :            : 
      88                 :            : int
      89                 :     189504 : mt_is_parallel(void)
      90                 :            : {
      91                 :     189504 :   return !!pari_mt;
      92                 :            : }
      93                 :            : 
      94                 :            : int
      95                 :   11085173 : mt_is_thread(void)
      96                 :            : {
      97                 :   11085173 :   return mt_thread_no>=0;
      98                 :            : }
      99                 :            : 
     100                 :          1 : void mt_broadcast(GEN code) {(void) code;}
     101                 :            : 
     102                 :        192 : void pari_mt_init(void)
     103                 :            : {
     104                 :        192 :   pari_mt = NULL;
     105                 :            : #ifdef _SC_NPROCESSORS_CONF
     106         [ +  - ]:        192 :   if (!pari_mt_nbthreads) pari_mt_nbthreads = sysconf(_SC_NPROCESSORS_CONF);
     107                 :            : #elif defined(_WIN32)
     108                 :            :   if (!pari_mt_nbthreads) pari_mt_nbthreads = win32_nbthreads();
     109                 :            : #else
     110                 :            :   pari_mt_nbthreads = 1;
     111                 :            : #endif
     112                 :        192 : }
     113                 :            : 
     114                 :        192 : void pari_mt_close(void) { }
     115                 :            : 
     116                 :            : static void*
     117                 :     178504 : mt_queue_run(void *arg)
     118                 :            : {
     119                 :     178504 :   GEN args = pari_thread_start((struct pari_thread*) arg);
     120                 :     192020 :   pari_sp av = avma;
     121                 :     192020 :   struct mt_queue *mq = (struct mt_queue *) args;
     122                 :     192020 :   mt_thread_no = mq->no;
     123                 :     192020 :   LOCK(mq->pmut)
     124                 :            :   {
     125                 :     193776 :     mq->avma = av;
     126                 :     193776 :     pthread_cond_signal(mq->pcond);
     127                 :     193776 :   } UNLOCK(mq->pmut);
     128                 :            :   for(;;)
     129                 :            :   {
     130                 :            :     GEN work, done;
     131                 :     247428 :     LOCK(&mq->mut)
     132                 :            :     {
     133         [ +  + ]:     300424 :       while(!mq->input)
     134                 :     246725 :         pthread_cond_wait(&mq->cond, &mq->mut);
     135                 :      53699 :     } UNLOCK(&mq->mut);
     136                 :      53710 :     avma = mq->avma;
     137                 :      53710 :     work = mq->input;
     138                 :      53710 :     pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL);
     139                 :      53738 :     done = closure_callgenvec(mq->worker,work);
     140                 :      53595 :     pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,NULL);
     141                 :      53680 :     LOCK(mq->pmut)
     142                 :            :     {
     143                 :      53694 :       mq->avma = av;
     144                 :      53694 :       mq->input = NULL;
     145                 :      53694 :       mq->output = done;
     146                 :      53694 :       pthread_cond_signal(mq->pcond);
     147                 :      53694 :     } UNLOCK(mq->pmut);
     148                 :      53691 :   }
     149                 :            : #ifdef __GNUC__
     150                 :            :   return NULL; /* NOT REACHED */
     151                 :            : #endif
     152                 :            : }
     153                 :            : 
     154                 :            : static long
     155                 :     115092 : mt_queue_check(struct mt_pstate *mt)
     156                 :            : {
     157                 :            :   long i;
     158         [ +  + ]:    1276664 :   for(i=0; i<mt->n; i++)
     159                 :            :   {
     160                 :    1215266 :     struct mt_queue *mq = mt->mq+i;
     161         [ +  + ]:    1215266 :     if (mq->output) return i;
     162                 :            :   }
     163                 :     115092 :   return -1;
     164                 :            : }
     165                 :            : 
     166                 :            : static GEN
     167                 :      96897 : mtpthread_queue_get(struct mt_state *junk, long *workid, long *pending)
     168                 :            : {
     169                 :      96897 :   struct mt_pstate *mt = pari_mt;
     170                 :            :   struct mt_queue *mq;
     171                 :      96897 :   GEN done = NULL;
     172                 :            :   long last;
     173                 :            :   (void) junk;
     174         [ +  + ]:      96897 :   if (mt->nbint<mt->n) { mt->last = mt->nbint; *pending = mt->pending; return NULL; }
     175         [ +  + ]:      53696 :   if ((last = mt_queue_check(mt)) < 0)
     176                 :            :   {
     177         [ +  - ]:      28831 :     BLOCK_SIGINT_START
     178                 :      28831 :     LOCK(&mt->pmut)
     179                 :            :     {
     180         [ +  + ]:      61396 :       while ((last = mt_queue_check(mt)) < 0)
     181                 :            :       {
     182                 :      32567 :         pthread_cond_wait(&mt->pcond, &mt->pmut);
     183         [ +  + ]:      32567 :         if (PARI_SIGINT_pending)
     184                 :            :         {
     185                 :          2 :           int sig = PARI_SIGINT_pending;
     186                 :          2 :           PARI_SIGINT_pending = 0;
     187                 :          2 :           pthread_mutex_unlock(&mt->pmut);
     188                 :          2 :           PARI_SIGINT_block = 0;
     189                 :          2 :           raise(sig);
     190                 :          0 :           PARI_SIGINT_block = 1;
     191                 :          0 :           pthread_mutex_lock(&mt->pmut);
     192                 :            :         }
     193                 :            :       }
     194                 :      28829 :     } UNLOCK(&mt->pmut);
     195 [ +  - ][ +  - ]:      28829 :     BLOCK_SIGINT_END
                 [ -  + ]
     196                 :            :   }
     197                 :      53694 :   mq = mt->mq+last;
     198         [ -  + ]:      53694 :   if (mq->output==err_e_STACK) pari_err(e_STACKTHREAD);
     199                 :      53694 :   done = gcopy(mq->output);
     200                 :      53694 :   mq->output = NULL;
     201         [ +  + ]:      53694 :   if (workid) *workid = mq->workid;
     202         [ +  + ]:      53694 :   if (typ(done)==t_ERROR) pari_err(0,done);
     203                 :      53692 :   mt->last = last;
     204                 :      53692 :   mt->pending--;
     205                 :      53692 :   *pending = mt->pending;
     206                 :      96893 :   return done;
     207                 :            : }
     208                 :            : 
     209                 :            : static void
     210                 :      96897 : mtpthread_queue_submit(struct mt_state *junk, long workid, GEN work)
     211                 :            : {
     212                 :      96897 :   struct mt_pstate *mt = pari_mt;
     213                 :      96897 :   struct mt_queue *mq = mt->mq+mt->last;
     214                 :            :   (void) junk;
     215         [ +  + ]:     150641 :   if (!work) { mt->nbint=mt->n; return; }
     216         [ +  - ]:      53744 :   BLOCK_SIGINT_START
     217         [ +  + ]:      53744 :   if (mt->nbint<mt->n)
     218                 :            :   {
     219                 :      43521 :     mt->nbint++;
     220         [ +  + ]:      43521 :     if (!mq->avma)
     221                 :            :     {
     222                 :      13331 :       LOCK(mq->pmut)
     223                 :            :       {
     224         [ +  + ]:      76111 :         while(!mq->avma)
     225                 :      62780 :           pthread_cond_wait(mq->pcond, mq->pmut);
     226                 :      13331 :       } UNLOCK(mq->pmut);
     227                 :            :     }
     228                 :            :   }
     229                 :      53744 :   LOCK(&mq->mut)
     230                 :            :   {
     231                 :      53744 :     mq->output = NULL;
     232                 :      53744 :     mq->workid = workid;
     233                 :      53744 :     mq->input = gcopy_avma(work, &mq->avma);
     234                 :      53744 :     pthread_cond_signal(&mq->cond);
     235                 :      53744 :   } UNLOCK(&mq->mut);
     236                 :      53744 :   mt->pending++;
     237 [ +  - ][ +  - ]:      53744 :   BLOCK_SIGINT_END
                 [ -  + ]
     238                 :            : }
     239                 :            : 
     240                 :            : void
     241                 :      12111 : mt_queue_reset(void)
     242                 :            : {
     243                 :      12111 :   struct mt_pstate *mt = pari_mt;
     244                 :            :   long i;
     245         [ +  + ]:     205887 :   for (i=0; i<mt->n; i++)
     246                 :     193776 :     pthread_cancel(mt->th[i]);
     247         [ +  + ]:     205887 :   for (i=0; i<mt->n; i++)
     248                 :     193776 :     pthread_join(mt->th[i],NULL);
     249         [ -  + ]:      12111 :   if (DEBUGLEVEL) pari_warn(warner,"stop threads");
     250                 :      12111 :   pari_mt = NULL;
     251         [ +  + ]:     205887 :   for (i=0;i<mt->n;i++)
     252                 :            :   {
     253                 :     193776 :     struct mt_queue *mq = mt->mq+i;
     254                 :     193776 :     pthread_cond_destroy(&mq->cond);
     255                 :     193776 :     pthread_mutex_destroy(&mq->mut);
     256                 :     193776 :     pari_thread_free(&mt->pth[i]);
     257                 :            :   }
     258                 :      12111 :   pari_free(mt->mq);
     259                 :      12111 :   pari_free(mt->pth);
     260                 :      12111 :   pari_free(mt->th);
     261                 :      12111 :   pari_free(mt);
     262                 :      12111 : }
     263                 :            : 
     264                 :            : void
     265                 :      12111 : mt_queue_start(struct pari_mt *pt, GEN worker)
     266                 :            : {
     267         [ -  + ]:      12111 :   if (pari_mt)
     268                 :          0 :     mtsingle_queue_start(pt, worker);
     269                 :            :   else
     270                 :            :   {
     271                 :      12111 :     long NBT = pari_mt_nbthreads;
     272                 :      12111 :     struct mt_pstate *mt =
     273                 :            :            (struct mt_pstate*) pari_malloc(sizeof(struct mt_pstate));
     274         [ -  + ]:      12111 :     long mtparisize = GP_DATA->threadsize? GP_DATA->threadsize: pari_mainstack->rsize;
     275                 :      12111 :     long mtparisizemax = GP_DATA->threadsizemax;
     276                 :            :     long i;
     277                 :      12111 :     mt->mq  = (struct mt_queue *) pari_malloc(sizeof(*mt->mq)*NBT);
     278                 :      12111 :     mt->th  = (pthread_t *) pari_malloc(sizeof(*mt->th)*NBT);
     279                 :      12111 :     mt->pth = (struct pari_thread *) pari_malloc(sizeof(*mt->pth)*NBT);
     280                 :      12111 :     mt->pending = 0;
     281                 :      12111 :     mt->n = NBT;
     282                 :      12111 :     mt->nbint = 0;
     283                 :      12111 :     mt->last = 0;
     284                 :      12111 :     pari_mt = mt;
     285                 :      12111 :     pthread_cond_init(&mt->pcond,NULL);
     286                 :      12111 :     pthread_mutex_init(&mt->pmut,NULL);
     287         [ +  + ]:     205887 :     for (i=0;i<NBT;i++)
     288                 :            :     {
     289                 :     193776 :       struct mt_queue *mq = mt->mq+i;
     290                 :     193776 :       mq->no     = i;
     291                 :     193776 :       mq->avma   = 0;
     292                 :     193776 :       mq->worker = worker;
     293                 :     193776 :       mq->input  = NULL;
     294                 :     193776 :       mq->output = NULL;
     295                 :     193776 :       mq->pcond  = &mt->pcond;
     296                 :     193776 :       mq->pmut   = &mt->pmut;
     297                 :     193776 :       pthread_cond_init(&mq->cond,NULL);
     298                 :     193776 :       pthread_mutex_init(&mq->mut,NULL);
     299         [ -  + ]:     193776 :       if (mtparisizemax)
     300                 :          0 :         pari_thread_valloc(&mt->pth[i],mtparisize,mtparisizemax,(GEN)mq);
     301                 :            :       else
     302                 :     193776 :         pari_thread_alloc(&mt->pth[i],mtparisize,(GEN)mq);
     303                 :            :     }
     304         [ -  + ]:      12111 :     if (DEBUGLEVEL) pari_warn(warner,"start threads");
     305         [ +  + ]:     205887 :     for (i=0;i<NBT;i++)
     306                 :     193776 :       pthread_create(&mt->th[i],NULL, &mt_queue_run, (void*)&mt->pth[i]);
     307                 :      12111 :     pt->get=&mtpthread_queue_get;
     308                 :      12111 :     pt->submit=&mtpthread_queue_submit;
     309                 :      12111 :     pt->end=&mt_queue_reset;
     310                 :            :   }
     311                 :      12111 : }

Generated by: LCOV version 1.9