
/*
 *	topmem.c
 *
 *	QNX 4
 *
 *	(C) Copyright 1991, 1992 by Robert Krten, all rights reserved.
 *
 *	This module is responsible for the TOP MEM (code, data, and memory)
 *	display.
 *
 *	1991 09 22	R. Krten		created
 *	1992 01 05	R. Krten		released for free
*/

#include "sysmon.h"

static	int		compareTOPMEM (TopmemT **, TopmemT **);
static	void	fetchSortTOPMEM (void);

#define	MaxHashEntries			16		/* hash is lowest four bits */

static struct _psinfo psData;
static struct _osinfo osData;

struct _seginfo segData [16];


static TopmemT **processList;
static	int processCount;
static	unsigned long totMemK;			/* total installed memory, kilobytes */

static	TopmemT	topmemBackbone [MaxHashEntries];

static	int	displayType = 'm';

void
doTOPMEM (pass)
int pass;
{
	memBackbone (pass);
	removeDeadEntries (pass);
	fetchSortTOPMEM();
	calcDeltaTOPMEM();
}

void initializeMemData(void)
{
	int		i;

	/*
	 *	clear out the top MEM backbone for the hash table
	*/

	processList = NULL;
	for (i = 0; i < MaxHashEntries; i++) {
		topmemBackbone [i].next = NULL;
	}
	processCount = 0;
	qnx_osinfo (0, &osData);
	totMemK = osData.totmemk;
	printf("Total mem: %d\n", totMemK);
}

void
memBackbone (pass)
int		pass;
{
	pid_t	currentPID;
	TopmemT	*ptr;
	TopmemT	*prev;
	int		sindex;
	int		segmentIndex;

	currentPID = 1;
	for (;;) {
		currentPID = qnx_psinfo (PROC_PID, currentPID, &psData, 0, segData);
		if (currentPID == -1) {
			if (errno == ESRCH || errno == EINVAL) {
				return;				/* done, go away */
			}
		}
		if ((psData.flags & (_PPF_MID | _PPF_VID)) == 0) {
			prev = &topmemBackbone [currentPID & 0x0f];
			for (ptr = prev -> next; ptr != NULL; ptr = (prev = ptr) -> next) {
				if (ptr -> pid == currentPID) {
					break;
				}
			}
			if (ptr == NULL) {
				if ((prev -> next = (TopmemT *) malloc (TopmemS)) == NULL) {
					fatal ("Couldn't allocate memory for new topmem hash entry");
				}
				ptr = prev -> next;		/* get to new entry */
				ptr -> pid = currentPID;
				ptr -> prio = psData.priority;
				fixName (ptr -> name, psData.un.proc.name);
				ptr -> next = NULL;
				processCount++;
			}
			ptr -> pass = pass;
			ptr -> dataK = ptr -> codeK = 0;
			for (segmentIndex = 0; qnx_psinfo (PROC_PID, currentPID, &psData, segmentIndex, &segData) == currentPID; segmentIndex += 16) {
				if (psData.un.proc.nselectors == 0) {
					break;
				}
				for (sindex = 0; sindex < psData.un.proc.nselectors; sindex++) {
					if (segData [sindex].flags & _PMF_INUSE) {
						if ((segData [sindex].flags & _PMF_BORROWED) == 0) {
							continue;
						}
						if (segData [sindex].nbytes / 1024 > totMemK) {
							continue;
						}
						if ((segData [sindex].flags & (_PMF_SHARED | _PMF_LINKED)) == (_PMF_SHARED | _PMF_LINKED)) {
							/* shared_bytes += segData [sindex].nbytes; */
						} else if (segData [sindex].flags & _PMF_CODE_RX) {
							ptr -> codeK += segData [sindex].nbytes;
						} else {
							ptr -> dataK += segData [sindex].nbytes;
						}
					}
				}
			}
			ptr -> codeK >>= 10;		/* convert to k */
			ptr -> dataK >>= 10;		/* convert to k */
			/*printf("%s:%d + %d\n", ptr->name, ptr->codeK, ptr->dataK);*/
		}
		currentPID++;
	}
}

