source: rtems/cpukit/libfs/src/nfsclient/src/nfsTest.c @ f0266e1

4.104.115
Last change on this file since f0266e1 was f0266e1, checked in by Joel Sherrill <joel.sherrill@…>, on 08/10/09 at 16:10:37

2009-08-10 Joel Sherrill <joel.sherrill@…>

  • libcsupport/src/times.c, libfs/src/nfsclient/src/nfsTest.c, libfs/src/nfsclient/src/rpcio.c: Convert calls to legacy routine rtems_clock_get( RTEMS_CLOCK_GET_xxx, ..) to rtems_clock_get_xxx().
  • Property mode set to 100644
File size: 10.3 KB
Line 
1/* $Id$ */
2
3/* Test program for evaluating NFS read throughput */
4
5/* Author: Till Straumann <strauman@slac.stanford.edu>, 2006 */
6
7/* This test code allows for evaluating NFS read performance
8 * under various scenarios:
9 *  - synchronous reads with various buffer sizes (select
10 *    'num_readers' == 0, see below).
11 *  - pseudo 'read-ahead' using multiple threads that issue
12 *    NFS reads from the same file (but from different offsets)
13 *    in parallel.
14 *    Rationale: each NFS read request is synchronous, i.e., the
15 *    caller sends a request to the server and waits for the
16 *    reply to come back. Performance enhancement can be expected
17 *    by requesting multiple blocks in parallel rather than
18 *    sequentially.
19 *
20 * rtems_interval
21 * nfsTestRead(char *file_name, int chunk_size, int num_readers);
22 *
23 * 1) creates 'num_readers' threads, each opening 'file_name' for
24 *    reading on a separate file descriptor.
25 * 2) creates message queues for communicating with reader threads
26 *
27 * 3) read file using nfsTestReadBigbuf() until EOF is reached
28 *
29 * 4) releases resources.
30 *
31 * RETURNS: Time elapsed during step 3 in ms. This is measured
32 *          using the system clock so make sure the test file
33 *          is big enough.
34 *
35 * nfsTestReadBigbuf() synchronously reads a block of
36 * 'num_readers * chunk_size' (which may be bigger than
37 * the UDP limit of 8k) using 'num_reader' threads to
38 * retrieve the various pieces of the big block in parallel.
39 * This speeds up things since several RPC calls can
40 * be in the works at once.
41 *
42 * NOTES:
43 *  - if 'num_readers' == 0 this corresponds to an 'ordinary'
44 *    NFS read. 'num_readers' == 1 schedules a single reader
45 *    thread (== ordinary NFS read + message passing overhead).
46 *  - no actual processing on the data is done; they are simply
47 *    thrown away. A real, performance-critical application could
48 *    pipeline 'reader' and 'cruncher' threads.
49 *  - read is not completely asynchronous; synchronization is still
50 *    performed at 'big block' boundaries (num_readers * chunk_size).
51 */
52
53/*
54 * Authorship
55 * ----------
56 * This software (NFS-2 client implementation for RTEMS) was created by
57 *     Till Straumann <strauman@slac.stanford.edu>, 2002-2007,
58 *         Stanford Linear Accelerator Center, Stanford University.
59 *
60 * Acknowledgement of sponsorship
61 * ------------------------------
62 * The NFS-2 client implementation for RTEMS was produced by
63 *     the Stanford Linear Accelerator Center, Stanford University,
64 *         under Contract DE-AC03-76SFO0515 with the Department of Energy.
65 *
66 * Government disclaimer of liability
67 * ----------------------------------
68 * Neither the United States nor the United States Department of Energy,
69 * nor any of their employees, makes any warranty, express or implied, or
70 * assumes any legal liability or responsibility for the accuracy,
71 * completeness, or usefulness of any data, apparatus, product, or process
72 * disclosed, or represents that its use would not infringe privately owned
73 * rights.
74 *
75 * Stanford disclaimer of liability
76 * --------------------------------
77 * Stanford University makes no representations or warranties, express or
78 * implied, nor assumes any liability for the use of this software.
79 *
80 * Stanford disclaimer of copyright
81 * --------------------------------
82 * Stanford University, owner of the copyright, hereby disclaims its
83 * copyright and all other rights in this software.  Hence, anyone may
84 * freely use it for any purpose without restriction. 
85 *
86 * Maintenance of notices
87 * ----------------------
88 * In the interest of clarity regarding the origin and status of this
89 * SLAC software, this and all the preceding Stanford University notices
90 * are to remain affixed to any copy or derivative of this software made
91 * or distributed by the recipient and are to be affixed to any copy of
92 * software made or distributed by the recipient that contains a copy or
93 * derivative of this software.
94 *
95 * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
96 */
97#include <rtems.h>
98#include <rtems/error.h>
99
100#include <fcntl.h>
101#include <stdlib.h>
102#include <stdio.h>
103
104unsigned nfsTestReaderPri = 80;
105
106struct nfsTestReq_ {
107        unsigned offset;        /* file offset */
108        int      size;          /* IN: block size to read (must be < 8192), OUT: bytes actually read */
109        void     *buf;          /* data buffer address */
110};
111
112/* Queue for sending requests to parallel reader tasks */
113rtems_id nfsTestRQ = 0;
114/* Queue to pickup replies from parallel reader tasks  */
115rtems_id nfsTestAQ = 0;
116
117
118/* Reader task; opens its own file descriptor
119 * and works on requests:
120 *    - obtain request from request queue.
121 *    - lseek to the requested file offset
122 *    - NFS read into buffer
123 *    - queue reply.
124 *
125 * Note that this implementation is very simple
126 *  - no full error checking.
127 *  - file is opened/closed by thread
128 * it's main purpose is running quick tests.
129 */
130static rtems_task
131nfsTestReader(rtems_task_argument arg)
132{
133int                fd = open((char*)arg,O_RDONLY);
134unsigned long      s;
135struct nfsTestReq_ r;
136rtems_status_code  sc;
137
138        if ( fd < 0 ) {
139                perror("nfsReader: opening file");
140                goto cleanup;
141        }
142        do {
143                s  = sizeof(r);
144                sc = rtems_message_queue_receive(nfsTestRQ, &r, &s, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
145                if ( RTEMS_SUCCESSFUL != sc ) {
146                        rtems_error(sc, "(Error) reading from message queue");
147                        goto cleanup;
148                }
149                if ( !r.buf ) {
150                        /* They send a NULL buffer as a shutdown request */
151                        break;
152                }
153#ifdef DEBUG
154                printf("Reader: reading offset %u, size %i to %p ... ",
155                        r.offset, r.size, r.buf);
156#endif
157                /* seek to requested offset */
158                lseek(fd, r.offset, SEEK_SET);
159                r.size = read(fd, r.buf, r.size);
160#ifdef DEBUG
161                printf("got %i\n",r.size);
162#endif
163                rtems_message_queue_send(nfsTestAQ, &r, sizeof(r));
164        } while (1) ;
165
166cleanup:
167        if ( fd >= 0 )
168                close(fd);
169        rtems_task_delete(RTEMS_SELF);
170}
171
172
173/* helper to create and start a reader task */
174static rtems_id
175taskSpawn(char *filenm, int inst)
176{
177rtems_status_code sc;
178rtems_id          tid;
179
180        sc = rtems_task_create(
181                        rtems_build_name('n','t','t','0'+inst),
182                        nfsTestReaderPri,
183                        1400,
184                        RTEMS_DEFAULT_MODES,   
185                        RTEMS_DEFAULT_ATTRIBUTES,
186                        &tid);
187        if ( RTEMS_SUCCESSFUL != sc ) {
188                rtems_error(sc,"(Error) Creating nfs reader task %i",inst);
189                return 0;
190        }
191
192        sc = rtems_task_start(tid, nfsTestReader, (rtems_task_argument)filenm);
193        if ( RTEMS_SUCCESSFUL != sc ) {
194                rtems_error(sc,"(Error) Staritng nfs reader task %i",inst);
195                rtems_task_delete(tid);
196                return 0;
197        }
198
199        return tid;
200}
201
202/*
203 * Read nrd*sz bytes into 'buf' from file offset 'off'
204 * using 'nrd' parallel reader tasks to do the job.
205 * This helper routine schedules 'nrd' requests to
206 * the reader tasks and waits for all requests to
207 * finish.
208 *
209 * RETURNS: number of bytes read or -1 (error).
210 *
211 * CAVEATS:
212 *      - assumes read requests always return 'sz' bytes
213 *    unless the end of file is reached.
214 *    THIS ASSUMPTION SHOULD NOT BE MADE WHEN WRITING
215 *    ANY 'REAL' CODE.
216 */
217static int
218nfsTestReadBigbuf(char *buf, int off, int sz, int nrd)
219{
220int i,rval=0;
221struct nfsTestReq_ r;
222        r.buf    = buf;
223        r.size   = sz;
224        r.offset = off;
225        /* send out parallel requests */
226        for (i=0; i<nrd; i++) {
227                rtems_message_queue_send(nfsTestRQ, &r, sizeof(r));
228                r.offset += sz;
229                r.buf    += sz;
230        }
231        /* wait for answers */
232        for (i=0; i<nrd; i++) {
233                unsigned long s = sizeof(r);
234                rtems_message_queue_receive(nfsTestAQ, &r, &s, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
235                if ( r.size < 0 ) {
236                        fprintf(stderr,"A reader failed\n");
237                        rval = -1;
238                } else {
239                        /* FIXME sanity checks:
240                         *   - catch case where any-but-last read returns < sz
241                         */
242                        if ( rval >= 0 ) {
243                                rval += r.size;
244                        }
245                }
246        }
247        return rval;
248}
249
250/* Main test routine
251 *
252 * Read file 'fname' usint 'nrd' parallel reader tasks,
253 * each operating on chunks of 'sz' bytes.
254 *
255 * RETURNS: time elapsed in milliseconds. This is measured
256 *          using the system clock. Hence, for the result
257 *          to be meaningful, the file must be big enough.
258 *
259 */
260rtems_interval
261nfsTestRead(char *fnam, int sz, int nrd)
262{
263int               i;
264unsigned          off;
265rtems_interval    now=-1, then, tickspsec;
266rtems_status_code sc;
267int                       fd=-1;
268char              *buf=0;
269
270        if ( nrd < 0 )
271                nrd = 0;
272
273        if ( sz < 0 || sz > 8192 ) {
274                fprintf(stderr,"\n");
275                return -1;
276        }
277
278        nfsTestRQ = nfsTestAQ = 0;
279
280        /* Allocate buffer */
281        if ( ! (buf=malloc(sz*(nrd ? nrd : 1))) ) {
282                perror("allocating buffer");
283                goto cleanup;
284        }
285
286        /* Don't bother proceeding if we can't open the file for reading */
287        if ( (fd=open(fnam,O_RDONLY)) < 0 ) {
288                perror("opening file");
289                goto cleanup;
290        }
291        if ( nrd ) {
292                close(fd); fd = -1;
293        }
294
295        /* Create request queue */
296        if ( nrd ) {
297                sc = rtems_message_queue_create(
298                                rtems_build_name('n','t','r','q'),
299                                nrd,
300                                sizeof(struct nfsTestReq_),
301                                RTEMS_DEFAULT_ATTRIBUTES,
302                                & nfsTestRQ );
303
304                if ( RTEMS_SUCCESSFUL != sc ) {
305                        rtems_error(sc, "(Error) creating request queue");
306                        nfsTestRQ = 0;
307                        goto cleanup;
308                }
309
310                /* Spawn reader tasks */
311                for ( i=0; i<nrd; i++ ) {
312                        if ( ! taskSpawn(fnam, i) )
313                                goto cleanup;
314                }
315
316                /* Create reply queue */
317                sc = rtems_message_queue_create(
318                                rtems_build_name('n','t','a','q'),
319                                nrd,
320                                sizeof(struct nfsTestReq_),
321                                RTEMS_DEFAULT_ATTRIBUTES,
322                                & nfsTestAQ );
323
324                if ( RTEMS_SUCCESSFUL != sc ) {
325                        rtems_error(sc, "(Error) creating reply queue");
326                        nfsTestAQ = 0;
327                        goto cleanup;
328                }
329        }
330
331        /* Timed main loop */
332        then = rtems_clock_get_ticks_since_boot();
333
334        if ( nrd ) {
335                off = 0;
336                while  ((i = nfsTestReadBigbuf(buf, off, sz, nrd)) > 0 ) {
337#ifdef DEBUG
338                        printf("bigbuf got %i\n", i);
339#endif
340                        off += i;
341                }
342        } else {
343                while ( (i = read(fd, buf, sz)) > 0 )
344                        /* nothing else to do */;
345                if ( i < 0 ) {
346                        perror("reading");
347                        goto cleanup;
348                }
349        }
350
351        now = rtems_clock_get_ticks_since_boot();
352        now = (now-then)*1000;
353        ticksspec = rtems_clock_get_ticks_per_second();
354        now /= tickspsec; /* time in ms */
355
356cleanup:
357        if ( fd >= 0 )
358                close(fd);
359
360        if ( nfsTestRQ ) {
361                /* request tasks to shutdown by sending NULL buf request  */
362                struct nfsTestReq_ r;
363                r.buf = 0;
364                for ( i=0; i<nrd; i++ ) {
365                        rtems_message_queue_send( nfsTestRQ, &r, sizeof(r) );
366                }
367                /* cheat: instead of proper synchronization with shutdown we simply
368                 * delay for a second...
369                 */
370                rtems_task_wake_after( tickspsec );
371                rtems_message_queue_delete( nfsTestRQ );
372        }
373        if ( nfsTestAQ )
374                rtems_message_queue_delete( nfsTestAQ );
375        free(buf);
376        return now;
377}
Note: See TracBrowser for help on using the repository browser.