Riccardo,

Thanks for your extended feedback!

> i finally managed to make my futurized sparse triangular solver to work.
> over the next days i'll try it for performance, but for this i'll need to
> develop a blocked version and some real CSR matrix.
> For now i post here the code so that if some expert has remarks i would be
> very glad to understand how to improve my code
> 
> I should acknowledge that finally the error was on my side in passing the
> dependencies, which tells that hpx actually runs as expected.
> even though the final code is very simple it took me 3 days to have it to
> run, 95% of it due to difficulties with the c++ interface.
> Even though this is largely due to my lack of understanding of advanced
> c++, allow me a constructive user feedback:

That conforms to our experience with other users. Most problems come from 
issues with C++ not with HPX. 

> 1 - I'd like to signal that compiler error message become very obscure
> once "dataflow" comes into play.
> essentially any error is signalled in a "something wrong in the dataflow
> call" instead of being pointed to correctly.
> I fully appreciated it is not HPX fault, however i can tell you that for
> an unexperienced user it is a very problematic situation.

Yah, errors caused by dataflow are not very useful. If you had some examples of 
code generating such errors we could try to improve those.

> 2 - it was not clear to me from the documentation that you expect either
> constant references or copy by value ... maybe an addition to your
> tutorial would or to your blog about this would be very interesting. I can
> ensure that for me it would have been impossible to figure this out from
> the error messages without Thomas's help.

This limitation is true for remote operation only (i.e. actions). But for those 
you should see static_asserts explaining things properly. Using local 
(non-action-based) async()/dataflow() do not have that restriction.

> 3 - it may be obvious for the developers but it was not obvious to me that
> unless i did a sort of "barrier" (wait_all) at the end of the code the
> destructors where being called before the parallel functions were
> executed. This was destroying my results. you might want to remark it in
> the documentation/blog posts...

Could you elaborate, please?

> 4 - the size of the overall HPX is huge. It would be much easier to
> include a dependency to it in other projects if it was split in smaller
> parts. For example if one is starting with SMP alone, dataflow & future
> would be very interesting on their own (i personally very much like the
> idea). Right now to compile HPX you also need all of the "distributed"
> code. the perfect situation would be that such core features are available
> as header only of course... Having said this i fully appreciate that the
> ideal situation would be to have such features available as part of the
> std lib.

Yes, that's something planned for HPX V2. Let's get V1 out of the door first, 
then we can look into this.

> as promised here goes my code. Any suggestion on how to improve it would
> be very welcome. In particular i don't love the idea of passing all of
> those pointers, i would prefer passing a NON-STATIC class variable, but i
> could not manage to do that.

You should be able to pass references instead. You would need to wrap the 
arguments in std::ref(), though:

int do_work(
    hpx::lcos::future<std::vector<hpx::lcos::shared_future<int> > > 
dependencies,
    int color,
    std::vector<int>& rows,
    std::vector<int>& cols,
    std::vector<double>& values,
    std::vector<double>& b,
    std::vector<double>& x)
{}

...

hpx::dataflow(hpx::launch::async,
    &do_work_pointerversion,
    hpx::when_all(item_dependencies.begin(), item_dependencies.end()),
    i, std::ref(rows), std::ref(cols), std::ref(values), std::ref(b), 
    std::ref(xparallel));


Alternatively you package the variables in a new type and invoke a member 
function of that type using dataflow:

struct my_type
{
    std::vector<int> rows;
    std::vector<int> cols
    std::vector<double> values;
    std::vector<double> b;
    std::vector<double> x;

    int do_work(
        hpx::future<std::vector<hpx::shared_future<int> > > dependencies,
        int color);
};

...

my_type t = {...};

hpx::dataflow(&my_type::do_work, &t, 
    hpx::when_all(item_dependencies.begin(), item_dependencies.end()),
    i);

also possible:

hpx::dataflow(&my_type::do_work, std::ref(t), 
    hpx::when_all(item_dependencies.begin(), item_dependencies.end()),
    i);

HTH
Regards Hartmut
---------------
http://boost-spirit.com
http://stellar.cct.lsu.edu


