Parcourir la source

Add perl script for multithreading simulations

Eric Ramat il y a 9 ans
Parent
commit
8f9f96ccaf

+ 14 - 2
CMakeLists.txt

@@ -23,19 +23,31 @@ INCLUDE(CMakeCPack.cmake)
  # Debug mode
 #
 
-IF (CMAKE_COMPILER_IS_GNUCC AND CMAKE_COMPILER_IS_GNUCXX)
+IF (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang" OR ${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU")
   SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra")
   SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -std=c++11 -pthread")
   IF (UNIX)
     SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pedantic")
     SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic")
   ENDIF (UNIX)
-ENDIF (CMAKE_COMPILER_IS_GNUCC AND CMAKE_COMPILER_IS_GNUCXX)
+ENDIF ()
 
 if (CMAKE_BUILD_TYPE STREQUAL "")
   SET(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING "Choose the type of build" FORCE)
 endif ()
 
+#
+ # Thread
+#
+
+message(STATUS "checking for a (p)thread library")
+find_package(Threads REQUIRED)
+if (NOT Threads_FOUND)
+  message(ERROR " failed to found a (p)thread support.")
+else ()
+  message(STATUS " threads support enabled (${CMAKE_THREAD_LIBS_INIT})")
+endif ()
+
 #
  # Modules
 #

+ 20 - 0
output/script.pl

@@ -0,0 +1,20 @@
+#!/usr/bin/perl
+
+use List::Util qw(sum);
+
+for ($n = 1; $n < 9; $n++) {
+    @values = ();
+    for ($i = 0; $i < 20; $i++)  {
+	push @values, `../build/src/tests/multithreading/pdevs-multithreading-main $n`;
+    }
+    $sum = sum(@values);
+    $average = $sum / 20;
+
+    $sum2 = 0;
+    for ($i = 0; $i < 20; $i++)  {
+	$e = $values[$i] - $average;
+	$sum2 = $sum2 + $e * $e;
+    }
+
+    print $n . "\t" . $average . "\t" . (sqrt($sum2) / 20) . "\n";
+}

+ 17 - 17
src/tests/boost_graph/graph_generator.hpp

@@ -57,13 +57,13 @@ public:
 
     virtual void generate(OrientedGraph& go)
     {
-        const char *texte = new const char();
-        texte = "file/data_base/tree/tree_20000.txt";
-        Graph_constructor_txt(texte,&go);
-       //boost::timer t; 
-	   
-       /* build_generator_graph(&go, edge_number, source_number, min_neigh,
-                              max_neigh, levels);*/
+        // const char *texte = new const char();
+        // texte = "file/data_base/tree/tree_20000.txt";
+        // Graph_constructor_txt(texte,&go);
+       //boost::timer t;
+
+       build_generator_graph(&go, edge_number, source_number, min_neigh,
+                              max_neigh, levels);
        //double t3 = t.elapsed();
 	   //std::cout << "tmp_gen = " << t3 << std::endl;
     }
@@ -90,8 +90,8 @@ public:
         /*const char *texte = new const char();
         texte = "enregistrement.txt";
         Graph_constructor_txt(texte,&go);*/
-       //boost::timer t; 
-	   
+       //boost::timer t;
+
        build_graph_grid(&go, side, vertex_selection,  weight_vertex, edge_weight, rec);
        //double t3 = t.elapsed();
 	   //std::cout << "tmp_gen = " << t3 << std::endl;
@@ -119,13 +119,13 @@ public:
 
     virtual void generate(OrientedGraph& go)
     {
-		const char *texte = new const char();
+		// const char *texte = new const char();
         //texte = "file/data_base/HO_models.txt";
-        texte = "file/data_base/linked/linked10000.txt";
-        Graph_constructor_txt(texte,&go);
-        
-      //build_generator_graph_linked(&go, edge_number, levels , min_neigh,
-                            //  max_neigh);
+        // texte = "file/data_base/linked/linked10000.txt";
+        // Graph_constructor_txt(texte,&go);
+
+        build_generator_graph_linked(&go, edge_number, levels , min_neigh,
+                                     max_neigh);
     }
 
 private:
@@ -163,7 +163,7 @@ public:
         //texte = "file/data_base/HO_models.txt";
         //texte = "file/data_base/linked/linked10000.txt";
         //Graph_constructor_txt(texte,&go);
