1 /*
2 Copyright (c) 2014, 2021, Oracle and/or its affiliates.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License, version 2.0,
6 as published by the Free Software Foundation.
7
8 This program is also distributed with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation. The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have included with MySQL.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License, version 2.0, for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software Foundation,
22 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
23
24 // First include (the generated) my_config.h, to get correct platform defines.
25 #include "my_config.h"
26 #include <gtest/gtest.h>
27
28 #include "opt_costmodel.h"
29 #include "opt_costconstantcache.h"
30 #include "fake_table.h"
31 #include "test_utils.h"
32
33
34 namespace costmodel_unittest {
35
36 using my_testing::Server_initializer;
37
38 class CostModelTest : public ::testing::Test
39 {
40 protected:
SetUp()41 virtual void SetUp()
42 {
43 // Add a storage engine to the hton2plugin array.
44 // This is needed for the cost model to add cost constants
45 // for the storage engine
46 LEX_STRING engine_name= {C_STRING_WITH_LEN("InnoDB")};
47
48 hton2plugin[0]= new st_plugin_int();
49 hton2plugin[0]->name= engine_name;
50
51 initializer.SetUp();
52 }
TearDown()53 virtual void TearDown()
54 {
55 initializer.TearDown();
56 delete hton2plugin[0];
57 hton2plugin[0]= NULL;
58 }
59
thd()60 THD *thd() { return initializer.thd(); }
61
62 Server_initializer initializer;
63 };
64
65 /*
66 Tests for temporary tables that are not dependent on hard coded cost
67 constants.
68 */
test_tmptable_cost(const Cost_model_server * cm,Cost_model_server::enum_tmptable_type tmp_table_type)69 void test_tmptable_cost(const Cost_model_server *cm,
70 Cost_model_server::enum_tmptable_type tmp_table_type)
71 {
72 const uint rows= 3;
73
74 // Cost of inserting and reading data in a temporary table
75 EXPECT_EQ(cm->tmptable_readwrite_cost(tmp_table_type, rows, rows),
76 rows * cm->tmptable_readwrite_cost(tmp_table_type, 1.0, 1.0));
77 }
78
79
80 /*
81 Test the Cost_model_server interface.
82 */
TEST_F(CostModelTest,CostModelServer)83 TEST_F(CostModelTest, CostModelServer)
84 {
85 const uint rows= 3;
86
87 // Create and initialize the server cost model
88 Cost_model_server cm;
89 cm.init();
90
91 // Create and initialize a cost constant object that will be used
92 // for verifying default values for cost constants
93 const Server_cost_constants default_server_cost;
94
95 // Test row evaluate cost
96 EXPECT_EQ(cm.row_evaluate_cost(1.0), default_server_cost.row_evaluate_cost());
97 EXPECT_EQ(cm.row_evaluate_cost(rows),
98 rows * cm.row_evaluate_cost(1.0));
99
100 // Test key compare cost
101 EXPECT_EQ(cm.key_compare_cost(1.0), default_server_cost.key_compare_cost());
102 EXPECT_EQ(cm.key_compare_cost(rows), rows * cm.key_compare_cost(1.0));
103
104 // Cost of creating a tempoary table without inserting data into it
105 EXPECT_EQ(cm.tmptable_create_cost(Cost_model_server::MEMORY_TMPTABLE),
106 default_server_cost.memory_temptable_create_cost());
107 EXPECT_EQ(cm.tmptable_create_cost(Cost_model_server::DISK_TMPTABLE),
108 default_server_cost.disk_temptable_create_cost());
109
110 // Cost of inserting one row in a temporary table
111 EXPECT_EQ(cm.tmptable_readwrite_cost(Cost_model_server::MEMORY_TMPTABLE,
112 1.0, 0.0),
113 default_server_cost.memory_temptable_row_cost());
114 EXPECT_EQ(cm.tmptable_readwrite_cost(Cost_model_server::DISK_TMPTABLE,
115 1.0, 0.0),
116 default_server_cost.disk_temptable_row_cost());
117
118 // Cost of reading one row in a temporary table
119 EXPECT_EQ(cm.tmptable_readwrite_cost(Cost_model_server::MEMORY_TMPTABLE,
120 0.0, 1.0),
121 default_server_cost.memory_temptable_row_cost());
122 EXPECT_EQ(cm.tmptable_readwrite_cost(Cost_model_server::DISK_TMPTABLE,
123 0.0, 1.0),
124 default_server_cost.disk_temptable_row_cost());
125
126 // Tests for temporary tables that are independent of cost constants
127 test_tmptable_cost(&cm, Cost_model_server::MEMORY_TMPTABLE);
128 test_tmptable_cost(&cm, Cost_model_server::DISK_TMPTABLE);
129 }
130
131
132 /*
133 Test the Cost_model_table interface.
134 */
TEST_F(CostModelTest,CostModelTable)135 TEST_F(CostModelTest, CostModelTable)
136 {
137 const uint rows= 3;
138 const double blocks= 4.0;
139 const uint key= 0;
140
141 // A table is needed in order to initialize the table cost model
142 Fake_TABLE table(1, false);
143
144 // Create and initialize a cost model table object
145 Cost_model_server cost_model_server;
146 cost_model_server.init();
147 Cost_model_table cm;
148 cm.init(&cost_model_server, &table);
149
150 // Create and initialize a cost constant object that will be used
151 // for verifying default values for cost constants
152 const Server_cost_constants default_server_cost;
153 const SE_cost_constants default_engine_cost;
154
155 // Test row evaluate cost
156 EXPECT_EQ(cm.row_evaluate_cost(1.0), default_server_cost.row_evaluate_cost());
157 EXPECT_EQ(cm.row_evaluate_cost(rows),
158 rows * cm.row_evaluate_cost(1.0));
159
160 // Test key compare cost
161 EXPECT_EQ(cm.key_compare_cost(1.0), default_server_cost.key_compare_cost());
162 EXPECT_EQ(cm.key_compare_cost(rows),
163 rows * cm.key_compare_cost(1.0));
164
165 // Test io block read cost
166 EXPECT_EQ(cm.io_block_read_cost(1.0),
167 default_engine_cost.io_block_read_cost());
168 EXPECT_EQ(cm.io_block_read_cost(blocks),
169 blocks * cm.io_block_read_cost(1.0));
170
171 // Test page_read_cost() with table in memory buffer
172 EXPECT_EQ(cm.page_read_cost(1.0),
173 default_engine_cost.memory_block_read_cost());
174 EXPECT_EQ(cm.page_read_cost(blocks),
175 blocks * cm.page_read_cost(1.0));
176
177 // Test page_read_cost() with table data on disk
178 table.file->stats.table_in_mem_estimate= 0.0; // Table is on disk
179 EXPECT_EQ(cm.page_read_cost(1.0),
180 default_engine_cost.io_block_read_cost());
181 EXPECT_EQ(cm.page_read_cost(blocks),
182 blocks * cm.page_read_cost(1.0));
183
184 // Test page_read_cost_index() with index data in memory
185 table.key_info[key].set_in_memory_estimate(1.0); // Index is in memory
186 EXPECT_EQ(cm.page_read_cost_index(key, 1.0),
187 default_engine_cost.memory_block_read_cost());
188 EXPECT_EQ(cm.page_read_cost_index(key, blocks),
189 blocks * cm.page_read_cost_index(key, 1.0));
190
191 // Test page_read_oost_index() with index data on disk
192 table.key_info[key].set_in_memory_estimate(0.0); // Index is on disk
193 EXPECT_EQ(cm.page_read_cost_index(key, 1.0),
194 default_engine_cost.io_block_read_cost());
195 EXPECT_EQ(cm.page_read_cost_index(key, blocks),
196 blocks * cm.page_read_cost_index(key, 1.0));
197
198 // Test disk seek base cost
199 EXPECT_EQ(cm.disk_seek_base_cost(),
200 DISK_SEEK_BASE_COST * cm.io_block_read_cost(1.0));
201
202 // Test disk seek cost
203 EXPECT_GT(cm.disk_seek_cost(2.0), cm.disk_seek_cost(1.0));
204 }
205
206 }
207