static char dqs_load_avg_rcsid[]="$Id: dqs_load_avg.c,v 1.1.1.1 1998/08/18 14:39:12 green Exp $";

/*----------------------------------------------------
 * dqs_load_avg.c Tom Green Mon Jan 31 10:42:48 1994
 *
 * Copyright 1993
 *
 * SUPER COMPUTER COMPUTATIONS RESEARCH INSTITUTE
 *            FLORIDA STATE UNIVERSITY
 *
 *
 * SCRI representatives make no claims about the
 * suitability of this software for any purpose.
 * It is provided "as is" without express or
 * implied warranty.
 *
 * $Log: dqs_load_avg.c,v $
 * Revision 1.1.1.1  1998/08/18 14:39:12  green
 * DQS 3.2.0.5 WIP Import
 *
 * Revision 1.1.1.1  1997/04/10 15:10:33  green
 * DQS 3.1.3.4.1 Distribution
 *
 * Revision 3.12  1996/11/20 23:03:56  nrl
 * Several fixes submitted by or as a result of investigations by
 * Ron Lee, Bodo Bechenback, Guntram Wolski and Frank Dwyyer.
 *
 * Revision 3.11  1996/03/22  04:20:39  nrl
 * Added error cataloguing number to all routines
 *
 * Revision 3.10  1995/03/22  12:10:21  nrl
 * Somehowl nelem=3 dropped out!
 *
 * Revision 3.9  1995/03/05  03:47:18  nrl
 * Included Axel Brandes job scheduling mechanism to keep one
 * user from hawging the queue.
 *
 * Revision 3.8  1995/01/30  15:21:59  nrl
 * added "tid" verification between execd and qmaster to prevent
 * "ghost" jobs from persisting in visible queue. Changed ERROR messages
 * which were for information only to DEBUG messages.
 *
 * Revision 3.7  1995/01/27  14:09:42  nrl
 * Changed Supspend on completion to continue beyond an unsuspend operation
 * so that jobs can be "stepped" thru the queues. Increased timout
 * retries for connect to make the system more tolerant of network delyas.
 *
 * Revision 3.6  1994/08/02  22:39:51  green
 * dinked around with function prototypes so 'make prototype' would work
 *
 * Revision 3.5  1994/07/22  14:12:45  green
 * AIX load averaging - one more time
 *
 * patch utilizes code stolen from Jussi Maki (Email: jmaki@hut.fi)
 * integrated by Kingsley Kerce
 *
 * Revision 3.4  1994/07/18  18:34:47  green
 * AIX load avg patch
 *
 * Revision 3.3  1994/07/07  15:16:01  green
 * fixed - hopefully(kinda) AIX load averaging
 *
 * Revision 3.2  1994/06/15  15:29:21  green
 * support for using DQS trusted host list for dshd
 *
 * 	passing of Host_head -n dqs_c_dqs_execd.c
 * 	time stamp Host_head on deletion in dqs_c_qconf.c
 * 	ck trusted host list in dqs_dshd.c
 * 	grab Host_head at startup in dqs_execd.c
 * 	rebuild Host_head/Host_hash in dqs_execd_rebuild_host_hash.c
 * 	dqs_free_hash in dqs_hash.c
 * 	grab new Host_head in dqs_load_avg.c
 * 	error log/printing in dsh.c
 *
 * Bug in my syslog code(or certain vendors required nullifying use
 * of syslogd until I can track it down...
 *
 * Revision 3.1  1994/05/31  14:42:31  green
 * added Mehrdad Foroozesh patch for getting AIX load averages.
 *
 * Revision 3.0  1994/03/07  04:14:01  green
 * 3.0 freeze
 *
 * Revision 1.5  1994/02/25  23:13:21  green
 * added "PID_FILE" to def.h to log process id.
 *
 * modified dqs_execd.c and qmaster.c to log pids to a file
 *
 * added dqs_log_pid() to dqs_utility.c
 *
 * remade func.h
 *
 * forced insertion of "green" into Man_head  -- this needs to be removed
 * and a def in dqs.h if running as non-root.
 *
 * Revision 1.4  1994/02/25  02:54:36  green
 * modified dqs_add_del.c to correct job ordering problem
 *
 * modified dqs_list.c to support ASCENDING on DQS_INT2 DQS_INT3
 *
 * modified dqs_load_avg.c in an attempt to fix CDs on VAX Ultrix -
 * by commenting out the offending code - this needs to be fixed...
 *
 * Revision 1.3  1994/02/24  18:11:28  green
 * added dqs_show_all_cofigurations() to dqs_execd.c an qmaster.c
 *
 * modified dqs_execd.c and dqs_load_avg.c to use me.default_cell rather than
 * conf.default_cell
 *
 * previous message about errant pointer reference was incorrect.
 * dqs_sig_handlers.c put back like it was previously
 *
 * there was however a point problem with dusage->master in dqs_setup.c.
 *
 * added dqs_show_all_cofigurations() to dqs_utility.c
 *
 * remade func.h
 *
 * activated the "-cell cell_name" option for dqs_execd in globals.h
 *
 * changed fscanf() to fgets() in qsub.c to fix problems on SV machines
 * and to avoid byte-stuffing problems.
 *
 * Revision 1.2  1994/02/09  19:48:10  green
 * syncing source with docs
 *
 * Revision 1.1.1.1  1994/02/01  17:57:43  green
 * DQS 3.0 ALPHA
 *
 *--------------------------------------------------*/
/*#define MAINPROGRAM
 */
#include "h.h"
#include "def.h"
#include "dqs.h"
#include "struct.h"
#include "func.h"
#include "globals.h"
#include "dqs_errno.h"

/************************************************************************************/
int dqs_send_load()
     
