Skip to content

File broker_process_size.c

File List > broker > broker_process_size.c

Go to the documentation of this file

/*
 * Copyright 2008 Search Solution Corporation
 * Copyright 2016 CUBRID Corporation
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */


/*
 * broker_process_size.c - Get process size
 *        Solaris, HPUX - by system call
 *        others - by 'ps' cmd (popen)
 *  return values
 *      > 1     success
 *      1   cannot get process information
 *      <= 0    no such process
 */

#ident "$Id$"

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

#if !defined(WINDOWS)
#include <unistd.h>
#else
#include <winsock2.h>
#include <windows.h>
#include <process.h>
#include <pdh.h>
#include <pdhmsg.h>
#include <io.h>
#endif

#if defined(SOLARIS)
#include <fcntl.h>
#include <sys/procfs.h>
#elif defined(HPUX)
#include <sys/pstat.h>
#elif defined(AIX)
#include <procinfo.h>
#elif defined(UNIXWARE7)
#include <sys/procfs.h>
#include <fcntl.h>
#elif defined(LINUX) || defined(ALPHA_LINUX)
#include <ctype.h>
#include <fcntl.h>
#include <string.h>
#include <sys/procfs.h>
#elif defined(OSF1)
#include <fcntl.h>
#include <sys/procfs.h>
#endif

#include "cas_common.h"
#include "broker_process_size.h"

#if defined(HPUX)
#include "hp_pstat.h"
#endif

#define GETSIZE_PATH            "getsize"

#if defined(LINUX) || defined(ALPHA_LINUX)
static char *skip_token (char *p);
#endif

#if defined(WINDOWS)
#define IS_COUNTER_VALUE_PTR_NULL()                                     \
        (cntvalue_pid == NULL || cntvalue_workset == NULL ||            \
         cntvalue_pct_cpu == NULL || cntvalue_num_thr == NULL)

static void alloc_counter_value ();

typedef PDH_STATUS (__stdcall * PDHOpenQuery) (LPCSTR, DWORD_PTR, PDH_HQUERY *);
typedef PDH_STATUS (__stdcall * PDHCloseQuery) (PDH_HQUERY);
typedef PDH_STATUS (__stdcall * PDHAddCounter) (PDH_HQUERY, LPCSTR, DWORD_PTR, PDH_HCOUNTER *);
typedef PDH_STATUS (__stdcall * PDHCollectQueryData) (PDH_HQUERY);
typedef PDH_STATUS (__stdcall * PDHGetFormattedCounterArray) (PDH_HCOUNTER, DWORD, LPDWORD, LPDWORD,
                                  PPDH_FMT_COUNTERVALUE_ITEM_A);
PDHOpenQuery fp_PdhOpenQuery;
PDHCloseQuery fp_PdhCloseQuery;
PDHAddCounter fp_PdhAddCounter;
PDHCollectQueryData fp_PdhCollectQueryData;
PDHGetFormattedCounterArray fp_PdhGetFormattedCounterArray;

HCOUNTER counter_pid;
HCOUNTER counter_pct_cpu;
HCOUNTER counter_workset;
HCOUNTER counter_num_thr;
PDH_FMT_COUNTERVALUE_ITEM *cntvalue_pid = NULL;
PDH_FMT_COUNTERVALUE_ITEM *cntvalue_pct_cpu = NULL;
PDH_FMT_COUNTERVALUE_ITEM *cntvalue_workset = NULL;
PDH_FMT_COUNTERVALUE_ITEM *cntvalue_num_thr = NULL;
HQUERY pdh_h_query;
int num_counter_value;
unsigned long pdh_num_proc;
#endif


