miércoles, 19 de junio de 2013

Memory used by Oracle processes on Linux



Memory used by Oracle processes on Linux


Some times the Operating system administrators and Database Administrators need to know how much memory is used by Oracle database processes.

With this program you can get that information from operating system point of view.  


**************** C Program to find memory used by Oracle processes ****************

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <pwd.h>
#include <getopt.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <dirent.h>
#include <string.h>



#define LINE_BUFFER 100

/* Global variables */

const char *programName;
const char *username;
long memoryPageSize;
uid_t userid;
int totalprocess= 0;
int totalinstances= 0;

struct memory
{
  long total;
  long free;
  long used;
  long buffers;
  long cached;
  long rused;
  long rfree;
};

struct process
{
  long pid;
  long rss;
  long share;
  double memory;
  char instance[LINE_BUFFER];
  char cmdline[LINE_BUFFER];
  struct process *nextNode;
};

struct instance
{
  char instance[LINE_BUFFER];
  double memory;
  int processes;
  struct instance *nextNode;
};

typedef struct memory systeminfo;
typedef struct process *processinfo;
typedef struct instance *instanceinfo;

processinfo rootProcessNode= NULL;
processinfo tailProcessNode= NULL;

instanceinfo rootInstanceNode= NULL;

/* Insert root node to the instance linked list */

void insertRootInstance(processinfo node)
{
  rootInstanceNode= malloc(sizeof(struct instance));
  strcpy(rootInstanceNode->instance, node->instance);
  rootInstanceNode->memory= node->memory;
  rootInstanceNode->processes= 1;
  rootInstanceNode->nextNode= NULL;
  totalinstances++;
}

/* Add a new node to the instance linked list */

void addInstanceNode(processinfo node)
{
  instanceinfo instanceNode= rootInstanceNode;
  instanceinfo backNode= rootInstanceNode;
  while(instanceNode != NULL)
    {
       if((strcmp(instanceNode->instance, node->instance)) == 0)
{
 break;
}
       backNode= instanceNode;
       instanceNode= instanceNode->nextNode;
    }
  if(instanceNode == NULL)
    {
      instanceinfo nodeInfo= malloc(sizeof(struct instance));
      strcpy(nodeInfo->instance, node->instance);
      nodeInfo->memory= node->memory;
      nodeInfo->processes= 1;
      nodeInfo->nextNode= NULL;
      backNode->nextNode= nodeInfo;
      totalinstances++;
    }
  else
    {
      instanceNode->memory= instanceNode->memory + node->memory;
      instanceNode->processes= instanceNode->processes + 1;
    }
}

/* This function sorts the instance linked list */

void sortInstanceList()
{
  int i= 0;
  while(i < totalinstances)
    {
      instanceinfo instanceNode= rootInstanceNode;
      while(instanceNode->nextNode != NULL)
{
 if(instanceNode->memory < instanceNode->nextNode->memory)
   {
     struct instance backupInfo= *instanceNode;
     instanceNode->memory= instanceNode->nextNode->memory;
     instanceNode->processes= instanceNode->nextNode->processes;
     strcpy(instanceNode->instance, instanceNode->nextNode->instance);
     instanceNode->nextNode->memory= backupInfo.memory;
     instanceNode->nextNode->processes= backupInfo.processes;
     strcpy(instanceNode->nextNode->instance, backupInfo.instance);
   }
 instanceNode= instanceNode->nextNode;
}
      i++;
    }
}

/* Priint instance head message */

void printInstanceMessage()
{
  printf("%c[%d;%d;%dm",27,0,32,1);
  printf("\n**** Operating System Instance Memory Information ****\n\n");
  printf("%c[%d;%d;%dm",27,0,33,1);
  printf("Instance\t\tMemory (MB)\t\tProcesses\n");
  printf("%c[%dm", 27, 0);
}

/* Print instance linked list */

void printInstanceList()
{
  instanceinfo instanceNode= rootInstanceNode;
  printInstanceMessage();
  while(instanceNode != NULL)
    {
      printf("%.15s    \t\t\%.2lf\t\t\t%d\n", instanceNode->instance, instanceNode->memory, instanceNode->processes);
      instanceNode= instanceNode->nextNode;
    }
}

/* Function to add a new node to the instance linked list */

