root/branches/cu-security-branch/test/client/sysint/io-stress.c @ 8397

Revision 8397, 15.5 KB (checked in by nlmills, 3 years ago)

initial merge with Orange-Branch. much will be broken

Line 
1/*
2 * (C) 2001 Clemson University and The University of Chicago
3 *
4 * See COPYING in top-level directory.
5 */
6
7/* pvfs2-tio
8 *  Threaded I/O benchmark to exercise the aio code paths on server.
9 */
10#include <stdio.h>
11#include <stdlib.h>
12#include <unistd.h>
13#include <limits.h>
14#include <string.h>
15#include <sys/types.h>
16#include <sys/stat.h>
17#include <fcntl.h>
18#include <libgen.h>
19#include <getopt.h>
20#include <pthread.h>
21#include <aio.h>
22
23#define __PINT_REQPROTO_ENCODE_FUNCS_C
24#include "pvfs2.h"
25#include "str-utils.h"
26#include "pint-sysint-utils.h"
27#include "pint-util.h"
28#include "pvfs2-internal.h"
29#include "quicklist.h"
30#include "quickhash.h"
31
32struct options
33{
34    char *srcfile;
35    int num_io;
36};
37
38enum object_type {
39    UNIX_FILE,
40    PVFS2_FILE
41};
42
43typedef struct pvfs2_file_object_s {
44    PVFS_fs_id fs_id;
45    PVFS_object_ref ref;
46    char pvfs2_path[PVFS_NAME_MAX];     
47    char user_path[PVFS_NAME_MAX];
48    PVFS_sys_attr attr;
49    PVFS_permissions perms;
50} pvfs2_file_object;
51
52typedef struct unix_file_object_s {
53    int fd;
54    int mode;
55    char path[NAME_MAX];
56    PVFS_fs_id fs_id;
57} unix_file_object;
58
59typedef struct file_object_s {
60    int fs_type;
61    union {
62        unix_file_object ufs;
63        pvfs2_file_object pvfs2;
64    } u;
65} file_object;
66
67
68static struct options* parse_args(int argc, char* argv[]);
69static void usage(int argc, char** argv);
70static int resolve_filename(file_object *obj, char *filename);
71static int generic_open(file_object *obj, PVFS_credentials *credentials);
72
73static file_object src;
74static char buf[2097152];
75
76typedef struct {
77    int index;
78    PVFS_id_gen_t tag;
79    PVFS_sys_op_id op_id;
80    PVFS_Request   file_req;
81    PVFS_Request   mem_req;
82    PVFS_sysresp_io resp_io;
83    file_object *src;
84    char  *buffer;
85    int64_t offset;
86    int64_t count;
87    PVFS_credentials credentials;
88    struct aiocb acb;
89    struct qlist_head hash_link;
90} io_request;
91
92static PVFS_error post_generic_write(io_request *req);
93static PVFS_error post_generic_read(io_request *req);
94#define NUM_IO 5
95
96io_request vfs_request[NUM_IO];
97/* this hashtable is used to keep track of operations in progress */
98#define DEFAULT_OPS_IN_PROGRESS_HTABLE_SIZE 67
99static int hash_key(void *key, int table_size);
100static int hash_key_compare(void *key, struct qlist_head *link);
101static struct qhash_table *s_ops_in_progress_table = NULL;
102
103static int hash_key(void *key, int table_size)
104{
105    PVFS_id_gen_t tag = *((PVFS_id_gen_t *)key);
106    return (tag % table_size);
107}
108
109static int hash_key_compare(void *key, struct qlist_head *link)
110{
111    io_request *vfs_request = NULL;
112    PVFS_id_gen_t tag = *((PVFS_id_gen_t *)key);
113
114    vfs_request = qlist_entry(link, io_request, hash_link);
115    assert(vfs_request);
116
117    return ((vfs_request->tag == tag) ? 1 : 0);
118}
119
120static int initialize_ops_in_progress_table(void)
121{
122    if (!s_ops_in_progress_table)
123    {
124        s_ops_in_progress_table = qhash_init(
125            hash_key_compare, hash_key,
126            DEFAULT_OPS_IN_PROGRESS_HTABLE_SIZE);
127    }
128    return (s_ops_in_progress_table ? 0 : -PVFS_ENOMEM);
129}
130
131static void finalize_ops_in_progress_table(void)
132{
133    int i = 0;
134    struct qlist_head *hash_link = NULL;
135
136    if (s_ops_in_progress_table)
137    {
138        for(i = 0; i < s_ops_in_progress_table->table_size; i++)
139        {
140            do
141            {
142                hash_link = qhash_search_and_remove_at_index(
143                    s_ops_in_progress_table, i);
144
145            } while(hash_link);
146        }
147        qhash_finalize(s_ops_in_progress_table);
148        s_ops_in_progress_table = NULL;
149    }
150}
151
152static PVFS_error remove_op_from_op_in_progress_table(
153    io_request *vfs_request)
154{
155    PVFS_error ret = -PVFS_EINVAL;
156    struct qlist_head *hash_link = NULL;
157    io_request *tmp_vfs_request = NULL;
158
159    if (vfs_request)
160    {
161        hash_link = qhash_search_and_remove(
162            s_ops_in_progress_table, (void *)(&vfs_request->tag));
163        if (hash_link)
164        {
165            tmp_vfs_request = qhash_entry(
166                hash_link, io_request, hash_link);
167            assert(tmp_vfs_request);
168            assert(tmp_vfs_request == vfs_request);
169            ret = 0;
170        }
171    }
172    return ret;
173}
174
175static PVFS_error add_op_to_op_in_progress_table(
176    io_request *vfs_request)
177{
178    PVFS_error ret = -PVFS_EINVAL;
179
180    if (vfs_request)
181    {
182        qhash_add(s_ops_in_progress_table,
183                  (void *)(&vfs_request->tag),
184                  &vfs_request->hash_link);
185        ret = 0;
186    }
187    return ret;
188}
189static long tag = 100;
190
191static void post_op(io_request *req)
192{
193    static int off_count = 0;
194    int rd_wr = 1;
195    req->offset = (off_count++ * 2097152);
196    req->tag = tag++;
197    req->src = &src;
198    req->buffer = buf;
199    req->count = 2097152;
200    PVFS_util_gen_credentials(&req->credentials);
201    if (rd_wr == 0)
202        post_generic_read(req);
203    else
204        post_generic_write(req);
205    add_op_to_op_in_progress_table(req);
206}
207
208#define MAX_OPS 64
209
210static void do_pvfs_io(int num_io)
211{
212    PVFS_error ret;
213    int i, count = num_io;
214    io_request *all_request[MAX_OPS], *req;
215    PVFS_sys_op_id op_id_array[MAX_OPS];
216    int error_code_array[MAX_OPS], op_count = 0;
217    PVFS_size total = 0;
218
219    printf("doing %d I/O 5 at a time\n", num_io);
220    for (i = 0; i < NUM_IO; i++) {
221        vfs_request[i].index = i;
222    }
223
224    for (i = 0; i < NUM_IO; i++) {
225        post_op(&vfs_request[i]);
226    }
227    while (1)
228    {
229        op_count = MAX_OPS;
230        memset(error_code_array, 0, MAX_OPS * sizeof(int));
231        memset(all_request, 0, MAX_OPS * sizeof(io_request *));
232        ret = PVFS_sys_testsome(
233                op_id_array, &op_count, (void *) all_request,
234                error_code_array, 10);
235        for (i = 0; i < op_count; i++)
236        {
237            req = all_request[i];
238            if (req->op_id != op_id_array[i])
239                continue;
240            if (req->resp_io.total_completed != 2097152)
241            {
242                fprintf(stderr, "Short I/O\n");
243            }
244            total += req->resp_io.total_completed;
245            ret = remove_op_from_op_in_progress_table(req);
246            if (ret)
247            {
248                PVFS_perror_gossip("Failed to remove op in progress from table\n", ret);
249            }
250            count--;
251            if (count > 0)
252                post_op(req);
253        }
254        if (count <= 0)
255            break;
256    }
257    printf("Total I/O staged %Ld\n", lld(total));
258    return;
259}
260
261static void do_unix_io(int num_io)
262{
263    int count;
264    long ret;
265    int status[NUM_IO];
266    int flag, i;
267
268    count = num_io;
269    ret = 0;
270    flag = -1;
271
272    for (i = 0; i < NUM_IO; i++) {
273        vfs_request[i].index = i;
274    }
275    for (i = 0; i < NUM_IO; i++) {
276        status[i] = EINPROGRESS;
277        post_op(&vfs_request[i]);
278    }
279    while (1)
280    {
281        long ret1;
282        flag = -1;
283        for (i = 0; i < NUM_IO; i++)
284        {
285            if (status[i] == EINPROGRESS)
286            {
287                ret1 = aio_error(&vfs_request[i].acb);
288                if (ret1 != 0)
289                {
290                    /* if op in progress, we have to skip it */
291                    if (ret1 == EINPROGRESS)
292                    {
293                        /* we have not completed */
294                        flag = 1;
295                        continue;
296                    }
297                    else
298                    {
299                        printf("I/O on %d failed: %s\n", i, strerror(errno));
300                        status[i] = -1;
301                    }
302                }
303                else
304                {
305                    /* we have completed */
306                    ret += aio_return(&vfs_request[i].acb);
307                    if (flag < 0)
308                    {
309                        flag = 0;
310                    }
311                    remove_op_from_op_in_progress_table(&vfs_request[i]);
312                    count--;
313                    if (count > 0)
314                    {
315                        status[i] = EINPROGRESS;
316                        post_op(&vfs_request[i]);
317                    }
318                }
319            }
320        }
321        if (count <= 0)
322            break;
323    }
324    return;
325}
326
327static void do_io(int num_io)
328{
329    if(src.fs_type == UNIX_FILE)
330        do_unix_io(num_io);
331    else
332        do_pvfs_io(num_io);
333    return;
334}
335
336int main(int argc, char ** argv)
337{
338    struct options* user_opts = NULL;
339    int64_t ret;
340    PVFS_credentials credentials;
341
342    initialize_ops_in_progress_table();
343    user_opts = parse_args(argc, argv);
344    if (!user_opts)
345    {
346        fprintf(stderr, "Error, failed to parse command line arguments\n");
347        return(-1);
348    }
349
350    ret = PVFS_util_init_defaults();
351    if (ret < 0)
352    {
353        PVFS_perror("PVFS_util_init_defaults", ret);
354        return(-1);
355    }
356    memset(&src, 0, sizeof(src));
357
358    resolve_filename(&src,  user_opts->srcfile);
359
360    PVFS_util_gen_credentials(&credentials);
361
362    ret = generic_open(&src, &credentials);
363    if (ret < 0)
364    {
365        fprintf(stderr, "Could not open %s\n", user_opts->srcfile);
366        goto main_out;
367    }
368
369    do_io(user_opts->num_io);
370main_out:
371    PVFS_sys_finalize();
372    finalize_ops_in_progress_table();
373    free(user_opts);
374    return(ret);
375}
376
377/* parse_args()
378 *
379 * parses command line arguments
380 *
381 * returns pointer to options structure on success, NULL on failure
382 */
383static struct options* parse_args(int argc, char* argv[])
384{
385    char flags[] = "f:i:";
386    int one_opt = 0;
387
388    struct options* tmp_opts = NULL;
389
390    /* create storage for the command line options */
391    tmp_opts = (struct options*)malloc(sizeof(struct options));
392    if(!tmp_opts){
393        return(NULL);
394    }
395    memset(tmp_opts, 0, sizeof(struct options));
396    tmp_opts->num_io = 10000;
397
398    /* look at command line arguments */
399    while((one_opt = getopt(argc, argv, flags)) != EOF)
400    {
401        switch(one_opt) {
402            case 'i':
403                tmp_opts->num_io = atoi(optarg);
404                break;
405            case('f'):
406                tmp_opts->srcfile = optarg;
407                break;
408            case('?'):
409                usage(argc, argv);
410                exit(EXIT_FAILURE);
411        }
412    }
413    if (tmp_opts->srcfile == NULL)
414    {
415        usage(argc, argv);
416        exit(EXIT_FAILURE);
417    }
418    return(tmp_opts);
419}
420
421static void usage(int argc, char** argv)
422{
423    fprintf(stderr,
424        "Usage: %s ARGS \n", argv[0]);
425    fprintf(stderr, "Where ARGS is one or more of"
426        "\n-f <file name>\t\t\tPVFS2 file pathname"
427        "\n-v\t\t\t\tprint version number and exit\n");
428    return;
429}
430
431/* resolve_filename:
432 *  given 'filename', find the PVFS2 fs_id and relative pvfs_path.  In case of
433 *  error, assume 'filename' is a unix file.
434 */
435static int resolve_filename(file_object *obj, char *filename)
436{
437    int ret;
438
439    ret = PVFS_util_resolve(filename, &(obj->u.pvfs2.fs_id),
440            obj->u.pvfs2.pvfs2_path, PVFS_NAME_MAX);
441    if (ret < 0)
442    {
443        obj->fs_type = UNIX_FILE;
444        strncpy(obj->u.ufs.path, filename, NAME_MAX);
445    } else {
446        obj->fs_type = PVFS2_FILE;
447        strncpy(obj->u.pvfs2.user_path, filename, PVFS_NAME_MAX);
448    }
449    return 0;
450}
451
452/* generic_open:
453 *  given a file_object, perform the apropriate open calls. 
454 */
455static int generic_open(file_object *obj, PVFS_credentials *credentials)
456{
457    struct stat stat_buf;
458    PVFS_sysresp_lookup resp_lookup;
459    PVFS_sysresp_getattr resp_getattr;
460    PVFS_object_ref ref;
461    int ret = -1;
462
463    if (obj->fs_type == UNIX_FILE)
464    {
465        PINT_statfs_t statfsbuf;
466        memset(&stat_buf, 0, sizeof(struct stat));
467
468        stat(obj->u.ufs.path, &stat_buf);
469        if (!S_ISREG(stat_buf.st_mode))
470        {
471            fprintf(stderr, "Not a file!\n");
472            return(-1);
473        }
474        obj->u.ufs.fd = open(obj->u.ufs.path, O_RDWR);
475        obj->u.ufs.mode = (int)stat_buf.st_mode;
476        if (obj->u.ufs.fd < 0)
477        {
478            perror("open");
479            fprintf(stderr, "could not open %s\n", obj->u.ufs.path);
480            return (-1);
481        }
482        if (PINT_statfs_fd_lookup(obj->u.ufs.fd, &statfsbuf) < 0)
483        {
484            perror("fstatfs:");
485            fprintf(stderr, "could not fstatfs %s\n", obj->u.ufs.path);
486        }
487        memcpy(&obj->u.ufs.fs_id, &PINT_statfs_fsid(&statfsbuf),
488               sizeof(PINT_statfs_fsid(&statfsbuf)));
489        return 0;
490    }
491    else
492    {
493        memset(&resp_lookup, 0, sizeof(PVFS_sysresp_lookup));
494        ret = PVFS_sys_lookup(obj->u.pvfs2.fs_id,
495                              (char *) obj->u.pvfs2.pvfs2_path,
496                              credentials,
497                              &resp_lookup,
498                              PVFS2_LOOKUP_LINK_FOLLOW, NULL);
499        if (ret < 0)
500        {
501            PVFS_perror("PVFS_sys_lookup", ret);
502            return (-1);
503        }
504        ref.handle = resp_lookup.ref.handle;
505        ref.fs_id = resp_lookup.ref.fs_id;
506
507        memset(&resp_getattr, 0, sizeof(PVFS_sysresp_getattr));
508        ret = PVFS_sys_getattr(ref, PVFS_ATTR_SYS_ALL,
509                               credentials, &resp_getattr, NULL);
510        if (ret)
511        {
512            fprintf(stderr, "Failed to do pvfs2 getattr on %s\n",
513                    obj->u.pvfs2.pvfs2_path);
514            return -1;
515        }
516
517        if (resp_getattr.attr.objtype != PVFS_TYPE_METAFILE)
518        {
519            fprintf(stderr, "Not a meta file!\n");
520            return -1;
521        }
522        obj->u.pvfs2.perms = resp_getattr.attr.perms;
523        memcpy(&obj->u.pvfs2.attr, &resp_getattr.attr,
524               sizeof(PVFS_sys_attr));
525        obj->u.pvfs2.attr.mask = PVFS_ATTR_SYS_ALL_SETABLE;
526        obj->u.pvfs2.ref = ref;
527    }
528    return 0;
529}
530
531/* read 'count' bytes from a (unix or pvfs2) file 'src', placing the result in
532 * 'buffer' */
533static PVFS_error post_generic_read(io_request *req)
534{
535    if(req->src->fs_type == UNIX_FILE)
536    {
537        req->acb.aio_fildes = req->src->u.ufs.fd;
538        req->acb.aio_lio_opcode = LIO_READ;
539        req->acb.aio_reqprio = 0;
540        req->acb.aio_offset = req->offset;
541        req->acb.aio_buf = req->buffer;
542        req->acb.aio_nbytes = req->count;
543        req->acb.aio_sigevent.sigev_notify = SIGEV_NONE;
544        return (aio_read(&req->acb));
545    }
546    else
547    {
548        PVFS_error ret;
549        req->file_req = PVFS_BYTE;
550        ret = PVFS_Request_contiguous(req->count, PVFS_BYTE, &req->mem_req);
551        if (ret < 0)
552        {
553            fprintf(stderr, "Error: PVFS_Request_contiguous failure\n");
554            return (ret);
555        }
556        ret = PVFS_isys_io(req->src->u.pvfs2.ref, req->file_req, req->offset,
557                req->buffer, req->mem_req, &req->credentials, &req->resp_io,
558                PVFS_IO_READ, &req->op_id, NULL, req);
559        if (ret != 0)
560        {
561            PVFS_perror("PVFS_isys_io", ret);
562            PVFS_Request_free(&req->mem_req);
563            return ret;
564        }
565        return 0;
566    }
567}
568
569/* write 'count' bytes to a (unix or pvfs2) file 'src', taking the result from
570 * 'buffer' */
571static PVFS_error post_generic_write(io_request *req)
572{
573    if(req->src->fs_type == UNIX_FILE)
574    {
575        req->acb.aio_fildes = req->src->u.ufs.fd;
576        req->acb.aio_lio_opcode = LIO_WRITE;
577        req->acb.aio_reqprio = 0;
578        req->acb.aio_offset = req->offset;
579        req->acb.aio_buf = req->buffer;
580        req->acb.aio_nbytes = req->count;
581        req->acb.aio_sigevent.sigev_notify = SIGEV_NONE;
582        return (aio_write(&req->acb));
583    }
584    else
585    {
586        PVFS_error ret;
587        req->file_req = PVFS_BYTE;
588        ret = PVFS_Request_contiguous(req->count, PVFS_BYTE, &req->mem_req);
589        if (ret < 0)
590        {
591            fprintf(stderr, "Error: PVFS_Request_contiguous failure\n");
592            return (ret);
593        }
594        ret = PVFS_isys_io(req->src->u.pvfs2.ref, req->file_req, req->offset,
595                req->buffer, req->mem_req, &req->credentials, &req->resp_io,
596                PVFS_IO_WRITE, &req->op_id, NULL, req);
597        if (ret != 0)
598        {
599            PVFS_perror("PVFS_isys_io", ret);
600            PVFS_Request_free(&req->mem_req);
601            return ret;
602        }
603        return 0;
604    }
605}
606
607/*
608 * Local variables:
609 *  c-indent-level: 4
610 *  c-basic-offset: 4
611 * End:
612 *
613 * vim: ts=8 sts=4 sw=4 expandtab
614 */
Note: See TracBrowser for help on using the browser.