Oracle Database の CPU time には割込みで使われた時間は含まれなさそう

SQL*Plus でログインして、自分の PID を調べる

[oracle@localhost ~]$ sqlplus neo/zion

SQL> select s.sid, s.serial#, p.spid from v$session s, v$process p where p.addr = s.paddr and s.sid = sys_context('USERENV','SID');

       SID    SERIAL# SPID
---------- ---------- ------------------------
        17         19 3164

サーバープロセスに strace をしかける

[root@localhost ~]# /usr/bin/strace -p 3164 -o strace.log
Process 3164 attached - interrupt to quit

SQL を実行し、SQL*Plus を終了する

SQL> select count(*) from agent;

  COUNT(*)
----------
  10000000

SQL> exit

サーバープロセスが終了して、strace もアタッチするプロセスがなくなり、終了する

[root@localhost ~]# /usr/bin/strace -p 3164 -o strace.log
Process 3164 attached - interrupt to quit
Process 3164 detached

strace で取得したシステムコールのトレースを見てみる

[root@localhost ~]# head -20 strace.log 
read(9, "\1?\0\0\6\0\0\0\0\0\30>\334\361\0\0\0\0\0\21i\35\376\377\377\377\1\0\0\0\4\0"..., 8208) = 319
gettimeofday({1353546605, 695700}, NULL) = 0
getrusage(RUSAGE_SELF, {ru_utime={0, 3999}, ru_stime={0, 33994}, ...}) = 0
times({tms_utime=0, tms_stime=3, tms_cutime=0, tms_cstime=0}) = 429525137
gettimeofday({1353546605, 695915}, NULL) = 0
getrusage(RUSAGE_SELF, {ru_utime={0, 3999}, ru_stime={0, 33994}, ...}) = 0
getrusage(RUSAGE_SELF, {ru_utime={0, 3999}, ru_stime={0, 33994}, ...}) = 0
times({tms_utime=0, tms_stime=3, tms_cutime=0, tms_cstime=0}) = 429525137
getrusage(RUSAGE_SELF, {ru_utime={0, 3999}, ru_stime={0, 33994}, ...}) = 0
times({tms_utime=0, tms_stime=3, tms_cutime=0, tms_cstime=0}) = 429525137
getrusage(RUSAGE_SELF, {ru_utime={0, 3999}, ru_stime={0, 33994}, ...}) = 0
getrusage(RUSAGE_SELF, {ru_utime={0, 3999}, ru_stime={0, 33994}, ...}) = 0
getrusage(RUSAGE_SELF, {ru_utime={0, 3999}, ru_stime={0, 33994}, ...}) = 0
gettimeofday({1353546605, 696013}, NULL) = 0
gettimeofday({1353546605, 696038}, NULL) = 0
getrusage(RUSAGE_SELF, {ru_utime={0, 3999}, ru_stime={0, 33994}, ...}) = 0
times({tms_utime=0, tms_stime=3, tms_cutime=0, tms_cstime=0}) = 429525137
getrusage(RUSAGE_SELF, {ru_utime={0, 3999}, ru_stime={0, 33994}, ...}) = 0
getrusage(RUSAGE_SELF, {ru_utime={0, 3999}, ru_stime={0, 33994}, ...}) = 0
times({tms_utime=0, tms_stime=3, tms_cutime=0, tms_cstime=0}) = 429525137

getrusage システムコールの ru_utime はユーザーモードでCPUを使った時間、ru_stime はカーネルモードで使った時間。おそらく、ru_stime はシステムコールで使った時間で、割込みで使われた時間は含まれなさそうな気がする。
また、機会があればその先を追ってみようと思う。

ru_utime
This is the total amount of time spent executing in user mode, expressed in a timeval structure (seconds plus microseconds).


ru_stime
This is the total amount of time spent executing in kernel mode, expressed in a timeval structure (seconds plus microseconds).

getrusage(2): resource usage - Linux man page

Linux 2.6 では、この行に 3つの欄が追加されている: iowait (I/O の完了を待っていた時間; 2.5.41 以降); irq (割り込み処理を行った時間; 2.6.0-test4 以降); softirq (ソフト割り込みの処理を行った時間; 2.6.0-test4 以降)。

Man page of PROC
  • include/linux/resource.h
#ifndef _LINUX_RESOURCE_H
#define _LINUX_RESOURCE_H

#include <linux/time.h>

struct task_struct;

/*
 * Resource control/accounting header file for linux
 */

/*
 * Definition of struct rusage taken from BSD 4.3 Reno
 * 
 * We don't support all of these yet, but we might as well have them....
 * Otherwise, each time we add new items, programs which depend on this
 * structure will lose.  This reduces the chances of that happening.
 */
#define	RUSAGE_SELF	0
#define	RUSAGE_CHILDREN	(-1)
#define RUSAGE_BOTH	(-2)		/* sys_wait4() uses this */

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 " */
};

struct rlimit {
	unsigned long	rlim_cur;
	unsigned long	rlim_max;
};

#define	PRIO_MIN	(-20)
#define	PRIO_MAX	20

#define	PRIO_PROCESS	0
#define	PRIO_PGRP	1
#define	PRIO_USER	2

