1 // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 // vi: set et ts=4 sw=2 sts=2:
3 /****************************************************************************/
4 /*                                                                          */
5 /* File:      prio.c                                                        */
6 /*                                                                          */
7 /* Purpose:   priority management for ddd                                   */
8 /*                                                                          */
9 /* Author:    Klaus Birken                                                  */
10 /*            Rechenzentrum Uni Stuttgart                                   */
11 /*            Universitaet Stuttgart                                        */
12 /*            Allmandring 30                                                */
13 /*            70550 Stuttgart                                               */
14 /*            internet: birken@rus.uni-stuttgart.de                         */
15 /*                                                                          */
16 /* History:   94/04/25 kb  begin                                            */
17 /*                                                                          */
18 /* Remarks:                                                                 */
19 /*                                                                          */
20 /****************************************************************************/
21 
22 /****************************************************************************/
23 /*                                                                          */
24 /* include files                                                            */
25 /*            system include files                                          */
26 /*            application include files                                     */
27 /*                                                                          */
28 /****************************************************************************/
29 
30 /* standard C library */
31 #include <config.h>
32 #include <cstdlib>
33 #include <cstdio>
34 #include <cstring>
35 
36 #include <iomanip>
37 #include <iostream>
38 
39 #include <dune/common/exceptions.hh>
40 #include <dune/common/stdstreams.hh>
41 
42 #include <dune/uggrid/parallel/ddd/dddi.h>
43 
44 USING_UG_NAMESPACE
45 
46 /* PPIF namespace: */
47 using namespace PPIF;
48 
49 START_UGDIM_NAMESPACE
50 
51 /****************************************************************************/
52 /*                                                                          */
53 /* defines in the following order                                           */
54 /*                                                                          */
55 /*        compile time constants defining static data size (i.e. arrays)    */
56 /*        other constants                                                   */
57 /*        macros                                                            */
58 /*                                                                          */
59 /****************************************************************************/
60 
61 
62 /* get index for one-dimensional storage of twodimensional symm. matrix,
63    which is stored as lower triangle and diagonal
64 
65    col must be <= row !
66  */
67 #define PM_ENTRY(pm,row,col)   (pm[((((row)+1)*(row))/2)+(col)])
68 #define PM_SIZE  ((MAX_PRIO*(MAX_PRIO+1))/2)
69 
70 
71 /* get priority-merge value for given default mode */
72 #define PM_GETDEFAULT(mm,p1,p2,pres)                         \
73   switch (mm) {                                            \
74   case PRIOMERGE_MAXIMUM :   pres = MAX(p1,p2); break;  \
75   case PRIOMERGE_MINIMUM :   pres = MIN(p1,p2); break;  \
76   default :                  pres = 0; break;           \
77   }
78 
79 
80 /****************************************************************************/
81 /*                                                                          */
82 /* data structures                                                          */
83 /*                                                                          */
84 /****************************************************************************/
85 
86 
87 
88 /****************************************************************************/
89 /*                                                                          */
90 /* definition of static variables                                           */
91 /*                                                                          */
92 /****************************************************************************/
93 
94 
95 
96 
97 
98 /****************************************************************************/
99 /*                                                                          */
100 /* routines                                                                 */
101 /*                                                                          */
102 /****************************************************************************/
103 
104 
105 
DDD_PrioritySet(DDD::DDDContext & context,DDD_HDR hdr,DDD_PRIO prio)106 void DDD_PrioritySet(DDD::DDDContext& context, DDD_HDR hdr, DDD_PRIO prio)
107 {
108 /* check input parameters */
109   if (prio>=MAX_PRIO)
110     DUNE_THROW(Dune::Exception, "priority must be less than " << MAX_PRIO);
111 
112 #       ifdef LogObjects
113   Dune::dinfo << "LOG DDD_PrioritySet " << OBJ_GID(hdr)
114               << " old=" << OBJ_PRIO(hdr) << " new=" << prio << "\n";
115 #       endif
116 
117 if (ddd_XferActive(context))
118 {
119   /* we are during Xfer, therefore initiate PrioChange operation */
120   DDD_XferPrioChange(context, hdr, prio);
121 }
122 else if(ddd_PrioActive(context))
123 {
124   /* we are in a Prio-environment, therefore initiate consistent PrioChange operation */
125   DDD_PrioChange(context, hdr, prio);
126 }
127 else
128 {
129   if (! ObjHasCpl(context, hdr))
130   {
131     /* just one local object, we can simply change its priority */
132     OBJ_PRIO(hdr) = prio;
133   }
134   else
135   {
136     /* distributed object will get inconsistent here. issue warning. */
137     if (DDD_GetOption(context, OPT_WARNING_PRIOCHANGE)==OPT_ON)
138       Dune::dwarn << "DDD_PrioritySet: creating inconsistency for gid="
139                   << OBJ_GID(hdr) << "\n";
140 
141     /* change priority, nevertheless */
142     OBJ_PRIO(hdr) = prio;
143   }
144 }
145 }
146 
147 
148 
149 
150 
151 /****************************************************************************/
152 
153 /*
154         compute the result of merging two priorities.
155 
156         this function merges two priorities p1 and p2 for
157         object of DDD_TYPE desc. the default merge operation
158         is used (PRIOMERGE_DEFAULT). if a merge-matrix has been
159         specified, this matrix will be used.
160 
161         on return, *pres will contain the resulting priority.
162         the return value is:
163 
164                 PRIO_UNKNOWN   can't decide which priority wins.
165                 PRIO_FIRST     first priority wins.
166                 PRIO_SECOND    second priority wins.
167                 PRIO_ERROR     an error has occurred.
168  */
169 
PriorityMerge(const TYPE_DESC * desc,DDD_PRIO p1,DDD_PRIO p2,DDD_PRIO * pres)170 enum PrioMergeVals PriorityMerge(const TYPE_DESC* desc, DDD_PRIO p1, DDD_PRIO p2, DDD_PRIO *pres)
171 {
172   /* check if matrix is available */
173   if (desc->prioMatrix == nullptr)
174   {
175     PM_GETDEFAULT(desc->prioDefault, p1, p2, *pres);
176     if (*pres==MAX_PRIO) return PRIO_ERROR;
177   }
178   else
179   {
180     if (p2<=p1)
181     {
182       *pres = PM_ENTRY(desc->prioMatrix,p1,p2);
183     }
184     else
185     {
186       *pres = PM_ENTRY(desc->prioMatrix,p2,p1);
187     }
188 
189   }
190 
191   if (*pres==p1 || *pres!=p2) return(PRIO_FIRST);
192   if (*pres==p2 || *pres!=p1) return(PRIO_SECOND);
193   return(PRIO_UNKNOWN);
194 }
195 
196 
197 /****************************************************************************/
198 
199 /*
200         allocate prioMatrix and set default entries
201  */
202 
SetPrioMatrix(TYPE_DESC * desc,int priomerge_mode)203 static int SetPrioMatrix (TYPE_DESC *desc, int priomerge_mode)
204 {
205   int r, c;
206 
207   if (desc->prioMatrix==nullptr)
208   {
209     /* prioMatrix has not been allocated before */
210     desc->prioMatrix = std::make_unique<DDD_PRIO[]>(PM_SIZE);
211   }
212 
213   for(r=0; r<MAX_PRIO; r++)
214   {
215     for(c=0; c<=r; c++)
216     {
217       DDD_PRIO pres;
218 
219       PM_GETDEFAULT(priomerge_mode, r, c, pres);
220       if (pres==MAX_PRIO) return false;
221 
222       PM_ENTRY(desc->prioMatrix, r, c) = pres;
223     }
224   }
225 
226   /* remember default setting */
227   desc->prioDefault = priomerge_mode;
228 
229   return true;
230 }
231 
232 
233 /****************************************************************************/
234 
235 /*
236         check prioMatrix
237  */
238 
CheckPrioMatrix(TYPE_DESC * desc)239 static int CheckPrioMatrix (TYPE_DESC *desc)
240 {
241   int r, c;
242 
243   if (desc->prioMatrix==nullptr)
244     /* no prioMatrix defined, ok */
245     return true;
246 
247   /* check: entries i must be 0<=i<MAX_PRIO */
248   for(r=0; r<MAX_PRIO; r++)
249   {
250     for(c=0; c<=r; c++)
251     {
252       DDD_PRIO p = PM_ENTRY(desc->prioMatrix,r,c);
253 
254       if (p>=MAX_PRIO)
255         DUNE_THROW(Dune::Exception,
256                    "PriorityMerge(" << r << "," << c << ") yields"
257                    << p << " larger than " << (MAX_PRIO-1));
258     }
259   }
260 
261 
262   /* TODO: check for associativity */
263 
264 
265   return true;
266 }
267 
268 
269 
270 /****************************************************************************/
271 
272 
DDD_PrioMergeDefault(DDD::DDDContext & context,DDD_TYPE type_id,int priomerge_mode)273 void DDD_PrioMergeDefault (DDD::DDDContext& context, DDD_TYPE type_id, int priomerge_mode)
274 {
275   if (! SetPrioMatrix(&context.typeDefs()[type_id], priomerge_mode))
276     DUNE_THROW(Dune::Exception, "unknown defaultprio-mergemode in DDD_TYPE " << type_id);
277 }
278 
279 
280 
DDD_PrioMergeDefine(DDD::DDDContext & context,DDD_TYPE type_id,DDD_PRIO p1,DDD_PRIO p2,DDD_PRIO pres)281 void DDD_PrioMergeDefine (DDD::DDDContext& context, DDD_TYPE type_id,
282                           DDD_PRIO p1, DDD_PRIO p2, DDD_PRIO pres)
283 {
284   TYPE_DESC *desc = &context.typeDefs()[type_id];
285 
286   /* check for correct type */
287   if (! ddd_TypeDefined(desc))
288     DUNE_THROW(Dune::Exception, "undefined DDD_TYPE");
289 
290 
291   /* create prioMatrix on demand */
292   if (desc->prioMatrix == nullptr)
293   {
294     if (! SetPrioMatrix(desc, PRIOMERGE_DEFAULT))
295       DUNE_THROW(Dune::Exception, "error for DDD_TYPE " << type_id);
296   }
297 
298 
299   /* check input priorities */
300 
301   if (p1>=MAX_PRIO)
302     DUNE_THROW(Dune::Exception, "invalid priority p1=" << p1);
303   if (p2>=MAX_PRIO)
304     DUNE_THROW(Dune::Exception, "invalid priority p2=" << p2);
305   if (pres>=MAX_PRIO)
306     DUNE_THROW(Dune::Exception, "invalid priority pres=" << pres);
307 
308 
309   /* set prioMatrix entry */
310   if (p2<=p1)
311   {
312     PM_ENTRY(desc->prioMatrix,p1,p2) = pres;
313   }
314   else
315   {
316     PM_ENTRY(desc->prioMatrix,p2,p1) = pres;
317   }
318 
319 
320   /* finally always check prioMatrix, just to be sure */
321   if (!CheckPrioMatrix(desc))
322     DUNE_THROW(Dune::Exception,
323                "error(s) in merge-check for DDD_TYPE " << type_id);
324 }
325 
326 
327 /****************************************************************************/
328 
329 
330 /*
331         call merge operation from application program
332  */
DDD_PrioMerge(DDD::DDDContext & context,DDD_TYPE type_id,DDD_PRIO p1,DDD_PRIO p2)333 DDD_PRIO DDD_PrioMerge (DDD::DDDContext& context, DDD_TYPE type_id, DDD_PRIO p1, DDD_PRIO p2)
334 {
335   TYPE_DESC *desc = &context.typeDefs()[type_id];
336   DDD_PRIO newprio;
337 
338   /* check for correct type */
339   if (! ddd_TypeDefined(desc))
340     DUNE_THROW(Dune::Exception, "undefined DDD_TYPE");
341 
342   if (p1>=MAX_PRIO)
343     DUNE_THROW(Dune::Exception, "invalid priority p1=" << p1);
344   if (p2>=MAX_PRIO)
345     DUNE_THROW(Dune::Exception, "invalid priority p2=" << p2);
346 
347   if (PriorityMerge(desc, p1, p2, &newprio) == PRIO_ERROR)
348     DUNE_THROW(Dune::Exception, "cannot merge priorities");
349 
350   return newprio;
351 }
352 
353 
354 /****************************************************************************/
355 
prioMergeDefaultName(int prioDefault)356 static const char* prioMergeDefaultName(int prioDefault)
357 {
358   switch (prioDefault) {
359   case PRIOMERGE_MAXIMUM:
360     return "MAX";
361   case PRIOMERGE_MINIMUM:
362     return "MIN";
363   default:
364     return "(ERROR)";
365   }
366 }
367 
DDD_PrioMergeDisplay(DDD::DDDContext & context,DDD_TYPE type_id)368 void DDD_PrioMergeDisplay (DDD::DDDContext& context, DDD_TYPE type_id)
369 {
370   std::ostream& out = std::cout;
371   TYPE_DESC* desc = &context.typeDefs()[type_id];
372   int r, c, changed_rows[MAX_PRIO];
373 
374   if (context.me() != 0)
375     return;
376 
377   /* check for correct type */
378   if (! ddd_TypeDefined(desc))
379     DUNE_THROW(Dune::Exception, "undefined DDD_TYPE");
380 
381   out << "/ PrioMergeDisplay for '" << desc->name << "', default mode "
382       << prioMergeDefaultName(desc->prioDefault) << "\n";
383 
384   if (desc->prioMatrix == nullptr)
385   {
386     out << "\\ \t(no special cases defined)\n";
387     return;
388   }
389 
390   /* find out which rows/columns we will have to print */
391   for(r=0; r<MAX_PRIO; r++)
392   {
393     changed_rows[r] = false;
394 
395     for(c=0; c<MAX_PRIO; c++)
396     {
397       DDD_PRIO p_dflt, p_actual;
398 
399       PM_GETDEFAULT(desc->prioDefault, r, c, p_dflt);
400       PriorityMerge(desc, r, c, &p_actual);
401 
402       if (p_dflt != p_actual)
403         changed_rows[r] = true;
404     }
405   }
406 
407   /* print */
408   using std::setw;
409   out << "|\t     ";
410   for(c=0; c<MAX_PRIO; c++)
411   {
412     if (! changed_rows[c])
413       continue;
414 
415     out << " " << setw(3) << c << "  ";
416   }
417   out << "\n";
418 
419   for(r=0; r<MAX_PRIO; r++)
420   {
421     if (! changed_rows[r])
422       continue;
423 
424     out << "|\t" << setw(2) << r << " :  ";
425     for(c=0; c<MAX_PRIO; c++)
426     {
427       DDD_PRIO p_dflt, p_actual;
428 
429       if (! changed_rows[c])
430         continue;
431 
432       PM_GETDEFAULT(desc->prioDefault, r, c, p_dflt);
433       PriorityMerge(desc, r, c, &p_actual);
434 
435       if (p_dflt != p_actual)
436         out << " " << setw(3) << p_actual << "  ";
437       else
438         out << "(" << setw(3) << p_actual << ") ";
439     }
440 
441     out << "\n";
442   }
443 
444   out << "\\\n";
445 }
446 
447 /****************************************************************************/
448 
449 END_UGDIM_NAMESPACE
450