1#include "PerformanceTestInfo.h"
2#include <Common/getMultipleKeysFromConfig.h>
3#include <Common/SettingsChanges.h>
4#include <IO/ReadBufferFromFile.h>
5#include <IO/ReadHelpers.h>
6#include <IO/WriteBufferFromFile.h>
7#include "applySubstitutions.h"
8#include <filesystem>
9#include <iostream>
10
11
12namespace DB
13{
14namespace ErrorCodes
15{
16extern const int BAD_ARGUMENTS;
17}
18
19namespace
20{
21
22void extractSettings(
23 const XMLConfigurationPtr & config,
24 const std::string & key,
25 const Strings & settings_list,
26 SettingsChanges & settings_to_apply)
27{
28 for (const std::string & setup : settings_list)
29 {
30 if (setup == "profile")
31 continue;
32
33 std::string value = config->getString(key + "." + setup);
34 if (value.empty())
35 value = "true";
36
37 settings_to_apply.emplace_back(SettingChange{setup, value});
38 }
39}
40
41}
42
43
44namespace fs = std::filesystem;
45
46PerformanceTestInfo::PerformanceTestInfo(
47 XMLConfigurationPtr config,
48 const std::string & profiles_file_,
49 const Settings & global_settings_)
50 : profiles_file(profiles_file_)
51 , settings(global_settings_)
52{
53 path = config->getString("path");
54 test_name = fs::path(path).stem().string();
55 if (config->has("main_metric"))
56 {
57 Strings main_metrics;
58 config->keys("main_metric", main_metrics);
59 if (main_metrics.size())
60 main_metric = main_metrics[0];
61 }
62
63 applySettings(config);
64 extractQueries(config);
65 extractAuxiliaryQueries(config);
66 processSubstitutions(config);
67 getExecutionType(config);
68 getStopConditions(config);
69}
70
71void PerformanceTestInfo::applySettings(XMLConfigurationPtr config)
72{
73 if (config->has("settings"))
74 {
75 SettingsChanges settings_to_apply;
76 Strings config_settings;
77 config->keys("settings", config_settings);
78
79 auto settings_contain = [&config_settings] (const std::string & setting)
80 {
81 auto position = std::find(config_settings.begin(), config_settings.end(), setting);
82 return position != config_settings.end();
83
84 };
85 /// Preprocess configuration file
86 if (settings_contain("profile"))
87 {
88 if (!profiles_file.empty())
89 {
90 std::string profile_name = config->getString("settings.profile");
91 XMLConfigurationPtr profiles_config(new XMLConfiguration(profiles_file));
92
93 Strings profile_settings;
94 profiles_config->keys("profiles." + profile_name, profile_settings);
95
96 extractSettings(profiles_config, "profiles." + profile_name, profile_settings, settings_to_apply);
97 }
98 }
99
100 extractSettings(config, "settings", config_settings, settings_to_apply);
101 settings.applyChanges(settings_to_apply);
102
103 if (settings_contain("average_rows_speed_precision"))
104 TestStats::avg_rows_speed_precision =
105 config->getDouble("settings.average_rows_speed_precision");
106
107 if (settings_contain("average_bytes_speed_precision"))
108 TestStats::avg_bytes_speed_precision =
109 config->getDouble("settings.average_bytes_speed_precision");
110 }
111}
112
113void PerformanceTestInfo::extractQueries(XMLConfigurationPtr config)
114{
115 if (config->has("query"))
116 queries = getMultipleValuesFromConfig(*config, "", "query");
117
118 if (config->has("query_file"))
119 {
120 const std::string filename = config->getString("query_file");
121 if (filename.empty())
122 throw Exception("Empty file name", ErrorCodes::BAD_ARGUMENTS);
123
124 bool tsv = fs::path(filename).extension().string() == ".tsv";
125
126 ReadBufferFromFile query_file(filename);
127 std::string query;
128
129 if (tsv)
130 {
131 while (!query_file.eof())
132 {
133 readEscapedString(query, query_file);
134 assertChar('\n', query_file);
135 queries.push_back(query);
136 }
137 }
138 else
139 {
140 readStringUntilEOF(query, query_file);
141 queries.push_back(query);
142 }
143 }
144
145 if (queries.empty())
146 throw Exception("Did not find any query to execute: " + test_name,
147 ErrorCodes::BAD_ARGUMENTS);
148}
149
150void PerformanceTestInfo::processSubstitutions(XMLConfigurationPtr config)
151{
152 if (config->has("substitutions"))
153 {
154 /// Make "subconfig" of inner xml block
155 ConfigurationPtr substitutions_view(config->createView("substitutions"));
156 constructSubstitutions(substitutions_view, substitutions);
157
158 auto create_and_fill_queries_preformat = create_and_fill_queries;
159 create_and_fill_queries.clear();
160 for (const auto & query : create_and_fill_queries_preformat)
161 {
162 auto formatted = formatQueries(query, substitutions);
163 create_and_fill_queries.insert(create_and_fill_queries.end(), formatted.begin(), formatted.end());
164 }
165
166 auto queries_preformat = queries;
167 queries.clear();
168 for (const auto & query : queries_preformat)
169 {
170 auto formatted = formatQueries(query, substitutions);
171 queries.insert(queries.end(), formatted.begin(), formatted.end());
172 }
173
174 auto drop_queries_preformat = drop_queries;
175 drop_queries.clear();
176 for (const auto & query : drop_queries_preformat)
177 {
178 auto formatted = formatQueries(query, substitutions);
179 drop_queries.insert(drop_queries.end(), formatted.begin(), formatted.end());
180 }
181 }
182}
183
184void PerformanceTestInfo::getExecutionType(XMLConfigurationPtr config)
185{
186 if (!config->has("type"))
187 throw Exception("Missing type property in config: " + test_name,
188 ErrorCodes::BAD_ARGUMENTS);
189
190 std::string config_exec_type = config->getString("type");
191 if (config_exec_type == "loop")
192 exec_type = ExecutionType::Loop;
193 else if (config_exec_type == "once")
194 exec_type = ExecutionType::Once;
195 else
196 throw Exception("Unknown type " + config_exec_type + " in :" + test_name,
197 ErrorCodes::BAD_ARGUMENTS);
198}
199
200
201void PerformanceTestInfo::getStopConditions(XMLConfigurationPtr config)
202{
203 TestStopConditions stop_conditions_template;
204 if (config->has("stop_conditions"))
205 {
206 ConfigurationPtr stop_conditions_config(config->createView("stop_conditions"));
207 stop_conditions_template.loadFromConfig(stop_conditions_config);
208 }
209
210 if (stop_conditions_template.empty())
211 throw Exception("No termination conditions were found in config",
212 ErrorCodes::BAD_ARGUMENTS);
213
214 times_to_run = config->getUInt("times_to_run", 1);
215
216 for (size_t i = 0; i < times_to_run * queries.size(); ++i)
217 stop_conditions_by_run.push_back(stop_conditions_template);
218
219}
220
221void PerformanceTestInfo::extractAuxiliaryQueries(XMLConfigurationPtr config)
222{
223 if (config->has("create_query"))
224 {
225 create_and_fill_queries = getMultipleValuesFromConfig(*config, "", "create_query");
226 }
227
228 if (config->has("fill_query"))
229 {
230 auto fill_queries = getMultipleValuesFromConfig(*config, "", "fill_query");
231 create_and_fill_queries.insert(create_and_fill_queries.end(), fill_queries.begin(), fill_queries.end());
232 }
233
234 if (config->has("drop_query"))
235 {
236 drop_queries = getMultipleValuesFromConfig(*config, "", "drop_query");
237 }
238}
239
240}
241