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

4.115
Last change on this file since 4e59276 was 4e59276, checked in by Mathew Kallada <matkallada@…>, on 12/28/12 at 14:05:20

libfs: Doxygen Enhancement Task #5

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