]> https://gitweb.dealii.org/ - dealii.git/commitdiff
Parallelize the operation of compute_number_cache().
authorWolfgang Bangerth <bangerth@colostate.edu>
Mon, 26 Sep 2016 21:49:55 +0000 (16:49 -0500)
committerWolfgang Bangerth <bangerth@colostate.edu>
Tue, 27 Sep 2016 04:32:03 +0000 (23:32 -0500)
For these functions, the 3d version calls the 2d version which itself calls the
1d version. These operations can all run concurrently. All three include two
loops each over all cells/quads/lines, so there should be plenty to do to
amortize parallel execution.

The only tricky part is that the quad and hex functions accessed a variable
that was first set by the 1d function (number_cache.n_lines). This may now
no longer be available in time for the 2d/3d functions, and so they
need to compute this information themselves. This is cheap, fortunately.

source/grid/tria.cc

index e5e5f94374b0c5efafb337a36d2414b82f601473..4afb503ada7a522c67decfc50d40103bfd848b5e 100644 (file)
@@ -1409,37 +1409,57 @@ namespace internal
                                  const unsigned int                       level_objects,
                                  internal::Triangulation::NumberCache<2> &number_cache)
       {
-        // update lines and n_levels
-        compute_number_cache (triangulation,
-                              level_objects,
-                              static_cast<internal::Triangulation::NumberCache<1>&>
-                              (number_cache));
+        // update lines and n_levels in number_cache. since we don't
+        // access any of these numbers, we can do this in the
+        // background
+        Threads::Task<void> update_lines
+          = Threads::new_task ((void (*)(const Triangulation<dim,spacedim> &,
+                                         const unsigned int,
+                                         internal::Triangulation::NumberCache<1> &))
+                               (&compute_number_cache<dim,spacedim>),
+                               triangulation,
+                               level_objects,
+                               static_cast<internal::Triangulation::NumberCache<1>&>
+                               (number_cache));
 
         typedef
         typename Triangulation<dim,spacedim>::quad_iterator quad_iterator;
         typedef
         typename Triangulation<dim,spacedim>::active_quad_iterator active_quad_iterator;
 
+        // count the number of levels; the function we called above
+        // for lines also does this and puts it into
+        // number_cache.n_levels, but this datum may not yet be
+        // available as we call the function on a separate task
+        unsigned int n_levels = 0;
+        if (level_objects > 0)
+          // find the last level on which there are used cells
+          for (unsigned int level=0; level<level_objects; ++level)
+            if (triangulation.begin(level) !=
+                triangulation.end(level))
+              n_levels = level+1;
+
+
         ///////////////////////////////////
         // update the number of quads on the different levels in the
         // cache
-        number_cache.n_quads_level.resize (number_cache.n_levels);
+        number_cache.n_quads_level.resize (n_levels);
         number_cache.n_quads = 0;
 
-        number_cache.n_active_quads_level.resize (number_cache.n_levels);
+        number_cache.n_active_quads_level.resize (n_levels);
         number_cache.n_active_quads = 0;
 
         // for 2d, quads have levels so take count the objects per
         // level and globally
         if (dim == 2)
           {
-            for (unsigned int level=0; level<number_cache.n_levels; ++level)
+            for (unsigned int level=0; level<n_levels; ++level)
               {
                 // count quads on this level
                 number_cache.n_quads_level[level] = 0;
 
                 quad_iterator quad = triangulation.begin_quad (level),
-                              endc = (level == number_cache.n_levels-1 ?
+                              endc = (level == n_levels-1 ?
                                       quad_iterator(triangulation.end_quad()) :
                                       triangulation.begin_quad (level+1));
                 for (; quad!=endc; ++quad)
@@ -1450,7 +1470,7 @@ namespace internal
               }
 
             // do the update for the number of active quads as well
-            for (unsigned int level=0; level<number_cache.n_levels; ++level)
+            for (unsigned int level=0; level<n_levels; ++level)
               {
                 // count quads on this level
                 number_cache.n_active_quads_level[level] = 0;
@@ -1481,6 +1501,9 @@ namespace internal
                 ++number_cache.n_active_quads;
             }
           }
+
+        // wait for the background computation for lines
+        update_lines.join ();
       }
 
       /**
@@ -1504,37 +1527,57 @@ namespace internal
                                  const unsigned int                       level_objects,
                                  internal::Triangulation::NumberCache<3> &number_cache)
       {
-        // update quads, lines and n_levels
-        compute_number_cache (triangulation,
-                              level_objects,
-                              static_cast<internal::Triangulation::NumberCache<2>&>
-                              (number_cache));
+        // update quads, lines and n_levels in number_cache. since we
+        // don't access any of these numbers, we can do this in the
+        // background
+        Threads::Task<void> update_quads_and_lines
+          = Threads::new_task ((void (*)(const Triangulation<dim,spacedim> &,
+                                         const unsigned int,
+                                         internal::Triangulation::NumberCache<2> &))
+                               (&compute_number_cache<dim,spacedim>),
+                               triangulation,
+                               level_objects,
+                               static_cast<internal::Triangulation::NumberCache<2>&>
+                               (number_cache));
 
         typedef
         typename Triangulation<dim,spacedim>::hex_iterator hex_iterator;
         typedef
         typename Triangulation<dim,spacedim>::active_hex_iterator active_hex_iterator;
 
+        // count the number of levels; the function we called above
+        // for quads (recursively, via the lines function) also does
+        // this and puts it into number_cache.n_levels, but this datum
+        // may not yet be available as we call the function on a
+        // separate task
+        unsigned int n_levels = 0;
+        if (level_objects > 0)
+          // find the last level on which there are used cells
+          for (unsigned int level=0; level<level_objects; ++level)
+            if (triangulation.begin(level) !=
+                triangulation.end(level))
+              n_levels = level+1;
+
         ///////////////////////////////////
         // update the number of hexes on the different levels in the
         // cache
-        number_cache.n_hexes_level.resize (number_cache.n_levels);
+        number_cache.n_hexes_level.resize (n_levels);
         number_cache.n_hexes = 0;
 
-        number_cache.n_active_hexes_level.resize (number_cache.n_levels);
+        number_cache.n_active_hexes_level.resize (n_levels);
         number_cache.n_active_hexes = 0;
 
         // for 3d, hexes have levels so take count the objects per
         // level and globally
         if (dim == 3)
           {
-            for (unsigned int level=0; level<number_cache.n_levels; ++level)
+            for (unsigned int level=0; level<n_levels; ++level)
               {
                 // count hexes on this level
                 number_cache.n_hexes_level[level] = 0;
 
                 hex_iterator hex = triangulation.begin_hex (level),
-                             endc = (level == number_cache.n_levels-1 ?
+                             endc = (level == n_levels-1 ?
                                      hex_iterator(triangulation.end_hex()) :
                                      triangulation.begin_hex (level+1));
                 for (; hex!=endc; ++hex)
@@ -1545,7 +1588,7 @@ namespace internal
               }
 
             // do the update for the number of active hexes as well
-            for (unsigned int level=0; level<number_cache.n_levels; ++level)
+            for (unsigned int level=0; level<n_levels; ++level)
               {
                 // count hexes on this level
                 number_cache.n_active_hexes_level[level] = 0;
@@ -1576,6 +1619,9 @@ namespace internal
                 ++number_cache.n_active_hexes;
             }
           }
+
+        // wait for the background computation for quads
+        update_quads_and_lines.join ();
       }
 
 

In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.

Douglas Adams


Typeset in Trocchi and Trocchi Bold Sans Serif.