1 /*
2 * Copyright © 2016 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 *
23 */
24
25 #include <unistd.h>
26 #include <stdlib.h>
27 #include <stdint.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <fcntl.h>
31 #include <inttypes.h>
32 #include <errno.h>
33 #include <sys/stat.h>
34 #include <sys/ioctl.h>
35 #include <sys/resource.h>
36 #include <sys/time.h>
37 #include <time.h>
38
39 #include "drm.h"
40 #include "ioctl_wrappers.h"
41 #include "drmtest.h"
42 #include "intel_io.h"
43 #include "igt_rand.h"
44
45 #define CLOSE_DEVICE 0x1
46
elapsed(const struct timespec * start,const struct timespec * end)47 static double elapsed(const struct timespec *start,
48 const struct timespec *end)
49 {
50 return (end->tv_sec - start->tv_sec) + 1e-9*(end->tv_nsec - start->tv_nsec);
51 }
52
loop(int nobj,int ndev,int nage,int ncpus,unsigned flags)53 static int loop(int nobj, int ndev, int nage, int ncpus, unsigned flags)
54 {
55 uint32_t *handle;
56 double *results;
57 int parent;
58 int size;
59 int n;
60
61 #if 0
62 printf("nobj=%d, ndev=%d, nage=%d, ncpus=%d, flags=%x\n",
63 nobj, ndev, nage, ncpus, flags);
64 #endif
65
66 parent = drm_open_driver(DRIVER_INTEL);
67
68 size = ncpus * sizeof(*results);
69 size = (size + 4095) & -4096;
70 results = mmap(0, size, PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
71
72 handle = malloc(nobj * sizeof(*handle));
73 for (n = 0; n < nobj; n++)
74 handle[n] = gem_create(parent, 4096);
75
76 igt_fork(child, ncpus) {
77 struct timespec start, end;
78 unsigned long count = 0;
79 int *dev, *fd;
80
81 hars_petruska_f54_1_random_perturb(child);
82
83 fd = malloc(ndev * nage * sizeof(*fd));
84 dev = malloc(ndev * sizeof(*dev));
85 for (n = 0; n < ndev; n++)
86 dev[n] = drm_open_driver(DRIVER_INTEL);
87 memset(fd, 0xff, ndev * nage * sizeof(*fd));
88
89 clock_gettime(CLOCK_MONOTONIC, &start);
90 do {
91 for (n = 0; n < ndev; n++) {
92 int h = hars_petruska_f54_1_random_unsafe() % nobj;
93 int a = hars_petruska_f54_1_random_unsafe() % nage;
94
95 if (!(flags & CLOSE_DEVICE)) {
96 int old = fd[n*nage + a];
97 if (old != -1) {
98 gem_close(dev[n], prime_fd_to_handle(dev[n], old));
99 close(old);
100 }
101 }
102
103 fd[n*nage + a] =
104 prime_handle_to_fd(parent, handle[h]);
105 prime_fd_to_handle(dev[n], fd[n*nage + a]);
106
107 if (flags & CLOSE_DEVICE) {
108 close(dev[n]);
109 dev[n] = drm_open_driver(DRIVER_INTEL);
110 }
111 }
112
113 count++;
114 clock_gettime(CLOCK_MONOTONIC, &end);
115 } while (elapsed(&start, &end) < 2.);
116 results[child] = 1e6*elapsed(&start, &end) / (ndev * count);
117 }
118 igt_waitchildren();
119
120 results[ncpus] = 0;
121 for (n = 0; n < ncpus; n++)
122 results[ncpus] += results[n];
123 printf("%.3f us\n", results[ncpus] / ncpus);
124 return 0;
125 }
126
allow_files(unsigned min)127 static bool allow_files(unsigned min)
128 {
129 struct rlimit rlim;
130 unsigned nofile_rlim = 1024*1024;
131
132 FILE *file = fopen("/proc/sys/fs/file-max", "r");
133 if (file) {
134 igt_assert(fscanf(file, "%u", &nofile_rlim) == 1);
135 igt_info("System limit for open files is %u\n", nofile_rlim);
136 fclose(file);
137 }
138
139 if (min > nofile_rlim)
140 return false;
141
142 if (getrlimit(RLIMIT_NOFILE, &rlim))
143 return false;
144
145 igt_info("Current file limit is %ld, estimated we need %d\n",
146 (long)rlim.rlim_cur, min);
147
148 if (rlim.rlim_cur > min)
149 return true;
150
151 rlim.rlim_cur = min;
152 rlim.rlim_max = min;
153 return setrlimit(RLIMIT_NOFILE, &rlim) == 0;
154 }
155
main(int argc,char ** argv)156 int main(int argc, char **argv)
157 {
158 unsigned flags = 0;
159 int ncpus = 1;
160 int ndev = 512;
161 int nobj = 32 << 10;
162 int nage = 1024;
163 int c;
164
165 while ((c = getopt (argc, argv, "a:d:o:cf")) != -1) {
166 switch (c) {
167 case 'o':
168 nobj = atoi(optarg);
169 if (nobj < 1)
170 nobj = 1;
171 break;
172
173 case 'd':
174 ndev = atoi(optarg);
175 if (ndev < 1)
176 ndev = 1;
177 break;
178
179 case 'a':
180 nage = atoi(optarg);
181 if (nage < 1)
182 nage = 1;
183 break;
184
185 case 'f':
186 ncpus = sysconf(_SC_NPROCESSORS_ONLN);
187 break;
188
189 case 'c':
190 flags |= CLOSE_DEVICE;
191 break;
192
193 default:
194 break;
195 }
196 }
197
198 if (!allow_files((nage + 1)*ndev + 1)) {
199 fprintf(stderr, "Unable to relax fd limit\n");
200 exit(1);
201 }
202
203 return loop(nobj, ndev, nage, ncpus, flags);
204 }
205