summaryrefslogtreecommitdiff
path: root/util/dtrace/locktimes.d
blob: 0627c3ed563432c4e416b1b4ca7732487c30e9bd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#!/usr/sbin/dtrace -qs
/*
 * Copyright (c) 2012, 2015 Oracle and/or its affiliates.  All rights reserved.
 * 
 * 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);
}