<commit_before>/*
 * pmResult rewrite methods for pmlogrewrite
 *
 * Copyright (c) 2011 <NAME>.  All Rights Reserved.
 * 
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 *
 * pmResult rewriting is complicated because ...
 *
 * - deleting a metric involves moving all of the following rp->vset[]
 *   entries "up" one position and decrementing rp->numpmid
 * - deleting an instance involves moving all of the following
 *   rp->vset[i]->vlist[] enties "up" one position and then decrementing
 *   rp->vset[i]->numval
 * - rescaling values involves calling __pmStuffValue which modifies
 *   rp->vset[i]->vlist[j].value, and in the case of all types other than
 *   U32 or 32 this will involve an allocation for a new pmValueBlock
 *   ... we need to keep track of the previous pmValueBlock (if any) to
 *   avoid memory leaks
 * - changing type has the same implications as rescaling
 * - a single metric within a pmResult may have both rescaling and type
 *   change
 * - the initial pmResult contains pointers into a PDU buffer so the fast
 *   track case in pmFreeresult() may not release any of the pmValueSet
 *   or pmValue or pmValueBlock allocations if pmFreeResult is given a
 *   rewritten pmResult, so we modify the pmResult in place but use save[]
 *   to remember the original pmValueSet when retyping or rescaling, use
 *   orig_numval[] to remember how many pmValue instances we had had for
 *   each pmValueSet, and use orig_numpmid to remember the original numpmid
 *   value
 */

#include "pmapi.h"
#include "impl.h"
#include "logger.h"
#include <assert.h>

/* for __pmPool* alloc */
#define MAGIC PM_VAL_HDR_SIZE + sizeof(__int64_t)

/*
 * Keep track of pmValueSets that have been moved aside to allow for
 * new values from __pmStuffValue() during rewriting.
 */
static pmValueSet	**save = NULL;
static int		len_save = 0;

/*
 * Save rp->vset[idx] in save[idx], and build a new rp->vset[idx]
 * for the number of values expected for this metric
 */
static int
save_vset(pmResult *rp, int idx)
{
    pmValueSet	*vsp;
    int		need;
    int		j;

    if (save[idx] != NULL)
	/* already done */
	return 1;

    vsp = save[idx] = rp->vset[idx];

    if (vsp->numval > 0)
	need = sizeof(pmValueSet) + (vsp->numval-1)*sizeof(pmValue);
    else
	need = sizeof(pmValueSet);
    rp->vset[idx] = (pmValueSet *)malloc(need);
    if (rp->vset[idx] == NULL) {
	fprintf(stderr, "save_vset: malloc(%d) failed: %s\n", need, strerror(errno));
	exit(1);
    }
    rp->vset[idx]->pmid = vsp->pmid;
    rp->vset[idx]->numval = vsp->numval;
    rp->vset[idx]->valfmt = vsp->valfmt;
    for (j = 0; j < vsp->numval; j++)
	rp->vset[idx]->vlist[j].inst = vsp->vlist[j].inst;
#ifdef PCP_DEBUG
    if (pmDebug & DBG_TRACE_APPL2) {
	fprintf(stderr, "save_vset: vset[%d] -> " PRINTF_P_PFX "%p (was " PRINTF_P_PFX "%p) pmid=%s numval=%d\n",
		idx, rp->vset[idx], save[idx], pmIDStr(rp->vset[idx]->pmid), rp->vset[idx]->numval);
    }
#endif
    return 0;
}

/*
 * free the pval for the jth instance of the ith metric
 */