-        
+
 		build_parcellaire_graph(&go, size_max, name);
     }
 
@@ -181,7 +181,7 @@ public:
     virtual void generate(OrientedGraph& go)
     {
         //build_corsen_graph(go);
-        
+
     }
 };
 

+ 2 - 2
src/tests/boost_graph/partitioning/graph_build.cpp

@@ -723,7 +723,7 @@ void build_generator_graph(OrientedGraph *go, int nbr_vertex, int nbr_source, in
 		}
 		nbr_branche += nbr_tmp;
 	}
-	std::cout<<nbr_branche<<std::endl;
+	// std::cout<<nbr_branche<<std::endl;
 
 	nbr_npb = nbr_vertex/(nbr_branche);
 
@@ -796,7 +796,7 @@ void build_generator_graph(OrientedGraph *go, int nbr_vertex, int nbr_source, in
 		//std::cout<<(*go)[i]._index<<" "<<indic<<" -> "<<(*go)[i]._type<<std::endl;
 	}
 
-	std::cout<<"Compteur : "<<compteur<<std::endl;
+	// std::cout<<"Compteur : "<<compteur<<std::endl;
 }
 
 void build_generator_graph_linked(OrientedGraph *go, int nbr_vertex, int nbr_couche, int nbr_v_min, int nbr_v_max){

+ 16 - 16
src/tests/boost_graph/partitioning/main.cpp

@@ -46,11 +46,11 @@ int main()
     srand((unsigned)time(NULL));
 
 	/*** Génération du graphe ***/
-	
+
     OrientedGraph *go = new OrientedGraph();
     std::string type_graph = "parcellaire";
     std::pair<bool,bool> Spectrale = {false,false};
-    
+
     if(type_graph == "grid"){
 		int side = floor(sqrt(100));
 		std::vector<std::pair<int,int>> vertex_selection;
@@ -65,7 +65,7 @@ int main()
 	    Plot_OrientedGraph(go,"../../sortie_graphe/Tests/Graphes/Multiniveau/txt/grid_500.txt");
 	}else if (type_graph == "tree"){
 		int nbr_sommets = 70;
-		int nbr_sources = 2; 
+		int nbr_sources = 2;
 		Entiers niveau = {2,2};
 		const char *texte;
         //texte = "file/data_base/tree/tree_20000.txt";
@@ -89,29 +89,29 @@ int main()
 		build_example_grid(*go);
 		//build_graph(*go, 11);
 	}
-	
+
 	/*** Comparaison des méthodes par étude du ratio de coupe ***/
-	
+
 	if(Spectrale.first){
 		UnorientedGraph *g = new UnorientedGraph();
 		make_unoriented_graph(*go, *g);
 		EntiersEntiers Partition2;
-		
+
 		Affichage_UnorientedGraph(g);
-		
+
 		Partition2 = Spectral_Partition("../../Classif_R/Graphe/txt/Partition2.txt");
 		Plot_OrientedGraph_All(go,Partition2,"../../Classif_R/Graphe/txt/Spectral_Partition.txt", true);
 		Plot_OrientedGraph(go,"../../Classif_R/Graphe/txt/toto.txt");
-		
+
 		delete g;
 	}
 
 	/*** Paramétrage du Multiniveau ***/
-	std::vector<uint> numeric_parameters = {num_vertices(*go)/50, 4, 10};
+	std::vector<uint> numeric_parameters = {(uint)(num_vertices(*go)/50), 4, 10};
 	std::vector<std::string> parameters = {"HEM", "gggp", "diff", "ratio"};
-	
+
 	uint nbr_tirage = 1;
-	
+
 	for(uint i = 0 ; i < nbr_tirage ; i++){
 		Edges edge_partie;
 		OutputEdgeList outputedgeslist(numeric_parameters.at(1));
@@ -125,24 +125,24 @@ int main()
 				Weight_Matrix_Txt(g,"../../Classif_R/Graphe/txt/Mwei.txt");
 				delete g;
 			}
-			
+
 			std::cout<<"Multiniveau"<<std::endl;
 			OrientedGraphs graphs = Multiniveau(go, numeric_parameters,
 												parameters, edge_partie ,
 												outputedgeslist, inputedgelist,
-												connections,false, 2);  	
+												connections,false, 2);
 												std::cout<<std::endl;
 		}else{
 			OrientedGraphs graphs = Multiniveau(go, numeric_parameters,
 												parameters, edge_partie ,
 												outputedgeslist, inputedgelist,
-												connections,true, 2); 
+												connections,true, 2);
 												std::cout<<std::endl;
 		}
 	}
