[Math-atlas-commits] CVS: AtlasBase/Clint atlas-make.base, 1.246, 1.247 atlas-thr.base, 1.61, 1.62
Brought to you by:
rwhaley,
tonyc040457
From: R. C. W. <rw...@us...> - 2009-12-30 00:52:00
|
Update of /cvsroot/math-atlas/AtlasBase/Clint In directory sfp-cvsdas-1.v30.ch3.sourceforge.com:/tmp/cvs-serv547/Clint Modified Files: atlas-make.base atlas-thr.base atlas.base Log Message: Index: atlas-make.base =================================================================== RCS file: /cvsroot/math-atlas/AtlasBase/Clint/atlas-make.base,v retrieving revision 1.246 retrieving revision 1.247 diff -C2 -d -r1.246 -r1.247 *** atlas-make.base 21 Dec 2009 15:22:52 -0000 1.246 --- atlas-make.base 30 Dec 2009 00:23:33 -0000 1.247 *************** *** 2004,2007 **** --- 2004,2014 ---- $(GMMdir)/ATL_@(pre)FindCE_mm.o $(ATLASlib) $(LIBS) + x@(pre)txover : force_build @(pre)txover.o + cd $(BLDdir)/src/threads/blas/level3 ; $(MAKE) ATL_@(pre)tgemm_M.o \ + ATL_@(pre)tgemm_rec.o @(pre)lib + $(CLINKER) $(CLINKFLAGS) -o $@ @(pre)txover.o \ + $(BLDdir)/src/threads/blas/level3/ATL_@(pre)tgemm_M.o \ + $(BLDdir)/src/threads/blas/level3/ATL_@(pre)tgemm_rec.o \ + $(TESTlib) $(ATLASlib) $(LIBS) x@(pre)tfc : $(INCAdir)/atlas_type.h $(L3INCdep) \ $(pre)tfc.o @(pre)mmlib *************** *** 2033,2036 **** --- 2040,2045 ---- $(ATLRUN) $(MMTdir) x@(pre)fc + @(pre)txover.o : $(mySRCdir)/txover.c + $(ICC) $(ICCFLAGS) -c -D@(typ) -o @(pre)txover.o $(mySRCdir)/txover.c @(pre)mmtime_pt.o : $(mySRCdir)/mmtime_pt.c $(ICC) $(ICCFLAGS) -c -D@(typ) -o @(pre)mmtime_pt.o \ *************** *** 4705,4708 **** --- 4714,4721 ---- $(ICC) $(ICCFLAGS) -D@(typ) -o $@ -c $(mySRCdir)/ATL_t@(rt).c @endwhile + @whiledef rt3 gemm_M gemm_rec + ATL_@(pre)t@(rt3).o : $(deps) $(mySRCdir)/ATL_t@(rt3).c + $(ICC) $(ICCFLAGS) -D@(typ) -o $@ -c $(mySRCdir)/ATL_t@(rt3).c + @endwhile ATL_@(pre)tgemm_CE.o : $(deps) @(pre)lib $(mySRCdir)/ATL_tgemm.c Index: atlas-thr.base =================================================================== RCS file: /cvsroot/math-atlas/AtlasBase/Clint/atlas-thr.base,v retrieving revision 1.61 retrieving revision 1.62 diff -C2 -d -r1.61 -r1.62 *** atlas-thr.base 22 Dec 2009 18:02:42 -0000 1.61 --- atlas-thr.base 30 Dec 2009 00:23:33 -0000 1.62 *************** *** 713,717 **** */ @ROUT ATL_thrdecompMM ATL_Xtgemm ! static int ATL_thrdecompMM_rec (ATL_TMMNODE_t *ptmms, const enum ATLAS_TRANS TA, const enum ATLAS_TRANS TB, ATL_CINT Mblks, const int mr, ATL_CINT Nblks, const int nr, ATL_CINT Kblks, --- 713,717 ---- */ @ROUT ATL_thrdecompMM ATL_Xtgemm ! int ATL_thrdecompMM_rec (ATL_TMMNODE_t *ptmms, const enum ATLAS_TRANS TA, const enum ATLAS_TRANS TB, ATL_CINT Mblks, const int mr, ATL_CINT Nblks, const int nr, ATL_CINT Kblks, *************** *** 872,876 **** } ! static int ATL_thrdecompMM_M (ATL_TMMNODE_t *ptmms, const enum ATLAS_TRANS TA, const enum ATLAS_TRANS TB, ATL_CINT Mblks, const int mr, ATL_CINT Nblks, const int nr, ATL_CINT Kblks, --- 872,876 ---- } ! int ATL_thrdecompMM_M (ATL_TMMNODE_t *ptmms, const enum ATLAS_TRANS TA, const enum ATLAS_TRANS TB, ATL_CINT Mblks, const int mr, ATL_CINT Nblks, const int nr, ATL_CINT Kblks, *************** *** 1079,1083 **** return(Mjoin(PATL,tNumGemmThreads)(M,N,K)); } ! @ROUT ATL_tgemm #include "atlas_misc.h" #include "atlas_threads.h" --- 1079,1083 ---- return(Mjoin(PATL,tNumGemmThreads)(M,N,K)); } ! @ROUT ATL_tgemm ATL_tgemm_rec ATL_tgemm_M #include "atlas_misc.h" #include "atlas_threads.h" *************** *** 1088,1097 **** void ATL_DoWorkMM(ATL_LAUNCHSTRUCT_t *lp, void *vp); int ATL_StructIsInitMM(void *vp); ! int ATL_thrdecompMM (ATL_TMMNODE_t *ptmms, const enum ATLAS_TRANS TA, const enum ATLAS_TRANS TB, ATL_CINT Mblks, const int mr, ATL_CINT Nblks, const int nr, ATL_CINT Kblks, const int kr, const void *A, ATL_INT lda, const void *B, const ATL_INT ldb, const void *C, ATL_CINT ldc, const int P, const int indx, const int COPYC); ! @multidef tta AtlasTrans AtlasNoTrans AtlasConjTrans --- 1088,1099 ---- void ATL_DoWorkMM(ATL_LAUNCHSTRUCT_t *lp, void *vp); int ATL_StructIsInitMM(void *vp); ! @whiledef rt ATL_thrdecompMM ATL_thrdecompMM_rec ATL_thrdecompMM_M ! int @(rt) (ATL_TMMNODE_t *ptmms, const enum ATLAS_TRANS TA, const enum ATLAS_TRANS TB, ATL_CINT Mblks, const int mr, ATL_CINT Nblks, const int nr, ATL_CINT Kblks, const int kr, const void *A, ATL_INT lda, const void *B, const ATL_INT ldb, const void *C, ATL_CINT ldc, const int P, const int indx, const int COPYC); ! @endwhile ! @ROUT ATL_tgemm @multidef tta AtlasTrans AtlasNoTrans AtlasConjTrans *************** *** 1138,1141 **** --- 1140,1144 ---- @undef tta @endwhile + @ROUT ATL_tgemm ATL_tgemm_rec ATL_tgemm_M static void InitTMMNodes(const enum ATLAS_TRANS TA, const enum ATLAS_TRANS TB, *************** *** 1410,1413 **** --- 1413,1420 ---- } + @ROUT + @ROUT ATL_tgemm_rec ATL_tgemm_M + void Mjoin(PATL,CombineStructsMM)(void *vme, void *vhim); + @ROUT ATL_tgemm void Mjoin(PATL,CombineStructsMM)(void *vme, void *vhim) { *************** *** 1454,1458 **** --- 1461,1471 ---- } + @ROUT ATL_tgemm void Mjoin(PATL,tgemm)(const enum ATLAS_TRANS TA, const enum ATLAS_TRANS TB, + @ROUT ATL_tgemm_rec + int Mjoin(PATL,tgemm_rec)(const enum ATLAS_TRANS TA, const enum ATLAS_TRANS TB, + @ROUT ATL_tgemm_M + int Mjoin(PATL,tgemm_M)(const enum ATLAS_TRANS TA, const enum ATLAS_TRANS TB, + @ROUT ATL_tgemm ATL_tgemm_rec ATL_tgemm_M ATL_CINT M, ATL_CINT N, ATL_CINT K, const SCALAR alpha, const TYPE *A, ATL_CINT lda, const TYPE *B, ATL_CINT ldb, *************** *** 1477,1480 **** --- 1490,1494 ---- return; } + @ROUT ATL_tgemm /* * Don't thread if the compute/mem ratio is essentially like a Level 1 blas *************** *** 1487,1490 **** --- 1501,1513 ---- A, lda, B, ldb, C, ldc, ATL_NTHREADS, 0, 0); } + @ROUT ATL_tgemm_rec + InitTMMNodes(TA, TB, SADD alpha, SADD beta, SADD ONE, SADD ZERO, tp, mms); + np = ATL_thrdecompMM_rec(mms, TA, TB, M/MB, M%MB, N/NB, N%NB, K/KB, K%KB, + A, lda, B, ldb, C, ldc, ATL_NTHREADS, 0, 0); + @ROUT ATL_tgemm_M + InitTMMNodes(TA, TB, SADD alpha, SADD beta, SADD ONE, SADD ZERO, tp, mms); + np = ATL_thrdecompMM_M(mms, TA, TB, M/MB, M%MB, N/NB, N%NB, K/KB, K%KB, + A, lda, B, ldb, C, ldc, ATL_NTHREADS, 0, 0); + @ROUT ATL_tgemm ATL_tgemm_rec ATL_tgemm_M #ifdef DEBUG fprintf(stderr, "np=%d\n\n", np); *************** *** 1492,1497 **** if (np < 2) { Mjoin(PATL,gemm)(TA, TB, M, N, K, alpha, A, lda, B, ldb, beta, C, ldc); ! return; } ls.opstruct = (char*) mms; --- 1515,1521 ---- if (np < 2) { + @ROUT ATL_tgemm_rec ATL_tgemm_M ` return(1);` Mjoin(PATL,gemm)(TA, TB, M, N, K, alpha, A, lda, B, ldb, beta, C, ldc); ! @ROUT ATL_tgemm ` return;` } ls.opstruct = (char*) mms; *************** *** 1508,1512 **** --- 1532,1538 ---- ATL_thread_start(tp, 0, ATL_log2tlaunch, tp); ATL_thread_join(tp); + @ROUT ATL_tgemm_rec ATL_tgemm_M ` return(np);` } + @ROUT ATL_tgemm void Mjoin(PATL,tvgemm)(const enum ATLAS_TRANS TA, const enum ATLAS_TRANS TB, Index: atlas.base =================================================================== RCS file: /cvsroot/math-atlas/AtlasBase/Clint/atlas.base,v retrieving revision 1.199 retrieving revision 1.200 diff -C2 -d -r1.199 -r1.200 *** atlas.base 29 Dec 2009 18:00:21 -0000 1.199 --- atlas.base 30 Dec 2009 00:23:33 -0000 1.200 *************** *** 27603,27607 **** } @ROUT txover ! @extract -b @(topd)/cw.inc what=cw -def cwdate 2009 @ROUT tfc --- 27603,27607 ---- } @ROUT txover ! @extract -b @(topd)/cw.inc what=cw -def cwdate 2009 lang=C @ROUT tfc *************** *** 28152,28165 **** } @ROUT txover ! typedef void (*GEMMPTR) (const enum ATLAS_TRANS TA, const enum ATLAS_TRANS TB, ATL_CINT M, ATL_CINT N, ATL_CINT K, const SCALAR alpha, const TYPE *A, ATL_CINT lda, const TYPE *B, ATL_CINT ldb, const SCALAR beta, TYPE *C, ATL_CINT ldc); ! #define nshape 7 enum ATLAS_MATSHAPE ! {SquareMNK, /* square, including recursive where all dim cut */ ! ShortMN_LK, ShortMK_LN, ShortNK_M, /* recursive shapes, one dim uncut */ ! ShortM_LNK, ShortN_LMK, ShortK_LMN} /* 1-D staticly blocked shapes */ double mmcase --- 28152,28184 ---- } @ROUT txover ! @whiledef rt tgemm tgemm_rec tgemm_M ! int Mjoin(PATL,@(rt)) (const enum ATLAS_TRANS TA, const enum ATLAS_TRANS TB, ATL_CINT M, ATL_CINT N, ATL_CINT K, const SCALAR alpha, const TYPE *A, ATL_CINT lda, const TYPE *B, ATL_CINT ldb, const SCALAR beta, TYPE *C, ATL_CINT ldc); ! @endwhile ! int Mjoin(PATL,gemm_serial) ! (const enum ATLAS_TRANS TA, const enum ATLAS_TRANS TB, ! ATL_CINT M, ATL_CINT N, ATL_CINT K, const SCALAR alpha, ! const TYPE *A, ATL_CINT lda, const TYPE *B, ATL_CINT ldb, ! const SCALAR beta, TYPE *C, ATL_CINT ldc) ! { ! Mjoin(PATL,gemm)(TA, TB, M, N, K, alpha, A, lda, B, ldb, beta, C, ldc); ! return(1); ! } ! ! typedef int (*GEMMPTR) ! (const enum ATLAS_TRANS TA, const enum ATLAS_TRANS TB, ! ATL_CINT M, ATL_CINT N, ATL_CINT K, const SCALAR alpha, ! const TYPE *A, ATL_CINT lda, const TYPE *B, ATL_CINT ldb, ! const SCALAR beta, TYPE *C, ATL_CINT ldc); ! #define NSHAPES 7 ! static char *shapesuff[NSHAPES] = ! {"SQmnk", "SmnLk", "SmkLN", "SnkLm", "SmLNK", "SnLmk", "SkLMN"}; enum ATLAS_MATSHAPE ! {SquareMNK=0, /* square, including recursive where all dim cut */ ! ShortMN_LK=1, ShortMK_LN=2, ShortNK_M=3,/* recursive shapes, one dim uncut */ ! ShortM_LNK=4, ShortN_LMK=5, ShortK_LMN=6};/* 1-D staticly blocked shapes */ double mmcase *************** *** 28168,28172 **** GEMMPTR gemm, /* ptr to matmul to time */ double mflopF, /* how many mflops to force */ ! ATL_CINT M, ATL_CINT N, ATL_CINT K /* matrix dimensions */ ) { --- 28187,28192 ---- GEMMPTR gemm, /* ptr to matmul to time */ double mflopF, /* how many mflops to force */ ! ATL_CINT M, ATL_CINT N, ATL_CINT K, /* matrix dimensions */ ! int *np /* number of procs returned by gemm call */ ) { *************** *** 28177,28184 **** const TYPE alpha = ATL_rone, beta = ATL_rnone; #endif ! ATL_CINT lda = M+8 : 1000, ldb = K+8, ldc = (M >= 1000) ? M+8 : 1000; ! ATL_INT setsz, nsets, incsz, nrep, i, j; double t0, t1; TYPE *A, *B, *C, *mp; setsz = M*N + M*K + K*N; --- 28197,28206 ---- const TYPE alpha = ATL_rone, beta = ATL_rnone; #endif ! ATL_CINT lda = M+8, ldb = K+8, ldc = (M >= 1000) ? M+8 : 1000; ! size_t setsz, nsets, incsz, nrep, i, j; double t0, t1; TYPE *A, *B, *C, *mp; + char *sp; + static int cnt=0; setsz = M*N + M*K + K*N; *************** *** 28191,28197 **** nsets--; } ! while (mp && nsets > 1) assert(mp); ! t0 = mflopF/(2.0*M*N*K); nrep = t0; if (t0-nrep > 0.45) --- 28213,28219 ---- nsets--; } ! while (!mp && nsets > 1); assert(mp); ! t0 = (mflopF*1000000.0)/(2.0*M*N*K); nrep = t0; if (t0-nrep > 0.45) *************** *** 28206,28215 **** B = A + lda*K; C = B + ldb*N; ! gemm(AtlasNoTrans, AtlasNoTrans, M, N, K, alpha, A, lda, B, ldb, ! beta, C, ldc); } ! t1 = time00(); free(mp); ! return( (2.0*M*N*K*nrep) / (1000000.0*(t1-t0)) ); } --- 28228,28253 ---- B = A + lda*K; C = B + ldb*N; ! *np = gemm(AtlasNoTrans, AtlasNoTrans, M, N, K, alpha, A, lda, B, ldb, ! beta, C, ldc); } ! t1 = time00() - t0; free(mp); ! if (gemm == Mjoin(PATL,tgemm_rec)) ! { ! sp = "tdistR"; ! t0 = (*np > 1) ? (2.0*M*N*K*nrep) / (1000000.0*t1) : 0.0; ! } ! else if (gemm == Mjoin(PATL,tgemm_M)) ! { ! sp = "tdistM"; ! t0 = (*np > 1) ? (2.0*M*N*K*nrep) / (1000000.0*t1) : 0.0; ! } ! else ! { ! sp = "serial"; ! t0 = (2.0*M*N*K*nrep) / (1000000.0*t1); ! } ! printf("%6d %6.6s %6d %6d %6d %9.2f\n", ++cnt, sp, M, N, K, t0); ! return(t0); } *************** *** 28224,28248 **** switch(shape) { ! ShortMN_LK: *M = *N = restS; *K = growS; return; ! ShortMK_LN: *M = *K = restS; *N = growS; return; ! ShortNK_M: *N = *K = restS; *M = growS; return; ! ShortM_LNK: *M = restS; *N = *K = growS; return; ! ShortN_LMK: *N = restS; *M = *K = growS; return; ! ShortK_LMN: *K = restS; *M = *N = growS; --- 28262,28286 ---- switch(shape) { ! case ShortMN_LK: *M = *N = restS; *K = growS; return; ! case ShortMK_LN: *M = *K = restS; *N = growS; return; ! case ShortNK_M: *N = *K = restS; *M = growS; return; ! case ShortM_LNK: *M = restS; *N = *K = growS; return; ! case ShortN_LMK: *N = restS; *M = *K = growS; return; ! case ShortK_LMN: *K = restS; *M = *N = growS; *************** *** 28252,28255 **** --- 28290,28294 ---- } } + int GetXover ( *************** *** 28260,28281 **** ATL_CINT NN /* size for non-growing dimension(s) */ ) { double mf0, mf1; ATL_INT M, N, K, j, mymax, mymin; /* * Make sure gemm1 isn't already faster on smallest case */ ! GetDims(shape, NN, minN, &M, &N, &K) ! mf0 = mmcase(flushsz, gemm0, mflopF, M, N, K); ! mf1 = mmcase(flushsz, gemm1, mflopF, M, N, K); ! if (mf0 < mf1) ! return(minN); /* * If gemm1 is never faster than gemm2, then there is no crossover */ ! GetDims(shape, NN, maxN, &M, &N, &K) ! mf0 = mmcase(flushsz, gemm0, mflopF, M, N, K); ! mf1 = mmcase(flushsz, gemm1, mflopF, M, N, K); ! if (mf0 >= mf1) return(0); /* --- 28299,28329 ---- ATL_CINT NN /* size for non-growing dimension(s) */ ) + /* + * NOTE: give serial code 5% advantage, since parallel code should be + * noticably better, and is prone to large variance + */ { double mf0, mf1; ATL_INT M, N, K, j, mymax, mymin; + int np, itmp; + const double m0 = (gemm0 == Mjoin(PATL,gemm_serial)) ? 1.05 : 1.0; /* * Make sure gemm1 isn't already faster on smallest case */ ! GetDims(shape, NN, minN, &M, &N, &K); ! mf1 = mmcase(flushsz, gemm1, mflopF, M, N, K, &np); ! if (np > 1) ! { ! mf0 = mmcase(flushsz, gemm0, mflopF, M, N, K, &itmp) * m0; ! if (mf0 < mf1) ! return(minN); ! } /* * If gemm1 is never faster than gemm2, then there is no crossover */ ! GetDims(shape, NN, maxN, &M, &N, &K); ! mf0 = mmcase(flushsz, gemm0, mflopF, M, N, K, &itmp) * m0; ! mf1 = mmcase(flushsz, gemm1, mflopF, M, N, K, &np); ! if (mf0 >= mf1 || np < 2) return(0); /* *************** *** 28287,28301 **** { j = ((mymax-mymin)>>1) + mymin; ! GetDims(shape, NN, j, &M, &N, &K) ! mf0 = mmcase(flushsz, gemm0, mflopF, M, N, K); ! mf1 = mmcase(flushsz, gemm1, mflopF, M, N, K); ! if (mf0 >= mf1) /* crossover not achieved at this size */ mymin = j; else /* crossover achieved */ ! mymax = j } ! while (mymax-mymin > 8) return(mf0 >= mf1 ? mymax : j); } @ROUT genmv void genmv(char pre, char *type, int mu, int n, int alpha, int beta) --- 28335,28464 ---- { j = ((mymax-mymin)>>1) + mymin; ! GetDims(shape, NN, j, &M, &N, &K); ! mf0 = mmcase(flushsz, gemm0, mflopF, M, N, K, &itmp) * m0; ! mf1 = mmcase(flushsz, gemm1, mflopF, M, N, K, &np); ! if (mf0*1.05 >= mf1 || np < 2) /* crossover not achieved at this size */ mymin = j; else /* crossover achieved */ ! mymax = j; } ! while (mymax-mymin > 32); return(mf0 >= mf1 ? mymax : j); } + + int GetShapesMaxN(enum ATLAS_MATSHAPE shape) + { + switch(shape) + { + case ShortMN_LK: + case ShortMK_LN: + case ShortNK_M: + return(16000); + case ShortM_LNK: + case ShortN_LMK: + case ShortK_LMN: + return(8000); + default: /* square */ + return(2000); + } + return(2000); + } + + ATL_INT *GetXoversByShape + ( + ATL_CINT flushsz, /* size of cache to flush */ + double mflopF, /* mflops to force for timing resolution */ + enum ATLAS_MATSHAPE shape /* shape of the matrix */ + ) + /* + * RETURNS: 16-length array. 1st 9 entries are crossover points for + * mm_rec vs serial, and 2nd 9 entries are crossover points + * for mm_M vs mm_rec. Each of the 9 entries corresponds to + * a power of two on the size of the restrained dimension(s) + */ + { + ATL_INT minN, maxN, xo, i, k, *ix; + minN = Mjoin(PATL,GetNB)(); + maxN = GetShapesMaxN(shape); + + printf("\n\nFINDING XOVERS FOR %s\n", shapesuff[shape]); + printf(" COUNT WHICH M N K MFLOP\n"); + printf("====== ====== ====== ====== ====== =========\n"); + ix = calloc(18, sizeof(ATL_INT)); + assert(ix); + for (i=8; i >= 0; i--) + { + k = (1<<i); + /* + * See when _rec starts beating serial + */ + xo = GetXover(flushsz, mflopF, Mjoin(PATL,gemm_serial), + Mjoin(PATL,tgemm_rec), shape, minN, maxN, k); + ix[i] = xo; + /* + * See if MM_M can beat MM_rec before serial/MM_rec crossover + */ + if (xo > 0) + { + xo = GetXover(flushsz, mflopF, Mjoin(PATL,gemm_serial), + Mjoin(PATL,tgemm_M), shape, minN, ix[i], k); + if (xo < 1) /* does not win before serial crossover */ + { + xo = GetXover(flushsz, mflopF, Mjoin(PATL,tgemm_rec), + Mjoin(PATL,tgemm_M), shape, ix[i], maxN, k); + } + } + else + { + xo = GetXover(flushsz, mflopF, Mjoin(PATL,gemm_serial), + Mjoin(PATL,tgemm_M), shape, minN, maxN, k); + } + ix[i+9] = xo; + + if (!ix[i]) + minN = ix[i+9]; + else if (!ix[i+9]) + minN = ix[i]; + else + minN = Mmin(ix[i], ix[i+9]); + if (!minN) /* if we can't thread this size, can't thread smaller */ + break; + } + return(ix); + } + + void FindXovers + ( + ATL_CINT flushsz, /* size of cache to flush */ + double mflopF, /* mflops to force for timing resolution */ + FILE *fpout /* file to print output to */ + ) + { + int i, k; + ATL_INT *xo; + for (i=0; i < NSHAPES; i++) + { + xo = GetXoversByShape(flushsz, mflopF, i); + fprintf(fpout, "static int ATL_tmm_%s_RXO[9] = \n {", shapesuff[i]); + for (k=0; k < 8; k++) + fprintf(fpout, "%ld,", xo[k]); + fprintf(fpout, "%d};\n", xo[8]); + + fprintf(fpout, "static int ATL_tmm_%s_MXO[9] = \n {", shapesuff[i]); + for (k=9; k < 17; k++) + fprintf(fpout, "%ld,", xo[k]); + fprintf(fpout, "%ld};\n", xo[17]); + free(xo); + } + } + + main(int nargs, char **args) + { + int flushsz = 4*1024*1024, mflopF=1; + FILE *fpout; + + fpout = fopen("txover.h", "w"); + FindXovers(flushsz, mflopF, fpout); + } @ROUT genmv void genmv(char pre, char *type, int mu, int n, int alpha, int beta) |