
/****************************************************************************/
/*                                                                          */
/*      NNstat -- Internet Statistics Collection Package                    */
/*                                                                          */
/*            Written by: Bob Braden & Annette DeSchon                      */
/*            USC Information Sciences Institute                            */
/*            Marina del Rey, California                                    */
/*                                                                          */
/*      Copyright (c) 1991 University of Southern California.               */
/*      All rights reserved.                                                */
/*                                                                          */
/*      Redistribution and use in source and binary forms are permitted     */
/*      provided that the above copyright notice and this paragraph are     */
/*      duplicated in all such forms and that any documentation,            */
/*      advertising materials, and other materials related to such          */
/*      distribution and use acknowledge that the software was              */
/*      developed by the University of Southern California, Information     */
/*      Sciences Institute.  The name of the University may not be used     */
/*      to endorse or promote products derived from this software           */
/*      without specific prior written permission.                          */
/*      THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR        */
/*      IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED      */
/*      WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR          */
/*      PURPOSE.                                                            */
/*                                                                          */
/****************************************************************************/

static char rcsid[]=
  "$Header: /tmp_mnt/r/jove_staff3/mogul/code/NNstat/3.3beta/RCS/sobjhist.c,v 1.6 1993/09/22 22:46:20 mogul Exp $";

 /*
 *  CHANGES:
 *   Rel 3.0 
 *  RTB: Add List routines.
 *  RTB: Terse mode produces simplified histogram list
 *  Cisco: Plug memory leak.
 *  Aug93/DECWRL: Alpha/OSF port.  XDR is a pointer type!
 *   
 */
 
/*
 *   Internet Statistics Facility -- Generic Operation Routines
 *
 *    This module defines a set of operations on a particular class
 *    of Statistical Objects.  In the spirit of object-oriented
 *    programming and information-hiding, these routines are
 *    the only ones which know about the internal structre of the
 *    Statistical Object (SOBJ) data structures.
 *
 */
 
/*
 *
 *  HI Object Class ==  GENERAL HISTOGRAM   
 *
 *    Objects of the HI class build linear frequency distributions.
 *    Specifically, a given unsigned value X is counted in
 *
 *              bin# = floor(X/S) if X <= S*M, 
 *              bin = "default" otherwise.
 *
 *    Here S is a given scale factor, and M is the maximum bin; any values
 *    beyond 1024 are counted in the "default" bin.  If M is unspecified,
 *    M=1024 is assumed. X cannot exceed 4 bytes!
 *
 *
 *    Operations on HI class objects:
 *
 *       SOBJ *Make_HI( objname, &parms, nparms, datalen )
 *
 *                parms = (S, [M])
 *
 *       Write_HI( (SOBJ *) SOBJ-ptr, &value , length)
 *
 *       Read_HI(fd, (SOBJ *) SOBJ-ptr )
 *
 *       Delete_HI( (SOBJ *) SOBJ-ptr )
 *
 *       Clear_HI( (SOBJ *) SOBJ-ptr )
 *
 *       List_HI( fd, OBJp )
 * 
 *
 *  P2 Object Class ==  POWER-OF-TWO FREQUENCY DISTRIBUTION  
 *
 *    Objects of the P2 class build logarithmic frequency distributions.
 *    Specifically, a given value X is counted in bin log2(X/F), where
 *    F is a given scale factor.  X cannot exceed 4 bytes!
 *
 *
 *    Operations on P2 class objects:
 *
 *       SOBJ *Make_P2( objname, &S, 1, datalen )
 *
 *           S = scale factor.  Bins are:
 *                (0):  value < S
 *                (1):   S <= value <= 2*S-1
 *                (j):   (2**j-1)*S <= value <= (2**j)*S -1
 *                   ...
 *
 *       Write_P2( (SOBJ *) SOBJ-ptr, &value, length)
 *
 *       Read_P2(fd, (SOBJ *) SOBJ-ptr )
 *
 *       Delete_P2( (SOBJ *) SOBJ-ptr ) 
 *
 *       Clear_P2( (SOBJ *) SOBJ-ptr ) 
 *
 *       List_P2( fd, OBJp ) 
 *
 */
 
#define MAXHBINS    1024 

#include <stdio.h>
#include <sys/types.h>
#include "stat.h"
#include "sobj.h"
    
