martes, 2 de julio de 2013

Command tail -n option implementation



C tail -n Implementation 



This a simple implementation for the command 'tail' with the option -n





#define _FILE_OFFSET_BITS 64
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <getopt.h>

#define BUFF_SIZE 4096
#define DEFAULT_LAST_LINES 10

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

void printProgramUsage(FILE* stream, int exitCode)
{
  fprintf(stream, "valid options\n");
  fprintf(stream, "-h Display program usage valid options.\n"
      "-n Prints the last n lines.\n");
  exit(exitCode);
}

int openFile(const char *file)
{
  int fd= open(file, O_RDONLY);
  if(fd == -1)
  {
    fprintf(stderr,"Error opening file: %s\n", file);
    exit(errno);
  }
  return (fd);
}

void printLines(int fd, off_t bytestart)
{
  char buffer[BUFF_SIZE];
  int readbytes;
  lseek(fd,bytestart,SEEK_SET);
  while((readbytes= read(fd,buffer,BUFF_SIZE)) > 0)
  {
     write(STDOUT_FILENO,buffer, readbytes);
  }
}

long moveLines(int fd, off_t fileset, long linesdistance)
{
  off_t current= lseek(fd, 0, SEEK_CUR);
  lseek(fd,fileset,SEEK_SET);
  long countlines= 0;
  int nbytes;
  char buffer[BUFF_SIZE];
  long amountbytes= 0;
  while((nbytes= read(fd,buffer,BUFF_SIZE)) > 0)
    {
      int index;
      for(index= 0; index < nbytes; index++)
    {
      if(buffer[index] == '\n')
        {
          if(countlines == (linesdistance - 1))
        {
          amountbytes++;
          return (fileset + amountbytes);
        }
          countlines++;
        }
      amountbytes++;
    }
    }
    return (fileset);
}
  

void walkFile(int fd, long numlines)
{
 long distance= 512;
 off_t end_file;
 off_t filebytes;
 int nbytes;
 int flag= 1;
 char buffer[BUFF_SIZE];
 long countbytes;
 long countlines;
 long linesdistance= 0;
 filebytes= lseek(fd,0,SEEK_END);
 end_file= filebytes - distance;
 do
 {
   if(end_file < 0)
   {
     end_file= 0;
     flag= 0;
   }
   else
     {
       end_file= moveLines(fd,end_file,1);
     }
   lseek(fd,end_file,SEEK_SET);
   linesdistance= 0;
   countbytes= 0;
   countlines= 0;
   while((nbytes= read(fd,buffer,BUFF_SIZE)) > 0)
   {
     int index;
     off_t moveline;
     for(index= 0; index < nbytes; index++)
     {
       if(buffer[index] == '\n' && (countbytes + end_file + 1) < filebytes)
       {
     if(countlines == numlines)
     {
       linesdistance++;
     }
     if(countlines < numlines)
     {
      countlines++;
     }
    }
       countbytes++;
     }
   }
   if(countlines == numlines)
   {
     linesdistance++;
     long startline= moveLines(fd,end_file,linesdistance);
     printLines(fd,startline);
     exit(0);
   }
   distance= distance * 2;
   end_file= filebytes - distance;
 }while(flag == 1);
  printLines(fd,0);
  close(fd);
}


int main(int argc, char *argv[])
{
  int fd;
  int opt;
  char *file= NULL;
  long lines;
  while((opt= getopt(argc,argv,"hn:")) != -1)
    {
      switch(opt)
    {
    case 'h': printProgramUsage(stdout,0);
      break;
    case 'n': 
      if(isNumber(optarg))
        {
          lines= atol(optarg);
          break;
        }
      else
        {
          fprintf(stderr,"-n argument not is a number\n");
          printProgramUsage(stderr,1);
        }
    case '?': printProgramUsage(stderr,1);
    default: printProgramUsage(stderr,1);
    }
    }
  if((optind + 1) != argc)
    {
      printProgramUsage(stderr,1);
    }

  file= argv[optind];
  if(lines <= 0)
    {
      lines= DEFAULT_LAST_LINES;
    }
  fd= openFile(file);
  walkFile(fd,lines);
  return 0;
}



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.




lunes, 17 de junio de 2013

Memoria de procesos Oracle sobre sistemas operativos Linux



Memoria de procesos Oracle



Mediante el siguiente programa escrito en C, se pretende determinar la cantidad de memoria consumida por los procesos Oracle, desde el punto de vista del sistema operativo.

Se debe recordar que la cantidad de memoria consumida por la instancia, debe de ser sumada a la cantidad de memoria configurada en la SGA y PGA.

