Whamcloud - gitweb
e65f71195a8b1fcbed432e881729643e66719895
[fs/lustre-release.git] / lustre / tests / mpi / rr_alloc.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see If not, see
18  * http://www.gnu.org/licenses
19  *
20  * Please contact http://www.seagate.com/contacts/ or visit www.seagate.com
21  * if you need additional information or have any questions.
22  *
23  * GPL HEADER END
24  */
25 /*
26  * Copyright (c) 2017, Seagate Technology LLC
27  *
28  * Author: Ashish Maurya <ashish.maurya@seagate.com>
29  */
30 /*
31  * lustre/tests/mpi/rr_alloc.c
32  *
33  * DESCRIPTION
34  *
35  * This code is creating <n> files using MPI processes which depend on the
36  * mounted clients. Processes are running in parallel through all the client
37  * nodes in RR fashion starting with rank 0 and so on, and creating files.
38  *
39  * USE CASE:- If there are 20 mounted clients on 4 client nodes, 5 clients on
40  * each node, it will run 5 processes on each client node through each mount
41  * point and each process will create <n> number of files given by the user.
42  * Each process rank is mapped to its matching mount point on the client node
43  * eg:- rank 0 <-> /tmp/mnt/lustre0 ; rank 1 <-> /tmp/mnt/lustre1 etc.
44  *
45  * NOTE:- For simplicity client on /mnt/lustre is not taken into account.
46  *
47  * IMPORTANT NOTE:- If argv[1] is /mnt/dir/ash, then the program assumes that.
48  * /mnt0/dir/, /mnt1/dir/, etc exist.
49  */
50
51 #include <mpi.h>
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <unistd.h>
55 #include <string.h>
56 #include <stdarg.h>
57 #include <errno.h>
58 #include <fcntl.h>
59 #include <limits.h>
60 #include <libgen.h>
61
62 void usage(char *prog)
63 {
64         printf("Usage: %s <filename with mount pt and test dir>", prog);
65         printf(" <no. of files> <no. of cli nodes>\n");
66         printf("Ex: mpirun -np <njobs> rr_alloc /tmp/mnt/lustre/ash 512 4\n");
67
68         exit(EXIT_FAILURE);
69 }
70
71 void perr_exit(int rank, int error, const char *fmt, ...)
72 {
73         va_list ap;
74
75         printf("Process rank %d exited with error code %d\n", rank, error);
76         va_start(ap, fmt);
77         vprintf(fmt, ap);
78
79         MPI_Abort(MPI_COMM_WORLD, error);
80 }
81
82 int main(int argc, char **argv)
83 {
84         int proc_rank = 0;
85         int serial_prank_per_cli = 0;
86         int proc_per_cli_node = 0;
87         int bytes = 0;
88         int file_no = 0;
89         int client_nodes = 0;
90         int nproc = 0;
91         int rc = 0;
92         int fd = 0;
93         int i = 0;
94         char file_path[PATH_MAX] = {0};
95         char mnt_path[PATH_MAX] = {0};
96         char *path1;
97         char *path2;
98         char *path3;
99         char *fname;
100         char *dname;
101
102         if (argc != 4)
103                 usage(argv[0]);
104
105         if (!strchr(argv[1], '/')) {
106                 fprintf(stderr, "Please enter filename with mount point\n");
107                 usage(argv[0]);
108         }
109
110         /*
111          * Separating filename and mount point name. This is required for
112          * mapping processes to particular mount point.
113          */
114         path1 = strdup(argv[1]);
115         path2 = strdup(argv[1]);
116         path3 = strdup(argv[1]);
117         fname = basename(path1);
118         dname = basename(dirname(path2));
119         /* dirname looping depends on the depth of the file from mount path */
120         strncpy(mnt_path, dirname(dirname(path3)), sizeof(mnt_path));
121
122         file_no = atoi(argv[2]);
123         if (!file_no) {
124                 fprintf(stderr, "Number of files must not be zero\n");
125                 usage(argv[0]);
126         }
127         client_nodes = atoi(argv[3]);
128         if (!client_nodes) {
129                 fprintf(stderr, "Client nodes must not be zero\n");
130                 usage(argv[0]);
131         }
132
133         rc = MPI_Init(&argc, &argv);
134         if (rc != MPI_SUCCESS) {
135                 fprintf(stderr, "MPI_Init failed: %d\n", rc);
136                 exit(EXIT_FAILURE);
137         }
138
139         rc = MPI_Comm_rank(MPI_COMM_WORLD, &proc_rank);
140         if (rc != MPI_SUCCESS)
141                 perr_exit(proc_rank, rc, "MPI_Comm_rank failed: %d\n", rc);
142
143         rc = MPI_Comm_size(MPI_COMM_WORLD, &nproc);
144         if (rc != MPI_SUCCESS)
145                 perr_exit(proc_rank, rc, "MPI_Comm_size failed: %d\n", rc);
146
147         /*
148          * Make sure that each rank is processed through its respective mnt pt
149          * eg: job 0,1 will be executed by /tmp/mnt/lustre0, /tmp/mnt/lustre1,
150          * etc. on each client node.
151          */
152         /* Number of processes on each client nodes */
153         proc_per_cli_node = nproc / client_nodes;
154
155         /*
156          * By default rank of processes is allocated in RR fashion throughout
157          * all the client nodes so all the processes are not in serial order on
158          * a particular client node. In order to map each process to a mount pt
159          * by its rank we need process rank in serial order on a client node
160          */
161         serial_prank_per_cli = proc_rank % proc_per_cli_node;
162
163         rc = MPI_Barrier(MPI_COMM_WORLD);
164         if (rc != MPI_SUCCESS)
165                 perr_exit(proc_rank, rc, "Prep MPI_Barrier failed: %d\n", rc);
166
167         for (i = 0; i < file_no; i++) {
168                 bytes = snprintf(file_path, sizeof(file_path),
169                         "%s%d/%s/%s-%d-%d", mnt_path, serial_prank_per_cli,
170                         dname, fname, proc_rank, i);
171                 if (bytes >= sizeof(file_path))
172                         perr_exit(proc_rank, -ENAMETOOLONG, "Name too long\n");
173                 fd = open(file_path, O_CREAT|O_RDWR, 0644);
174                 if (fd < 0) {
175                         perr_exit(proc_rank, errno, "Cannot open \"%s\": %s\n",
176                                 file_path, strerror(errno));
177                 }
178                 close(fd);
179         }
180         MPI_Finalize();
181         return 0;
182 }