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