Skip to content

Commit 7777bee

Browse files
committed
pct_strategy: run round robin for livelock avoding
1 parent 5030643 commit 7777bee

File tree

2 files changed

+50
-28
lines changed

2 files changed

+50
-28
lines changed

runtime/include/pct_strategy.h

Lines changed: 45 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,7 @@ struct PctStrategy : public BaseStrategyWithThreads<TargetObj, Verifier> {
3434
size_t NextThreadId() override {
3535
auto& threads = this->threads;
3636
int max = std::numeric_limits<int>::min();
37-
int snd_max = std::numeric_limits<int>::min();
38-
size_t index_of_max = 0, index_of_snd_max = 0;
37+
size_t index_of_max = 0;
3938
// Have to ignore waiting threads, so can't do it faster than O(n)
4039
for (size_t i = 0; i < threads.size(); ++i) {
4140
// Ignore waiting tasks
@@ -51,21 +50,31 @@ struct PctStrategy : public BaseStrategyWithThreads<TargetObj, Verifier> {
5150
}
5251

5352
if (max <= priorities[i]) {
54-
index_of_snd_max = index_of_max;
55-
snd_max = max;
5653
max = priorities[i];
5754
index_of_max = i;
58-
} else if (snd_max <= priorities[i]) {
59-
snd_max = priorities[i];
60-
index_of_snd_max = i;
55+
}
56+
}
57+
58+
if (round_robin_stage > 0) {
59+
for (size_t attempt = 0; attempt < threads.size(); ++attempt) {
60+
auto i = (++last_chosen) % threads.size();
61+
if (!threads[i].empty() && threads[i].back()->IsBlocked()) {
62+
continue;
63+
}
64+
index_of_max = i;
65+
max = priorities[i];
66+
break;
67+
}
68+
// debug(stderr, "round robin choose: %d\n", index_of_max);
69+
if (round_robin_start == index_of_max) {
70+
--round_robin_stage;
6171
}
6272
}
6373

6474
// TODO: Choose wiser constant
65-
if (count_chosen_same == 100 && index_of_max == last_chosen &&
66-
snd_max != std::numeric_limits<int>::min()) {
67-
priorities[index_of_max] = snd_max - 1;
68-
index_of_max = index_of_snd_max;
75+
if (count_chosen_same == 1000 && index_of_max == last_chosen) {
76+
round_robin_stage = 5;
77+
round_robin_start = index_of_max;
6978
}
7079

7180
if (index_of_max == last_chosen) {
@@ -97,8 +106,7 @@ struct PctStrategy : public BaseStrategyWithThreads<TargetObj, Verifier> {
97106
auto& round_schedule = this->round_schedule;
98107
auto& threads = this->threads;
99108
int max = std::numeric_limits<int>::min();
100-
int snd_max = std::numeric_limits<int>::min();
101-
size_t index_of_max = 0, index_of_snd_max = 0;
109+
size_t index_of_max = 0;
102110
// Have to ignore waiting threads, so can't do it faster than O(n)
103111
for (size_t i = 0; i < threads.size(); ++i) {
104112
int task_index = this->GetNextTaskInThread(i);
@@ -113,29 +121,40 @@ struct PctStrategy : public BaseStrategyWithThreads<TargetObj, Verifier> {
113121
}
114122

115123
if (max <= priorities[i]) {
116-
index_of_snd_max = index_of_max;
117-
snd_max = max;
118124
max = priorities[i];
119125
index_of_max = i;
120-
} else if (snd_max <= priorities[i]) {
121-
snd_max = priorities[i];
122-
index_of_snd_max = i;
126+
}
127+
}
128+
129+
if (round_robin_stage > 0) {
130+
for (size_t attempt = 0; attempt < threads.size(); ++attempt) {
131+
auto i = (++last_chosen) % threads.size();
132+
int task_index = this->GetNextTaskInThread(i);
133+
if (task_index == threads[i].size() ||
134+
threads[i][task_index]->IsBlocked()) {
135+
continue;
136+
}
137+
index_of_max = i;
138+
max = priorities[i];
139+
break;
140+
}
141+
// debug(stderr, "round robin choose: %d\n", index_of_max);
142+
if (round_robin_start == index_of_max) {
143+
--round_robin_stage;
123144
}
124145
}
125146

126147
// TODO: Choose wiser constant
127-
if (count_chosen_same == 100 && index_of_max == last_chosen &&
128-
snd_max != std::numeric_limits<int>::min()) {
129-
priorities[index_of_max] = snd_max - 1;
130-
index_of_max = index_of_snd_max;
148+
if (count_chosen_same == 1000 && index_of_max == last_chosen) {
149+
round_robin_stage = 5;
150+
round_robin_start = index_of_max;
131151
}
132152

133153
if (index_of_max == last_chosen) {
134154
++count_chosen_same;
135155
} else {
136156
count_chosen_same = 1;
137157
}
138-
139158
last_chosen = index_of_max;
140159
// Picked thread is `index_of_max`
141160
int next_task_index = this->GetNextTaskInThread(index_of_max);
@@ -179,6 +198,7 @@ struct PctStrategy : public BaseStrategyWithThreads<TargetObj, Verifier> {
179198
k_statistics.push_back(current_schedule_length);
180199
current_schedule_length = 0;
181200
count_chosen_same = 0;
201+
round_robin_stage = 0;
182202

183203
// current_depth have been increased
184204
size_t new_k = std::reduce(k_statistics.begin(), k_statistics.end()) /
@@ -211,6 +231,8 @@ struct PctStrategy : public BaseStrategyWithThreads<TargetObj, Verifier> {
211231
// original article)
212232
size_t count_chosen_same;
213233
size_t last_chosen;
234+
size_t round_robin_start;
235+
size_t round_robin_stage{0};
214236
std::vector<int> priorities;
215237
std::vector<size_t> priority_change_points;
216238
std::mt19937 rng;

runtime/include/scheduler.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ struct BaseStrategyWithThreads : public Strategy {
164164
size_t tasks_in_thread = thread.size();
165165
for (size_t i = 0; i < tasks_in_thread; ++i) {
166166
if (!IsTaskRemoved(thread[i]->GetId())) {
167-
thread[i] = thread[i]->Restart(&*state);
167+
thread[i] = thread[i]->Restart(state.get());
168168
}
169169
}
170170
}
@@ -220,7 +220,7 @@ struct BaseStrategyWithThreads : public Strategy {
220220
}
221221
threads[thread_index].emplace_back(
222222
this->constructors[verified_constructor].Build(
223-
&*this->state, thread_index, this->new_task_id++));
223+
this->state.get(), thread_index, this->new_task_id++));
224224
TaskWithMetaData task{threads[thread_index].back(), true, thread_index};
225225
return task;
226226
}
@@ -264,7 +264,7 @@ struct BaseStrategyWithThreads : public Strategy {
264264
return b.GetName() == *releaseTask;
265265
});
266266
auto task =
267-
constructor.Build(&*this->state, thread_index, task_index);
267+
constructor.Build(this->state.get(), thread_index, task_index);
268268
auto verified = this->sched_checker.Verify(CreatedTaskMetaData{
269269
std::string(task->GetName()), true, thread_index});
270270
assert(verified && "wrong release task at termination");
@@ -615,7 +615,7 @@ struct TLAScheduler : Scheduler {
615615
if (frame.is_new) {
616616
// It was a new task.
617617
// So restart it from the beginning with the same args.
618-
*task = (*task)->Restart(&*state);
618+
*task = (*task)->Restart(state.get());
619619
} else {
620620
// It was a not new task, hence, we recreated in early.
621621
}
@@ -732,7 +732,7 @@ struct TLAScheduler : Scheduler {
732732
for (size_t cons_num = 0; auto cons : constructors) {
733733
frame.is_new = true;
734734
auto size_before = tasks.size();
735-
tasks.emplace_back(cons.Build(&*state, i, -1 /* TODO: fix task id for tla, because it is Scheduler and not Strategy class for some reason */));
735+
tasks.emplace_back(cons.Build(state.get(), i, -1 /* TODO: fix task id for tla, because it is Scheduler and not Strategy class for some reason */));
736736

737737
auto [is_over, res] = ResumeTask(frame, step, switches, thread, true);
738738
if (is_over || res.has_value()) {

0 commit comments

Comments
 (0)