{
  int              sfd;
  int              status;
  static int       nloads=0;
  dqs_list_type    *listel_ptr=NULL;
  dqs_list_type    *listel_ptr2=NULL;
  dqs_list_type    *response_list=NULL;
  
  DENTER((DQS_EVENT,"dqs_send_load"));
  
  listel_ptr=(dqs_list_type *)dqs_malloc(sizeof(dqs_list_type));
  listel_ptr->type=me.who;
  listel_ptr->int0=LOAD_AVG;
  listel_ptr->int1=dqs_get_loadavg();
  
  /* send out Host_head time stamp in to see if we need a new one */
  if (Host_head)
    listel_ptr->int3=Host_head->int0;
  
  if (!Rusage_head)
    listel_ptr->int2=TRUE; /* ??? */
  
  if (nloads>CLEAR_EXECD_TIDS)
    {
      if (!Rusage_head)
	{ /* tell the qmaster to delete all execd TIDs associated with host */
	  listel_ptr->int2=TRUE;
	  nloads=0;
	}
    }
  
  nloads++;
  
  listel_ptr->str0=dqs_string_insert(NULL,me.qualified_hostname);
  
  if ((sfd=dqs_send_list(me.default_cell,conf.qmaster_service,sfd,listel_ptr))<0)
    {
      (void) dqs_free_list(listel_ptr);
      DEXITE;
      return(-1);
    }
  if (dqs_get_list(sfd,&listel_ptr2))
    {
      ERROR((DQS_EVENT,"DQS_ERROR_0281 error getting ack from qmaster"));
      (void) dqs_free_list(listel_ptr);
      DEXITE;
      return(-1);
    }
  dqs_close_sfd(sfd);
  
  if (listel_ptr2)
    if (listel_ptr2->chain)
      {
	INFO((DQS_EVENT,"DQS_ERROR_0282 rebuilding trusted host list"));
	listel_ptr2->chain=dqs_execd_rebuild_host_hash(listel_ptr2->chain);
      }
  
  (void) dqs_free_list(listel_ptr);
  (void) dqs_free_list(listel_ptr2);
  
  DEXIT;
  return(status);
  
}

#ifdef _AIX
/*
 * (C) Copyright 1994, Jussi Maki (Email: jmaki@hut.fi). All rights reserved
 * This code is part of AIX monitor program. 
 * Permission to copy and use this source for noncommersial use.
 * For commersial use a permission must be asked from author.
 */

/*********************************************************************/
static int getkmemdata(buf,bufsize,address)
     char *buf;
     int bufsize;
     off_t address;
{
  int fd;
  int n;
  static kmem_unreadable=FALSE;
  
  DENTER((DQS_EVENT,"getkmemdata"));
  
  if (kmem_unreadable)
    {
      DEXITE;
      return(-1);
    }
  
  fd = open("/dev/kmem", O_RDONLY);
  if (fd < 0) {
    DPRINTF((DQS_EVENT,"error: can't open /dev/kmem"));
    kmem_unreadable=TRUE;
    DEXITE;
    return(-1);
  }
  
  /*
  ** Get the structure from the running kernel.
  */
  lseek(fd, address, SEEK_SET);
  n = read(fd, buf, bufsize);
  
  close(fd);
  
  DEXIT;
  return(n);
}

/*********************************************************************/
static int getloadavg_avenrun(loadv,nelem)
     double loadv[];
     int nelem;
     
{
  static int initted=0;
  int avenrun[3];
  static struct nlist kernelnames[] = {
    {"avenrun", 0, 0, 0, 0, 0},
    {NULL, 0, 0, 0, 0, 0}
  };
  static int no_avenrun_here = 0;
  int kmem_result;
  
  DENTER((DQS_EVENT,"getloadavg_avenrun"));
  
  if (no_avenrun_here)
    {
      DEXITE;
      return -1;
    }
  
  if (!initted) {
    initted = 1;
    if (knlist(kernelnames,1,sizeof(struct nlist)) == -1){
      no_avenrun_here = 1;
      DEXITE;
      return -1;
    }
  }
  
  kmem_result = getkmemdata((char *)&avenrun, sizeof(avenrun), kernelnames->n_value);
  if (kmem_result < 0)
    {
      no_avenrun_here = 1;
      DEXITE;
      return (-1);
    }
  
  if (nelem > 0) loadv[0]=avenrun[0]/65536.0;
  if (nelem > 1) loadv[1]=avenrun[1]/65536.0;
  if (nelem > 2) loadv[2]=avenrun[2]/65536.0;
  DEXIT;
  return(0);
}
#endif

/************************************************************************************/
int dqs_get_loadavg()
     
{
  double avg[3];
  u_long32 load_avg=0;
  int loads;
  
  DENTER((DQS_EVENT,"dqs_get_loadavg"));
  
  
  
#ifndef vax
#ifdef _AIX
  {
    int nelem;
    nelem=3;
    loads = getloadavg_avenrun(avg, nelem);
  }
#else
  /* we use GNU's load routines */
  loads = getloadavg (avg, 3);
#endif
  
  
  
  if (loads == -1)
    {
      load_avg=0;
    }
  else
    load_avg=avg[1]*100;
  
  DPRINTF((DQS_EVENT,"---> %f %f %f - %d",avg[0],avg[1],avg[2],load_avg));
#endif
  
  DEXIT;
  return(load_avg);
}

/*
  mmmmain(argc,argv)
  int argc;
  char **argv;
  
  {
  int i;
  
  DENTER_MAIN((DQS_EVENT,"main"));
  
  while (1)
  {
  i=dqs_get_loadavg();
  printf("%d\n",i);
  sleep(6);
  }
  }
*/