static void
free_pval(pmResult *rp, int i, int j)
{
    if (rp->vset[i]->vlist[j].value.pval->vlen == MAGIC) {
#ifdef PCP_DEBUG
	if (pmDebug & DBG_TRACE_APPL2) {
	    fprintf(stderr, "free_pval: __pmPoolFree(" PRINTF_P_PFX "%p) pmid=%s inst=%d\n",
		rp->vset[i]->vlist[j].value.pval, pmIDStr(rp->vset[i]->pmid), rp->vset[i]->vlist[j].inst);
	}
#endif
	__pmPoolFree(rp->vset[i]->vlist[j].value.pval, MAGIC);
    }
    else {
#ifdef PCP_DEBUG
	if (pmDebug & DBG_TRACE_APPL2) {
	    fprintf(stderr, "free_pval: free(" PRINTF_P_PFX "%p) pmid=%s inst=%d\n",
		rp->vset[i]->vlist[j].value.pval, pmIDStr(rp->vset[i]->pmid), rp->vset[i]->vlist[j].inst);
	}
#endif
	free(rp->vset[i]->vlist[j].value.pval);
    }
}

/*
 * if a pmValueSet was saved via save_vset(), then free the newly build 
 * pmValueSet and put the old one back in place
 */
static void
clean_vset(pmResult *rp)
{
    int		i;
    int		j;

    for (i = 0; i < rp->numpmid; i++) {
	if (save[i] != NULL) {
	    if (rp->vset[i]->valfmt == PM_VAL_DPTR) {
		/* values hanging off the pval */
		for (j = 0; j < rp->vset[i]->numval; j++)
		    free_pval(rp, i, j);
	    }
	    /*
	     * we did the vset[i] allocation in save_vset(), so malloc()
	     * and no __pmPoolAlloc() cases
	     */
#ifdef PCP_DEBUG
	    if (pmDebug & DBG_TRACE_APPL2) {
		fprintf(stderr, "clean_vset: free(" PRINTF_P_PFX "%p) pmValueSet pmid=%s\n",
			rp->vset[i], pmIDStr(rp->vset[i]->pmid));
	    }
#endif
	    free(rp->vset[i]);
	    rp->vset[i] = save[i];
	    save[i] = NULL;
	}
    }
}

/*
 * pick/calculate one value from multiple values for the ith vset[] ...
 */