-	
+
 	delete go;
-	
+
 	std::cout << "Duration : " << t.elapsed()/nbr_tirage << " seconds" << std::endl;
 	return 0;
 }

+ 1 - 1
src/tests/mpi/CMakeLists.txt

@@ -20,7 +20,7 @@ LINK_DIRECTORIES(
 
 ADD_EXECUTABLE(pdevs-mpi-main graph_manager.hpp main.cpp)
 
-TARGET_LINK_LIBRARIES(pdevs-mpi-main
+TARGET_LINK_LIBRARIES(pdevs-mpi-main partitioning
   ${Boost_SERIALIZATION_LIBRARY}
   ${Boost_MPI_LIBRARY}
   ${MPI_CXX_LIBRARIES})

+ 75 - 148
src/tests/mpi/graph_manager.hpp

@@ -35,6 +35,8 @@
 #include <paradevs/kernel/pdevs/mpi/GraphManager.hpp>
 #include <paradevs/kernel/pdevs/Simulator.hpp>
 
+#include <tests/boost_graph/graph_defs.hpp>
+
 namespace paradevs { namespace tests { namespace mpi {
 
 class S1GraphManager :
@@ -155,154 +157,79 @@ private:
     paradevs::pdevs::mpi::ModelProxy < common::DoubleTime > S2;
 };
 
-// class S3GraphManager :
-//         public paradevs::pdevs::GraphManager < common::DoubleTime >
-// {
-// public:
-//     S3GraphManager(common::Coordinator < common::DoubleTime >* coordinator,
-//                    const paradevs::common::NoParameters& parameters) :
-//         paradevs::pdevs::GraphManager < common::DoubleTime >(coordinator,
-//                                                              parameters)
-//     {
-//         coordinator->add_out_port("out");
-//         for (unsigned int i = 0; i < 10; ++i) {
-//             std::ostringstream ss;
-//             simulator_type* s = new simulator_type(ss.str(),
-//                                                    common::NoParameters());
-
-//             ss << "a" << (i + 1);
-//             _simulators.push_back(s);
-//             add_child(s);
-//             s->add_out_port("out");
-//         }
-//     }
-
-//     void init()
-//     { }
-
-//     void start(common::DoubleTime::type /* t */)
-//     { }
-
-//     void transition(
-//         const common::Models < common::DoubleTime >& /* receivers */,
-//         common::DoubleTime::type /* t */)
-//     { }
-
-//     virtual ~S3GraphManager()
-//     {
-//         for (typename std::vector < simulator_type* >::const_iterator it =
-//                  _simulators.begin(); it != _simulators.end(); ++it) {
-//             delete *it;
-//         }
-//     }
-
-// private:
-//     typedef paradevs::pdevs::Simulator < common::DoubleTime,
-//                                          pdevs::A > simulator_type;
-
-//     std::vector < simulator_type* > _simulators;
-// };
-
-// class Root2GraphManager :
-//         public paradevs::pdevs::GraphManager < common::DoubleTime >
-// {
-// public:
-//     Root2GraphManager(
-//         common::Coordinator < common::DoubleTime >* coordinator,
-//         const paradevs::common::NoParameters& parameters) :
-//         paradevs::pdevs::GraphManager < common::DoubleTime >(
-//                                             coordinator, parameters),
-//         S1("S1", paradevs::common::NoParameters(),
-//            paradevs::common::NoParameters()),
-//         S2("S2", paradevs::common::NoParameters(),
-//            paradevs::common::NoParameters())
-//     {
-//         add_child(&S1);
-//         add_child(&S2);
-//     }
-
-//     void init()
-//     {
-//         S1.set_sender(
-//             dynamic_cast < paradevs::pdevs::mpi::Coordinator <
-//                 common::DoubleTime,
-//                 paradevs::tests::mpi::Root2GraphManager >*
-//             >(get_coordinator())->get_sender());
-//         S2.set_sender(
-//             dynamic_cast < paradevs::pdevs::mpi::Coordinator <
-//                 common::DoubleTime,
-//                 paradevs::tests::mpi::Root2GraphManager >*
-//             >(get_coordinator())->get_sender());
-//     }
-
-//     void start(common::DoubleTime::type t)
-//     {
-//         S1.get_sender().send(
-//             paradevs::pdevs::mpi::start_message <
-//                 common::DoubleTime >(t));
-//         S2.get_sender().send(
-//             paradevs::pdevs::mpi::start_message <
-//                 common::DoubleTime >(t));
-//     }
-
-//     void transition(const common::Models < common::DoubleTime >& receivers,
-//                     common::DoubleTime::type t)
-//     {
-//         if (std::find(receivers.begin(), receivers.end(),
-//                       &S1) != receivers.end()) {
-//             S1.get_sender().send(
-//                 paradevs::pdevs::mpi::transition_message <
-//                     common::DoubleTime >(t));
-//         }
-//         if (std::find(receivers.begin(), receivers.end(),
-//                       &S2) != receivers.end()) {
-//             S2.get_sender().send(
-//                 paradevs::pdevs::mpi::transition_message <
-//                     common::DoubleTime >(t));
-//         }
-//     }
-
-//     virtual ~Root2GraphManager()
-//     { }
-
-// private:
-//     paradevs::pdevs::mpi::Coordinator <
-//         common::DoubleTime,
-//         S3GraphManager > S1;
-//     paradevs::pdevs::mpi::Coordinator <
-//         common::DoubleTime,
-//         S3GraphManager > S2;
-// };
-
-// class Root3GraphManager :
-//         public paradevs::pdevs::GraphManager < common::DoubleTime >
-// {
-// public:
-//     Root3GraphManager(
-//         common::Coordinator < common::DoubleTime >* coordinator,
-//         const paradevs::common::NoParameters& parameters) :
-//         paradevs::pdevs::GraphManager < common::DoubleTime >(
-//                                             coordinator, parameters),
-//         S1("S1", paradevs::common::NoParameters(),
-//            paradevs::common::NoParameters()),
-//         S2("S2", paradevs::common::NoParameters(),
-//            paradevs::common::NoParameters())
-//     {
-//         add_child(&S1);
-//         add_child(&S2);
-//     }
-
-//     virtual ~Root3GraphManager()
-//     { }
-
-// private:
-//     paradevs::pdevs::Coordinator <
-//         common::DoubleTime,
-//         S3GraphManager > S1;
-//     paradevs::pdevs::Coordinator <
-//         common::DoubleTime,
-//         S3GraphManager > S2;
-// };
+struct MPIHierarchicalGraphManagerParameters
+{
+    paradevs::tests::boost_graph::OrientedGraphs graphs;
+    paradevs::tests::boost_graph::InputEdgeList input_edges;
+    paradevs::tests::boost_graph::OutputEdgeList output_edges;
+    paradevs::tests::boost_graph::Connections parent_connections;
+    std::vector < int > ranks;
+};
+
+class MPIHierarchicalGraphManager :
+        public paradevs::pdevs::GraphManager <
+    common::DoubleTime, MPIHierarchicalGraphManagerParameters >
+{
+public:
+    MPIHierarchicalGraphManager(
+        common::Coordinator < common::DoubleTime >* coordinator,
+        const MPIHierarchicalGraphManagerParameters& parameters) :
+        paradevs::pdevs::GraphManager <
+            common::DoubleTime,
+            MPIHierarchicalGraphManagerParameters >
+        (coordinator, parameters)
+    {
+        // build model proxies (graphs)
+        for (unsigned int i = 0; i < parameters.graphs.size(); ++i) {
+            ModelProxy* model = 0;
+            std::ostringstream ss;
+
+            ss << "S" << i;
+            model = new ModelProxy(ss.str(), parameters.ranks[i], false);
+            _models.push_back(model);
+            add_child(model);
+        }
+
+        // // builds internal connections (edges)
+        // for (Connections::const_iterator it = parent_connections.begin();
+        //      it != parent_connections.end(); ++it) {
+        //     const Connection& connection = *it;
+        //     std::ostringstream ss_out;
+        //     std::ostringstream ss_in;
+
+        //     ss_out << "out_" << connection.first.second;
+        //     ss_in << "in_" << connection.first.second;
+
+        //     if (not ParallelHeapHierarchicalGraphManager <
+        //             GraphBuilder >::exist_link(
+        //                 _coordinators[connection.first.first - 1],
+        //                 ss_out.str(),
+        //                 _coordinators[connection.second.first - 1],
+        //                 ss_in.str())) {
+        //         ParallelHeapHierarchicalGraphManager <
+        //             GraphBuilder >::add_link(
+        //                 _coordinators[connection.first.first - 1],
+        //                 ss_out.str(),
+        //                 _coordinators[connection.second.first - 1],
+        //                 ss_in.str());
+        //     }
+        // }
+    }
+
+    virtual ~MPIHierarchicalGraphManager()
+    {
+        for (typename ModelProxies::const_iterator it = _models.begin();
+             it != _models.end(); ++it) {
+            delete *it;
+        }
+    }
+
+private:
+    typedef paradevs::pdevs::mpi::ModelProxy < common::DoubleTime > ModelProxy;
+    typedef std::vector < ModelProxy* > ModelProxies;
+
+    ModelProxies _models;
+};
 
 } } } // namespace paradevs tests mpi
 

+ 60 - 1
src/tests/mpi/main.cpp

@@ -32,11 +32,18 @@
 #include <boost/mpi/environment.hpp>
 #include <boost/mpi/communicator.hpp>
 
+#include <tests/boost_graph/graph_builder.hpp>
+#include <tests/boost_graph/graph_generator.hpp>
+#include <tests/boost_graph/graph_partitioning.hpp>
+
+#include <chrono>
+
 using namespace paradevs::tests::mpi;
 using namespace paradevs::common;
 using namespace boost::mpi;
+using namespace std::chrono;
 
-int main(int argc, char *argv[])
+void example_simple(int argc, char *argv[])
 {
     environment env(argc, argv);
     communicator world;
@@ -82,6 +89,58 @@ int main(int argc, char *argv[])
             LP.loop();
         }
     }