#if defined(SOLARIS)
int
getsize (int pid)
{
  int procfd;
  struct prpsinfo info;
  const char *procdir = "/proc";
  char pname[128];

  if (pid <= 0)
    {
      return -1;
    }

  sprintf (pname, "%s/%05d", procdir, pid);

retry:
  if ((procfd = open (pname, O_RDONLY)) == -1)
    {
      return -1;
    }

  if (ioctl (procfd, PIOCPSINFO, (char *) &info) == -1)
    {
      int saverr = errno;

      close (procfd);
      if (saverr == EAGAIN)
    {
      goto retry;
    }
      if (saverr != ENOENT)
    {
      ;
    }
      return 1;
    }

  close (procfd);

  return (int) (info.pr_bysize / 1024);
}
#elif defined(HPUX)
int
getsize (int pid)
{
  int page_size = sysconf (_SC_PAGESIZE);
  INT64 psize;
  struct pst_status info;

  if (pid <= 0)
    {
      return -1;
    }

  if (HP_PSTAT_GETPROC (&info, pid) < 0)
    {
      if (errno == ESRCH)
    {
      return -1;
    }
      return 1;
    }

  psize = info.pst_vdsize + info.pst_vtsize + info.pst_vssize;
  psize *= (page_size / 1024);  /* psize by kilobyte */
  return (int) (psize);
}
#elif defined(AIX)
int
getsize (int pid)
{
  struct procentry64 entry;
  int page_size = sysconf (_SC_PAGESIZE);
  pid_t tmp_pid = pid;

  if (pid <= 0)
    {
      return -1;
    }

  if (getprocs64 (&entry, sizeof (entry), NULL, 0, &tmp_pid, 1) < 0)
    {
      if (kill (pid, 0) < 0)
    {
      if (errno == ESRCH)
        {
          return -1;
        }
    }
      return 1;
    }
  if (entry.pi_pid != pid)
    {
      return -1;
    }

  return (int) (((INT64) entry.pi_dvm) * ((INT64) page_size) / 1024);
}
#elif defined(UNIXWARE7)
int
getsize (int pid)
{
  char proc_file[128];
  psinfo_t pinfo;
  int read_len;
  int fd;
  int page_size = sysconf (_SC_PAGESIZE);

  if (pid <= 0)
    {
      return -1;
    }

  sprintf (proc_file, "/proc/%d/psinfo", pid);
  fd = open (proc_file, O_RDONLY);
  if (fd < 0)
    {
      return -1;
    }

  read_len = read (fd, &pinfo, sizeof (pinfo));
  close (fd);
  if (read_len < sizeof (pinfo))
    {
      return 8;
    }
  if (pinfo.pr_size <= 0)
    {
      pinfo.pr_size = 2;
    }

  return (int) (((INT64) pinfo.pr_size) * ((INT64) page_size) / 1024);
}
#elif defined(LINUX) || defined(ALPHA_LINUX)
int
getsize (int pid)
{
  char path[256];
  char line[256];
  FILE *fp;
  long total_mem_kb = 0;
  long rss = 0;
  long swap = 0;
  int found_count = 0;

  if (pid <= 0)
    {
      return -1;
    }

  snprintf (path, sizeof (path), "/proc/%d/status", pid);
  fp = fopen (path, "r");
  if (fp == NULL)
    {
      return -1;
    }

  while (fgets (line, sizeof (line), fp))
    {
      if (strncmp (line, "VmRSS:", 6) == 0)
    {
      rss = atol (line + 6);
      found_count++;
    }
      else if (strncmp (line, "VmSwap:", 7) == 0)
    {
      swap = atol (line + 7);
      found_count++;
    }

      if (found_count == 2)
    {
      break;
    }
    }

  fclose (fp);

  if (found_count == 0)
    {
      return -1;
    }

  total_mem_kb = rss + swap;

  return total_mem_kb;
}