static void
removeDeadEntries (pass)
int		pass;
{
	int		i;
	TopmemT	*ptr;
	TopmemT	*prev;

	for (i = 0; i < MaxHashEntries; i++) {
		prev = &topmemBackbone [i];
		ptr = prev -> next;
		while (ptr != NULL) {
			if (!*ptr -> name) {
				getName (ptr -> name, ptr -> pid);
			}
			if (ptr -> pass != pass) {
				prev -> next = ptr -> next;
				free (ptr);
				processCount--;
			} else {
				prev = ptr;
			}
			ptr = prev -> next;
		}
	}
}

static int
compareTOPMEM (a, b)
TopmemT **a;
TopmemT	**b;
{
	switch (displayType) {
	case	'c':
		return ((*b) -> codeK - (*a) -> codeK);
	case	'd':
		return ((*b) -> dataK - (*a) -> dataK);
	case	'm':
		return (((*b) -> codeK + (*b) -> dataK) - ((*a) -> codeK + (*a) -> dataK));
	}
	return (0);	/* to keep compiler happy */
}

static TopmemT freeMem;

static void
fetchSortTOPMEM ()
{
	int		i;
	int		p;
	TopmemT *ptr;

	free(processList);
	if ((processList = (TopmemT **) malloc (sizeof (TopmemT *) * (processCount+1))) == NULL) {
		fatal ("Couldn't allocate memory for new processList");
	}
	qnx_osinfo (0, &osData);
	strcpy (freeMem.name, "idle");
	freeMem.pid = 0;
	freeMem.codeK = freeMem.dataK = osData.freememk;
	if (displayType == 'm') {
		freeMem.codeK /= 2;	/* share free memory between data and code */
		freeMem.dataK /= 2;
	}
	processList [0] = &freeMem;
	p = 1;
	for (i = 0; i < MaxHashEntries; i++) {
		ptr = topmemBackbone [i].next;
		while (ptr != NULL) {
			processList [p++] = ptr;
			ptr = ptr -> next;
		}
	}
	qsort (processList, p, sizeof (TopmemT *), compareTOPMEM);
}

/* Debug line {FILE *fp;int j; fp=fopen("debug.out","a");for(j=0;j<i;j++){fprintf(fp,"%s code %ld data %ld (bytes)\n",processList[j]->name,processList[j]->codeK,processList[j]->dataK);}fclose(fp);} */

static PrioTotalsT prioTotals;

/* Return a copy of the latest priority-based CPU usage in the
   provided PrioTotalsT object */
void
memPrioTotals(PrioTotalsT *pt)
{
  memcpy(pt->memprio_totals, &prioTotals.memprio_totals, sizeof(prioTotals.memprio_totals));
}

static char procname [17];

void
calcDeltaTOPMEM()
{
	int		i;
	long	grandTotal;
	float		percentageCode;
	float		percentageData;
	float		percentage;
	float mem[NumberOfPriorities];


	/* Re-initialize the priority totals object */
	for (i = 0; i < NumberOfPriorities; i++) {
	  prioTotals.memprio_totals[i] = 0;
	}

	grandTotal = totMemK;
	for (i = 0; (i < processCount); i++) {
		if (!processList [i] -> codeK && !processList [i] -> dataK) {
			break;
		}

		percentageCode = ((float) processList [i] -> codeK * 100. / (float) grandTotal);
		percentageData = ((float) processList [i] -> dataK * 100. / (float) grandTotal);
		percentage = (percentageData + percentageCode);
		processList[i]->percentage = percentage;
		prioTotals.memprio_totals[processList[i]->prio] += percentage;
		/*printf("%f %f\n", mem[processList[i]->prio]);*/
	}
}

int
getProcessMem(char *name)
{
  int i;

  if (!processList || processCount == 0) return -1;

  if (!name) return -1;

  for (i = 0; i < processCount; i++) {
    if (!strcmp(name, processList[i]->name)) {
      return processList[i]->percentage;
    }
  }

  return -1;
}

