You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
227 lines
6.2 KiB
227 lines
6.2 KiB
/*
|
|
* Copyright 2020, 2021 Linaro Ltd.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include <dirent.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/types.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
|
|
#include <drm/drm.h>
|
|
#include <linux/dma-buf.h>
|
|
#include <linux/dma-heap.h>
|
|
#include <linux/ion.h>
|
|
#include <linux/ion_4.19.h>
|
|
|
|
#define HEAP_DEVPATH "/dev/dma_heap"
|
|
#define ION_DEVPATH "/dev/ion"
|
|
|
|
#define ONE_MEG (1024 * 1024)
|
|
#define NUM_SIZES 4
|
|
int sizes[NUM_SIZES] = {4 * 1024, ONE_MEG, 8 * ONE_MEG, 32 * ONE_MEG};
|
|
|
|
#define NUM_ITERS 5000
|
|
#define NSEC_PER_SEC 1000000000LL
|
|
#define MAX_HEAP_COUNT ION_HEAP_TYPE_CUSTOM
|
|
|
|
int ion_heap_open(void) {
|
|
int ret, fd;
|
|
char buf[256];
|
|
|
|
ret = sprintf(buf, "%s", ION_DEVPATH);
|
|
if (ret < 0) {
|
|
printf("sprintf failed!\n");
|
|
return ret;
|
|
}
|
|
|
|
fd = open(buf, O_RDWR);
|
|
if (fd < 0) printf("open %s failed!\n", buf);
|
|
return fd;
|
|
}
|
|
|
|
int ion_heap_alloc(int ionfd, int heap_id, size_t len, unsigned int flags, int* dmabuf_fd) {
|
|
struct ion_new_allocation_data alloc_data;
|
|
int ret;
|
|
|
|
memset(&alloc_data, 0, sizeof(alloc_data));
|
|
alloc_data.heap_id_mask = 1 << heap_id;
|
|
alloc_data.flags = flags;
|
|
alloc_data.len = len;
|
|
|
|
/* Allocate memory for this ION client as per heap_type */
|
|
ret = ioctl(ionfd, ION_IOC_NEW_ALLOC, &alloc_data);
|
|
|
|
*dmabuf_fd = alloc_data.fd;
|
|
|
|
return ret;
|
|
}
|
|
|
|
int dmabuf_heap_open(char* name) {
|
|
int ret, fd;
|
|
char buf[256];
|
|
|
|
ret = sprintf(buf, "%s/%s", HEAP_DEVPATH, name);
|
|
if (ret < 0) {
|
|
printf("sprintf failed!\n");
|
|
return ret;
|
|
}
|
|
|
|
fd = open(buf, O_RDWR);
|
|
if (fd < 0) printf("open %s failed!\n", buf);
|
|
return fd;
|
|
}
|
|
|
|
int dmabuf_heap_alloc(int fd, size_t len, unsigned int flags, int* dmabuf_fd) {
|
|
struct dma_heap_allocation_data data = {
|
|
.len = len,
|
|
.fd_flags = O_RDWR | O_CLOEXEC,
|
|
.heap_flags = flags,
|
|
};
|
|
int ret;
|
|
|
|
if (dmabuf_fd == NULL) return -EINVAL;
|
|
|
|
ret = ioctl(fd, DMA_HEAP_IOCTL_ALLOC, &data);
|
|
if (ret < 0) return ret;
|
|
*dmabuf_fd = (int)data.fd;
|
|
return ret;
|
|
}
|
|
|
|
void dmabuf_sync(int fd, int start_stop) {
|
|
struct dma_buf_sync sync = {0};
|
|
int ret;
|
|
|
|
sync.flags = start_stop | DMA_BUF_SYNC_RW;
|
|
ret = ioctl(fd, DMA_BUF_IOCTL_SYNC, &sync);
|
|
if (ret) printf("sync failed %d\n", errno);
|
|
}
|
|
|
|
void ion_heap_bench(unsigned int heap_type, int size, int flags) {
|
|
int heap_id;
|
|
int ionfd = -1, dmabuf_fd = -1;
|
|
struct ion_heap_query query;
|
|
struct ion_heap_data heap_data[MAX_HEAP_COUNT];
|
|
struct timespec ts_start, ts_end;
|
|
long long start, end;
|
|
int ret;
|
|
unsigned int i;
|
|
|
|
ionfd = ion_heap_open();
|
|
if (ionfd < 0) return;
|
|
|
|
memset(&query, 0, sizeof(query));
|
|
query.cnt = MAX_HEAP_COUNT;
|
|
query.heaps = (unsigned long int)&heap_data[0];
|
|
/* Query ION heap_id_mask from ION heap */
|
|
ret = ioctl(ionfd, ION_IOC_HEAP_QUERY, &query);
|
|
if (ret < 0) {
|
|
printf("<%s>: Failed: ION_IOC_HEAP_QUERY: %s\n", __func__, strerror(errno));
|
|
goto out;
|
|
}
|
|
heap_id = MAX_HEAP_COUNT + 1;
|
|
for (i = 0; i < query.cnt; i++) {
|
|
if (heap_data[i].type == heap_type) {
|
|
heap_id = heap_data[i].heap_id;
|
|
break;
|
|
}
|
|
}
|
|
if (heap_id > MAX_HEAP_COUNT) {
|
|
printf("<%s>: ERROR: heap type does not exists\n", __func__);
|
|
goto out;
|
|
}
|
|
|
|
clock_gettime(CLOCK_MONOTONIC, &ts_start);
|
|
for (i = 0; i < NUM_ITERS; i++) {
|
|
ret = ion_heap_alloc(ionfd, heap_id, size, flags, &dmabuf_fd);
|
|
if (ret) goto out;
|
|
close(dmabuf_fd);
|
|
}
|
|
clock_gettime(CLOCK_MONOTONIC, &ts_end);
|
|
|
|
start = ts_start.tv_sec * NSEC_PER_SEC + ts_start.tv_nsec;
|
|
end = ts_end.tv_sec * NSEC_PER_SEC + ts_end.tv_nsec;
|
|
|
|
printf("ion heap: alloc %d bytes %i times in %lld ns \t %lld ns/call\n", size, NUM_ITERS,
|
|
end - start, (end - start) / NUM_ITERS);
|
|
out:
|
|
if (ionfd >= 0) close(ionfd);
|
|
}
|
|
|
|
void dmabuf_heap_bench(char* heap_name, int size) {
|
|
int heap_fd = -1, dmabuf_fd = -1;
|
|
struct timespec ts_start, ts_end;
|
|
long long start, end;
|
|
int ret;
|
|
int i;
|
|
|
|
heap_fd = dmabuf_heap_open(heap_name);
|
|
if (heap_fd < 0) return;
|
|
|
|
clock_gettime(CLOCK_MONOTONIC, &ts_start);
|
|
for (i = 0; i < NUM_ITERS; i++) {
|
|
ret = dmabuf_heap_alloc(heap_fd, size, 0, &dmabuf_fd);
|
|
if (ret) goto out;
|
|
close(dmabuf_fd);
|
|
}
|
|
clock_gettime(CLOCK_MONOTONIC, &ts_end);
|
|
|
|
start = ts_start.tv_sec * NSEC_PER_SEC + ts_start.tv_nsec;
|
|
end = ts_end.tv_sec * NSEC_PER_SEC + ts_end.tv_nsec;
|
|
|
|
printf("dmabuf heap: alloc %d bytes %i times in %lld ns \t %lld ns/call\n", size, NUM_ITERS,
|
|
end - start, (end - start) / NUM_ITERS);
|
|
out:
|
|
if (heap_fd >= 0) close(heap_fd);
|
|
}
|
|
|
|
int main(int argc, char* argv[]) {
|
|
char* dmabuf_heap_name;
|
|
unsigned int ion_heap_type;
|
|
int ion_flags = 0;
|
|
int testing_ion = 0;
|
|
int i;
|
|
if (argc < 2) {
|
|
printf("Usage %s [-i <ion heap type> <ion heap flags>] <dmabuf heap name>\n", argv[0]);
|
|
return -1;
|
|
}
|
|
|
|
if (argv[1][0] == '-' && argv[1][1] == 'i') {
|
|
testing_ion = 1;
|
|
ion_heap_type = strtol(argv[2], NULL, 0);
|
|
ion_flags = strtol(argv[3], NULL, 0);
|
|
dmabuf_heap_name = argv[4];
|
|
} else {
|
|
dmabuf_heap_name = argv[1];
|
|
}
|
|
|
|
printf("Testing dmabuf %s", dmabuf_heap_name);
|
|
if (testing_ion) printf(" vs ion heaptype %d (flags: 0x%x)", ion_heap_type, ion_flags);
|
|
printf("\n---------------------------------------------\n");
|
|
for (i = 0; i < NUM_SIZES; i++) {
|
|
dmabuf_heap_bench(dmabuf_heap_name, sizes[i]);
|
|
if (testing_ion) ion_heap_bench(ion_heap_type, sizes[i], ion_flags);
|
|
}
|
|
|
|
return 0;
|
|
}
|