+}
+
+void example_grid(int argc, char *argv[])
+{
+    environment env(argc, argv);
+    communicator world;
+
+    unsigned int side = 100;
+    std::vector<std::pair<int,int>> vertex_selection;
+    std::pair<int,int> tmp;
+    tmp.first = 0;
+    tmp.second = 3;
+    vertex_selection.push_back(tmp);
+    paradevs::tests::boost_graph::Entiers weight_vertex;
+    weight_vertex.push_back(1);
+    const char *edge_weight;
+    edge_weight = "../../sortie_graphe/tests_grid.txt";
+    bool rec = false;
 
+    paradevs::tests::boost_graph::RandomGridGraphGenerator generator(
+        side, vertex_selection,  weight_vertex, edge_weight, rec);
+    paradevs::tests::boost_graph::PartitioningGraphBuilder builder(
+        4, "gggp", 20, false, generator);
+    paradevs::tests::mpi::MPIHierarchicalGraphManagerParameters parameters;
+
+    builder.build(parameters.graphs, parameters.input_edges,
+                  parameters.output_edges, parameters.parent_connections);
+    if (world.rank() == 0) {
+        paradevs::common::RootCoordinator <
+            DoubleTime, paradevs::pdevs::mpi::Coordinator <
+                DoubleTime,
+                paradevs::tests::mpi::MPIHierarchicalGraphManager,
+                paradevs::common::NoParameters,
+                paradevs::tests::mpi::MPIHierarchicalGraphManagerParameters >
+            > rc(0, 10, "root", paradevs::common::NoParameters(), parameters);
+
+        steady_clock::time_point t1 = steady_clock::now();
+
+        rc.run();
+
+        steady_clock::time_point t2 = steady_clock::now();
+
+        duration < double > time_span = duration_cast <
+            duration < double > >(t2 - t1);
+
+        std::cout << "MULTI = " << time_span.count() << std::endl;
+    } else {
+    }
+}
+
+int main(int argc, char *argv[])
+{
+    example_simple(argc, argv);
     return 0;
 }

