1 /*
2  * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
3  * Copyright (c) 2020 SAP SE. All rights reserved.
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This code is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License version 2 only, as
8  * published by the Free Software Foundation.
9  *
10  * This code is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13  * version 2 for more details (a copy is included in the LICENSE file that
14  * accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License version
17  * 2 along with this work; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19  *
20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21  * or visit www.oracle.com if you need additional information or have any
22  * questions.
23  *
24  */
25 
26 #include "precompiled.hpp"
27 #include "memory/metaspace/chunkHeaderPool.hpp"
28 #include "memory/metaspace/counters.hpp"
29 #include "memory/metaspace/metachunk.hpp"
30 //#define LOG_PLEASE
31 #include "metaspaceGtestCommon.hpp"
32 
33 using metaspace::ChunkHeaderPool;
34 using metaspace::Metachunk;
35 using metaspace::SizeCounter;
36 
37 class ChunkHeaderPoolTest {
38 
39   static const size_t max_cap = 0x1000;
40 
41   ChunkHeaderPool _pool;
42 
43   // Array of the same size as the pool max capacity; holds the allocated elements.
44   Metachunk* _elems[max_cap];
45   SizeCounter _num_allocated;
46 
attempt_free_at(size_t index)47   void attempt_free_at(size_t index) {
48 
49     LOG("attempt_free_at " SIZE_FORMAT ".", index);
50 
51     if (_elems[index] == NULL) {
52       return;
53     }
54 
55     _pool.return_chunk_header(_elems[index]);
56     _elems[index] = NULL;
57 
58     _num_allocated.decrement();
59     DEBUG_ONLY(_num_allocated.check(_pool.used());)
60 
61     DEBUG_ONLY(_pool.verify();)
62 
63   }
64 
attempt_allocate_at(size_t index)65   void attempt_allocate_at(size_t index) {
66 
67     LOG("attempt_allocate_at " SIZE_FORMAT ".", index);
68 
69     if (_elems[index] != NULL) {
70       return;
71     }
72 
73     Metachunk* c = _pool.allocate_chunk_header();
74     EXPECT_NOT_NULL(c);
75     _elems[index] = c;
76     c->set_free();
77 
78     _num_allocated.increment();
79     DEBUG_ONLY(_num_allocated.check(_pool.used());)
80 
81     DEBUG_ONLY(_pool.verify();)
82   }
83 
attempt_allocate_or_free_at(size_t index)84   void attempt_allocate_or_free_at(size_t index) {
85     if (_elems[index] == NULL) {
86       attempt_allocate_at(index);
87     } else {
88       attempt_free_at(index);
89     }
90   }
91 
92   // Randomly allocate from the pool and free. Slight preference for allocation.
test_random_alloc_free(int num_iterations)93   void test_random_alloc_free(int num_iterations) {
94 
95     for (int iter = 0; iter < num_iterations; iter++) {
96       size_t index = (size_t)os::random() % max_cap;
97       attempt_allocate_or_free_at(index);
98     }
99 
100     DEBUG_ONLY(_pool.verify();)
101 
102   }
103 
test_once()104   static void test_once() {
105     ChunkHeaderPoolTest test;
106     test.test_random_alloc_free(100);
107   }
108 
109 public:
110 
ChunkHeaderPoolTest()111   ChunkHeaderPoolTest() : _pool() {
112     memset(_elems, 0, sizeof(_elems));
113   }
114 
run_tests()115   static void run_tests() {
116     for (int i = 0; i < 1000; i++) {
117       test_once();
118     }
119   }
120 
121 };
122 
TEST_VM(metaspace,chunk_header_pool_basics)123 TEST_VM(metaspace, chunk_header_pool_basics) {
124 
125   ChunkHeaderPool pool;
126   EXPECT_EQ(pool.used(), (int)0);
127   EXPECT_EQ(pool.freelist_size(), (int)0);
128 
129   Metachunk* header = pool.allocate_chunk_header();
130   EXPECT_NOT_NULL(header);
131   EXPECT_EQ(pool.used(), 1);
132   EXPECT_EQ(pool.freelist_size(), (int)0);
133 
134   header->set_free();
135   pool.return_chunk_header(header);
136   EXPECT_EQ(pool.used(), (int)0);
137   EXPECT_EQ(pool.freelist_size(), 1);
138 
139   header = pool.allocate_chunk_header();
140   EXPECT_NOT_NULL(header);
141   EXPECT_EQ(pool.used(), 1);
142   EXPECT_EQ(pool.freelist_size(), (int)0);
143 
144   header->set_free();
145   pool.return_chunk_header(header);
146   EXPECT_EQ(pool.used(), (int)0);
147   EXPECT_EQ(pool.freelist_size(), 1);
148 
149 }
150 
TEST_VM(metaspace,chunk_header_pool)151 TEST_VM(metaspace, chunk_header_pool) {
152   ChunkHeaderPoolTest::run_tests();
153 }
154