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