FORM v5.0.1-23-g7a8f756
threads.c
Go to the documentation of this file.
1
22/* #[ License : */
23/*
24 * Copyright (C) 1984-2026 J.A.M. Vermaseren
25 * When using this file you are requested to refer to the publication
26 * J.A.M.Vermaseren "New features of FORM" math-ph/0010025
27 * This is considered a matter of courtesy as the development was paid
28 * for by FOM the Dutch physics granting agency and we would like to
29 * be able to track its scientific use to convince FOM of its value
30 * for the community.
31 *
32 * This file is part of FORM.
33 *
34 * FORM is free software: you can redistribute it and/or modify it under the
35 * terms of the GNU General Public License as published by the Free Software
36 * Foundation, either version 3 of the License, or (at your option) any later
37 * version.
38 *
39 * FORM is distributed in the hope that it will be useful, but WITHOUT ANY
40 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
41 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
42 * details.
43 *
44 * You should have received a copy of the GNU General Public License along
45 * with FORM. If not, see <http://www.gnu.org/licenses/>.
46 */
47/* #] License : */
48
49#ifdef WITHPTHREADS
50
51#define WHOLEBRACKETS
52/*
53 #[ Variables :
54
55 The sortbot additions are from 17-may-2007 and after. They constitute
56 an attempt to make the final merge sorting faster for the master.
57 This way the master has only one compare per term.
58 It does add some complexity, but the final merge routine (MasterMerge)
59 is much simpler for the sortbots. On the other hand the original merging is
60 for a large part a copy of the MergePatches routine in sort.c and hence
61 even though complex the bad part has been thoroughly debugged.
62*/
63
64#include "form3.h"
65#include <math.h>
66
67#ifdef WITH_ALARM
68// This is only required if we are blocking SIG_ALRM in the worker threads.
69#include <signal.h>
70#endif
71
72#ifdef WITHFLOAT
73#include <gmp.h>
74
75int PackFloat(WORD *,mpf_t);
76int UnpackFloat(mpf_t, WORD *);
77void RatToFloat(mpf_t result, UWORD *formrat, int ratsize);
78#endif
79
80static int numberofthreads;
81static int numberofworkers;
82static int identityofthreads = 0;
83static int *listofavailables;
84static int topofavailables = 0;
85static pthread_key_t identitykey;
86static INILOCK(numberofthreadslock)
87static INILOCK(availabilitylock)
88static pthread_t *threadpointers = 0;
89static pthread_mutex_t *wakeuplocks;
90static pthread_mutex_t *wakeupmasterthreadlocks;
91static pthread_cond_t *wakeupconditions;
92static pthread_condattr_t *wakeupconditionattributes;
93static int *wakeup;
94static int *wakeupmasterthread;
95static INILOCK(wakeupmasterlock)
96static pthread_cond_t wakeupmasterconditions = PTHREAD_COND_INITIALIZER;
97static pthread_cond_t *wakeupmasterthreadconditions;
98static int wakeupmaster = 0;
99static int identityretval;
100/* static INILOCK(clearclocklock) */
101static LONG *timerinfo;
102static LONG *sumtimerinfo;
103static int numberclaimed;
104
105static THREADBUCKET **threadbuckets, **freebuckets;
106static int numthreadbuckets;
107static int numberoffullbuckets;
108
109/* static int numberbusy = 0; */
110
111INILOCK(dummylock)
112INIRWLOCK(dummyrwlock)
113static pthread_cond_t dummywakeupcondition = PTHREAD_COND_INITIALIZER;
114
115#ifdef WITHSORTBOTS
116static POSITION SortBotPosition;
117static int numberofsortbots;
118static INILOCK(wakeupsortbotlock)
119static pthread_cond_t wakeupsortbotconditions = PTHREAD_COND_INITIALIZER;
120static int topsortbotavailables = 0;
121static LONG numberofterms;
122#endif
123
124/*
125 #] Variables :
126 #[ Identity :
127 #[ StartIdentity :
128*/
134void StartIdentity(void)
135{
136 pthread_key_create(&identitykey,FinishIdentity);
137}
138
139/*
140 #] StartIdentity :
141 #[ FinishIdentity :
142*/
147void FinishIdentity(void *keyp)
148{
149 DUMMYUSE(keyp);
150/* free(keyp); */
151}
152
153/*
154 #] FinishIdentity :
155 #[ SetIdentity :
156*/
161int SetIdentity(int *identityretval)
162{
163/*
164#ifdef _MSC_VER
165 printf("addr %d\n",&numberofthreadslock);
166 printf("size %d\n",sizeof(numberofthreadslock));
167#endif
168*/
169 LOCK(numberofthreadslock);
170 *identityretval = identityofthreads++;
171 UNLOCK(numberofthreadslock);
172 pthread_setspecific(identitykey,(void *)identityretval);
173 return(*identityretval);
174}
175
176/*
177 #] SetIdentity :
178 #[ WhoAmI :
179*/
180
191int WhoAmI(void)
192{
193 int *identity;
194/*
195 First a fast exit for when there is at most one thread
196*/
197 if ( identityofthreads <= 1 ) return(0);
198/*
199 Now the reading of the key.
200 According to the book the statement should read:
201
202 pthread_getspecific(identitykey,(void **)(&identity));
203
204 but according to the information in pthread.h it is:
205*/
206 identity = (int *)pthread_getspecific(identitykey);
207 return(*identity);
208}
209
210/*
211 #] WhoAmI :
212 #[ BeginIdentities :
213*/
219void BeginIdentities(void)
220{
221 StartIdentity();
222 SetIdentity(&identityretval);
223}
224
225/*
226 #] BeginIdentities :
227 #] Identity :
228 #[ StartHandleLock :
229*/
236void StartHandleLock(void)
237{
238 AM.handlelock = dummyrwlock;
239}
240
241/*
242 #] StartHandleLock :
243 #[ StartAllThreads :
244*/
262int StartAllThreads(int number)
263{
264 int identity, j, dummy, mul;
265 ALLPRIVATES *B;
266 pthread_t thethread;
267 identity = WhoAmI();
268
269#ifdef WITHSORTBOTS
270 timerinfo = (LONG *)Malloc1(sizeof(LONG)*number*2,"timerinfo");
271 sumtimerinfo = (LONG *)Malloc1(sizeof(LONG)*number*2,"sumtimerinfo");
272 for ( j = 0; j < number*2; j++ ) { timerinfo[j] = 0; sumtimerinfo[j] = 0; }
273 mul = 2;
274#else
275 timerinfo = (LONG *)Malloc1(sizeof(LONG)*number,"timerinfo");
276 sumtimerinfo = (LONG *)Malloc1(sizeof(LONG)*number,"sumtimerinfo");
277 for ( j = 0; j < number; j++ ) { timerinfo[j] = 0; sumtimerinfo[j] = 0; }
278 mul = 1;
279#endif
280
281 listofavailables = (int *)Malloc1(sizeof(int)*(number+1),"listofavailables");
282 threadpointers = (pthread_t *)Malloc1(sizeof(pthread_t)*number*mul,"threadpointers");
283 AB = (ALLPRIVATES **)Malloc1(sizeof(ALLPRIVATES *)*number*mul,"Private structs");
284
285 wakeup = (int *)Malloc1(sizeof(int)*number*mul,"wakeup");
286 wakeuplocks = (pthread_mutex_t *)Malloc1(sizeof(pthread_mutex_t)*number*mul,"wakeuplocks");
287 wakeupconditions = (pthread_cond_t *)Malloc1(sizeof(pthread_cond_t)*number*mul,"wakeupconditions");
288 wakeupconditionattributes = (pthread_condattr_t *)
289 Malloc1(sizeof(pthread_condattr_t)*number*mul,"wakeupconditionattributes");
290
291 wakeupmasterthread = (int *)Malloc1(sizeof(int)*number*mul,"wakeupmasterthread");
292 wakeupmasterthreadlocks = (pthread_mutex_t *)Malloc1(sizeof(pthread_mutex_t)*number*mul,"wakeupmasterthreadlocks");
293 wakeupmasterthreadconditions = (pthread_cond_t *)Malloc1(sizeof(pthread_cond_t)*number*mul,"wakeupmasterthread");
294
295 numberofthreads = number;
296 numberofworkers = number - 1;
297 threadpointers[identity] = pthread_self();
298 topofavailables = 0;
299
300#ifdef WITH_ALARM
301 /* During thread creation, we block SIGALRM on the main thread. The created
302 threads will inherit this. This is required for #timeout to work properly
303 in TFORM: only the main thread should recieve SIGALRM. */
304 sigset_t sig_set;
305 sigemptyset(&sig_set);
306 sigaddset(&sig_set, SIGALRM);
307 pthread_sigmask(SIG_BLOCK, &sig_set, NULL);
308#endif
309
310 for ( j = 1; j < number; j++ ) {
311 if ( pthread_create(&thethread,NULL,RunThread,(void *)(&dummy)) )
312 goto failure;
313 }
314/*
315 Now we initialize the master at the same time that the workers are doing so.
316*/
317 B = InitializeOneThread(identity);
318 AR.infile = &(AR.Fscr[0]);
319 AR.outfile = &(AR.Fscr[1]);
320 AR.hidefile = &(AR.Fscr[2]);
321 AM.sbuflock = dummylock;
322 AS.inputslock = dummylock;
323 AS.outputslock = dummylock;
324 AS.MaxExprSizeLock = dummylock;
325 AP.PreVarLock = dummylock;
326 AC.halfmodlock = dummylock;
327 MakeThreadBuckets(number,0);
328/*
329 Now we wait for the workers to finish their startup.
330 We don't want to initialize the sortbots yet and run the risk that
331 some of them may end up with a lower number than one of the workers.
332*/
333 MasterWaitAll();
334#ifdef WITHSORTBOTS
335 if ( numberofworkers > 2 ) {
336 numberofsortbots = numberofworkers-2;
337 for ( j = numberofworkers+1; j < 2*numberofworkers-1; j++ ) {
338 if ( pthread_create(&thethread,NULL,RunSortBot,(void *)(&dummy)) )
339 goto failure;
340 }
341 }
342 else {
343 numberofsortbots = 0;
344 }
345 MasterWaitAllSortBots();
346 DefineSortBotTree();
347#endif
348 IniSortBlocks(number-1);
349 AS.MasterSort = 0;
350 AM.storefilelock = dummylock;
351
352#ifdef WITH_ALARM
353 /* Now we allow the main thread to recieve SIGALRM again. */
354 pthread_sigmask(SIG_UNBLOCK, &sig_set, NULL);
355#endif
356
357/*
358MesPrint("AB = %x %x %x %d",AB[0],AB[1],AB[2], identityofthreads);
359*/
360 return(0);
361failure:
362 MesPrint("Cannot start %d threads",number);
363 Terminate(-1);
364 return(-1);
365}
366
367/*
368 #] StartAllThreads :
369 #[ InitializeOneThread :
370*/
374UBYTE *scratchname[] = { (UBYTE *)"scratchsize",
375 (UBYTE *)"scratchsize",
376 (UBYTE *)"hidesize" };
403ALLPRIVATES *InitializeOneThread(int identity)
404{
405 WORD *t, *ScratchBuf;
406 int i, j, bsize, *bp;
407 LONG ScratchSize[3], IOsize;
408 ALLPRIVATES *B;
409 UBYTE *s;
410
411 wakeup[identity] = 0;
412 wakeuplocks[identity] = dummylock;
413 pthread_condattr_init(&(wakeupconditionattributes[identity]));
414 pthread_condattr_setpshared(&(wakeupconditionattributes[identity]),PTHREAD_PROCESS_PRIVATE);
415 wakeupconditions[identity] = dummywakeupcondition;
416 pthread_cond_init(&(wakeupconditions[identity]),&(wakeupconditionattributes[identity]));
417 wakeupmasterthread[identity] = 0;
418 wakeupmasterthreadlocks[identity] = dummylock;
419 wakeupmasterthreadconditions[identity] = dummywakeupcondition;
420
421 bsize = sizeof(ALLPRIVATES);
422 bsize = (bsize+sizeof(int)-1)/sizeof(int);
423 B = (ALLPRIVATES *)Malloc1(sizeof(int)*bsize,"B struct");
424 for ( bp = (int *)B, j = 0; j < bsize; j++ ) *bp++ = 0;
425
426 AB[identity] = B;
427/*
428 12-jun-2007 JV:
429 For the timing one has to know a few things:
430 The POSIX standard is that there is only a single process ID and that
431 getrusage returns the time of all the threads together.
432 Under Linux there are two methods though: The older LinuxThreads and NPTL.
433 LinuxThreads gives each thread its own process id. This makes that we
434 can time the threads with getrusage, and hence this was done. Under NPTL
435 this has been 'corrected' and suddenly getruage doesn't work anymore the
436 way it used to. Now we need
437 clock_gettime(CLOCK_THREAD_CPUTIME_ID,&timing)
438 which is declared in <time.h> and we need -lrt extra in the link statement.
439 (this is at least the case on blade02 at DESY-Zeuthen).
440 See also the code in tools.c at the routine Timer.
441 We may still have to include more stuff there.
442*/
443 if ( identity > 0 ) TimeCPU(0);
444
445#ifdef WITHSORTBOTS
446
447 if ( identity > numberofworkers ) {
448/*
449 Some workspace is needed when we have a PolyFun and we have to add
450 two terms and the new result is going to be longer than the old result.
451*/
452 LONG length = AM.WorkSize*sizeof(WORD)/8+AM.MaxTer*2;
453 AT.WorkSpace = (WORD *)Malloc1(length,"WorkSpace");
454 AT.WorkTop = AT.WorkSpace + length/sizeof(WORD);
455 AT.WorkPointer = AT.WorkSpace;
456 AT.identity = identity;
457/*
458 The SB struct gets treated in IniSortBlocks.
459 The SortBotIn variables will be defined DefineSortBotTree.
460*/
461 if ( AN.SoScratC == 0 ) {
462 AN.SoScratC = (UWORD *)Malloc1(2*(AM.MaxTal+2)*sizeof(UWORD),"Scratch in SortBot");
463 }
464 AT.SS = (SORTING *)Malloc1(sizeof(SORTING),"dummy sort buffer");
465 AT.SS->PolyFlag = 0;
466
467 AT.comsym[0] = 8;
468 AT.comsym[1] = SYMBOL;
469 AT.comsym[2] = 4;
470 AT.comsym[3] = 0;
471 AT.comsym[4] = 1;
472 AT.comsym[5] = 1;
473 AT.comsym[6] = 1;
474 AT.comsym[7] = 3;
475 AT.comnum[0] = 4;
476 AT.comnum[1] = 1;
477 AT.comnum[2] = 1;
478 AT.comnum[3] = 3;
479 AT.comfun[0] = FUNHEAD+4;
480 AT.comfun[1] = FUNCTION;
481 AT.comfun[2] = FUNHEAD;
482 AT.comfun[3] = 0;
483#if FUNHEAD > 3
484 for ( i = 4; i <= FUNHEAD; i++ )
485 AT.comfun[i] = 0;
486#endif
487 AT.comfun[FUNHEAD+1] = 1;
488 AT.comfun[FUNHEAD+2] = 1;
489 AT.comfun[FUNHEAD+3] = 3;
490 AT.comind[0] = 7;
491 AT.comind[1] = INDEX;
492 AT.comind[2] = 3;
493 AT.comind[3] = 0;
494 AT.comind[4] = 1;
495 AT.comind[5] = 1;
496 AT.comind[6] = 3;
497
498 AT.inprimelist = -1;
499 AT.sizeprimelist = 0;
500 AT.primelist = 0;
501 AT.bracketinfo = 0;
502
503 AR.CompareRoutine = (COMPAREDUMMY)(&Compare1);
504
505 AR.sLevel = 0;
506 AR.wranfia = 0;
507 AR.wranfcall = 0;
508 AR.wranfnpair1 = NPAIR1;
509 AR.wranfnpair2 = NPAIR2;
510 AN.NumFunSorts = 5;
511 AN.MaxFunSorts = 5;
512 AN.SplitScratch = 0;
513 AN.SplitScratchSize = AN.InScratch = 0;
514 AN.SplitScratch1 = 0;
515 AN.SplitScratchSize1 = AN.InScratch1 = 0;
516
517 AN.FunSorts = (SORTING **)Malloc1((AN.NumFunSorts+1)*sizeof(SORTING *),"FunSort pointers");
518 for ( i = 0; i <= AN.NumFunSorts; i++ ) AN.FunSorts[i] = 0;
519 AN.FunSorts[0] = AT.S0 = AT.SS;
520 AN.idfunctionflag = 0;
521 AN.tryterm = 0;
522
523 return(B);
524 }
525 if ( identity == 0 && AN.SoScratC == 0 ) {
526 AN.SoScratC = (UWORD *)Malloc1(2*(AM.MaxTal+2)*sizeof(UWORD),"Scratch in SortBot");
527 }
528#endif
529 AR.CurDum = AM.IndDum;
530 for ( j = 0; j < 3; j++ ) {
531 if ( identity == 0 ) {
532 if ( j == 2 ) {
533 ScratchSize[j] = AM.HideSize;
534 }
535 else {
536 ScratchSize[j] = AM.ScratSize;
537 }
538 if ( ScratchSize[j] < 10*AM.MaxTer ) ScratchSize[j] = 10 * AM.MaxTer;
539 }
540 else {
541/*
542 ScratchSize[j] = AM.ScratSize / (numberofthreads-1);
543 ScratchSize[j] = ScratchSize[j] / 20;
544 if ( ScratchSize[j] < 10*AM.MaxTer ) ScratchSize[j] = 10 * AM.MaxTer;
545*/
546 if ( j == 1 ) ScratchSize[j] = AM.ThreadScratOutSize;
547 else ScratchSize[j] = AM.ThreadScratSize;
548 if ( ScratchSize[j] < 4*AM.MaxTer ) ScratchSize[j] = 4 * AM.MaxTer;
549 AR.Fscr[j].name = 0;
550 }
551 ScratchSize[j] = ( ScratchSize[j] + 255 ) / 256;
552 ScratchSize[j] = ScratchSize[j] * 256;
553 ScratchBuf = (WORD *)Malloc1(ScratchSize[j]*sizeof(WORD),(char *)(scratchname[j]));
554 AR.Fscr[j].POsize = ScratchSize[j] * sizeof(WORD);
555 AR.Fscr[j].POfull = AR.Fscr[j].POfill = AR.Fscr[j].PObuffer = ScratchBuf;
556 AR.Fscr[j].POstop = AR.Fscr[j].PObuffer + ScratchSize[j];
557 PUTZERO(AR.Fscr[j].POposition);
558 AR.Fscr[j].pthreadslock = dummylock;
559 AR.Fscr[j].wPOsize = AR.Fscr[j].POsize;
560 AR.Fscr[j].wPObuffer = AR.Fscr[j].PObuffer;
561 AR.Fscr[j].wPOfill = AR.Fscr[j].POfill;
562 AR.Fscr[j].wPOfull = AR.Fscr[j].POfull;
563 AR.Fscr[j].wPOstop = AR.Fscr[j].POstop;
564 }
565 AR.InInBuf = 0;
566 AR.InHiBuf = 0;
567 AR.Fscr[0].handle = -1;
568 AR.Fscr[1].handle = -1;
569 AR.Fscr[2].handle = -1;
570 AR.FoStage4[0].handle = -1;
571 AR.FoStage4[1].handle = -1;
572 IOsize = AM.S0->file.POsize;
573#ifdef WITHZLIB
574 AR.FoStage4[0].ziosize = IOsize;
575 AR.FoStage4[1].ziosize = IOsize;
576 AR.FoStage4[0].ziobuffer = 0;
577 AR.FoStage4[1].ziobuffer = 0;
578#endif
579 AR.FoStage4[0].POsize = ((IOsize+sizeof(WORD)-1)/sizeof(WORD))*sizeof(WORD);
580 AR.FoStage4[1].POsize = ((IOsize+sizeof(WORD)-1)/sizeof(WORD))*sizeof(WORD);
581
582 AR.hidefile = &(AR.Fscr[2]);
583 AR.StoreData.Handle = -1;
584 AR.SortType = AC.SortType;
585
586 AN.IndDum = AM.IndDum;
587
588 if ( identity > 0 ) {
589 s = (UBYTE *)(FG.fname); i = 0;
590 while ( *s ) { s++; i++; }
591 s = (UBYTE *)Malloc1(sizeof(char)*(i+12),"name for Fscr[0] file");
592 snprintf((char *)s,i+12,"%s.%d",FG.fname,identity);
593 s[i-3] = 's'; s[i-2] = 'c'; s[i-1] = '0';
594 AR.Fscr[0].name = (char *)s;
595 s = (UBYTE *)(FG.fname); i = 0;
596 while ( *s ) { s++; i++; }
597 s = (UBYTE *)Malloc1(sizeof(char)*(i+12),"name for Fscr[1] file");
598 snprintf((char *)s,i+12,"%s.%d",FG.fname,identity);
599 s[i-3] = 's'; s[i-2] = 'c'; s[i-1] = '1';
600 AR.Fscr[1].name = (char *)s;
601 }
602
603 AR.CompressBuffer = (WORD *)Malloc1((AM.CompressSize+10)*sizeof(WORD),"compresssize");
604 AR.ComprTop = AR.CompressBuffer + AM.CompressSize;
605 AR.CompareRoutine = (COMPAREDUMMY)(&Compare1);
606/*
607 Here we make all allocations for the struct AT
608 (which is AB[identity].T or B->T with B = AB+identity).
609*/
610 AT.WorkSpace = (WORD *)Malloc1(AM.WorkSize*sizeof(WORD),"WorkSpace");
611 AT.WorkTop = AT.WorkSpace + AM.WorkSize;
612 AT.WorkPointer = AT.WorkSpace;
613
614 AT.Nest = (NESTING)Malloc1((LONG)sizeof(struct NeStInG)*AM.maxFlevels,"functionlevels");
615 AT.NestStop = AT.Nest + AM.maxFlevels;
616 AT.NestPoin = AT.Nest;
617
618 AT.WildMask = (WORD *)Malloc1((LONG)AM.MaxWildcards*sizeof(WORD),"maxwildcards");
619
620 LOCK(availabilitylock);
621 AT.ebufnum = inicbufs(); /* Buffer for extras during execution */
622 AT.fbufnum = inicbufs(); /* Buffer for caching in factorization */
623 AT.allbufnum = inicbufs(); /* Buffer for id,all */
624 AT.aebufnum = inicbufs(); /* Buffer for id,all */
625 UNLOCK(availabilitylock);
626
627 AT.RepCount = (int *)Malloc1((LONG)((AM.RepMax+3)*sizeof(int)),"repeat buffers");
628 AN.RepPoint = AT.RepCount;
629 AN.polysortflag = 0;
630 AN.subsubveto = 0;
631 AN.tryterm = 0;
632 AT.RepTop = AT.RepCount + AM.RepMax;
633
634 AT.WildArgTaken = (WORD *)Malloc1((LONG)AC.WildcardBufferSize*sizeof(WORD)/2
635 ,"argument list names");
636 AT.WildcardBufferSize = AC.WildcardBufferSize;
637 AT.previousEfactor = 0;
638
639 AT.identity = identity;
640 AT.LoadBalancing = 0;
641/*
642 Still to do: the SS stuff.
643 the Fscr[3]
644 the FoStage4[2]
645*/
646 if ( AT.WorkSpace == 0 ||
647 AT.Nest == 0 ||
648 AT.WildMask == 0 ||
649 AT.RepCount == 0 ||
650 AT.WildArgTaken == 0 ) goto OnError;
651/*
652 And initializations
653*/
654 AT.comsym[0] = 8;
655 AT.comsym[1] = SYMBOL;
656 AT.comsym[2] = 4;
657 AT.comsym[3] = 0;
658 AT.comsym[4] = 1;
659 AT.comsym[5] = 1;
660 AT.comsym[6] = 1;
661 AT.comsym[7] = 3;
662 AT.comnum[0] = 4;
663 AT.comnum[1] = 1;
664 AT.comnum[2] = 1;
665 AT.comnum[3] = 3;
666 AT.comfun[0] = FUNHEAD+4;
667 AT.comfun[1] = FUNCTION;
668 AT.comfun[2] = FUNHEAD;
669 AT.comfun[3] = 0;
670#if FUNHEAD > 3
671 for ( i = 4; i <= FUNHEAD; i++ )
672 AT.comfun[i] = 0;
673#endif
674 AT.comfun[FUNHEAD+1] = 1;
675 AT.comfun[FUNHEAD+2] = 1;
676 AT.comfun[FUNHEAD+3] = 3;
677 AT.comind[0] = 7;
678 AT.comind[1] = INDEX;
679 AT.comind[2] = 3;
680 AT.comind[3] = 0;
681 AT.comind[4] = 1;
682 AT.comind[5] = 1;
683 AT.comind[6] = 3;
684 AT.locwildvalue[0] = SUBEXPRESSION;
685 AT.locwildvalue[1] = SUBEXPSIZE;
686 for ( i = 2; i < SUBEXPSIZE; i++ ) AT.locwildvalue[i] = 0;
687 AT.mulpat[0] = TYPEMULT;
688 AT.mulpat[1] = SUBEXPSIZE+3;
689 AT.mulpat[2] = 0;
690 AT.mulpat[3] = SUBEXPRESSION;
691 AT.mulpat[4] = SUBEXPSIZE;
692 AT.mulpat[5] = 0;
693 AT.mulpat[6] = 1;
694 for ( i = 7; i < SUBEXPSIZE+5; i++ ) AT.mulpat[i] = 0;
695 AT.proexp[0] = SUBEXPSIZE+4;
696 AT.proexp[1] = EXPRESSION;
697 AT.proexp[2] = SUBEXPSIZE;
698 AT.proexp[3] = -1;
699 AT.proexp[4] = 1;
700 for ( i = 5; i < SUBEXPSIZE+1; i++ ) AT.proexp[i] = 0;
701 AT.proexp[SUBEXPSIZE+1] = 1;
702 AT.proexp[SUBEXPSIZE+2] = 1;
703 AT.proexp[SUBEXPSIZE+3] = 3;
704 AT.proexp[SUBEXPSIZE+4] = 0;
705 AT.dummysubexp[0] = SUBEXPRESSION;
706 AT.dummysubexp[1] = SUBEXPSIZE+4;
707 for ( i = 2; i < SUBEXPSIZE; i++ ) AT.dummysubexp[i] = 0;
708 AT.dummysubexp[SUBEXPSIZE] = WILDDUMMY;
709 AT.dummysubexp[SUBEXPSIZE+1] = 4;
710 AT.dummysubexp[SUBEXPSIZE+2] = 0;
711 AT.dummysubexp[SUBEXPSIZE+3] = 0;
712
713 AT.MinVecArg[0] = 7+ARGHEAD;
714 AT.MinVecArg[ARGHEAD] = 7;
715 AT.MinVecArg[1+ARGHEAD] = INDEX;
716 AT.MinVecArg[2+ARGHEAD] = 3;
717 AT.MinVecArg[3+ARGHEAD] = 0;
718 AT.MinVecArg[4+ARGHEAD] = 1;
719 AT.MinVecArg[5+ARGHEAD] = 1;
720 AT.MinVecArg[6+ARGHEAD] = -3;
721 t = AT.FunArg;
722 *t++ = 4+ARGHEAD+FUNHEAD;
723 for ( i = 1; i < ARGHEAD; i++ ) *t++ = 0;
724 *t++ = 4+FUNHEAD;
725 *t++ = 0;
726 *t++ = FUNHEAD;
727 for ( i = 2; i < FUNHEAD; i++ ) *t++ = 0;
728 *t++ = 1; *t++ = 1; *t++ = 3;
729
730 AT.inprimelist = -1;
731 AT.sizeprimelist = 0;
732 AT.primelist = 0;
733 AT.nfac = AT.nBer = 0;
734 AT.factorials = 0;
735 AT.bernoullis = 0;
736 AR.wranfia = 0;
737 AR.wranfcall = 0;
738 AR.wranfnpair1 = NPAIR1;
739 AR.wranfnpair2 = NPAIR2;
740 AR.wranfseed = 0;
741
742 AT.NormData = Malloc1(sizeof(*(AT.NormData)), "NormData thread pointers");
743 AT.NormDataSize = 1;
744 AT.NormData[0] = AllocNormData();
745 AT.NormDepth = 0;
746
747 AN.SplitScratch = 0;
748 AN.SplitScratchSize = AN.InScratch = 0;
749 AN.SplitScratch1 = 0;
750 AN.SplitScratchSize1 = AN.InScratch1 = 0;
751/*
752 Now the sort buffers. They depend on which thread. The master
753 inherits the sortbuffer from AM.S0
754*/
755 if ( identity == 0 ) {
756 AT.S0 = AM.S0;
757 }
758 else {
759/*
760 For the moment we don't have special settings.
761 They may become costly in virtual memory.
762*/
763 AT.S0 = AllocSort(AM.S0->LargeSize*sizeof(WORD)/numberofworkers
764 ,AM.S0->SmallSize*sizeof(WORD)/numberofworkers
765 ,AM.S0->SmallEsize*sizeof(WORD)/numberofworkers
766 ,AM.S0->TermsInSmall
767 ,AM.S0->MaxPatches
768/* ,AM.S0->MaxPatches/numberofworkers */
769 ,AM.S0->MaxFpatches/numberofworkers
770 ,AM.S0->file.POsize
771 ,0);
772 }
773 AR.CompressPointer = AR.CompressBuffer;
774/*
775 Install the store caches (15-aug-2006 JV)
776*/
777 AT.StoreCache = AT.StoreCacheAlloc = 0;
778 if ( AM.NumStoreCaches > 0 ) {
779 STORECACHE sa, sb;
780 LONG size;
781 size = sizeof(struct StOrEcAcHe)+AM.SizeStoreCache;
782 size = ((size-1)/sizeof(size_t)+1)*sizeof(size_t);
783 AT.StoreCacheAlloc = (STORECACHE)Malloc1(size*AM.NumStoreCaches,"StoreCaches");
784 sa = AT.StoreCache = AT.StoreCacheAlloc;
785 for ( i = 0; i < AM.NumStoreCaches; i++ ) {
786 sb = (STORECACHE)(void *)((UBYTE *)sa+size);
787 if ( i == AM.NumStoreCaches-1 ) {
788 sa->next = 0;
789 }
790 else {
791 sa->next = sb;
792 }
793 SETBASEPOSITION(sa->position,-1);
794 SETBASEPOSITION(sa->toppos,-1);
795 sa = sb;
796 }
797 }
798
799 ReserveTempFiles(2);
800 return(B);
801OnError:;
802 MLOCK(ErrorMessageLock);
803 MesPrint("Error initializing thread %d",identity);
804 MUNLOCK(ErrorMessageLock);
805 Terminate(-1);
806 return(B);
807}
808
809/*
810 #] InitializeOneThread :
811 #[ FinalizeOneThread :
812*/
823void FinalizeOneThread(int identity)
824{
825 timerinfo[identity] = TimeCPU(1);
826}
827
828/*
829 #] FinalizeOneThread :
830 #[ ClearAllThreads :
831*/
838void ClearAllThreads(void)
839{
840 int i;
841 MasterWaitAll();
842 for ( i = 1; i <= numberofworkers; i++ ) {
843 WakeupThread(i,CLEARCLOCK);
844 }
845#ifdef WITHSORTBOTS
846 for ( i = numberofworkers+1; i <= numberofworkers+numberofsortbots; i++ ) {
847 WakeupThread(i,CLEARCLOCK);
848 }
849#endif
850}
851
852/*
853 #] ClearAllThreads :
854 #[ TerminateAllThreads :
855*/
862void TerminateAllThreads(void)
863{
864 int i;
865 for ( i = 1; i <= numberofworkers; i++ ) {
866 GetThread(i);
867 WakeupThread(i,TERMINATETHREAD);
868 }
869#ifdef WITHSORTBOTS
870 for ( i = numberofworkers+1; i <= numberofworkers+numberofsortbots; i++ ) {
871 WakeupThread(i,TERMINATETHREAD);
872 }
873#endif
874 for ( i = 1; i <= numberofworkers; i++ ) {
875 pthread_join(threadpointers[i],NULL);
876 }
877#ifdef WITHSORTBOTS
878 for ( i = numberofworkers+1; i <= numberofworkers+numberofsortbots; i++ ) {
879 pthread_join(threadpointers[i],NULL);
880 }
881#endif
882}
883
884/*
885 #] TerminateAllThreads :
886 #[ MakeThreadBuckets :
887*/
913int MakeThreadBuckets(int number, int par)
914{
915 int i;
916 LONG sizethreadbuckets;
917 THREADBUCKET *thr;
918
919 // Here we divide by 4, which has been the behaviour with the default
920 // AC.ThreadBucketSize for a long time.
921 // MAXTER is the default value of AM.MaxTer, in units of sizeof(WORD).
922 sizethreadbuckets = (AC.ThreadBucketSize*MAXTER)/4;
923 // Now we scale up the buffer logarithmically with the user AM.MaxTer.
924 // If we scale linearly, we end up with really enormous buffers here
925 // when AM.MaxTer is of the order of millions of WORDs.
926 float scale = 1.0;
927 if ( AM.MaxTer/sizeof(WORD) > MAXTER ) {
928 scale += log(((float)AM.MaxTer/sizeof(WORD))/MAXTER);
929 }
930 sizethreadbuckets = (LONG)((float)sizethreadbuckets*scale);
931 // Nonetheless, we must fit at least BUCKETMINTERMS terms in each bucket!
932 // So the buffer will eventually scale linearly with MaxTer anyway, but
933 // much less aggressively than the old code.
934 sizethreadbuckets = MaX((ULONG)sizethreadbuckets, BUCKETMINTERMS*AM.MaxTer/sizeof(WORD));
935
936 if ( par == 0 ) {
937 numthreadbuckets = 2*(number-1);
938 threadbuckets = (THREADBUCKET **)Malloc1(numthreadbuckets*sizeof(THREADBUCKET *),"threadbuckets");
939 freebuckets = (THREADBUCKET **)Malloc1(numthreadbuckets*sizeof(THREADBUCKET *),"freebuckets");
940 }
941 if ( par > 0 ) {
942 if ( sizethreadbuckets <= threadbuckets[0]->threadbuffersize ) return(0);
943 for ( i = 0; i < numthreadbuckets; i++ ) {
944 thr = threadbuckets[i];
945 M_free(thr->deferbuffer,"deferbuffer");
946 M_free(thr->threadbuffer,"threadbuffer");
947 M_free(thr->compressbuffer,"compressbuffer");
948 }
949 }
950 else {
951 for ( i = 0; i < numthreadbuckets; i++ ) {
952 threadbuckets[i] = (THREADBUCKET *)Malloc1(sizeof(THREADBUCKET),"threadbuckets");
953 threadbuckets[i]->lock = dummylock;
954 }
955 }
956 for ( i = 0; i < numthreadbuckets; i++ ) {
957 thr = threadbuckets[i];
958 thr->threadbuffersize = sizethreadbuckets;
959 // This buffer does not need to be so large, start it at MaxTer.
960 // We'll double it if necessary.
961 thr->compressbuffersize = AM.MaxTer/sizeof(WORD);
962 thr->free = BUCKETFREE;
963 thr->deferbuffer = (POSITION *)Malloc1((AC.ThreadBucketSize+1)*sizeof(POSITION),"deferbuffer");
964 thr->threadbuffer = (WORD *)Malloc1(sizethreadbuckets*sizeof(WORD),"threadbuffer");
965 thr->compressbuffer = (WORD *)Malloc1(thr->compressbuffersize*sizeof(WORD),"compressbuffer");
966 thr->busy = BUCKETPREPARINGTERM;
967 thr->usenum = thr->totnum = 0;
968 thr->type = BUCKETDOINGTERMS;
969 }
970 return(0);
971}
972
973/*
974 #] MakeThreadBuckets :
975 #[ GetTimerInfo :
976*/
977
983/* UNFINISHED_FEATURE_EXCL_START */
984int GetTimerInfo(LONG** ti,LONG** sti)
985{
986 *ti = timerinfo;
987 *sti = sumtimerinfo;
988#ifdef WITHSORTBOTS
989 return AM.totalnumberofthreads*2;
990#else
991 return AM.totalnumberofthreads;
992#endif
993}
994/* UNFINISHED_FEATURE_EXCL_STOP */
995/*
996 #] GetTimerInfo :
997 #[ WriteTimerInfo :
998*/
999
1004/* UNFINISHED_FEATURE_EXCL_START */
1005void WriteTimerInfo(LONG* ti,LONG* sti)
1006{
1007 int i;
1008#ifdef WITHSORTBOTS
1009 int max = AM.totalnumberofthreads*2;
1010#else
1011 int max = AM.totalnumberofthreads;
1012#endif
1013 for ( i=0; i<max; ++i ) {
1014 timerinfo[i] = ti[i];
1015 sumtimerinfo[i] = sti[i];
1016 }
1017}
1018/* UNFINISHED_FEATURE_EXCL_STOP */
1019/*
1020 #] WriteTimerInfo :
1021 #[ GetWorkerTimes :
1022*/
1028LONG GetWorkerTimes(void)
1029{
1030 LONG retval = 0;
1031 int i;
1032 for ( i = 1; i <= numberofworkers; i++ ) retval += timerinfo[i] + sumtimerinfo[i];
1033#ifdef WITHSORTBOTS
1034 for ( i = numberofworkers+1; i <= numberofworkers+numberofsortbots; i++ )
1035 retval += timerinfo[i] + sumtimerinfo[i];
1036#endif
1037 return(retval);
1038}
1039
1040/*
1041 #] GetWorkerTimes :
1042 #[ UpdateOneThread :
1043*/
1050int UpdateOneThread(int identity)
1051{
1052 ALLPRIVATES *B = AB[identity], *B0 = AB[0];
1053 AR.GetFile = AR0.GetFile;
1054 AR.KeptInHold = AR0.KeptInHold;
1055 AR.CurExpr = AR0.CurExpr;
1056 AR.SortType = AC.SortType;
1057 if ( AT.WildcardBufferSize < AC.WildcardBufferSize ) {
1058 M_free(AT.WildArgTaken,"argument list names");
1059 AT.WildcardBufferSize = AC.WildcardBufferSize;
1060 AT.WildArgTaken = (WORD *)Malloc1((LONG)AC.WildcardBufferSize*sizeof(WORD)/2
1061 ,"argument list names");
1062 if ( AT.WildArgTaken == 0 ) return(-1);
1063 }
1064 return(0);
1065}
1066
1067/*
1068 #] UpdateOneThread :
1069 #[ LoadOneThread :
1070*/
1084int LoadOneThread(int from, int identity, THREADBUCKET *thr, int par)
1085{
1086 WORD *t1, *t2;
1087 ALLPRIVATES *B = AB[identity], *B0 = AB[from];
1088
1089 AR.DefPosition = AR0.DefPosition;
1090 AR.NoCompress = AR0.NoCompress;
1091 AR.gzipCompress = AR0.gzipCompress;
1092 AR.BracketOn = AR0.BracketOn;
1093 AR.CurDum = AR0.CurDum;
1094 AR.DeferFlag = AR0.DeferFlag;
1095 AR.TePos = 0;
1096 AR.sLevel = AR0.sLevel;
1097 AR.Stage4Name = AR0.Stage4Name;
1098 AR.GetOneFile = AR0.GetOneFile;
1099 AR.PolyFun = AR0.PolyFun;
1100 AR.PolyFunInv = AR0.PolyFunInv;
1101 AR.PolyFunType = AR0.PolyFunType;
1102 AR.PolyFunExp = AR0.PolyFunExp;
1103 AR.PolyFunVar = AR0.PolyFunVar;
1104 AR.PolyFunPow = AR0.PolyFunPow;
1105 AR.Eside = AR0.Eside;
1106 AR.Cnumlhs = AR0.Cnumlhs;
1107/*
1108 AR.MaxBracket = AR0.MaxBracket;
1109
1110 The compressbuffer contents are mainly relevant for keep brackets
1111 We should do this only if there is a keep brackets statement
1112 We may however still need the compressbuffer for expressions in the rhs.
1113*/
1114 if ( par >= 1 ) {
1115/*
1116 We may not need this %%%%% 7-apr-2006
1117*/
1118 t1 = AR.CompressBuffer; t2 = AR0.CompressBuffer;
1119 while ( t2 < AR0.CompressPointer ) *t1++ = *t2++;
1120 AR.CompressPointer = t1;
1121
1122 }
1123 else {
1124 AR.CompressPointer = AR.CompressBuffer;
1125 }
1126 if ( AR.DeferFlag ) {
1127 if ( AR.infile->handle < 0 ) {
1128 AR.infile->POfill = AR0.infile->POfill;
1129 }
1130 else {
1131/*
1132 We have to set the value of POposition to something that will
1133 force a read in the first try.
1134*/
1135 AR.infile->POfull = AR.infile->POfill = AR.infile->PObuffer;
1136 }
1137 }
1138 if ( par == 0 ) {
1139 AN.threadbuck = thr;
1140 AN.ninterms = thr->firstterm;
1141 }
1142 else if ( par == 1 ) {
1143 WORD *tstop;
1144 t1 = thr->threadbuffer; tstop = t1 + *t1;
1145 t2 = AT.WorkPointer;
1146 while ( t1 < tstop ) *t2++ = *t1++;
1147 AN.ninterms = thr->firstterm;
1148 }
1149 AN.TeInFun = 0;
1150 AN.ncmod = AC.ncmod;
1151 AT.BrackBuf = AT0.BrackBuf;
1152 AT.bracketindexflag = AT0.bracketindexflag;
1153 AN.PolyFunTodo = 0;
1154/*
1155 The relevant variables and the term are in their place.
1156 There is nothing more to do.
1157*/
1158 return(0);
1159}
1160
1161/*
1162 #] LoadOneThread :
1163 #[ BalanceRunThread :
1164*/
1179/* UNFINISHED_FEATURE_EXCL_START */
1180int BalanceRunThread(PHEAD int identity, WORD *term, WORD level)
1181{
1182 GETBIDENTITY
1183 ALLPRIVATES *BB;
1184 WORD *t, *tt;
1185 int i, *ti, *tti;
1186
1187 LoadOneThread(AT.identity,identity,0,2);
1188/*
1189 Extra loading if needed. Quantities changed in Generator.
1190 Like the level that has to be passed.
1191*/
1192 BB = AB[identity];
1193 BB->R.level = level;
1194 BB->T.TMbuff = AT.TMbuff;
1195 ti = AT.RepCount; tti = BB->T.RepCount;
1196 i = AN.RepPoint - AT.RepCount;
1197 BB->N.RepPoint = BB->T.RepCount + i;
1198 for ( ; i >= 0; i-- ) tti[i] = ti[i];
1199
1200 t = term; i = *term;
1201 tt = BB->T.WorkSpace;
1202 NCOPY(tt,t,i);
1203 BB->T.WorkPointer = tt;
1204
1205 WakeupThread(identity,HIGHERLEVELGENERATION);
1206
1207 return(0);
1208}
1209/* UNFINISHED_FEATURE_EXCL_STOP */
1210/*
1211 #] BalanceRunThread :
1212 #[ SetWorkerFiles :
1213*/
1218void SetWorkerFiles(void)
1219{
1220 int id;
1221 ALLPRIVATES *B, *B0 = AB[0];
1222 for ( id = 1; id < AM.totalnumberofthreads; id++ ) {
1223 B = AB[id];
1224 AR.infile = &(AR.Fscr[0]);
1225 AR.outfile = &(AR.Fscr[1]);
1226 AR.hidefile = &(AR.Fscr[2]);
1227 AR.infile->handle = AR0.infile->handle;
1228 AR.hidefile->handle = AR0.hidefile->handle;
1229 if ( AR.infile->handle < 0 ) {
1230 AR.infile->PObuffer = AR0.infile->PObuffer;
1231 AR.infile->POstop = AR0.infile->POstop;
1232 AR.infile->POfill = AR0.infile->POfill;
1233 AR.infile->POfull = AR0.infile->POfull;
1234 AR.infile->POsize = AR0.infile->POsize;
1235 AR.InInBuf = AR0.InInBuf;
1236 AR.infile->POposition = AR0.infile->POposition;
1237 AR.infile->filesize = AR0.infile->filesize;
1238 }
1239 else {
1240 AR.infile->PObuffer = AR.infile->wPObuffer;
1241 AR.infile->POstop = AR.infile->wPOstop;
1242 AR.infile->POfill = AR.infile->wPOfill;
1243 AR.infile->POfull = AR.infile->wPOfull;
1244 AR.infile->POsize = AR.infile->wPOsize;
1245 AR.InInBuf = 0;
1246 PUTZERO(AR.infile->POposition);
1247 }
1248/*
1249 If there is some writing, it betters happens to ones own outfile.
1250 Currently this is to be done only for InParallel.
1251 Merging of the outputs is then done by the CopyExpression routine.
1252*/
1253 {
1254 AR.outfile->PObuffer = AR.outfile->wPObuffer;
1255 AR.outfile->POstop = AR.outfile->wPOstop;
1256 AR.outfile->POfill = AR.outfile->wPOfill;
1257 AR.outfile->POfull = AR.outfile->wPOfull;
1258 AR.outfile->POsize = AR.outfile->wPOsize;
1259 PUTZERO(AR.outfile->POposition);
1260 }
1261 if ( AR.hidefile->handle < 0 ) {
1262 AR.hidefile->PObuffer = AR0.hidefile->PObuffer;
1263 AR.hidefile->POstop = AR0.hidefile->POstop;
1264 AR.hidefile->POfill = AR0.hidefile->POfill;
1265 AR.hidefile->POfull = AR0.hidefile->POfull;
1266 AR.hidefile->POsize = AR0.hidefile->POsize;
1267 AR.InHiBuf = AR0.InHiBuf;
1268 AR.hidefile->POposition = AR0.hidefile->POposition;
1269 AR.hidefile->filesize = AR0.hidefile->filesize;
1270 }
1271 else {
1272 AR.hidefile->PObuffer = AR.hidefile->wPObuffer;
1273 AR.hidefile->POstop = AR.hidefile->wPOstop;
1274 AR.hidefile->POfill = AR.hidefile->wPOfill;
1275 AR.hidefile->POfull = AR.hidefile->wPOfull;
1276 AR.hidefile->POsize = AR.hidefile->wPOsize;
1277 AR.InHiBuf = 0;
1278 PUTZERO(AR.hidefile->POposition);
1279 }
1280 }
1281 if ( AR0.StoreData.dirtyflag ) {
1282 for ( id = 1; id < AM.totalnumberofthreads; id++ ) {
1283 B = AB[id];
1284 AR.StoreData = AR0.StoreData;
1285 }
1286 }
1287}
1288
1289/*
1290 #] SetWorkerFiles :
1291 #[ RunThread :
1292*/
1300void *RunThread(void *dummy)
1301{
1302 WORD *term, *ttin, *tt, *ttco, *oldwork;
1303 int identity, wakeupsignal, identityretv, i, tobereleased, errorcode;
1304 ALLPRIVATES *B;
1305 THREADBUCKET *thr;
1306 POSITION *ppdef;
1307 EXPRESSIONS e;
1308 DUMMYUSE(dummy);
1309 identity = SetIdentity(&identityretv);
1310 threadpointers[identity] = pthread_self();
1311 B = InitializeOneThread(identity);
1312 while ( ( wakeupsignal = ThreadWait(identity) ) > 0 ) {
1313 switch ( wakeupsignal ) {
1314/*
1315 #[ STARTNEWEXPRESSION :
1316*/
1317 case STARTNEWEXPRESSION:
1318/*
1319 Set up the sort routines etc.
1320 Start with getting some buffers synchronized with the compiler
1321*/
1322 if ( UpdateOneThread(identity) ) {
1323 MLOCK(ErrorMessageLock);
1324 MesPrint("Update error in starting expression in thread %d in module %d",identity,AC.CModule);
1325 MUNLOCK(ErrorMessageLock);
1326 Terminate(-1);
1327 }
1328 AR.DeferFlag = AC.ComDefer;
1329 AR.sLevel = AS.sLevel;
1330 AR.MaxDum = AM.IndDum;
1331 AR.expchanged = AB[0]->R.expchanged;
1332 AR.expflags = AB[0]->R.expflags;
1333 AR.PolyFun = AB[0]->R.PolyFun;
1334 AR.PolyFunInv = AB[0]->R.PolyFunInv;
1335 AR.PolyFunType = AB[0]->R.PolyFunType;
1336 AR.PolyFunExp = AB[0]->R.PolyFunExp;
1337 AR.PolyFunVar = AB[0]->R.PolyFunVar;
1338 AR.PolyFunPow = AB[0]->R.PolyFunPow;
1339/*
1340 Now fire up the sort buffer.
1341*/
1342 NewSort(BHEAD0);
1343 break;
1344/*
1345 #] STARTNEWEXPRESSION :
1346 #[ LOWESTLEVELGENERATION :
1347*/
1348 case LOWESTLEVELGENERATION:
1349#ifdef INNERTEST
1350 if ( AC.InnerTest ) {
1351 if ( StrCmp(AC.TestValue,(UBYTE *)INNERTEST) == 0 ) {
1352 MesPrint("Testing(Worker%d): value = %s",AT.identity,AC.TestValue);
1353 }
1354 }
1355#endif
1356 e = Expressions + AR.CurExpr;
1357 thr = AN.threadbuck;
1358 ppdef = thr->deferbuffer;
1359 ttin = thr->threadbuffer;
1360 ttco = thr->compressbuffer;
1361 term = AT.WorkPointer;
1362 thr->usenum = 0;
1363 tobereleased = 0;
1364 AN.inputnumber = thr->firstterm;
1365 AN.ninterms = thr->firstterm;
1366 do {
1367 thr->usenum++; /* For if the master wants to steal the bucket */
1368 tt = term; i = *ttin;
1369 NCOPY(tt,ttin,i);
1370 AT.WorkPointer = tt;
1371 if ( AR.DeferFlag ) {
1372 tt = AR.CompressBuffer; i = *ttco;
1373 NCOPY(tt,ttco,i);
1374 AR.CompressPointer = tt;
1375 AR.DefPosition = ppdef[0]; ppdef++;
1376 }
1377 if ( thr->free == BUCKETTERMINATED ) {
1378/*
1379 The next statement allows the master to steal the bucket
1380 for load balancing purposes. We do still execute the current
1381 term, but afterwards we drop out.
1382 Once we have written the release code, we cannot use this
1383 bucket anymore. Hence the exit to the label bucketstolen.
1384*/
1385 if ( thr->usenum == thr->totnum ) {
1386 thr->free = BUCKETCOMINGFREE;
1387 }
1388 else {
1389 thr->free = BUCKETRELEASED;
1390 tobereleased = 1;
1391 }
1392 }
1393/*
1394 What if we want to steal and we set thr->free while
1395 the thread is inside the next code for a long time?
1396 if ( AT.LoadBalancing ) {
1397*/
1398 LOCK(thr->lock);
1399 thr->busy = BUCKETDOINGTERM;
1400 UNLOCK(thr->lock);
1401/*
1402 }
1403 else {
1404 thr->busy = BUCKETDOINGTERM;
1405 }
1406*/
1407 AN.RepPoint = AT.RepCount + 1;
1408
1409 if ( ( e->vflags & ISFACTORIZED ) != 0 && term[1] == HAAKJE ) {
1410 StoreTerm(BHEAD term);
1411 }
1412 else {
1413 if ( AR.DeferFlag ) {
1414 AR.CurDum = AN.IndDum = Expressions[AR.CurExpr].numdummies + AM.IndDum;
1415 }
1416 else {
1417 AN.IndDum = AM.IndDum;
1418 AR.CurDum = ReNumber(BHEAD term);
1419 }
1420 if ( AC.SymChangeFlag ) MarkDirty(term,DIRTYSYMFLAG);
1421 if ( AN.ncmod ) {
1422 if ( ( AC.modmode & ALSOFUNARGS ) != 0 ) MarkDirty(term,DIRTYFLAG);
1423 else if ( AR.PolyFun ) PolyFunDirty(BHEAD term);
1424 }
1425 else if ( AC.PolyRatFunChanged ) PolyFunDirty(BHEAD term);
1426 if ( ( AP.PreDebug & THREADSDEBUG ) != 0 ) {
1427 MLOCK(ErrorMessageLock);
1428 MesPrint("Thread %w executing term:");
1429 PrintTerm(term,"LLG");
1430 MUNLOCK(ErrorMessageLock);
1431 }
1432 if ( ( AR.PolyFunType == 2 ) && ( AC.PolyRatFunChanged == 0 )
1433 && ( e->status == LOCALEXPRESSION || e->status == GLOBALEXPRESSION ) ) {
1434 PolyFunClean(BHEAD term);
1435 }
1436 if ( Generator(BHEAD term,0) ) {
1438 MLOCK(ErrorMessageLock);
1439 MesPrint("Error in processing one term in thread %d in module %d",identity,AC.CModule);
1440 MUNLOCK(ErrorMessageLock);
1441 Terminate(-1);
1442 }
1443 AN.ninterms++;
1444 }
1445/* if ( AT.LoadBalancing ) { */
1446 LOCK(thr->lock);
1447 thr->busy = BUCKETPREPARINGTERM;
1448 UNLOCK(thr->lock);
1449/*
1450 }
1451 else {
1452 thr->busy = BUCKETPREPARINGTERM;
1453 }
1454*/
1455 if ( thr->free == BUCKETTERMINATED ) {
1456 if ( thr->usenum == thr->totnum ) {
1457 thr->free = BUCKETCOMINGFREE;
1458 }
1459 else {
1460 thr->free = BUCKETRELEASED;
1461 tobereleased = 1;
1462 }
1463 }
1464 if ( tobereleased ) goto bucketstolen;
1465 } while ( *ttin );
1466 thr->free = BUCKETCOMINGFREE;
1467bucketstolen:;
1468/* if ( AT.LoadBalancing ) { */
1469 LOCK(thr->lock);
1470 thr->busy = BUCKETTOBERELEASED;
1471 UNLOCK(thr->lock);
1472/* }
1473 else {
1474 thr->busy = BUCKETTOBERELEASED;
1475 }
1476*/
1477 AT.WorkPointer = term;
1478 break;
1479/*
1480 #] LOWESTLEVELGENERATION :
1481 #[ FINISHEXPRESSION :
1482*/
1483#ifdef WITHSORTBOTS
1484 case CLAIMOUTPUT:
1485 LOCK(AT.SB.MasterBlockLock[1]);
1486 break;
1487#endif
1488 case FINISHEXPRESSION:
1489/*
1490 Finish the sort
1491
1492 Start with claiming the first block
1493 Once we have claimed it we can let the master know that
1494 everything is all right.
1495*/
1496 LOCK(AT.SB.MasterBlockLock[1]);
1497 ThreadClaimedBlock(identity);
1498/*
1499 Entry for when we work with sortbots
1500*/
1501#ifdef WITHSORTBOTS
1502 /* fall through */
1503 case FINISHEXPRESSION2:
1504#endif
1505/*
1506 Now we may need here an fsync on the sort file
1507*/
1508 if ( AC.ThreadSortFileSynch ) {
1509 if ( AT.S0->file.handle >= 0 ) {
1510 SynchFile(AT.S0->file.handle);
1511 }
1512 }
1513 AT.SB.FillBlock = 1;
1514 AT.SB.MasterFill[1] = AT.SB.MasterStart[1];
1515 errorcode = EndSort(BHEAD AT.S0->sBuffer,0);
1516 UNLOCK(AT.SB.MasterBlockLock[AT.SB.FillBlock]);
1517 UpdateMaxSize();
1518 if ( errorcode ) {
1519 MLOCK(ErrorMessageLock);
1520 MesPrint("Error terminating sort in thread %d in module %d",identity,AC.CModule);
1521 MUNLOCK(ErrorMessageLock);
1522 Terminate(-1);
1523 }
1524 break;
1525/*
1526 #] FINISHEXPRESSION :
1527 #[ CLEANUPEXPRESSION :
1528*/
1529 case CLEANUPEXPRESSION:
1530/*
1531 Cleanup everything and wait for the next expression
1532*/
1533 if ( AR.outfile->handle >= 0 ) {
1534 CloseFile(AR.outfile->handle);
1535 AR.outfile->handle = -1;
1536 remove(AR.outfile->name);
1537 AR.outfile->POfill = AR.outfile->POfull = AR.outfile->PObuffer;
1538 PUTZERO(AR.outfile->POposition);
1539 PUTZERO(AR.outfile->filesize);
1540 }
1541 else {
1542 AR.outfile->POfill = AR.outfile->POfull = AR.outfile->PObuffer;
1543 PUTZERO(AR.outfile->POposition);
1544 PUTZERO(AR.outfile->filesize);
1545 }
1546 {
1547 CBUF *C = cbuf+AT.ebufnum;
1548 WORD **w, ii;
1549 if ( C->numrhs > 0 || C->numlhs > 0 ) {
1550 if ( C->rhs ) {
1551 w = C->rhs; ii = C->numrhs;
1552 do { *w++ = 0; } while ( --ii > 0 );
1553 }
1554 if ( C->lhs ) {
1555 w = C->lhs; ii = C->numlhs;
1556 do { *w++ = 0; } while ( --ii > 0 );
1557 }
1558 C->numlhs = C->numrhs = 0;
1559 ClearTree(AT.ebufnum);
1560 C->Pointer = C->Buffer;
1561 }
1562 }
1563 break;
1564/*
1565 #] CLEANUPEXPRESSION :
1566 #[ HIGHERLEVELGENERATION :
1567*/
1568 case HIGHERLEVELGENERATION:
1569/*
1570 When foliating halfway the tree.
1571 This should only be needed in a second level load balancing
1572*/
1573 term = AT.WorkSpace; AT.WorkPointer = term + *term;
1574 if ( Generator(BHEAD term,AR.level) ) {
1576 MLOCK(ErrorMessageLock);
1577 MesPrint("Error in load balancing one term at level %d in thread %d in module %d",AR.level,AT.identity,AC.CModule);
1578 MUNLOCK(ErrorMessageLock);
1579 Terminate(-1);
1580 }
1581 AT.WorkPointer = term;
1582 break;
1583/*
1584 #] HIGHERLEVELGENERATION :
1585 #[ STARTNEWMODULE :
1586*/
1587 case STARTNEWMODULE:
1588/*
1589 For resetting variables.
1590*/
1591 SpecialCleanup(B);
1592 break;
1593/*
1594 #] STARTNEWMODULE :
1595 #[ TERMINATETHREAD :
1596*/
1597 case TERMINATETHREAD:
1598 goto EndOfThread;
1599/*
1600 #] TERMINATETHREAD :
1601 #[ DOONEEXPRESSION :
1602
1603 When a thread has to do a complete (not too big) expression.
1604 The number of the expression to be done is in AR.exprtodo.
1605 The code is mostly taken from Processor. The only difference
1606 is with what to do with the output.
1607 The output should go to the scratch buffer of the worker
1608 (which is free at the right moment). If this buffer is too
1609 small we have a problem. We could write to file or give the
1610 master what we have and from now on the master has to collect
1611 pieces until things are complete.
1612 Note: this assumes that the expressions don't keep their order.
1613 If they have to keep their order, don't use this feature.
1614*/
1615 case DOONEEXPRESSION: {
1616
1617 POSITION position, outposition;
1618 FILEHANDLE *fi, *fout, *oldoutfile;
1619 LONG dd = 0;
1620 WORD oldBracketOn = AR.BracketOn;
1621 WORD *oldBrackBuf = AT.BrackBuf;
1622 WORD oldbracketindexflag = AT.bracketindexflag;
1623 WORD fromspectator = 0;
1624 e = Expressions + AR.exprtodo;
1625 i = AR.exprtodo;
1626 AR.CurExpr = i;
1627 AR.SortType = AC.SortType;
1628 AR.expchanged = 0;
1629 if ( ( e->vflags & ISFACTORIZED ) != 0 ) {
1630 AR.BracketOn = 1;
1631 AT.BrackBuf = AM.BracketFactors;
1632 AT.bracketindexflag = 1;
1633 }
1634
1635 position = AS.OldOnFile[i];
1636 if ( e->status == HIDDENLEXPRESSION || e->status == HIDDENGEXPRESSION
1637 || e->status == UNHIDELEXPRESSION || e->status == UNHIDEGEXPRESSION ) {
1638 AR.GetFile = 2; fi = AR.hidefile;
1639 }
1640 else {
1641 AR.GetFile = 0; fi = AR.infile;
1642 }
1643/*
1644 PUTZERO(fi->POposition);
1645 if ( fi->handle >= 0 ) {
1646 fi->POfill = fi->POfull = fi->PObuffer;
1647 }
1648*/
1649 SetScratch(fi,&position);
1650 term = oldwork = AT.WorkPointer;
1651 AR.CompressPointer = AR.CompressBuffer;
1652 AR.CompressPointer[0] = 0;
1653 AR.KeptInHold = 0;
1654 if ( GetTerm(BHEAD term) <= 0 ) {
1655 MLOCK(ErrorMessageLock);
1656 MesPrint("Expression %d has problems in scratchfile (t)",i);
1657 MUNLOCK(ErrorMessageLock);
1658 Terminate(-1);
1659 }
1660 if ( AT.bracketindexflag > 0 ) OpenBracketIndex(i);
1661 term[3] = i;
1662 if ( term[5] < 0 ) {
1663 fromspectator = -term[5];
1664 PUTZERO(AM.SpectatorFiles[fromspectator-1].readpos);
1665 term[5] = AC.cbufnum;
1666 }
1667 PUTZERO(outposition);
1668 fout = AR.outfile;
1669 fout->POfill = fout->POfull = fout->PObuffer;
1670 fout->POposition = outposition;
1671 if ( fout->handle >= 0 ) {
1672 fout->POposition = outposition;
1673 }
1674/*
1675 The next statement is needed because we need the system
1676 to believe that the expression is at position zero for
1677 the moment. In this worker, with no memory of other expressions,
1678 it is. This is needed for when a bracket index is made
1679 because there e->onfile is an offset. Afterwards, when the
1680 expression is written to its final location in the masters
1681 output e->onfile will get its real value.
1682*/
1683 PUTZERO(e->onfile);
1684 if ( PutOut(BHEAD term,&outposition,fout,0) < 0 ) goto ProcErr;
1685
1686 AR.DeferFlag = AC.ComDefer;
1687
1688 AR.sLevel = AB[0]->R.sLevel;
1689 term = AT.WorkPointer;
1690 NewSort(BHEAD0);
1691 AR.MaxDum = AM.IndDum;
1692 AN.ninterms = 0;
1693 if ( fromspectator ) {
1694 while ( GetFromSpectator(term,fromspectator-1) ) {
1695 AT.WorkPointer = term + *term;
1696 AN.RepPoint = AT.RepCount + 1;
1697 AN.IndDum = AM.IndDum;
1698 AR.CurDum = ReNumber(BHEAD term);
1699 if ( AC.SymChangeFlag ) MarkDirty(term,DIRTYSYMFLAG);
1700 if ( AN.ncmod ) {
1701 if ( ( AC.modmode & ALSOFUNARGS ) != 0 ) MarkDirty(term,DIRTYFLAG);
1702 else if ( AR.PolyFun ) PolyFunDirty(BHEAD term);
1703 }
1704 else if ( AC.PolyRatFunChanged ) PolyFunDirty(BHEAD term);
1705 if ( ( AR.PolyFunType == 2 ) && ( AC.PolyRatFunChanged == 0 )
1706 && ( e->status == LOCALEXPRESSION || e->status == GLOBALEXPRESSION ) ) {
1707 PolyFunClean(BHEAD term);
1708 }
1709 if ( Generator(BHEAD term,0) ) {
1710 LowerSortLevel(); goto ProcErr;
1711 }
1712 }
1713 }
1714 else {
1715 while ( GetTerm(BHEAD term) ) {
1716 SeekScratch(fi,&position);
1717 AN.ninterms++; dd = AN.deferskipped;
1718 if ( ( e->vflags & ISFACTORIZED ) != 0 && term[1] == HAAKJE ) {
1719 StoreTerm(BHEAD term);
1720 }
1721 else {
1722 if ( AC.CollectFun && *term <= (AM.MaxTer/(2*(LONG)sizeof(WORD))) ) {
1723 if ( GetMoreTerms(term) < 0 ) {
1724 LowerSortLevel(); goto ProcErr;
1725 }
1726 SeekScratch(fi,&position);
1727 }
1728 AT.WorkPointer = term + *term;
1729 AN.RepPoint = AT.RepCount + 1;
1730 if ( AR.DeferFlag ) {
1731 AR.CurDum = AN.IndDum = Expressions[AR.exprtodo].numdummies;
1732 }
1733 else {
1734 AN.IndDum = AM.IndDum;
1735 AR.CurDum = ReNumber(BHEAD term);
1736 }
1737 if ( AC.SymChangeFlag ) MarkDirty(term,DIRTYSYMFLAG);
1738 if ( AN.ncmod ) {
1739 if ( ( AC.modmode & ALSOFUNARGS ) != 0 ) MarkDirty(term,DIRTYFLAG);
1740 else if ( AR.PolyFun ) PolyFunDirty(BHEAD term);
1741 }
1742 else if ( AC.PolyRatFunChanged ) PolyFunDirty(BHEAD term);
1743 if ( ( AR.PolyFunType == 2 ) && ( AC.PolyRatFunChanged == 0 )
1744 && ( e->status == LOCALEXPRESSION || e->status == GLOBALEXPRESSION ) ) {
1745 PolyFunClean(BHEAD term);
1746 }
1747 if ( Generator(BHEAD term,0) ) {
1748 LowerSortLevel(); goto ProcErr;
1749 }
1750 AN.ninterms += dd;
1751 }
1752 SetScratch(fi,&position);
1753 if ( fi == AR.hidefile ) {
1754 AR.InHiBuf = (fi->POfull-fi->PObuffer)
1755 -DIFBASE(position,fi->POposition)/sizeof(WORD);
1756 }
1757 else {
1758 AR.InInBuf = (fi->POfull-fi->PObuffer)
1759 -DIFBASE(position,fi->POposition)/sizeof(WORD);
1760 }
1761 }
1762 }
1763 AN.ninterms += dd;
1764 if ( EndSort(BHEAD AT.S0->sBuffer,0) < 0 ) goto ProcErr;
1765 e->numdummies = AR.MaxDum - AM.IndDum;
1766 AR.BracketOn = oldBracketOn;
1767 AT.BrackBuf = oldBrackBuf;
1768 if ( ( e->vflags & TOBEFACTORED ) != 0 )
1770 else if ( ( ( e->vflags & TOBEUNFACTORED ) != 0 )
1771 && ( ( e->vflags & ISFACTORIZED ) != 0 ) )
1773 if ( AT.S0->TermsLeft ) e->vflags &= ~ISZERO;
1774 else e->vflags |= ISZERO;
1775 if ( AR.expchanged == 0 ) e->vflags |= ISUNMODIFIED;
1776 if ( AT.S0->TermsLeft ) AR.expflags |= ISZERO;
1777 if ( AR.expchanged ) AR.expflags |= ISUNMODIFIED;
1778 AR.GetFile = 0;
1779 AT.bracketindexflag = oldbracketindexflag;
1780/*
1781 Now copy the whole thing from fout to AR0.outfile
1782 Do this in one go to keep the lock occupied as short as possible
1783*/
1784 SeekScratch(fout,&outposition);
1785 LOCK(AS.outputslock);
1786 oldoutfile = AB[0]->R.outfile;
1787 if ( e->status == INTOHIDELEXPRESSION || e->status == INTOHIDEGEXPRESSION ) {
1788 AB[0]->R.outfile = AB[0]->R.hidefile;
1789 }
1790 SeekScratch(AB[0]->R.outfile,&position);
1791 e->onfile = position;
1792 if ( CopyExpression(fout,AB[0]->R.outfile) < 0 ) {
1793 AB[0]->R.outfile = oldoutfile;
1794 UNLOCK(AS.outputslock);
1795 MLOCK(ErrorMessageLock);
1796 MesPrint("Error copying output of 'InParallel' expression to master. Thread: %d",identity);
1797 MUNLOCK(ErrorMessageLock);
1798 goto ProcErr;
1799 }
1800 AB[0]->R.outfile = oldoutfile;
1801 AB[0]->R.expflags = AR.expflags;
1802 UNLOCK(AS.outputslock);
1803
1804 if ( fout->handle >= 0 ) { /* Now get rid of the file */
1805 CloseFile(fout->handle);
1806 fout->handle = -1;
1807 remove(fout->name);
1808 PUTZERO(fout->POposition);
1809 PUTZERO(fout->filesize);
1810 fout->POfill = fout->POfull = fout->PObuffer;
1811 }
1812 UpdateMaxSize();
1813
1814 AT.WorkPointer = oldwork;
1815
1816 } break;
1817/*
1818 #] DOONEEXPRESSION :
1819 #[ DOBRACKETS :
1820
1821 In case we have a bracket index we can have the worker treat
1822 one or more of the entries in the bracket index.
1823 The advantage is that identical terms will meet each other
1824 sooner in the sorting and hence fewer compares will be needed.
1825 Also this way the master doesn't need to fill the buckets.
1826 The main problem is the load balancing which can become very
1827 bad when there is a long tail without things outside the bracket.
1828
1829 We get sent:
1830 1: The number of the first bracket to be done
1831 2: The number of the last bracket to be done
1832*/
1833 case DOBRACKETS: {
1834 BRACKETINFO *binfo;
1835 BRACKETINDEX *bi;
1836 FILEHANDLE *fi;
1837 POSITION stoppos,where;
1838 e = Expressions + AR.CurExpr;
1839 binfo = e->bracketinfo;
1840 thr = AN.threadbuck;
1841 bi = &(binfo->indexbuffer[thr->firstbracket]);
1842 if ( AR.GetFile == 2 ) fi = AR.hidefile;
1843 else fi = AR.infile;
1844 where = bi->start;
1845 ADD2POS(where,AS.OldOnFile[AR.CurExpr]);
1846 SetScratch(fi,&(where));
1847 stoppos = binfo->indexbuffer[thr->lastbracket].next;
1848 ADD2POS(stoppos,AS.OldOnFile[AR.CurExpr]);
1849 AN.ninterms = thr->firstterm;
1850/*
1851 Now we have to put the 'value' of the bracket in the
1852 Compress buffer.
1853*/
1854 ttco = AR.CompressBuffer;
1855 tt = binfo->bracketbuffer + bi->bracket;
1856 i = *tt;
1857 NCOPY(ttco,tt,i)
1858 AR.CompressPointer = ttco;
1859 term = AT.WorkPointer;
1860 while ( GetTerm(BHEAD term) ) {
1861 SeekScratch(fi,&where);
1862 AT.WorkPointer = term + *term;
1863 AN.IndDum = AM.IndDum;
1864 AR.CurDum = ReNumber(BHEAD term);
1865 if ( AC.SymChangeFlag ) MarkDirty(term,DIRTYSYMFLAG);
1866 if ( AN.ncmod ) {
1867 if ( ( AC.modmode & ALSOFUNARGS ) != 0 ) MarkDirty(term,DIRTYFLAG);
1868 else if ( AR.PolyFun ) PolyFunDirty(BHEAD term);
1869 }
1870 else if ( AC.PolyRatFunChanged ) PolyFunDirty(BHEAD term);
1871 if ( ( AR.PolyFunType == 2 ) && ( AC.PolyRatFunChanged == 0 )
1872 && ( e->status == LOCALEXPRESSION || e->status == GLOBALEXPRESSION ) ) {
1873 PolyFunClean(BHEAD term);
1874 }
1875 if ( ( AP.PreDebug & THREADSDEBUG ) != 0 ) {
1876 MLOCK(ErrorMessageLock);
1877 MesPrint("Thread %w executing term:");
1878 PrintTerm(term,"DoBrackets");
1879 MUNLOCK(ErrorMessageLock);
1880 }
1881 AT.WorkPointer = term + *term;
1882 if ( Generator(BHEAD term,0) ) {
1884 MLOCK(ErrorMessageLock);
1885 MesPrint("Error in processing one term in thread %d in module %d",identity,AC.CModule);
1886 MUNLOCK(ErrorMessageLock);
1887 Terminate(-1);
1888 }
1889 AN.ninterms++;
1890 SetScratch(fi,&(where));
1891 if ( ISGEPOS(where,stoppos) ) break;
1892 }
1893 AT.WorkPointer = term;
1894 thr->free = BUCKETCOMINGFREE;
1895 break;
1896 }
1897/*
1898 #] DOBRACKETS :
1899 #[ CLEARCLOCK :
1900
1901 The program only comes here after a .clear
1902*/
1903 case CLEARCLOCK:
1904/* LOCK(clearclocklock); */
1905 sumtimerinfo[identity] += TimeCPU(1);
1906 timerinfo[identity] = TimeCPU(0);
1907/* UNLOCK(clearclocklock); */
1908 break;
1909/*
1910 #] CLEARCLOCK :
1911 #[ MCTSEXPANDTREE :
1912*/
1913 case MCTSEXPANDTREE:
1914 AT.optimtimes = AB[0]->T.optimtimes;
1915 find_Horner_MCTS_expand_tree();
1916 break;
1917/*
1918 #] MCTSEXPANDTREE :
1919 #[ OPTIMIZEEXPRESSION :
1920*/
1921 case OPTIMIZEEXPRESSION:
1923 break;
1924/*
1925 #] OPTIMIZEEXPRESSION :
1926*/
1927 default:
1928 MLOCK(ErrorMessageLock);
1929 MesPrint("Illegal wakeup signal %d for thread %d",wakeupsignal,identity);
1930 MUNLOCK(ErrorMessageLock);
1931 Terminate(-1);
1932 break;
1933 }
1934 /* we need the following update in case we are using checkpoints. then we
1935 need to readjust the clocks when recovering using this information */
1936 timerinfo[identity] = TimeCPU(1);
1937 }
1938EndOfThread:;
1939/*
1940 This is the end of the thread. We cleanup and exit.
1941 If we are using flint, call the per-thread cleanup function. This keep valgrind happy.
1942*/
1943#ifdef WITHFLINT
1944 flint_final_cleanup_thread();
1945#endif
1946 FinalizeOneThread(identity);
1947 return(0);
1948ProcErr:
1949 Terminate(-1);
1950 return(0);
1951}
1952
1953/*
1954 #] RunThread :
1955 #[ RunSortBot :
1956*/
1964#ifdef WITHSORTBOTS
1965
1966void *RunSortBot(void *dummy)
1967{
1968 int identity, wakeupsignal, identityretv;
1969 ALLPRIVATES *B, *BB;
1970 DUMMYUSE(dummy);
1971 identity = SetIdentity(&identityretv);
1972 threadpointers[identity] = pthread_self();
1973 B = InitializeOneThread(identity);
1974 while ( ( wakeupsignal = SortBotWait(identity) ) > 0 ) {
1975 switch ( wakeupsignal ) {
1976/*
1977 #[ INISORTBOT :
1978*/
1979 case INISORTBOT:
1980 AR.CompressBuffer = AB[0]->R.CompressBuffer;
1981 AR.ComprTop = AB[0]->R.ComprTop;
1982 AR.CompressPointer = AB[0]->R.CompressPointer;
1983 AR.CurExpr = AB[0]->R.CurExpr;
1984 AR.PolyFun = AB[0]->R.PolyFun;
1985 AR.PolyFunInv = AB[0]->R.PolyFunInv;
1986 AR.PolyFunType = AB[0]->R.PolyFunType;
1987 AR.PolyFunExp = AB[0]->R.PolyFunExp;
1988 AR.PolyFunVar = AB[0]->R.PolyFunVar;
1989 AR.PolyFunPow = AB[0]->R.PolyFunPow;
1990 AR.SortType = AC.SortType;
1991 if ( AR.PolyFun == 0 ) { AT.SS->PolyFlag = 0; }
1992 else if ( AR.PolyFunType == 1 ) { AT.SS->PolyFlag = 1; }
1993 else if ( AR.PolyFunType == 2 ) {
1994 if ( AR.PolyFunExp == 2
1995 || AR.PolyFunExp == 3 ) AT.SS->PolyFlag = 1;
1996 else AT.SS->PolyFlag = 2;
1997 }
1998 AT.SS->PolyWise = 0;
1999 AN.ncmod = AC.ncmod;
2000 LOCK(AT.SB.MasterBlockLock[1]);
2001 BB = AB[AT.SortBotIn1];
2002 LOCK(BB->T.SB.MasterBlockLock[BB->T.SB.MasterNumBlocks]);
2003 BB = AB[AT.SortBotIn2];
2004 LOCK(BB->T.SB.MasterBlockLock[BB->T.SB.MasterNumBlocks]);
2005 AT.SB.FillBlock = 1;
2006 AT.SB.MasterFill[1] = AT.SB.MasterStart[1];
2007 SETBASEPOSITION(AN.theposition,0);
2008 // Reset the sortbot comparison count
2009 AT.SS->verbComparisons = 0;
2010 // Reset the maximal term size count
2011 AT.SS->verbMaxTermSize = 0;
2012 break;
2013/*
2014 #] INISORTBOT :
2015 #[ RUNSORTBOT :
2016*/
2017 case RUNSORTBOT:
2018 SortBotMerge(B);
2019 break;
2020/*
2021 #] RUNSORTBOT :
2022 #[ TERMINATETHREAD :
2023*/
2024 case TERMINATETHREAD:
2025 goto EndOfThread;
2026/*
2027 #] TERMINATETHREAD :
2028 #[ CLEARCLOCK :
2029
2030 The program only comes here after a .clear
2031*/
2032 case CLEARCLOCK:
2033/* LOCK(clearclocklock); */
2034 sumtimerinfo[identity] += TimeCPU(1);
2035 timerinfo[identity] = TimeCPU(0);
2036/* UNLOCK(clearclocklock); */
2037 break;
2038/*
2039 #] CLEARCLOCK :
2040*/
2041 default:
2042 MLOCK(ErrorMessageLock);
2043 MesPrint("Illegal wakeup signal %d for thread %d",wakeupsignal,identity);
2044 MUNLOCK(ErrorMessageLock);
2045 Terminate(-1);
2046 break;
2047 }
2048 }
2049EndOfThread:;
2050/*
2051 This is the end of the thread. We cleanup and exit.
2052 If we are using flint, call the per-thread cleanup function. This keep valgrind happy.
2053*/
2054#ifdef WITHFLINT
2055 flint_final_cleanup_thread();
2056#endif
2057 FinalizeOneThread(identity);
2058 return(0);
2059}
2060
2061#endif
2062
2063/*
2064 #] RunSortBot :
2065 #[ IAmAvailable :
2066*/
2078void IAmAvailable(int identity)
2079{
2080 int top;
2081 LOCK(availabilitylock);
2082 top = topofavailables;
2083 listofavailables[topofavailables++] = identity;
2084 if ( top == 0 ) {
2085 UNLOCK(availabilitylock);
2086 LOCK(wakeupmasterlock);
2087 wakeupmaster = identity;
2088 pthread_cond_signal(&wakeupmasterconditions);
2089 UNLOCK(wakeupmasterlock);
2090 }
2091 else {
2092 UNLOCK(availabilitylock);
2093 }
2094}
2095
2096/*
2097 #] IAmAvailable :
2098 #[ GetAvailableThread :
2099*/
2108int GetAvailableThread(void)
2109{
2110 int retval = -1;
2111 LOCK(availabilitylock);
2112 if ( topofavailables > 0 ) retval = listofavailables[--topofavailables];
2113 UNLOCK(availabilitylock);
2114 if ( retval >= 0 ) {
2115/*
2116 Make sure the thread is indeed waiting and not between
2117 saying that it is available and starting to wait.
2118*/
2119 LOCK(wakeuplocks[retval]);
2120 UNLOCK(wakeuplocks[retval]);
2121 }
2122 return(retval);
2123}
2124
2125/*
2126 #] GetAvailableThread :
2127 #[ ConditionalGetAvailableThread :
2128*/
2136int ConditionalGetAvailableThread(void)
2137{
2138 int retval = -1;
2139 if ( topofavailables > 0 ) {
2140 LOCK(availabilitylock);
2141 if ( topofavailables > 0 ) {
2142 retval = listofavailables[--topofavailables];
2143 }
2144 UNLOCK(availabilitylock);
2145 if ( retval >= 0 ) {
2146/*
2147 Make sure the thread is indeed waiting and not between
2148 saying that it is available and starting to wait.
2149*/
2150 LOCK(wakeuplocks[retval]);
2151 UNLOCK(wakeuplocks[retval]);
2152 }
2153 }
2154 return(retval);
2155}
2156
2157/*
2158 #] ConditionalGetAvailableThread :
2159 #[ GetThread :
2160*/
2170int GetThread(int identity)
2171{
2172 int retval = -1, j;
2173 LOCK(availabilitylock);
2174 for ( j = 0; j < topofavailables; j++ ) {
2175 if ( identity == listofavailables[j] ) break;
2176 }
2177 if ( j < topofavailables ) {
2178 --topofavailables;
2179 for ( ; j < topofavailables; j++ ) {
2180 listofavailables[j] = listofavailables[j+1];
2181 }
2182 retval = identity;
2183 }
2184 UNLOCK(availabilitylock);
2185 return(retval);
2186}
2187
2188/*
2189 #] GetThread :
2190 #[ ThreadWait :
2191*/
2201int ThreadWait(int identity)
2202{
2203 int retval, top, j;
2204 LOCK(wakeuplocks[identity]);
2205 LOCK(availabilitylock);
2206 top = topofavailables;
2207 for ( j = topofavailables; j > 0; j-- )
2208 listofavailables[j] = listofavailables[j-1];
2209 listofavailables[0] = identity;
2210 topofavailables++;
2211 if ( top == 0 || topofavailables == numberofworkers ) {
2212 UNLOCK(availabilitylock);
2213 LOCK(wakeupmasterlock);
2214 wakeupmaster = identity;
2215 pthread_cond_signal(&wakeupmasterconditions);
2216 UNLOCK(wakeupmasterlock);
2217 }
2218 else {
2219 UNLOCK(availabilitylock);
2220 }
2221 while ( wakeup[identity] == 0 ) {
2222 pthread_cond_wait(&(wakeupconditions[identity]),&(wakeuplocks[identity]));
2223 }
2224 retval = wakeup[identity];
2225 wakeup[identity] = 0;
2226 UNLOCK(wakeuplocks[identity]);
2227 return(retval);
2228}
2229
2230/*
2231 #] ThreadWait :
2232 #[ SortBotWait :
2233*/
2234
2235#ifdef WITHSORTBOTS
2245int SortBotWait(int identity)
2246{
2247 int retval;
2248 LOCK(wakeuplocks[identity]);
2249 LOCK(availabilitylock);
2250 topsortbotavailables++;
2251 if ( topsortbotavailables >= numberofsortbots ) {
2252 UNLOCK(availabilitylock);
2253 LOCK(wakeupsortbotlock);
2254 wakeupmaster = identity;
2255 pthread_cond_signal(&wakeupsortbotconditions);
2256 UNLOCK(wakeupsortbotlock);
2257 }
2258 else {
2259 UNLOCK(availabilitylock);
2260 }
2261 while ( wakeup[identity] == 0 ) {
2262 pthread_cond_wait(&(wakeupconditions[identity]),&(wakeuplocks[identity]));
2263 }
2264 retval = wakeup[identity];
2265 wakeup[identity] = 0;
2266 UNLOCK(wakeuplocks[identity]);
2267 return(retval);
2268}
2269
2270#endif
2271
2272/*
2273 #] SortBotWait :
2274 #[ ThreadClaimedBlock :
2275*/
2286int ThreadClaimedBlock(int identity)
2287{
2288 LOCK(availabilitylock);
2289 numberclaimed++;
2290 if ( numberclaimed >= numberofworkers ) {
2291 UNLOCK(availabilitylock);
2292 LOCK(wakeupmasterlock);
2293 wakeupmaster = identity;
2294 pthread_cond_signal(&wakeupmasterconditions);
2295 UNLOCK(wakeupmasterlock);
2296 }
2297 else {
2298 UNLOCK(availabilitylock);
2299 }
2300 return(0);
2301}
2302
2303/*
2304 #] ThreadClaimedBlock :
2305 #[ MasterWait :
2306*/
2314int MasterWait(void)
2315{
2316 int retval;
2317 LOCK(wakeupmasterlock);
2318 while ( wakeupmaster == 0 ) {
2319 pthread_cond_wait(&wakeupmasterconditions,&wakeupmasterlock);
2320 }
2321 retval = wakeupmaster;
2322 wakeupmaster = 0;
2323 UNLOCK(wakeupmasterlock);
2324 return(retval);
2325}
2326
2327/*
2328 #] MasterWait :
2329 #[ MasterWaitThread :
2330*/
2337int MasterWaitThread(int identity)
2338{
2339 int retval;
2340 LOCK(wakeupmasterthreadlocks[identity]);
2341 while ( wakeupmasterthread[identity] == 0 ) {
2342 pthread_cond_wait(&(wakeupmasterthreadconditions[identity])
2343 ,&(wakeupmasterthreadlocks[identity]));
2344 }
2345 retval = wakeupmasterthread[identity];
2346 wakeupmasterthread[identity] = 0;
2347 UNLOCK(wakeupmasterthreadlocks[identity]);
2348 return(retval);
2349}
2350
2351/*
2352 #] MasterWaitThread :
2353 #[ MasterWaitAll :
2354*/
2361void MasterWaitAll(void)
2362{
2363 LOCK(wakeupmasterlock);
2364 while ( topofavailables < numberofworkers ) {
2365 pthread_cond_wait(&wakeupmasterconditions,&wakeupmasterlock);
2366 }
2367 UNLOCK(wakeupmasterlock);
2368 return;
2369}
2370
2371/*
2372 #] MasterWaitAll :
2373 #[ MasterWaitAllSortBots :
2374*/
2375
2376#ifdef WITHSORTBOTS
2377
2383void MasterWaitAllSortBots(void)
2384{
2385 LOCK(wakeupsortbotlock);
2386 while ( topsortbotavailables < numberofsortbots ) {
2387 pthread_cond_wait(&wakeupsortbotconditions,&wakeupsortbotlock);
2388 }
2389 UNLOCK(wakeupsortbotlock);
2390 return;
2391}
2392
2393#endif
2394
2395/*
2396 #] MasterWaitAllSortBots :
2397 #[ MasterWaitAllBlocks :
2398*/
2405void MasterWaitAllBlocks(void)
2406{
2407 LOCK(wakeupmasterlock);
2408 while ( numberclaimed < numberofworkers ) {
2409 pthread_cond_wait(&wakeupmasterconditions,&wakeupmasterlock);
2410 }
2411 UNLOCK(wakeupmasterlock);
2412 return;
2413}
2414
2415/*
2416 #] MasterWaitAllBlocks :
2417 #[ WakeupThread :
2418*/
2427void WakeupThread(int identity, int signalnumber)
2428{
2429 if ( signalnumber == 0 ) {
2430 MLOCK(ErrorMessageLock);
2431 MesPrint("Illegal wakeup signal for thread %d",identity);
2432 MUNLOCK(ErrorMessageLock);
2433 Terminate(-1);
2434 }
2435 LOCK(wakeuplocks[identity]);
2436 wakeup[identity] = signalnumber;
2437 pthread_cond_signal(&(wakeupconditions[identity]));
2438 UNLOCK(wakeuplocks[identity]);
2439}
2440
2441/*
2442 #] WakeupThread :
2443 #[ WakeupMasterFromThread :
2444*/
2453void WakeupMasterFromThread(int identity, int signalnumber)
2454{
2455 if ( signalnumber == 0 ) {
2456 MLOCK(ErrorMessageLock);
2457 MesPrint("Illegal wakeup signal for master %d",identity);
2458 MUNLOCK(ErrorMessageLock);
2459 Terminate(-1);
2460 }
2461 LOCK(wakeupmasterthreadlocks[identity]);
2462 wakeupmasterthread[identity] = signalnumber;
2463 pthread_cond_signal(&(wakeupmasterthreadconditions[identity]));
2464 UNLOCK(wakeupmasterthreadlocks[identity]);
2465}
2466
2467/*
2468 #] WakeupMasterFromThread :
2469 #[ SendOneBucket :
2470*/
2476int SendOneBucket(int type)
2477{
2478 ALLPRIVATES *B0 = AB[0];
2479 THREADBUCKET *thr = 0;
2480 int j, k, id;
2481 for ( j = 0; j < numthreadbuckets; j++ ) {
2482 if ( threadbuckets[j]->free == BUCKETFILLED ) {
2483 thr = threadbuckets[j];
2484 for ( k = j+1; k < numthreadbuckets; k++ )
2485 threadbuckets[k-1] = threadbuckets[k];
2486 threadbuckets[numthreadbuckets-1] = thr;
2487 break;
2488 }
2489 }
2490 AN0.ninterms++;
2491 while ( ( id = GetAvailableThread() ) < 0 ) { MasterWait(); }
2492/*
2493 Prepare the thread. Give it the term and variables.
2494*/
2495 LoadOneThread(0,id,thr,0);
2496 thr->busy = BUCKETASSIGNED;
2497 thr->free = BUCKETINUSE;
2498 numberoffullbuckets--;
2499/*
2500 And signal the thread to run.
2501 Form now on we may only interfere with this bucket
2502 1: after it has been marked BUCKETCOMINGFREE
2503 2: when thr->busy == BUCKETDOINGTERM and then only when protected by
2504 thr->lock. This would be for load balancing.
2505*/
2506 WakeupThread(id,type);
2507/* AN0.ninterms += thr->ddterms; */
2508 return(0);
2509}
2510
2511/*
2512 #] SendOneBucket :
2513 #[ InParallelProcessor :
2514*/
2534int InParallelProcessor(void)
2535{
2536 GETIDENTITY
2537 int i, id, retval = 0, num = 0;
2538 EXPRESSIONS e;
2539 if ( numberofworkers >= 2 ) {
2540 SetWorkerFiles();
2541 for ( i = 0; i < NumExpressions; i++ ) {
2542 e = Expressions+i;
2543 if ( e->partodo <= 0 ) continue;
2544 if ( e->status == LOCALEXPRESSION || e->status == GLOBALEXPRESSION
2545 || e->status == UNHIDELEXPRESSION || e->status == UNHIDEGEXPRESSION
2546 || e->status == INTOHIDELEXPRESSION || e->status == INTOHIDEGEXPRESSION ) {
2547 }
2548 else {
2549 e->partodo = 0;
2550 continue;
2551 }
2552 if ( e->counter == 0 ) { /* Expression with zero terms */
2553 e->partodo = 0;
2554 continue;
2555 }
2556/*
2557 This expression should go to an idle worker
2558*/
2559 while ( ( id = GetAvailableThread() ) < 0 ) { MasterWait(); }
2560 LoadOneThread(0,id,0,-1);
2561 AB[id]->R.exprtodo = i;
2562 WakeupThread(id,DOONEEXPRESSION);
2563 num++;
2564 }
2565/*
2566 Now we have to wait for all workers to finish
2567*/
2568 if ( num > 0 ) MasterWaitAll();
2569
2570 if ( AC.CollectFun ) AR.DeferFlag = 0;
2571 }
2572 else {
2573 for ( i = 0; i < NumExpressions; i++ ) {
2574 Expressions[i].partodo = 0;
2575 }
2576 }
2577 return(retval);
2578}
2579
2580/*
2581 #] InParallelProcessor :
2582 #[ ThreadsProcessor :
2583*/
2608int ThreadsProcessor(EXPRESSIONS e, WORD LastExpression, WORD fromspectator)
2609{
2610 ALLPRIVATES *B0 = AB[0], *B = B0;
2611 int id, oldgzipCompress, endofinput = 0, j, still, k, defcount = 0, bra = 0, first = 1;
2612 LONG dd = 0, ddd, thrbufsiz, thrbufsiz0, thrbufsiz2, numbucket = 0, numpasses;
2613 LONG num, i;
2614 WORD *oldworkpointer = AT0.WorkPointer, *tt, *ttco = 0, *t1 = 0, ter, *tstop = 0, *t2;
2615 THREADBUCKET *thr = 0;
2616 FILEHANDLE *oldoutfile = AR0.outfile;
2617 GETTERM GetTermP = &GetTerm;
2618 POSITION eonfile = AS.OldOnFile[e-Expressions];
2619 numberoffullbuckets = 0;
2620/*
2621 Start up all threads. The lock needs to be around the whole loop
2622 to keep processes from terminating quickly and putting themselves
2623 in the list of available threads again.
2624*/
2625 AM.tracebackflag = 1;
2626
2627 AS.sLevel = AR0.sLevel;
2628 LOCK(availabilitylock);
2629 topofavailables = 0;
2630 for ( id = 1; id <= numberofworkers; id++ ) {
2631 WakeupThread(id,STARTNEWEXPRESSION);
2632 }
2633 UNLOCK(availabilitylock);
2634 NewSort(BHEAD0);
2635 AN0.ninterms = 1;
2636/*
2637 Now for redefine
2638*/
2639 if ( AC.numpfirstnum > 0 ) {
2640 for ( j = 0; j < AC.numpfirstnum; j++ ) {
2641 AC.inputnumbers[j] = -1;
2642 }
2643 }
2644 MasterWaitAll();
2645/*
2646 Determine a reasonable bucketsize.
2647 This is based on the value of AC.ThreadBucketSize and the number
2648 of terms. We want at least 5 buckets per worker at the moment.
2649 Some research should show whether this is reasonable.
2650
2651 The number of terms in the expression is in e->counter
2652*/
2653 thrbufsiz2 = thrbufsiz = AC.ThreadBucketSize-1;
2654 if ( ( e->counter / ( numberofworkers * 5 ) ) < thrbufsiz ) {
2655 thrbufsiz = e->counter / ( numberofworkers * 5 ) - 1;
2656 if ( thrbufsiz < 0 ) thrbufsiz = 0;
2657 }
2658 thrbufsiz0 = thrbufsiz;
2659 numpasses = 5; /* this is just for trying */
2660 thrbufsiz = thrbufsiz0 / (2 << numpasses);
2661/*
2662 Mark all buckets as free and take the first.
2663*/
2664 for ( j = 0; j < numthreadbuckets; j++ )
2665 threadbuckets[j]->free = BUCKETFREE;
2666 thr = threadbuckets[0];
2667/*
2668 #[ Whole brackets :
2669
2670 First we look whether we have to work with entire brackets
2671 This is the case when there is a non-NULL address in e->bracketinfo.
2672 Of course we shouldn't have interference from a collect or keep statement.
2673*/
2674#ifdef WHOLEBRACKETS
2675 if ( e->bracketinfo && AC.CollectFun == 0 && AR0.DeferFlag == 0 ) {
2676 FILEHANDLE *curfile;
2677 int didone = 0;
2678 LONG num, n;
2679 AN0.expr = e;
2680 for ( n = 0; n < e->bracketinfo->indexfill; n++ ) {
2681 num = TreatIndexEntry(B0,n);
2682 if ( num > 0 ) {
2683 didone = 1;
2684/*
2685 This bracket can be sent off.
2686 1: Look for an empty bucket
2687*/
2688ReTry:;
2689 for ( j = 0; j < numthreadbuckets; j++ ) {
2690 switch ( threadbuckets[j]->free ) {
2691 case BUCKETFREE:
2692 thr = threadbuckets[j];
2693 goto Found1;
2694 case BUCKETCOMINGFREE:
2695 thr = threadbuckets[j];
2696 thr->free = BUCKETFREE;
2697 for ( k = j+1; k < numthreadbuckets; k++ )
2698 threadbuckets[k-1] = threadbuckets[k];
2699 threadbuckets[numthreadbuckets-1] = thr;
2700 j--;
2701 break;
2702 default:
2703 break;
2704 }
2705 }
2706Found1:;
2707 if ( j < numthreadbuckets ) {
2708/*
2709 Found an empty bucket. Fill it.
2710*/
2711 thr->firstbracket = n;
2712 thr->lastbracket = n + num - 1;
2713 thr->type = BUCKETDOINGBRACKET;
2714 thr->free = BUCKETFILLED;
2715 thr->firstterm = AN0.ninterms;
2716 for ( j = n; j < n+num; j++ ) {
2717 AN0.ninterms += e->bracketinfo->indexbuffer[j].termsinbracket;
2718 }
2719 n += num-1;
2720 numberoffullbuckets++;
2721 if ( topofavailables > 0 ) {
2722 SendOneBucket(DOBRACKETS);
2723 }
2724 }
2725/*
2726 All buckets are in use.
2727 Look/wait for an idle worker. Give it a bucket.
2728 After that, retry for a bucket
2729*/
2730 else {
2731 while ( topofavailables <= 0 ) {
2732 MasterWait();
2733 }
2734 SendOneBucket(DOBRACKETS);
2735 goto ReTry;
2736 }
2737 }
2738 }
2739 if ( didone ) {
2740/*
2741 And now put the input back in the original position.
2742*/
2743 switch ( e->status ) {
2744 case UNHIDELEXPRESSION:
2745 case UNHIDEGEXPRESSION:
2746 case DROPHLEXPRESSION:
2747 case DROPHGEXPRESSION:
2748 case HIDDENLEXPRESSION:
2749 case HIDDENGEXPRESSION:
2750 curfile = AR0.hidefile;
2751 break;
2752 default:
2753 curfile = AR0.infile;
2754 break;
2755 }
2756 SetScratch(curfile,&eonfile);
2757 GetTerm(B0,AT0.WorkPointer);
2758/*
2759 Now we point the GetTerm that is used to the one that is selective
2760*/
2761 GetTermP = &GetTerm2;
2762/*
2763 Next wait till there is a bucket available and initialize thr to it.
2764*/
2765 for(;;) {
2766 for ( j = 0; j < numthreadbuckets; j++ ) {
2767 switch ( threadbuckets[j]->free ) {
2768 case BUCKETFREE:
2769 thr = threadbuckets[j];
2770 goto Found2;
2771 case BUCKETCOMINGFREE:
2772 thr = threadbuckets[j];
2773 thr->free = BUCKETFREE;
2774 for ( k = j+1; k < numthreadbuckets; k++ )
2775 threadbuckets[k-1] = threadbuckets[k];
2776 threadbuckets[numthreadbuckets-1] = thr;
2777 j--;
2778 break;
2779 default:
2780 break;
2781 }
2782 }
2783 while ( topofavailables <= 0 ) {
2784 MasterWait();
2785 }
2786 while ( topofavailables > 0 && numberoffullbuckets > 0 ) {
2787 SendOneBucket(DOBRACKETS);
2788 }
2789 }
2790Found2:;
2791 while ( numberoffullbuckets > 0 ) {
2792 while ( topofavailables <= 0 ) {
2793 MasterWait();
2794 }
2795 while ( topofavailables > 0 && numberoffullbuckets > 0 ) {
2796 SendOneBucket(DOBRACKETS);
2797 }
2798 }
2799/*
2800 Disable the 'warming up' with smaller buckets.
2801
2802 numpasses = 0;
2803 thrbufsiz = thrbufsiz0;
2804*/
2805 AN0.lastinindex = -1;
2806 }
2807 MasterWaitAll();
2808 }
2809#endif
2810/*
2811 #] Whole brackets :
2812
2813 Now the loop to start a bucket
2814*/
2815 for(;;) {
2816 if ( fromspectator ) {
2817 ter = GetFromSpectator(thr->threadbuffer,fromspectator-1);
2818 if ( ter == 0 ) fromspectator = 0;
2819 }
2820 else {
2821 ter = GetTermP(B0,thr->threadbuffer);
2822/*
2823 At this point we could check whether the input term is
2824 just an expression that resides in a scratch file.
2825 If this is the case we should store the current input info
2826 (file and buffer content) and redirect the input.
2827 At the end we can go back to where we were.
2828 There are two possibilities: we are in the same scratchfile
2829 as the main input and the other expression is still in the
2830 input buffer, or we have to do some reading. The reading is
2831 of course done in GetTerm.
2832
2833 How to set this up can also be studied in TestSub (in file proces.c)
2834 where it checks for EXPRESSION.
2835*/
2836 }
2837 if ( ter < 0 ) break;
2838 if ( ter == 0 ) { endofinput = 1; goto Finalize; }
2839 dd = AN0.deferskipped;
2840 if ( AR0.DeferFlag ) {
2841 defcount = 0;
2842 thr->deferbuffer[defcount++] = AR0.DefPosition;
2843 ttco = thr->compressbuffer; t1 = AR0.CompressBuffer; j = *t1;
2844 while ( thr->compressbuffersize <= j ) {
2845 // the compressbuffer is not large enough!
2846 WORD *top = thr->compressbuffer+thr->compressbuffersize;
2847 DoubleBuffer((void**)&(thr->compressbuffer),(void**)&(top),
2848 sizeof(*(thr->compressbuffer)), "double compressbuffer");
2849 ttco = thr->compressbuffer;
2850 thr->compressbuffersize *= 2;
2851 }
2852 NCOPY(ttco,t1,j);
2853 }
2854 else if ( first && ( AC.CollectFun == 0 ) ) { /* Brackets ? */
2855 first = 0;
2856 t1 = tstop = thr->threadbuffer;
2857 tstop += *tstop; tstop -= ABS(tstop[-1]);
2858 t1++;
2859 while ( t1 < tstop ) {
2860 if ( t1[0] == HAAKJE ) { bra = 1; break; }
2861 t1 += t1[1];
2862 }
2863 t1 = thr->threadbuffer;
2864 }
2865/*
2866 Check whether we have a collect,function going. If so execute it.
2867*/
2868 if ( AC.CollectFun && *(thr->threadbuffer) < (AM.MaxTer/((LONG)sizeof(WORD))-10) ) {
2869 if ( ( dd = GetMoreTerms(thr->threadbuffer) ) < 0 ) {
2870 LowerSortLevel(); goto ProcErr;
2871 }
2872 }
2873/*
2874 Check whether we have a priority task:
2875*/
2876 if ( topofavailables > 0 && numberoffullbuckets > 0 ) SendOneBucket(LOWESTLEVELGENERATION);
2877/*
2878 Now put more terms in the bucket. Position tt after the first term
2879*/
2880 tt = thr->threadbuffer; tt += *tt;
2881 thr->totnum = 1;
2882 thr->usenum = 0;
2883/*
2884 Next we worry about the 'slow startup' in which we make the initial
2885 buckets smaller, so that we get all threads busy as soon as possible.
2886*/
2887 if ( numpasses > 0 ) {
2888 numbucket++;
2889 if ( numbucket >= numberofworkers ) {
2890 numbucket = 0;
2891 numpasses--;
2892 if ( numpasses == 0 ) thrbufsiz = thrbufsiz0;
2893 else thrbufsiz = thrbufsiz0 / (2 << numpasses);
2894 }
2895 thrbufsiz2 = thrbufsiz + thrbufsiz/5; /* for completing brackets */
2896 }
2897/*
2898 we have already 1+dd terms
2899*/
2900 while ( ( dd < thrbufsiz ) &&
2901 ( tt - thr->threadbuffer ) < ( thr->threadbuffersize - AM.MaxTer/((LONG)sizeof(WORD)) - 2 ) ) {
2902/*
2903 First check:
2904*/
2905 if ( topofavailables > 0 && numberoffullbuckets > 0 ) SendOneBucket(LOWESTLEVELGENERATION);
2906/*
2907 There is room in the bucket. Fill yet another term.
2908*/
2909 if ( GetTermP(B0,tt) == 0 ) { endofinput = 1; break; }
2910 dd++;
2911 thr->totnum++;
2912 dd += AN0.deferskipped;
2913 if ( AR0.DeferFlag ) {
2914 thr->deferbuffer[defcount++] = AR0.DefPosition;
2915 t1 = AR0.CompressBuffer; j = *t1;
2916 while ( thr->compressbuffer+thr->compressbuffersize-ttco <= j ) {
2917 // the compressbuffer is not large enough!
2918 const ptrdiff_t oldoffset = ttco - thr->compressbuffer;
2919 WORD *top = thr->compressbuffer+thr->compressbuffersize;
2920 DoubleBuffer((void**)&(thr->compressbuffer),(void**)&(top),
2921 sizeof(*(thr->compressbuffer)), "double compressbuffer");
2922 ttco = thr->compressbuffer + oldoffset;
2923 thr->compressbuffersize *= 2;
2924 }
2925 NCOPY(ttco,t1,j);
2926 }
2927 if ( AC.CollectFun && *tt < (AM.MaxTer/((LONG)sizeof(WORD))-10) ) {
2928 if ( ( ddd = GetMoreTerms(tt) ) < 0 ) {
2929 LowerSortLevel(); goto ProcErr;
2930 }
2931 dd += ddd;
2932 }
2933 t1 = tt;
2934 tt += *tt;
2935 }
2936/*
2937 Check whether there are regular brackets and if we have no DeferFlag
2938 and no collect, we try to add more terms till we finish the current
2939 bracket. We should however not overdo it. Let us say: up to 20%
2940 more terms are allowed.
2941*/
2942 if ( bra ) {
2943 tstop = t1 + *t1; tstop -= ABS(tstop[-1]);
2944 t2 = t1+1;
2945 while ( t2 < tstop ) {
2946 if ( t2[0] == HAAKJE ) { break; }
2947 t2 += t2[1];
2948 }
2949 if ( t2[0] == HAAKJE ) {
2950 t2 += t2[1]; num = t2 - t1;
2951 while ( ( dd < thrbufsiz2 ) &&
2952 ( tt - thr->threadbuffer ) < ( thr->threadbuffersize - AM.MaxTer - 2 ) ) {
2953/*
2954 First check:
2955*/
2956 if ( topofavailables > 0 && numberoffullbuckets > 0 ) SendOneBucket(LOWESTLEVELGENERATION);
2957/*
2958 There is room in the bucket. Fill yet another term.
2959*/
2960 if ( GetTermP(B0,tt) == 0 ) { endofinput = 1; break; }
2961/*
2962 Same bracket?
2963*/
2964 tstop = tt + *tt; tstop -= ABS(tstop[-1]);
2965 if ( tstop-tt < num ) { /* Different: abort */
2966 AR0.KeptInHold = 1;
2967 break;
2968 }
2969 for ( i = 1; i < num; i++ ) {
2970 if ( t1[i] != tt[i] ) break;
2971 }
2972 if ( i < num ) { /* Different: abort */
2973 AR0.KeptInHold = 1;
2974 break;
2975 }
2976/*
2977 Same bracket. We need this term.
2978*/
2979 dd++;
2980 thr->totnum++;
2981 tt += *tt;
2982 }
2983 }
2984 }
2985 thr->ddterms = dd; /* total number of terms including keep brackets */
2986 thr->firstterm = AN0.ninterms;
2987 AN0.ninterms += dd;
2988 *tt = 0; /* mark end of bucket */
2989 thr->free = BUCKETFILLED;
2990 thr->type = BUCKETDOINGTERMS;
2991 numberoffullbuckets++;
2992 if ( topofavailables <= 0 && endofinput == 0 ) {
2993/*
2994 Problem: topofavailables may already be > 0, but the
2995 thread has not yet gone into waiting. Can the signal get lost?
2996 How can we tell that a thread is waiting for a signal?
2997
2998 All threads are busy. Try to load up another bucket.
2999 In the future we could be more sophisticated.
3000 At the moment we load a complete bucket which could be
3001 1000 terms or even more.
3002 In principle it is better to keep a full bucket ready
3003 and check after each term we put in the next bucket. That
3004 way we don't waste time of the workers.
3005*/
3006 for ( j = 0; j < numthreadbuckets; j++ ) {
3007 switch ( threadbuckets[j]->free ) {
3008 case BUCKETFREE:
3009 thr = threadbuckets[j];
3010 if ( !endofinput ) goto NextBucket;
3011/*
3012 If we are at the end of the input we mark
3013 the free buckets in a special way. That way
3014 we don't keep running into them.
3015*/
3016 thr->free = BUCKETATEND;
3017 break;
3018 case BUCKETCOMINGFREE:
3019 thr = threadbuckets[j];
3020 thr->free = BUCKETFREE;
3021/*
3022 Bucket has just been finished.
3023 Put at the end of the list. We don't want
3024 an early bucket to wait to be treated last.
3025*/
3026 for ( k = j+1; k < numthreadbuckets; k++ )
3027 threadbuckets[k-1] = threadbuckets[k];
3028 threadbuckets[numthreadbuckets-1] = thr;
3029 j--; /* we have to redo the same number j. */
3030 break;
3031 default:
3032 break;
3033 }
3034 }
3035/*
3036 We have no free bucket or we are at the end.
3037 The only thing we can do now is wait for a worker to come free,
3038 provided there are still buckets to send.
3039*/
3040 }
3041/*
3042 Look for the next bucket to send. There is at least one full bucket!
3043*/
3044 for ( j = 0; j < numthreadbuckets; j++ ) {
3045 if ( threadbuckets[j]->free == BUCKETFILLED ) {
3046 thr = threadbuckets[j];
3047 for ( k = j+1; k < numthreadbuckets; k++ )
3048 threadbuckets[k-1] = threadbuckets[k];
3049 threadbuckets[numthreadbuckets-1] = thr;
3050 break;
3051 }
3052 }
3053/*
3054 Wait for a thread to become available
3055 The bucket we are going to use is in thr.
3056*/
3057DoBucket:;
3058 AN0.ninterms++;
3059 while ( ( id = GetAvailableThread() ) < 0 ) { MasterWait(); }
3060/*
3061 Prepare the thread. Give it the term and variables.
3062*/
3063 LoadOneThread(0,id,thr,0);
3064 LOCK(thr->lock);
3065 thr->busy = BUCKETASSIGNED;
3066 UNLOCK(thr->lock);
3067 thr->free = BUCKETINUSE;
3068 numberoffullbuckets--;
3069/*
3070 And signal the thread to run.
3071 Form now on we may only interfere with this bucket
3072 1: after it has been marked BUCKETCOMINGFREE
3073 2: when thr->busy == BUCKETDOINGTERM and then only when protected by
3074 thr->lock. This would be for load balancing.
3075*/
3076 WakeupThread(id,LOWESTLEVELGENERATION);
3077/* AN0.ninterms += thr->ddterms; */
3078/*
3079 Now look whether there is another bucket filled and a worker available
3080*/
3081 if ( topofavailables > 0 ) { /* there is a worker */
3082 for ( j = 0; j < numthreadbuckets; j++ ) {
3083 if ( threadbuckets[j]->free == BUCKETFILLED ) {
3084 thr = threadbuckets[j];
3085 for ( k = j+1; k < numthreadbuckets; k++ )
3086 threadbuckets[k-1] = threadbuckets[k];
3087 threadbuckets[numthreadbuckets-1] = thr;
3088 goto DoBucket; /* and we found a bucket */
3089 }
3090 }
3091/*
3092 no bucket is loaded but there is a thread available
3093 find a bucket to load. If there is none (all are USED or ATEND)
3094 we jump out of the loop.
3095*/
3096 for ( j = 0; j < numthreadbuckets; j++ ) {
3097 switch ( threadbuckets[j]->free ) {
3098 case BUCKETFREE:
3099 thr = threadbuckets[j];
3100 if ( !endofinput ) goto NextBucket;
3101 thr->free = BUCKETATEND;
3102 break;
3103 case BUCKETCOMINGFREE:
3104 thr = threadbuckets[j];
3105 if ( endofinput ) {
3106 thr->free = BUCKETATEND;
3107 }
3108 else {
3109 thr->free = BUCKETFREE;
3110 for ( k = j+1; k < numthreadbuckets; k++ )
3111 threadbuckets[k-1] = threadbuckets[k];
3112 threadbuckets[numthreadbuckets-1] = thr;
3113 j--;
3114 }
3115 break;
3116 default:
3117 break;
3118 }
3119 }
3120 if ( j >= numthreadbuckets ) break;
3121 }
3122 else {
3123/*
3124 No worker available.
3125 Look for a bucket to load.
3126 Its number will be in "still"
3127*/
3128Finalize:;
3129 still = -1;
3130 for ( j = 0; j < numthreadbuckets; j++ ) {
3131 switch ( threadbuckets[j]->free ) {
3132 case BUCKETFREE:
3133 thr = threadbuckets[j];
3134 if ( !endofinput ) goto NextBucket;
3135 thr->free = BUCKETATEND;
3136 break;
3137 case BUCKETCOMINGFREE:
3138 thr = threadbuckets[j];
3139 if ( endofinput ) thr->free = BUCKETATEND;
3140 else {
3141 thr->free = BUCKETFREE;
3142 for ( k = j+1; k < numthreadbuckets; k++ )
3143 threadbuckets[k-1] = threadbuckets[k];
3144 threadbuckets[numthreadbuckets-1] = thr;
3145 j--;
3146 }
3147 break;
3148 case BUCKETFILLED:
3149 if ( still < 0 ) still = j;
3150 break;
3151 default:
3152 break;
3153 }
3154 }
3155 if ( still < 0 ) {
3156/*
3157 No buckets to be executed and no buckets FREE.
3158 We must be at the end. Break out of the loop.
3159*/
3160 break;
3161 }
3162 thr = threadbuckets[still];
3163 for ( k = still+1; k < numthreadbuckets; k++ )
3164 threadbuckets[k-1] = threadbuckets[k];
3165 threadbuckets[numthreadbuckets-1] = thr;
3166 goto DoBucket;
3167 }
3168NextBucket:;
3169 }
3170/*
3171 Now the stage one load balancing.
3172 If the load has been readjusted we have again filled buckets.
3173 In that case we jump back in the loop.
3174
3175 Tricky point: when do the workers see the new value of AT.LoadBalancing?
3176 It should activate the locks on thr->busy
3177*/
3178 if ( AC.ThreadBalancing ) {
3179 for ( id = 1; id <= numberofworkers; id++ ) {
3180 AB[id]->T.LoadBalancing = 1;
3181 }
3182 if ( LoadReadjusted() ) goto Finalize;
3183 for ( id = 1; id <= numberofworkers; id++ ) {
3184 AB[id]->T.LoadBalancing = 0;
3185 }
3186 }
3187 if ( AC.ThreadBalancing ) {
3188/*
3189 The AS.Balancing flag should have Generator look for
3190 free workers and apply the "buro" method.
3191
3192 There is still a serious problem.
3193 When for instance a sum_, there may be space created in a local
3194 compiler buffer for a wildcard substitution or whatever.
3195 Compiler buffer execution scribble space.....
3196 This isn't copied along?
3197 Look up ebufnum. There are 12 places with AddRHS!
3198 Problem: one process allocates in ebuf. Then term is given to
3199 other process. It would like to use from this ebuf, but the sender
3200 finishes first and removes the ebuf (and/or overwrites it).
3201
3202 Other problem: local $ variables aren't copied along.
3203*/
3204 AS.Balancing = 0;
3205 }
3206 MasterWaitAll();
3207 AS.Balancing = 0;
3208/*
3209 When we deal with the last expression we can now remove the input
3210 scratch file. This saves potentially much disk space (up to 1/3)
3211*/
3212 if ( LastExpression ) {
3213 UpdateMaxSize();
3214 if ( AR0.infile->handle >= 0 ) {
3215 CloseFile(AR0.infile->handle);
3216 AR0.infile->handle = -1;
3217 remove(AR0.infile->name);
3218 PUTZERO(AR0.infile->POposition);
3219 AR0.infile->POfill = AR0.infile->POfull = AR0.infile->PObuffer;
3220 }
3221 }
3222/*
3223 We order the threads to finish in the MasterMerge routine
3224 It will start with waiting for all threads to finish.
3225 One could make an administration in which threads that have
3226 finished can start already with the final sort but
3227 1: The load balancing should not make this super urgent
3228 2: It would definitely not be very compatible with the second
3229 stage load balancing.
3230*/
3231 oldgzipCompress = AR0.gzipCompress;
3232 AR0.gzipCompress = 0;
3233 if ( AR0.outtohide ) AR0.outfile = AR0.hidefile;
3234 if ( MasterMerge() < 0 ) {
3235 if ( AR0.outtohide ) AR0.outfile = oldoutfile;
3236 AR0.gzipCompress = oldgzipCompress;
3237 goto ProcErr;
3238 }
3239 if ( AR0.outtohide ) AR0.outfile = oldoutfile;
3240 AR0.gzipCompress = oldgzipCompress;
3241/*
3242 Now wait for all threads to be ready to give them the cleaning up signal.
3243 With the new MasterMerge routine we can do the cleanup already automatically
3244 avoiding having to send these signals.
3245*/
3246 MasterWaitAll();
3247 AR0.sLevel--;
3248 for ( id = 1; id < AM.totalnumberofthreads; id++ ) {
3249 if ( GetThread(id) > 0 ) WakeupThread(id,CLEANUPEXPRESSION);
3250 }
3251 e->numdummies = 0;
3252 for ( id = 1; id < AM.totalnumberofthreads; id++ ) {
3253 if ( AB[id]->R.MaxDum - AM.IndDum > e->numdummies )
3254 e->numdummies = AB[id]->R.MaxDum - AM.IndDum;
3255 AR0.expchanged |= AB[id]->R.expchanged;
3256 }
3257/*
3258 And wait for all to be clean.
3259*/
3260 MasterWaitAll();
3261 AT0.WorkPointer = oldworkpointer;
3262 return(0);
3263ProcErr:;
3264 return(-1);
3265}
3266
3267/*
3268 #] ThreadsProcessor :
3269 #[ LoadReadjusted :
3270*/
3289int LoadReadjusted(void)
3290{
3291 ALLPRIVATES *B0 = AB[0];
3292 THREADBUCKET *thr = 0, *thrtogo = 0;
3293 int numtogo, numfree, numbusy, n, nperbucket, extra, i, j, u, bus;
3294 LONG numinput;
3295 WORD *t1, *c1, *t2, *c2, *t3;
3296/*
3297 Start with waiting for at least one free processor.
3298 We don't want the master competing for time when all are busy.
3299*/
3300 while ( topofavailables <= 0 ) MasterWait();
3301/*
3302 Now look for the fullest bucket and make a list of free buckets
3303 The bad part is that most numbers can change at any moment.
3304*/
3305restart:;
3306 numtogo = 0;
3307 numfree = 0;
3308 numbusy = 0;
3309 for ( j = 0; j < numthreadbuckets; j++ ) {
3310 thr = threadbuckets[j];
3311 if ( thr->free == BUCKETFREE || thr->free == BUCKETATEND
3312 || thr->free == BUCKETCOMINGFREE ) {
3313 freebuckets[numfree++] = thr;
3314 }
3315 else if ( thr->type != BUCKETDOINGTERMS ) {}
3316 else if ( thr->totnum > 1 ) { /* never steal from a bucket with one term */
3317 LOCK(thr->lock);
3318 bus = thr->busy;
3319 UNLOCK(thr->lock);
3320 if ( thr->free == BUCKETINUSE ) {
3321 n = thr->totnum-thr->usenum;
3322 if ( bus == BUCKETASSIGNED ) numbusy++;
3323 else if ( ( bus != BUCKETASSIGNED )
3324 && ( n > numtogo ) ) {
3325 numtogo = n;
3326 thrtogo = thr;
3327 }
3328 }
3329 else if ( bus == BUCKETTOBERELEASED
3330 && thr->free == BUCKETRELEASED ) {
3331 freebuckets[numfree++] = thr;
3332 thr->free = BUCKETATEND;
3333 LOCK(thr->lock);
3334 thr->busy = BUCKETPREPARINGTERM;
3335 UNLOCK(thr->lock);
3336 }
3337 }
3338 }
3339 if ( numfree == 0 ) return(0); /* serious problem */
3340 if ( numtogo > 0 ) { /* provisionally there is something to be stolen */
3341 thr = thrtogo;
3342/*
3343 If the number has changed there is good progress.
3344 Maybe there is another thread that needs assistance.
3345 We start all over.
3346*/
3347 if ( thr->totnum-thr->usenum < numtogo ) goto restart;
3348/*
3349 If the thread is in the term loading phase
3350 (thr->busy == BUCKETPREPARINGTERM) we better stay away from it.
3351 We wait now for the thread to be busy, and don't allow it
3352 now to drop out of this state till we are done here.
3353 This all depends on whether AT.LoadBalancing == 1 is seen by
3354 the thread.
3355*/
3356 LOCK(thr->lock);
3357 if ( thr->busy != BUCKETDOINGTERM ) {
3358 UNLOCK(thr->lock);
3359 goto restart;
3360 }
3361 if ( thr->totnum-thr->usenum < numtogo ) {
3362 UNLOCK(thr->lock);
3363 goto restart;
3364 }
3365 thr->free = BUCKETTERMINATED;
3366/*
3367 The above will signal the thread we want to terminate.
3368 Next all effort goes into making sure the landing is soft.
3369 Unfortunately we don't want to wait for a signal, because the thread
3370 may be working for a long time on a single term.
3371*/
3372 if ( thr->usenum == thr->totnum ) {
3373/*
3374 Terminated in the mean time or by now working on the
3375 last term. Try again.
3376*/
3377 thr->free = BUCKETATEND;
3378 UNLOCK(thr->lock);
3379 goto restart;
3380 }
3381 goto intercepted;
3382 }
3383/* This has always been commented. Indeed no lock is held here. */
3384/* UNLOCK(thr->lock); */
3385 if ( numbusy > 0 ) {
3386 /* JD: this avoids large runtimes for tform tests under valgrind.
3387 What seems to happen is we return from here, goto Finalize, and
3388 end up in LoadReadjusted again without the threads having a
3389 chance to update their busy status. Then we end up here again.
3390 Sleep the thread for, say, 1us to allow threads to aquire the lock. */
3391 struct timespec sleeptime;
3392 sleeptime.tv_sec = 0;
3393 sleeptime.tv_nsec = 1000L;
3394 nanosleep(&sleeptime, NULL);
3395 return(1); /* Wait a bit.... */
3396 }
3397 return(0);
3398intercepted:;
3399/*
3400 We intercepted one successfully. Now it becomes interesting. Action:
3401 1: determine how many terms per free bucket.
3402 2: find the first untreated term.
3403 3: put the terms in the free buckets.
3404
3405 Remember: we still have the lock to avoid interference from the thread
3406 that is being robbed. We were holding it and then jumped here with
3407 goto intercepted.
3408*/
3409 numinput = thr->firstterm + thr->usenum;
3410 nperbucket = numtogo / numfree;
3411 extra = numtogo - nperbucket*numfree;
3412 if ( AR0.DeferFlag ) {
3413 t1 = thr->threadbuffer; c1 = thr->compressbuffer; u = thr->usenum;
3414 for ( n = 0; n < thr->usenum; n++ ) { t1 += *t1; c1 += *c1; }
3415 t3 = t1;
3416 if ( extra > 0 ) {
3417 for ( i = 0; i < extra; i++ ) {
3418 thrtogo = freebuckets[i];
3419 t2 = thrtogo->threadbuffer;
3420 c2 = thrtogo->compressbuffer;
3421 thrtogo->free = BUCKETFILLED;
3422 thrtogo->type = BUCKETDOINGTERMS;
3423 thrtogo->totnum = nperbucket+1;
3424 thrtogo->ddterms = 0;
3425 thrtogo->usenum = 0;
3426 thrtogo->busy = BUCKETASSIGNED;
3427 thrtogo->firstterm = numinput;
3428 numinput += nperbucket+1;
3429 for ( n = 0; n <= nperbucket; n++ ) {
3430 j = *t1; NCOPY(t2,t1,j);
3431 j = *c1; NCOPY(c2,c1,j);
3432 thrtogo->deferbuffer[n] = thr->deferbuffer[u++];
3433 }
3434 *t2 = *c2 = 0;
3435 }
3436 }
3437 if ( nperbucket > 0 ) {
3438 for ( i = extra; i < numfree; i++ ) {
3439 thrtogo = freebuckets[i];
3440 t2 = thrtogo->threadbuffer;
3441 c2 = thrtogo->compressbuffer;
3442 thrtogo->free = BUCKETFILLED;
3443 thrtogo->type = BUCKETDOINGTERMS;
3444 thrtogo->totnum = nperbucket;
3445 thrtogo->ddterms = 0;
3446 thrtogo->usenum = 0;
3447 thrtogo->busy = BUCKETASSIGNED;
3448 thrtogo->firstterm = numinput;
3449 numinput += nperbucket;
3450 for ( n = 0; n < nperbucket; n++ ) {
3451 j = *t1; NCOPY(t2,t1,j);
3452 j = *c1; NCOPY(c2,c1,j);
3453 thrtogo->deferbuffer[n] = thr->deferbuffer[u++];
3454 }
3455 *t2 = *c2 = 0;
3456 }
3457 }
3458 }
3459 else {
3460 t1 = thr->threadbuffer;
3461 for ( n = 0; n < thr->usenum; n++ ) { t1 += *t1; }
3462 t3 = t1;
3463 if ( extra > 0 ) {
3464 for ( i = 0; i < extra; i++ ) {
3465 thrtogo = freebuckets[i];
3466 t2 = thrtogo->threadbuffer;
3467 thrtogo->free = BUCKETFILLED;
3468 thrtogo->type = BUCKETDOINGTERMS;
3469 thrtogo->totnum = nperbucket+1;
3470 thrtogo->ddterms = 0;
3471 thrtogo->usenum = 0;
3472 thrtogo->busy = BUCKETASSIGNED;
3473 thrtogo->firstterm = numinput;
3474 numinput += nperbucket+1;
3475 for ( n = 0; n <= nperbucket; n++ ) {
3476 j = *t1; NCOPY(t2,t1,j);
3477 }
3478 *t2 = 0;
3479 }
3480 }
3481 if ( nperbucket > 0 ) {
3482 for ( i = extra; i < numfree; i++ ) {
3483 thrtogo = freebuckets[i];
3484 t2 = thrtogo->threadbuffer;
3485 thrtogo->free = BUCKETFILLED;
3486 thrtogo->type = BUCKETDOINGTERMS;
3487 thrtogo->totnum = nperbucket;
3488 thrtogo->ddterms = 0;
3489 thrtogo->usenum = 0;
3490 thrtogo->busy = BUCKETASSIGNED;
3491 thrtogo->firstterm = numinput;
3492 numinput += nperbucket;
3493 for ( n = 0; n < nperbucket; n++ ) {
3494 j = *t1; NCOPY(t2,t1,j);
3495 }
3496 *t2 = 0;
3497 }
3498 }
3499 }
3500 *t3 = 0; /* This is some form of extra insurance */
3501 if ( thr->free == BUCKETRELEASED && thr->busy == BUCKETTOBERELEASED ) {
3502 thr->free = BUCKETATEND; thr->busy = BUCKETPREPARINGTERM;
3503 }
3504 UNLOCK(thr->lock);
3505 return(1);
3506}
3507
3508/*
3509 #] LoadReadjusted :
3510 #[ SortStrategy :
3511*/
3544/*
3545 #] SortStrategy :
3546 #[ PutToMaster :
3547*/
3570int PutToMaster(PHEAD WORD *term)
3571{
3572 int i,j,nexti,ret = 0;
3573 int urgent = 0;
3574 WORD *t, *fill, *top, zero = 0;
3575 if ( term == 0 ) { /* Mark the end of the expression */
3576 t = &zero; j = 1;
3577 }
3578 else {
3579 t = term; ret = j = *term;
3580 if ( j == 0 ) { j = 1; } /* Just in case there is a spurious end */
3581 }
3582 i = AT.SB.FillBlock; /* The block we are working at */
3583 fill = AT.SB.MasterFill[i]; /* Where we are filling */
3584 top = AT.SB.MasterStop[i]; /* End of the block */
3585
3586 // If there is space in the block, and we have already written MINWRITENUMBEROFTERMS,
3587 // determine if the reading thread is waiting for us by trying to lock the previous
3588 // block. If we manage to lock it, then we still have time to continue filling this
3589 // block. If we can't lock it, the reading thread is waiting for us and we should
3590 // move to the next block ASAP.
3591 if ( j < top - fill && AT.SB.BlockTerms[i] > MINWRITENUMBEROFTERMS ) {
3592 const int prev = ( i == 1 ? AT.SB.MasterNumBlocks : i-1 );
3593 if ( ! pthread_mutex_trylock(&(AT.SB.MasterBlockLock[prev])) ) {
3594 UNLOCK(AT.SB.MasterBlockLock[prev]);
3595 }
3596 else {
3597 urgent = 1;
3598 }
3599 }
3600
3601 // If the term doesn't fit in the current block, or a thread is waiting for us
3602 // (and we've already written at least MINWRITENUMBEROFTERMS), move to the next:
3603 if ( ( j >= top - fill ) || urgent ) {
3604 nexti = i+1;
3605 if ( nexti > AT.SB.MasterNumBlocks ) {
3606 nexti = 1;
3607 }
3608 LOCK(AT.SB.MasterBlockLock[nexti]);
3609 UNLOCK(AT.SB.MasterBlockLock[i]);
3610 AT.SB.MasterFill[i] = AT.SB.MasterStart[i];
3611 AT.SB.FillBlock = i = nexti;
3612 fill = AT.SB.MasterStart[i];
3613 top = AT.SB.MasterStop[i];
3614 if ( AT.SB.BlockTerms[i] != 0 ) {
3615 // In this case, there has been an accounting error in a previous use
3616 // of this block. Blocks that have been read from and unlocked, should
3617 // have BlockTerms == 0.
3618 MLOCK(ErrorMessageLock);
3619 MesPrint("Error in PutToMaster, starting a block with BlockTerms != 0");
3620 MUNLOCK(ErrorMessageLock);
3621 Terminate(-1);
3622 }
3623 }
3624
3625 NCOPY(fill, t, j);
3626 AT.SB.BlockTerms[i]++;
3627 AT.SB.MasterFill[i] = fill;
3628 return(ret);
3629}
3630
3631/*
3632 #] PutToMaster :
3633 #[ SortBotOut :
3634*/
3635
3636#ifdef WITHSORTBOTS
3637
3646int
3647SortBotOut(PHEAD WORD *term)
3648{
3649 WORD im;
3650
3651 if ( AT.identity != 0 ) return(PutToMaster(BHEAD term));
3652
3653 if ( term == 0 ) {
3654 if ( FlushOut(&SortBotPosition,AR.outfile,1) ) return(-1);
3655 ADDPOS(AT.SS->SizeInFile[0],1);
3656 return(0);
3657 }
3658 else {
3659 numberofterms++;
3660 if ( ( im = PutOut(BHEAD term,&SortBotPosition,AR.outfile,1) ) < 0 ) {
3661 MLOCK(ErrorMessageLock);
3662 MesPrint("Called from MasterMerge/SortBotOut");
3663 MUNLOCK(ErrorMessageLock);
3664 return(-1);
3665 }
3666 ADDPOS(AT.SS->SizeInFile[0],im);
3667 return(im);
3668 }
3669}
3670
3671#endif
3672
3673/*
3674 #] SortBotOut :
3675 #[ MasterMerge :
3676*/
3694int MasterMerge(void)
3695{
3696 ALLPRIVATES *B0 = AB[0], *B = 0;
3697 SORTING *S = AT0.SS;
3698 WORD **poin, **poin2, ul, k, i, im, *m1, j;
3699 WORD lpat, mpat, level, l1, l2, r1, r2, r3, c;
3700 WORD *m2, *m3, r31, r33, ki, *rr;
3701 UWORD *coef;
3702 POSITION position;
3703 FILEHANDLE *fin, *fout;
3704#ifdef WITHSORTBOTS
3705 if ( numberofworkers > 2 ) return(SortBotMasterMerge());
3706#endif
3707 fin = &S->file;
3708 if ( AR0.PolyFun == 0 ) { S->PolyFlag = 0; }
3709 else if ( AR0.PolyFunType == 1 ) { S->PolyFlag = 1; }
3710 else if ( AR0.PolyFunType == 2 ) {
3711 if ( AR0.PolyFunExp == 2
3712 || AR0.PolyFunExp == 3 ) S->PolyFlag = 1;
3713 else S->PolyFlag = 2;
3714 }
3715 S->TermsLeft = 0;
3716 coef = AN0.SoScratC;
3717 poin = S->poina; poin2 = S->poin2a;
3718 rr = AR0.CompressPointer;
3719 *rr = 0;
3720/*
3721 #[ Setup :
3722*/
3723 S->inNum = numberofthreads;
3724 fout = AR0.outfile;
3725/*
3726 Load the patches. The threads have to finish their sort first.
3727*/
3728 S->lPatch = S->inNum - 1;
3729/*
3730 Claim all zero blocks. We need them anyway.
3731 In principle the workers should never get into these.
3732 We also claim all last blocks. This is a safety procedure that
3733 should prevent the workers from working their way around the clock
3734 before the master gets started again.
3735*/
3736 AS.MasterSort = 1;
3737 numberclaimed = 0;
3738 for ( i = 1; i <= S->lPatch; i++ ) {
3739 B = AB[i];
3740 LOCK(AT.SB.MasterBlockLock[0]);
3741 LOCK(AT.SB.MasterBlockLock[AT.SB.MasterNumBlocks]);
3742 }
3743/*
3744 Now wake up the threads and have them start their final sorting.
3745 They should start with claiming their block and the master is
3746 not allowed to continue until that has been done.
3747 This waiting of the master will be done below in MasterWaitAllBlocks
3748*/
3749 for ( i = 0; i < S->lPatch; i++ ) {
3750 GetThread(i+1);
3751 WakeupThread(i+1,FINISHEXPRESSION);
3752 }
3753/*
3754 Prepare the output file.
3755*/
3756 if ( fout->handle >= 0 ) {
3757 PUTZERO(position);
3758 SeekFile(fout->handle,&position,SEEK_END);
3759 ADDPOS(position,((fout->POfill-fout->PObuffer)*sizeof(WORD)));
3760 }
3761 else {
3762 SETBASEPOSITION(position,(fout->POfill-fout->PObuffer)*sizeof(WORD));
3763 }
3764/*
3765 Wait for all threads to finish loading their first block.
3766*/
3767 MasterWaitAllBlocks();
3768/*
3769 Claim all first blocks.
3770 We don't release the last blocks.
3771 The strategy is that we always keep the previous block.
3772 In principle it looks like it isn't needed for the last block but
3773 actually it is to keep the front from overrunning the tail when writing.
3774*/
3775 for ( i = 1; i <= S->lPatch; i++ ) {
3776 B = AB[i];
3777 LOCK(AT.SB.MasterBlockLock[1]);
3778 AT.SB.MasterBlock = 1;
3779 }
3780/*
3781 #] Setup :
3782
3783 Now construct the tree:
3784*/
3785 lpat = 1;
3786 do { lpat <<= 1; } while ( lpat < S->lPatch );
3787 mpat = ( lpat >> 1 ) - 1;
3788 k = lpat - S->lPatch;
3789/*
3790 k is the number of empty places in the tree. they will
3791 be at the even positions from 2 to 2*k
3792*/
3793 for ( i = 1; i < lpat; i++ ) { S->tree[i] = -1; }
3794 for ( i = 1; i <= k; i++ ) {
3795 im = ( i * 2 ) - 1;
3796 poin[im] = AB[i]->T.SB.MasterStart[AB[i]->T.SB.MasterBlock];
3797 poin2[im] = poin[im] + *(poin[im]);
3798 S->used[i] = im;
3799 S->ktoi[im] = i-1;
3800 S->tree[mpat+i] = 0;
3801 poin[im-1] = poin2[im-1] = 0;
3802 }
3803 for ( i = (k*2)+1; i <= lpat; i++ ) {
3804 S->used[i-k] = i;
3805 S->ktoi[i] = i-k-1;
3806 poin[i] = AB[i-k]->T.SB.MasterStart[AB[i-k]->T.SB.MasterBlock];
3807 poin2[i] = poin[i] + *(poin[i]);
3808 }
3809/*
3810 the array poin tells the position of the i-th element of the S->tree
3811 'S->used' is a stack with the S->tree elements that need to be entered
3812 into the S->tree. at the beginning this is S->lPatch. during the
3813 sort there will be only very few elements.
3814 poin2 is the next value of poin. it has to be determined
3815 before the comparisons as the position or the size of the
3816 term indicated by poin may change.
3817 S->ktoi translates a S->tree element back to its stream number.
3818
3819 start the sort
3820*/
3821 level = S->lPatch;
3822/*
3823 introduce one term
3824*/
3825OneTerm:
3826 k = S->used[level];
3827 i = k + lpat - 1;
3828 if ( !*(poin[k]) ) {
3829 // Stream k has hit the end-of-stream "0". We still need to decrement
3830 // BlockTerms, which includes the marker in the count.
3831 ki = S->ktoi[k];
3832 AB[ki+1]->T.SB.BlockTerms[AB[ki+1]->T.SB.MasterBlock]--;
3833 do {
3834 if ( !( i >>= 1 ) ) {
3835 goto EndOfMerge;
3836 }
3837 } while ( !S->tree[i] );
3838 if ( S->tree[i] == -1 ) {
3839 S->tree[i] = 0;
3840 level--;
3841 goto OneTerm;
3842 }
3843 k = S->tree[i];
3844 S->used[level] = k;
3845 S->tree[i] = 0;
3846 }
3847/*
3848 move terms down the tree
3849*/
3850 while ( i >>= 1 ) {
3851 if ( S->tree[i] > 0 ) {
3852 if ( ( c = CompareTerms(B0, poin[S->tree[i]],poin[k],(WORD)0) ) > 0 ) {
3853/*
3854 S->tree[i] is the smaller. Exchange and go on.
3855*/
3856 S->used[level] = S->tree[i];
3857 S->tree[i] = k;
3858 k = S->used[level];
3859 }
3860 else if ( !c ) { /* Terms are equal */
3861/*
3862 S->TermsLeft--;
3863 Here the terms are equal and their coefficients
3864 have to be added.
3865*/
3866 l1 = *( m1 = poin[S->tree[i]] );
3867 l2 = *( m2 = poin[k] );
3868 if ( S->PolyWise ) { /* Here we work with PolyFun */
3869 WORD *tt1, *w;
3870 tt1 = m1;
3871 m1 += S->PolyWise;
3872 m2 += S->PolyWise;
3873 if ( S->PolyFlag == 2 ) {
3874 w = poly_ratfun_add(B0,m1,m2);
3875 if ( *tt1 + w[1] - m1[1] > AM.MaxTer/((LONG)sizeof(WORD)) ) {
3876 MLOCK(ErrorMessageLock);
3877 MesPrint("Term too complex in PolyRatFun addition. MaxTermSize of %10l is too small",AM.MaxTer);
3878 MUNLOCK(ErrorMessageLock);
3879 Terminate(-1);
3880 }
3881 AT0.WorkPointer = w;
3882 if ( w[FUNHEAD] == -SNUMBER && w[FUNHEAD+1] == 0 && w[1] > FUNHEAD ) {
3883 goto cancelled;
3884 }
3885 }
3886 else {
3887 w = AT0.WorkPointer;
3888 if ( w + m1[1] + m2[1] > AT0.WorkTop ) {
3889 MLOCK(ErrorMessageLock);
3890 MesPrint("MasterMerge: A WorkSpace of %10l is too small",AM.WorkSize);
3891 MUNLOCK(ErrorMessageLock);
3892 Terminate(-1);
3893 }
3894 AddArgs(B0,m1,m2,w);
3895 }
3896 r1 = w[1];
3897 if ( r1 <= FUNHEAD
3898 || ( w[FUNHEAD] == -SNUMBER && w[FUNHEAD+1] == 0 ) )
3899 { goto cancelled; }
3900 if ( r1 == m1[1] ) {
3901 NCOPY(m1,w,r1);
3902 }
3903 else if ( r1 < m1[1] ) {
3904 r2 = m1[1] - r1;
3905 m2 = w + r1;
3906 m1 += m1[1];
3907 while ( --r1 >= 0 ) *--m1 = *--m2;
3908 m2 = m1 - r2;
3909 r1 = S->PolyWise;
3910 while ( --r1 >= 0 ) *--m1 = *--m2;
3911 *m1 -= r2;
3912 poin[S->tree[i]] = m1;
3913 }
3914 else {
3915 // Here we are writing the new merged term *before* the original start of term1.
3916 // We can always do this, since before term1 there is previous term data of this
3917 // block, or the previous block, for which we are holding a lock. This requires
3918 // the existence of "block 0", if term1 is the first term of block 1!
3919 // It also requires the blocks to be contiguous in memory; we can't allocate
3920 // separate memory regions for each block without larger-scale changes.
3921 r2 = r1 - m1[1];
3922 m2 = tt1 - r2;
3923 r1 = S->PolyWise;
3924 m1 = tt1;
3925 *m1 += r2;
3926 poin[S->tree[i]] = m2;
3927 NCOPY(m2,m1,r1);
3928 r1 = w[1];
3929 NCOPY(m2,w,r1);
3930 }
3931 }
3932#ifdef WITHFLOAT
3933 else if ( AT.SortFloatMode ) {
3934 WORD *term1, *term2;
3935 term1 = poin[S->tree[i]];
3936 term2 = poin[k];
3937 if ( MergeWithFloat(B0, &term1,&term2) == 0 )
3938 goto cancelled;
3939 poin[S->tree[i]] = term1;
3940 }
3941#endif
3942 else {
3943 r1 = *( m1 += l1 - 1 );
3944 m1 -= ABS(r1) - 1;
3945 r1 = ( ( r1 > 0 ) ? (r1-1) : (r1+1) ) >> 1;
3946 r2 = *( m2 += l2 - 1 );
3947 m2 -= ABS(r2) - 1;
3948 r2 = ( ( r2 > 0 ) ? (r2-1) : (r2+1) ) >> 1;
3949
3950 if ( AddRat(B0,(UWORD *)m1,r1,(UWORD *)m2,r2,coef,&r3) ) {
3951 MLOCK(ErrorMessageLock);
3952 MesCall("MasterMerge");
3953 MUNLOCK(ErrorMessageLock);
3954 SETERROR(-1)
3955 }
3956
3957 if ( AN.ncmod != 0 ) {
3958 if ( ( AC.modmode & POSNEG ) != 0 ) {
3959 NormalModulus(coef,&r3);
3960 }
3961 else if ( BigLong(coef,r3,(UWORD *)AC.cmod,ABS(AN.ncmod)) >= 0 ) {
3962 WORD ii;
3963 SubPLon(coef,r3,(UWORD *)AC.cmod,ABS(AN.ncmod),coef,&r3);
3964 coef[r3] = 1;
3965 for ( ii = 1; ii < r3; ii++ ) coef[r3+ii] = 0;
3966 }
3967 }
3968 r3 *= 2;
3969 r33 = ( r3 > 0 ) ? ( r3 + 1 ) : ( r3 - 1 );
3970 if ( r3 < 0 ) r3 = -r3;
3971 if ( r1 < 0 ) r1 = -r1;
3972 r1 *= 2;
3973 r31 = r3 - r1;
3974 if ( !r3 ) { /* Terms cancel */
3975cancelled:
3976 ul = S->used[level] = S->tree[i];
3977 S->tree[i] = -1;
3978/*
3979 We skip to the next term in stream ul
3980*/
3981 im = *poin2[ul];
3982 poin[ul] = poin2[ul];
3983 ki = S->ktoi[ul];
3984 AB[ki+1]->T.SB.BlockTerms[AB[ki+1]->T.SB.MasterBlock]--;
3985 if ( AB[ki+1]->T.SB.BlockTerms[AB[ki+1]->T.SB.MasterBlock] == 0 ) {
3986/*
3987 We made it to the end of the block. We have to
3988 release the previous block and claim the next.
3989*/
3990 B = AB[ki+1];
3991 i = AT.SB.MasterBlock;
3992 if ( i == 1 ) {
3993 UNLOCK(AT.SB.MasterBlockLock[AT.SB.MasterNumBlocks]);
3994 }
3995 else {
3996 UNLOCK(AT.SB.MasterBlockLock[i-1]);
3997 }
3998 if ( i == AT.SB.MasterNumBlocks ) {
3999 i = 1;
4000 }
4001 else { i++; }
4002 LOCK(AT.SB.MasterBlockLock[i]);
4003 AT.SB.MasterBlock = i;
4004 poin[ul] = AT.SB.MasterStart[i];
4005 im = *poin[ul];
4006 poin2[ul] = poin[ul] + im;
4007 }
4008 else {
4009 poin2[ul] += im;
4010 }
4011 S->used[++level] = k;
4012 }
4013 else if ( !r31 ) { /* copy coef into term1 */
4014 goto CopCof2;
4015 }
4016 else if ( r31 < 0 ) { /* copy coef into term1
4017 and adjust the length of term1 */
4018 goto CopCoef;
4019 }
4020 else {
4021/*
4022 this is the dreaded calamity.
4023 is there enough space?
4024*/
4025 if( (poin[S->tree[i]]+l1+r31) >= poin2[S->tree[i]] ) {
4026/*
4027 no space! now the special trick for which
4028 we left 2*maxlng spaces open at the beginning
4029 of each patch.
4030*/
4031 if ( (l1 + r31)*((LONG)sizeof(WORD)) >= AM.MaxTer ) {
4032 MLOCK(ErrorMessageLock);
4033 MesPrint("MasterMerge: Coefficient overflow during sort");
4034 MUNLOCK(ErrorMessageLock);
4035 goto ReturnError;
4036 }
4037 m2 = poin[S->tree[i]];
4038 m3 = ( poin[S->tree[i]] -= r31 );
4039 do { *m3++ = *m2++; } while ( m2 < m1 );
4040 m1 = m3;
4041 }
4042CopCoef:
4043 *(poin[S->tree[i]]) += r31;
4044CopCof2:
4045 m2 = (WORD *)coef; im = r3;
4046 NCOPY(m1,m2,im);
4047 *m1 = r33;
4048 }
4049 }
4050/*
4051 Now skip to the next term in stream k.
4052*/
4053NextTerm:
4054 im = poin2[k][0];
4055 poin[k] = poin2[k];
4056 ki = S->ktoi[k];
4057 AB[ki+1]->T.SB.BlockTerms[AB[ki+1]->T.SB.MasterBlock]--;
4058 if ( AB[ki+1]->T.SB.BlockTerms[AB[ki+1]->T.SB.MasterBlock] == 0 ) {
4059/*
4060 We made it to the end of the block. We have to
4061 release the previous block and claim the next.
4062*/
4063 B = AB[ki+1];
4064 i = AT.SB.MasterBlock;
4065 if ( i == 1 ) {
4066 UNLOCK(AT.SB.MasterBlockLock[AT.SB.MasterNumBlocks]);
4067 }
4068 else {
4069 UNLOCK(AT.SB.MasterBlockLock[i-1]);
4070 }
4071 if ( i == AT.SB.MasterNumBlocks ) {
4072 i = 1;
4073 }
4074 else { i++; }
4075 LOCK(AT.SB.MasterBlockLock[i]);
4076 AT.SB.MasterBlock = i;
4077 poin[k] = AT.SB.MasterStart[i];
4078 im = *poin[k];
4079 poin2[k] = poin[k] + im;
4080 }
4081 else {
4082 poin2[k] += im;
4083 }
4084 goto OneTerm;
4085 }
4086 }
4087 else if ( S->tree[i] < 0 ) {
4088 S->tree[i] = k;
4089 level--;
4090 goto OneTerm;
4091 }
4092 }
4093/*
4094 found the smallest in the set. indicated by k.
4095 write to its destination.
4096*/
4097 S->TermsLeft++;
4098 if ( ( im = PutOut(B0,poin[k],&position,fout,1) ) < 0 ) {
4099 MLOCK(ErrorMessageLock);
4100 MesPrint("Called from MasterMerge with k = %d (stream %d)",k,S->ktoi[k]);
4101 MUNLOCK(ErrorMessageLock);
4102 goto ReturnError;
4103 }
4104 ADDPOS(S->SizeInFile[0],im);
4105 goto NextTerm;
4106EndOfMerge:
4107 if ( FlushOut(&position,fout,1) ) goto ReturnError;
4108 ADDPOS(S->SizeInFile[0],1);
4109 CloseFile(fin->handle);
4110 remove(fin->name);
4111 fin->handle = -1;
4112 position = S->SizeInFile[0];
4113 MULPOS(position,sizeof(WORD));
4114
4115 // Collect global sort statistics information from the threads.
4116 // The total GenTerms is the sum of the thread GenTerms.
4117 // The total small/large buffer sort info is the sum of the thread info.
4118 // The total comparison count is the sum of the thread counts.
4119 // The total unsorted size is the sum of the total generated terms sizes
4120 // The total maximal term size is the maximum of all maximal term sizes
4121 S->GenTerms = 0;
4122 for ( j = 1; j <= numberofworkers; j++ ) {
4123 S->GenTerms += AB[j]->T.SS->GenTerms;
4124 S->verbComparisons += AB[j]->T.SS->verbComparisons;
4125 if ( S->verbMaxTermSize < AB[j]->T.SS->verbMaxTermSize )
4126 S->verbMaxTermSize = AB[j]->T.SS->verbMaxTermSize;
4127 S->verbSBsortTerms += AB[j]->T.SS->verbSBsortTerms;
4128 S->verbSBsortCap += AB[j]->T.SS->verbSBsortCap;
4129 S->verbLBsortPatches += AB[j]->T.SS->verbLBsortPatches;
4130 S->verbLBsortCap += AB[j]->T.SS->verbLBsortCap;
4131 S->verbUnsortedSize += AB[j]->T.SS->verbUnsortedSize;
4132 }
4133
4134 WriteStats(&position,STATSPOSTSORT,NOCHECKLOGTYPE);
4135 Expressions[AR0.CurExpr].counter = S->TermsLeft;
4136 Expressions[AR0.CurExpr].size = position;
4137/*
4138 Release all locks
4139*/
4140 for ( i = 1; i <= S->lPatch; i++ ) {
4141 B = AB[i];
4142 UNLOCK(AT.SB.MasterBlockLock[0]);
4143 if ( AT.SB.MasterBlock == 1 ) {
4144 UNLOCK(AT.SB.MasterBlockLock[AT.SB.MasterNumBlocks]);
4145 }
4146 else {
4147 UNLOCK(AT.SB.MasterBlockLock[AT.SB.MasterBlock-1]);
4148 }
4149 UNLOCK(AT.SB.MasterBlockLock[AT.SB.MasterBlock]);
4150 }
4151 AS.MasterSort = 0;
4152 return(0);
4153ReturnError:
4154 for ( i = 1; i <= S->lPatch; i++ ) {
4155 B = AB[i];
4156 UNLOCK(AT.SB.MasterBlockLock[0]);
4157 if ( AT.SB.MasterBlock == 1 ) {
4158 UNLOCK(AT.SB.MasterBlockLock[AT.SB.MasterNumBlocks]);
4159 }
4160 else {
4161 UNLOCK(AT.SB.MasterBlockLock[AT.SB.MasterBlock-1]);
4162 }
4163 UNLOCK(AT.SB.MasterBlockLock[AT.SB.MasterBlock]);
4164 }
4165 AS.MasterSort = 0;
4166 return(-1);
4167}
4168
4169/*
4170 #] MasterMerge :
4171 #[ SortBotMasterMerge :
4172*/
4173
4174#ifdef WITHSORTBOTS
4175
4191int SortBotMasterMerge(void)
4192{
4193 FILEHANDLE *fin, *fout;
4194 ALLPRIVATES *B = AB[0], *BB;
4195 POSITION position;
4196 SORTING *S = AT.SS;
4197 int i, j;
4198/*
4199 Get the sortbots get to claim their writing blocks.
4200 We have to wait till all have been claimed because they also have to
4201 claim the last writing blocks of the workers to prevent the head of
4202 the circular buffer to overrun the tail.
4203
4204 Before waiting we can do some needed initializations.
4205 Also the master has to claim the last writing blocks of its input.
4206*/
4207 topsortbotavailables = 0;
4208 for ( i = numberofworkers+1; i <= numberofworkers+numberofsortbots; i++ ) {
4209 WakeupThread(i,INISORTBOT);
4210 }
4211
4212 AS.MasterSort = 1;
4213 fout = AR.outfile;
4214 numberofterms = 0;
4215 AR.CompressPointer[0] = 0;
4216 numberclaimed = 0;
4217 BB = AB[AT.SortBotIn1];
4218 LOCK(BB->T.SB.MasterBlockLock[BB->T.SB.MasterNumBlocks]);
4219 BB = AB[AT.SortBotIn2];
4220 LOCK(BB->T.SB.MasterBlockLock[BB->T.SB.MasterNumBlocks]);
4221
4222 MasterWaitAllSortBots();
4223/*
4224 Now we can start up the workers. They will claim their writing blocks.
4225 Here the master will wait till all writing blocks have been claimed.
4226*/
4227 for ( i = 1; i <= numberofworkers; i++ ) {
4228 j = GetThread(i);
4229 WakeupThread(i,FINISHEXPRESSION);
4230 }
4231/*
4232 Prepare the output file in the mean time.
4233*/
4234 if ( fout->handle >= 0 ) {
4235 PUTZERO(SortBotPosition);
4236 SeekFile(fout->handle,&SortBotPosition,SEEK_END);
4237 ADDPOS(SortBotPosition,((fout->POfill-fout->PObuffer)*sizeof(WORD)));
4238 }
4239 else {
4240 SETBASEPOSITION(SortBotPosition,(fout->POfill-fout->PObuffer)*sizeof(WORD));
4241 }
4242 MasterWaitAllBlocks();
4243/*
4244 Now we can start the sortbots after which the master goes in
4245 sortbot mode to do its part of the job (the very final merge and
4246 the writing to output file).
4247*/
4248 topsortbotavailables = 0;
4249 for ( i = numberofworkers+1; i <= numberofworkers+numberofsortbots; i++ ) {
4250 WakeupThread(i,RUNSORTBOT);
4251 }
4252 if ( SortBotMerge(BHEAD0) ) {
4253 MLOCK(ErrorMessageLock);
4254 MesPrint("Called from SortBotMasterMerge");
4255 MUNLOCK(ErrorMessageLock);
4256 AS.MasterSort = 0;
4257 return(-1);
4258 }
4259/*
4260 And next the cleanup
4261*/
4262 if ( S->file.handle >= 0 )
4263 {
4264 fin = &S->file;
4265 CloseFile(fin->handle);
4266 remove(fin->name);
4267 fin->handle = -1;
4268 }
4269 position = S->SizeInFile[0];
4270 MULPOS(position,sizeof(WORD));
4271
4272 // Collect global sort statistics information from the threads.
4273 // The total GenTerms is the sum of the thread GenTerms.
4274 // The total small/large buffer sort info is the sum of the thread info.
4275 // The total comparison count is the sum of the thread and sortbot counts.
4276 // The total unsorted size is the sum of the total generated terms sizes
4277 // The total maximal term size is the maximum of all maximal term sizes
4278 S->GenTerms = 0;
4279 for ( j = 1; j <= numberofworkers; j++ ) {
4280 S->GenTerms += AB[j]->T.SS->GenTerms;
4281 S->verbComparisons += AB[j]->T.SS->verbComparisons;
4282 if ( S->verbMaxTermSize < AB[j]->T.SS->verbMaxTermSize )
4283 S->verbMaxTermSize = AB[j]->T.SS->verbMaxTermSize;
4284 S->verbSBsortTerms += AB[j]->T.SS->verbSBsortTerms;
4285 S->verbSBsortCap += AB[j]->T.SS->verbSBsortCap;
4286 S->verbLBsortPatches += AB[j]->T.SS->verbLBsortPatches;
4287 S->verbLBsortCap += AB[j]->T.SS->verbLBsortCap;
4288 S->verbUnsortedSize += AB[j]->T.SS->verbUnsortedSize;
4289 }
4290 for ( j = numberofworkers+1; j <= numberofworkers+numberofsortbots; j++ ) {
4291 S->verbComparisons += AB[j]->T.SS->verbComparisons;
4292 if ( S->verbMaxTermSize < AB[j]->T.SS->verbMaxTermSize )
4293 S->verbMaxTermSize = AB[j]->T.SS->verbMaxTermSize;
4294 }
4295
4296 S->TermsLeft = numberofterms;
4297 WriteStats(&position,STATSPOSTSORT,NOCHECKLOGTYPE);
4298 Expressions[AR.CurExpr].counter = S->TermsLeft;
4299 Expressions[AR.CurExpr].size = position;
4300 AS.MasterSort = 0;
4301/*
4302 The next statement is to prevent one of the sortbots not having
4303 completely cleaned up before the next module starts.
4304 If this statement is omitted every once in a while one of the sortbots
4305 is still running when the next expression starts and misses its
4306 initialization. The result is usually disastrous.
4307*/
4308 MasterWaitAllSortBots();
4309
4310 return(0);
4311}
4312
4313#endif
4314
4315/*
4316 #] SortBotMasterMerge :
4317 #[ SortBotMerge :
4318*/
4319
4320#ifdef WITHSORTBOTS
4321
4327int SortBotMerge(PHEAD0)
4328{
4329 GETBIDENTITY
4330 ALLPRIVATES *Bin1 = AB[AT.SortBotIn1],*Bin2 = AB[AT.SortBotIn2];
4331 WORD *term1, *term2, *wp;
4332 int blin1, blin2; /* Current block numbers */
4333 int error = 0;
4334 WORD l1, l2, *m1, *m2, *w, r1, r2, r3, r33, r31, *tt1, ii;
4335 WORD *to, *from, im, c;
4336 UWORD *coef;
4337 SORTING *S = AT.SS;
4338#ifdef WITHFLOAT
4339 WORD *fun1, *fun2, *fun3, *tstop1, *tstop2, size1, size2, size3, l3, jj, *m3;
4340#endif
4341/*
4342 Set the pointers to the input terms and the output space
4343*/
4344 coef = AN.SoScratC;
4345 blin1 = 1;
4346 blin2 = 1;
4347 if ( AT.identity == 0 ) {
4348 wp = AT.WorkPointer;
4349 }
4350 else {
4351 wp = AT.WorkPointer = AT.WorkSpace;
4352 }
4353/*
4354 Get the locks for reading the input
4355 This means that we can start once these locks have been cleared
4356 which means that there will be input.
4357*/
4358 LOCK(Bin1->T.SB.MasterBlockLock[blin1]);
4359 LOCK(Bin2->T.SB.MasterBlockLock[blin2]);
4360
4361 term1 = Bin1->T.SB.MasterStart[blin1];
4362 term2 = Bin2->T.SB.MasterStart[blin2];
4363 AT.SB.FillBlock = 1;
4364/*
4365 Now the main loop. Keep going until one of the two hits the end.
4366*/
4367 while ( *term1 && *term2 ) {
4368 if ( ( c = CompareTerms(BHEAD term1,term2,(WORD)0) ) > 0 ) {
4369/*
4370 #[ One is smallest :
4371*/
4372 Bin1->T.SB.BlockTerms[blin1]--;
4373 if ( SortBotOut(BHEAD term1) < 0 ) {
4374 MLOCK(ErrorMessageLock);
4375 MesPrint("Called from SortBotMerge with thread = %d",AT.identity);
4376 MUNLOCK(ErrorMessageLock);
4377 error = -1;
4378 goto ReturnError;
4379 }
4380 term1 += *term1;
4381 if ( Bin1->T.SB.BlockTerms[blin1] == 0 ) {
4382 if ( blin1 == 1 ) {
4383 UNLOCK(Bin1->T.SB.MasterBlockLock[Bin1->T.SB.MasterNumBlocks]);
4384 }
4385 else {
4386 UNLOCK(Bin1->T.SB.MasterBlockLock[blin1-1]);
4387 }
4388 if ( blin1 == Bin1->T.SB.MasterNumBlocks ) {
4389 blin1 = 1;
4390 }
4391 else {
4392 blin1++;
4393 }
4394 LOCK(Bin1->T.SB.MasterBlockLock[blin1]);
4395 Bin1->T.SB.MasterBlock = blin1;
4396 term1 = Bin1->T.SB.MasterStart[blin1];
4397 }
4398/*
4399 #] One is smallest :
4400*/
4401 }
4402 else if ( c < 0 ) {
4403/*
4404 #[ Two is smallest :
4405*/
4406 Bin2->T.SB.BlockTerms[blin2]--;
4407 if ( SortBotOut(BHEAD term2) < 0 ) {
4408 MLOCK(ErrorMessageLock);
4409 MesPrint("Called from SortBotMerge with thread = %d",AT.identity);
4410 MUNLOCK(ErrorMessageLock);
4411 error = -1;
4412 goto ReturnError;
4413 }
4414next2:
4415 term2 += *term2;
4416 if ( Bin2->T.SB.BlockTerms[blin2] == 0 ) {
4417 if ( blin2 == 1 ) {
4418 UNLOCK(Bin2->T.SB.MasterBlockLock[Bin2->T.SB.MasterNumBlocks]);
4419 }
4420 else {
4421 UNLOCK(Bin2->T.SB.MasterBlockLock[blin2-1]);
4422 }
4423 if ( blin2 == Bin2->T.SB.MasterNumBlocks ) {
4424 blin2 = 1;
4425 }
4426 else {
4427 blin2++;
4428 }
4429 LOCK(Bin2->T.SB.MasterBlockLock[blin2]);
4430 Bin2->T.SB.MasterBlock = blin2;
4431 term2 = Bin2->T.SB.MasterStart[blin2];
4432 }
4433/*
4434 #] Two is smallest :
4435*/
4436 }
4437 else {
4438/*
4439 #[ Equal :
4440*/
4441 Bin1->T.SB.BlockTerms[blin1]--;
4442 Bin2->T.SB.BlockTerms[blin2]--;
4443 l1 = *( m1 = term1 );
4444 l2 = *( m2 = term2 );
4445 if ( S->PolyWise ) { /* Here we work with PolyFun */
4446 tt1 = m1;
4447 m1 += S->PolyWise;
4448 m2 += S->PolyWise;
4449 if ( S->PolyFlag == 2 ) {
4450 AT.WorkPointer = wp;
4451 w = poly_ratfun_add(BHEAD m1,m2);
4452 if ( *tt1 + w[1] - m1[1] > AM.MaxTer/((LONG)sizeof(WORD)) ) {
4453 MLOCK(ErrorMessageLock);
4454 MesPrint("Term too complex in PolyRatFun addition. MaxTermSize of %10l is too small",AM.MaxTer);
4455 MUNLOCK(ErrorMessageLock);
4456 Terminate(-1);
4457 }
4458 AT.WorkPointer = wp;
4459 if ( w[FUNHEAD] == -SNUMBER && w[FUNHEAD+1] == 0 && w[1] > FUNHEAD ) {
4460 goto cancelled;
4461 }
4462 }
4463 else {
4464 w = wp;
4465 if ( w + m1[1] + m2[1] > AT.WorkTop ) {
4466 MLOCK(ErrorMessageLock);
4467 MesPrint("SortBotMerge(%d): A Maxtermsize of %10l is too small",
4468 AT.identity,AM.MaxTer/sizeof(WORD));
4469 MesPrint("m1[1] = %d, m2[1] = %d, Space = %l",m1[1],m2[1],(LONG)(AT.WorkTop-wp));
4470 PrintTerm(term1,"term1");
4471 PrintTerm(term2,"term2");
4472 MesPrint("PolyWise = %d",S->PolyWise);
4473 MUNLOCK(ErrorMessageLock);
4474 Terminate(-1);
4475 }
4476 AddArgs(BHEAD m1,m2,w);
4477 }
4478 r1 = w[1];
4479 if ( r1 <= FUNHEAD
4480 || ( w[FUNHEAD] == -SNUMBER && w[FUNHEAD+1] == 0 ) )
4481 { goto cancelled; }
4482 if ( r1 == m1[1] ) {
4483 NCOPY(m1,w,r1);
4484 }
4485 else if ( r1 < m1[1] ) {
4486 r2 = m1[1] - r1;
4487 m2 = w + r1;
4488 m1 += m1[1];
4489 while ( --r1 >= 0 ) *--m1 = *--m2;
4490 m2 = m1 - r2;
4491 r1 = S->PolyWise;
4492 while ( --r1 >= 0 ) *--m1 = *--m2;
4493 *m1 -= r2;
4494 term1 = m1;
4495 }
4496 else {
4497 // Here we are writing the new merged term *before* the original start of term1.
4498 // We can always do this, since before term1 there is previous term data of this
4499 // block, or the previous block, for which we are holding a lock. This requires
4500 // the existence of "block 0", if term1 is the first term of block 1!
4501 // It also requires the blocks to be contiguous in memory; we can't allocate
4502 // separate memory regions for each block without larger-scale changes.
4503 r2 = r1 - m1[1];
4504 m2 = tt1 - r2;
4505 r1 = S->PolyWise;
4506 m1 = tt1;
4507 *m1 += r2;
4508 term1 = m2;
4509 NCOPY(m2,m1,r1);
4510 r1 = w[1];
4511 NCOPY(m2,w,r1);
4512 }
4513 }
4514#ifdef WITHFLOAT
4515 else if ( AT.SortFloatMode ) {
4516/*
4517 The terms are in m1/term1 and m2/term2 and their length in l1 and l2.
4518 We have to locate the floats which have already been
4519 verified in the compare routine. Once we have the new
4520 term we can jump to the code that writes away the
4521 result after adding the rationals.
4522*/
4523 tstop1 = m1+l1; size1 = tstop1[-1]; tstop1 -= ABS(size1);
4524 tstop2 = m2+l2; size2 = tstop2[-1]; tstop2 -= ABS(size2);
4525 if ( AT.SortFloatMode == 3 ) {
4526 fun1 = m1+1;
4527 while ( fun1[0] != FLOATFUN && fun1+fun1[1] < tstop1 ) {
4528 fun1 += fun1[1];
4529 }
4530 if ( size1 < 0 ) fun1[FUNHEAD+3] = -fun1[FUNHEAD+3];
4531 UnpackFloat(aux1,fun1);
4532 fun2 = m2+1;
4533 while ( fun2[0] != FLOATFUN && fun2+fun2[1] < tstop2 ) {
4534 fun2 += fun2[1];
4535 }
4536 if ( size2 < 0 ) fun2[FUNHEAD+3] = -fun2[FUNHEAD+3];
4537 UnpackFloat(aux2,fun2);
4538 }
4539 else if ( AT.SortFloatMode == 1 ) {
4540 fun1 = m1+1;
4541 while ( fun1[0] != FLOATFUN && fun1+fun1[1] < tstop1 ) {
4542 fun1 += fun1[1];
4543 }
4544 if ( size1 < 0 ) fun1[FUNHEAD+3] = -fun1[FUNHEAD+3];
4545 UnpackFloat(aux1,fun1);
4546 fun2 = tstop2;
4547 RatToFloat(aux2,(UWORD *)fun2,size2);
4548 }
4549 else if ( AT.SortFloatMode == 2 ) {
4550 fun1 = tstop1;
4551 RatToFloat(aux1,(UWORD *)fun1,size1);
4552 fun2 = m2+1;
4553 while ( fun2[0] != FLOATFUN && fun2+fun2[1] < tstop2 ) {
4554 fun2 += fun2[1];
4555 }
4556 if ( size2 < 0 ) fun2[FUNHEAD+3] = -fun2[FUNHEAD+3];
4557 UnpackFloat(aux2,fun2);
4558 }
4559 else {
4560 MLOCK(ErrorMessageLock);
4561 MesPrint("Illegal value %d for AT.SortFloatMode in SortBotMerge.",AT.SortFloatMode);
4562 MUNLOCK(ErrorMessageLock);
4563 Terminate(-1);
4564 return(0);
4565 }
4566 mpf_add(aux3,aux1,aux2);
4567 size3 = mpf_sgn(aux3);
4568 if ( size3 == 0 ) { /* Cancelling! Rare! */
4569 goto cancelled;
4570 }
4571 else if ( size3 < 0 ) mpf_neg(aux3,aux3);
4572 fun3 = TermMalloc("MasterMerge");
4573 PackFloat(fun3,aux3);
4574 l3 = fun3[1]+(fun1-m1)+3; /* new size */
4575
4576 if ( l3 != l1 ) {
4577/*
4578 Copy it all to wp
4579*/
4580 if ( (l3)*((LONG)sizeof(WORD)) >= AM.MaxTer ) {
4581 MLOCK(ErrorMessageLock);
4582 MesPrint("MasterMerge: Coefficient overflow during sort");
4583 MUNLOCK(ErrorMessageLock);
4584 goto ReturnError;
4585 }
4586 m3 = wp; m2 = term1;
4587 while ( m2 < fun1 ) *m3++ = *m2++;
4588 for ( jj = 0; jj < fun3[1]; jj++ ) *m3++ = fun3[jj];
4589 *m3++ = 1; *m3++ = 1;
4590 *m3++ = size3 < 0 ? -3: 3;
4591 *wp = m3-wp;
4592 TermFree(fun3,"MasterMerge");
4593 goto PutOutwp;
4594 }
4595 for ( jj = 0; jj < fun3[1]; jj++ ) fun1[jj] = fun3[jj];
4596 fun1 += fun3[1];
4597 *fun1++ = 1; *fun1++ = 1;
4598 *fun1++ = size3 < 0 ? -3: 3;
4599 *term1 = fun1-term1;
4600 TermFree(fun3,"MasterMerge");
4601 }
4602#endif
4603 else {
4604 r1 = *( m1 += l1 - 1 );
4605 m1 -= ABS(r1) - 1;
4606 r1 = ( ( r1 > 0 ) ? (r1-1) : (r1+1) ) >> 1;
4607 r2 = *( m2 += l2 - 1 );
4608 m2 -= ABS(r2) - 1;
4609 r2 = ( ( r2 > 0 ) ? (r2-1) : (r2+1) ) >> 1;
4610
4611 if ( AddRat(BHEAD (UWORD *)m1,r1,(UWORD *)m2,r2,coef,&r3) ) {
4612 MLOCK(ErrorMessageLock);
4613 MesCall("SortBotMerge");
4614 MUNLOCK(ErrorMessageLock);
4615 SETERROR(-1)
4616 }
4617
4618 if ( AN.ncmod != 0 ) {
4619 if ( ( AC.modmode & POSNEG ) != 0 ) {
4620 NormalModulus(coef,&r3);
4621 }
4622 else if ( BigLong(coef,r3,(UWORD *)AC.cmod,ABS(AN.ncmod)) >= 0 ) {
4623 SubPLon(coef,r3,(UWORD *)AC.cmod,ABS(AN.ncmod),coef,&r3);
4624 coef[r3] = 1;
4625 for ( ii = 1; ii < r3; ii++ ) coef[r3+ii] = 0;
4626 }
4627 }
4628 if ( !r3 ) { goto cancelled; }
4629 r3 *= 2;
4630 r33 = ( r3 > 0 ) ? ( r3 + 1 ) : ( r3 - 1 );
4631 if ( r3 < 0 ) r3 = -r3;
4632 if ( r1 < 0 ) r1 = -r1;
4633 r1 *= 2;
4634 r31 = r3 - r1;
4635 if ( !r31 ) { /* copy coef into term1 */
4636 m2 = (WORD *)coef; im = r3;
4637 NCOPY(m1,m2,im);
4638 *m1 = r33;
4639 }
4640 else {
4641 to = wp; from = term1;
4642 while ( from < m1 ) *to++ = *from++;
4643 from = (WORD *)coef; im = r3;
4644 NCOPY(to,from,im);
4645 *to++ = r33;
4646 wp[0] = to - wp;
4647PutOutwp:
4648 if ( SortBotOut(BHEAD wp) < 0 ) {
4649 MLOCK(ErrorMessageLock);
4650 MesPrint("Called from SortBotMerge with thread = %d",AT.identity);
4651 MUNLOCK(ErrorMessageLock);
4652 error = -1;
4653 goto ReturnError;
4654 }
4655 goto cancelled;
4656 }
4657 }
4658 if ( SortBotOut(BHEAD term1) < 0 ) {
4659 MLOCK(ErrorMessageLock);
4660 MesPrint("Called from SortBotMerge with thread = %d",AT.identity);
4661 MUNLOCK(ErrorMessageLock);
4662 error = -1;
4663 goto ReturnError;
4664 }
4665cancelled:; /* Now we need two new terms */
4666 term1 += *term1;
4667 if ( Bin1->T.SB.BlockTerms[blin1] == 0 ) {
4668
4669 if ( blin1 == 1 ) {
4670 UNLOCK(Bin1->T.SB.MasterBlockLock[Bin1->T.SB.MasterNumBlocks]);
4671 }
4672 else {
4673 UNLOCK(Bin1->T.SB.MasterBlockLock[blin1-1]);
4674 }
4675 if ( blin1 == Bin1->T.SB.MasterNumBlocks ) {
4676 blin1 = 1;
4677 }
4678 else {
4679 blin1++;
4680 }
4681 LOCK(Bin1->T.SB.MasterBlockLock[blin1]);
4682 Bin1->T.SB.MasterBlock = blin1;
4683 term1 = Bin1->T.SB.MasterStart[blin1];
4684 }
4685 goto next2;
4686/*
4687 #] Equal :
4688*/
4689 }
4690 }
4691/*
4692 Copy the tail
4693*/
4694 if ( *term1 ) {
4695/*
4696 #[ Tail in one :
4697*/
4698 while ( *term1 ) {
4699 Bin1->T.SB.BlockTerms[blin1]--;
4700 if ( SortBotOut(BHEAD term1) < 0 ) {
4701 MLOCK(ErrorMessageLock);
4702 MesPrint("Called from SortBotMerge with thread = %d",AT.identity);
4703 MUNLOCK(ErrorMessageLock);
4704 error = -1;
4705 goto ReturnError;
4706 }
4707 if ( Bin1->T.SB.BlockTerms[blin1] == 0 ) {
4708
4709 if ( blin1 == 1 ) {
4710 UNLOCK(Bin1->T.SB.MasterBlockLock[Bin1->T.SB.MasterNumBlocks]);
4711 }
4712 else {
4713 UNLOCK(Bin1->T.SB.MasterBlockLock[blin1-1]);
4714 }
4715 if ( blin1 == Bin1->T.SB.MasterNumBlocks ) {
4716 blin1 = 1;
4717 }
4718 else {
4719 blin1++;
4720 }
4721 LOCK(Bin1->T.SB.MasterBlockLock[blin1]);
4722 Bin1->T.SB.MasterBlock = blin1;
4723 term1 = Bin1->T.SB.MasterStart[blin1];
4724 }
4725 else {
4726 term1 += *term1;
4727 }
4728 }
4729/*
4730 #] Tail in one :
4731*/
4732 }
4733 else if ( *term2 ) {
4734/*
4735 #[ Tail in two :
4736*/
4737 while ( *term2 ) {
4738 Bin2->T.SB.BlockTerms[blin2]--;
4739 if ( SortBotOut(BHEAD term2) < 0 ) {
4740 MLOCK(ErrorMessageLock);
4741 MesPrint("Called from SortBotMerge with thread = %d",AT.identity);
4742 MUNLOCK(ErrorMessageLock);
4743 error = -1;
4744 goto ReturnError;
4745 }
4746 if ( Bin2->T.SB.BlockTerms[blin2] == 0 ) {
4747
4748 if ( blin2 == 1 ) {
4749 UNLOCK(Bin2->T.SB.MasterBlockLock[Bin2->T.SB.MasterNumBlocks]);
4750 }
4751 else {
4752 UNLOCK(Bin2->T.SB.MasterBlockLock[blin2-1]);
4753 }
4754 if ( blin2 == Bin2->T.SB.MasterNumBlocks ) {
4755 blin2 = 1;
4756 }
4757 else {
4758 blin2++;
4759 }
4760 LOCK(Bin2->T.SB.MasterBlockLock[blin2]);
4761 Bin2->T.SB.MasterBlock = blin2;
4762 term2 = Bin2->T.SB.MasterStart[blin2];
4763 }
4764 else {
4765 term2 += *term2;
4766 }
4767 }
4768/*
4769 #] Tail in two :
4770*/
4771 }
4772
4773 // Both streams have hit the end-of-stream marker "0". We still need to
4774 // decrement the BlockTerms counters a final time, the marker is included
4775 // in the count.
4776 Bin1->T.SB.BlockTerms[blin1]--;
4777 Bin2->T.SB.BlockTerms[blin2]--;
4778
4779 SortBotOut(BHEAD 0);
4780ReturnError:;
4781/*
4782 Release all locks.
4783*/
4784 UNLOCK(Bin1->T.SB.MasterBlockLock[blin1]);
4785 if ( blin1 > 1 ) {
4786 UNLOCK(Bin1->T.SB.MasterBlockLock[blin1-1]);
4787 }
4788 else {
4789 UNLOCK(Bin1->T.SB.MasterBlockLock[Bin1->T.SB.MasterNumBlocks]);
4790 }
4791 UNLOCK(Bin2->T.SB.MasterBlockLock[blin2]);
4792 if ( blin2 > 1 ) {
4793 UNLOCK(Bin2->T.SB.MasterBlockLock[blin2-1]);
4794 }
4795 else {
4796 UNLOCK(Bin2->T.SB.MasterBlockLock[Bin2->T.SB.MasterNumBlocks]);
4797 }
4798 if ( AT.identity > 0 ) {
4799 UNLOCK(AT.SB.MasterBlockLock[AT.SB.FillBlock]);
4800 }
4801/*
4802 And that was all folks
4803*/
4804 return(error);
4805}
4806
4807#endif
4808
4809/*
4810 #] SortBotMerge :
4811 #[ IniSortBlocks :
4812*/
4813
4814static int SortBlocksInitialized = 0;
4815
4822int IniSortBlocks(int numworkers)
4823{
4824 ALLPRIVATES *B;
4825 SORTING *S;
4826 LONG totalsize, workersize, blocksize, numberofterms;
4827 int maxter, id, j;
4828 int numberofblocks = NUMBEROFBLOCKSINSORT, numparts;
4829 WORD *w;
4830
4831 if ( SortBlocksInitialized ) return(0);
4832 SortBlocksInitialized = 1;
4833 if ( numworkers == 0 ) return(0);
4834
4835#ifdef WITHSORTBOTS
4836 if ( numworkers > 2 ) {
4837 numparts = 2*numworkers - 2;
4838 numberofblocks = numberofblocks/2;
4839 }
4840 else {
4841 numparts = numworkers;
4842 }
4843#else
4844 numparts = numworkers;
4845#endif
4846 S = AM.S0;
4847 totalsize = S->LargeSize + S->SmallEsize;
4848 workersize = totalsize / numparts;
4849 maxter = AM.MaxTer/sizeof(WORD);
4850 blocksize = ( workersize - maxter )/numberofblocks;
4851 numberofterms = blocksize / maxter;
4852 if ( numberofterms < MINIMUMNUMBEROFTERMS ) {
4853/*
4854 This should have been taken care of in RecalcSetups.
4855*/
4856 MesPrint("We have a problem with the size of the blocks in IniSortBlocks");
4857 Terminate(-1);
4858 }
4859/*
4860 Layout: For each worker
4861 block 0: size is maxter WORDS
4862 numberofblocks blocks of size blocksize WORDS
4863*/
4864 w = S->lBuffer;
4865 if ( w == 0 ) w = S->sBuffer;
4866 for ( id = 1; id <= numparts; id++ ) {
4867 B = AB[id];
4868 AT.SB.MasterBlockLock = (pthread_mutex_t *)Malloc1(
4869 sizeof(pthread_mutex_t)*(numberofblocks+1),"MasterBlockLock");
4870 AT.SB.MasterStart = (WORD **)Malloc1(sizeof(WORD *)*(numberofblocks+1)*3,"MasterBlock");
4871 AT.SB.MasterFill = AT.SB.MasterStart + (numberofblocks+1);
4872 AT.SB.MasterStop = AT.SB.MasterFill + (numberofblocks+1);
4873 AT.SB.MasterNumBlocks = numberofblocks;
4874 AT.SB.BlockTerms = (LONG*)Malloc1(sizeof(LONG)*(numberofblocks+1),"BlockTerms");
4875 AT.SB.MasterBlock = 0;
4876 AT.SB.FillBlock = 0;
4877 AT.SB.MasterFill[0] = AT.SB.MasterStart[0] = w;
4878 AT.SB.BlockTerms[0] = 0;
4879 w += maxter;
4880 AT.SB.MasterStop[0] = w;
4881 AT.SB.MasterBlockLock[0] = dummylock;
4882 for ( j = 1; j <= numberofblocks; j++ ) {
4883 AT.SB.MasterFill[j] = AT.SB.MasterStart[j] = w;
4884 AT.SB.BlockTerms[j] = 0;
4885 w += blocksize;
4886 AT.SB.MasterStop[j] = w;
4887 AT.SB.MasterBlockLock[j] = dummylock;
4888 }
4889 }
4890 if ( w > S->sTop2 ) {
4891 MesPrint("Counting problem in IniSortBlocks");
4892 Terminate(-1);
4893 }
4894 return(0);
4895}
4896
4897/*
4898 #] IniSortBlocks :
4899 #[ UpdateSortBlocks :
4900*/
4901
4906int UpdateSortBlocks(int numworkers)
4907{
4908 ALLPRIVATES *B;
4909 SORTING *S;
4910 LONG totalsize, workersize, blocksize, numberofterms;
4911 int maxter, id, j;
4912 int numberofblocks = NUMBEROFBLOCKSINSORT, numparts;
4913 WORD *w;
4914
4915 if ( numworkers == 0 ) return(0);
4916
4917#ifdef WITHSORTBOTS
4918 if ( numworkers > 2 ) {
4919 numparts = 2*numworkers - 2;
4920 numberofblocks = numberofblocks/2;
4921 }
4922 else {
4923 numparts = numworkers;
4924 }
4925#else
4926 numparts = numworkers;
4927#endif
4928 S = AM.S0;
4929 totalsize = S->LargeSize + S->SmallEsize;
4930 workersize = totalsize / numparts;
4931 maxter = AM.MaxTer/sizeof(WORD);
4932 blocksize = ( workersize - maxter )/numberofblocks;
4933 numberofterms = blocksize / maxter;
4934 if ( numberofterms < MINIMUMNUMBEROFTERMS ) {
4935/*
4936 This should have been taken care of in RecalcSetups.
4937*/
4938 MesPrint("We have a problem with the size of the blocks in UpdateSortBlocks");
4939 Terminate(-1);
4940 }
4941/*
4942 Layout: For each worker
4943 block 0: size is maxter WORDS
4944 numberofblocks blocks of size blocksize WORDS
4945*/
4946 w = S->lBuffer;
4947 if ( w == 0 ) w = S->sBuffer;
4948 for ( id = 1; id <= numparts; id++ ) {
4949 B = AB[id];
4950 AT.SB.MasterFill[0] = AT.SB.MasterStart[0] = w;
4951 w += maxter;
4952 AT.SB.MasterStop[0] = w;
4953 for ( j = 1; j <= numberofblocks; j++ ) {
4954 AT.SB.MasterFill[j] = AT.SB.MasterStart[j] = w;
4955 w += blocksize;
4956 AT.SB.MasterStop[j] = w;
4957 }
4958 }
4959 if ( w > S->sTop2 ) {
4960 MesPrint("Counting problem in UpdateSortBlocks");
4961 Terminate(-1);
4962 }
4963 return(0);
4964}
4965
4966/*
4967 #] UpdateSortBlocks :
4968 #[ DefineSortBotTree :
4969*/
4970
4971#ifdef WITHSORTBOTS
4972
4978void DefineSortBotTree(void)
4979{
4980 ALLPRIVATES *B;
4981 int n, i, from;
4982 if ( numberofworkers <= 2 ) return;
4983 n = numberofworkers*2-2;
4984 for ( i = numberofworkers+1, from = 1; i <= n; i++ ) {
4985 B = AB[i];
4986 AT.SortBotIn1 = from++;
4987 AT.SortBotIn2 = from++;
4988 }
4989 B = AB[0];
4990 AT.SortBotIn1 = from++;
4991 AT.SortBotIn2 = from++;
4992}
4993
4994#endif
4995
4996/*
4997 #] DefineSortBotTree :
4998 #[ GetTerm2 :
4999
5000 Routine does a GetTerm but only when a bracket index is involved and
5001 only from brackets that have been judged not suitable for treatment
5002 as complete brackets by a single worker. Whether or not a bracket should
5003 be treated by a single worker is decided by TreatIndexEntry
5004*/
5005
5006WORD GetTerm2(PHEAD WORD *term)
5007{
5008 WORD *ttco, *tt, retval;
5009 LONG n,i;
5010 FILEHANDLE *fi;
5011 EXPRESSIONS e = AN.expr;
5012 BRACKETINFO *b = e->bracketinfo;
5013 BRACKETINDEX *bi = b->indexbuffer;
5014 POSITION where, eonfile = AS.OldOnFile[e-Expressions], bstart, bnext;
5015/*
5016 1: Get the current position.
5017*/
5018 switch ( e->status ) {
5019 case UNHIDELEXPRESSION:
5020 case UNHIDEGEXPRESSION:
5021 case DROPHLEXPRESSION:
5022 case DROPHGEXPRESSION:
5023 case HIDDENLEXPRESSION:
5024 case HIDDENGEXPRESSION:
5025 fi = AR.hidefile;
5026 break;
5027 default:
5028 fi = AR.infile;
5029 break;
5030 }
5031 if ( AR.KeptInHold ) {
5032 retval = GetTerm(BHEAD term);
5033 return(retval);
5034 }
5035 SeekScratch(fi,&where);
5036 if ( AN.lastinindex < 0 ) {
5037/*
5038 We have to test whether we have to do the first bracket
5039*/
5040 if ( ( n = TreatIndexEntry(BHEAD 0) ) <= 0 ) {
5041 AN.lastinindex = n;
5042 where = bi[n].start;
5043 ADD2POS(where,eonfile);
5044 SetScratch(fi,&where);
5045/*
5046 Put the bracket in the Compress buffer.
5047*/
5048 ttco = AR.CompressBuffer;
5049 tt = b->bracketbuffer + bi[0].bracket;
5050 i = *tt;
5051 NCOPY(ttco,tt,i)
5052 AR.CompressPointer = ttco;
5053 retval = GetTerm(BHEAD term);
5054 return(retval);
5055 }
5056 else AN.lastinindex = n-1;
5057 }
5058/*
5059 2: Find the corresponding index number
5060 a: test whether it is in the current bracket
5061*/
5062 n = AN.lastinindex;
5063 bstart = bi[n].start;
5064 ADD2POS(bstart,eonfile);
5065 bnext = bi[n].next;
5066 ADD2POS(bnext,eonfile);
5067 if ( ISLESSPOS(bstart,where) && ISLESSPOS(where,bnext) ) {
5068 retval = GetTerm(BHEAD term);
5069 return(retval);
5070 }
5071 for ( n++ ; n < b->indexfill; n++ ) {
5072 i = TreatIndexEntry(BHEAD n);
5073 if ( i <= 0 ) {
5074/*
5075 Put the bracket in the Compress buffer.
5076*/
5077 ttco = AR.CompressBuffer;
5078 tt = b->bracketbuffer + bi[n].bracket;
5079 i = *tt;
5080 NCOPY(ttco,tt,i)
5081 AR.CompressPointer = ttco;
5082 AN.lastinindex = n;
5083 where = bi[n].start;
5084 ADD2POS(where,eonfile);
5085 SetScratch(fi,&(where));
5086 retval = GetTerm(BHEAD term);
5087 return(retval);
5088 }
5089 else n += i - 1;
5090 }
5091 return(0);
5092}
5093
5094/*
5095 #] GetTerm2 :
5096 #[ TreatIndexEntry :
5097*/
5106int TreatIndexEntry(PHEAD LONG n)
5107{
5108 BRACKETINFO *b = AN.expr->bracketinfo;
5109 LONG numbra = b->indexfill - 1, i;
5110 LONG totterms;
5111 BRACKETINDEX *bi;
5112 POSITION pos1, average;
5113/*
5114 1: number of the bracket should be such that there is one bucket
5115 for each worker remaining.
5116*/
5117 if ( ( numbra - n ) <= numberofworkers ) return(0);
5118/*
5119 2: size of the bracket contents should be less than what remains in
5120 the expression divided by the number of workers.
5121*/
5122 bi = b->indexbuffer;
5123 DIFPOS(pos1,bi[numbra].next,bi[n].next); /* Size of what remains */
5124 BASEPOSITION(average) = DIVPOS(pos1,(3*numberofworkers));
5125 DIFPOS(pos1,bi[n].next,bi[n].start); /* Size of the current bracket */
5126 if ( ISLESSPOS(average,pos1) ) return(0);
5127/*
5128 It passes.
5129 Now check whether we can do more brackets
5130*/
5131 totterms = bi->termsinbracket;
5132 if ( totterms > 2*AC.ThreadBucketSize ) return(1);
5133 for ( i = 1; i < numbra-n; i++ ) {
5134 DIFPOS(pos1,bi[n+i].next,bi[n].start); /* Size of the combined brackets */
5135 if ( ISLESSPOS(average,pos1) ) return(i);
5136 totterms += bi->termsinbracket;
5137 if ( totterms > 2*AC.ThreadBucketSize ) return(i+1);
5138 }
5139/*
5140 We have a problem at the end of the system. Just do one.
5141*/
5142 return(1);
5143}
5144
5145/*
5146 #] TreatIndexEntry :
5147 #[ SetHideFiles :
5148*/
5149
5150void SetHideFiles(void) {
5151 int i;
5152 ALLPRIVATES *B, *B0 = AB[0];
5153 for ( i = 1; i <= numberofworkers; i++ ) {
5154 B = AB[i];
5155 AR.hidefile->handle = AR0.hidefile->handle;
5156 if ( AR.hidefile->handle < 0 ) {
5157 AR.hidefile->PObuffer = AR0.hidefile->PObuffer;
5158 AR.hidefile->POstop = AR0.hidefile->POstop;
5159 AR.hidefile->POfill = AR0.hidefile->POfill;
5160 AR.hidefile->POfull = AR0.hidefile->POfull;
5161 AR.hidefile->POsize = AR0.hidefile->POsize;
5162 AR.hidefile->POposition = AR0.hidefile->POposition;
5163 AR.hidefile->filesize = AR0.hidefile->filesize;
5164 }
5165 else {
5166 AR.hidefile->PObuffer = AR.hidefile->wPObuffer;
5167 AR.hidefile->POstop = AR.hidefile->wPOstop;
5168 AR.hidefile->POfill = AR.hidefile->wPOfill;
5169 AR.hidefile->POfull = AR.hidefile->wPOfull;
5170 AR.hidefile->POsize = AR.hidefile->wPOsize;
5171 PUTZERO(AR.hidefile->POposition);
5172 }
5173 }
5174}
5175
5176/*
5177 #] SetHideFiles :
5178 #[ IniFbufs :
5179*/
5180
5181void IniFbufs(void)
5182{
5183 int i;
5184 for ( i = 0; i < AM.totalnumberofthreads; i++ ) {
5185 IniFbuffer(AB[i]->T.fbufnum);
5186 }
5187}
5188
5189/*
5190 #] IniFbufs :
5191 #[ SetMods :
5192*/
5193
5194void SetMods(void)
5195{
5196 ALLPRIVATES *B;
5197 int i, n, j;
5198 for ( j = 0; j < AM.totalnumberofthreads; j++ ) {
5199 B = AB[j];
5200 AN.ncmod = AC.ncmod;
5201 if ( AN.cmod != 0 ) M_free(AN.cmod,"AN.cmod");
5202 n = ABS(AN.ncmod);
5203 AN.cmod = (UWORD *)Malloc1(sizeof(WORD)*n,"AN.cmod");
5204 for ( i = 0; i < n; i++ ) AN.cmod[i] = AC.cmod[i];
5205 }
5206}
5207
5208/*
5209 #] SetMods :
5210 #[ UnSetMods :
5211*/
5212
5213void UnSetMods(void)
5214{
5215 ALLPRIVATES *B;
5216 int j;
5217 for ( j = 0; j < AM.totalnumberofthreads; j++ ) {
5218 B = AB[j];
5219 if ( AN.cmod != 0 ) M_free(AN.cmod,"AN.cmod");
5220 AN.cmod = 0;
5221 }
5222}
5223
5224/*
5225 #] UnSetMods :
5226 #[ find_Horner_MCTS_expand_tree_threaded :
5227*/
5228
5229void find_Horner_MCTS_expand_tree_threaded(void) {
5230 int id;
5231 while (( id = GetAvailableThread() ) < 0)
5232 MasterWait();
5233 WakeupThread(id,MCTSEXPANDTREE);
5234}
5235
5236/*
5237 #] find_Horner_MCTS_expand_tree_threaded :
5238 #[ optimize_expression_given_Horner_threaded :
5239*/
5240
5241extern void optimize_expression_given_Horner_threaded(void) {
5242 int id;
5243 while (( id = GetAvailableThread() ) < 0)
5244 MasterWait();
5245 WakeupThread(id,OPTIMIZEEXPRESSION);
5246}
5247
5248/*
5249 #] optimize_expression_given_Horner_threaded :
5250*/
5251
5252#endif
int inicbufs(void)
Definition comtool.c:47
int IniFbuffer(WORD bufnum)
Definition comtool.c:614
void AddArgs(PHEAD WORD *, WORD *, WORD *)
Definition sort.c:2082
WORD * poly_ratfun_add(PHEAD WORD *, WORD *)
Definition polywrap.cc:633
int poly_unfactorize_expression(EXPRESSIONS)
Definition polywrap.cc:1535
WORD PutOut(PHEAD WORD *, POSITION *, FILEHANDLE *, WORD)
Definition sort.c:1203
LONG EndSort(PHEAD WORD *, int)
Definition sort.c:486
int Generator(PHEAD WORD *, WORD)
Definition proces.c:3255
void LowerSortLevel(void)
Definition sort.c:4703
int StoreTerm(PHEAD WORD *)
Definition sort.c:4285
int poly_factorize_expression(EXPRESSIONS)
Definition polywrap.cc:1178
void WriteStats(POSITION *, WORD, WORD)
Definition sort.c:136
int NewSort(PHEAD0)
Definition sort.c:395
int NormalModulus(UWORD *, WORD *)
Definition reken.c:1404
int FlushOut(POSITION *, FILEHANDLE *, int)
Definition sort.c:1565
WORD Compare1(PHEAD WORD *, WORD *, WORD)
Definition sort.c:2375
LONG TimeCPU(WORD)
Definition tools.c:3489
void optimize_expression_given_Horner()
Definition optimize.cc:4060
BRACKETINDEX * indexbuffer
Definition structs.h:323
WORD * bracketbuffer
Definition structs.h:324
WORD ** rhs
Definition structs.h:975
WORD ** lhs
Definition structs.h:974
WORD * Buffer
Definition structs.h:971
WORD * Pointer
Definition structs.h:973
int handle
Definition structs.h:709
struct NeStInG * NESTING
struct StOrEcAcHe * STORECACHE