2011-09-13 17:48:33 +00:00
|
|
|
#!/usr/sbin/dtrace -qs
|
|
|
|
/*
|
2012-11-14 20:13:24 +00:00
|
|
|
* Copyright (c) 2011, 2012 Oracle and/or its affiliates. All rights reserved.
|
2011-09-13 17:48:33 +00:00
|
|
|
*
|
|
|
|
* locktimesid.d - Display lock wait times grouped by filename.
|
|
|
|
*
|
|
|
|
* This script graphs the time spent waiting for DB page locks.
|
|
|
|
*
|
|
|
|
* The optional integer maxcount parameter directs the script to exit once that
|
|
|
|
* many page lock waits have been measured.
|
|
|
|
*
|
|
|
|
* usage: locktimes.d { -p <pid> | -c "<program> [<args]" } [maxcount]
|
|
|
|
*
|
|
|
|
* The result times in nanoseconds are grouped by (filename, pgno, lock_mode).
|
|
|
|
*
|
|
|
|
* Static probes used:
|
|
|
|
* lock-suspend(DBT *lockobj, db_lockmode_t lock_ mode)
|
|
|
|
* lock-resume(DBT *lockobj, db_lockmode_t mode)
|
|
|
|
* db-open(char *file, char *db, uint32_t flags, uint8_t fileid[20])
|
|
|
|
* db-cursor(char *file, char *db, unsigned txnid, unsigned flags,
|
|
|
|
* uint8_t fileid[20])
|
|
|
|
*
|
|
|
|
* The DBT locates the locked object in shared memory. As long as
|
|
|
|
* application-specific locks are not being used, the DBT points to
|
|
|
|
* a DB_ILOCK:
|
|
|
|
* db_pgno_t pgno;
|
|
|
|
* u_int8_t fileid[20];
|
|
|
|
* u_int32_t type;
|
|
|
|
* Type is 1 for handle, 2 for page, 3 for a queue's record number.
|
|
|
|
* The mode paramteris the enum db_lockmode_t
|
|
|
|
* notgranted,read,write,wait,iread,iwrite,iwr,read_unc,wwrite
|
|
|
|
*
|
|
|
|
* This script may display unexpected results when application-specific
|
|
|
|
* locks are present.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
#pragma D option defaultargs
|
|
|
|
|
|
|
|
typedef D`uint32_t db_pgno_t;
|
|
|
|
|
|
|
|
/* A DBT for the DB API */
|
|
|
|
typedef struct __db_dbt {
|
|
|
|
uintptr_t data; /* Key/data */
|
|
|
|
uint32_t size; /* key/data length */
|
|
|
|
|
|
|
|
uint32_t ulen; /* RO: length of user buffer. */
|
|
|
|
uint32_t dlen; /* RO: get/put record length. */
|
|
|
|
uint32_t doff; /* RO: get/put record offset. */
|
|
|
|
|
|
|
|
uintptr_t app_data;
|
|
|
|
uint32_t flags;
|
|
|
|
} DBT;
|
|
|
|
|
|
|
|
/* A DBT in shared memory */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* DB fileids are actually uint8_t fileid[20]; in D it is easier to handle them
|
|
|
|
* as a struct of 5 four-byte integers.
|
|
|
|
*/
|
|
|
|
typedef struct fileid
|
|
|
|
{
|
|
|
|
uint32_t id1;
|
|
|
|
uint32_t id2;
|
|
|
|
uint32_t id3;
|
|
|
|
uint32_t id4;
|
|
|
|
uint32_t id5;
|
|
|
|
} FILEID;
|
|
|
|
|
|
|
|
typedef struct __db_ilock {
|
|
|
|
uint32_t pgno;
|
|
|
|
FILEID fileid;
|
|
|
|
uint32_t type;
|
|
|
|
} DB_ILOCK;
|
|
|
|
|
|
|
|
this DBT *dbt;
|
|
|
|
this DB_ILOCK *ilock;
|
|
|
|
this FILEID *fileid;
|
|
|
|
this string filename;
|
|
|
|
|
|
|
|
string filenames[unsigned, unsigned, unsigned, unsigned, unsigned];
|
|
|
|
|
|
|
|
self int suspend;
|
|
|
|
|
|
|
|
dtrace:::BEGIN
|
|
|
|
{
|
|
|
|
maxcount = $1 != 0 ? $1 : -1;
|
|
|
|
lockcount = 0;
|
|
|
|
printf("DB lock wait times by (file, pgno) for process %d\n", $target);
|
|
|
|
printf("Interrupt to display summary\n");
|
|
|
|
modes[0] = "NOTGRANTED";
|
|
|
|
modes[1] = "READ";
|
|
|
|
modes[2] = "WRITE";
|
|
|
|
modes[3] = "WAIT";
|
|
|
|
modes[4] = "INTENT_WRITE";
|
|
|
|
modes[5] = "INTENT_READ";
|
|
|
|
modes[6] = "INTENT_WR";
|
|
|
|
modes[7] = "READ_UNCOMMITTED";
|
|
|
|
modes[8] = "WAS_WRITE";
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* lock-suspend(DBT *lockobj, int lock_mode) */
|
|
|
|
bdb$target:::lock-suspend
|
|
|
|
{
|
|
|
|
self->suspend = timestamp;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* lock-resume(DBT *lockobj, int lock_mode) */
|
|
|
|
bdb$target:::lock-resume
|
|
|
|
/self->suspend > 0/
|
|
|
|
{
|
|
|
|
this->duration = timestamp - self->suspend;
|
|
|
|
self->suspend = 0;
|
|
|
|
this->dbt = copyin(arg0, sizeof(DBT));
|
|
|
|
this->ilock = copyin(this->dbt->data, sizeof(DB_ILOCK));
|
|
|
|
this->filename = filenames[this->ilock->fileid.id1,
|
|
|
|
this->ilock->fileid.id2, this->ilock->fileid.id3,
|
|
|
|
this->ilock->fileid.id4, this->ilock->fileid.id5];
|
|
|
|
@locktimes[this->filename, this->ilock->pgno, modes[arg1]] =
|
|
|
|
quantize(this->duration);
|
|
|
|
lockcount++;
|
|
|
|
}
|
|
|
|
|
|
|
|
bdb$target:::lock-resume
|
|
|
|
/lockcount == maxcount/
|
|
|
|
{
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* db-open(char *file, char *db, uint32_t flags, uint8_t fileid[20])
|
|
|
|
*
|
|
|
|
* Watch db-open probes in order to get the fileid -> file name mapping.
|
|
|
|
*/
|
|
|
|
bdb$target:::db-open
|
|
|
|
/arg0 != 0/
|
|
|
|
{
|
|
|
|
this->filename = copyinstr(arg0);
|
|
|
|
this->fileid = (FILEID *) copyin(arg3, 20);
|
|
|
|
filenames[this->fileid->id1, this->fileid->id2, this->fileid->id3,
|
|
|
|
this->fileid->id4, this->fileid->id5] = this->filename;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* db-cursor(char *file, char *db, unsigned txnid, unsigned flags, uint8_t fileid[20])
|
|
|
|
*
|
|
|
|
* Watch cursor creation probes in order to get the fileid -> file name mapping.
|
|
|
|
*/
|
|
|
|
bdb$target:::db-cursor
|
|
|
|
/arg0 != 0/
|
|
|
|
{
|
|
|
|
this->filename = (string) copyinstr(arg0);
|
|
|
|
this->fileid = (FILEID *) copyin(arg4, 20);
|
|
|
|
filenames[this->fileid->id1, this->fileid->id2, this->fileid->id3,
|
|
|
|
this->fileid->id4, this->fileid->id5] = this->filename;
|
|
|
|
}
|
|
|
|
|
|
|
|
dtrace:::END
|
|
|
|
{
|
|
|
|
printa("Wait time for file %s page %u %s locks in nanoseconds %@a\n", @locktimes);
|
|
|
|
}
|