static char *
skip_token (char *p)
{
  while (isspace (*p))
    p++;
  while (*p && !isspace (*p))
    p++;
  return p;
}
#elif defined(OSF1)
int
getsize (int pid)
{
  int page_size = sysconf (_SC_PAGESIZE);
  int procfd;
  struct prpsinfo info;
  const char *procdir = "/proc";
  char pname[128];

  if (pid <= 0)
    {
      return -1;
    }

  sprintf (pname, "%s/%05d", procdir, pid);

retry:
  if ((procfd = open (pname, O_RDONLY)) == -1)
    {
      return -1;
    }

  if (ioctl (procfd, PIOCPSINFO, (char *) &info) == -1)
    {
      int saverr = errno;

      close (procfd);
      if (saverr == EAGAIN)
    {
      goto retry;
    }
      if (saverr != ENOENT)
    {
      ;
    }
      return 1;
    }

  close (procfd);

  return (int) (((INT64) info.pr_size) * ((INT64) page_size) / 1024);
}
#elif defined(WINDOWS)
static void
alloc_counter_value ()
{
  PDH_FMT_COUNTERVALUE_ITEM *tmp_pid = NULL;
  PDH_FMT_COUNTERVALUE_ITEM *tmp_cpu = NULL;
  PDH_FMT_COUNTERVALUE_ITEM *tmp_workset = NULL;
  PDH_FMT_COUNTERVALUE_ITEM *tmp_num_thr = NULL;

  int _mem_size = sizeof (PDH_FMT_COUNTERVALUE_ITEM) * num_counter_value;
  tmp_pid = (PDH_FMT_COUNTERVALUE_ITEM *) realloc (cntvalue_pid, _mem_size);
  if (tmp_pid == NULL)
    {
      cntvalue_pid = NULL;
    }
  else
    {
      cntvalue_pid = tmp_pid;
    }

  tmp_workset = (PDH_FMT_COUNTERVALUE_ITEM *) realloc (cntvalue_workset, _mem_size);
  if (tmp_workset == NULL)
    {
      cntvalue_workset = NULL;
    }
  else
    {
      cntvalue_workset = tmp_workset;
    }

  tmp_cpu = (PDH_FMT_COUNTERVALUE_ITEM *) realloc (cntvalue_pct_cpu, _mem_size);
  if (tmp_cpu == NULL)
    {
      cntvalue_pct_cpu = NULL;
    }
  else
    {
      cntvalue_pct_cpu = tmp_cpu;
    }

  tmp_num_thr = (PDH_FMT_COUNTERVALUE_ITEM *) realloc (cntvalue_num_thr, _mem_size);
  if (tmp_num_thr == NULL)
    {
      cntvalue_num_thr = NULL;
    }
  else
    {
      cntvalue_num_thr = tmp_num_thr;
    }
}

int
getsize (int pid)
{
  return 1;
}

int
pdh_get_value (int pid, int *workset, float *pct_cpu, int *br_num_thr)
{
  unsigned long i;

  if (pid <= 0)
    {
      *workset = 0;
      *pct_cpu = 0;
      if (br_num_thr)
    {
      *br_num_thr = 0;
    }
      return 0;
    }

  for (i = 0; i < pdh_num_proc; i++)
    {
      if (cntvalue_pid[i].FmtValue.longValue == pid)
    {
      *workset = (int) (cntvalue_workset[i].FmtValue.largeValue / 1024);
      *pct_cpu = (float) (cntvalue_pct_cpu[i].FmtValue.doubleValue);
      if (br_num_thr)
        {
          *br_num_thr = (int) (cntvalue_num_thr[i].FmtValue.largeValue);
        }
      return 0;
    }
    }

  return -1;
}

int
pdh_init ()
{
  HMODULE h_module;
  PDH_STATUS pdh_status;
  CHAR path_buffer[128];

  h_module = LoadLibrary ("pdh.dll");
  if (h_module == NULL)
    {
      return -1;
    }

  fp_PdhOpenQuery = (PDHOpenQuery) GetProcAddress (h_module, "PdhOpenQueryA");
  if (fp_PdhOpenQuery == NULL)
    {
      return -1;
    }

  fp_PdhAddCounter = (PDHAddCounter) GetProcAddress (h_module, "PdhAddCounterA");
  if (fp_PdhAddCounter == NULL)
    {
      return -1;
    }

  fp_PdhCollectQueryData = (PDHCollectQueryData) GetProcAddress (h_module, "PdhCollectQueryData");
  if (fp_PdhCollectQueryData == NULL)
    {
      return -1;
    }

  fp_PdhGetFormattedCounterArray =
    (PDHGetFormattedCounterArray) GetProcAddress (h_module, "PdhGetFormattedCounterArrayA");
  if (fp_PdhGetFormattedCounterArray == NULL)
    {
      return -1;
    }

  fp_PdhCloseQuery = (PDHCloseQuery) GetProcAddress (h_module, "PdhCloseQuery");
  if (fp_PdhCloseQuery == NULL)
    {
      return -1;
    }

  pdh_status = (*fp_PdhOpenQuery) (0, 0, &pdh_h_query);
  if (pdh_status != ERROR_SUCCESS)
    {
      return -1;
    }

  strcpy (path_buffer, "\\Process(*)\\ID Process");
  pdh_status = (*fp_PdhAddCounter) (pdh_h_query, path_buffer, 0, &counter_pid);
  if (pdh_status != ERROR_SUCCESS)
    {
      return -1;
    }

  strcpy (path_buffer, "\\Process(*)\\Working Set");
  pdh_status = (*fp_PdhAddCounter) (pdh_h_query, path_buffer, 0, &counter_workset);
  if (pdh_status != ERROR_SUCCESS)
    {
      return -1;
    }

  strcpy (path_buffer, "\\Process(*)\\% Processor Time");
  pdh_status = (*fp_PdhAddCounter) (pdh_h_query, path_buffer, 0, &counter_pct_cpu);
  if (pdh_status != ERROR_SUCCESS)
    {
      return -1;
    }

  strcpy (path_buffer, "\\Process(*)\\Thread Count");
  pdh_status = (*fp_PdhAddCounter) (pdh_h_query, path_buffer, 0, &counter_num_thr);
  if (pdh_status != ERROR_SUCCESS)
    {
      return -1;
    }

  num_counter_value = 128;

  alloc_counter_value ();
  if (IS_COUNTER_VALUE_PTR_NULL ())
    {
      return -1;
    }
  memset (cntvalue_pid, 0, sizeof (PDH_FMT_COUNTERVALUE_ITEM) * num_counter_value);
  memset (cntvalue_workset, 0, sizeof (PDH_FMT_COUNTERVALUE_ITEM) * num_counter_value);
  memset (cntvalue_pct_cpu, 0, sizeof (PDH_FMT_COUNTERVALUE_ITEM) * num_counter_value);
  memset (cntvalue_num_thr, 0, sizeof (PDH_FMT_COUNTERVALUE_ITEM) * num_counter_value);

  return 0;
}