> 
> regards
> Riccardo
> 
> //[hello_world_client_getting_started
> #include <hpx/hpx_init.hpp>
> #include <hpx/hpx.hpp>
> #include <hpx/include/parallel_algorithm.hpp>
> #include <hpx/include/parallel_numeric.hpp>
> #include <hpx/include/threads.hpp>
> #include <hpx/include/threadmanager.hpp>
> #include <hpx/include/lcos.hpp>
> #include <unordered_map>
> #include <unordered_set>
> #include <vector>
> 
> //compile with
> //g++ -std=c++14 -fPIC coloring_simpler.cpp -o coloring.exe -
> I/home/rrossi/scratch/hpx/build -I/home/rrossi/scratch/hpx/hpx -
> I/home/rrossi/compiled_libraries/boost_1_62/include/ -
> L/home/rrossi/scratch/hpx/build/lib -lhpx -
> L/home/rrossi/compiled_libraries/boost_1_62/lib/ -lboost_program_options -
> lboost_system -lboost_thread
> 
> 
> 
> 
> 
> //this is the real worker function, which solves one line
> void SerialSolveLine(const int& i,
>                      const std::vector<int>& rows,
>                      const std::vector<int>& cols,
>                      const std::vector<double>& values,
>                      const std::vector<double>& b,
>                      std::vector<double>& x
>                     )
> {
>     const auto row_begin = rows[i];
>     const auto row_end = rows[i+1];
>     double diag;
>     double rhs = b[i];
>     for(int k = row_begin; k<row_end; k++)
>     {
> 
>         const auto col = cols[k];
>         const auto value = values[k];
>         if(col==i)
>             diag = value;
>         else
>             rhs -= value*x[col];
>     }
>     x[i] = rhs/diag;
> }
> 
> //provides the reference result
> void SerialTriangularSolve(const std::vector<int>& rows,
>                            const std::vector<int>& cols,
>                            const std::vector<double>& values,
>                            const std::vector<double>& b,
>                            std::vector<double>& x
>                           )
> {
>     for(unsigned int i=0; i<x.size(); i++)
>     {
>         SerialSolveLine(i,rows,cols,values,b,x);
>     }
> }
> 
> int do_work_pointerversion(
>     hpx::lcos::future<std::vector<hpx::lcos::shared_future<int> > >
> dependencies,
>     int color,
>     std::vector<int>* rows,
>     std::vector<int>* cols,
>     std::vector<double>* values,
>     std::vector<double>* b,
>     std::vector<double>* x)
> {
>     SerialSolveLine(color,*rows,*cols,*values,*b,*x);
>     return color;
> }
> 
> int hpx_main(boost::program_options::variables_map&)
> {
>     //lower triangular input matrix stored in compresses sparse row format
> //matrix
> // 1.0
> // 2.0 3.0
> //     4.0 5.0
> //         6.0 7.0
> //                 8.0
> //  11  10              9.0
> 
> //CSR format
> //rows vector 0     1       3       5       7    8           11
> //cols vector 0     0   1   1   2   2   3   4    0    1   5
> //values      1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 11.0 10.0 9.0
>     std::vector<int> rows = { 0, 1, 3, 5, 7, 8, 11};
>     std::vector<int> cols = {0,0,1,1,2,2,3,4,0,1,5};
>     std::vector<double> values =
> {1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,11.0,10.0,9.0};
> 
>     std::vector<double> b = {1.0,0.0,0.0,0.0,0.0,0.0};
>     std::vector<double> x(6);
>     std::vector<double> xparallel(6);
> 
>     int ncolors = x.size();
>     std::vector< std::unordered_set<unsigned int> > dependencies(ncolors);
>     dependencies[0]; //first has no dependencies
>     dependencies[1].insert({0}); //can be executed when 0 is done
>     dependencies[2].insert({1}); //can be executed when 1 is done
>     dependencies[3].insert({2}); //can be executed when 2 is done
>     dependencies[4]; //no dependencies
>     dependencies[5].insert({0,1}); //can be executed when both 0 and 1 are
> done
> 
>     ////////////////////////////////////////////////////////
>     //here reference serial solution
>     SerialTriangularSolve(rows,cols,values,b,x);
> 
>     std::cout << "reference result is " << std::endl;
>     for( auto it : x)
>         std::cout << it << std::endl;
>     std::cout << std::endl;
>     ////////////////////////////////////////////////////////
> 
>     //this is a set with all of the tasks i am spawning
>     std::unordered_map< unsigned int, hpx::lcos::shared_future<int> >
> work_items;
> 
>     //here i actually spawn the threads
>     for(int i=0; i<ncolors; i++)
>     {
>         std::vector< hpx::lcos::shared_future<int> > item_dependencies;
> 
>         item_dependencies.reserve(dependencies[i].size());
>         for(auto it : dependencies[i])
>         {
>             item_dependencies.push_back(work_items[it]);
>         }
> 
>         work_items[i] = hpx::dataflow(hpx::launch::async,
>                                       &do_work_pointerversion,
>                                       hpx::when_all(item_dependencies.begi
> n(), item_dependencies.end()),
>                                       i, &rows, &cols, &values, &b,
> &xparallel );
>     }
> 
>     //the following wait_all is FUNDAMENTAL, otherwise it calls the
> destructor and the results are bullshit
>     std::vector< hpx::lcos::shared_future<int> > towait;
>     for(auto it : work_items)
>         towait.push_back(it.second);
>     hpx::wait_all(towait);
> 
>     std::cout << "parallel futurized result is " << std::endl;
>     for( auto it : xparallel)
>         std::cout << it << std::endl;
> 
>     return hpx::finalize(); // Initiate shutdown of the runtime system.
> }
> 
> int main(int argc, char* argv[])
> {
>     return hpx::init(argc, argv); // Initialize and run HPX.
> }
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> --
> Riccardo Rossi
> PhD, Civil Engineer
> 
> member of the Kratos Team: www.cimne.com/kratos
> Tenure Track Lecturer at Universitat Politècnica de Catalunya,
> BarcelonaTech (UPC)
> Full Research Professor at International Center for Numerical Methods in
> Engineering (CIMNE)
> 
> C/ Gran Capità, s/n, Campus Nord UPC, Ed. B0, Despatx 102
> (please deliver post to the porters of building C1)
> 08034 – Barcelona – Spain – www.cimne.com  -
> T.(+34) 93 401 56 96 skype: rougered4
> 
> 
> 
> Les dades personals contingudes en aquest missatge són tractades amb la
> finalitat de mantenir el contacte professional entre CIMNE i voste. Podra
> exercir els drets d'accés, rectificació, cancel·lació i oposició,
> dirigint-se a [email protected]. La utilització de la seva adreça de
> correu electronic per part de CIMNE queda subjecte a les disposicions de
> la Llei 34/2002, de Serveis de la Societat de la Informació i el Comerç
> Electronic.
>  Imprimiu aquest missatge, només si és estrictament necessari.

_______________________________________________
hpx-users mailing list
[email protected]
https://mail.cct.lsu.edu/mailman/listinfo/hpx-users

Reply via email to