1 /*
2 * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved.
3 *
4 * This library is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as published
6 * by the Free Software Foundation; either version 2.1 of the License, or
7 * (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
12 * License for more details.
13 */
14
15 /*
16 * Generic routines to provide the "optimized" pmFetch bundling
17 * services ... the optimization is driven by the crude heuristics
18 * weights defined in optcost below.
19 */
20
21 /* if DESPERATE, we need DEBUG */
22 #if defined(DESPERATE) && !defined(PCP_DEBUG)
23 #define DEBUG
24 #endif
25
26 #include "pmapi.h"
27 #include "impl.h"
28
29 /*
30 * elements of optcost are
31 *
32 * c_pmid cost per PMD for PMIDs in a fetch
33 * c_indom cost per PMD for indoms in a fetch
34 * c_fetch cost of a new fetch group (should be less than
35 * c_indomsize * c_xtrainst, else all fetches will go
36 * into a single group, unless the scope is global)
37 * c_indomsize expected numer of instances for an indom
38 * c_xtrainst cost of retrieving an unwanted metric inst
39 * c_scope cost opt., 0 for incremental, 1 for global
40 */
41
42 /* default costs */
43 static optcost_t optcost = { 4, 1, 15, 10, 2, 0 };
44
45 static int
46 addpmid(fetchctl_t *fp, pmID pmid)
47 {
48 int i;
49 int j;
50
51 for (i = 0; i < fp->f_numpmid; i++) {
52 if (pmid == fp->f_pmidlist[i])
53 return 0;
54 if (pmid > fp->f_pmidlist[i])
55 break;
56 }
57 fp->f_numpmid++;
58 fp->f_pmidlist = (pmID *)realloc(fp->f_pmidlist, fp->f_numpmid*sizeof(pmID));
59 if (fp->f_pmidlist == NULL) {
60 __pmNoMem("addpmid", fp->f_numpmid*sizeof(pmID), PM_FATAL_ERR);
61 }
62
63 for (j = fp->f_numpmid-1; j > i; j--)
64 fp->f_pmidlist[j] = fp->f_pmidlist[j-1];
65 fp->f_pmidlist[i] = pmid;
66
67 return 1;
68 }
69
70 static int
71 addinst(int *numinst, int **instlist, optreq_t *new)
72 {
73 int i;
74 int j;
75 int k;
76 int numi;
77 int *ilist;
78 int match;
79
80 if (*numinst == 0)
81 return 0;
82 if (new->r_numinst == 0) {
83 *numinst = 0;
84 if (*instlist != NULL) {
85 free(*instlist);
86 *instlist = NULL;
87 }
88 return 1;
89 }
90 numi = *numinst;
91 if (numi == -1)
92 numi = 0;
93
94 ilist = (int *)realloc(*instlist, (numi + new->r_numinst)*sizeof(int));
95 if (ilist == NULL) {
96 __pmNoMem("addinst.up", (numi + new->r_numinst)*sizeof(int), PM_FATAL_ERR);
97 }
98
99 for (j = 0; j < new->r_numinst; j++) {
100 match = 0;
101 for (i = 0; i < numi; i++) {
102 if (ilist[i] == new->r_instlist[j]) {
103 match = 1;
104 break;
105 }
106 if (ilist[i] > new->r_instlist[j])
107 break;
108 }
109 if (match)
110 continue;
111 for (k = numi; k > i; k--)
112 ilist[k] = ilist[k-1];
113 ilist[i] = new->r_instlist[j];
114 numi++;
115 }
116
117 ilist = (int *)realloc(ilist, numi*sizeof(int));
118 if (ilist == NULL) {
119 __pmNoMem("addinst.down", numi*sizeof(int), PM_FATAL_ERR);
120 }
121
122 *numinst = numi;
123 *instlist = ilist;
124
125 return 1;
126 }
127
128 /*
129 * if we retrieve the instances identified by numa and lista[], how much larger
130 * is this than the set of instances identified by numb and listb[]?
131 */
132 static int
133 missinst(int numa, int *lista, int numb, int *listb)
134 {
135 int xtra = 0;
136 int i;
137 int j;
138
139 /* count in lista[] but _not_ in listb[] */
140 if (numa == 0) {
141 /* special case for all instances in lista[] */
142 if (numb != 0 && numb < optcost.c_indomsize)
143 xtra += optcost.c_indomsize - numb;
144 }
145 else {
146 /* not all instances for both lista[] and listb[] */
147 i = 0;
148 j = 0;
149 while (i < numa && j < numb) {
150 if (lista[i] == listb[j]) {
151 i++;
152 j++;
153 }
154 else if (lista[i] < listb[j]) {
155 i++;
156 xtra++;
157 }
158 else {
159 j++;
160 xtra++;
161 }
162 }
163 xtra += (numa - i) + (numb - j);
164 }
165
166 return xtra;
167 }
168
169 static void
170 redoinst(fetchctl_t *fp)
171 {
172 indomctl_t *idp;
173 pmidctl_t *pmp;
174 optreq_t *rqp;
175
176 for (idp = fp->f_idp; idp != NULL; idp = idp->i_next) {
177 idp->i_numinst = -1;
178 for (pmp = idp->i_pmp; pmp != NULL; pmp = pmp->p_next) {
179 pmp->p_numinst = -1;
180 for (rqp = pmp->p_rqp; rqp != NULL; rqp = rqp->r_next) {
181 addinst(&pmp->p_numinst, &pmp->p_instlist, rqp);
182 addinst(&idp->i_numinst, &idp->i_instlist, rqp);
183 }
184 }
185 }
186 }
187
188 static void
189 redopmid(fetchctl_t *fp)
190 {
191 indomctl_t *idp;
192 pmidctl_t *pmp;
193
194 fp->f_numpmid = 0;
195 for (idp = fp->f_idp; idp != NULL; idp = idp->i_next) {
196 for (pmp = idp->i_pmp; pmp != NULL; pmp = pmp->p_next) {
197 addpmid(fp, pmp->p_pmid);
198 }
199 }
200 }
201
202 static int
203 optCost(fetchctl_t *fp)
204 {
205 indomctl_t *idp;
206 indomctl_t *xidp;
207 pmidctl_t *pmp;
208 pmidctl_t *xpmp;
209 __pmID_int *pmidp;
210 __pmInDom_int *indomp;
211 int pmd;
212 int cost = 0;
213 int done;
214
215 /*
216 * cost per PMD for the pmids in this fetch
217 */
218 for (idp = fp->f_idp; idp != NULL; idp = idp->i_next) {
219 for (pmp = idp->i_pmp; pmp != NULL; pmp = pmp->p_next) {
220 pmidp = (__pmID_int *)&pmp->p_pmid;
221 pmd = pmidp->domain;
222 done = 0;
223 for (xidp = fp->f_idp; xidp != NULL; xidp = xidp->i_next) {
224 for (xpmp = xidp->i_pmp; xpmp != NULL; xpmp = xpmp->p_next) {
225 pmidp = (__pmID_int *)&xpmp->p_pmid;
226 if (xpmp != pmp && pmd == pmidp->domain) {
227 done = 1;
228 break;
229 }
230 if (xpmp == pmp) {
231 cost += optcost.c_pmid;
232 done = 1;
233 break;
234 }
235 }
236 if (done || xidp == idp)
237 break;
238 }
239 }
240 }
241
242 /*
243 * cost per PMD for the indoms in this fetch
244 */
245 for (idp = fp->f_idp; idp != NULL; idp = idp->i_next) {
246 indomp = (__pmInDom_int *)&idp->i_indom;
247 pmd = indomp->domain;
248 for (xidp = fp->f_idp; xidp != idp; xidp = xidp->i_next) {
249 indomp = (__pmInDom_int *)&xidp->i_indom;
250 if (pmd == indomp->domain)
251 break;
252 }
253 if (xidp == idp)
254 cost += optcost.c_indom;
255 }
256
257 /*
258 * cost for extra retrievals due to multiple metrics over the same indom
259 */
260 for (idp = fp->f_idp; idp != NULL; idp = idp->i_next) {
261 for (pmp = idp->i_pmp; pmp != NULL; pmp = pmp->p_next) {
262 cost += optcost.c_xtrainst * missinst(idp->i_numinst, idp->i_instlist, pmp->p_numinst, pmp->p_instlist);
263 }
264 }
265
266 return cost;
267 }
268
269 #ifdef PCP_DEBUG
270 static char *
271 statestr(int state)
272 {
273 static char sbuf[100];
274 sbuf[0] = '\0';
275 if (state & OPT_STATE_NEW) strcat(sbuf, "NEW ");
276 if (state & OPT_STATE_PMID) strcat(sbuf, "PMID ");
277 if (state & OPT_STATE_PROFILE) strcat(sbuf, "PROFILE ");
278 if (state & OPT_STATE_XREQ) strcat(sbuf, "XREQ ");
279 if (state & OPT_STATE_XPMID) strcat(sbuf, "XPMID ");
280 if (state & OPT_STATE_XINDOM) strcat(sbuf, "XINDOM ");
281 if (state & OPT_STATE_XFETCH) strcat(sbuf, "XFETCH ");
282 if (state & OPT_STATE_XPROFILE) strcat(sbuf, "XPROFILE ");
283
284 return sbuf;
285 }
286
287 static void
288 dumplist(FILE *f, int style, char *tag, int numi, int *ilist)
289 {
290 fprintf(f, "%s: [%d]", tag, numi);
291 if (ilist == NULL)
292 fprintf(f, " (nil)\n");
293 else {
294 int i;
295 for (i = 0; i < numi; i++) {
296 if (style == 1)
297 fprintf(f, " %s", pmIDStr((pmID)ilist[i]));
298 else
299 fprintf(f, " %d", ilist[i]);
300 }
301 fputc('\n', f);
302 }
303 }
304
305 static void
306 ___pmOptFetchDump(FILE *f, const fetchctl_t *fp)
307 {
308 indomctl_t *idp;
309 pmidctl_t *pmp;
310 optreq_t *rqp;
311
312 fflush(stderr);
313 fflush(stdout);
314 fprintf(f, "Dump optfetch structures from " PRINTF_P_PFX "%p next=" PRINTF_P_PFX "%p\n", fp, fp->f_next);
315 fprintf(f, "Fetch Control @ " PRINTF_P_PFX "%p: cost=%d state=%s\n", fp, fp->f_cost, statestr(fp->f_state));
316 dumplist(f, 1, "PMIDs", fp->f_numpmid, (int *)fp->f_pmidlist);
317 for (idp = fp->f_idp; idp != NULL; idp = idp->i_next) {
318 fprintf(f, " InDom %s Control @ " PRINTF_P_PFX "%p:\n", pmInDomStr(idp->i_indom), idp);
319 dumplist(f, 0, " instances", idp->i_numinst, idp->i_instlist);
320 for (pmp = idp->i_pmp; pmp != NULL; pmp = pmp->p_next) {
321 fprintf(f, " PMID %s Control @ " PRINTF_P_PFX "%p:\n", pmIDStr(pmp->p_pmid), pmp);
322 dumplist(f, 0, " instances", pmp->p_numinst, pmp->p_instlist);
323 for (rqp = pmp->p_rqp; rqp != NULL; rqp = rqp->r_next) {
324 fprintf(f, " Request @ " PRINTF_P_PFX "%p:\n", rqp);
325 dumplist(f, 0, " instances", rqp->r_numinst, rqp->r_instlist);
326 }
327 }
328 }
329 fputc('\n', f);
330 fflush(f);
331 }
332
333 void
334 __pmOptFetchDump(FILE *f, const fetchctl_t *root)
335 {
336 const fetchctl_t *fp;
337
338 for (fp = root; fp != NULL; fp = fp->f_next)
339 ___pmOptFetchDump(f, fp);
340 }
341 #endif /* DEBUG */
342
343 /*
344 * add a new request into a group of fetches
345 */
346 int
347 __pmOptFetchAdd(fetchctl_t **root, optreq_t *new)
348 {
349 fetchctl_t *fp;
350 fetchctl_t *tfp;
351 indomctl_t *idp;
352 pmidctl_t *pmp = NULL;
353 int mincost;
354 int change;
355 pmInDom indom = new->r_desc->indom;
356 pmID pmid = new->r_desc->pmid;
357
358 /* add new fetch as first option ... will be reclaimed later if not used */
359 if ((fp = (fetchctl_t *)calloc(1, sizeof(fetchctl_t))) == NULL) {
360 __pmNoMem("optAddFetch.fetch", sizeof(fetchctl_t), PM_FATAL_ERR);
361 }
362 fp->f_next = *root;
363 *root = fp;
364
365 for (fp = *root; fp != NULL; fp = fp->f_next) {
366 fp->f_cost = optCost(fp);
367
368 change = OPT_STATE_XINDOM | OPT_STATE_XPMID | OPT_STATE_XREQ;
369 for (idp = fp->f_idp; idp != NULL; idp = idp->i_next) {
370 if (idp->i_indom != indom)
371 continue;
372 change = OPT_STATE_XPMID | OPT_STATE_XREQ;
373 for (pmp = idp->i_pmp; pmp != NULL; pmp = pmp->p_next) {
374 if (pmp->p_pmid == pmid) {
375 change = OPT_STATE_XREQ;
376 break;
377 }
378 }
379 break;
380 }
381 if (fp == *root)
382 change |= OPT_STATE_XFETCH;
383 fp->f_state = (fp->f_state & OPT_STATE_UMASK) | change;
384
385 if (change & OPT_STATE_XINDOM) {
386 if ((idp = (indomctl_t *)calloc(1, sizeof(indomctl_t))) == NULL) {
387 __pmNoMem("optAddFetch.indomctl", sizeof(indomctl_t), PM_FATAL_ERR);
388 }
389 idp->i_indom = indom;
390 idp->i_next = fp->f_idp;
391 idp->i_numinst = -1;
392 fp->f_idp = idp;
393 }
394 if (change & OPT_STATE_XPMID) {
395 if ((pmp = (pmidctl_t *)calloc(1, sizeof(pmidctl_t))) == NULL) {
396 __pmNoMem("optAddFetch.pmidctl", sizeof(pmidctl_t), PM_FATAL_ERR);
397 }
398 pmp->p_next = idp->i_pmp;
399 idp->i_pmp = pmp;
400 pmp->p_pmid = pmid;
401 pmp->p_numinst = -1;
402 }
403 addinst(&pmp->p_numinst, &pmp->p_instlist, new);
404 if (addinst(&idp->i_numinst, &idp->i_instlist, new))
405 fp->f_state |= OPT_STATE_XPROFILE;
406
407 fp->f_newcost = optCost(fp);
408 if (fp == *root)
409 fp->f_newcost += optcost.c_fetch;
410 #ifdef DESPERATE
411 if (pmDebug & DBG_TRACE_OPTFETCH) {
412 fprintf(stderr, "optFetch: cost=");
413 if (fp->f_cost == OPT_COST_INFINITY)
414 fprintf(stderr, "INFINITY");
415 else
416 fprintf(stderr, "%d", fp->f_cost);
417 fprintf(stderr, ", newcost=");
418 if (fp->f_newcost == OPT_COST_INFINITY)
419 fprintf(stderr, "INFINITY");
420 else
421 fprintf(stderr, "%d", fp->f_newcost);
422 fprintf(stderr, ", for %s @ grp 0x%x, state %s\n",
423 pmIDStr(pmid), fp, statestr(fp->f_state));
424 }
425 #endif
426 }
427
428 tfp = NULL;
429 mincost = OPT_COST_INFINITY;
430 for (fp = *root; fp != NULL; fp = fp->f_next) {
431 int cost;
432 if (optcost.c_scope)
433 /* global */
434 cost = fp->f_newcost;
435 else
436 /* local */
437 cost = fp->f_newcost - fp->f_cost;
438 if (cost < mincost) {
439 mincost = cost;
440 tfp = fp;
441 }
442 }
443 #ifdef DESPERATE
444 if (pmDebug & DBG_TRACE_OPTFETCH) {
445 fprintf(stderr, "optFetch: chose %s cost=%d for %s @ grp 0x%x, change %s\n",
446 optcost.c_scope ? "global" : "incremental",
447 mincost, pmIDStr(pmid), tfp, statestr(tfp->f_state));
448 }
449 #endif
450
451 /*
452 * Warning! Traversal of the list is a bit tricky, because the
453 * current element (fp) may be freed, making fp->fp_next
454 * a bad idea at the end of each iteration ...
455 */
456 for (fp = *root; fp != NULL; ) {
457 for (idp = fp->f_idp; idp != NULL; idp = idp->i_next) {
458 if (idp->i_indom != indom)
459 continue;
|
Event var_compare_op: |
Comparing "pmp" to null implies that "pmp" might be null. |
| Also see events: |
[var_deref_op][var_deref_op] |
|
At conditional (1): "pmp != NULL": Taking false branch.
|
460 for (pmp = idp->i_pmp; pmp != NULL; pmp = pmp->p_next) {
461 if (pmp->p_pmid == pmid)
462 break;
463 }
464 break;
465 }
|
At conditional (2): "fp == tfp": Taking true branch.
|
466 if (fp == tfp) {
467 /*
468 * The chosen one ...
469 */
|
At conditional (3): "fp->f_state & 0x40": Taking true branch.
|
470 if (fp->f_state & OPT_STATE_XFETCH)
471 fp->f_state |= OPT_STATE_NEW;
|
At conditional (4): "addpmid(tfp, pmid)": Taking false branch.
|
472 if (addpmid(tfp, pmid))
473 fp->f_state |= OPT_STATE_PMID;
|
At conditional (5): "fp->f_state & 0x80": Taking true branch.
|
474 if (fp->f_state & OPT_STATE_XPROFILE)
475 fp->f_state |= OPT_STATE_PROFILE;
476 new->r_next = pmp->p_rqp;
477 new->r_fetch = tfp;
478 pmp->p_rqp = new;
479 fp->f_cost = fp->f_newcost;
480 fp->f_state &= OPT_STATE_UMASK;
481 fp = fp->f_next;
482 }
483 else {
484 /*
485 * Otherwise, need to undo changes made to data structures.
486 * Note. if new structures added, they will be at the start of
487 * their respective lists.
488 */
489 if (fp->f_state & OPT_STATE_XPMID) {
490 idp->i_pmp = pmp->p_next;
491 free(pmp);
492 }
493 if (fp->f_state & OPT_STATE_XINDOM) {
494 fp->f_idp = idp->i_next;
495 free(idp);
496 }
497 if (fp->f_state & OPT_STATE_XFETCH) {
498 *root = fp->f_next;
499 free(fp);
500 fp = *root;
501 }
502 else {
503 redoinst(fp);
504 fp->f_state &= OPT_STATE_UMASK;
505 fp = fp->f_next;
506 }
507 }
508 }
509
510 return 0;
511 }
512
513 /*
514 * remove a request from a group of fetches
515 */
516 int
517 __pmOptFetchDel(fetchctl_t **root, optreq_t *new)
518 {
519 fetchctl_t *fp;
520 fetchctl_t *p_fp;
521 indomctl_t *idp;
522 indomctl_t *p_idp;
523 pmidctl_t *pmp;
524 pmidctl_t *p_pmp;
525 optreq_t *rqp;
526 optreq_t *p_rqp;
527
528 p_fp = NULL;
529 for (fp = *root; fp != NULL; fp = fp->f_next) {
530 p_idp = NULL;
531 for (idp = fp->f_idp; idp != NULL; idp = idp->i_next) {
532 p_pmp = NULL;
533 for (pmp = idp->i_pmp; pmp != NULL; pmp = pmp->p_next) {
534 p_rqp = NULL;
535 for (rqp = pmp->p_rqp; rqp != NULL; rqp = rqp->r_next) {
536 if (rqp == new) {
537 if (p_rqp != NULL)
538 /* not first request for this metric */
539 p_rqp->r_next = rqp->r_next;
540 else if (rqp->r_next != NULL)
541 /* first of several requests for this metric */
542 pmp->p_rqp = rqp->r_next;
543 else {
544 /* only request for this metric */
545 if (p_pmp != NULL)
546 /* not first metric for this indom */
547 p_pmp->p_next = pmp->p_next;
548 else if (pmp->p_next != NULL)
549 /* first of several metrics for this indom */
550 idp->i_pmp = pmp->p_next;
551 else {
552 /* only metric for this indom */
553 if (p_idp != NULL)
554 /* not first indom for this fetch */
555 p_idp->i_next = idp->i_next;
556 else if (idp->i_next != NULL)
557 /* first of several idoms for this fetch */
558 fp->f_idp = idp->i_next;
559 else {
560 /* only indom for this fetch */
561 if (p_fp != NULL)
562 /* not first fetch for the group */
563 p_fp->f_next = fp->f_next;
564 else
565 /* first of fetch for the group */
566 *root = fp->f_next;
567 free(fp);
568 fp = NULL;
569 }
570 free(idp);
571 }
572 free(pmp);
573 }
574 /* data structures repaired, now redo lists */
575 if (fp != NULL) {
576 redoinst(fp);
577 redopmid(fp);
578 fp->f_state = OPT_STATE_PMID | OPT_STATE_PROFILE;
579 fp->f_cost = optCost(fp);
580 }
581 return 0;
582 }
583 p_rqp = rqp;
584 }
585 p_pmp = pmp;
586 }
587 p_idp = idp;
588 }
589 p_fp = fp;
590 }
591 return -1;
592 }
593
594 int
595 __pmOptFetchRedo(fetchctl_t **root)
596 {
597 fetchctl_t *newroot = NULL;
598 fetchctl_t *fp;
599 fetchctl_t *t_fp;
600 indomctl_t *idp;
601 indomctl_t *t_idp;
602 pmidctl_t *pmp;
603 pmidctl_t *t_pmp;
604 optreq_t *rqp;
605 optreq_t *t_rqp;
606 optreq_t *p_rqp;
607 optreq_t *rlist;
608 int numreq;
609
610 rlist = NULL;
611 numreq = 0;
612 /*
613 * collect all of the requests first
614 */
615 for (fp = *root; fp != NULL; ) {
616 for (idp = fp->f_idp; idp != NULL; ) {
617 for (pmp = idp->i_pmp; pmp != NULL; ) {
618 for (rqp = pmp->p_rqp; rqp != NULL; ) {
619 t_rqp = rqp->r_next;
620 rqp->r_next = rlist;
621 rlist = rqp;
622 rqp = t_rqp;
623 numreq++;
624 }
625 t_pmp = pmp;
626 pmp = pmp->p_next;
627 free(t_pmp);
628 }
629 t_idp = idp;
630 idp = idp->i_next;
631 free(t_idp);
632 }
633 t_fp = fp;
634 fp = fp->f_next;
635 free(t_fp);
636 }
637
638 if (numreq) {
639 /* something to do, randomly cut and splice the list of requests */
640 numreq = (int)lrand48() % numreq;
641 t_rqp = rlist;
642 p_rqp = NULL;
643 for (rqp = rlist; rqp != NULL; rqp = rqp->r_next) {
644 if (numreq == 0)
645 t_rqp = rqp;
646 numreq--;
647 p_rqp = rqp;
648 }
649 if (p_rqp == NULL || t_rqp == rlist)
650 /* do nothing */
651 ;
652 else {
653 /* p_rqp is end of list, t_rqp is new head */
654 p_rqp->r_next = rlist;
655 rlist = t_rqp->r_next;
656 t_rqp->r_next = NULL;
657 }
658
659 /* now add them all back again */
660 for (rqp = rlist; rqp != NULL; ) {
661 /* warning, rqp->r_next may change */
662 t_rqp = rqp->r_next;
663 __pmOptFetchAdd(&newroot, rqp);
664 rqp = t_rqp;
665 }
666 }
667
668 *root = newroot;
669 return 0;
670 }
671
672 int
673 __pmOptFetchGetParams(optcost_t *ocp)
674 {
675 *ocp = optcost;
676 return 0;
677 }
678
679 int
680 __pmOptFetchPutParams(optcost_t *ocp)
681 {
682 optcost = *ocp;
683 return 0;
684 }