static int
pick_val(int i, metricspec_t *mp)
{
    int		j;
    int		pick = -1;

    assert(inarch.rp->vset[i]->numval > 0);

    for (j = 0; j < inarch.rp->vset[i]->numval; j++) {
	if (mp->output == OUTPUT_ONE) {
	    if (inarch.rp->vset[i]->vlist[j].inst == mp->one_inst) {
		pick = j;
		break;
	    }
	    continue;
	}
	if (j == 0) {
	    pick = 0;
	    if (mp->output == OUTPUT_MIN || mp->output == OUTPUT_MAX ||
	        mp->output == OUTPUT_SUM || mp->output == OUTPUT_AVG)
		continue;
	}
	switch (mp->old_desc.type) {
	    case PM_TYPE_32:
		switch (mp->output) {
		    case OUTPUT_MIN:
			if (inarch.rp->vset[i]->vlist[j].value.lval < inarch.rp->vset[i]->vlist[pick].value.lval)
			    pick = j;
			break;
		    case OUTPUT_MAX:
			if (inarch.rp->vset[i]->vlist[j].value.lval > inarch.rp->vset[i]->vlist[pick].value.lval)
			    pick = j;
			break;
		    case OUTPUT_SUM:
		    case OUTPUT_AVG:
			inarch.rp->vset[i]->vlist[0].value.lval += inarch.rp->vset[i]->vlist[j].value.lval;
			break;
		}
		break;
	    case PM_TYPE_U32:
		switch (mp->output) {
		    case OUTPUT_MIN:
			if ((__uint32_t)inarch.rp->vset[i]->vlist[j].value.lval < (__uint32_t)inarch.rp->vset[i]->vlist[pick].value.lval)
			    pick = j;
			break;
		    case OUTPUT_MAX:
			if ((__uint32_t)inarch.rp->vset[i]->vlist[j].value.lval > (__uint32_t)inarch.rp->vset[i]->vlist[pick].value.lval)
			    pick = j;
			break;
		    case OUTPUT_SUM:
		    case OUTPUT_AVG:
			*(__uint32_t *)&inarch.rp->vset[i]->vlist[0].value.lval += (__uint32_t)inarch.rp->vset[i]->vlist[j].value.lval;
			break;
		}
		break;
	    case PM_TYPE_64:
		switch (mp->output) {
		    case OUTPUT_MIN:
			if (*(__int64_t *)inarch.rp->vset[i]->vlist[j].value.pval->vbuf < *(__int64_t *)inarch.rp->vset[i]->vlist[pick].value.pval->vbuf)
			    pick = j;
			break;
		    case OUTPUT_MAX:
			if (*(__int64_t *)inarch.rp->vset[i]->vlist[j].value.pval->vbuf > *(__int64_t *)inarch.rp->vset[i]->vlist[pick].value.pval->vbuf)
			    pick = j;
			break;
		    case OUTPUT_SUM:
		    case OUTPUT_AVG:
			*(__int64_t *)inarch.rp->vset[i]->vlist[0].value.pval->vbuf += *(__int64_t *)inarch.rp->vset[i]->vlist[j].value.pval->vbuf;
			break;
		}
		break;
	    case PM_TYPE_U64:
		switch (mp->output) {
		    case OUTPUT_MIN:
			if (*(__uint64_t *)inarch.rp->vset[i]->vlist[j].value.pval->vbuf < *(__uint64_t *)inarch.rp->vset[i]->vlist[pick].value.pval->vbuf)
			    pick = j;
			break;
		    case OUTPUT_MAX:
			if (*(__uint64_t *)inarch.rp->vset[i]->vlist[j].value.pval->vbuf > *(__uint64_t *)inarch.rp->vset[i]->vlist[pick].value.pval->vbuf)
			    pick = j;
			break;
		    case OUTPUT_SUM:
		    case OUTPUT_AVG:
			*(__uint64_t *)inarch.rp->vset[i]->vlist[0].value.pval->vbuf += *(__uint64_t *)inarch.rp->vset[i]->vlist[j].value.pval->vbuf;
			break;
		}
		break;
	    case PM_TYPE_FLOAT:
		switch (mp->output) {
		    case OUTPUT_MIN:
			if (*(float *)inarch.rp->vset[i]->vlist[j].value.pval->vbuf < *(float *)inarch.rp->vset[i]->vlist[pick].value.pval->vbuf)
			    pick = j;
			break;
		    case OUTPUT_MAX:
			if (*(float *)inarch.rp->vset[i]->vlist[j].value.pval->vbuf > *(float *)inarch.rp->vset[i]->vlist[pick].value.pval->vbuf)
			    pick = j;
			break;
		    case OUTPUT_SUM:
		    case OUTPUT_AVG:
			*(float *)inarch.rp->vset[i]->vlist[0].value.pval->vbuf += *(float *)inarch.rp->vset[i]->vlist[j].value.pval->vbuf;
			break;
		}
		break;
	    case PM_TYPE_DOUBLE:
		switch (mp->output) {
		    case OUTPUT_MIN:
			if (*(double *)inarch.rp->vset[i]->vlist[j].value.pval->vbuf < *(double *)inarch.rp->vset[i]->vlist[pick].value.pval->vbuf)
			    pick = j;
			break;
		    case OUTPUT_MAX:
			if (*(double *)inarch.rp->vset[i]->vlist[j].value.pval->vbuf > *(double *)inarch.rp->vset[i]->vlist[pick].value.pval->vbuf)
			    pick = j;
			break;
		    case OUTPUT_SUM:
		    case OUTPUT_AVG:
			*(double *)inarch.rp->vset[i]->vlist[0].value.pval->vbuf += *(double *)inarch.rp->vset[i]->vlist[j].value.pval->vbuf;
			break;
		}
		break;
	}
    }

    if (mp->output == OUTPUT_AVG) {
	switch (mp->old_desc.type) {
	    case PM_TYPE_32:
		inarch.rp->vset[i]->vlist[0].value.lval = (int)(0.5 + inarch.rp->vset[i]->vlist[0].value.lval / (double)inarch.rp->vset[i]->numval);
		break;
	    case PM_TYPE_U32:
		*(__uint32_t *)&inarch.rp->vset[i]->vlist[0].value.lval = (__uint32_t)(0.5 + *(__uint32_t *)&inarch.rp->vset[i]->vlist[0].value.lval / (double)inarch.rp->vset[i]->numval);
		break;
	    case PM_TYPE_64:
		*(__int64_t *)inarch.rp->vset[i]->vlist[0].value.pval->vbuf = (int64_t)(0.5 + *(__int64_t *)inarch.rp->vset[i]->vlist[0].value.pval->vbuf / (double)inarch.rp->vset[i]->numval);
		break;
	    case PM_TYPE_U64:
		*(__uint64_t *)inarch.rp->vset[i]->vlist[0].value.pval->vbuf = (__uint64_t)(0.5 + *(__uint64_t *)inarch.rp->vset[i]->vlist[0].value.pval->vbuf / (double)inarch.rp->vset[i]->numval);
		break;
	    case PM_TYPE_FLOAT:
		*(float *)inarch.rp->vset[i]->vlist[0].value.pval->vbuf /= inarch.rp->vset[i]->numval;
		break;
	    case PM_TYPE_DOUBLE:
		*(double *)inarch.rp->vset[i]->vlist[0].value.pval->vbuf /= inarch.rp->vset[i]->numval;
		break;
	}
    }
    return pick;
}

