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.10.0 lcov report (development 20924-e159ed0) Lines: 185 192 96.4 %
Date: 2017-08-21 06:23:16 Functions: 14 16 87.5 %
Legend: Lines: hit not hit

          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             :   struct pari_mainstack *mainstack;
      26             :   GEN input, output;
      27             :   GEN worker;
      28             :   long workid;
      29             :   pthread_cond_t cond;
      30             :   pthread_mutex_t mut;
      31             :   pthread_cond_t *pcond;
      32             :   pthread_mutex_t *pmut;
      33             : };
      34             : 
      35             : struct mt_pstate
      36             : {
      37             :   pthread_t *th;
      38             :   struct pari_thread *pth;
      39             :   struct mt_queue *mq;
      40             :   long n, nbint, last;
      41             :   long pending;
      42             :   pthread_cond_t pcond;
      43             :   pthread_mutex_t pmut;
      44             : };
      45             : 
      46             : static THREAD long mt_thread_no = -1;
      47             : static struct mt_pstate *pari_mt;
      48             : 
      49             : #define LOCK(x) pthread_mutex_lock(x); do
      50             : #define UNLOCK(x) while(0); pthread_mutex_unlock(x)
      51             : 
      52             : void
      53    96307127 : mt_sigint_block(void)
      54             : {
      55    96307127 :   if (mt_thread_no>=0)
      56     4632672 :     pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,NULL);
      57    97205763 : }
      58             : 
      59             : void
      60    96748306 : mt_sigint_unblock(void)
      61             : {
      62    96748306 :   if (mt_thread_no>=0)
      63     5037610 :     pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL);
      64    97359496 : }
      65             : 
      66             : void
      67        1118 : mt_err_recover(long er)
      68             : {
      69             :   (void) er;
      70        1118 :   if (mt_thread_no>=0)
      71             :   {
      72           2 :     struct mt_pstate *mt = pari_mt;
      73           2 :     struct mt_queue *mq = mt->mq+mt_thread_no;
      74           2 :     GEN err = bin_copy(copy_bin(pari_err_last()));
      75           2 :     LOCK(mq->pmut)
      76             :     {
      77           2 :       mq->output = err;
      78           2 :       pthread_cond_signal(mq->pcond);
      79           2 :     } UNLOCK(mq->pmut);
      80           2 :     pthread_exit((void*)1);
      81             :   }
      82        1116 : }
      83             : 
      84             : void
      85           0 : mt_sigint(void)
      86             : {
      87           0 :   if (pari_mt) pthread_cond_broadcast(&pari_mt->pcond);
      88           0 : }
      89             : 
      90             : int
      91      191481 : mt_is_parallel(void)
      92             : {
      93      191481 :   return !!pari_mt;
      94             : }
      95             : 
      96             : int
      97    14270120 : mt_is_thread(void)
      98             : {
      99    14270120 :   return mt_thread_no>=0;
     100             : }
     101             : 
     102           0 : void mt_broadcast(GEN code) {(void) code;}
     103             : 
     104         210 : void pari_mt_init(void)
     105             : {
     106         210 :   pari_mt = NULL;
     107             : #ifdef _SC_NPROCESSORS_CONF
     108         210 :   if (!pari_mt_nbthreads) pari_mt_nbthreads = sysconf(_SC_NPROCESSORS_CONF);
     109             : #elif defined(_WIN32)
     110             :   if (!pari_mt_nbthreads) pari_mt_nbthreads = win32_nbthreads();
     111             : #else
     112             :   pari_mt_nbthreads = 1;
     113             : #endif
     114         210 : }
     115             : 
     116         210 : void pari_mt_close(void) { }
     117             : 
     118             : static void
     119       32359 : mt_queue_cleanup(void *arg)
     120             : {
     121             :   (void) arg;
     122       32359 :   pari_thread_close();
     123       32124 : }
     124             : 
     125             : static void*
     126       31788 : mt_queue_run(void *arg)
     127             : {
     128       31788 :   GEN args = pari_thread_start((struct pari_thread*) arg);
     129       32375 :   pari_sp av = avma;
     130       32375 :   struct mt_queue *mq = (struct mt_queue *) args;
     131       32375 :   mt_thread_no = mq->no;
     132       32375 :   pthread_cleanup_push(mt_queue_cleanup,NULL);
     133       32399 :   LOCK(mq->pmut)
     134             :   {
     135       32417 :     mq->mainstack = pari_mainstack;
     136       32417 :     mq->avma = av;
     137       32417 :     pthread_cond_signal(mq->pcond);
     138       32417 :   } UNLOCK(mq->pmut);
     139             :   for(;;)
     140             :   {
     141             :     GEN work, done;
     142      102737 :     LOCK(&mq->mut)
     143             :     {
     144      273601 :       while(!mq->input)
     145      101039 :         pthread_cond_wait(&mq->cond, &mq->mut);
     146       69889 :     } UNLOCK(&mq->mut);
     147       70278 :     pari_mainstack = mq->mainstack;
     148       70278 :     avma = mq->avma;
     149       70278 :     work = mq->input;
     150       70278 :     pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL);
     151       70274 :     done = closure_callgenvec(mq->worker,work);
     152       68923 :     pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,NULL);
     153       70006 :     LOCK(mq->pmut)
     154             :     {
     155       70369 :       mq->mainstack = pari_mainstack;
     156       70369 :       mq->avma = av;
     157       70369 :       mq->input = NULL;
     158       70369 :       mq->output = done;
     159       70369 :       pthread_cond_signal(mq->pcond);
     160       70369 :     } UNLOCK(mq->pmut);
     161       70321 :   }
     162             :   pthread_cleanup_pop(1);
     163             : #ifdef __GNUC__
     164             :   return NULL; /* LCOV_EXCL_LINE */
     165             : #endif
     166             : }
     167             : 
     168             : static long
     169      102066 : mt_queue_check(struct mt_pstate *mt)
     170             : {
     171             :   long i;
     172      863801 :   for(i=0; i<mt->n; i++)
     173             :   {
     174      832104 :     struct mt_queue *mq = mt->mq+i;
     175      832104 :     if (mq->output) return i;
     176             :   }
     177       31697 :   return -1;
     178             : }
     179             : 
     180             : static GEN
     181       97942 : mtpthread_queue_get(struct mt_state *junk, long *workid, long *pending)
     182             : {
     183       97942 :   struct mt_pstate *mt = pari_mt;
     184             :   struct mt_queue *mq;
     185       97942 :   GEN done = NULL;
     186             :   long last;
     187             :   (void) junk;
     188       97942 :   if (mt->nbint<mt->n)
     189             :   {
     190       27571 :     mt->last = mt->nbint;
     191       27571 :     *pending = mt->pending;
     192       27571 :     return NULL;
     193             :   }
     194       70371 :   BLOCK_SIGINT_START
     195       70371 :   LOCK(&mt->pmut)
     196             :   {
     197      172437 :     while ((last = mt_queue_check(mt)) < 0)
     198             :     {
     199       31697 :       pthread_cond_wait(&mt->pcond, &mt->pmut);
     200       31697 :       if (PARI_SIGINT_pending)
     201             :       {
     202           2 :         int sig = PARI_SIGINT_pending;
     203           2 :         PARI_SIGINT_pending = 0;
     204           2 :         pthread_mutex_unlock(&mt->pmut);
     205           2 :         PARI_SIGINT_block = 0;
     206           2 :         raise(sig);
     207           0 :         PARI_SIGINT_block = 1;
     208           0 :         pthread_mutex_lock(&mt->pmut);
     209             :       }
     210             :     }
     211       70369 :   } UNLOCK(&mt->pmut);
     212       70369 :   BLOCK_SIGINT_END
     213       70369 :   mq = mt->mq+last;
     214       70369 :   if (mq->output==err_e_STACK) pari_err(e_STACKTHREAD);
     215       70369 :   done = gcopy(mq->output);
     216       70369 :   mq->output = NULL;
     217       70369 :   if (workid) *workid = mq->workid;
     218       70369 :   if (typ(done)==t_ERROR) pari_err(0,done);
     219       70367 :   mt->last = last;
     220       70367 :   mt->pending--;
     221       70367 :   *pending = mt->pending;
     222       70367 :   return done;
     223             : }
     224             : 
     225             : static void
     226       97942 : mtpthread_queue_submit(struct mt_state *junk, long workid, GEN work)
     227             : {
     228       97942 :   struct mt_pstate *mt = pari_mt;
     229       97942 :   struct mt_queue *mq = mt->mq+mt->last;
     230             :   (void) junk;
     231      195884 :   if (!work) { mt->nbint=mt->n; return; }
     232       70419 :   BLOCK_SIGINT_START
     233       70419 :   if (mt->nbint<mt->n)
     234             :   {
     235       32135 :     mt->nbint++;
     236       32135 :     LOCK(mq->pmut)
     237             :     {
     238       90705 :       while(!mq->avma)
     239       26435 :         pthread_cond_wait(mq->pcond, mq->pmut);
     240       32135 :     } UNLOCK(mq->pmut);
     241             :   }
     242       70419 :   LOCK(&mq->mut)
     243             :   {
     244       70419 :     mq->output = NULL;
     245       70419 :     mq->workid = workid;
     246       70419 :     BLOCK_SIGINT_START
     247             :     {
     248       70419 :       pari_sp av = avma;
     249       70419 :       struct pari_mainstack *st = pari_mainstack;
     250       70419 :       pari_mainstack = mq->mainstack;
     251       70419 :       avma = mq->avma;
     252       70419 :       mq->input = gcopy(work);
     253       70419 :       mq->avma = avma;
     254       70419 :       mq->mainstack = pari_mainstack;
     255       70419 :       pari_mainstack = st;
     256       70419 :       avma = av;
     257             :     }
     258       70419 :     BLOCK_SIGINT_END
     259       70419 :     pthread_cond_signal(&mq->cond);
     260       70419 :   } UNLOCK(&mq->mut);
     261       70419 :   mt->pending++;
     262       70419 :   BLOCK_SIGINT_END
     263             : }
     264             : 
     265             : void
     266        4610 : mt_queue_reset(void)
     267             : {
     268        4610 :   struct mt_pstate *mt = pari_mt;
     269             :   long i;
     270        4610 :   BLOCK_SIGINT_START
     271       37027 :   for (i=0; i<mt->n; i++)
     272       32417 :     pthread_cancel(mt->th[i]);
     273       37027 :   for (i=0; i<mt->n; i++)
     274       32417 :     pthread_join(mt->th[i],NULL);
     275        4610 :   pari_mt = NULL;
     276        4610 :   BLOCK_SIGINT_END
     277        4610 :   if (DEBUGLEVEL) pari_warn(warner,"stop threads");
     278       37027 :   for (i=0;i<mt->n;i++)
     279             :   {
     280       32417 :     struct mt_queue *mq = mt->mq+i;
     281       32417 :     pthread_cond_destroy(&mq->cond);
     282       32417 :     pthread_mutex_destroy(&mq->mut);
     283       32417 :     pari_thread_free(&mt->pth[i]);
     284             :   }
     285        4610 :   pari_free(mt->mq);
     286        4610 :   pari_free(mt->pth);
     287        4610 :   pari_free(mt->th);
     288        4610 :   pari_free(mt);
     289        4610 : }
     290             : 
     291             : void
     292        5288 : mt_queue_start_lim(struct pari_mt *pt, GEN worker, long lim)
     293             : {
     294        5288 :   if (lim==0) lim = pari_mt_nbthreads;
     295        5229 :   else        lim = minss(pari_mt_nbthreads, lim);
     296        5288 :   if (pari_mt || lim <= 1)
     297         678 :     mtsingle_queue_start(pt, worker);
     298             :   else
     299             :   {
     300        4610 :     struct mt_pstate *mt =
     301             :            (struct mt_pstate*) pari_malloc(sizeof(struct mt_pstate));
     302        4610 :     long mtparisize = GP_DATA->threadsize? GP_DATA->threadsize: pari_mainstack->rsize;
     303        4610 :     long mtparisizemax = GP_DATA->threadsizemax;
     304             :     long i;
     305        4610 :     mt->mq  = (struct mt_queue *) pari_malloc(sizeof(*mt->mq)*lim);
     306        4610 :     mt->th  = (pthread_t *) pari_malloc(sizeof(*mt->th)*lim);
     307        4610 :     mt->pth = (struct pari_thread *) pari_malloc(sizeof(*mt->pth)*lim);
     308        4610 :     mt->pending = 0;
     309        4610 :     mt->n = lim;
     310        4610 :     mt->nbint = 0;
     311        4610 :     mt->last = 0;
     312        4610 :     pthread_cond_init(&mt->pcond,NULL);
     313        4610 :     pthread_mutex_init(&mt->pmut,NULL);
     314        4610 :     pari_thread_sync();
     315       37027 :     for (i=0;i<lim;i++)
     316             :     {
     317       32417 :       struct mt_queue *mq = mt->mq+i;
     318       32417 :       mq->no     = i;
     319       32417 :       mq->avma   = 0;
     320       32417 :       mq->mainstack = NULL;
     321       32417 :       mq->worker = worker;
     322       32417 :       mq->input  = NULL;
     323       32417 :       mq->output = NULL;
     324       32417 :       mq->pcond  = &mt->pcond;
     325       32417 :       mq->pmut   = &mt->pmut;
     326       32417 :       pthread_cond_init(&mq->cond,NULL);
     327       32417 :       pthread_mutex_init(&mq->mut,NULL);
     328       32417 :       if (mtparisizemax)
     329           0 :         pari_thread_valloc(&mt->pth[i],mtparisize,mtparisizemax,(GEN)mq);
     330             :       else
     331       32417 :         pari_thread_alloc(&mt->pth[i],mtparisize,(GEN)mq);
     332             :     }
     333        4610 :     if (DEBUGLEVEL) pari_warn(warner,"start threads");
     334        4610 :     BLOCK_SIGINT_START
     335       37027 :     for (i=0;i<lim;i++)
     336       32417 :       pthread_create(&mt->th[i],NULL, &mt_queue_run, (void*)&mt->pth[i]);
     337        4610 :     pari_mt = mt;
     338        4610 :     BLOCK_SIGINT_END
     339        4610 :     pt->get=&mtpthread_queue_get;
     340        4610 :     pt->submit=&mtpthread_queue_submit;
     341        4610 :     pt->end=&mt_queue_reset;
     342             :   }
     343        5288 : }

Generated by: LCOV version 1.11