#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);
}


El programa pude ser compilado mediante el siguiente comando:
gcc sourceC -o objectC
gcc memtrack.c -o memtrack

El programa puede ser usado de la siguiente manera:
objectC -u oracleSoftwareOwner
memtrack -u oracle


























Notas
  1. En caso de que alguno de los procesos evidencie un alto consumo de memoria, es recomendable validarlo con la cantidad de memoria consumida por la sesión en la base de datos.
  2. Debe recordar que un proceso con un alto consumo de memoria puede tener origen en la codificación de la unidades PL/SQL o de las sentencias de la aplicación.
  3. Este programa fue diseñado para dar solucion al problema 12.1 del libro Linux Programming Interface.



jueves, 23 de mayo de 2013

Implementacion de malloc basado en sbrk


Implementación de malloc basado en sbrk


La siguiente implementación de malloc basada en sbrk, no pretende ser un reemplazo de la función malloc, el propósito de esta implementación es didáctico y busca ampliar la compresión frente a los conceptos de asignación y liberación de memoria.

La implementación de malloc está basada en  las siguientes premisas:

  • Se asigna el primer bloque de memoria libre que se ajuste al requerimiento del programa.
  • Si un bloque de memoria libre es considerablemente más grande que el requerimiento del programa, el bloque será dividido con el fin de ahorrar espacio.
  • El tamaño de los bloques de memoria asignado deber ser múltiplos de 4.


La implementación de la función free está basada en las siguientes premisas:


  • Si se encuentran dos bloques de memoria contiguos libres, estos serán fusionados para crear un solo bloque de memoria más grande.
  • No se realizara una contracción del program break (brk) a no ser que toda la memoria requerida por el programa sea liberada.



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

/* Este macro define una formula para encontrar el multiplo
 de cuatro mas cercano al valor requerido*/

#define align4(x) (((((x)-1)>>2)<<2)+4)

/* Define el tamaño del struct, esto es realizado para no usar malloc*/

#define BLOCK_SIZE 20

/* Struct que contiene la metadata relacionada con el bloque de memoria*/

struct memory_block
{
    size_t size;
    struct memory_block *next;
    struct memory_block *prev;
    int free;
    void *pointer;
    char data[1];
};

typedef struct memory_block *chunk;

chunk rootPointer= NULL;
chunk tailPointer= NULL;

/* Divide el bloque de memoria con el fin de realizar un mejor uso de este
 recurso*/

void splitMemoryChunk(chunk memoryChunk, size_t size)
{
    chunk newChunk;
    newChunk= (chunk) (memoryChunk->data + size);
    newChunk->size= memoryChunk->size - size - BLOCK_SIZE;
    newChunk->next= memoryChunk->next;
    newChunk->prev= memoryChunk;
    newChunk->free= 1;
    newChunk->pointer= newChunk->data;
    memoryChunk->size= size;
    memoryChunk->next= newChunk;
    if(newChunk->next)
    {
        newChunk->next->prev= newChunk;
    }
}

/* Imprime la metadata relacionada con el bloque de memoria*/

void printMemoryInfo(chunk memoryAddress)
{
    printf("\n\t **** Memory Allocation Info ****\t\n");
    printf("\t Memory Address: %10p", memoryAddress);
    printf("\n\t Memory Size: %d", memoryAddress->size);
    printf("\n\t Memory Free: %d", memoryAddress->free);
    printf("\n\t Memory Data: %p", memoryAddress->data);
    printf("\n\t Memory Pointer %p", memoryAddress->pointer);
    printf("\n\t ******************************** \t\n");
}

/* Realiza la busqueda de un bloque de memoria que se ajuste
 al tamaño requerido*/

chunk findFirstFit(chunk *lastChunk, size_t size)
{
    chunk currentChunk= rootPointer;
    while (currentChunk && !(currentChunk->free && currentChunk->size >= size))
    {
        *lastChunk= currentChunk;
        currentChunk= currentChunk->next;
    }
    return currentChunk;
}

/* Crea un nuevo bloque de memoria */

chunk extendHeap(chunk lastChunk, size_t size)
{
    chunk newChunk;
    newChunk= sbrk(0);
    if(sbrk(BLOCK_SIZE + size) == (void *) -1)
    {
        return NULL;
    }
    newChunk->size= size;
    newChunk->next= NULL;
    newChunk->prev= lastChunk;
    newChunk->pointer= newChunk->data;
    if(lastChunk)
    {
        lastChunk->next= newChunk;
    }
    newChunk->free= 0;
    printMemoryInfo(newChunk);
    return newChunk;
}

