/*
 *   perfstat() interface
 *     e.g. AIX
 */
#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-features.h>
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>
#include <net-snmp/agent/hardware/cpu.h>

#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>

#include <sys/protosw.h>
#include <libperfstat.h>

netsnmp_feature_require(hardware_cpu_copy_stats)
void _cpu_copy_stats( netsnmp_cpu_info *cpu );

    /*
     * Initialise the list of CPUs on the system
     *   (including descriptions)
     */
void init_cpu_perfstat( void ) {
    int                   i;
    perfstat_id_t         name;
    perfstat_cpu_t       *cs2;
    netsnmp_cpu_info     *cpu = netsnmp_cpu_get_byIdx( -1, 1 );
    strcpy(cpu->name, "Overall CPU statistics");

    cpu_num = perfstat_cpu( NULL, NULL, sizeof(perfstat_cpu_t), 0 );
    cs2 = (perfstat_cpu_t*)malloc( cpu_num*sizeof(perfstat_cpu_t));
 
    strcpy( name.name, "");
    if (perfstat_cpu(&name, cs2, sizeof(perfstat_cpu_t), cpu_num) > 0) {
        for ( i = 0; i < cpu_num; i++ ) {
            cpu = netsnmp_cpu_get_byIdx( i, 1 );
            sprintf( cpu->name, cs2[i].name);
        }
    }
    free(cs2);
}


    /*
     * Load the latest CPU usage statistics
     */
int netsnmp_cpu_arch_load( netsnmp_cache *cache, void *magic ) {
    int                     i,n;
    perfstat_id_t           name;
    perfstat_cpu_total_t    cs;
    perfstat_cpu_t         *cs2;
    perfstat_memory_total_t ms;
    netsnmp_cpu_info       *cpu = netsnmp_cpu_get_byIdx( -1, 0 );

    if (perfstat_cpu_total((perfstat_id_t *)NULL, &cs,
                     sizeof(perfstat_cpu_total_t), 1) > 0) {

        /* Returns 'u_longlong_t' statistics */
        cpu->user_ticks = (unsigned long long)cs.user / cs.ncpus;
        cpu->sys_ticks  = ((unsigned long long)cs.sys + (unsigned long long)cs.wait) / cs.ncpus;
        cpu->kern_ticks = (unsigned long long)cs.sys / cs.ncpus;
        cpu->wait_ticks = (unsigned long long)cs.wait / cs.ncpus;
        cpu->idle_ticks = (unsigned long long)cs.idle / cs.ncpus;
        /* intrpt_ticks, sirq_ticks, nice_ticks unused */
    
        /*
         * Interrupt/Context Switch statistics
         *   XXX - Do these really belong here ?
         */
        cpu->pageIn       = (unsigned long long)cs.sysread;
        cpu->pageOut      = (unsigned long long)cs.syswrite;
        cpu->nInterrupts  = (unsigned long long)cs.devintrs + cs.softintrs;
        cpu->nCtxSwitches = (unsigned long long)cs.pswitch;
    }

    if (perfstat_memory_total((perfstat_id_t *)NULL, &ms,
                     sizeof(perfstat_memory_total_t), 1) > 0) {
        cpu->swapIn  = (unsigned long long)ms.pgspins;
        cpu->swapOut = (unsigned long long)ms.pgspouts;
    }


    /*
     * Per-CPU statistics
     */
    n   = cs.ncpus;   /* XXX - Compare against cpu_num */
    cs2 = (perfstat_cpu_t*)malloc( n*sizeof(perfstat_cpu_t));
    strcpy( name.name, "");
    if (perfstat_cpu(&name, cs2, sizeof(perfstat_cpu_t), n) > 0) {
        for ( i = 0; i < n; i++ ) {
            cpu = netsnmp_cpu_get_byIdx( i, 1 );
            cpu->user_ticks = (unsigned long long)cs2[i].user;
            cpu->sys_ticks  = (unsigned long long)cs2[i].sys + (unsigned long long)cs2[i].wait;
            cpu->kern_ticks = (unsigned long long)cs2[i].sys;
            cpu->wait_ticks = (unsigned long long)cs2[i].wait;
            cpu->idle_ticks = (unsigned long long)cs2[i].idle;
            cpu->pageIn     = (unsigned long long)cs2[i].sysread;
            cpu->pageOut    = (unsigned long long)cs2[i].syswrite;
            cpu->nCtxSwitches = (unsigned long long)cs2[i].pswitch;
            /* Interrupt stats only apply overall, not per-CPU */
        }
    } else {
        _cpu_copy_stats( cpu );
    }
    free(cs2);

    return 0;
}