SOBJ *Make_HI(), *Make_P2(), *make_hist() ;
boolean  Write_HI(), Read_HI(), Write_P2(), Read_P2() ;
void Clear_HI(), Delete_HI(), List_HI(), List_P2() ;

        /* Transfer Vector 
         * for external access to these routines
         */
GENERICOP HIop = { Make_HI, Write_HI, Read_HI, Clear_HI, Delete_HI, List_HI } ;
GENERICOP P2op = { Make_P2, Write_P2, Read_P2, Clear_HI, Delete_HI, List_P2 } ;
    
    /*
     *  Define HI/P2 object data structures
     *
     */
#define HistA struct stat_freq_area
#define esize sizeof(HistE)
 
HistA {     /* Histogram Object area */
    SOBJ   hia_sobj ;         /* SOBJ = standard root of area */
    
    short  hia_bsize ;        /* Size of bin area (bytes) */
    short  hia_nbins ;        /* Size of bin area (#elements) */    
    
    long   hia_sum1 ;         /* sum / 2**16 */ 
    long   hia_sum2 ;         /* sum mod 2**16  */  
    HistDATA hia_data;        /* scale factor, avg, min, max */
    HistE   *hia_binp;          /* pointer to bin vector */
} ;

#define   hia_totalno  hia_sobj.sob_totalno
#define   hia_scalef   hia_data.Hist_scalef    /* Scalefactor */    
#define   hia_avg      hia_data.Hist_avg       /* Current average value */
#define   hia_minval   hia_data.Hist_min       /* Smallest observed value */
#define   hia_maxval   hia_data.Hist_max       /* Largest observed value */
#define   hia_default  hia_data.Hist_default   /* Default count */

#define OUTSIZE 256

struct Hist_parms {
    u_int32  hip_scalef;
    u_int32  hip_maxbin;
} ;


SOBJ *Make_HI(objname, parmp, nparms, datalen)
    char *objname;
    struct Hist_parms *parmp ;
    int   datalen, nparms;
    {
    int nbins = MAXHBINS;
        
    if (nparms < 1) {
        SOBJ_error = "HI: parm missing";
        return(NULL);
    }       
    if (nparms > 1) {
        if (ntohl(parmp->hip_maxbin) > MAXHBINS-1) {
            SOBJ_error = "HI: too many bins";
            return(NULL);
        }
        nbins = ntohl(parmp->hip_maxbin)+1;
    }
    if (datalen  > 4) {
        SOBJ_error = "HI: cannot handle > 4bytes";
        return(NULL);
    }                
    return((SOBJ *) make_hist(ntohl(parmp->hip_scalef), nbins)) ;      
}    


SOBJ *Make_P2(objname, parmp, nparms, datalen)
    char *objname;
    struct Hist_parms *parmp ;
    int datalen, nparms;
    {       
    if (nparms < 1) {
        SOBJ_error = "P2: parm missing";
        return(NULL);
    }   
    if (datalen  > 4) {
        SOBJ_error = "HI: cannot handle > 4bytes";
        return(NULL);
    }   
    return((SOBJ *) make_hist(ntohl(parmp->hip_scalef), 8*datalen)) ;      
}    

    /* 
     *   Common object Make routine...
     */
SOBJ *make_hist(scalef, nbins)
    int   scalef, nbins;
    {
    register HistA *hiap ;
    
    if ((hiap = (HistA *) malloc(sizeof (HistA))) == NULL) {
        SOBJ_error = "HI/P2: Mem full" ;
        return(NULL) ;
    }       
    
    hiap->hia_nbins = nbins;
    hiap->hia_scalef = (scalef)?scalef:1 ;
    hiap->hia_bsize =  (esize)*hiap->hia_nbins;

    if ((hiap->hia_binp = (HistE *) malloc(hiap->hia_bsize))== NULL) {
        SOBJ_error = "HI/P2: Mem Full" ;
        free(hiap);
        return(NULL) ;
    }
    Clear_HI(hiap);
    return(&hiap->hia_sobj) ;  /* SUCCESS */      
}    
     
     
boolean Write_HI( hiap, Valuep, L)
    register HistA *hiap ;
    char *Valuep ;
    int L;
    {
    register u_int32 Value = LFETCH(Valuep, L) ;
    
    if (Value < hiap->hia_minval) hiap->hia_minval = Value ;
    if (Value > hiap->hia_maxval) hiap->hia_maxval = Value ;
    
    hiap->hia_sum2 += Value ;
    hiap->hia_sum1 += (hiap->hia_sum2 >> 16) ;
    hiap->hia_sum2 &= 0xffff ;
                              
    if ((Value /= hiap->hia_scalef) >= hiap->hia_nbins)
        hiap->hia_default++;
    else        
        hiap->hia_binp[Value]++ ;
    return(0) ;
}
    
     
boolean Write_P2( hiap, Valuep, L)
    register HistA *hiap ;
    char *Valuep ;
    int L;
    {
    register u_int32 Value = LFETCH(Valuep, L) ;
    register int i = 0 ;
                              
    if (Value < hiap->hia_minval) hiap->hia_minval = Value ;
    if (Value > hiap->hia_maxval) hiap->hia_maxval = Value ;
    
    hiap->hia_sum2 += Value ;
    hiap->hia_sum1 += (hiap->hia_sum2 >> 16) ;
    hiap->hia_sum2 &= 0xffff ;
    
    Value /= hiap->hia_scalef ;
    
    while (Value) {i += 1 ; Value >>= 1 ;}  
        /* i is number significant bits in Value */     
    hiap->hia_binp[i]++ ;   
    return(0) ;
}
            