int
pdh_collect ()
{
  unsigned long in_size;
  PDH_STATUS pdh_status;
  int i, retry_count = 10;
  char success_flag = FALSE;

  if (IS_COUNTER_VALUE_PTR_NULL ())
    {
      alloc_counter_value ();
      if (IS_COUNTER_VALUE_PTR_NULL ())
    goto collect_error;
    }

  for (i = 0; i < retry_count; i++)
    {
      pdh_status = (*fp_PdhCollectQueryData) (pdh_h_query);
      if (pdh_status != ERROR_SUCCESS)
    {
      continue;
    }
      in_size = sizeof (PDH_FMT_COUNTERVALUE_ITEM) * num_counter_value;

      pdh_status = (*fp_PdhGetFormattedCounterArray) (counter_pid, PDH_FMT_LONG, &in_size, &pdh_num_proc, cntvalue_pid);
      if (pdh_status != ERROR_SUCCESS)
    {
      if (pdh_status == PDH_MORE_DATA)
        {
          num_counter_value *= 2;
          alloc_counter_value ();
          if (IS_COUNTER_VALUE_PTR_NULL ())
        {
          goto collect_error;
        }
        }
      continue;
    }
      pdh_status =
    (*fp_PdhGetFormattedCounterArray) (counter_workset, PDH_FMT_LARGE, &in_size, &pdh_num_proc, cntvalue_workset);
      if (pdh_status != ERROR_SUCCESS)
    {
      continue;
    }
      pdh_status =
    (*fp_PdhGetFormattedCounterArray) (counter_pct_cpu, PDH_FMT_DOUBLE, &in_size, &pdh_num_proc, cntvalue_pct_cpu);
      if (pdh_status != ERROR_SUCCESS)
    {
      continue;
    }
      pdh_status =
    (*fp_PdhGetFormattedCounterArray) (counter_num_thr, PDH_FMT_LONG, &in_size, &pdh_num_proc, cntvalue_num_thr);
      if (pdh_status != ERROR_SUCCESS)
    {
      continue;
    }

      success_flag = TRUE;
      break;
    }

  if (success_flag == TRUE)
    {
      return 0;
    }

collect_error:
  pdh_num_proc = 0;
  return -1;
}
#else
int
getsize (int pid)
{
  FILE *pp;
  char cmd[256];
  char buf[256];
  int i, c;
  INT64 psize;

  if (pid <= 0)
    {
      return -1;
    }

  sprintf (cmd, "%s %d", GETSIZE_PATH, pid);
  pp = popen (cmd, "r");
  if (pp == NULL)
    {
      return -1;
    }
  i = 0;
  while ((c = getc (pp)) != EOF)
    {
      buf[i++] = c;
    }
  buf[i] = '\0';
  pclose (pp);
  psize = atoll (buf);

  if (psize <= 0)
    {
      if (kill (pid, 0) < 0)
    {
      if (errno == ESRCH)
        {
          return -1;
        }
    }
      return 1;
    }

  return (int) psize;
}
#endif