09
5月
2007

リソース情報の取得と設定

プログラムを実行する際のリソース情報(とくにリソースの制限)を取得する必要がある場合がある.
limits.h
プライオリティの取得と設定
リソース使用量
リソースの制限とその設定

limits.h

imits.hやそこから読み込まれるヘッダにはcharのビット数やファイル名長の制限など,おおくの制限が定義されている.また,とくにファイル名長は,互換性を維持するためにpathconfやfpathconfという関数がある.
#include <limits.h>
#include <unistd.h>
#include <stdio.h>

int main()
{
  fprintf(stdout,"CHAR_BIT %d\n",CHAR_BIT);
  fprintf(stdout,"SCHAR_MIN %d\n",SCHAR_MIN);
  fprintf(stdout,"SCHAR_MAX %d\n",SCHAR_MAX);
  fprintf(stdout,"NAME_MAX %d\n",NAME_MAX);

  fprintf(stdout,"=========================================================\n");

  fprintf(stdout,"CHAR_BIT from pathconf %d \n",pathconf("/",_PC_NAME_MAX));

  exit(0);
}
これを実行すると,私の環境では以下のように出力された.
CHAR_BIT 8
SCHAR_MIN -128
SCHAR_MAX 127
NAME_MAX 255
=========================================================
CHAR_BIT from pathconf 255 
あと
grep -rl " NAME_MAX " /usr/include/*
とすると
/usr/include/glib-1.2/glib.h
grep: 警告: /usr/include/gnome-xml/libxml: ディレクトリーが再帰的ループをしています
/usr/include/linux/limits.h
となった. NAME_MAXの値はglib.hとlinux/limits.hのどちらが使用されているのだろうか(値は同じだった).

プライオリティの取得と設定

プライオリティといえばniceだが(?),プログラム中で自分自身や自分の子プロセスのプライオリティを取得したり設定したりできる.getpriorityとsetpriorityである.
#include <sys/resource.h>
#include <stdio.h>

int main()
{
  /* getpriorityの第一引数は第二引数の意味を示す.
     以下はgetpid()の値がPRIO_PROCESS(プロセスID)であること意味している.
     これは,例えば第二引数がプロセスグループとかユーザを意味したりするので必要である.*/
  fprintf(stdout,"priority %d \n",getpriority(PRIO_PROCESS,getpid()));
  fprintf(stdout,"set priority to 10\n");
  /* プライオリティの設定.
     コマンドniceから察するに(未確認)プライオリティの範囲は-20から19で,
     負のプライオリティを設定するにはroot権限が必要になる. */
  setpriority(PRIO_PROCESS,getpid(),10);
  fprintf(stdout,"priority %d \n",getpriority(PRIO_PROCESS,getpid()));

  exit(0);
}
以下実行結果.プライオリティのデフォルトは0である.
priority 0 
set priority to 10
priority 10 

リソース使用量

getrusageを使用するとリソースの使用量の情報を取得できる.この情報はrusage構造体を介して返される.rusage構造体は以下のように宣言されている(/usr/include/linux/resource.hより).
struct  rusage {
        struct timeval ru_utime;        /* user time used */
        struct timeval ru_stime;        /* system time used */
        long    ru_maxrss;              /* maximum resident set size */
        long    ru_ixrss;               /* integral shared memory size */
        long    ru_idrss;               /* integral unshared data size */
        long    ru_isrss;               /* integral unshared stack size */
        long    ru_minflt;              /* page reclaims */
        long    ru_majflt;              /* page faults */
        long    ru_nswap;               /* swaps */
        long    ru_inblock;             /* block input operations */
        long    ru_oublock;             /* block output operations */
        long    ru_msgsnd;              /* messages sent */
        long    ru_msgrcv;              /* messages received */
        long    ru_nsignals;            /* signals received */
        long    ru_nvcsw;               /* voluntary context switches */
        long    ru_nivcsw;              /* involuntary  */
};
以下,getrusageのサンプルを示す.
/********  man getrusageの注意書きより  **********************
今日では <sys/time.h> をインクルードする必要はないが、
インクルードしておけば移植性が増す。
(実際 struct timeval は<sys/time.h> で定義されている。)
**************************************************************/
#include <sys/resource.h>
#include <limits.h>
#include <stdio.h>

int main()
{
  struct rusage *resource_data;

  double i=0;
  double j=0;

  /* 何らかの処理を実行 */
  for(i=0;i<1000000;i++){
    j+=log(i*j);
    fprintf(stdout,"%f\n",j);
  }

  /* ruage構造体の取得.第一引数はRUSAGE_SELF(該当プロセスのみ)か
     RUSAGE_CHILDREN(子プロセスも含む)である.*/
  getrusage(RUSAGE_SELF,resource_data);
  /* rusage構造体から情報を出力 */
  /* ru_utimeは使用したユーザ時間(timeval構造体).
     以下/usr/include/linux/time.hより
struct timeval {
        time_t          tv_sec;          seconds
        suseconds_t     tv_usec;         microseconds
};
*/
  fprintf(stdout,"user time used = %lds %ldus\n",
          resource_data->ru_utime.tv_sec,resource_data->ru_utime.tv_usec);
  /* ru_stimeは使用したシステム時間(timeval構造体) */
  fprintf(stdout,"system time used = %lds %ldus\n",
          resource_data->ru_stime.tv_sec,resource_data->ru_stime.tv_usec);

  exit(0);
}
実行結果は以下のようになる(無論環境依存だが).
user time used = 3s 970000us
system time used = 1s 570000us