void Delete_HI( hiap )
    HistA *hiap ;
    {
    if (hiap->hia_binp) free(hiap->hia_binp);
    free(hiap) ;
}


void Clear_HI( hiap )
    HistA *hiap ;
    {
    bzero( (char *) hiap->hia_binp, hiap->hia_bsize );  
    hiap->hia_minval = INFINITY;
    hiap->hia_maxval = hiap->hia_default = 0;
    hiap->hia_sum1 = hiap->hia_sum2 = 0;
}


boolean Read_HI(fd, hiap)
    XDR *fd;
    register HistA  *hiap ;
    {
    register HistE *tbp = &hiap->hia_binp[hiap->hia_nbins] ;
    register int left = hiap->hia_nbins;
    int i;
    HistE *hep = hiap->hia_binp;
    u_long Avg();
            
    while (left > 0) 
        if (*--tbp) break; else left--;
       /* Scan backwards from end for first non-zero count */      
    if (left<(hiap->hia_nbins-1)) left++ ;  /* Include one zero bin */
     
    hiap->hia_avg = Avg(hiap->hia_sum1, hiap->hia_sum2, hiap->hia_totalno); 
    
    i = left;
    if (!PutReadResp(fd, HIr_SIZE(left), hiap) ||
        !ListHI(fd, &hep, &i, &hiap->hia_data, ISTTY(fd))
        )
        return(FALSE); 
    return(TRUE); 
}


boolean Read_P2(fd, hiap)
    XDR *fd;
    register HistA  *hiap ;
    {
    register HistE *tbp = &hiap->hia_binp[hiap->hia_nbins] ;
    register int left = hiap->hia_nbins;
    int i;
    HistE *hep = hiap->hia_binp;
    u_long Avg();
            
    while (left > 0) 
        if (*--tbp) break; else left--;
       /* Scan backwards from end for first non-zero count */      
    if (left<(hiap->hia_nbins-1)) left++ ;  /* Include one zero bin */
     
    hiap->hia_avg = Avg(hiap->hia_sum1, hiap->hia_sum2, hiap->hia_totalno); 
    
    i = left;
    if (!PutReadResp(fd, P2r_SIZE(left), hiap) ||
        !ListP2(fd, &hep, &i, &hiap->hia_data, ISTTY(fd))
        )
        return(FALSE);
    return(TRUE);  
} /* Read_P2() */


u_long Avg(sum1, sum2, totalno)
    u_long sum1, sum2, totalno;
    {
    float SUM;
        
    if (totalno) {
        SUM = ((float) sum1)*65536 + sum2;
        return(SUM/totalno);
    } 
    else
        return(0);
} /* Avg() */
    

void
List_HI(fd, OBJp)
XDR *fd;
OBJ *OBJp;
{
   P2DATA p2data;
   HistE  *binpp = NULL;
   int    count = MAX_HIBINS;

   if (!ListHI(fd, &binpp, &count, &p2data, 1))
        printf(" BAD ListHI! "); 
        
} /* List_HI() */
 

    /*
     *  ListHI() --  I/O routine for 'hist' class read data.
     */
