此文摘自 developers.sun.com 写的很精采, 我自己试用了一下, 性能果然有所提高
|
| developers.sun.com | | | | | | | | 
---|---|---|---|---|---|---|---|---|---
| |
|
|
![]() |
|---|
Technical Articles & Tips
Cache OCI Calls to Improve Performance of 32-Bit or 64-Bit Oracle Clients
| By Nagendra Nagarajayya, October 2003 |
|---|
Contents:
Introduction
Identifying the Problem
The Workaround: Cache
oraus.msbin MemoryBuilding
cache_oraus.soHow to Use
cache_oraus.soHow the Caching Works
6.1 Interposition of theopen()Function Call
6.2 Interposition of thefcntl()Function Call
6.3 Interposition of thelseek(),read(), andclose()Function CallsPerformance Improvement
7.1 WithoutLD_PRELOADandcache_oraus.so
7.2 WithLD_PRELOADandcache_oraus.soCaveat
Conclusion
Acknowledgments
References
A. Appendix: Test Programs and Wrappers
A1. README
A2. cache_oraus.c
A3. test.c
A4. test.sh
A5. test1.sh
A6. test_v.c
A7. test_v.sh
A8. c.sh
A9. c64.sh
A10. Cache_open_calls.c
1. Introduction
If you work with Oracle clients that make use of OCI (Oracle Call Interface), you may have noticed that the OCI driver in 8.1.7.x makes thousands of calls to translate messages from the oraus.msb file. This can degrade application performance by 5 percent or more (quite severely in some cases). This problem has been documented by Oracle under bug ID 2142623.
The problem can be overcome by caching the oraus.msb file in memory, and translating the file access and system calls to user calls and memory operations. The caching solution is dynamic, and code changes are not needed. The solution can improve the performance of the Oracle client application. Recently, this solution resulted in bringing down the application runtime from 15 minutes to a few seconds at a major customer – about 100x times performance improvement.
The performance benefits can be seen in applications like sqlplus and Oracle clients (C and C++) making use of the OCI driver. Java technology-based applications using JDBC (native driver) should also see similar benefits.
2. Identifying the Problem
An Oracle client application can be trussed on the Solaris Operating System (OS) to see the calls being made to this file -- "truss" is a system utility available on the Solaris platform, and it can be used to trace system calls made by an application. A running Oracle client application can be trussed as follows:
truss -p [oracle client pid]
The truss command will show all the system calls being made by the application. The ones of interest are the open() , fcntl() , lseek() , read() , and close() calls. These calls are made by the OCI driver repeatedly to translate messages. Here is a truss snippet showing the problem calls:
open("/oracle/app/oracle/product/8.1.7/rdbms/mesg/oraus.msb", O_RDONLY) = 9
fcntl(9, F_SETFD, 0x00000001) = 0
lseek(9, 0, SEEK_SET) = 0
read(9, "1513 "011303\t\t\0\0\0\0".., 256) = 256
lseek(9, 512, SEEK_SET) = 512
read(9, "1C88 Y r ~ M\0\0\0\0\0\0".., 512) = 512
lseek(9, 1024, SEEK_SET) = 1024
read(9, "\018\0 $\0 7\0 @\0 J\0 V".., 512) = 512
lseek(9, 39936, SEEK_SET) = 39936
read(9, "\0\t0519\0\0\0 >051A\0\0".., 512) = 512
close(9) = 0
These system calls can be expensive. The number of times these system calls are executed depends on the client application and the duration of the application run.
3. The Workaround: Cache oraus.msb in Memory
The workaround is to cache the contents of the oraus.msb in memory and not make these system calls. This can be done dynamically by using the LD_PRELOAD technique available on the Solaris OE. (For further information, see the References section.) LD_PRELOAD is an environment variable on Solaris that allows shared libraries to be preloaded before an application begins execution. To make use of this technique, we need to build a shared library that will interpose on the open() , fcntl() , lseek() , read() , and close() calls.
4. Building cache_oraus.so
The shared library can be built with the Forte C compiler (now part of the Sun ONE Compiler Collection) using the following switches:
32-bit:
cc -G -o cache_oraus.so -fast cache_oraus.c -l dl
64-bit:
cc -G -o cache_oraus.so -fast -xarch=v9a cache_oraus.c -l dl
5. How to Use cache_oraus.so
The following environment variables need to be set to use the caching mechanism:
export LD_PRELOAD=./cache_oraus.so
export oraus_msb_file=/ora/app/oracle/product/8.1.7/rdbms/mesg/oraus.msb
This can be set in a shell script used to start the client application.
6. How the Caching Works
The caching works by interposing the open() , fcntl() , lseek() , read() , and close() calls. The first time the application executes one of these calls, the control is first transferred to the interposed function code.
6.1 Interposition of the open() Function Call
Whenever a file is opened, the control is transferred to the interposed open() from cache_oraus.so . The interposed open() checks to see if the file being opened is the oraus.msb (see STEP 3 in the following code example). If so, the file is opened, and memory mapped (STEP 5.1). The descriptor returned by open() is also cached. For all other opens, the control is transferred to the original libc.so (STEP 7).
int open(const char *path, int oflag, mode_t mode) {
static int(*fptr)() = 0;
static char* msb_path;
STEP 1
if (fptr == 0) {
fptr = (int (*)())dlsym(RTLD_NEXT, "open");
if (fptr == NULL) {
fprintf(stderr, "dlopen: %s \n", dlerror());
return 0;
}
STEP 1.1
msb_path = (char*)getenv("oraus_msb_file");
}
STEP 2
if (!msb_path) {
msb_path = "/oracle/app/oracle/product/8.1.7/rdbms/mesg/oraus.msb";
}
STEP 3
if (strcmp(path, msb_path) == 0) {
STEP 4
if (k_bm_fd == -1) {
k_bm_fd = ((*fptr)(path, oflag, mode));
if (k_bm_fd <= 0) {
perror(path);
exit(1);
}
STEP 5
fstat(k_bm_fd, &k_bm_stat_buf);
STEP 5.1
k_bm_buf = (char*)mmap((caddr_t) 0,
k_bm_stat_buf.st_size, (PROT_READ),
MAP_SHARED, k_bm_fd, 0);
assert(k_bm_buf != MAP_FAILED);
return k_bm_fd;
} else {
STEP 6
return k_bm_fd;
}
}
STEP 7
return ((*fptr)(path, oflag, mode));
}
| STEPS | Description |
|---|---|
| 1 | Use dlysym() to get a pointer to the original libc.so open() call, so that we can chain to it. |
| 1.1 | We use an environment variable, oraus_msb_file , to find the location of the oraus.msb file. |
| 2 | If this variable is not set, we use a default path. |
| 3 | We make sure the open call is related to the oraus_msb_file . For all other open calls, we chain to the original open() call. |
| 4 | We make sure this is the first time we are going through this code path as we want to map the file into memory only once. We open the file and cache the returned descriptor in k_bm_fd . |
| 5 | We get some information about the file itself, such as size. |
| 5.1 | The most important step: we map the file into memory. |
| 6 | We have already opened the file, and we return the cache descriptor. |
| 7 | For all other opens, the interpose gives control back to the original libc.so open() call. |
**Table 1:open() Call **
6.2 Interposition of the fcntl() Function Call
A fcntl() call is made to change the file control parameters. The first time fcntl() is executed to change oraus.msb control parameters, the control is first transferred to the fcntl() in libc.so . The return value is cached, as well as returned back to the Oracle client (STEP 2). The next time fcntl() is executed, if the file descriptor matches the oraus.msb file descriptor, the cached return value is returned (STEP 3). The control is not transferred to fcntl() in libc.so .
int fcntl(int fildes, int cmd, int arg) {
static int ret;
static int(*fptr)() = 0;
char* path;
STEP 1
if (fptr == 0) {
fptr = (int (*)())dlsym(RTLD_NEXT, "fcntl");
if (fptr == NULL) {
fprintf(stderr, "dlopen: %s \n", dlerror());
return 0;
}
}
STEP 2
if (k_fcntl_bm_fd == -1) {
if (fildes == k_bm_fd) {
ret = ((*fptr)(fildes, cmd, arg));
k_fcntl_bm_fd = k_bm_fd;
return ret;;
}
STEP 3
} else if (k_fcntl_bm_fd == fildes) {
return ret;
}
STEP 4
return ((*fptr)(fildes, cmd, arg));
}
| STEPS | Description |
|---|---|
| 1 | Use dlysym() to get a pointer to the original libc.so fcntl() call, so that we can chain to it. |
| 2 | We make sure this is the first time we are going through this code path as we want to execute fcntl() only once. We also make a copy of the open descriptor in k_fcntl_bm_fd . |
| 3 | If the fildes is equal to k_fcntl_bm_fd , then we just return the cached return value. |
| 4 | For all other opens, the interpose gives control back to the original libc.so fcntl() call. |
**Table 2:fcntl() Call **
Back to Top
6.3 Interposition of the lseek() , read() , and close() Function Calls
For the lseek() call, if the file descriptor matches the cached oraus.msb file descriptor, the file offset is stored instead of calling the lseek() in libc.so (STEP L2). On a read() call, if the file descriptor matches the cached oraus.msb file descriptor, the file offset stored from the lseek() is used to index into the memory mapped oraus.msb data. A memcpy() is then executed (STEP R2). So an I/O call is now transformed to a simple memcpy() call. A close() on the cached file descriptor is ignored so that the cached file descriptor can be reused.
off_t lseek(int fildes, off_t offset, int whence) {
static off_t (*fptr)() = 0;
STEP L1
if (fptr == 0) {
fptr = (int (*)())dlsym(RTLD_NEXT, "lseek");
if (fptr == NULL) {
fprintf(stderr, "dlopen: %s \n", dlerror());
return 0;
}
}
STEP L2
if (fildes == k_bm_fd) {
k_bm_offset = offset;
return offset;
}
STEP L3
return ((*fptr)(fildes, offset, whence));
}
| STEPS | Description |
|---|---|
| L1 | Use dlysym() to get a pointer to the original libc.so lseek() call, so that we can chain to it. |
| L2 | If the fildes is equal to k_bm_fd , then we keep track of the k_bm_offset so that we access this memory location. |
| L3 | For all other opens, the interpose gives control back to the original libc.so lseek() call. |
**Table 3:lseek() Call **
ssize_t read(int fildes, void *buf, size_t nbyte) {
static ssize_t (*fptr)() = 0;
STEP R1
if (fptr == 0) {
fptr = (ssize_t (*)())dlsym(RTLD_NEXT, "read");
if (fptr == NULL) {
fprintf(stderr, "dlopen: %s\n", dlerror());
return (0);
}
}
STEP R2
if (fildes == k_bm_fd) {
memcpy(buf, k_bm_buf+k_bm_offset, nbyte);
return nbyte;
}
STEP R3
return ((*fptr)(fildes, buf, nbyte));
}
| STEPS | Description |
|---|---|
| R1 | Use dlysym() to get a pointer to the original libc.so read() call, so that we can chain to it. |
| R2 | If the fildes is equal to k_bm_fd , then we use the stored k_bm_offset to access the right memory location, and do a memcpy() . |
| R3 | For all other opens, the interpose gives control back to the original libc.so read() call. |
**Table 4:read() Call **
int close(int fildes) {
static int(*fptr)() = 0;
STEP C1
if (fptr == 0) {
fptr = (int (*)())dlsym(RTLD_NEXT, "close");
if (fptr == NULL) {
fprintf(stderr, "dlopen: %s \n", dlerror());
return 0;
}
}
STEP C2
if (fildes == k_bm_fd) {
return 0;
}
STEP C3
return ((*fptr)(fildes));
}
| STEPS | Description |
|---|---|
| C1 | Use dlysym() to get a pointer to the original libc.so close() call, so that we can chain to it. |
| C2 | If the fildes is equal to k_bm_fd , then we justreturn 0 to signal a successful close, but without closing the file. |
| C3 | For all other opens, the interpose gives control back to the original libc.so close() call. |
**Table 5:close() Call **
Back to Top
7. Performance Improvement
The performance improvement comes from not executing the system calls. The multiple instances of open() , fcntl() , lseek() , read() , and close() to read the oraus.msb messages are transformed to user-level calls. Also, the I/O operation becomes a simple memory-to-memory transfer.
To measure the performance gains, a test program mimicking an Oracle client's behavior was developed. The test program performs open() , lseek() , read() , and close() calls on the oraus.msb file 50,000 times.
The test program showed a gain of about 1000%. However, in a real Oracle client application, this might translate to about a 2 percent-to-15 percent gain in performance.
7.1 Without LD_PRELOAD and cache_oraus.so
| Type | Time in Seconds |
|---|---|
| Real | 5.633 |
| User | 0.010 |
| Sys | 0.014 |
**Table 6:ptime test.sh **
Back to Top
7.2 With LD_PRELOAD and cache_oraus.so
| Type | Time in Seconds |
|---|---|
| Real | 0.462 |
| User | 0.010 |
| Sys | 0.013 |
**Table 7:ptime test.sh **
8. Caveat
The preceding code is not multithreaded. For Oracle clients that are multithreaded, the write access to the cache variables needs to be mutex protected or synchronized.
9. Conclusion
Caching the file oraus.msb in memory improves the performance of Oracle clients. Even though the performance gain observed in the test program is about 1000 percent, the gain when running a really big Oracle client application might not be more than 2 to 15 percent, due to other I/O contentions. This gain can be achieved without any code changes to the client application.
10. Acknowledgments
I would like to thank Teresa Riege (Sun) and Thomas Yen (Kenan/BP billing platform, CSG Systems) for their contributions and help in testing this utility during the 2002 Kenan/BP study (see related article listed in References). I would also like to thank my colleagues at MDE (IPE) for supporting me during this project.
I would like also to thank Ben Humphreys, technical support specialist, Sun, who made the 64-bit modifications to the code.
11. References
- Nagendra Nagarajayya, S.R. Venkatramanan, " Fast Sockets, An Interprocess Communication Library to Boost Application Performance "
- Sun Product Documentation site
- Oracle MetaLink (for news, problems, and bugs)
- CSG Kenan/BP Exceeds Billing Needs of Largest Telecom Service Providers in Scalability Test
Appendix: Test Programs and Wrappers
The Sample Code is being made available by Sun merely as a convenience to you. The Sample Code below is provided "AS IS." Sun makes no warranties of any kind whatsoever with respect to the Sample Code.
ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY WARRANTY OF NON-INFRINGEMENT OR IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE HEREBY DISCLAIMED AND EXCLUDED TO THE EXTENT ALLOWED BY APPLICABLE LAW. IN NO EVENT WILL SUN BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, SPECIAL, INDIRECT, CONSEQUENTIAL, INCIDENTAL, OR PUNITIVE DAMAGES HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY ARISING OUT OF THE USE OF OR INABILITY TO USE THE SAMPLE CODE, EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
A1. README
*
* Oct 02, 03
* Nagendra Nagarajayya
* MDE/IPE(CSI)
* Sun Microsystems, Inc
*
set LD_PRELOAD within a wrapper to cache_oraus.so, and specify
the path to the oraus.msb file using the ENV variable, "oraus_msb_file".
If the env is not specified, the following path is used,
/oracle/app/oracle/product/8.1.7/rdbms/mesg/oraus.msb.
WARNING:
The solution presented does not support multi-threaded clients, but should be
very easy to do so. BTW, it could work as it is with MT threaded clients, but
has not been tested.
Example:
export LD_PRELOAD=./cache_oraus.so
export oraus_msb_file=/ora/app/oracle/product/8.1.7/rdbms/mesg/oraus.msb
Note:
cache_open_calls.c is similar to cache_oraus.c but caches only the open calls.
It does not memory map the oraus.msb file.
Compilation instructions:
-------------------------
Use the wrapper c.sh to compile cache_oraus.c. c.sh also compiles cache_open_calls.c,
and the test programs. Use c64.sh to compile cache_oraus.c for 64 bit support.
To test the library:
--------------------
Use, ptime test.sh, and ptime test1.sh.
To verify if the library is reading the contents properly,
use test_v.sh, and test_v.c
A2. Cache_oraus.c
/*
Date: April 18, 2002
Author: Nagendra Nagarajayya
MDE/IPE/CSI
Sun Microsystems, Inc.
Date: October 02, 2003
Ben Humphreys
Technical Support Specialist
Sun Microsystems, Inc.
Descr: made changes to source for 64 bit support
Description: This caches oraus.msb file in memory and transforms I/O calls
to the file to a read access.
*/
/*
The Sample Code is being made available by Sun merely as a convenience to you.
The Sample Code below is provided "AS IS." Sun makes no warranties of any kind
whatsoever with respect to the Sample Code. ALL EXPRESS OR IMPLIED CONDITIONS,
REPRESENTATIONS AND WARRANTIES, INCLUDING ANY WARRANTY OF NON-INFRINGEMENT OR
IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE
HEREBY DISCLAIMED AND EXCLUDED TO THE EXTENT ALLOWED BY APPLICABLE LAW. IN NO
EVENT WILL SUN BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
SPECIAL, INDIRECT, CONSEQUENTIAL, INCIDENTAL, OR PUNITIVE DAMAGES HOWEVER CAUSED
AND REGARDLESS OF THE THEORY OF LIABILITY ARISING OUT OF THE USE OF OR INABILITY
TO USE THE SAMPLE CODE, EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#include
1<stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <dlfcn.h>
6 #include <sys types.h="">
7 #include <sys stat.h="">
8 #include <assert.h>
9 #include <sys mman.h="">
10 #include <sys int_types.h="">
11 static int k_fcntl_bm_fd = -1;
12 static int k_bm_fd = -1;
13 static int k_bm_offset = 0;
14 static char* k_bm_buf ;
15 static struct stat k_bm_stat_buf ;
16 int fcntl(int fildes, int cmd, intptr_t arg) {
17 static int ret;
18 static ssize_t(*fptr)() = 0;
19 char* path;
20 if (fptr == 0) {
21 fptr = (ssize_t (*)())dlsym(RTLD_NXT, "fcntl");
22 if (fptr == NULL) {
23 fprintf(stderr, "dlopen: %s \n", dlerror());
24 return 0;
25 }
26 }
27 if (k_fcntl_bm_fd == -1) {
28 if (fildes == k_bm_fd) {
29 ret = ((*fptr)(fildes, cmd, arg));
30 k_fcntl_bm_fd = k_bm_fd;
31 return ret;;
32 }
33 } else if (k_fcntl_bm_fd == fildes) {
34 return ret;
35 }
36 return ((*fptr)(fildes, cmd, arg));
37 }
38 off_t lseek(int fildes, off_t offset, int whence) {
39 static off_t(*fptr)() = 0;
40 if (fptr == 0) {
41 fptr = (off_t (*)())dlsym(RTLD_NEXT, "lseek");
42 if (fptr == NULL) {
43 fprintf(stderr, "dlopen: %s \n", dlerror());
44 return 0;
45 }
46 }
47 if (fildes == k_bm_fd) {
48 k_bm_offset = offset;
49 return offset;
50 }
51 /* fprintf(stderr, "offset=%d k_bm_offset=%d\n", offset, k_bm_offset);
52 */
53 return ((*fptr)(fildes, offset, whence));
54 }
55 ssize_t read(int fildes, void *buf, size_t nbyte) {
56 static ssize_t(*fptr)() = 0;
57 if (fptr == 0) {
58 fptr = (ssize_t (*)())dlsym(RTLD_NEXT, "read");
59 if (fptr == NULL) {
60 fprintf(stderr, "dlopen: %s\n", dlerror());
61 return (0);
62 }
63 }
64 /* fprintf(stderr, "fildes = %d k_bm_fd = %d \n", fildes, k_bm_fd);
65 */
66 if (fildes == k_bm_fd) {
67 memcpy(buf, k_bm_buf+k_bm_offset, nbyte);
68 return nbyte;
69 }
70 return ((*fptr)(fildes, buf, nbyte));
71 }
72
73 int open(const char *path, int oflag, mode_t mode) {
74
75 static char* msb_path;
76 static int(*fptr)() = 0;
77 if (fptr == 0) {
78 fptr = (int (*)())dlsym(RTLD_NEXT, "open");
79 if (fptr == NULL) {
80 fprintf(stderr, "dlopen: %s \n", dlerror());
81 return 0;
82 }
83 msb_path = (char*)getenv("oraus_msb_file");
84 }
85 if (!msb_path) {
86 msb_path = "/oracle/app/oracle/product/8.1.7/rdbms/mesg/oraus.msb";
87 }
88 if (strcmp(path, msb_path) == 0) {
89 if (k_bm_fd == -1) {
90 k_bm_fd = ((*fptr)(path, oflag, mode));
91 if (k_bm_fd <= 0) {
92 perror(path);
93 exit(1);
94 }
95
96 fstat(k_bm_fd, &k_bm_stat_buf);
97 /*
98 fprintf(stderr, "open the file %d\n",k_bm_fd);
99 */
100 k_bm_buf = (char*)mmap((caddr_t) 0,
101 k_bm_stat_buf.st_size, (PROT_READ),
102 MAP_SHARED, k_bm_fd, 0);
103 assert(k_bm_buf != MAP_FAILED);
104 return k_bm_fd;
105 } else {
106 /* fprintf(stderr, "re-open the file %d\n",k_bm_fd);
107 */
108 return k_bm_fd;
109 }
110 }
111 return ((*fptr)(path, oflag, mode));
112 }
113 int close(int fildes) {
114 static int(*fptr)() = 0;
115
116 if (fptr == 0) {
117 fptr = (int (*)())dlsym(RTLD_NEXT, "close");
118 if (fptr == NULL) {
119 fprintf(stderr, "dlopen: %s \n", dlerror());
120 return 0;
121 }
122 }
123 if (fildes == k_bm_fd) {
124 /* fprintf(stderr, "close the file %d\n",k_bm_fd);
125 */
126 return 0;
127 }
128 return ((*fptr)(fildes));
129 }
130 See README file for details on how to compile this program, and the
131 environment needed to execute the Oracle client program. Appendixes
132 A3-A6 explain a little more about the test programs.
133
134
135#### A3. test.c
136
137This test program reads the ` oraus.msb ` file 50,000 times to mimic Oracle client application behavior.
138
139
140 #include <stdio.h>
141 #include <unistd.h>
142 #include <sys types.h="">
143 #include <sys stat.h="">
144 #include <fcntl.h>
145 #include <string.h>
146 int fd = 0;
147 int fd1 = 0;
148 char buf[1024];
149 char buf1[1024];
150 int x1 = 0;
151 int x2 = 0;
152 int x3 = 0;
153 int x4 = 0;
154 int x5 = 0;
155 int main() {
156 int i;
157 int r=-1;
158 for (i=0; i<50000; i++) {
159 fd = open("/ora/app/oracle/product/8.1.7/rdbms/mesg/oraus.msb", O_RDONLY);
160 /* fd1 = open("/oracle/app/oracle/product/8.1.7/rdbms/mesg/oraus.msb_1", O_RDONLY);
161 */
162 /* fprintf(stderr, "fd = %d fd1 = %d \n", fd, fd1);
163 */
164 r = fcntl(fd, F_SETFD);
165 lseek(fd, 0, SEEK_SET);
166 read(fd, &buf, 256);
167 /*
168 r = fcntl(fd1, F_SETFD);
169 lseek(fd1, 0, SEEK_SET);
170 read(fd1, &buf1, 256);
171 x1 = memcmp(&buf1, &buf, 256);
172 if (x1 != 0 ) {
173 fprintf(stderr, "x1 did not mach %d\n", x1);
174 }
175 */
176 lseek(fd, 512, SEEK_SET);
177 read(fd, &buf, 512);
178 /*
179 lseek(fd1, 512, SEEK_SET);
180 read(fd1, &buf1, 512);
181 x2 = memcmp(&buf1, &buf, 512);
182 if (x2 != 0 ) {
183 fprintf(stderr, "x2 did not mach %d \n", x2);
184 }
185 */
186 lseek(fd, 1024, SEEK_SET);
187 read(fd, &buf, 512);
188 /*
189 lseek(fd1, 1024, SEEK_SET);
190 read(fd1, &buf1, 512);
191 x3 = memcmp(&buf1, &buf, 512);
192 if (x3 != 0 ) {
193 fprintf(stderr, "x3 did not mach \n");
194 }
195 */
196 lseek(fd, 39936, SEEK_SET);
197 read(fd, &buf, 512);
198 /*
199 lseek(fd1, 39936, SEEK_SET);
200 read(fd1, &buf1, 512);
201 x4 = memcmp(&buf1, &buf, 512);
202 if (x4 != 0 ) {
203 fprintf(stderr, "x4 did not mach \n");
204 }
205 */
206 close(fd);
207 /*
208 close(fd1);
209 */
210 }
211
212 }
213
214
215#### A4. test.sh
216
217This is a wrapper to execute the test program to show the performance gains of caching the contents of ` oraus.msb ` in memory. The ` LD_PRELOAD ` and ` oraus_msb_file ` environment variables point to ` cache_oraus.so ` and the ` oraus.msb ` file.
218
219
220 #!/bin/bash
221 export oraus_msb_file=/ora/app/oracle/product/8.1.7/rdbms/mesg/oraus.msb
222 export LD_PRELOAD=/usr/lib/cache_oraus.so
223 export LD_PRELOAD=./cache_oraus.so
224 time ./test
225
226
227#### A5. test1.sh
228
229This is a wrapper to execute the test program without the caching mechanism.
230
231
232 #!/bin/bash
233 time ./test
234
235
236#### A6. test_v.c
237
238This program was used to verify that the interposed calls work properly.
239
240
241 #include <stdio.h>
242 #include <unistd.h>
243 #include <sys types.h="">
244 #include <sys stat.h="">
245 #include <fcntl.h>
246 #include <string.h>
247 int fd = 0;
248 int fd1 = 0;
249 char buf[1024];
250 char buf1[1024];
251 int x1 = 0;
252 int x2 = 0;
253 int x3 = 0;
254 int x4 = 0;
255 int x5 = 0;
256 int main() {
257 int i;
258 int r=-1;
259 for (i=0; i<50000; i++) {
260 fd = open("/ora/app/oracle/product/8.1.7/rdbms/mesg/oraus.msb", O_RDONLY);
261 fd1 = open("/ora/app/oracle/product/8.1.7/rdbms/mesg/oraus.msb_1", O_RDONLY);
262 /* fprintf(stderr, "fd = %d fd1 = %d \n", fd, fd1);
263 */
264 r = fcntl(fd, F_SETFD);
265 lseek(fd, 0, SEEK_SET);
266 read(fd, &buf, 256);
267 r = fcntl(fd1, F_SETFD);
268 lseek(fd1, 0, SEEK_SET);
269 read(fd1, &buf1, 256);
270 x1 = memcmp(&buf1, &buf, 256);
271 if (x1 != 0 ) {
272 fprintf(stderr, "x1 did not mach %d\n", x1);
273 }
274 lseek(fd, 512, SEEK_SET);
275 read(fd, &buf, 512);
276 lseek(fd1, 512, SEEK_SET);
277 read(fd1, &buf1, 512);
278 x2 = memcmp(&buf1, &buf, 512);
279 if (x2 != 0 ) {
280 fprintf(stderr, "x2 did not mach %d \n", x2);
281 }
282 lseek(fd, 1024, SEEK_SET);
283 read(fd, &buf, 512);
284 lseek(fd1, 1024, SEEK_SET);
285 read(fd1, &buf1, 512);
286 x3 = memcmp(&buf1, &buf, 512);
287 if (x3 != 0 ) {
288 fprintf(stderr, "x3 did not mach \n");
289 }
290 lseek(fd, 39936, SEEK_SET);
291 read(fd, &buf, 512);
292 lseek(fd1, 39936, SEEK_SET);
293 read(fd1, &buf1, 512);
294 x4 = memcmp(&buf1, &buf, 512);
295 if (x4 != 0 ) {
296 fprintf(stderr, "x4 did not mach \n");
297 }
298 close(fd);
299 close(fd1);
300 }
301
302 }
303
304
305#### A7. test_v.sh
306
307This is a wrapper for testing ` test_v.c ` .
308
309
310 #!/bin/bash
311 export LD_PRELOAD=/usr/lib/cache_oraus.so
312 export LD_PRELOAD=./cache_oraus.so
313 time ./test_v
314
315
316#### A8. c.sh
317
318
319 #!/bin/bash
320 PATH=/opt/SUNWspro/bin/:$PATH
321 export PATH;
322 cc -fast -xarch=v8plusa -xdepend -xvector -xstrconst -xprefetch -G -o
323 cache_open_calls.so cache_open_calls.c -ldl
324 cc -fast -xdepend -xvector -xstrconst -xarch=v8plusa -xprefetch -G -o
325 cache_oraus.so cache_oraus.c -ldl
326 cc -fast -xstrconst -xvector -xdepend -xarch=v8plusa -xprefetch -o
327 test test.c -ldl
328 cc -fast -xstrconst -xvector -xdepend -xarch=v8plusa -xprefetch -o
329 test_v test_v.c -ldl
330
331
332#### A9. c64.sh
333
334
335 #!/bin/bash
336 # Changes to source cache_oraus.c for 64 bit support was made
337 # by Ben Humphreys
338 PATH=/opt/SUNWspro/bin/:$PATH
339 export PATH;
340 cc -fast -xarch=v9a -xcode=abs64 -xdepend -xvector -xstrconst -xprefetch -G -o
341 cache_open_calls.so cache_open_calls.c -ldl
342 cc -fast -xarch=v9a -xcode=abs64 -xdepend -xvector -xstrconst -xprefetch -G -o
343 cache_oraus.so cache_oraus.c -ldl
344 cc -fast -xarch=v9a -xcode=abs64 -xstrconst -xvector -xdepend -xprefetch -o
345 test test.c -ldl
346 cc -fast -xarch=v9a -xcode=abs64 -xstrconst -xvector -xdepend -xprefetch -o
347 test_v test_v.c -ldl
348
349
350< name=A10>
351
352#### A10. Cache_open_calls.c
353
354
355 /*
356 Date: April 18, 02
357 Author: Nagendra Nagarajayya
358 Description: Caches open, and close calls to oraus.msb file
359 */
360 #include <stdio.h>
361 #include <unistd.h>
362 #include <dlfcn.h>
363 #include <string.h>
364 #include <stdlib.h>
365 static int k_bm_fd = -1;
366 int open(const char *path, int oflag, mode_t mode) {
367 static int (*fptr)() = 0;
368 if (fptr == 0) {
369 fptr = (int (*)())dlsym(RTLD_NEXT, "open");
370 if (fptr == NULL) {
371 fprintf(stderr, "dlopen: %s \n", dlerror());
372 return 0;
373 }
374 }
375 if (strcmp(path, "/oracle/app/oracle/product/8.1.7/rdbms/mesg/oraus.msb") == 0) {
376 if (k_bm_fd == -1) {
377 k_bm_fd = ((*fptr)(path, oflag, mode));
378 if (k_bm_fd <= 0) {
379 perror(path);
380 exit(1);
381 }
382
383 /* fstat(k_bm_fd, &k_bm_stat_buf);
384 fprintf(stderr, "open the file %d\n",k_bm_fd);
385 */
386 return k_bm_fd;
387 } else {
388 /* fprintf(stderr, "re-open the file %d\n",k_bm_fd);
389 */
390 return k_bm_fd;
391 }
392 }
393 return ((*fptr)(path, oflag, mode));
394 }
395 int close(int fildes) {
396 static int (*fptr)() = 0;
397 if (fptr == 0) {
398 fptr = (int (*)())dlsym(RTLD_NEXT, "close");
399 if (fptr == NULL) {
400 fprintf(stderr, "dlopen: %s \n", dlerror());
401 return 0;
402 }
403 }
404 if (fildes == k_bm_fd) {
405 /* fprintf(stderr, "close the file %d\n",k_bm_fd);
406 */
407 return 0;
408 }
409 return ((*fptr)(fildes));
410 }
411
412
413### About the Author
414
415Nagendra Nagarajayya has been at Sun for more than 9 years. A Staff Engineer in Market Development Engineering (MDE/IPE), he works with telco ISVs on architecture, performance tuning, sizing and scaling, benchmarking, porting, and so on. His interests include multithreading, concurrency and parallelism, HA, distributed computing, networking, and the Java and Solaris platforms.</stdlib.h></string.h></dlfcn.h></unistd.h></stdio.h></string.h></fcntl.h></sys></sys></unistd.h></stdio.h></string.h></fcntl.h></sys></sys></unistd.h></stdio.h></sys></sys></assert.h></sys></sys></dlfcn.h></unistd.h></string.h></stdlib.h></stdio.h>