1 /* ************************************************************************
2  * Copyright 2013 Advanced Micro Devices, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  * ************************************************************************/
16 
17 
18 #include <stdlib.h>
19 #include <assert.h>
20 
21 #include <blas_mempat.h>
22 #include <blas_kgen.h>
23 #include <clblas-internal.h>
24 #include <kern_cache.h>
25 #include <blas_funcs.h>
26 
27 #include "fileio.h"
28 #include "toolslib.h"
29 
30 #include "tune.h"
31 #include "subdim.h"
32 #include <math.h>
33 
34 #if defined(_MSC_VER)
35 #define fmin min
36 #define fmax max
37 #endif
38 
39 #define isLdsUsed(pattern)                                          \
40     (checkMatrixMemLevelSet(pattern, MATRIX_A, CLMEM_LEVEL_LDS) ||  \
41      checkMatrixMemLevelSet(pattern, MATRIX_B, CLMEM_LEVEL_LDS))
42 
43 int VISIBILITY_HIDDEN
getDataTypeSize(DataType dataType)44 getDataTypeSize(DataType dataType)
45 {
46     int dataTypeSize = 0;
47 
48     switch (dataType) {
49         case TYPE_FLOAT:
50             dataTypeSize = 4;
51             break;
52         case TYPE_DOUBLE:
53         case TYPE_COMPLEX_FLOAT:
54             dataTypeSize = 8;
55             break;
56         case TYPE_COMPLEX_DOUBLE:
57             dataTypeSize = 16;
58             break;
59     }
60     return dataTypeSize;
61 }
62 /*
63 *  Checks current dimensionality on a validity
64 */
65 bool VISIBILITY_HIDDEN
isSubDimValid(SubDimInfo * sd)66 isSubDimValid(SubDimInfo* sd)
67 {
68     int j;
69     size_t wgX = sd->pgran.wgSize[0];
70     size_t wgY = sd->pgran.wgSize[1];
71     SubproblemDim l0 = sd->sdim[0];
72     SubproblemDim l1 = sd->sdim[1];
73     size_t dataTypeSize = getDataTypeSize(sd->dtype);
74     size_t dataFloatSize = getDataTypeSize(TYPE_FLOAT);
75     int maxRegistr = 64;
76     bool ret = true;
77     bool inv;
78     IgnoreItem* ii = sd->first;
79 
80     // if pattern-based validation is available
81     if( NULL != sd->pattern->sops->checkCalcDecomp ){
82 
83         return sd->pattern->sops->checkCalcDecomp(
84             &sd->pgran,
85             sd->sdim,
86             2,
87             sd->dtype,
88             PGRAN_CHECK );
89     }
90 
91     ret = ret && (l1.y >= 4*dataFloatSize/dataTypeSize);
92 
93     if (sd->blasLevel == 3) {
94         if (!isMatrixAccessColMaj(sd->func, sd->flag, MATRIX_A) ||
95                 !isMatrixAccessColMaj(sd->func, sd->flag, MATRIX_B)) {
96             /* Avoid small bwidth and big x0, y0 for cases other than
97              * column major access to both matrixes */
98             ret = ret && (l1.bwidth >= 4*dataFloatSize/dataTypeSize);
99             ret = ret && (l0.y < 128);
100             ret = ret && (l0.x < 128);
101         }
102     }
103 
104     if ( 0 == l1.bwidth ){
105         return false;
106     }
107     else{
108         ret = ret && ((l0.bwidth % l1.bwidth) == 0);
109         ret = ret && (wgX*wgY == 64);
110     }
111     //ret = ret && (wgX*wgY < sd->workGroupSizes);
112     //ret = ret && (wgX*wgY > 16);
113     if (sd->blasLevel == 2) {
114         ret = ret && (l0.y > l1.y);
115     }
116     else {
117         ret = ret && (l0.x > l1.x);
118         ret = ret && (l0.y > l1.y);
119         ret = ret && (l1.x >= 4*dataFloatSize/dataTypeSize);
120     }
121     if (sd->is2D) {
122         bool r = ret;
123         ret = ret && (wgY * l1.itemX == l0.x);
124         ret = ret && (wgX * l1.itemY == l0.y);
125         if (r != ret) {
126             return ret;
127         }
128     }
129 
130     if (ret && sd->isSquareBlock) {
131         ret = ret &&  (l0.x == l0.y && l0.x == l0.bwidth);
132     }
133 
134     //if (!(isLdsUsed(sd->pattern) || (sd->isSquareBlock && sd->nrLevel == 2))) {
135     //    ret = ret &&  l0.bwidth == l1.bwidth;
136     //}
137 
138     if (ret) {
139         int r ;
140         r = (int)(l1.x*l1.bwidth + l1.y*l1.bwidth + l1.x*l1.y);
141 
142         r = r * (int)dataTypeSize / sizeof(cl_float4);
143 
144         if (r > maxRegistr) {
145             return false;
146         }
147     }
148 
149     if  (ret &&  sd->pattern->sops->isFitToLDS != NULL) {
150         bool isFitToLDS;
151         CLBlasKargs args;
152 
153         convKExtraFlagToArg(sd->flag, &args);
154 
155         isFitToLDS = sd->pattern->sops->isFitToLDS(sd->sdim, sd->dtype,
156                                                sd->ldsSize, &args);
157         if (!isFitToLDS)
158             return false;
159     }
160 
161     // Skip ignored dimension
162     for (;ii != NULL; ii = ii->next) {
163         inv = true;
164         for(j = 0; j < V_COUNT; ++j) {
165             int v1 = ii->var[j];
166             int v2 = get(&sd->var[j]);
167             if (v1 == -1) {
168                 continue;
169             }
170             if (v1 == v2) {
171                 continue;
172             }
173             inv = false;
174             break;
175         }
176         if (inv) {
177             ret = false;
178         }
179     }
180 
181     return ret;
182 }
183 
184 /*
185  * Set invalid SubDimension.
186  * Invalid SubDimensions will be skipped.
187  */
188 void VISIBILITY_HIDDEN
setInvalid(SubDimInfo * sdi,int l0x,int l0y,int l0w,int l1x,int l1y,int l1w)189 setInvalid(SubDimInfo* sdi, int l0x, int l0y, int l0w,
190                             int l1x, int l1y, int l1w)
191 {
192     IgnoreItem* ii = malloc(sizeof(IgnoreItem));
193     ii->var[V_L0_X]  = l0x;
194     ii->var[V_L0_Y]  = l0y;
195     ii->var[V_L0_BW] = l0w;
196     ii->var[V_L1_X]  = l1x;
197     ii->var[V_L1_Y]  = l1y;
198     ii->var[V_L1_BW] = l1w;
199     ii->next = sdi->first;
200     sdi->first = ii;
201 }
202 
203 void VISIBILITY_HIDDEN
initVector(SubDimInfo * sd)204 initVector(SubDimInfo* sd)
205 {                //0 1 2 3  4  5  6   7   8   9   10   11
206     int dim  [] = {1,2,4,8,16,32,64,128,256,512,1024,2048, 4096};
207     if (sd->blasLevel == 2 ) {
208         setVariable(sd, V_L0_X,  1, &dim[0]);
209         setVariable(sd, V_L0_Y,  6, &dim[4]);
210         setVariable(sd, V_L0_BW, 10, &dim[0]);
211         setVariable(sd, V_L1_X,  1, &dim[0]);
212         setVariable(sd, V_L1_Y,  6, &dim[1]);
213         setVariable(sd, V_L1_BW, 6, &dim[0]);
214     }
215     else {
216         setVariable(sd, V_L0_X,  4, &dim[4]);
217         setVariable(sd, V_L0_Y,  4, &dim[4]);
218         setVariable(sd, V_L0_BW, 6, &dim[0]);
219         setVariable(sd, V_L1_X,  6, &dim[0]);
220         setVariable(sd, V_L1_Y,  6, &dim[0]);
221         setVariable(sd, V_L1_BW, 6, &dim[0]);
222     }
223 }
224 
225 void VISIBILITY_HIDDEN
initKNMVector(SubDimInfo * sd,unsigned int baseDim,unsigned int * K,unsigned int * N,unsigned int * M)226 initKNMVector(
227         SubDimInfo* sd,
228         unsigned int baseDim,
229         unsigned int* K,
230         unsigned int* N,
231         unsigned int* M
232         )
233 {
234     if (sd->blasLevel == 2 ) {
235         *K = 1;
236         *N = baseDim * 2;
237         *M = baseDim * 2;
238     } else
239     {
240         *K = baseDim;
241         *N = baseDim;
242         *M = baseDim;
243     }
244 }
245 
246 int VISIBILITY_HIDDEN
get(SubDimItem * sd)247 get(SubDimItem* sd)
248 {
249     return sd->data[sd->curId];
250 }
251 
252 void VISIBILITY_HIDDEN
calcPGranularity(SubDimInfo * sd)253 calcPGranularity (SubDimInfo* sd)
254 {
255     SubproblemDim* dim = sd->sdim;
256     PGranularity* pgran = &sd->pgran;
257     //int level = sd->cuLevel;
258 
259     pgran->wgDim = 2;
260     pgran->wfSize = 64;
261 	pgran->maxWorkGroupSize = sd->workGroupSizes;
262 
263     // if pattern provides granularity calculation
264     // call the pattern function
265     if( NULL != sd->pattern->sops->checkCalcDecomp ){
266 
267         sd->pattern->sops->checkCalcDecomp(
268             pgran,
269             dim,
270             2,
271             sd->dtype,
272             PGRAN_CALC );
273     }
274     else{
275         pgran->wgSize[1] =  (unsigned int)(dim[0].x / dim[1].itemX);
276         pgran->wgSize[0] =  (unsigned int)(dim[0].y / dim[1].itemY);
277 
278         if (!sd->is2D) {
279             pgran->wgDim = 1;
280             pgran->wgSize[0] *= pgran->wgSize[1];
281             pgran->wgSize[1] = 1;
282         }
283     }
284 
285 }
286 
287 void VISIBILITY_HIDDEN
calcParam(SubDimInfo * sd)288 calcParam(SubDimInfo* sd)
289 {
290     SubproblemDim* dim = sd->sdim;
291 
292     int dataTypeSize = getDataTypeSize(sd->dtype);
293 
294     memset(dim, 0, sizeof(sd->sdim));
295 
296     dim[0].x      = get(&sd->var[V_L0_X]);
297     dim[0].itemX  = get(&sd->var[V_L0_X]);
298     dim[0].y      = get(&sd->var[V_L0_Y]);
299     dim[0].itemY  = get(&sd->var[V_L0_Y]);
300     dim[0].bwidth = get(&sd->var[V_L0_BW]);
301 
302     dim[1].x      = get(&sd->var[V_L1_X]);
303     dim[1].itemX  = get(&sd->var[V_L1_X]);
304     dim[1].y      = get(&sd->var[V_L1_Y]);
305     dim[1].itemY  = get(&sd->var[V_L1_Y]);
306     dim[1].bwidth = get(&sd->var[V_L1_BW])
307             / (dataTypeSize / getDataTypeSize(TYPE_FLOAT));
308 
309     if (funcHasTriangMatrix((BlasFunctionID)sd->func) && !sd->is2D) {
310         dim[0].itemY  = SUBDIM_UNUSED;
311     }
312 
313     if (sd->blasLevel == 2) {
314         size_t xBlocks;
315 
316         xBlocks = dim[0].x / dim[1].x;
317         dim[0].x = 1;
318         dim[1].itemX = 1;
319         dim[1].x = 1;
320         if( NULL == sd->pattern->sops->checkCalcDecomp ){
321             dim[0].bwidth = dim[1].bwidth * xBlocks;
322         }
323     }
324 
325     calcPGranularity(sd);
326 }
327 
328 bool VISIBILITY_HIDDEN
next(SubDimItem var[V_COUNT])329 next(SubDimItem var[V_COUNT])
330 {
331     int i = V_COUNT - 1;
332     bool next;
333     do {
334         next = false;
335         var[i].curId ++;
336         if (var[i].curId >= var[i].maxId) {
337             var[i].curId = 0;
338             next = true;
339             -- i;
340         }
341     } while (next && i >= 0 );
342     return (next && i < 0);
343 }
344 
345 void VISIBILITY_HIDDEN
findValidSubdimInit(SubDimInfo * sd)346 findValidSubdimInit(SubDimInfo* sd)
347 {
348     bool n = false;
349     do {
350         n = false;
351         calcParam(sd);
352         sd->valid = sd->isValid(sd);
353         if (!sd->valid) {
354             n = !next(sd->var);
355             sd->valid = false;
356         }
357     } while (n);
358 }
359 
360 bool
nextSubdimElem(SubDimInfo * sd)361 nextSubdimElem(SubDimInfo* sd)
362 {
363     bool n = false;
364 
365     // !!! DEBUG
366     if (sd->count > 500) {
367         abort();
368     }
369 
370     sd->count ++;
371     if (sd->valid == false) {
372         return false;
373     }
374 
375     if (sd->init != NULL) {
376         sd->valid = false;
377         n = !next(sd->var);
378         if (n)
379             findValidSubdimInit(sd);
380     }
381     return sd->valid;
382 }
383 
384 /*
385  * The variant included of the group.
386  */
387 bool
isMemberOfGroup(GroupStatInfo * gsi,Variant * vi)388 isMemberOfGroup(GroupStatInfo* gsi,  Variant* vi)
389 {
390     bool res = true;
391     res &= gsi->var[V_L0_X]  == -1 || vi->var[V_L0_X]  == gsi->var[V_L0_X];
392     res &= gsi->var[V_L0_Y]  == -1 || vi->var[V_L0_Y]  == gsi->var[V_L0_Y];
393     res &= gsi->var[V_L0_BW] == -1 || vi->var[V_L0_BW] == gsi->var[V_L0_BW];
394     res &= gsi->var[V_L1_X]  == -1 || vi->var[V_L1_X]  == gsi->var[V_L1_X];
395     res &= gsi->var[V_L1_Y]  == -1 || vi->var[V_L1_Y]  == gsi->var[V_L1_Y];
396     res &= gsi->var[V_L1_BW] == -1 || vi->var[V_L1_BW] == gsi->var[V_L1_BW];
397     return res;
398 }
399 
400 /*
401  * Calculate the minimum expected run time.
402  */
403 
404 double
calcMinExpectedTimeForGroup(GroupStatInfo * gsi)405 calcMinExpectedTimeForGroup(GroupStatInfo* gsi)
406 {
407     /*
408      * K_INCREASE - Expected range of time values in the group
409      * K_GLOBAL -
410      */
411     const double K_INCREASE = 1.5;
412     const double K_GLOBAL = 0.97;
413 
414     /* Number of variants in group */
415     double m = gsi->allCount;
416     /* Number of variants in group for whom time is measured*/
417     double i = gsi->count;
418 
419     /*
420      *  k - Reflects the expected spread of values in the group,
421      *  depending on the number of measurements
422      *  decreases with increasing i
423      *  if i == 1 then k K_INCREASE
424      *  if i == m then k = 1
425      */
426 
427     double ki = 1/ ((K_INCREASE + K_INCREASE/(m+i) -1)/(i) + (m-K_INCREASE)/(m+1));
428     double averageTime = (gsi->allTime / m);
429 
430     /*
431      * kdelta - Reflects the expected spread of values in the group,
432      * depending on the spread of values of the measured variations
433      */
434 
435     double kdelta = (gsi->minTime*3)/((gsi->minTime*2) + averageTime);
436     double t = K_GLOBAL * kdelta * ki * gsi->minTime;
437 
438     /*
439      * Select the minimum time between the minimum time for the current group
440      * and the minimum time for the previous groups
441      */
442     return t;
443 }
444 
445 bool
nextSubdim(SubDimInfo * sd,int maxParam,double time)446 nextSubdim(SubDimInfo* sd, int maxParam, double time)
447 {
448     int i;
449     int j;
450     double minW = -5000;
451     int vari = 0;
452     double midTime;
453     int iCount = 0;
454     double maxTime;
455     const int MAX_WEIGHT = 99;
456 
457     Variant* v0 = sd->curVar;   // Current variant
458     Variant* varNext = NULL;    // Next Variant
459 
460     if (sd->count >= maxParam) {
461         return false;
462     }
463 
464     if (sd->returnAll) {
465         bool ret = nextSubdimElem (sd);
466         calcParam(sd);
467         sd->curVarID = sd->count;
468         return ret;
469     }
470 
471     v0->time = time;
472     sd->sumTime += time;
473 
474     midTime = sd->sumTime/(sd->count + 1);
475 
476     if (time > 0)  {
477         sd->minTime = fmin(sd->minTime, (float)time);
478     }
479 
480     maxTime = fmax(2.1*midTime - sd->minTime,  sd->minTime*5);
481 
482     /* Initialize all groups */
483     for (j = 0; j < sd->infoCount; j++ ) {
484         GroupStatInfo* si = &sd->info[j];
485         si->allTime = 0;
486         si->count   = 0;
487         si->minTime = 1e9;
488     }
489 
490     /* Calculate an estimate for the groups */
491     for (i = 0; i < sd->varCount; ++i) {
492         Variant* vi = &sd->allVariant[i];
493         /* If time for variant is measured*/
494         if (vi->time > 0) {
495             for (j = 0; j < sd->infoCount; j++ ) {
496                 GroupStatInfo* gsi = &sd->info[j];
497                 // For each group, if variant is member this group
498                 if (isMemberOfGroup(gsi, vi)) {
499                     gsi->minTime = fmin(gsi->minTime, vi->time);
500                     gsi->allTime += fmin(vi->time, maxTime);
501                     gsi->count ++;
502                     gsi->minTime = calcMinExpectedTimeForGroup(gsi);
503                 }
504            }
505         }
506         vi->minTime = 0;
507         vi->maxTime = 5000;
508         vi->weight  = MAX_WEIGHT;
509     }
510 
511     /*
512      * Calculate the estimate run-time variant
513      */
514     for (i = 0; i < sd->varCount; ++i) {
515         Variant* vi = &sd->allVariant[i];
516 
517         vi->weight = MAX_WEIGHT;
518         if (vi->time == 0) {
519             double kgroup = 1.0;
520 
521             for (j = 0; j < sd->infoCount; j++ ) {
522                 GroupStatInfo* gsi = &sd->info[j];
523                 // if the variant included of the group
524                 if (isMemberOfGroup(gsi, vi)) {
525                     if (gsi->count > 0) {
526                         vi->minTime = fmax(vi->minTime, gsi->minTime);
527                         vi->weight  = sd->minTime/vi->minTime;
528                     }
529                     else {
530                         /*
531                          * If variant don't included of the group
532                          * then to reduce estimated time
533                          */
534                         kgroup *= 1.1;
535                     }
536                 }
537             }
538             vi->weight *= kgroup;
539             vi->minTime /= kgroup;
540         }
541     }
542 
543     /* Find variant with minimal run time */
544 
545     for (i = 0; i < sd->varCount; ++i)
546     {
547         Variant* vi = &sd->allVariant[i];
548         if (vi->time == 0 && vi->weight >= 0.01 ) {
549             iCount ++;
550 
551             if (minW < vi->weight) {
552                 minW = vi->weight;
553                 varNext = vi;
554                 vari = i;
555             }
556         }
557     }
558 
559     //
560     if (varNext == NULL) {
561         return false;
562     }
563 
564     sd->curVar =  varNext;
565     sd->curVarID = vari;
566 #ifdef TEST_LOG
567     printf ("%4d %6.2f [%6.2f:%5.2f ]",iCount, sd->minTime,
568             sd->curVar->minTime, sd->curVar->weight);
569 #endif
570 
571     for(j = 0; j < V_COUNT; ++j) {
572         sd->var[j].curId = varNext->var[j];
573     }
574 
575     calcParam(sd);
576     sd->count++;
577     return true;
578 }
579 
580 void
resetSubdim(SubDimInfo * sd)581 resetSubdim(SubDimInfo* sd)
582 {
583     int i;
584     for (i=0; i< V_COUNT; ++i) {
585         sd->var[i].curId = 0;
586     }
587 
588     sd->count = 0;
589 
590     sd->valid = false;
591     if (sd->init != NULL) {
592         sd->init(sd);
593         findValidSubdimInit(sd);
594 
595         assert(sd->valid);
596     }
597 }
598 
599 /*
600  * Groups variants in nonzero parameters.
601  *
602  * Example: l0x = 1 and remaining parameters = 0;
603  * At different variants the parameter l0x accepts values 16, 32, 64.
604  * At the first stage creates are 3 groups (a set of groups).
605  * At the second stage all variants are arranged on these groups.
606  *
607  * The each variant included one group of the set of group.
608  * The each variant included in each set of group.
609  * In set of group can be only one group
610  */
611 
setGroup(SubDimInfo * sd,int l0x,int l0y,int l0w,int l1x,int l1y,int l1w,int pg)612 void setGroup(SubDimInfo* sd,
613          int l0x, int l0y, int l0w,
614          int l1x, int l1y, int l1w,
615          int pg)
616 {
617     int i, j;
618     int start = sd->infoCount;
619     int end   = sd->infoCount;
620 
621     (void) pg;
622 
623     //For each variant
624     for (i = 0; i < sd->varCount; ++i) {
625         Variant* vi = &sd->allVariant[i];
626         int  id = -1;
627         // For each group of the set of group
628         for (j = start; j < end; j++ ) {
629             bool bj = true;
630             bj &= l0x == 0 || vi->var[V_L0_X] == sd->info[j].var[V_L0_X];
631             bj &= l0y == 0 || vi->var[V_L0_Y] == sd->info[j].var[V_L0_Y];
632             bj &= l0w == 0 || vi->var[V_L0_BW] == sd->info[j].var[V_L0_BW];
633             bj &= l1x == 0 || vi->var[V_L1_X] == sd->info[j].var[V_L1_X];
634             bj &= l1y == 0 || vi->var[V_L1_Y] == sd->info[j].var[V_L1_Y];
635             bj &= l1w == 0 || vi->var[V_L1_BW] == sd->info[j].var[V_L1_BW];
636             // if the variant belongs to group
637             if (bj) {
638                 id = j;
639                 break;
640             }
641         }
642         /*
643          * if the variant doesn't belong to any group create new group
644          */
645 
646         if (id == -1) {
647             sd->info[end].var[V_L0_X]  = (l0x == 1)? vi->var[V_L0_X]  : -1;
648             sd->info[end].var[V_L0_Y]  = (l0y == 1)? vi->var[V_L0_Y]  : -1;
649             sd->info[end].var[V_L0_BW] = (l0w == 1)? vi->var[V_L0_BW] : -1;
650             sd->info[end].var[V_L1_X]  = (l1x == 1)? vi->var[V_L1_X]  : -1;
651             sd->info[end].var[V_L1_Y]  = (l1y == 1)? vi->var[V_L1_Y]  : -1;
652             sd->info[end].var[V_L1_BW] = (l1w == 1)? vi->var[V_L1_BW] : -1;
653             sd->info[end].pg = 0;
654 
655             sd->info[end].allTime = 0;
656             sd->info[end].allCount = 1;
657 
658             end++;
659             sd->infoCount++;
660         }
661         else {
662             sd->info[id].allCount++;
663         }
664     }
665 }
666 
667 void
initSubDimInfo(SubDimInfo * sd,MemoryPattern * mempatt,DeviceInfo * devinfo,unsigned int func,unsigned int patt,DataType dtype,KernelExtraFlags flag)668 initSubDimInfo(SubDimInfo* sd,
669                MemoryPattern* mempatt,
670                DeviceInfo* devinfo,
671                unsigned int func,
672                unsigned int patt,
673                DataType dtype,
674                KernelExtraFlags flag)
675 {
676     int i = 0;
677 
678     memset(sd, 0, sizeof(SubDimInfo));
679 
680     sd->func = func;
681     sd->patt = patt;
682     sd->dtype = dtype;
683     sd->flag  = flag;
684     sd->pattern = mempatt;
685     sd->first = NULL;
686 
687     sd->is2D  = (sd->pattern->sops->getFlags() & SF_WSPACE_2D)?true:false;
688     sd->isSquareBlock = ((sd->pattern->sops->getFlags() &
689                           SF_TOP_INPUT_SQUARE_BLOCKS) != 0);
690     sd->blasLevel = funcBlasLevel(sd->func);
691     sd->nrLevel   = sd->pattern->nrLevels;
692 
693     sd->ldsSize = devinfo->ldsSize;
694     sd->workGroupSizes = devinfo->workGroupSizes;
695 
696     // Virtual function
697     sd->isValid = isSubDimValid;
698     sd->init = initVector;
699 
700     resetSubdim(sd);
701 
702     i = 0;
703     do {
704         i++;
705     } while (nextSubdimElem(sd));
706     sd->allVariant = malloc(i* sizeof(Variant));
707 
708     resetSubdim(sd);
709     sd->varCount = i;
710 
711     for (i = 0; i < sd->varCount; ++i) {
712         int j;
713         int gpx;
714         int gpy;
715 
716         for(j = 0; j < V_COUNT; ++j) {
717             sd->allVariant[i].var[j]  = sd->var[j].curId;
718         }
719 
720         sd->allVariant[i].minTime = 0.0;
721         sd->allVariant[i].probableTime = 0.0;
722         sd->allVariant[i].maxTime = 5000.0;
723         sd->allVariant[i].weight = 10;
724         sd->allVariant[i].time = 0;
725 
726         gpx = get(&sd->var[V_L0_X])/ get(&sd->var[V_L1_X]);
727         gpy = get(&sd->var[V_L0_Y])/ get(&sd->var[V_L1_Y]);
728         sd->allVariant[i].pg =  gpx * 1000 + gpy;
729 
730         nextSubdimElem(sd);
731     }
732     resetSubdim(sd);
733 
734     sd->minTime = 9999;
735     sd->curVar = &sd->allVariant[0];
736     sd->curVarID = 0;
737 
738 
739     // Initializing group
740     sd->infoMaxCount = 5000;
741     sd->infoCount  = 0;
742     sd->info = malloc(sd->infoMaxCount * sizeof(GroupStatInfo) );
743 
744     //           L0       L1       PG
745     //           x  y  w  x  y  w
746     setGroup(sd, 1, 1, 0, 0, 0, 0, 0);
747     setGroup(sd, 1, 1, 1, 0, 0, 0, 0);
748     setGroup(sd, 0, 0, 0, 1, 1, 1, 0);
749     setGroup(sd, 1, 1, 0, 1, 1, 0, 0);
750 }
751 
752 void
setVariable(struct SubDimInfo * sdi,SubDimVariable var,int dcount,int * dim)753 setVariable(struct SubDimInfo* sdi, SubDimVariable var, int dcount, int* dim)
754 {
755     size_t size =  dcount*sizeof(int);
756 
757     sdi->var[var].curId = 0;
758     sdi->var[var].maxId = dcount;
759 
760     if (sdi->var[var].data != NULL) {
761         free (sdi->var[var].data);
762         sdi->var[var].data = NULL;
763     }
764     sdi->var[var].data = malloc(size);
765     memcpy(sdi->var[var].data, dim, size);
766 }
767 
768 
769