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