1*25da2beaSAndroid Build Coastguard Worker /* SPDX-License-Identifier: MIT */
2*25da2beaSAndroid Build Coastguard Worker /*
3*25da2beaSAndroid Build Coastguard Worker * Description: basic madvise test
4*25da2beaSAndroid Build Coastguard Worker */
5*25da2beaSAndroid Build Coastguard Worker #include <errno.h>
6*25da2beaSAndroid Build Coastguard Worker #include <stdio.h>
7*25da2beaSAndroid Build Coastguard Worker #include <unistd.h>
8*25da2beaSAndroid Build Coastguard Worker #include <stdlib.h>
9*25da2beaSAndroid Build Coastguard Worker #include <string.h>
10*25da2beaSAndroid Build Coastguard Worker #include <fcntl.h>
11*25da2beaSAndroid Build Coastguard Worker #include <sys/types.h>
12*25da2beaSAndroid Build Coastguard Worker #include <sys/time.h>
13*25da2beaSAndroid Build Coastguard Worker #include <sys/mman.h>
14*25da2beaSAndroid Build Coastguard Worker
15*25da2beaSAndroid Build Coastguard Worker #include "helpers.h"
16*25da2beaSAndroid Build Coastguard Worker #include "liburing.h"
17*25da2beaSAndroid Build Coastguard Worker
18*25da2beaSAndroid Build Coastguard Worker #define FILE_SIZE (128 * 1024)
19*25da2beaSAndroid Build Coastguard Worker
20*25da2beaSAndroid Build Coastguard Worker #define LOOPS 100
21*25da2beaSAndroid Build Coastguard Worker #define MIN_LOOPS 10
22*25da2beaSAndroid Build Coastguard Worker
utime_since(const struct timeval * s,const struct timeval * e)23*25da2beaSAndroid Build Coastguard Worker static unsigned long long utime_since(const struct timeval *s,
24*25da2beaSAndroid Build Coastguard Worker const struct timeval *e)
25*25da2beaSAndroid Build Coastguard Worker {
26*25da2beaSAndroid Build Coastguard Worker long long sec, usec;
27*25da2beaSAndroid Build Coastguard Worker
28*25da2beaSAndroid Build Coastguard Worker sec = e->tv_sec - s->tv_sec;
29*25da2beaSAndroid Build Coastguard Worker usec = (e->tv_usec - s->tv_usec);
30*25da2beaSAndroid Build Coastguard Worker if (sec > 0 && usec < 0) {
31*25da2beaSAndroid Build Coastguard Worker sec--;
32*25da2beaSAndroid Build Coastguard Worker usec += 1000000;
33*25da2beaSAndroid Build Coastguard Worker }
34*25da2beaSAndroid Build Coastguard Worker
35*25da2beaSAndroid Build Coastguard Worker sec *= 1000000;
36*25da2beaSAndroid Build Coastguard Worker return sec + usec;
37*25da2beaSAndroid Build Coastguard Worker }
38*25da2beaSAndroid Build Coastguard Worker
utime_since_now(struct timeval * tv)39*25da2beaSAndroid Build Coastguard Worker static unsigned long long utime_since_now(struct timeval *tv)
40*25da2beaSAndroid Build Coastguard Worker {
41*25da2beaSAndroid Build Coastguard Worker struct timeval end;
42*25da2beaSAndroid Build Coastguard Worker
43*25da2beaSAndroid Build Coastguard Worker gettimeofday(&end, NULL);
44*25da2beaSAndroid Build Coastguard Worker return utime_since(tv, &end);
45*25da2beaSAndroid Build Coastguard Worker }
46*25da2beaSAndroid Build Coastguard Worker
do_madvise(struct io_uring * ring,void * addr,off_t len,int advice)47*25da2beaSAndroid Build Coastguard Worker static int do_madvise(struct io_uring *ring, void *addr, off_t len, int advice)
48*25da2beaSAndroid Build Coastguard Worker {
49*25da2beaSAndroid Build Coastguard Worker struct io_uring_sqe *sqe;
50*25da2beaSAndroid Build Coastguard Worker struct io_uring_cqe *cqe;
51*25da2beaSAndroid Build Coastguard Worker int ret;
52*25da2beaSAndroid Build Coastguard Worker
53*25da2beaSAndroid Build Coastguard Worker sqe = io_uring_get_sqe(ring);
54*25da2beaSAndroid Build Coastguard Worker if (!sqe) {
55*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "failed to get sqe\n");
56*25da2beaSAndroid Build Coastguard Worker return 1;
57*25da2beaSAndroid Build Coastguard Worker }
58*25da2beaSAndroid Build Coastguard Worker
59*25da2beaSAndroid Build Coastguard Worker io_uring_prep_madvise(sqe, addr, len, advice);
60*25da2beaSAndroid Build Coastguard Worker sqe->user_data = advice;
61*25da2beaSAndroid Build Coastguard Worker ret = io_uring_submit_and_wait(ring, 1);
62*25da2beaSAndroid Build Coastguard Worker if (ret != 1) {
63*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "submit: %d\n", ret);
64*25da2beaSAndroid Build Coastguard Worker return 1;
65*25da2beaSAndroid Build Coastguard Worker }
66*25da2beaSAndroid Build Coastguard Worker
67*25da2beaSAndroid Build Coastguard Worker ret = io_uring_wait_cqe(ring, &cqe);
68*25da2beaSAndroid Build Coastguard Worker if (ret) {
69*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "wait: %d\n", ret);
70*25da2beaSAndroid Build Coastguard Worker return 1;
71*25da2beaSAndroid Build Coastguard Worker }
72*25da2beaSAndroid Build Coastguard Worker
73*25da2beaSAndroid Build Coastguard Worker ret = cqe->res;
74*25da2beaSAndroid Build Coastguard Worker if (ret == -EINVAL || ret == -EBADF) {
75*25da2beaSAndroid Build Coastguard Worker fprintf(stdout, "Madvise not supported, skipping\n");
76*25da2beaSAndroid Build Coastguard Worker unlink(".madvise.tmp");
77*25da2beaSAndroid Build Coastguard Worker exit(0);
78*25da2beaSAndroid Build Coastguard Worker } else if (ret) {
79*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "cqe->res=%d\n", cqe->res);
80*25da2beaSAndroid Build Coastguard Worker }
81*25da2beaSAndroid Build Coastguard Worker io_uring_cqe_seen(ring, cqe);
82*25da2beaSAndroid Build Coastguard Worker return ret;
83*25da2beaSAndroid Build Coastguard Worker }
84*25da2beaSAndroid Build Coastguard Worker
do_copy(int fd,char * buf,void * ptr)85*25da2beaSAndroid Build Coastguard Worker static long do_copy(int fd, char *buf, void *ptr)
86*25da2beaSAndroid Build Coastguard Worker {
87*25da2beaSAndroid Build Coastguard Worker struct timeval tv;
88*25da2beaSAndroid Build Coastguard Worker
89*25da2beaSAndroid Build Coastguard Worker gettimeofday(&tv, NULL);
90*25da2beaSAndroid Build Coastguard Worker memcpy(buf, ptr, FILE_SIZE);
91*25da2beaSAndroid Build Coastguard Worker return utime_since_now(&tv);
92*25da2beaSAndroid Build Coastguard Worker }
93*25da2beaSAndroid Build Coastguard Worker
test_madvise(struct io_uring * ring,const char * filename)94*25da2beaSAndroid Build Coastguard Worker static int test_madvise(struct io_uring *ring, const char *filename)
95*25da2beaSAndroid Build Coastguard Worker {
96*25da2beaSAndroid Build Coastguard Worker unsigned long cached_read, uncached_read, cached_read2;
97*25da2beaSAndroid Build Coastguard Worker int fd, ret;
98*25da2beaSAndroid Build Coastguard Worker char *buf;
99*25da2beaSAndroid Build Coastguard Worker void *ptr;
100*25da2beaSAndroid Build Coastguard Worker
101*25da2beaSAndroid Build Coastguard Worker fd = open(filename, O_RDONLY);
102*25da2beaSAndroid Build Coastguard Worker if (fd < 0) {
103*25da2beaSAndroid Build Coastguard Worker perror("open");
104*25da2beaSAndroid Build Coastguard Worker return 1;
105*25da2beaSAndroid Build Coastguard Worker }
106*25da2beaSAndroid Build Coastguard Worker
107*25da2beaSAndroid Build Coastguard Worker buf = t_malloc(FILE_SIZE);
108*25da2beaSAndroid Build Coastguard Worker
109*25da2beaSAndroid Build Coastguard Worker ptr = mmap(NULL, FILE_SIZE, PROT_READ, MAP_PRIVATE, fd, 0);
110*25da2beaSAndroid Build Coastguard Worker if (ptr == MAP_FAILED) {
111*25da2beaSAndroid Build Coastguard Worker perror("mmap");
112*25da2beaSAndroid Build Coastguard Worker return 1;
113*25da2beaSAndroid Build Coastguard Worker }
114*25da2beaSAndroid Build Coastguard Worker
115*25da2beaSAndroid Build Coastguard Worker cached_read = do_copy(fd, buf, ptr);
116*25da2beaSAndroid Build Coastguard Worker if (cached_read == -1)
117*25da2beaSAndroid Build Coastguard Worker return 1;
118*25da2beaSAndroid Build Coastguard Worker
119*25da2beaSAndroid Build Coastguard Worker cached_read = do_copy(fd, buf, ptr);
120*25da2beaSAndroid Build Coastguard Worker if (cached_read == -1)
121*25da2beaSAndroid Build Coastguard Worker return 1;
122*25da2beaSAndroid Build Coastguard Worker
123*25da2beaSAndroid Build Coastguard Worker ret = do_madvise(ring, ptr, FILE_SIZE, MADV_DONTNEED);
124*25da2beaSAndroid Build Coastguard Worker if (ret)
125*25da2beaSAndroid Build Coastguard Worker return 1;
126*25da2beaSAndroid Build Coastguard Worker
127*25da2beaSAndroid Build Coastguard Worker uncached_read = do_copy(fd, buf, ptr);
128*25da2beaSAndroid Build Coastguard Worker if (uncached_read == -1)
129*25da2beaSAndroid Build Coastguard Worker return 1;
130*25da2beaSAndroid Build Coastguard Worker
131*25da2beaSAndroid Build Coastguard Worker ret = do_madvise(ring, ptr, FILE_SIZE, MADV_DONTNEED);
132*25da2beaSAndroid Build Coastguard Worker if (ret)
133*25da2beaSAndroid Build Coastguard Worker return 1;
134*25da2beaSAndroid Build Coastguard Worker
135*25da2beaSAndroid Build Coastguard Worker ret = do_madvise(ring, ptr, FILE_SIZE, MADV_WILLNEED);
136*25da2beaSAndroid Build Coastguard Worker if (ret)
137*25da2beaSAndroid Build Coastguard Worker return 1;
138*25da2beaSAndroid Build Coastguard Worker
139*25da2beaSAndroid Build Coastguard Worker msync(ptr, FILE_SIZE, MS_SYNC);
140*25da2beaSAndroid Build Coastguard Worker
141*25da2beaSAndroid Build Coastguard Worker cached_read2 = do_copy(fd, buf, ptr);
142*25da2beaSAndroid Build Coastguard Worker if (cached_read2 == -1)
143*25da2beaSAndroid Build Coastguard Worker return 1;
144*25da2beaSAndroid Build Coastguard Worker
145*25da2beaSAndroid Build Coastguard Worker if (cached_read < uncached_read &&
146*25da2beaSAndroid Build Coastguard Worker cached_read2 < uncached_read)
147*25da2beaSAndroid Build Coastguard Worker return 0;
148*25da2beaSAndroid Build Coastguard Worker
149*25da2beaSAndroid Build Coastguard Worker return 2;
150*25da2beaSAndroid Build Coastguard Worker }
151*25da2beaSAndroid Build Coastguard Worker
main(int argc,char * argv[])152*25da2beaSAndroid Build Coastguard Worker int main(int argc, char *argv[])
153*25da2beaSAndroid Build Coastguard Worker {
154*25da2beaSAndroid Build Coastguard Worker struct io_uring ring;
155*25da2beaSAndroid Build Coastguard Worker int ret, i, good, bad;
156*25da2beaSAndroid Build Coastguard Worker char *fname;
157*25da2beaSAndroid Build Coastguard Worker
158*25da2beaSAndroid Build Coastguard Worker if (argc > 1) {
159*25da2beaSAndroid Build Coastguard Worker fname = argv[1];
160*25da2beaSAndroid Build Coastguard Worker } else {
161*25da2beaSAndroid Build Coastguard Worker fname = ".madvise.tmp";
162*25da2beaSAndroid Build Coastguard Worker t_create_file(fname, FILE_SIZE);
163*25da2beaSAndroid Build Coastguard Worker }
164*25da2beaSAndroid Build Coastguard Worker
165*25da2beaSAndroid Build Coastguard Worker if (io_uring_queue_init(8, &ring, 0)) {
166*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "ring creation failed\n");
167*25da2beaSAndroid Build Coastguard Worker goto err;
168*25da2beaSAndroid Build Coastguard Worker }
169*25da2beaSAndroid Build Coastguard Worker
170*25da2beaSAndroid Build Coastguard Worker good = bad = 0;
171*25da2beaSAndroid Build Coastguard Worker for (i = 0; i < LOOPS; i++) {
172*25da2beaSAndroid Build Coastguard Worker ret = test_madvise(&ring, fname);
173*25da2beaSAndroid Build Coastguard Worker if (ret == 1) {
174*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "test_madvise failed\n");
175*25da2beaSAndroid Build Coastguard Worker goto err;
176*25da2beaSAndroid Build Coastguard Worker } else if (!ret)
177*25da2beaSAndroid Build Coastguard Worker good++;
178*25da2beaSAndroid Build Coastguard Worker else if (ret == 2)
179*25da2beaSAndroid Build Coastguard Worker bad++;
180*25da2beaSAndroid Build Coastguard Worker if (i >= MIN_LOOPS && !bad)
181*25da2beaSAndroid Build Coastguard Worker break;
182*25da2beaSAndroid Build Coastguard Worker }
183*25da2beaSAndroid Build Coastguard Worker
184*25da2beaSAndroid Build Coastguard Worker /* too hard to reliably test, just ignore */
185*25da2beaSAndroid Build Coastguard Worker if (0 && bad > good)
186*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "Suspicious timings (%u > %u)\n", bad, good);
187*25da2beaSAndroid Build Coastguard Worker if (fname != argv[1])
188*25da2beaSAndroid Build Coastguard Worker unlink(fname);
189*25da2beaSAndroid Build Coastguard Worker io_uring_queue_exit(&ring);
190*25da2beaSAndroid Build Coastguard Worker return 0;
191*25da2beaSAndroid Build Coastguard Worker err:
192*25da2beaSAndroid Build Coastguard Worker if (fname != argv[1])
193*25da2beaSAndroid Build Coastguard Worker unlink(fname);
194*25da2beaSAndroid Build Coastguard Worker return 1;
195*25da2beaSAndroid Build Coastguard Worker }
196