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;
@@ -82,6 +133,7 @@ void sort_before_print(PartitionMap partitions, const SBG::LIB::WeightedSBGraph&
82133 cout << " partitions: " << partitions << endl;
83134}
84135
136+
85137void read_directory (const std::string& name, std::vector<std::string>& v)
86138{
87139 auto path_leaf_string = [](const std::filesystem::directory_entry& entry) { return entry.path ().string (); };
@@ -92,136 +144,161 @@ void read_directory(const std::string& name, std::vector<std::string>& v)
92144 std::transform (start, end, std::back_inserter (v), path_leaf_string);
93145}
94146
147+
95148int main (int argc, char ** argv)
96149{
97150 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' }};
151+ PartitionerParams params;
114152
153+ // look for configuration file
154+ while (true )
155+ {
115156 int option_index = 0 ;
116- opt = getopt_long (argc, argv, " f:p:e:o:g:d:i:tmvh:" , long_options, &option_index);
157+ static struct option long_options[] = {{" config-filename" , required_argument, 0 , ' c' },
158+ {" filename" , required_argument, 0 , ' f' }, {" partitions" , required_argument, 0 , ' p' },
159+ {" output-file" , required_argument, 0 , ' g' }, {" output-graph" , required_argument, 0 , ' o' },
160+ {" compute-metrics" , no_argument, 0 , ' m' }, {" directory" , required_argument, 0 , ' d' },
161+ {" initial-partition-strategy" , required_argument, 0 , ' i' }, {" enable-multithreading" , no_argument, 0 , ' t' },
162+ {" version" , no_argument, 0 , ' v' }, {" help" , no_argument, 0 , ' h' }};
163+
164+ opt = getopt_long (argc, argv, " c:f:p:e:o:g:d:i:tmvh:" , long_options, &option_index);
117165 if (opt == EOF) break ;
118166
119167 switch (opt) {
120- case ' f ' :
121- if (optarg) {
122- filename = string (optarg);
123- }
124- break ;
168+ case ' c ' :
169+ if (optarg) {
170+ params. config_filename = string (optarg);
171+ }
172+ break ;
125173
126- case ' p' :
127- if (optarg) {
128- number_of_partitions = atoi (optarg);
174+ default :
175+ continue ;
129176 }
130- break ;
177+ }
131178
132- case ' o' :
133- if (optarg) {
134- output_sb_graph = string (optarg);
135- }
136- break ;
179+ // read configuration file if exists, before reading flags
180+ if (params.config_filename ) {
181+ read_configuration_file (*params.config_filename , params);
182+ }
183+
184+ // reset it to read values again. We reed them again because flags overwrite values from configuration file
185+ optind = 0 ;
186+ while (true ) {
187+ int option_index = 0 ;
188+ static struct option long_options[] = {{" config-filename" , required_argument, 0 , ' c' },
189+ {" filename" , required_argument, 0 , ' f' }, {" partitions" , required_argument, 0 , ' p' },
190+ {" output-file" , required_argument, 0 , ' g' }, {" output-graph" , required_argument, 0 , ' o' },
191+ {" compute-metrics" , no_argument, 0 , ' m' }, {" directory" , required_argument, 0 , ' d' },
192+ {" initial-partition-strategy" , required_argument, 0 , ' i' }, {" enable-multithreading" , no_argument, 0 , ' t' },
193+ {" version" , no_argument, 0 , ' v' }, {" help" , no_argument, 0 , ' h' }};
194+
195+ opt = getopt_long (argc, argv, " c:f:p:e:o:g:d:i:tmvh:" , long_options, &option_index);
196+ if (opt == EOF) break ;
137197
138- case ' g' :
139- if (optarg) {
140- output_file = string (optarg);
141- }
142- break ;
198+ switch (opt) {
199+ case ' c' : // already read
200+ break ;
201+
202+ case ' f' :
203+ if (optarg) {
204+ params.filename = string (optarg);
205+ }
206+ break ;
143207
144- case ' e ' :
145- if (optarg) {
146- epsilon = atof (optarg);
147- }
148- break ;
208+ case ' p ' :
209+ if (optarg) {
210+ params. number_of_partitions = atoi (optarg);
211+ }
212+ break ;
149213
150- case ' m' :
151- compute_metrics = true ;
152- break ;
214+ case ' o' :
215+ if (optarg) {
216+ params.output_sb_graph = string (optarg);
217+ }
218+ break ;
153219
154- case ' d ' :
155- if (optarg) {
156- directory = string (optarg);
157- }
158- break ;
220+ case ' g ' :
221+ if (optarg) {
222+ params. output_file = string (optarg);
223+ }
224+ break ;
159225
160- case ' i ' :
161- if (optarg) {
162- initial_partition_strategy = InitialPartitionStrategy ( atoi ( optarg) );
163- }
164- break ;
226+ case ' e ' :
227+ if (optarg) {
228+ params. epsilon = atof ( optarg);
229+ }
230+ break ;
165231
166- case ' t ' :
167- enable_multithreading = true ;
168- break ;
232+ case ' m ' :
233+ params. compute_metrics = true ;
234+ break ;
169235
170- case ' v' :
171- version ();
172- exit (0 );
236+ case ' d' :
237+ if (optarg) {
238+ params.directory = string (optarg);
239+ }
240+ break ;
173241
174- case ' h' :
175- usage ();
176- exit (0 );
242+ case ' i' :
243+ if (optarg) {
244+ params.initial_partition_strategy = InitialPartitionStrategy (atoi (optarg));
245+ }
246+ break ;
177247
178- case ' ?' :
179- usage ();
180- exit (-1 );
181- break ;
248+ case ' t' :
249+ params.enable_multithreading = true ;
250+ break ;
182251
183- default :
184- cout << " opt " << opt << endl;
185- abort ();
252+ case ' v' :
253+ version ();
254+ exit (0 );
255+
256+ case ' h' :
257+ usage ();
258+ exit (0 );
259+
260+ case ' ?' :
261+ usage ();
262+ exit (-1 );
263+ break ;
264+
265+ default :
266+ abort ();
186267 }
187268 }
188269
189- if (not filename or not number_of_partitions) {
270+ if (not params. filename or not params. number_of_partitions ) {
190271 usage ();
191272 exit (1 );
192273 }
193274
194- if (not epsilon) {
195- epsilon = 0.0 ;
196- }
197-
198- if (*epsilon < 0 or *epsilon > 1 ) {
275+ if (params.epsilon < 0 or params.epsilon > 1 ) {
199276 usage ();
200277 exit (1 );
201278 }
202279
203- cout << " filename is " << *filename << endl;
204- cout << " number of partitions is " << *number_of_partitions << endl;
280+ cout << " filename is " << *params. filename << endl;
281+ cout << " number of partitions is " << *params. number_of_partitions << endl;
205282
206283 optional<string> s;
207- if (output_sb_graph) {
284+ if (params. output_sb_graph ) {
208285 s = " " ;
209286 }
210287
211288 auto start_build_graph = chrono::high_resolution_clock::now ();
212- auto sb_graph = build_sb_graph (filename->c_str ());
289+ auto sb_graph = build_sb_graph (params. filename ->c_str ());
213290 auto end_build_graph = chrono::high_resolution_clock::now ();
214291 auto time_to_build_graph = chrono::duration<double , std::milli>(end_build_graph - start_build_graph).count ();
215292
216293 cout << " sb_graph: " << sb_graph << endl;
217294
218295 auto start_partitionate = chrono::high_resolution_clock::now ();
219- auto partitions = best_initial_partition (sb_graph, *number_of_partitions, initial_partition_strategy, enable_multithreading);
220- kl_sbg_imbalance_partitioner (sb_graph, partitions, * epsilon, enable_multithreading);
296+ auto partitions = best_initial_partition (sb_graph, *params. number_of_partitions , params. initial_partition_strategy , params. enable_multithreading );
297+ kl_sbg_imbalance_partitioner (sb_graph, partitions, params. epsilon , params. enable_multithreading );
221298 auto end_partitionate = chrono::high_resolution_clock::now ();
222299 auto time_to_partitionate = chrono::duration<double , std::milli>(end_partitionate - start_partitionate).count ();
223300
224- if (compute_metrics) {
301+ if (params. compute_metrics ) {
225302 map<string, metrics::communication_metrics> metrics;
226303
227304 int edge_cut = metrics::edge_cut (partitions, sb_graph);
@@ -237,9 +314,9 @@ int main(int argc, char** argv)
237314 cout << f << " : " << m << endl;
238315 }
239316
240- if (compute_metrics and directory) {
317+ if (params. compute_metrics and params. directory ) {
241318 std::vector<std::string> dir_files;
242- read_directory (*directory, dir_files);
319+ read_directory (*params. directory , dir_files);
243320
244321 for (const auto & f : dir_files) {
245322 auto partition_from_file = metrics::read_partition_from_file (f, sb_graph);
@@ -263,7 +340,7 @@ int main(int argc, char** argv)
263340 cout << " time_to_partitionate = " << time_to_partitionate << " ms" << endl;
264341
265342 if (sanity_check_enabled) {
266- sanity_check (sb_graph, partitions, *number_of_partitions);
343+ sanity_check (sb_graph, partitions, *params. number_of_partitions );
267344 }
268345
269346 if (s) {
0 commit comments