リソースの制限とその設定

リソースの制限にはソフト制限とハード制限がある.

ソフト制限超えるべきでない値.超えるとライブラリ関数がエラーを返すことがある.
ハード制限この制限を超えるとシステムがプロセスにシグナルを送りそのプロセスを殺そうとする

ソフト制限はハード制限を超えない範囲で設定できる,ということである.さらに,ハード制限は引き下げることが可能である.また,root権限がある場合だけはハード制限を引きあげることができる.
リソースの制限はrlimit構造体で取得できる.以下,/usr/include/bits/resource.hより

struct rlimit
  {
    /* The current (soft) limit.  */
    rlim_t rlim_cur;
    /* The hard limit.  */
    rlim_t rlim_max;
  };
rlimit構造体はgetrlimit,setrlimitで取得,設定できる.それぞれの第一引数はどのリソースに対するrlimitかを示す.第一引数には以下のものを設定できる(/usr/include/bits/resource.hより).
enum __rlimit_resource
{
  /* Per-process CPU limit, in seconds.  */
  RLIMIT_CPU = 0,
#define RLIMIT_CPU RLIMIT_CPU

  /* Largest file that can be created, in bytes.  */
  RLIMIT_FSIZE = 1,
#define	RLIMIT_FSIZE RLIMIT_FSIZE

  /* Maximum size of data segment, in bytes.  */
  RLIMIT_DATA = 2,
#define	RLIMIT_DATA RLIMIT_DATA

  /* Maximum size of stack segment, in bytes.  */
  RLIMIT_STACK = 3,
#define	RLIMIT_STACK RLIMIT_STACK

  /* Largest core file that can be created, in bytes.  */
  RLIMIT_CORE = 4,
#define	RLIMIT_CORE RLIMIT_CORE

  /* Largest resident set size, in bytes.
     This affects swapping; processes that are exceeding their
     resident set size will be more likely to have physical memory
     taken from them.  */
  RLIMIT_RSS = 5,
#define	RLIMIT_RSS RLIMIT_RSS

  /* Number of open files.  */
  RLIMIT_NOFILE = 7,
  RLIMIT_OFILE = RLIMIT_NOFILE, /* BSD name for same.  */
#define RLIMIT_NOFILE RLIMIT_NOFILE
#define RLIMIT_OFILE RLIMIT_OFILE

  /* Address space limit.  */
  RLIMIT_AS = 9,
#define RLIMIT_AS RLIMIT_AS

  /* Number of processes.  */
  RLIMIT_NPROC = 6,
#define RLIMIT_NPROC RLIMIT_NPROC

  /* Locked-in-memory address space.  */
  RLIMIT_MEMLOCK = 8,
#define RLIMIT_MEMLOCK RLIMIT_MEMLOCK

  /* Maximum number of file locks.  */
  RLIMIT_LOCKS = 10,
#define RLIMIT_LOCKS RLIMIT_LOCKS

  RLIMIT_NLIMITS = 11,
  RLIM_NLIMITS = RLIMIT_NLIMITS
#define RLIMIT_NLIMITS RLIMIT_NLIMITS
#define RLIM_NLIMITS RLIM_NLIMITS
};
getrlimitを使用するサンプルを以下に示す.
#include <sys/time.h>
#include <sys/resource.h>
#include <unistd.h>
#include <stdio.h>

int main()
{
  struct rlimit *resource;

  if(getrlimit(RLIMIT_CPU,resource)==-1){
    fprintf(stderr,"failed to getrlimit\n");
  }
  fprintf(stdout,"CPU Current/Max = %ld/%ld\n",
	  resource->rlim_cur,resource->rlim_max);

  exit(0);
}
実行結果を以下に示す.
CPU Current/Max = -1/-1
???????あれ??????......bashのコマンドにulimitというのがある.
$ulimit -a
core file size        (blocks, -c) 0
data seg size         (kbytes, -d) unlimited
file size             (blocks, -f) unlimited
max locked memory     (kbytes, -l) unlimited
max memory size       (kbytes, -m) unlimited
open files                    (-n) 1024
pipe size          (512 bytes, -p) 8
stack size            (kbytes, -s) 8192
cpu time             (seconds, -t) unlimited
max user processes            (-u) 256
virtual memory        (kbytes, -v) unlimited
なるほど,無制限の場合は-1なのか.結果的にとてもつまらないサンプルになってしまった.

You may also like...