/*
 * Limit the stack by to some sane default: root can always
 * increase this limit if needed..  8MB seems reasonable.
 */
#define _STK_LIM	(8*1024*1024)

/*
 * GPG wants 32kB of mlocked memory, to make sure pass phrases
 * and other sensitive information are never written to disk.
 */
#define MLOCK_LIMIT	(8 * PAGE_SIZE)

/*
 * Due to binary compatibility, the actual resource numbers
 * may be different for different linux versions..
 */
#include <asm/resource.h>

int getrusage(struct task_struct *p, int who, struct rusage __user *ru);

#endif
  • kernel/sys.c
/*
 * It would make sense to put struct rusage in the task_struct,
 * except that would make the task_struct be *really big*.  After
 * task_struct gets moved into malloc'ed memory, it would
 * make sense to do this.  It will make moving the rest of the information
 * a lot simpler!  (Which we're not doing right now because we're not
 * measuring them yet).
 *
 * When sampling multiple threads for RUSAGE_SELF, under SMP we might have
 * races with threads incrementing their own counters.  But since word
 * reads are atomic, we either get new values or old values and we don't
 * care which for the sums.  We always take the siglock to protect reading
 * the c* fields from p->signal from races with exit.c updating those
 * fields when reaping, so a sample either gets all the additions of a
 * given child after it's reaped, or none so this sample is before reaping.
 *
 * Locking:
 * We need to take the siglock for CHILDEREN, SELF and BOTH
 * for  the cases current multithreaded, non-current single threaded
 * non-current multithreaded.  Thread traversal is now safe with
 * the siglock held.
 * Strictly speaking, we donot need to take the siglock if we are current and
 * single threaded,  as no one else can take our signal_struct away, no one
 * else can  reap the  children to update signal->c* counters, and no one else
 * can race with the signal-> fields. If we do not take any lock, the
 * signal-> fields could be read out of order while another thread was just
 * exiting. So we should  place a read memory barrier when we avoid the lock.
 * On the writer side,  write memory barrier is implied in  __exit_signal
 * as __exit_signal releases  the siglock spinlock after updating the signal->
 * fields. But we don't do this yet to keep things simple.
 *
 */

static void k_getrusage(struct task_struct *p, int who, struct rusage *r)
{
	struct task_struct *t;
	unsigned long flags;
	cputime_t utime, stime;

	memset((char *) r, 0, sizeof *r);
	utime = stime = cputime_zero;

	rcu_read_lock();
	if (!lock_task_sighand(p, &flags)) {
		rcu_read_unlock();
		return;
	}

	switch (who) {
		case RUSAGE_BOTH:
		case RUSAGE_CHILDREN:
			utime = p->signal->cutime;
			stime = p->signal->cstime;
			r->ru_nvcsw = p->signal->cnvcsw;
			r->ru_nivcsw = p->signal->cnivcsw;
			r->ru_minflt = p->signal->cmin_flt;
			r->ru_majflt = p->signal->cmaj_flt;

			if (who == RUSAGE_CHILDREN)
				break;

		case RUSAGE_SELF:
			utime = cputime_add(utime, p->signal->utime);
			stime = cputime_add(stime, p->signal->stime);
			r->ru_nvcsw += p->signal->nvcsw;
			r->ru_nivcsw += p->signal->nivcsw;
			r->ru_minflt += p->signal->min_flt;
			r->ru_majflt += p->signal->maj_flt;
			t = p;
			do {
				utime = cputime_add(utime, t->utime);
				stime = cputime_add(stime, t->stime);
				r->ru_nvcsw += t->nvcsw;
				r->ru_nivcsw += t->nivcsw;
				r->ru_minflt += t->min_flt;
				r->ru_majflt += t->maj_flt;
				t = next_thread(t);
			} while (t != p);
			break;

		default:
			BUG();
	}

	unlock_task_sighand(p, &flags);
	rcu_read_unlock();

	cputime_to_timeval(utime, &r->ru_utime);
	cputime_to_timeval(stime, &r->ru_stime);
}

int getrusage(struct task_struct *p, int who, struct rusage __user *ru)
{
	struct rusage r;
	k_getrusage(p, who, &r);
	return copy_to_user(ru, &r, sizeof(r)) ? -EFAULT : 0;
}

asmlinkage long sys_getrusage(int who, struct rusage __user *ru)
{
	if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN)
		return -EINVAL;
	return getrusage(current, who, ru);
}

環境は以下の通り

[root@localhost ~]# cat /etc/issue
Enterprise Linux Enterprise Linux Server release 5.5 (Carthage)
Kernel \r on an \m

[root@localhost ~]# uname -a
Linux localhost.localdomain 2.6.18-194.17.1.0.1.el5 #1 SMP Wed Sep 29 15:40:03 EDT 2010 i686 i686 i386 GNU/Linux

SQL> select * from v$version;

BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - Production
PL/SQL Release 11.2.0.2.0 - Production
CORE    11.2.0.2.0      Production
TNS for Linux: Version 11.2.0.2.0 - Production
NLSRTL Version 11.2.0.2.0 - Production