1/*
2 Copyright (c) 2005-2019 Intel Corporation
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#define HARNESS_NO_PARSE_COMMAND_LINE 1
18
19#include <stdio.h>
20#include "tbb/scalable_allocator.h"
21
22class minimalAllocFree {
23public:
24 void operator()(int size) const {
25 tbb::scalable_allocator<char> a;
26 char* str = a.allocate( size );
27 a.deallocate( str, size );
28 }
29};
30
31#define HARNESS_TBBMALLOC_THREAD_SHUTDOWN 1
32#include "harness.h"
33
34template<typename Body, typename Arg>
35void RunThread(const Body& body, const Arg& arg) {
36 NativeParallelForTask<Arg,Body> job(arg, body);
37 job.start();
38 job.wait_to_finish();
39}
40
41/*--------------------------------------------------------------------*/
42// The regression test against bug #1518 where thread bootstrap allocations "leaked"
43
44#include "harness_memory.h"
45
46bool TestBootstrapLeak() {
47 /* In the bug 1518, each thread leaked ~384 bytes.
48 Initially, scalable allocator maps 1MB. Thus it is necessary to take out most of this space.
49 1MB is chunked into 16K blocks; of those, one block is for thread bootstrap, and one more
50 should be reserved for the test body. 62 blocks left, each can serve 15 objects of 1024 bytes.
51 */
52 const int alloc_size = 1024;
53 const int take_out_count = 15*62;
54
55 tbb::scalable_allocator<char> a;
56 char* array[take_out_count];
57 for( int i=0; i<take_out_count; ++i )
58 array[i] = a.allocate( alloc_size );
59
60 RunThread( minimalAllocFree(), alloc_size ); // for threading library to take some memory
61 size_t memory_in_use = GetMemoryUsage();
62 // Wait for memory usage data to "stabilize". The test number (1000) has nothing underneath.
63 for( int i=0; i<1000; i++) {
64 if( GetMemoryUsage()!=memory_in_use ) {
65 memory_in_use = GetMemoryUsage();
66 i = -1;
67 }
68 }
69
70 ptrdiff_t memory_leak = 0;
71 // Note that 16K bootstrap memory block is enough to serve 42 threads.
72 const int num_thread_runs = 200;
73 for (int run=0; run<3; run++) {
74 memory_in_use = GetMemoryUsage();
75 for( int i=0; i<num_thread_runs; ++i )
76 RunThread( minimalAllocFree(), alloc_size );
77
78 memory_leak = GetMemoryUsage() - memory_in_use;
79 if (!memory_leak)
80 break;
81 }
82 if( memory_leak>0 ) { // possibly too strong?
83 REPORT( "Error: memory leak of up to %ld bytes\n", static_cast<long>(memory_leak));
84 }
85
86 for( int i=0; i<take_out_count; ++i )
87 a.deallocate( array[i], alloc_size );
88
89 return memory_leak<=0;
90}
91
92/*--------------------------------------------------------------------*/
93// The regression test against a bug with incompatible semantics of msize and realloc
94
95bool TestReallocMsize(size_t startSz) {
96 bool passed = true;
97
98 char *buf = (char*)scalable_malloc(startSz);
99 ASSERT(buf, "");
100 size_t realSz = scalable_msize(buf);
101 ASSERT(realSz>=startSz, "scalable_msize must be not less then allocated size");
102 memset(buf, 'a', realSz-1);
103 buf[realSz-1] = 0;
104 char *buf1 = (char*)scalable_realloc(buf, 2*realSz);
105 ASSERT(buf1, "");
106 ASSERT(scalable_msize(buf1)>=2*realSz,
107 "scalable_msize must be not less then allocated size");
108 buf1[2*realSz-1] = 0;
109 if ( strspn(buf1, "a") < realSz-1 ) {
110 REPORT( "Error: data broken for %d Bytes object.\n", startSz);
111 passed = false;
112 }
113 scalable_free(buf1);
114
115 return passed;
116}
117
118// regression test against incorrect work of msize/realloc
119// for aligned objects
120void TestAlignedMsize()
121{
122 const int NUM = 4;
123 char *p[NUM];
124 size_t objSizes[NUM];
125 size_t allocSz[] = {4, 8, 512, 2*1024, 4*1024, 8*1024, 16*1024, 0};
126 size_t align[] = {8, 512, 2*1024, 4*1024, 8*1024, 16*1024, 0};
127
128 for (int a=0; align[a]; a++)
129 for (int s=0; allocSz[s]; s++) {
130 for (int i=0; i<NUM; i++) {
131 p[i] = (char*)scalable_aligned_malloc(allocSz[s], align[a]);
132 ASSERT(is_aligned(p[i], align[a]), NULL);
133 }
134
135 for (int i=0; i<NUM; i++) {
136 objSizes[i] = scalable_msize(p[i]);
137 ASSERT(objSizes[i] >= allocSz[s],
138 "allocated size must be not less than requested");
139 memset(p[i], i, objSizes[i]);
140 }
141 for (int i=0; i<NUM; i++) {
142 for (unsigned j=0; j<objSizes[i]; j++)
143 ASSERT(((char*)p[i])[j] == i, "Error: data broken");
144 }
145
146 for (int i=0; i<NUM; i++) {
147 p[i] = (char*)scalable_aligned_realloc(p[i], 2*allocSz[s], align[a]);
148 ASSERT(is_aligned(p[i], align[a]), NULL);
149 memset((char*)p[i]+allocSz[s], i+1, allocSz[s]);
150 }
151 for (int i=0; i<NUM; i++) {
152 for (unsigned j=0; j<allocSz[s]; j++)
153 ASSERT(((char*)p[i])[j] == i, "Error: data broken");
154 for (size_t j=allocSz[s]; j<2*allocSz[s]; j++)
155 ASSERT(((char*)p[i])[j] == i+1, "Error: data broken");
156 }
157 for (int i=0; i<NUM; i++)
158 scalable_free(p[i]);
159 }
160}
161
162/*--------------------------------------------------------------------*/
163// The main test function
164
165int TestMain () {
166 bool passed = true;
167 // Check whether memory usage data can be obtained; if not, skip test_bootstrap_leak.
168 if( GetMemoryUsage() )
169 passed &= TestBootstrapLeak();
170
171 // TestReallocMsize runs for each power of 2 and each Fibonacci number below 64K
172 for (size_t a=1, b=1, sum=1; sum<=64*1024; ) {
173 passed &= TestReallocMsize(sum);
174 a = b;
175 b = sum;
176 sum = a+b;
177 }
178 for (size_t a=2; a<=64*1024; a*=2)
179 passed &= TestReallocMsize(a);
180
181 ASSERT( passed, "Test failed" );
182
183 TestAlignedMsize();
184
185 return Harness::Done;
186}
187