/*
 * rescale values for the ith vset[]
 */
static void
rescale(int i, metricspec_t *mp)<commit_msg>pmlogrewrite - fix alignment problems<commit_after>/*
 * pmResult rewrite methods for pmlogrewrite
 *
 * Copyright (c) 2011 <NAME>.  All Rights Reserved.
 * 
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 *
 * pmResult rewriting is complicated because ...
 *
 * - deleting a metric involves moving all of the following rp->vset[]
 *   entries "up" one position and decrementing rp->numpmid
 * - deleting an instance involves moving all of the following
 *   rp->vset[i]->vlist[] enties "up" one position and then decrementing
 *   rp->vset[i]->numval
 * - rescaling values involves calling __pmStuffValue which modifies
 *   rp->vset[i]->vlist[j].value, and in the case of all types other than
 *   U32 or 32 this will involve an allocation for a new pmValueBlock
 *   ... we need to keep track of the previous pmValueBlock (if any) to
 *   avoid memory leaks
 * - changing type has the same implications as rescaling
 * - a single metric within a pmResult may have both rescaling and type
 *   change
 * - the initial pmResult contains pointers into a PDU buffer so the fast
 *   track case in pmFreeresult() may not release any of the pmValueSet
 *   or pmValue or pmValueBlock allocations if pmFreeResult is given a
 *   rewritten pmResult, so we modify the pmResult in place but use save[]
 *   to remember the original pmValueSet when retyping or rescaling, use
 *   orig_numval[] to remember how many pmValue instances we had had for
 *   each pmValueSet, and use orig_numpmid to remember the original numpmid
 *   value
 */

#include "pmapi.h"
#include "impl.h"
#include "logger.h"
#include <assert.h>

/* for __pmPool* alloc */
#define MAGIC PM_VAL_HDR_SIZE + sizeof(__int64_t)

/*
 * Keep track of pmValueSets that have been moved aside to allow for
 * new values from __pmStuffValue() during rewriting.
 */
static pmValueSet	**save = NULL;
static int		len_save = 0;

/*
 * Save rp->vset[idx] in save[idx], and build a new rp->vset[idx]
 * for the number of values expected for this metric
 */