void insertInstanceNode(processinfo node)
{
  if(rootInstanceNode == NULL)
    {
      insertRootInstance(node);
    }
  else
    {
      addInstanceNode(node);
    }
}

/* Insert root node to the process linked list */

void insertRootNode(processinfo node)
{
  rootProcessNode= node;
  tailProcessNode= rootProcessNode;
  rootProcessNode->nextNode= NULL;
}

/* Add a node to the process linked list */

void addProcessNode(processinfo node)
{
  tailProcessNode->nextNode= node;
  tailProcessNode= node;
  tailProcessNode->nextNode= NULL;
}

/* Function to add a new node to the process linked list */

void insertProcessNode(processinfo node)
{
  if(rootProcessNode == NULL)
    {
      insertRootNode(node);
    }
  else
    {
      addProcessNode(node);
    }
  insertInstanceNode(node);
}


/* This function sorts process linked list */

void sortProcessList()
{
  int i= 0;
  while(i < totalprocess)
    {
      processinfo processNode= rootProcessNode;
      while(processNode->nextNode != NULL)
{
 if(processNode->memory < processNode->nextNode->memory)
   {
     struct process backupInfo= *processNode;
     processNode->pid= processNode->nextNode->pid;
     processNode->rss= processNode->nextNode->rss;
     processNode->share= processNode->nextNode->share;
     processNode->memory= processNode->nextNode->memory;
     strcpy(processNode->instance, processNode->nextNode->instance);
     strcpy(processNode->cmdline, processNode->nextNode->cmdline);
     processNode->nextNode->pid= backupInfo.pid;
     processNode->nextNode->rss= backupInfo.rss;
     processNode->nextNode->share= backupInfo.share;
     processNode->nextNode->memory= backupInfo.memory;
     strcpy(processNode->nextNode->instance, backupInfo.instance);
     strcpy(processNode->nextNode->cmdline, backupInfo.cmdline);
   }
 processNode= processNode->nextNode;
}
      i++;
    }
   
}

/* This function prints process linked list*/

void printProcessList()
{
  void printMemoryMessage();
  void printInfo(processinfo);
  processinfo processNode= rootProcessNode;
  printMemoryMessage();
  while(processNode != NULL)
    {
      printInfo(processNode);
      processNode= processNode->nextNode;
    }
}

/* Print program usage */

void printProgramUsage(FILE* stream, int exitCode)
{
  fprintf(stream, "%s valid options\n", programName);
  fprintf(stream, "-h --help Display program usage valid options.\n"
 "-u --username Opertaing system username to monitor.\n");
  exit(exitCode);
}


/* The goal of this function is to get the operating
   system memory page size */

long getMemoryPageSize(int limit)
{
  errno= 0;
  long pageSize;
  pageSize= sysconf(limit);
  if(pageSize != -1)
    {
      return pageSize;
    }
  else
    if (errno == 0)
    {
      fprintf(stderr, "Program error getting page size\n");
      exit(1);
    }
    else
      {
fprintf(stderr, "Invalid System Limit\n");
exit(errno);
      }
  return pageSize;
}

/* The goal of this function is to get the user id from
   operating system username that was got like argument on to
   program call */

uid_t getUserIdFromUsername(const char *username)
{
  struct passwd *userInfo;
  userInfo= getpwnam(username);
  if(userInfo == NULL)
    {
      fprintf(stderr, "Username not exist\n");
      exit(1);
    }
  return userInfo->pw_uid;
}

/* This function reads /proc/meminfo line by line to get
 memory parameters required */

systeminfo parseSystemMemoryInfo(FILE* fdMemory)
{
  systeminfo memoryUsage;
  char line[LINE_BUFFER];
  int countMatch= 0;
  long total= 0;
  long free= 0;
  long buffers= 0;
  long cached= 0;;
  while ((fgets(line, LINE_BUFFER, fdMemory)) != NULL && countMatch < 4)
    {
      if ((sscanf(line, "MemTotal:\t%ld", &total)) == 1)
        {
 countMatch++;
        }
        if ((sscanf(line, "MemFree:\t%ld", &free)) == 1)
        {
 countMatch++;
        }
        if ((sscanf(line, "Buffers:\t%ld", &buffers)) == 1)
        {
 countMatch++;
        }
        if ((sscanf(line, "Cached:\t%ld", &cached)) == 1)
        {
 countMatch++;
        }
    }
  memoryUsage.total= total / 1024;
  memoryUsage.free= free / 1024;
  memoryUsage.used= memoryUsage.total - memoryUsage.free;
  long plus_cached= (buffers + cached) / 1024;
  memoryUsage.rused= memoryUsage.used - plus_cached;
  memoryUsage.rfree= memoryUsage.free + plus_cached;
  return (memoryUsage);
}

