1 /*
2 * Copyright 2020, 2021 Linaro Ltd.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <dirent.h>
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <stdint.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sys/ioctl.h>
25 #include <sys/mman.h>
26 #include <sys/types.h>
27 #include <time.h>
28 #include <unistd.h>
29
30 #include <drm/drm.h>
31 #include <linux/dma-buf.h>
32 #include <linux/dma-heap.h>
33 #include <linux/ion.h>
34 #include <linux/ion_4.19.h>
35
36 #define HEAP_DEVPATH "/dev/dma_heap"
37 #define ION_DEVPATH "/dev/ion"
38
39 #define ONE_MEG (1024 * 1024)
40 #define NUM_SIZES 4
41 int sizes[NUM_SIZES] = {4 * 1024, ONE_MEG, 8 * ONE_MEG, 32 * ONE_MEG};
42
43 #define NUM_ITERS 5000
44 #define NSEC_PER_SEC 1000000000LL
45 #define MAX_HEAP_COUNT ION_HEAP_TYPE_CUSTOM
46
ion_heap_open(void)47 int ion_heap_open(void) {
48 int ret, fd;
49 char buf[256];
50
51 ret = sprintf(buf, "%s", ION_DEVPATH);
52 if (ret < 0) {
53 printf("sprintf failed!\n");
54 return ret;
55 }
56
57 fd = open(buf, O_RDWR);
58 if (fd < 0) printf("open %s failed!\n", buf);
59 return fd;
60 }
61
ion_heap_alloc(int ionfd,int heap_id,size_t len,unsigned int flags,int * dmabuf_fd)62 int ion_heap_alloc(int ionfd, int heap_id, size_t len, unsigned int flags, int* dmabuf_fd) {
63 struct ion_new_allocation_data alloc_data;
64 int ret;
65
66 memset(&alloc_data, 0, sizeof(alloc_data));
67 alloc_data.heap_id_mask = 1 << heap_id;
68 alloc_data.flags = flags;
69 alloc_data.len = len;
70
71 /* Allocate memory for this ION client as per heap_type */
72 ret = ioctl(ionfd, ION_IOC_NEW_ALLOC, &alloc_data);
73
74 *dmabuf_fd = alloc_data.fd;
75
76 return ret;
77 }
78
dmabuf_heap_open(char * name)79 int dmabuf_heap_open(char* name) {
80 int ret, fd;
81 char buf[256];
82
83 ret = sprintf(buf, "%s/%s", HEAP_DEVPATH, name);
84 if (ret < 0) {
85 printf("sprintf failed!\n");
86 return ret;
87 }
88
89 fd = open(buf, O_RDWR);
90 if (fd < 0) printf("open %s failed!\n", buf);
91 return fd;
92 }
93
dmabuf_heap_alloc(int fd,size_t len,unsigned int flags,int * dmabuf_fd)94 int dmabuf_heap_alloc(int fd, size_t len, unsigned int flags, int* dmabuf_fd) {
95 struct dma_heap_allocation_data data = {
96 .len = len,
97 .fd_flags = O_RDWR | O_CLOEXEC,
98 .heap_flags = flags,
99 };
100 int ret;
101
102 if (dmabuf_fd == NULL) return -EINVAL;
103
104 ret = ioctl(fd, DMA_HEAP_IOCTL_ALLOC, &data);
105 if (ret < 0) return ret;
106 *dmabuf_fd = (int)data.fd;
107 return ret;
108 }
109
dmabuf_sync(int fd,int start_stop)110 void dmabuf_sync(int fd, int start_stop) {
111 struct dma_buf_sync sync = {0};
112 int ret;
113
114 sync.flags = start_stop | DMA_BUF_SYNC_RW;
115 ret = ioctl(fd, DMA_BUF_IOCTL_SYNC, &sync);
116 if (ret) printf("sync failed %d\n", errno);
117 }
118
ion_heap_bench(unsigned int heap_type,int size,int flags)119 void ion_heap_bench(unsigned int heap_type, int size, int flags) {
120 int heap_id;
121 int ionfd = -1, dmabuf_fd = -1;
122 struct ion_heap_query query;
123 struct ion_heap_data heap_data[MAX_HEAP_COUNT];
124 struct timespec ts_start, ts_end;
125 long long start, end;
126 int ret;
127 unsigned int i;
128
129 ionfd = ion_heap_open();
130 if (ionfd < 0) return;
131
132 memset(&query, 0, sizeof(query));
133 query.cnt = MAX_HEAP_COUNT;
134 query.heaps = (unsigned long int)&heap_data[0];
135 /* Query ION heap_id_mask from ION heap */
136 ret = ioctl(ionfd, ION_IOC_HEAP_QUERY, &query);
137 if (ret < 0) {
138 printf("<%s>: Failed: ION_IOC_HEAP_QUERY: %s\n", __func__, strerror(errno));
139 goto out;
140 }
141 heap_id = MAX_HEAP_COUNT + 1;
142 for (i = 0; i < query.cnt; i++) {
143 if (heap_data[i].type == heap_type) {
144 heap_id = heap_data[i].heap_id;
145 break;
146 }
147 }
148 if (heap_id > MAX_HEAP_COUNT) {
149 printf("<%s>: ERROR: heap type does not exists\n", __func__);
150 goto out;
151 }
152
153 clock_gettime(CLOCK_MONOTONIC, &ts_start);
154 for (i = 0; i < NUM_ITERS; i++) {
155 ret = ion_heap_alloc(ionfd, heap_id, size, flags, &dmabuf_fd);
156 if (ret) goto out;
157 close(dmabuf_fd);
158 }
159 clock_gettime(CLOCK_MONOTONIC, &ts_end);
160
161 start = ts_start.tv_sec * NSEC_PER_SEC + ts_start.tv_nsec;
162 end = ts_end.tv_sec * NSEC_PER_SEC + ts_end.tv_nsec;
163
164 printf("ion heap: alloc %d bytes %i times in %lld ns \t %lld ns/call\n", size, NUM_ITERS,
165 end - start, (end - start) / NUM_ITERS);
166 out:
167 if (ionfd >= 0) close(ionfd);
168 }
169
dmabuf_heap_bench(char * heap_name,int size)170 void dmabuf_heap_bench(char* heap_name, int size) {
171 int heap_fd = -1, dmabuf_fd = -1;
172 struct timespec ts_start, ts_end;
173 long long start, end;
174 int ret;
175 int i;
176
177 heap_fd = dmabuf_heap_open(heap_name);
178 if (heap_fd < 0) return;
179
180 clock_gettime(CLOCK_MONOTONIC, &ts_start);
181 for (i = 0; i < NUM_ITERS; i++) {
182 ret = dmabuf_heap_alloc(heap_fd, size, 0, &dmabuf_fd);
183 if (ret) goto out;
184 close(dmabuf_fd);
185 }
186 clock_gettime(CLOCK_MONOTONIC, &ts_end);
187
188 start = ts_start.tv_sec * NSEC_PER_SEC + ts_start.tv_nsec;
189 end = ts_end.tv_sec * NSEC_PER_SEC + ts_end.tv_nsec;
190
191 printf("dmabuf heap: alloc %d bytes %i times in %lld ns \t %lld ns/call\n", size, NUM_ITERS,
192 end - start, (end - start) / NUM_ITERS);
193 out:
194 if (heap_fd >= 0) close(heap_fd);
195 }
196
main(int argc,char * argv[])197 int main(int argc, char* argv[]) {
198 char* dmabuf_heap_name;
199 unsigned int ion_heap_type;
200 int ion_flags = 0;
201 int testing_ion = 0;
202 int i;
203 if (argc < 2) {
204 printf("Usage %s [-i <ion heap type> <ion heap flags>] <dmabuf heap name>\n", argv[0]);
205 return -1;
206 }
207
208 if (argv[1][0] == '-' && argv[1][1] == 'i') {
209 testing_ion = 1;
210 ion_heap_type = strtol(argv[2], NULL, 0);
211 ion_flags = strtol(argv[3], NULL, 0);
212 dmabuf_heap_name = argv[4];
213 } else {
214 dmabuf_heap_name = argv[1];
215 }
216
217 printf("Testing dmabuf %s", dmabuf_heap_name);
218 if (testing_ion) printf(" vs ion heaptype %d (flags: 0x%x)", ion_heap_type, ion_flags);
219 printf("\n---------------------------------------------\n");
220 for (i = 0; i < NUM_SIZES; i++) {
221 dmabuf_heap_bench(dmabuf_heap_name, sizes[i]);
222 if (testing_ion) ion_heap_bench(ion_heap_type, sizes[i], ion_flags);
223 }
224
225 return 0;
226 }
227