static int
save_vset(pmResult *rp, int idx)
{
    pmValueSet	*vsp;
    int		need;
    int		j;

    if (save[idx] != NULL)
	/* already done */
	return 1;

    vsp = save[idx] = rp->vset[idx];

    if (vsp->numval > 0)
	need = sizeof(pmValueSet) + (vsp->numval-1)*sizeof(pmValue);
    else
	need = sizeof(pmValueSet);
    rp->vset[idx] = (pmValueSet *)malloc(need);
    if (rp->vset[idx] == NULL) {
	fprintf(stderr, "save_vset: malloc(%d) failed: %s\n", need, strerror(errno));
	exit(1);
    }
    rp->vset[idx]->pmid = vsp->pmid;
    rp->vset[idx]->numval = vsp->numval;
    rp->vset[idx]->valfmt = vsp->valfmt;
    for (j = 0; j < vsp->numval; j++)
	rp->vset[idx]->vlist[j].inst = vsp->vlist[j].inst;
#ifdef PCP_DEBUG
    if (pmDebug & DBG_TRACE_APPL2) {
	fprintf(stderr, "save_vset: vset[%d] -> " PRINTF_P_PFX "%p (was " PRINTF_P_PFX "%p) pmid=%s numval=%d\n",
		idx, rp->vset[idx], save[idx], pmIDStr(rp->vset[idx]->pmid), rp->vset[idx]->numval);
    }
#endif
    return 0;
}

/*
 * free the pval for the jth instance of the ith metric
 */
static void
free_pval(pmResult *rp, int i, int j)
{
    if (rp->vset[i]->vlist[j].value.pval->vlen == MAGIC) {
#ifdef PCP_DEBUG
	if (pmDebug & DBG_TRACE_APPL2) {
	    fprintf(stderr, "free_pval: __pmPoolFree(" PRINTF_P_PFX "%p) pmid=%s inst=%d\n",
		rp->vset[i]->vlist[j].value.pval, pmIDStr(rp->vset[i]->pmid), rp->vset[i]->vlist[j].inst);
	}
#endif
	__pmPoolFree(rp->vset[i]->vlist[j].value.pval, MAGIC);
    }
    else {
#ifdef PCP_DEBUG
	if (pmDebug & DBG_TRACE_APPL2) {
	    fprintf(stderr, "free_pval: free(" PRINTF_P_PFX "%p) pmid=%s inst=%d\n",
		rp->vset[i]->vlist[j].value.pval, pmIDStr(rp->vset[i]->pmid), rp->vset[i]->vlist[j].inst);
	}
#endif
	free(rp->vset[i]->vlist[j].value.pval);
    }
}

/*
 * if a pmValueSet was saved via save_vset(), then free the newly build 
 * pmValueSet and put the old one back in place
 */
static void
clean_vset(pmResult *rp)
{
    int		i;
    int		j;

    for (i = 0; i < rp->numpmid; i++) {
	if (save[i] != NULL) {
	    if (rp->vset[i]->valfmt == PM_VAL_DPTR) {
		/* values hanging off the pval */
		for (j = 0; j < rp->vset[i]->numval; j++)
		    free_pval(rp, i, j);
	    }
	    /*
	     * we did the vset[i] allocation in save_vset(), so malloc()
	     * and no __pmPoolAlloc() cases
	     */
#ifdef PCP_DEBUG
	    if (pmDebug & DBG_TRACE_APPL2) {
		fprintf(stderr, "clean_vset: free(" PRINTF_P_PFX "%p) pmValueSet pmid=%s\n",
			rp->vset[i], pmIDStr(rp->vset[i]->pmid));
	    }
#endif
	    free(rp->vset[i]);
	    rp->vset[i] = save[i];
	    save[i] = NULL;
	}
    }
}

/*
 * pick/calculate one value from multiple values for the ith vset[] ...
 *
 * Note: pval->vbuf may not have correct alignment for all data types,
 *       so memcpy() rather than assign.
 */
