5 ** This file implements the 'io' subcommand of the test program. It is used
6 ** for testing the performance of various combinations of write() and fsync()
7 ** system calls. All operations occur on a single file, which may or may not
8 ** exist when a test is started.
10 ** A test consists of a series of commands. Each command is either a write
11 ** or an fsync. A write is specified as "<amount>@<offset>", where <amount>
12 ** is the amount of data written, and <offset> is the offset of the file
13 ** to write to. An <amount> or an <offset> is specified as an integer number
14 ** of bytes. Or, if postfixed with a "K", "M" or "G", an integer number of
15 ** KB, MB or GB, respectively. An fsync is simply "S". All commands are
18 ** Example test program:
20 ** 2M@6M 1492K@4M S 4096@4K S
22 ** This program writes 2 MB of data starting at the offset 6MB offset of
23 ** the file, followed by 1492 KB of data written at the 4MB offset of the
24 ** file, followed by a call to fsync(), a write of 4KB of data at byte
25 ** offset 4096, and finally another call to fsync().
27 ** Commands may either be specified on the command line (one command per
28 ** command line argument) or read from stdin. Commands read from stdin
29 ** must be separated by white-space.
31 ** COMMAND LINE INVOCATION
33 ** The sub-command implemented in this file must be invoked with at least
34 ** two arguments - the path to the file to write to and the page-size to
35 ** use for writing. If there are more than two arguments, then each
36 ** subsequent argument is assumed to be a test command. If there are exactly
37 ** two arguments, the test commands are read from stdin.
39 ** A write command does not result in a single call to system call write().
40 ** Instead, the specified region is written sequentially using one or
41 ** more calls to write(), each of which writes not more than one page of
42 ** data. For example, if the page-size is 4KB, the command "2M@6M" results
43 ** in 512 calls to write(), each of which writes 4KB of data.
47 ** Two equivalent examples:
49 ** $ lsmtest io testfile.db 4KB 2M@6M 1492K@4M S 4096@4K S
50 ** 3544K written in 129 ms
51 ** $ echo "2M@6M 1492K@4M S 4096@4K S" | lsmtest io testfile.db 4096
52 ** 3544K written in 127 ms
58 typedef struct IoContext IoContext
;
68 static int safe_isspace(char c
){
76 static int safe_isdigit(char c
){
81 static i64
getNextSize(char *zIn
, char **pzOut
, int *pRc
){
86 if( !safe_isdigit(*z
) ){
92 while( safe_isdigit(*z
) ){
93 iRet
= iRet
*10 + (*z
- '0');
105 iRet
= iRet
* 1024 * 1024;
110 iRet
= iRet
* 1024 * 1024 * 1024;
115 if( pzOut
) *pzOut
= z
;
130 while( safe_isspace(*z
) ) z
++;
134 if( pzOut
) *pzOut
= z
;
138 if( c
=='s' || c
=='S' ){
139 if( pzOut
) *pzOut
= &z
[1];
140 return fdatasync(pCtx
->fd
);
143 if( safe_isdigit(c
) ){
150 nByte
= (int)getNextSize(z
, &z
, &rc
);
151 if( rc
|| *z
!='@' ) goto bad_command
;
153 iOff
= getNextSize(z
, &z
, &rc
);
154 if( rc
|| (safe_isspace(*z
)==0 && *z
!='\0') ) goto bad_command
;
155 if( pzOut
) *pzOut
= z
;
157 nPg
= (nByte
+pgsz
-1) / pgsz
;
158 lseek(pCtx
->fd
, (off_t
)iOff
, SEEK_SET
);
159 for(iPg
=0; iPg
<nPg
; iPg
++){
160 write(pCtx
->fd
, aData
, pgsz
);
162 pCtx
->nWrite
+= nByte
/1024;
168 testPrintError("unrecognized command: %s", zCmd
);
172 static int readStdin(char **pzOut
){
177 while( !feof(stdin
) ){
181 zOut
= realloc(zOut
, nAlloc
);
182 nRead
= fread(&zOut
[nOut
], 1, nAlloc
-nOut
-1, stdin
);
184 if( nRead
==0 ) break;
193 int do_io(int nArg
, char **azArg
){
206 memset(&ctx
, 0, sizeof(IoContext
));
208 testPrintUsage("FILE PGSZ ?CMD-1 ...?");
214 pgsz
= (int)getNextSize(zPgsz
, 0, &rc
);
216 testPrintError("Ridiculous page size: %d", pgsz
);
219 aData
= malloc(pgsz
);
220 memset(aData
, 0x77, pgsz
);
222 ctx
.fd
= open(zFile
, O_RDWR
|O_CREAT
|_O_BINARY
, 0644);
232 while( *z
&& rc
==0 ){
233 rc
= doOneCmd(&ctx
, aData
, pgsz
, z
, &z
);
237 for(i
=2; i
<nArg
; i
++){
238 rc
= doOneCmd(&ctx
, aData
, pgsz
, azArg
[i
], 0);
242 printf("%dK written in %d ms\n", ctx
.nWrite
, testTimeGet());