/* Open operating system memory information file */

FILE *openMemInfo(const char *memPath)
{
  FILE *fdMemory;
  fdMemory= fopen(memPath, "r");
  if(fdMemory == NULL)
    {
      fprintf(stderr, "Error getting operating system memory information\n");
      exit(errno);
    }
  return (fdMemory);
}

/* This function open /proc/meminfo to get operating system
 * memory  usage*/

void printMemorySystemInfo()
{
  FILE *fdMemory;
  systeminfo memoryUsage;
  fdMemory= openMemInfo("/proc/meminfo");
  printf("%c[%d;%d;%dm",27,0,32,1);
  printf("**** Operating System Memory Information ****\n\n");
  printf("%c[%d;%d;%dm",27,0,33,1);
  printf("Total (MB)     \t Used (MB)    \t Free (MB)\n");
  printf("%c[%dm", 27, 0);
  memoryUsage= parseSystemMemoryInfo(fdMemory);
  printf("%ld", memoryUsage.total);
  printf("\t\t %ld (%ld%%)", memoryUsage.rused, (memoryUsage.rused * 100 / memoryUsage.total));
  printf("\t %ld (%ld%%)\n", memoryUsage.rfree, (memoryUsage.rfree * 100 / memoryUsage.total));
  fclose(fdMemory);
}

/* Check if the string argument is a number */

int isNumber(char *string)
{
    char *endPointer;
    long pid= strtol(string, &endPointer, 10);
    if (*endPointer == '\0')
    {
        return 1;
    }
    return 0;
}

/* Check if the process is real userd id or efective user id
   match whith oracle software owner */

int parseStatus(FILE *file)
{
    char line[LINE_BUFFER];
    char command[10];
    long realId= -1;
    long efectiveId= -1;
    while ((fgets(line, LINE_BUFFER, file)) != NULL)
    {
      if((sscanf(line, "Name:\t%s", command)) == 1)
{

 if((strcmp(command, "oracle")) != 0)
   {
     return 0;
   }
}
      if ((sscanf(line, "Uid:\t%ld\t%ld", &realId,&efectiveId)) == 1)
        {
  break;
        }
    }
    if(userid == realId || userid == efectiveId)
      {
return 1;
      }
    return 0;
}

/* Open a directory */

DIR *openDirectory(const char *dirPath)
{
    DIR *directory= NULL;
    directory= opendir(dirPath);
    return (directory);
}

/* Parse the line that was passed from the statm file. */

processinfo getMemoryInfo(char *line, processinfo processMemory)
{
  char *endPointer;
  strtol(line, &endPointer, 10);
  processMemory->rss= strtol(endPointer, &endPointer, 10);
  processMemory->share= strtol(endPointer, &endPointer, 10);
  return (processMemory);
}

/* Print process memory head message */

void printMemoryMessage()
{
  printf("%c[%d;%d;%dm",27,0,32,1);
  printf("\n**** Operating System Process Memory Information ****\n\n");
  printf("%c[%d;%d;%dm",27,0,33,1);
  printf("PID\t\tMemory (MB)\t\tCMD\t\t\t\tInstance\n");
  printf("%c[%dm", 27, 0);
}

/* Function to get command instance */

char *getInstance(char *cmdline)
{
  static char instance[10];
  static char word1[20];
  if((sscanf(cmdline,"oracle%s",word1)) == 1)
    {
      getInstance(word1);
    }
  else
    {
      char *token= strtok(cmdline, "_");
      while(token != NULL)
{
 strcpy(word1,token);
 token= strtok(NULL,"_");
}
    }
  strncpy(instance,word1,10);
  return (instance);
}

/* Function to print process memory information */

