gem5  v20.1.0.0
coroutine.test.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018 ARM Limited
3  * All rights reserved
4  *
5  * The license below extends only to copyright in the software and shall
6  * not be construed as granting a license to any other intellectual
7  * property including but not limited to intellectual property relating
8  * to a hardware implementation of the functionality of the software
9  * licensed hereunder. You may use the software subject to the license
10  * terms below provided that you ensure that this notice is replicated
11  * unmodified and in its entirety in all distributions of the software,
12  * modified or unmodified, in source code or in binary form.
13  *
14  * Redistribution and use in source and binary forms, with or without
15  * modification, are permitted provided that the following conditions are
16  * met: redistributions of source code must retain the above copyright
17  * notice, this list of conditions and the following disclaimer;
18  * redistributions in binary form must reproduce the above copyright
19  * notice, this list of conditions and the following disclaimer in the
20  * documentation and/or other materials provided with the distribution;
21  * neither the name of the copyright holders nor the names of its
22  * contributors may be used to endorse or promote products derived from
23  * this software without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36  */
37 
38 #include <gtest/gtest.h>
39 
40 #include "base/coroutine.hh"
41 
42 using namespace m5;
43 
49 TEST(Coroutine, Unstarted)
50 {
51  auto yielding_task =
53  {
54  yield();
55  };
56 
57  const bool start_upon_creation = false;
58  Coroutine<void, void> coro(yielding_task, start_upon_creation);
59 
60  ASSERT_FALSE(coro.started());
61 }
62 
67 TEST(Coroutine, Unfinished)
68 {
69  auto yielding_task =
71  {
72  yield();
73  };
74 
75  Coroutine<void, void> coro(yielding_task);
76  ASSERT_TRUE(coro);
77 }
78 
85 TEST(Coroutine, Passing)
86 {
87  const std::vector<int> input{ 1, 2, 3 };
88  const std::vector<int> expected_values = input;
89 
90  auto passing_task =
91  [&expected_values] (Coroutine<int, void>::CallerType& yield)
92  {
93  int argument;
94 
95  for (const auto expected : expected_values) {
96  argument = yield.get();
97  ASSERT_EQ(argument, expected);
98  }
99  };
100 
101  Coroutine<int, void> coro(passing_task);
102  ASSERT_TRUE(coro);
103 
104  for (const auto val : input) {
105  coro(val);
106  }
107 }
108 
115 TEST(Coroutine, Returning)
116 {
117  const std::vector<int> output{ 1, 2, 3 };
118  const std::vector<int> expected_values = output;
119 
120  auto returning_task =
122  {
123  for (const auto ret : output) {
124  yield(ret);
125  }
126  };
127 
128  Coroutine<void, int> coro(returning_task);
129  ASSERT_TRUE(coro);
130 
131  for (const auto expected : expected_values) {
132  int returned = coro.get();
133  ASSERT_EQ(returned, expected);
134  }
135 }
136 
144 TEST(Coroutine, Fibonacci)
145 {
146  const std::vector<int> expected_values{
147  1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233 };
148 
149  const int steps = expected_values.size();
150 
151  auto fibonacci_task =
152  [steps] (Coroutine<void, int>::CallerType& yield)
153  {
154  int prev = 0;
155  int current = 1;
156 
157  for (auto iter = 0; iter < steps; iter++) {
158  int sum = prev + current;
159  yield(sum);
160 
161  prev = current;
162  current = sum;
163  }
164  };
165 
166  Coroutine<void, int> coro(fibonacci_task);
167  ASSERT_TRUE(coro);
168 
169  for (const auto expected : expected_values) {
170  ASSERT_TRUE(coro);
171  int returned = coro.get();
172  ASSERT_EQ(returned, expected);
173  }
174 }
175 
185 TEST(Coroutine, Cooperative)
186 {
187  const std::string caller_str("HloWrd");
188  const std::string coro_str("el ol!");
189  const std::string expected("Hello World!");
190 
191  auto cooperative_task =
193  {
194  for (auto& appended_c : coro_str) {
195  auto old_str = yield.get();
196  yield(old_str + appended_c);
197  }
198  };
199 
200  Coroutine<std::string, std::string> coro(cooperative_task);
201 
202  std::string result;
203  for (auto& c : caller_str) {
204  ASSERT_TRUE(coro);
205  result += c;
206  result = coro(result).get();
207  }
208 
209  ASSERT_EQ(result, expected);
210 }
211 
218 TEST(Coroutine, Nested)
219 {
220  const std::string wrong("Inner");
221  const std::string expected("Inner + Outer");
222 
223  auto inner_task =
225  {
226  std::string inner_string("Inner");
227  yield(inner_string);
228  };
229 
230  auto outer_task =
231  [&inner_task] (Coroutine<void, std::string>::CallerType& yield)
232  {
233  Coroutine<void, std::string> coro(inner_task);
234  std::string inner_string = coro.get();
235 
236  std::string outer_string("Outer");
237  yield(inner_string + " + " + outer_string);
238  };
239 
240 
241  Coroutine<void, std::string> coro(outer_task);
242  ASSERT_TRUE(coro);
243 
244  std::string result = coro.get();
245 
246  ASSERT_NE(result, wrong);
247  ASSERT_EQ(result, expected);
248 }
249 
259 TEST(Coroutine, TwoCallers)
260 {
261  bool valid_return = false;
262 
263  Coroutine<void, void> callee{[]
265  {
266  yield();
267  yield();
268  }};
269 
270  Coroutine<void, void> other_caller{[&callee, &valid_return]
272  {
273  callee();
274  valid_return = true;
275  yield();
276  }};
277 
278  ASSERT_TRUE(valid_return);
279 }
output
static void output(const char *filename)
Definition: debug.cc:60
RiscvISA::sum
Bitfield< 18 > sum
Definition: registers.hh:609
m5::Coroutine::CallerType
CallerType: A reference to an object of this class will be passed to the coroutine task.
Definition: coroutine.hh:83
std::vector< int >
m5
Definition: compiler.hh:90
TEST
TEST(Coroutine, Unstarted)
This test is checking if the Coroutine, once it's created it doesn't start since the second argument ...
Definition: coroutine.test.cc:49
m5::Coroutine::get
std::enable_if<!std::is_same< T, void >::value, T >::type get()
get() is the way we can extrapolate return values (yielded) from the coroutine.
Definition: coroutine.hh:249
X86ISA::val
Bitfield< 63 > val
Definition: misc.hh:769
m5::Coroutine
This template defines a Coroutine wrapper type with a Boost-like interface.
Definition: coroutine.hh:62
Fiber::started
bool started() const
Returns whether the "main" function of this fiber has started.
Definition: fiber.hh:107
coroutine.hh
ArmISA::c
Bitfield< 29 > c
Definition: miscregs_types.hh:50
expected
std::vector< SwitchingFiber * > expected({ &a, &b, &a, &a, &a, &b, &c, &a, &c, &c, &c })

Generated on Wed Sep 30 2020 14:02:07 for gem5 by doxygen 1.8.17