1515 You should have received a copy of the GNU General Public License
1616 along with SBG Partitioner. If not, see <http://www.gnu.org/licenses/>.
1717
18- ******************************************************************************/
18+ ******************************************************************************/
1919
2020#include < chrono>
2121#include < filesystem>
3131#include " kernighan_lin_partitioner.hpp"
3232#include " partition_graph.hpp"
3333#include " partition_metrics_api.hpp"
34+ #include " sbg_partitioner_log.hpp"
3435
3536using namespace std ;
3637
3738using namespace sbg_partitioner ;
3839
40+
41+ static void read_configuration_file (const string& filename, PartitionerParams& params)
42+ {
43+
44+ // helper function
45+ auto to_bool = [](string& str) {
46+ std::transform (str.begin (), str.end (), str.begin (), ::tolower);
47+ std::istringstream is (str);
48+ bool b;
49+ is >> std::boolalpha >> b;
50+ return b;
51+ };
52+
53+ ifstream ifs (filename);
54+ string line;
55+ while (std::getline (ifs, line)) {
56+ std::istringstream is_line (line);
57+ std::string key;
58+ if (std::getline (is_line, key, ' =' )) {
59+ std::string value;
60+ if (std::getline (is_line, value)) {
61+ if (key == " filename" ) {
62+ params.filename = value;
63+ } else if (key == " partitions" ) {
64+ params.number_of_partitions = stoi (value);
65+ } else if (key == " imbalance" ) {
66+ params.epsilon = stof (value);
67+ } else if (key == " multithreading" ) {
68+ params.enable_multithreading = to_bool (value);
69+ } else if (key == " initial_partition_strategy" ) {
70+ params.initial_partition_strategy = InitialPartitionStrategy (stoi (value));
71+ } else if (key == " metrics" ) {
72+ params.compute_metrics = to_bool (value);
73+ } else if (key == " partitions_directory" ) {
74+ params.directory = value;
75+ } else {
76+ cerr << " Key " << key << " not found, it will be ignored" << endl;
77+ }
78+ }
79+ }
80+ }
81+ }
82+
83+
3984static void usage ()
4085{
4186 cout << " Usage sbg-partitioner" << endl;
4287 cout << endl;
88+
89+ cout << " -c, --config-filename Path to the configuration file, a file with key/values "
90+ " that represents the partitioner configuration. If a flag and value by configuration "
91+ " file are passed, the flag will be used."
92+ << endl;
4393 cout << " -f, --filename Path to the input file, a json file that represents "
4494 " the model we want to partitionate."
4595 << endl;
@@ -66,6 +116,7 @@ static void usage()
66116 cout << " SBG Partitioner home page: https://github.com/CIFASIS/sbg-partitioner " << endl;
67117}
68118
119+
69120static void version ()
70121{
71122 cout << " SBG Partitioner 1.0.0" << endl;
@@ -74,6 +125,7 @@ static void version()
74125 cout << " There is NO WARRANTY, to the extent permitted by law." << endl;
75126}
76127
128+
77129void sort_before_print (PartitionMap partitions, const SBG::LIB::WeightedSBGraph& sb_graph, SBG::LIB::SetAF& set_fact)
78130{
79131 for (auto & p : partitions) {
@@ -82,6 +134,7 @@ void sort_before_print(PartitionMap partitions, const SBG::LIB::WeightedSBGraph&
82134 cout << " partitions: " << partitions << endl;
83135}
84136
137+
85138void read_directory (const std::string& name, std::vector<std::string>& v)
86139{
87140 auto path_leaf_string = [](const std::filesystem::directory_entry& entry) { return entry.path ().string (); };
@@ -92,119 +145,144 @@ void read_directory(const std::string& name, std::vector<std::string>& v)
92145 std::transform (start, end, std::back_inserter (v), path_leaf_string);
93146}
94147
148+
95149int main (int argc, char ** argv)
96150{
97151 int opt;
98- optional<string> filename = nullopt ;
99- optional<string> directory = nullopt ;
100- optional<unsigned > number_of_partitions = nullopt ;
101- optional<string> output_file;
102- optional<string> output_sb_graph = nullopt ;
103- optional<float > epsilon = nullopt ;
104- InitialPartitionStrategy initial_partition_strategy = InitialPartitionStrategy::ALL;
105- bool enable_multithreading = false ;
106- bool compute_metrics = false ;
107-
108- while (true ) {
109- static struct option long_options[] = {{" filename" , required_argument, 0 , ' f' }, {" partitions" , required_argument, 0 , ' p' },
110- {" output-file" , required_argument, 0 , ' g' }, {" output-graph" , required_argument, 0 , ' o' },
111- {" compute-metrics" , no_argument, 0 , ' m' }, {" directory" , required_argument, 0 , ' d' },
112- {" initial-partition-strategy" , required_argument, 0 , ' i' }, {" enable-multithreading" , no_argument, 0 , ' t' },
113- {" version" , no_argument, 0 , ' v' }, {" help" , no_argument, 0 , ' h' }};
152+ PartitionerParams params;
114153
154+ // look for configuration file
155+ while (true )
156+ {
115157 int option_index = 0 ;
116- opt = getopt_long (argc, argv, " f:p:e:o:g:d:i:tmvh:" , long_options, &option_index);
158+ static struct option long_options[] = {{" config-filename" , required_argument, 0 , ' c' },
159+ {" filename" , required_argument, 0 , ' f' }, {" partitions" , required_argument, 0 , ' p' },
160+ {" output-file" , required_argument, 0 , ' g' }, {" output-graph" , required_argument, 0 , ' o' },
161+ {" compute-metrics" , no_argument, 0 , ' m' }, {" directory" , required_argument, 0 , ' d' },
162+ {" initial-partition-strategy" , required_argument, 0 , ' i' }, {" enable-multithreading" , no_argument, 0 , ' t' },
163+ {" version" , no_argument, 0 , ' v' }, {" help" , no_argument, 0 , ' h' }};
164+
165+ opt = getopt_long (argc, argv, " c:f:p:e:o:g:d:i:tmvh:" , long_options, &option_index);
117166 if (opt == EOF) break ;
118167
119168 switch (opt) {
120- case ' f ' :
121- if (optarg) {
122- filename = string (optarg);
123- }
124- break ;
169+ case ' c ' :
170+ if (optarg) {
171+ params. config_filename = string (optarg);
172+ }
173+ break ;
125174
126- case ' p' :
127- if (optarg) {
128- number_of_partitions = atoi (optarg);
175+ default :
176+ continue ;
129177 }
130- break ;
178+ }
131179
132- case ' o' :
133- if (optarg) {
134- output_sb_graph = string (optarg);
135- }
136- break ;
180+ // read configuration file if exists, before reading flags
181+ if (params.config_filename ) {
182+ read_configuration_file (*params.config_filename , params);
183+ }
184+
185+ // reset it to read values again. We reed them again because flags overwrite values from configuration file
186+ optind = 0 ;
187+ while (true ) {
188+ int option_index = 0 ;
189+ static struct option long_options[] = {{" config-filename" , required_argument, 0 , ' c' },
190+ {" filename" , required_argument, 0 , ' f' }, {" partitions" , required_argument, 0 , ' p' },
191+ {" output-file" , required_argument, 0 , ' g' }, {" output-graph" , required_argument, 0 , ' o' },
192+ {" compute-metrics" , no_argument, 0 , ' m' }, {" directory" , required_argument, 0 , ' d' },
193+ {" initial-partition-strategy" , required_argument, 0 , ' i' }, {" enable-multithreading" , no_argument, 0 , ' t' },
194+ {" version" , no_argument, 0 , ' v' }, {" help" , no_argument, 0 , ' h' }};
195+
196+ opt = getopt_long (argc, argv, " c:f:p:e:o:g:d:i:tmvh:" , long_options, &option_index);
197+ if (opt == EOF) break ;
137198
138- case ' g' :
139- if (optarg) {
140- output_file = string (optarg);
141- }
142- break ;
199+ switch (opt) {
200+ case ' c' : // already read
201+ break ;
202+
203+ case ' f' :
204+ if (optarg) {
205+ params.filename = string (optarg);
206+ }
207+ break ;
143208
144- case ' e ' :
145- if (optarg) {
146- epsilon = atof (optarg);
147- }
148- break ;
209+ case ' p ' :
210+ if (optarg) {
211+ params. number_of_partitions = atoi (optarg);
212+ }
213+ break ;
149214
150- case ' m' :
151- compute_metrics = true ;
152- break ;
215+ case ' o' :
216+ if (optarg) {
217+ params.output_sb_graph = string (optarg);
218+ }
219+ break ;
153220
154- case ' d ' :
155- if (optarg) {
156- directory = string (optarg);
157- }
158- break ;
221+ case ' g ' :
222+ if (optarg) {
223+ params. output_file = string (optarg);
224+ }
225+ break ;
159226
160- case ' i ' :
161- if (optarg) {
162- initial_partition_strategy = InitialPartitionStrategy ( atoi ( optarg) );
163- }
164- break ;
227+ case ' e ' :
228+ if (optarg) {
229+ params. epsilon = atof ( optarg);
230+ }
231+ break ;
165232
166- case ' t ' :
167- enable_multithreading = true ;
168- break ;
233+ case ' m ' :
234+ params. compute_metrics = true ;
235+ break ;
169236
170- case ' v' :
171- version ();
172- exit (0 );
237+ case ' d' :
238+ if (optarg) {
239+ params.directory = string (optarg);
240+ }
241+ break ;
173242
174- case ' h' :
175- usage ();
176- exit (0 );
243+ case ' i' :
244+ if (optarg) {
245+ params.initial_partition_strategy = InitialPartitionStrategy (atoi (optarg));
246+ }
247+ break ;
177248
178- case ' ?' :
179- usage ();
180- exit (-1 );
181- break ;
249+ case ' t' :
250+ params.enable_multithreading = true ;
251+ break ;
252+
253+ case ' v' :
254+ version ();
255+ exit (0 );
256+
257+ case ' h' :
258+ usage ();
259+ exit (0 );
182260
183- default :
184- cout << " opt " << opt << endl;
185- abort ();
261+ case ' ?' :
262+ usage ();
263+ exit (-1 );
264+ break ;
265+
266+ default :
267+ abort ();
186268 }
187269 }
188270
189- if (not filename or not number_of_partitions) {
271+ if (not params. filename or not params. number_of_partitions ) {
190272 usage ();
191273 exit (1 );
192274 }
193275
194- if (not epsilon) {
195- epsilon = 0.0 ;
196- }
197-
198- if (*epsilon < 0 or *epsilon > 1 ) {
276+ if (params.epsilon < 0 or params.epsilon > 1 ) {
199277 usage ();
200278 exit (1 );
201279 }
202280
203- cout << " filename is " << *filename << endl;
204- cout << " number of partitions is " << *number_of_partitions << endl;
281+ cout << " filename is " << *params. filename << endl;
282+ cout << " number of partitions is " << *params. number_of_partitions << endl;
205283
206284 optional<string> s;
207- if (output_sb_graph) {
285+ if (params. output_sb_graph ) {
208286 s = " " ;
209287 }
210288
@@ -213,25 +291,22 @@ int main(int argc, char** argv)
213291 SBG::LIB::UnordPWMapAF pw_fact (map_fact);
214292
215293 auto start_build_graph = chrono::high_resolution_clock::now ();
216- auto sb_graph = build_sb_graph (filename->c_str (), pw_fact);
294+ auto sb_graph = build_sb_graph (params. filename ->c_str (), pw_fact);
217295 auto end_build_graph = chrono::high_resolution_clock::now ();
218296 auto time_to_build_graph = chrono::duration<double , std::milli>(end_build_graph - start_build_graph).count ();
219297
220298 cout << " sb_graph: " << sb_graph << endl;
221299
222300 auto start_partitionate = chrono::high_resolution_clock::now ();
223- auto partitions = best_initial_partition (sb_graph, *number_of_partitions, initial_partition_strategy, enable_multithreading);
224- kl_sbg_imbalance_partitioner (sb_graph, partitions, * epsilon, enable_multithreading);
301+ auto partitions = best_initial_partition (sb_graph, *params. number_of_partitions , params. initial_partition_strategy , params. enable_multithreading );
302+ kl_sbg_imbalance_partitioner (sb_graph, partitions, params. epsilon , params. enable_multithreading );
225303 auto end_partitionate = chrono::high_resolution_clock::now ();
226304 auto time_to_partitionate = chrono::duration<double , std::milli>(end_partitionate - start_partitionate).count ();
227305
228- if (compute_metrics) {
306+ if (params. compute_metrics ) {
229307 map<string, metrics::communication_metrics> metrics;
230-
231308 int edge_cut = metrics::edge_cut (partitions, sb_graph, set_fact);
232-
233309 auto [comm_volume, max_comm_volume] = metrics::communication_volume (partitions, sb_graph, set_fact, map_fact);
234-
235310 auto max_imb = metrics::maximum_imbalance (partitions, sb_graph, set_fact);
236311
237312 metrics::communication_metrics comm_metrics = metrics::communication_metrics{edge_cut, comm_volume, max_comm_volume, max_imb};
@@ -241,17 +316,14 @@ int main(int argc, char** argv)
241316 cout << f << " : " << m << endl;
242317 }
243318
244- if (compute_metrics and directory) {
319+ if (params. compute_metrics and params. directory ) {
245320 std::vector<std::string> dir_files;
246- read_directory (*directory, dir_files);
321+ read_directory (*params. directory , dir_files);
247322
248323 for (const auto & f : dir_files) {
249324 auto partition_from_file = metrics::read_partition_from_file (f, sb_graph, set_fact);
250-
251325 int edge_cut = metrics::edge_cut (partition_from_file, sb_graph, set_fact);
252-
253326 auto [comm_volume, max_comm_volume] = metrics::communication_volume (partition_from_file, sb_graph, set_fact, map_fact);
254-
255327 auto max_imb = metrics::maximum_imbalance (partition_from_file, sb_graph, set_fact);
256328
257329 metrics::communication_metrics comm_metrics = metrics::communication_metrics{edge_cut, comm_volume, max_comm_volume, max_imb};
@@ -267,7 +339,7 @@ int main(int argc, char** argv)
267339 cout << " time_to_partitionate = " << time_to_partitionate << " ms" << endl;
268340
269341 if (sanity_check_enabled) {
270- sanity_check (sb_graph, partitions, *number_of_partitions);
342+ sanity_check (sb_graph, partitions, *params. number_of_partitions );
271343 }
272344
273345 if (s) {
0 commit comments