Skip to content

Commit 8c57097

Browse files
committed
Optimization.
1 parent 4beaab8 commit 8c57097

File tree

2 files changed

+186
-124
lines changed

2 files changed

+186
-124
lines changed

build/lib/src/library_cycle_graph/library_cycle_graph_loader.dart

Lines changed: 70 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ class LibraryCycleGraphLoader {
8282
_newAssets.clear();
8383
_cycles.clear();
8484
_graphs.clear();
85+
_graphsToComputeByPhase.clear();
86+
_runningAtPhases.clear();
8587
}
8688

8789
/// Loads [id] and its transitive dependencies at all phases available to
@@ -103,9 +105,10 @@ class LibraryCycleGraphLoader {
103105
.where((entry) => entry.key <= assetDepsLoader.phase)
104106
.any((entry) => entry.value.isNotEmpty)) {
105107
final firstPhase = (_idsToLoad.keys..toList().sort()).firstWhere(
106-
(key) => key <= assetDepsLoader.phase && _idsToLoad[key]!.isNotEmpty);
108+
(key) => key <= assetDepsLoader.phase && _idsToLoad[key]!.isNotEmpty,
109+
);
107110
final idToLoad = _idsToLoad[firstPhase]!.last;
108-
print('($_runningAtPhases, $id) take $idToLoad at phase $firstPhase');
111+
// print('($_runningAtPhases, $id) take $idToLoad at phase $firstPhase');
109112

110113
// Nothing to do if deps were already loaded, unless they expire and
111114
// [assetDepsLoader] is at a late enough phase to see the updated value.
@@ -116,41 +119,44 @@ class LibraryCycleGraphLoader {
116119
continue;
117120
}
118121

119-
print(
120-
'($_runningAtPhases, $id) Load $idToLoad at ${assetDepsLoader.phase}');
122+
/* print(
123+
'($_runningAtPhases, $id) Load
124+
$idToLoad at ${assetDepsLoader.phase}');*/
121125
final assetDeps =
122126
_assetDeps[idToLoad] = await assetDepsLoader.load(idToLoad);
123127

124128
// First time seeing the asset, mark for computation of cycles and
125129
// graphs given the initial state of the build.
126130
if (alreadyLoadedAssetDeps == null) {
127-
print('For phase $firstPhase, Add to new assets: $idToLoad');
131+
// print('For phase $firstPhase, Add to new assets: $idToLoad');
128132
_newAssets.add(idToLoad);
129133
}
130134

131135
if (assetDeps.isComplete) {
132136
// "isComplete" means it's a source file or a generated value that has
133137
// already been generated. It has deps, so mark them for loading.
134-
print(
135-
'($_runningAtPhases, $id) Completed $idToLoad: ${assetDeps.lastValue.deps}');
138+
/* print(
139+
'($_runningAtPhases, $id) Completed $idToLoad:
140+
${assetDeps.lastValue.deps}');*/
136141
for (final dep in assetDeps.lastValue.deps) {
137142
final phaseIdsToLoad = _idsToLoad[0] ??= [];
138143
phaseIdsToLoad.add(dep);
139-
print('($_runningAtPhases, $id) add $dep to _idsToLoad at 0');
144+
// print('($_runningAtPhases, $id) add $dep to _idsToLoad at 0');
140145
}
141-
print('Ehm: $thisPhaseIdsToLoad --- $_idsToLoad');
146+
// print('Ehm: $thisPhaseIdsToLoad --- $_idsToLoad');
142147
} else {
143148
// It's a generated source that has not yet been generated. Mark it for
144149
// loading later.
145-
print('($_runningAtPhases, $id) Add $idToLoad to IDs to load later');
146-
(_idsToLoad[assetDeps.values.last.expiresAfter! + 1] ??= [])
147-
.add(idToLoad);
150+
// print('($_runningAtPhases, $id) Add $idToLoad to IDs to load later');
151+
(_idsToLoad[assetDeps.values.last.expiresAfter! + 1] ??= []).add(
152+
idToLoad,
153+
);
148154
}
149155