+ 93 - 10
src/tests/multithreading/main.cpp

@@ -37,9 +37,9 @@
 using namespace paradevs::common;
 using namespace std::chrono;
 
-void monothreading()
+double grid_monothreading()
 {
-    unsigned int side = 100;
+    unsigned int side = 40;
     std::vector<std::pair<int,int>> vertex_selection;
     std::pair<int,int> tmp;
     tmp.first = 0;
@@ -77,12 +77,12 @@ void monothreading()
     duration < double > time_span = duration_cast <
         duration < double > >(t2 - t1);
 
-    std::cout << "MONO = " << time_span.count() << std::endl;
+    return time_span.count();
 }
 
-void multithreading(int cluster_number)
+double grid_multithreading(int cluster_number)
 {
-    unsigned int side = 100;
+    unsigned int side = 40;
     std::vector<std::pair<int,int>> vertex_selection;
     std::pair<int,int> tmp;
     tmp.first = 0;
@@ -117,14 +117,97 @@ void multithreading(int cluster_number)
     duration < double > time_span = duration_cast <
         duration < double > >(t2 - t1);
 
-    std::cout << "MULTI = " << time_span.count() << std::endl;
+    return time_span.count();
 }
 
-int main()
+double tree_monothreading()
 {
-    monothreading();
-    for (int i = 2; i <= 8; ++i) {
-        multithreading(i);
+    std::vector < int > levels = { 4, 3, 2 };
+    int nbr_sommets = 1000;
+    int sources = nbr_sommets/100*1;
+    paradevs::tests::boost_graph::RandomGraphGenerator generator(nbr_sommets,
+                                                                 levels,
+                                                                 sources, 2, 3);
+
+    paradevs::common::RootCoordinator <
+        DoubleTime, paradevs::pdevs::Coordinator <
+            DoubleTime,
+            paradevs::tests::boost_graph::HeapHierarchicalGraphManager <
+                paradevs::tests::boost_graph::PartitioningGraphBuilder >,
+            paradevs::common::NoParameters,
+            paradevs::tests::boost_graph::PartitioningParameters >
+        > rc(0, 10, "root", paradevs::common::NoParameters(),
+             paradevs::tests::boost_graph::PartitioningParameters(
+                 4, "gggp", 200, false, generator));
+
+    steady_clock::time_point t1 = steady_clock::now();
+
+    rc.run();
+
+    steady_clock::time_point t2 = steady_clock::now();
+
+    duration < double > time_span = duration_cast <
+        duration < double > >(t2 - t1);
+
+    return time_span.count();
+}
+
+double tree_multithreading(int cluster_number)
+{
+    std::vector < int > levels = { 4, 3, 2 };
+    int nbr_sommets = 1000;
+    int sources = nbr_sommets/100*1;
+    paradevs::tests::boost_graph::RandomGraphGenerator generator(nbr_sommets,
+                                                                 levels,
+                                                                 sources, 2, 3);
+
+    paradevs::common::RootCoordinator <
+        DoubleTime, paradevs::pdevs::multithreading::Coordinator <
+            DoubleTime,
+            paradevs::tests::boost_graph::ParallelHeapHierarchicalGraphManager <
+                paradevs::tests::boost_graph::PartitioningGraphBuilder >,
+            paradevs::common::NoParameters,
+            paradevs::tests::boost_graph::PartitioningParameters >
+        > rc(0, 10, "root", paradevs::common::NoParameters(),
+             paradevs::tests::boost_graph::PartitioningParameters(
+                 cluster_number, "gggp", 200, false, generator));
+
+    steady_clock::time_point t1 = steady_clock::now();
+
+    rc.run();
+
+    steady_clock::time_point t2 = steady_clock::now();
+
+    duration < double > time_span = duration_cast <
+        duration < double > >(t2 - t1);
+
+    return time_span.count();
+}
+
+void grid(int n)
+{
+    if (n == 1) {
+        std::cout << grid_monothreading() << std::endl;
+    } else {
+        std::cout << grid_multithreading(n) << std::endl;
+    }
+}
+
+void tree(int n)
+{
+    if (n == 1) {
+        std::cout << tree_monothreading() << std::endl;
+    } else {
+        std::cout << tree_multithreading(n) << std::endl;
+    }
+}
+
+
+int main(int argc, char** argv)
+{
+    if (argc > 1) {
+        // grid(atoi(argv[1]));
+        tree(atoi(argv[1]));
     }
     return 0;
 }