void printInfo(processinfo process)
{
  printf("%ld\t\t%.2lf\t\t\t%.15s\t\t\t%s\n",process->pid, process->memory, process->cmdline, process->instance);
}

/* This function open process directory, and read several files
   to get all process information */

processinfo getProcessInfo(char *directory, char *processDir, size_t pathSize, processinfo processMemory)
{
  processMemory= NULL;
  DIR *processDirectory= NULL;
  char *statusFile= malloc(pathSize);
  char *statmFile= malloc(pathSize);
  char *cmdlineFile= malloc(pathSize);
  snprintf(statusFile, pathSize, "/proc/%s/status", processDir);
  snprintf(statmFile, pathSize, "/proc/%s/statm", processDir);
  snprintf(cmdlineFile, pathSize, "/proc/%s/cmdline", processDir);
  processDirectory= openDirectory(directory);
  if(processDirectory != NULL)
    {
      FILE *fdstatus= fopen(statusFile, "r");
      FILE *fdstatm= fopen(statmFile, "r");
      FILE *fdcmdline= fopen(cmdlineFile, "r");
      if (fdstatus != NULL && fdstatm != NULL && fdcmdline != NULL)
{
 if(parseStatus(fdstatus))
   {
     processMemory= malloc(sizeof(struct process));
     char line[LINE_BUFFER];
     char line2[LINE_BUFFER];
     fgets(line, LINE_BUFFER, fdstatm);
     fgets(line2, LINE_BUFFER, fdcmdline);
     processMemory= getMemoryInfo(line, processMemory);
     processMemory->pid= atol(processDir);
     strcpy(processMemory->cmdline,line2);
              strcpy(processMemory->instance, getInstance(line2));
     processMemory->memory= (double) ((processMemory->rss - processMemory->share) * memoryPageSize) /  1024;
   }
 fclose(fdstatus);
 fclose(fdstatm);
 fclose(fdcmdline);
}
    }
  closedir(processDirectory);
  return (processMemory);
}


/* read all directories in the /proc virtual file system */

void printProcessInfo()
{
  processinfo process;
  DIR *procDirectory;
  struct dirent *directoryContent= NULL;
  procDirectory= openDirectory("/proc");
  if(procDirectory == NULL)
    {
      fprintf(stderr, "Error opening proc directory\n");
      exit(errno);
    }
  while ((directoryContent= readdir(procDirectory)) != NULL)
    {
      char *directoryName= directoryContent->d_name;
      if (isNumber(directoryName))
{
          char *directoryPath= malloc(256);
          snprintf(directoryPath, 256, "/proc/%s", directoryName);
 process= getProcessInfo(directoryPath,directoryName, 256, process);
 if(process != NULL)
   {
     insertProcessNode(process);
     totalprocess++;
   }
}
    }
  closedir(procDirectory);
}

void printByUsername()
{
  username= optarg;
  userid= getUserIdFromUsername(username);
  printMemorySystemInfo();
  printProcessInfo();
  sortInstanceList();
  printInstanceList();
  sortProcessList();
  printProcessList();
  exit(EXIT_SUCCESS);
}

int main(int argc, char *argv[])
{
  int option;
  const char* const short_options= "hu:";
  const struct option long_options[]=
  {
      {"help",0,NULL,'h'},
      {"username",1,NULL,'u'},
      {NULL,0,NULL,0}
  };
  programName= argv[0];
  memoryPageSize= getMemoryPageSize(_SC_PAGESIZE) / 1024;
  do
  {
      option = getopt_long(argc, argv, short_options, long_options, NULL);
      switch(option)
      {
      case 'h': printProgramUsage(stdout,0);
      case 'u':printByUsername();
      case '?': printProgramUsage(stderr,1);
      case -1:printProgramUsage(stderr,1);
break;
      default: abort();
      }
  }while(option != -1);
  exit(EXIT_SUCCESS);
}


*********************************************************************************

Compilation Instructions:

1. Copy the above code in any text editor.
2. Save the text file with any name and .c extension (Ej oramemtrack.c).
3. Compile the code with gcc (gcc oramemtrack.c -o oramemtrack).

You can execute the binary file with the below instruction:

./oramemtrack -u oracleSoftwareOwner (./oramemtrack -u oracle).

Don't forget to add the SGA size and PGA size of each database instance running on the server.