150156
_idsToLoad[firstPhase]!.remove(idToLoad);
151157
}
152158

153-
print('($_runningAtPhases, $id) returning: $_idsToLoad');
159+
// print('($_runningAtPhases, $id) returning: $_idsToLoad');
154160
}
155161

156162
/// Computes [_cycles] for all [_newAssets] at phase 0, then for all assets
@@ -167,11 +173,13 @@ class LibraryCycleGraphLoader {
167173
// Process phases that have work to do in ascending order.
168174
while (true) {
169175
int phase;
170-
Set<AssetId> idsToComputeCyclesFrom;
176+
Iterable<AssetId> idsToComputeCyclesFrom;
171177
if (_newAssets.isNotEmpty) {
172178
// New assets: work to do at phase 0, the initial build state.
173179
phase = 0;
174-
idsToComputeCyclesFrom = _newAssets;
180+
idsToComputeCyclesFrom = _newAssets.where(
181+
(id) => !_cycles.containsKey(id),
182+
);
175183
_newAssets = {};
176184
} else {
177185
// Work through phases <= `upToPhase` at which graphs expire,
@@ -184,9 +192,8 @@ class LibraryCycleGraphLoader {
184192

185193
// Edges for strongly connected components computation.
186194
Iterable<AssetId> edgesFromId(AssetId id) {
187-
print('Edges for $id');
195+
// print('Edges for $id');
188196
final deps = _assetDeps[id]!.valueAt(phase: phase).deps;
189-
return deps;
190197

191198
// Check edge against cycles that have already been computed
192199
// at the current `phase`. Newly discovered assets at the same phase
@@ -197,29 +204,30 @@ class LibraryCycleGraphLoader {
197204
);
198205
}
199206

200-
print('Up to $upToPhase, compute $phase');
207+
// print('Up to $upToPhase, compute $phase');
201208

202209
// Do the strongly connected components computation and convert
203210
// from its output, a list of lists of IDs, to a list of [LibraryCycle].
204211
final newComponentLists = stronglyConnectedComponents(
205212
idsToComputeCyclesFrom,
206213
edgesFromId,
207214
);
208-
final newCycles = newComponentLists.map((list) {
209-
// Compare to the library cycle computed at `phase - 1`. If the
210-
// cycles are the same size then they must have the same contents,
211-
// because cycles only change by growing as phases progress. In that
212-
// case, reuse the existing [LibraryCycle].
213-
final maybePhasedCycle = _cycles[list.first];
214-
if (maybePhasedCycle != null) {
215-
final value = maybePhasedCycle.valueAt(phase: phase - 1);
216-
if (value.ids.length == list.length) {
217-
return value;
218-
}
219-
}
220-
// The cycle is new or has changed, return a new value.
221-
return LibraryCycle((b) => b..ids.replace(list));
222-
}).toList();
215+
final newCycles =
216+
newComponentLists.map((list) {
217+
// Compare to the library cycle computed at `phase - 1`. If the
218+
// cycles are the same size then they must have the same contents,
219+
// because cycles only change by growing as phases progress. In that
220+
// case, reuse the existing [LibraryCycle].
221+
final maybePhasedCycle = _cycles[list.first];
222+
if (maybePhasedCycle != null) {
223+
final value = maybePhasedCycle.valueAt(phase: phase - 1);
224+
if (value.ids.length == list.length) {
225+
return value;
226+
}
227+
}
228+
// The cycle is new or has changed, return a new value.
229+
return LibraryCycle((b) => b..ids.replace(list));
230+
}).toList();
223231

224232
// Build graphs from cycles.
225233
_buildGraphs(phase, newCycles: newCycles);
@@ -229,9 +237,10 @@ class LibraryCycleGraphLoader {
229237
// it gets a new dep that leads back to the cycle then that whole path
230238
// joins the cycle. Get this expirey phase from the graph built by
231239
// `_buildGraphs`.
232-
final expiresAfter = _graphs[cycle.ids.first]!
233-
.expiringValueAt(phase: phase)
234-
.expiresAfter;
240+
final expiresAfter =
241+
_graphs[cycle.ids.first]!
242+
.expiringValueAt(phase: phase)
243+
.expiresAfter;
235244

236245
// Merge the computed cycle into any existing phased value for each ID.
237246
// The phased value can differ by ID: they are in the same cycle at this
@@ -240,18 +249,23 @@ class LibraryCycleGraphLoader {
240249
// Nevertheless, the case in which the phased values are the same is a
241250
// common one, so use a temporary map from old value to new value to
242251
// avoid creating many equal but not identical phased values.
243-
final updatedValueByOldValue = Map<PhasedValue<LibraryCycle>?,
244-
PhasedValue<LibraryCycle>>.identity();
252+
final updatedValueByOldValue =
253+
Map<
254+
PhasedValue<LibraryCycle>?,
255+
PhasedValue<LibraryCycle>
256+
>.identity();
245257

246258
for (final id in cycle.ids) {
247259
final existingCycle = _cycles[id];
248260
_cycles[id] = updatedValueByOldValue.putIfAbsent(existingCycle, () {
249261
if (existingCycle == null) {
250262
return PhasedValue.of(cycle, expiresAfter: expiresAfter);
251263
}
252-
final newValue =
253-
ExpiringValue<LibraryCycle>(cycle, expiresAfter: expiresAfter);
254-
if (existingCycle.values.contains(newValue)) return existingCycle;
264+
final newValue = ExpiringValue<LibraryCycle>(
265+
cycle,
266+
expiresAfter: expiresAfter,
267+
);
268+
//if (existingCycle.values.contains(newValue)) return existingCycle;
255269
return existingCycle.followedBy(newValue);
256270
});
257271
}
@@ -329,18 +343,23 @@ class LibraryCycleGraphLoader {
329343
// Nevertheless, the case in which the phased values are the same is a
330344
// common one, so use a temporary map from old value to new value to
331345
// avoid creating many equal but not identical phased values.
332-
final updatedValueByOldValue = Map<PhasedValue<LibraryCycleGraph>?,
333-
PhasedValue<LibraryCycleGraph>>.identity();
346+
final updatedValueByOldValue =
347+
Map<
348+
PhasedValue<LibraryCycleGraph>?,
349+
PhasedValue<LibraryCycleGraph>
350+
>.identity();
334351

335352
for (final idToUpdate in root.ids) {
336353
final oldValue = _graphs[idToUpdate];
337354
_graphs[idToUpdate] = updatedValueByOldValue.putIfAbsent(oldValue, () {
338355
if (oldValue == null) {
339356
return PhasedValue.of(graph.build(), expiresAfter: expiresAfter);
340357
}
341-
final newValue =
342-
ExpiringValue(graph.build(), expiresAfter: expiresAfter);
343-
if (oldValue.values.contains(newValue)) return oldValue;
358+
final newValue = ExpiringValue(
359+
graph.build(),
360+
expiresAfter: expiresAfter,
361+
);
362+
//if (oldValue.values.contains(newValue)) return oldValue;
344363
return oldValue.followedBy(newValue);
345364
});
346365
}
@@ -358,9 +377,11 @@ class LibraryCycleGraphLoader {
358377
) async {
359378
if (_runningAtPhases.isNotEmpty &&
360379
assetDepsLoader.phase >= _runningAtPhases.last) {
361-
throw StateError('Cannot recurse at phase ${assetDepsLoader.phase}, '
362-
'already running at an equal or earlier phase. '
363-
'Already running at : $_runningAtPhases');
380+
throw StateError(
381+
'Cannot recurse at phase ${assetDepsLoader.phase}, '
382+
'already running at an equal or earlier phase. '
383+
'Already running at : $_runningAtPhases',
384+
);
364385
}
365386
_runningAtPhases.add(assetDepsLoader.phase);
366387
try {

0 commit comments

Comments
 (0)