1 /*
2  * Copyright (c) 2017, NVIDIA CORPORATION.  All rights reserved.
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 "stdioInterf.h"
19 #include "fioMacros.h"
20 
21 #define DEFENTS (512)
22 
23 /* allocate channel structure */
24 
25 struct chdr *
__fort_allchn(struct chdr * cp,int dents,int sents,int cpus)26 __fort_allchn(struct chdr *cp, int dents, int sents, int cpus)
27 {
28   struct chdr *c;
29   struct chdr *ct;
30 
31   /* allocate new channel, ents, and cpu structures */
32 
33   c = (chdr *)__fort_calloc(sizeof(chdr) +
34                                (sizeof(struct ents) * (dents + sents)) +
35                                (sizeof(struct ccpu) * cpus),
36                            1);
37   c->sp = (struct ents *)((char *)c + sizeof(chdr));
38   c->sn = sents;
39   c->rp =
40       (struct ents *)((char *)c + sizeof(chdr) + (sizeof(struct ents) * sents));
41   c->rn = dents;
42   c->cp = (struct ccpu *)((char *)c + sizeof(chdr) +
43                           (sizeof(struct ents) * (sents + dents)));
44   c->cn = cpus;
45   c->flags = CHDR_1INT | CHDR_1DBL;
46 
47   /* chain structure into list */
48 
49   if (cp != (struct chdr *)0) {
50     ct = cp;
51     while (ct->next != (struct chdr *)0) {
52       ct = ct->next;
53     }
54     ct->next = c;
55   }
56 
57   return (c);
58 }
59 
60 /* free a list of channels */
61 
62 void
__fort_frechn(struct chdr * c)63 __fort_frechn(struct chdr *c)
64 {
65   struct chdr *d;
66   int n;
67 
68   while (c != (struct chdr *)0) {
69     for (n = 0; n < c->sn; n++) {
70       if (c->sp[n].beg != (struct ent *)0) {
71         __fort_free((char *)c->sp[n].beg);
72       }
73     }
74     for (n = 0; n < c->rn; n++) {
75       if (c->rp[n].beg != (struct ent *)0) {
76         __fort_free((char *)c->rp[n].beg);
77       }
78     }
79     for (n = 0; n < c->cn; n++) {
80       if (c->cp[n].opt != (void *)0) {
81         __fort_free((char *)c->cp[n].opt);
82       }
83     }
84     d = c->next;
85     __fort_free(c);
86     c = d;
87   }
88 }
89 
90 /* reset channels */
91 
92 void
__fort_rstchn(struct chdr * c)93 __fort_rstchn(struct chdr *c)
94 {
95   int n;
96 
97   while (c != (struct chdr *)0) {
98     for (n = 0; n < c->sn; n++) {
99       c->sp[n].avl = c->sp[n].beg;
100     }
101     for (n = 0; n < c->rn; n++) {
102       c->rp[n].avl = c->rp[n].beg;
103     }
104     c = c->next;
105   }
106 }
107 
108 /* send data */
109 
__fort_sendl(struct chdr * c,int indx,void * adr,long cnt,long str,int typ,long ilen)110 void __fort_sendl(struct chdr *c, /* channels */
111                  int indx,       /* indx to send to */
112                  void *adr,      /* adr of first data item */
113                  long cnt,       /* number of data items */
114                  long str,       /* stride between data items */
115                  int typ,        /* data type (see pghpft.h) */
116                  long ilen)      /* data item length */
117 {
118   register struct ents *s;
119   register int n;
120 
121 #ifdef DEBUG
122   if (indx >= c->sn) {
123     __fort_abort("__fort_send: index >= cpu count\n");
124   }
125 #endif
126   s = &(c->sp[indx]);
127   if (s->avl == s->end) {
128     n = s->end - s->beg;
129     if (s->beg == (struct ent *)0) {
130       s->beg = (struct ent *)__fort_malloc((n + DEFENTS) * sizeof(struct ent));
131     } else {
132       s->beg = (struct ent *)__fort_realloc(s->beg,
133                                            (n + DEFENTS) * sizeof(struct ent));
134     }
135     s->end = s->beg + n + DEFENTS;
136     s->avl = s->beg + n;
137   }
138   s->avl->adr = adr;
139   s->avl->cnt = cnt;
140   s->avl->str = str;
141   s->avl->typ = typ;
142   s->avl->ilen = ilen;
143   s->avl->len = cnt * ilen;
144   if (c->flags & (CHDR_1INT | CHDR_1DBL)) {
145     if (cnt != 1) {
146       c->flags &= ~(CHDR_1INT | CHDR_1DBL);
147     } else {
148       if (ilen != sizeof(int)) {
149         c->flags &= ~CHDR_1INT;
150       }
151       if (ilen != sizeof(double)) {
152         c->flags &= ~CHDR_1DBL;
153       }
154     }
155   }
156   s->avl++;
157 }
158 
159 /* recv data */
160 
__fort_recvl(struct chdr * c,int indx,void * adr,long cnt,long str,int typ,long ilen)161 void __fort_recvl(struct chdr *c, /* channels */
162                  int indx,       /* indx to receive from */
163                  void *adr,      /* adr of first data item */
164                  long cnt,       /* number of data items */
165                  long str,       /* stride between data items */
166                  int typ,        /* data type (see pghpft.h) */
167                  long ilen)      /* data item length */
168 {
169   register struct ents *r;
170   register int n;
171 
172 #ifdef DEBUG
173   if (indx >= c->rn) {
174     __fort_abort("__fort_recv: index >= cpu count\n");
175   }
176 #endif
177   r = &(c->rp[indx]);
178   if (r->avl == r->end) {
179     n = r->end - r->beg;
180     if (r->beg == (struct ent *)0) {
181       r->beg = (struct ent *)__fort_malloc((n + DEFENTS) * sizeof(struct ent));
182     } else {
183       r->beg = (struct ent *)__fort_realloc(r->beg,
184                                            (n + DEFENTS) * sizeof(struct ent));
185     }
186     r->end = r->beg + n + DEFENTS;
187     r->avl = r->beg + n;
188   }
189   r->avl->adr = adr;
190   r->avl->cnt = cnt;
191   r->avl->str = str;
192   r->avl->typ = typ;
193   r->avl->ilen = ilen;
194   r->avl->len = cnt * ilen;
195   if (c->flags & (CHDR_1INT | CHDR_1DBL)) {
196     if (cnt != 1) {
197       c->flags &= ~(CHDR_1INT | CHDR_1DBL);
198     } else {
199       if (ilen != sizeof(int)) {
200         c->flags &= ~CHDR_1INT;
201       }
202       if (ilen != sizeof(double)) {
203         c->flags &= ~CHDR_1DBL;
204       }
205     }
206   }
207   r->avl++;
208 }
209 
210 /* chain channels together */
211 
__fort_chain_em_up(struct chdr * list,struct chdr * c)212 struct chdr *__fort_chain_em_up(struct chdr *list, /* current and new head */
213                                struct chdr *c)    /* new tail */
214 {
215   struct chdr *ct;
216 
217   if (list == (struct chdr *)0) {
218     return (c);
219   }
220   ct = list;
221   while (ct->next != (struct chdr *)0) {
222     ct = ct->next;
223   }
224   ct->next = c;
225   return (list);
226 }
227 
228 /* change data addresses and type in list of channels */
229 
__fort_adjbase(struct chdr * c,char * bases,char * baser,int typ,long ilen)230 void __fort_adjbase(struct chdr *c, /* list of channels */
231                    char *bases,    /* send base address */
232                    char *baser,    /* recv base address */
233                    int typ,        /* data type */
234                    long ilen)      /* data item length */
235 {
236   struct ent *p;
237   int n;
238   long l;
239 
240   while (c != (struct chdr *)0) {
241     if (~c->flags & CHDR_BASE) {
242       __fort_abort("__fort_adjbase: setbase not called");
243     }
244     c->flags &= ~(CHDR_1INT | CHDR_1DBL);
245     if ((c->bases != bases) || (c->typ != typ) || (c->ilen != ilen)) {
246       if (c->ilen == ilen) {
247         for (n = 0; n < c->sn; n++) {
248           p = c->sp[n].beg;
249           while (p < c->sp[n].avl) {
250             l = p->adr - c->bases;
251             p->adr = l + bases;
252 #ifdef DEBUG
253             if (c->typ != p->typ)
254               __fort_abort("__fort_adjbase: inconsistent send data types");
255 #endif
256             p->typ = typ;
257             p++;
258           }
259         }
260       } else {
261         for (n = 0; n < c->sn; n++) {
262           p = c->sp[n].beg;
263           while (p < c->sp[n].avl) {
264             l = p->adr - c->bases;
265             l /= c->ilen;
266             l *= ilen;
267             p->adr = l + bases;
268 #ifdef DEBUG
269             if (c->typ != p->typ)
270               __fort_abort("__fort_adjbase: inconsistent send data types");
271 #endif
272             p->typ = typ;
273             p->ilen = ilen;
274             p->len = p->cnt * ilen;
275             p++;
276           }
277         }
278       }
279       c->bases = bases;
280     }
281     if ((c->baser != baser) || (c->typ != typ) || (c->ilen != ilen)) {
282       if (c->ilen == ilen) {
283         for (n = 0; n < c->rn; n++) {
284           p = c->rp[n].beg;
285           while (p < c->rp[n].avl) {
286             l = p->adr - c->baser;
287             p->adr = l + baser;
288 #ifdef DEBUG
289             if (c->typ != p->typ)
290               __fort_abort("__fort_adjbase: inconsistent recv data types");
291 #endif
292             p->typ = typ;
293             p++;
294           }
295         }
296       } else {
297         for (n = 0; n < c->rn; n++) {
298           p = c->rp[n].beg;
299           while (p < c->rp[n].avl) {
300             l = p->adr - c->baser;
301             l /= c->ilen;
302             l *= ilen;
303             p->adr = l + baser;
304 #ifdef DEBUG
305             if (c->typ != p->typ)
306               __fort_abort("__fort_adjbase: inconsistent recv data types");
307 #endif
308             p->typ = typ;
309             p->ilen = ilen;
310             p->len = p->cnt * ilen;
311             p++;
312           }
313         }
314       }
315       c->baser = baser;
316     }
317     c->typ = typ;
318     c->ilen = ilen;
319     c = c->next;
320   }
321 }
322 
323 /* set bases addresses and data type (called once after __fort_chn_xxx) */
324 
__fort_setbase(chdr * c,char * bases,char * baser,int typ,long ilen)325 void __fort_setbase(chdr *c,     /* list of channels */
326                    char *bases, /* send base address */
327                    char *baser, /* recv base address */
328                    int typ,     /* data type */
329                    long ilen)   /* data item length */
330 {
331 
332   while (c != (struct chdr *)0) {
333     c->flags |= CHDR_BASE;
334     c->bases = bases;
335     c->baser = baser;
336     c->typ = typ;
337     c->ilen = ilen;
338     c = c->next;
339   }
340 }
341 
342 /*
343  * keep track of the global buffer
344  *
345  * this routine should ONLY be used by routines called by __fort_doit and
346  * then only very carefully.
347  */
348 
349 #define GBUFA 4096 /* global buffer size alignment */
350 
351 static int gbufz;
352 static char *gbuf;
353 
354 char *
__fort_getgbuf(long len)355 __fort_getgbuf(long len)
356 {
357   if (len <= gbufz) {
358     return (gbuf);
359   }
360   if (gbuf != (char *)0) {
361     __fort_gfree(gbuf);
362   }
363   len = (len + GBUFA - 1) & ~(GBUFA - 1);
364   gbuf = __fort_gmalloc(len);
365   gbufz = len;
366   return (gbuf);
367 }
368 
369 /* prune unsed entries and do special optimizations */
370 
371 #define MINSHIFT 1024 /* smaller send values may be send */
372 
373 void
__fort_chn_prune(struct chdr * c)374 __fort_chn_prune(struct chdr *c)
375 {
376   struct ccpu *cp;
377   struct ccpu ccpu;
378   int n;
379   int m;
380 
381   while (c != (struct chdr *)0) {
382 
383     /* prune unused entries */
384 
385     m = 0;
386     for (n = 0; n < c->cn; n++) {
387       if (n != m) {
388         c->cp[m] = c->cp[n];
389       }
390       if (((c->cp[n].sp != (struct ents *)0) &&
391            (c->cp[n].sp->avl > c->cp[n].sp->beg)) ||
392           ((c->cp[n].rp != (struct ents *)0) &&
393            (c->cp[n].rp->avl > c->cp[n].rp->beg))) {
394         m++;
395       }
396     }
397     c->cn = m;
398 
399     c = c->next;
400   }
401 }
402