Skip to content

Commit f8b4d0e

Browse files
Martin Huschenbettcopybara-github
Martin Huschenbett
authored andcommitted
Add a new ActionType::SOURCE_SET for handling the case where we inspect the source sets of the origin. This requires the addition of two new fields to Action as well that are only used with this action type. Hence the unions.
The benefit of handling the source sets with a separate action is that we push fewer actions onto the `actions` stack and that the maximal stack size decreases. The runtime performance benefits of this seems to be rather small (140s -> 138s). PiperOrigin-RevId: 707500665
1 parent cdc2776 commit f8b4d0e

File tree

1 file changed

+45
-22
lines changed

1 file changed

+45
-22
lines changed

pytype/typegraph/solver.cc

Lines changed: 45 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ struct TraverseState {
4242

4343
enum ActionType {
4444
TRAVERSE,
45+
SOURCE_SET,
4546
INSERT_GOALS_TO_REMOVE,
4647
ERASE_GOALS_TO_REMOVE,
4748
ERASE_SEEN_GOALS,
@@ -57,20 +58,36 @@ enum ActionType {
5758
// through "actions".
5859
struct Action {
5960
ActionType action_type;
60-
// Goal either to delete are added to the corresponding set.
61-
const Binding* goal;
62-
// The iterator is for std::set and this is stable upon deletion and insertion
63-
// if it's not directly the element being deleted or inserted. We will only
64-
// try to erase the element on the exact node traversal, so we can safely
65-
// reuse the iterator that was returned from the insertion.
66-
// Not using this for action ERASE_GOALS_TO_REMOVE, as we are requesting
67-
// for removal before the insertion has happened.
68-
GoalSet::iterator erase_it;
61+
union {
62+
// Goal either to delete are added to the corresponding set.
63+
const Binding* goal;
64+
// Source set to handle by a SOURCE_SET action. This is never the same as
65+
// source_sets_end for actions on the actions stack.
66+
std::set<SourceSet>::const_iterator source_sets_it;
67+
};
68+
union {
69+
// The iterator is for std::set and this is stable upon deletion and
70+
// insertion if it's not directly the element being deleted or inserted.
71+
// We will only try to erase the element on the exact node traversal, so
72+
// we can safely reuse the iterator that was returned from the insertion.
73+
// Not using this for action ERASE_GOALS_TO_REMOVE, as we are requesting
74+
// for removal before the insertion has happened.
75+
GoalSet::iterator erase_it;
76+
// End of the source sets in a SOURCE_SET action.
77+
std::set<SourceSet>::const_iterator source_sets_end;
78+
};
79+
6980
Action(ActionType action_type, const Binding* goal)
7081
: action_type(action_type), goal(goal) {}
7182
Action(ActionType action_type, const Binding* goal,
7283
GoalSet::iterator erase_it)
7384
: action_type(action_type), goal(goal), erase_it(erase_it) {}
85+
Action(ActionType action_type,
86+
std::set<SourceSet>::const_iterator source_sets_it,
87+
std::set<SourceSet>::const_iterator source_sets_end)
88+
: action_type(action_type),
89+
source_sets_it(source_sets_it),
90+
source_sets_end(source_sets_end) {}
7491
};
7592

7693
static void traverse(const CFGNode* position,
@@ -104,19 +121,10 @@ static void traverse(const CFGNode* position,
104121
}
105122

106123
state.removed_goals.push_back(goal);
107-
actions.emplace(ERASE_REMOVED_GOALS, nullptr);
108-
for (const auto& source_set : origin->source_sets) {
109-
for (const Binding* next_goal : source_set) {
110-
if (!state.goals_to_remove.count(next_goal)) {
111-
actions.emplace(ERASE_GOALS_TO_REMOVE, next_goal);
112-
}
113-
}
114-
actions.emplace(TRAVERSE, nullptr);
115-
for (const Binding* next_goal : source_set) {
116-
if (!state.goals_to_remove.count(next_goal)) {
117-
actions.emplace(INSERT_GOALS_TO_REMOVE, next_goal);
118-
}
119-
}
124+
actions.emplace(ERASE_REMOVED_GOALS, nullptr, it);
125+
if (!origin->source_sets.empty()) {
126+
actions.emplace(SOURCE_SET, origin->source_sets.cbegin(),
127+
origin->source_sets.cend());
120128
}
121129
}
122130

@@ -149,6 +157,21 @@ static std::vector<RemoveResult> remove_finished_goals(const CFGNode* pos,
149157
case TRAVERSE:
150158
traverse(pos, results, actions, state);
151159
break;
160+
case SOURCE_SET: {
161+
const auto& source_set = *action.source_sets_it;
162+
action.source_sets_it++;
163+
if (action.source_sets_it != action.source_sets_end) {
164+
actions.push(action);
165+
}
166+
for (const Binding* next_goal : source_set) {
167+
auto [it, added] = state.goals_to_remove.insert(next_goal);
168+
if (added) {
169+
actions.emplace(ERASE_GOALS_TO_REMOVE, next_goal);
170+
}
171+
}
172+
actions.emplace(TRAVERSE, nullptr);
173+
break;
174+
}
152175
case INSERT_GOALS_TO_REMOVE:
153176
state.goals_to_remove.insert(action.goal);
154177
break;

0 commit comments

Comments
 (0)