1 /*
2 * Copyright (C) 2018 Samsung Electronics Co., 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 #include <cerrno>
17 #include <cstring>
18
19 #include <unistd.h>
20 #include <fcntl.h>
21 #include <sys/mman.h>
22 #include <sys/ioctl.h>
23
24 #include "ion_test_fixture.h"
25 #include "ion_test_define.h"
26
27 #define TEST_ALLOC_CACHED 1
28 #define TEST_ALLOC_BUDDY 2
29
30 class AllocateAPI : public IonAllocTest {
31 protected:
32 struct test_type_struct {
33 int type_flags;
34 const char *type_title;
35 };
checkZero(int fd,size_t size,unsigned long * val)36 off_t checkZero(int fd, size_t size, unsigned long *val) {
37 unsigned long *p = reinterpret_cast<unsigned long *>(mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
38 if (p == MAP_FAILED)
39 return -1;
40
41 off_t idx;
42 for (idx = 0; idx < static_cast<off_t>(size / sizeof(*p)); idx++) {
43 if (p[idx] != 0) {
44 if (val)
45 *val = p[idx];
46 break;
47 }
48 }
49
50 munmap(p, size);
51
52 return idx * sizeof(*p);
53 }
54
flushShrinker()55 void flushShrinker() {
56 int fd = open("/sys/kernel/debug/ion_system_heap_shrink", O_RDWR);
57 if (fd < 0)
58 return;
59
60 unsigned long val = mb(256); // This is very big enough to flush shrinker
61 if (write(fd, &val, sizeof(val)) < 0)
62 FAIL() << "Failed to write " << val << " to 'ion_system_heap_shrink': " << strerror(errno);
63 if (read(fd, &val, sizeof(val)) < 0)
64 FAIL() << "Failed to read from 'ion_system_heap_shrink': " << strerror(errno);
65 if (val > 0)
66 FAIL() << "ion_system_heap_shrink still has value " << val;
67 close(fd);
68 }
69 };
70
TEST_F(AllocateAPI,Allocate)71 TEST_F(AllocateAPI, Allocate)
72 {
73 static const size_t allocation_sizes[] = {
74 mkb(16, 716), mkb(12, 4), mkb(8, 912), mkb(4, 60), mkb(2, 520), mkb(1, 92),
75 mb(16), mb(12), mb(8), mb(4), mb(2), mb(1), kb(64), kb(4),
76 };
77 static const test_type_struct test_types[] = {
78 {0, "uncached"},
79 {TEST_ALLOC_CACHED, "cached"},
80 {TEST_ALLOC_BUDDY, "uncached|flush_pool"},
81 {TEST_ALLOC_CACHED | TEST_ALLOC_BUDDY, "cached|flush_pool"},
82 };
83
84 for (test_type_struct type: test_types) {
85 for (unsigned int i = 0; i < MAX_LEGACY_HEAP_IDS; i++) {
86 unsigned int heap_id = getModernHeapId(i);
87 unsigned int heapmask = 1 << getLegacyHeapId(i);
88
89 if (heap_id == ION_NUM_HEAP_IDS)
90 continue;
91 if ((type.type_flags & TEST_ALLOC_BUDDY) && !(getHeapFlags(heap_id) & ION_HEAPDATA_FLAGS_DEFER_FREE))
92 continue;
93
94 for (size_t size : allocation_sizes) {
95 if (size > getHeapSize(heap_id))
96 continue;
97
98 unsigned int flags = (type.type_flags & TEST_ALLOC_CACHED) ? ION_FLAG_CACHED : 0;
99 int fd;
100
101 SCOPED_TRACE(::testing::Message() << "heap: " << getHeapName(heap_id) << ", heap id: " << heap_id << ", heapmask: " << heapmask);
102 SCOPED_TRACE(::testing::Message() << "size: " << size << ", flags: " << flags);
103 SCOPED_TRACE(::testing::Message() << "test type: " << type.type_title);
104
105 if (type.type_flags & TEST_ALLOC_BUDDY)
106 flushShrinker();
107
108 EXPECT_LE(0, fd = exynos_ion_alloc(getIonFd(), size, heapmask, flags)) << ": " << strerror(errno);
109
110 EXPECT_LT(2, fd);
111 EXPECT_GT(1024, fd);
112 if (fd >= 0) {
113 if (!(getHeapFlags(heap_id) & ION_HEAPDATA_FLAGS_UNTOUCHABLE)) {
114 off_t erridx;
115 unsigned long val = 0;
116 EXPECT_EQ(static_cast<off_t>(size), erridx = checkZero(fd, size, &val))
117 << "non-zero " << val << " found at " << erridx << " byte";
118 }
119 EXPECT_EQ(0, close(fd));
120 }
121 }
122 }
123 }
124 }
125