/* Imprime la metadata de todos los bloques de memoria*/

void printChunkList()
{
    printf ("\n\t **** Print Memory Chunk List **** \t\n");
    chunk memoryRunner= rootPointer;
    while(memoryRunner != NULL)
    {
        printMemoryInfo(memoryRunner);
        memoryRunner= memoryRunner->next;
    }
    printf ("\n\t **** End Chunk List **** \t\n");
}

/* Implemetacion de malloc que realiza la asignacion
 de memoria*/

void *myMalloc(size_t size)
{
    chunk lastChunk, memoryChunk;
    size_t alignSize= align4(size);
    if(rootPointer)
    {
        lastChunk= rootPointer;
        memoryChunk= findFirstFit(&lastChunk, alignSize);
        if(memoryChunk)
        {
           printf("\n\t **** Find Memory Chunk ****\t\n");
           printMemoryInfo(memoryChunk);
            if((memoryChunk->size - alignSize) >= (BLOCK_SIZE + 4))
            {
                splitMemoryChunk(memoryChunk, alignSize);
            }
            memoryChunk->free= 0;
        }
        else
        {
            memoryChunk= extendHeap(lastChunk, alignSize);
            if(!memoryChunk)
            {
                return NULL;
            }
        }
    }
    else
    {
        memoryChunk= extendHeap(NULL, alignSize);
        if (!memoryChunk)
        {
            return NULL;
        }
        rootPointer= memoryChunk;
    }
    return (memoryChunk->data);
}

/* Obtiene la direcccion de memoria que almacena la metadata
 del bloque de memoria*/

chunk getMemoryChunk(void *chunkPointer)
{
    char *tmp;
    tmp= chunkPointer;
    chunkPointer= tmp -= BLOCK_SIZE;
    return chunkPointer;
}

/* Valida si la direccion de memoria que requiere ser liberada, en efecto fue entregada
 mediante nuestra implementacion de malloc*/

int validMemoryAddress(void *chunkPointer)
{
    if(rootPointer)
    {
        if (chunkPointer > (void *) rootPointer && chunkPointer < sbrk(0))
        {
            return (chunkPointer == (getMemoryChunk(chunkPointer))->pointer);
        }
    }
    return 0;
}

/* Fusiona dos bloques de memoria libres*/

chunk mergeMemoryChunk(chunk memoryChunk)
{
    if(memoryChunk->next && memoryChunk->next->free)
    {
        memoryChunk->size= memoryChunk->size + BLOCK_SIZE + memoryChunk->next->size;
        memoryChunk->next= memoryChunk->next->next;
        if(memoryChunk->next)
        {
            memoryChunk->next->prev= memoryChunk;
        }
    }
    return memoryChunk;
}

/* Implementacion de la funcion free*/

void myFree(void *chunkPointer)
{
    chunk memoryMetadata;
    if(validMemoryAddress(chunkPointer))
    {
        memoryMetadata= getMemoryChunk(chunkPointer);
        memoryMetadata->free= 1;
        printf("\n\t **** Memory Free Info **** \t\n");
        printMemoryInfo(memoryMetadata);
        if (memoryMetadata->prev && memoryMetadata->prev->free)
        {
            memoryMetadata= mergeMemoryChunk(memoryMetadata->prev);
            if(memoryMetadata->next)
            {
                mergeMemoryChunk(memoryMetadata);
            }
            else
            {
                if (memoryMetadata->prev)
                {
                    memoryMetadata->prev->next= NULL;
                }
                else
                {
                    rootPointer= NULL;
                    brk(memoryMetadata);
                }
            }
        }
     
    }
 }

int main()
{
    int *pointer1;
    int *pointer2;
    int *pointer3;
    int *pointer4;
    int *pointer5;
    int *pointer6;
    pointer1= myMalloc(10);
    pointer2= myMalloc(10);
    pointer3= myMalloc(100);
    pointer4= myMalloc(10);
    pointer5= myMalloc(10);
    printChunkList();
    myFree(pointer3);
    myFree(pointer4);
    printChunkList();
    pointer6= myMalloc(15);
    printChunkList();
    return 0;
}


Notas

  • En las funciones implementadas contienen algunas adiciones de la instrucción printf con l fin de visualizar los bloques de memoria manipulados por las operaciones.
  • La implemetación  esta basada en el texto proporcionado en texto Malloc Tutorial.
  • La Implementación de este programa fue concebida con el fin de dar solución al problema propuesto en el capitulo 7 del libro Linux Programming Interface.