static int
pick_val(int i, metricspec_t *mp)
{
    int		j;
    int		pick = -1;
    pmAtomValue	jval;
    pmAtomValue	pickval;

    assert(inarch.rp->vset[i]->numval > 0);

    for (j = 0; j < inarch.rp->vset[i]->numval; j++) {
	if (mp->output == OUTPUT_ONE) {
	    if (inarch.rp->vset[i]->vlist[j].inst == mp->one_inst) {
		pick = j;
		break;
	    }
	    continue;
	}
	if (j == 0) {
	    pick = 0;
	    switch (mp->old_desc.type) {
		case PM_TYPE_64:
		    memcpy(&pickval.ll, &inarch.rp->vset[i]->vlist[0].value.pval->vbuf, sizeof(__int64_t));
		    break;
		case PM_TYPE_U64:
		    memcpy(&pickval.ull, &inarch.rp->vset[i]->vlist[0].value.pval->vbuf, sizeof(__uint64_t));
		    break;
		case PM_TYPE_FLOAT:
		    memcpy(&pickval.f, &inarch.rp->vset[i]->vlist[0].value.pval->vbuf, sizeof(float));
		    break;
		case PM_TYPE_DOUBLE:
		    memcpy(&pickval.d, &inarch.rp->vset[i]->vlist[0].value.pval->vbuf, sizeof(double));
		    break;
	    }
	    if (mp->output == OUTPUT_MIN || mp->output == OUTPUT_MAX ||
	        mp->output == OUTPUT_SUM || mp->output == OUTPUT_AVG)
		continue;
	}
	switch (mp->old_desc.type) {
	    case PM_TYPE_32:
		switch (mp->output) {
		    case OUTPUT_MIN:
			if (inarch.rp->vset[i]->vlist[j].value.lval < inarch.rp->vset[i]->vlist[pick].value.lval)
			    pick = j;
			break;
		    case OUTPUT_MAX:
			if (inarch.rp->vset[i]->vlist[j].value.lval > inarch.rp->vset[i]->vlist[pick].value.lval)
			    pick = j;
			break;
		    case OUTPUT_SUM:
		    case OUTPUT_AVG:
			inarch.rp->vset[i]->vlist[0].value.lval += inarch.rp->vset[i]->vlist[j].value.lval;
			break;
		}
		break;
	    case PM_TYPE_U32:
		switch (mp->output) {
		    case OUTPUT_MIN:
			if ((__uint32_t)inarch.rp->vset[i]->vlist[j].value.lval < (__uint32_t)inarch.rp->vset[i]->vlist[pick].value.lval)
			    pick = j;
			break;
		    case OUTPUT_MAX:
			if ((__uint32_t)inarch.rp->vset[i]->vlist[j].value.lval > (__uint32_t)inarch.rp->vset[i]->vlist[pick].value.lval)
			    pick = j;
			break;
		    case OUTPUT_SUM:
		    case OUTPUT_AVG:
			*(__uint32_t *)&inarch.rp->vset[i]->vlist[0].value.lval += (__uint32_t)inarch.rp->vset[i]->vlist[j].value.lval;
			break;
		}
		break;
	    case PM_TYPE_64:
		memcpy(&jval.ll, &inarch.rp->vset[i]->vlist[j].value.pval->vbuf, sizeof(__int64_t));
		switch (mp->output) {
		    case OUTPUT_MIN:
			if (jval.ll < pickval.ll) {
			    pickval.ll = jval.ll;
			    pick = j;
			}
			break;
		    case OUTPUT_MAX:
			if (jval.ll > pickval.ll) {
			    pickval.ll = jval.ll;
			    pick = j;
			}
			break;
		    case OUTPUT_SUM:
		    case OUTPUT_AVG:
			pickval.ll += jval.ll;
			break;
		}
		break;
	    case PM_TYPE_U64:
		memcpy(&jval.ull, &inarch.rp->vset[i]->vlist[j].value.pval->vbuf, sizeof(__int64_t));
		switch (mp->output) {
		    case OUTPUT_MIN:
			if (jval.ull < pickval.ull) {
			    pickval.ull = jval.ull;
			    pick = j;
			}
			break;
		    case OUTPUT_MAX:
			if (jval.ull > pickval.ull) {
			    pickval.ull = jval.ull;
			    pick = j;
			}
			break;
		    case OUTPUT_SUM:
		    case OUTPUT_AVG:
			pickval.ull += jval.ull;
			break;
		}
		break;
	    case PM_TYPE_FLOAT:
		memcpy(&jval.f, &inarch.rp->vset[i]->vlist[j].value.pval->vbuf, sizeof(float));
		switch (mp->output) {
		    case OUTPUT_MIN:
			if (jval.f < pickval.f) {
			    pickval.f = jval.f;
			    pick = j;
			}
			break;
		    case OUTPUT_MAX:
			if (jval.f > pickval.f) {
			    pickval.f = jval.f;
			    pick = j;
			}
			break;
		    case OUTPUT_SUM:
		    case OUTPUT_AVG:
			pickval.f += jval.f;
			break;
		}
		break;
	    case PM_TYPE_DOUBLE:
		memcpy(&jval.d, &inarch.rp->vset[i]->vlist[j].value.pval->vbuf, sizeof(double));
		switch (mp->output) {
		    case OUTPUT_MIN:
			if (jval.d < pickval.d) {
			    pickval.d = jval.d;
			    pick = j;
			}
			break;
		    case OUTPUT_MAX:
			if (jval.d > pickval.d) {
			    pickval.d = jval.d;
			    pick = j;
			}
			break;
		    case OUTPUT_SUM:
		    case OUTPUT_AVG:
			pickval.d += jval.d;
			break;
		}
		break;
	}
    }

    if (mp->output == OUTPUT_AVG) {
	switch (mp->old_desc.type) {
	    case PM_TYPE_32:
		inarch.rp->vset[i]->vlist[0].value.lval = (int)(0.5 + inarch.rp->vset[i]->vlist[0].value.lval / (double)inarch.rp->vset[i]->numval);
		break;
	    case PM_TYPE_U32:
		*(__uint32_t *)&inarch.rp->vset[i]->vlist[0].value.lval = (__uint32_t)(0.5 + *(__uint32_t *)&inarch.rp->vset[i]->vlist[0].value.lval / (double)inarch.rp->vset[i]->numval);
		break;
	    case PM_TYPE_64:
		pickval.ll = 0.5 + pickval.ll / (double)inarch.rp->vset[i]->numval;
		break;
	    case PM_TYPE_U64:
		pickval.ull = 0.5 + pickval.ull / (double)inarch.rp->vset[i]->numval;
		break;
	    case PM_TYPE_FLOAT:
		pickval.f = pickval.f / (float)inarch.rp->vset[i]->numval;
		break;
	    case PM_TYPE_DOUBLE:
		pickval.d = pickval.d / (double)inarch.rp->vset[i]->numval;
		break;
	}
    }
    if (mp->output == OUTPUT_AVG || mp->output == OUTPUT_SUM) {
	switch (mp->old_desc.type) {
	    case PM_TYPE_64:
		memcpy(&inarch.rp->vset[i]->vlist[0].value.pval->vbuf, &pickval.ll, sizeof(__int64_t));
		break;
	    case PM_TYPE_U64:
		memcpy(&inarch.rp->vset[i]->vlist[0].value.pval->vbuf, &pickval.ull, sizeof(__uint64_t));
		break;
	    case PM_TYPE_FLOAT:
		memcpy(&inarch.rp->vset[i]->vlist[0].value.pval->vbuf, &pickval.f, sizeof(float));
		break;
	    case PM_TYPE_DOUBLE:
		memcpy(&inarch.rp->vset[i]->vlist[0].value.pval->vbuf, &pickval.d, sizeof(double));
		break;
	}
    }

    return pick;
}

/*
 * rescale values for the ith vset[]
 */
static void
rescale(int i, metricspec_t *mp)
{'fraction_non_alphanumeric': 0.16798062310030396, 'fraction_numerical': 0.010828267477203647, 'mean_word_length': 3.1280141148794356, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 410, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4791731', 'n_tokens_mistral': 9104, 'n_tokens_neox': 8400, 'n_words': 1829}