xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/unittests/parallel-for-selftests.c (revision f8cf1a9151c7af1cb0bd8b09c13c66bca599c027)
1 /* Self tests for parallel_for_each
2 
3    Copyright (C) 2021-2023 Free Software Foundation, Inc.
4 
5    This file is part of GDB.
6 
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11 
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16 
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
19 
20 /* This file is divided in two parts:
21    - FOR_EACH-undefined, and
22    - FOR_EACH-defined.
23    The former includes the latter, more than once, with different values for
24    FOR_EACH.  The FOR_EACH-defined part reads like a regular function.  */
25 #ifndef FOR_EACH
26 
27 #include "defs.h"
28 #include "gdbsupport/selftest.h"
29 #include "gdbsupport/parallel-for.h"
30 
31 #if CXX_STD_THREAD
32 
33 #include "gdbsupport/thread-pool.h"
34 
35 namespace selftests {
36 namespace parallel_for {
37 
38 struct save_restore_n_threads
39 {
40   save_restore_n_threads ()
41     : n_threads (gdb::thread_pool::g_thread_pool->thread_count ())
42   {
43   }
44 
45   ~save_restore_n_threads ()
46   {
47     gdb::thread_pool::g_thread_pool->set_thread_count (n_threads);
48   }
49 
50   int n_threads;
51 };
52 
53 /* Define test_par using TEST in the FOR_EACH-defined part.  */
54 #define TEST test_par
55 #define FOR_EACH gdb::parallel_for_each
56 #include "parallel-for-selftests.c"
57 #undef FOR_EACH
58 #undef TEST
59 
60 /* Define test_seq using TEST in the FOR_EACH-defined part.  */
61 #define TEST test_seq
62 #define FOR_EACH gdb::sequential_for_each
63 #include "parallel-for-selftests.c"
64 #undef FOR_EACH
65 #undef TEST
66 
67 static void
68 test (int n_threads)
69 {
70   test_par (n_threads);
71   test_seq (n_threads);
72 }
73 
74 static void
75 test_n_threads ()
76 {
77   test (0);
78   test (1);
79   test (3);
80 }
81 
82 }
83 }
84 
85 #endif /* CXX_STD_THREAD */
86 
87 void _initialize_parallel_for_selftests ();
88 void
89 _initialize_parallel_for_selftests ()
90 {
91 #ifdef CXX_STD_THREAD
92   selftests::register_test ("parallel_for",
93 			    selftests::parallel_for::test_n_threads);
94 #endif /* CXX_STD_THREAD */
95 }
96 
97 #else /* FOR_EACH */
98 
99 static void
100 TEST (int n_threads)
101 {
102   save_restore_n_threads saver;
103   gdb::thread_pool::g_thread_pool->set_thread_count (n_threads);
104 
105 #define NUMBER 10000
106 
107   std::atomic<int> counter (0);
108   FOR_EACH (1, 0, NUMBER,
109 	    [&] (int start, int end)
110 	    {
111 	      counter += end - start;
112 	    });
113   SELF_CHECK (counter == NUMBER);
114 
115   counter = 0;
116   FOR_EACH (1, 0, 0,
117 	    [&] (int start, int end)
118 	    {
119 	      counter += end - start;
120 	    });
121   SELF_CHECK (counter == 0);
122 
123   auto task_size_max_ = [] (int iter)
124     {
125       return (size_t)SIZE_MAX;
126     };
127   auto task_size_max = gdb::make_function_view (task_size_max_);
128 
129   counter = 0;
130   FOR_EACH (1, 0, NUMBER,
131 	    [&] (int start, int end)
132 	    {
133 	      counter += end - start;
134 	    }, task_size_max);
135   SELF_CHECK (counter == NUMBER);
136 
137   auto task_size_one_ = [] (int iter)
138     {
139       return (size_t)1;
140     };
141   auto task_size_one = gdb::make_function_view (task_size_one_);
142 
143   counter = 0;
144   FOR_EACH (1, 0, NUMBER,
145 	    [&] (int start, int end)
146 	    {
147 	      counter += end - start;
148 	    }, task_size_one);
149   SELF_CHECK (counter == NUMBER);
150 
151 #undef NUMBER
152 
153   /* Check that if there are fewer tasks than threads, then we won't
154      end up with a null result.  */
155   std::vector<std::unique_ptr<int>> intresults;
156   std::atomic<bool> any_empty_tasks (false);
157 
158   FOR_EACH (1, 0, 1,
159 	    [&] (int start, int end)
160 	      {
161 		if (start == end)
162 		  any_empty_tasks = true;
163 		return std::unique_ptr<int> (new int (end - start));
164 	      });
165   SELF_CHECK (!any_empty_tasks);
166   SELF_CHECK (std::all_of (intresults.begin (),
167 			   intresults.end (),
168 			   [] (const std::unique_ptr<int> &entry)
169 			     {
170 			       return entry != nullptr;
171 			     }));
172 
173   /* The same but using the task size parameter.  */
174   intresults.clear ();
175   any_empty_tasks = false;
176   FOR_EACH (1, 0, 1,
177 	    [&] (int start, int end)
178 	      {
179 		if (start == end)
180 		  any_empty_tasks = true;
181 		return std::unique_ptr<int> (new int (end - start));
182 	      },
183 	    task_size_one);
184   SELF_CHECK (!any_empty_tasks);
185   SELF_CHECK (std::all_of (intresults.begin (),
186 			   intresults.end (),
187 			   [] (const std::unique_ptr<int> &entry)
188 			     {
189 			       return entry != nullptr;
190 			     }));
191 }
192 
193 #endif /* FOR_EACH */
194