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;
Event var_deref_op: Dereferencing null variable "pmp".
Also see events: [var_compare_op][var_deref_op]
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) {
Event var_deref_op: Dereferencing null variable "pmp".
Also see events: [var_compare_op][var_deref_op]
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  	}