boolean ListHI(fd, binpp, maxnop, Histp, islog)
    register XDR *fd;
    HistE  **binpp;
    int     *maxnop;
    HistDATA  *Histp;
    int      islog;
{
    register u_int32 s, delta;
    int k = *maxnop;
    char outp[OUTSIZE];
    int incr = (*binpp)? sizeof(HistE): 0;
    HistE count, *hep = (*binpp)? *binpp: &count;
    
    if (!readhist(fd, Histp, islog)) return(FALSE);
    
    if (fd) {
       if (!xdr_int(fd, &k))  /* bin count */
          return(FALSE);
       }
    
    if (*binpp&&k>*maxnop) return(FALSE);
        /* decode: caller gave us a buffer, but it was too small. */
    *maxnop = k;
    
    delta = Histp->Hist_scalef;
    s = (tersemode)? delta/2 : 0;
    
    while (k-- > 0) {
        if (fd) 
           if (!xdr_u_int(fd, hep))  return(FALSE);
        if (islog) {
            if (tersemode)
                sprintf(outp, "%d  %d\n", s, *hep); 
            else
                sprintf(outp, "[%d-%d]= %d\n", s, s+delta-1, *hep);
            s += delta;
            log(outp, logfp);
        };
        hep = (HistE *) ((char *) hep + incr);  
    }
    if (islog && Histp->Hist_default) {
        sprintf(outp, "[Off-scale]= %d\n", Histp->Hist_default);
        log(outp, logfp);
    }
 
    return(TRUE);
} /* ListHI() */

                    
void
List_P2(fd, OBJp)
XDR *fd;
OBJ *OBJp;
{
   P2DATA p2data;
   HistE   *p2bp = NULL;
   int    count = MAX_P2BINS;
   
   if (!ListP2(fd, &p2bp, &count, &p2data, 1))
      printf(" BAD ListP2! ");
      
} /* List_P2 */

    /*
     *  ListP2() --  I/O routine for hist_pwr2 read data.
     *
     */
boolean ListP2(fd, binpp, maxnop, p2dp,  islog)
    register XDR *fd;
    HistE  **binpp;
    int     *maxnop;
    P2DATA  *p2dp;
    int      islog;
{
    register u_int32 s;
    int k = *maxnop;
    char outp[OUTSIZE];
    int incr = (*binpp)? sizeof(u_int32): 0;
    HistE count, *hep = (*binpp)? *binpp: &count;
        
    if (!readhist(fd, p2dp, islog)) return(FALSE);
    
    if (fd) {
       if (!xdr_int(fd, &k) ||
           !xdr_u_int(fd, hep)
           )
          return(FALSE);
       }
    if (islog) {    
       s = p2dp->Hist_scalef;
       sprintf(outp, "  [0-%d]= %d\n",  s-1, *hep);
       log(outp, logfp);
    }
    
    if (*binpp&&k>*maxnop) return(FALSE);
        /* decode: caller gave us a buffer, but it was too small. */
    *maxnop = k;
    
    while (--k > 0) {
        hep = (u_int32 *) ((char *) hep + incr); 
        if (fd) 
           if (!xdr_u_int(fd, hep))  return(FALSE);
        if (islog) {
            if (k)
               sprintf(outp, "  [%d-%d]= %d\n", s, s+s-1, *hep);
            else
               sprintf(outp, "  [%d-inf'ty]= %d\n", s, *hep) ;
            s <<= 1;
            log(outp, logfp);
        };
    }
 
    return(TRUE);
} /* ListP2 */


    /* readhist() -- Common histogram routine used by ListHI(), ListP2().
     *
     */
boolean readhist(fd, hdp, islog)
    register XDR *fd;
    HistDATA *hdp;
    int      islog;
{
    char outp[OUTSIZE];
        
    if (fd) {
       if (!xdr_u_int(fd, &hdp->Hist_scalef) ||
           !xdr_u_int(fd, &hdp->Hist_avg) ||
           !xdr_u_int(fd, &hdp->Hist_min) ||
           !xdr_u_int(fd, &hdp->Hist_max) ||
           !xdr_u_int(fd, &hdp->Hist_default) 
           )
        return(FALSE);
    }
    if (islog) 
        if (hdp->Hist_min != INFINITY) {       
            sprintf(outp,  "   Avg= %d  Min= %d  Max= %d\n", 
               hdp->Hist_avg, hdp->Hist_min, hdp->Hist_max);
            log(outp, logfp);
        }
    return(TRUE);
} /* readhist */   
