@@ -88,58 +88,68 @@ package enum ConvertActionConverter {
8888 // Iterate over all the known pages in chunks
8989 var remaining = context. knownPages [ ... ]
9090
91- let numberOfBatches = ProcessInfo . processInfo. processorCount * 4
92- let numberOfElementsPerTask = Int ( Double ( remaining. count) / Double( numberOfBatches) + 1 )
91+ // Don't run more tasks in parallel than there are cores to run them
92+ let maxParallelTasks : Int = ProcessInfo . processInfo. processorCount
93+ let numberOfElementsPerTask = max (
94+ Int ( Double ( remaining. count) / Double( maxParallelTasks * 10 ) + 1 ) ,
95+ 25 // An arbitrary smallest task size to avoid some concurrency overhead when there aren't that many pages is too small.
96+ )
9397
94- while !remaining. isEmpty {
95- let slice = remaining. prefix ( numberOfElementsPerTask)
96- remaining = remaining. dropFirst ( numberOfElementsPerTask)
98+ func _render( referencesIn slice: consuming ArraySlice < ResolvedTopicReference > ) throws -> SupplementaryRenderInformation {
99+ var supplementaryRenderInfo = SupplementaryRenderInformation ( )
97100
98- // Start work of one slice of the known pages
99- taskGroup. addTask {
100- var supplementaryRenderInfo = SupplementaryRenderInformation ( )
101-
102- for identifier in slice {
103- try autoreleasepool {
104- let entity = try context. entity ( with: identifier)
101+ for identifier in slice {
102+ try autoreleasepool {
103+ let entity = try context. entity ( with: identifier)
105104
106- guard let renderNode = converter. renderNode ( for: entity) else {
107- // No render node was produced for this entity, so just skip it.
108- return
109- }
110-
111- try outputConsumer. consume ( renderNode: renderNode)
105+ guard let renderNode = converter. renderNode ( for: entity) else {
106+ // No render node was produced for this entity, so just skip it.
107+ return
108+ }
109+
110+ try outputConsumer. consume ( renderNode: renderNode)
112111
113- switch documentationCoverageOptions. level {
114- case . detailed, . brief:
115- let coverageEntry = try CoverageDataEntry (
116- documentationNode: entity,
117- renderNode: renderNode,
118- context: context
119- )
120- if coverageFilterClosure ( coverageEntry) {
121- supplementaryRenderInfo. coverageInfo. append ( coverageEntry)
122- }
123- case . none:
124- break
112+ switch documentationCoverageOptions. level {
113+ case . detailed, . brief:
114+ let coverageEntry = try CoverageDataEntry (
115+ documentationNode: entity,
116+ renderNode: renderNode,
117+ context: context
118+ )
119+ if coverageFilterClosure ( coverageEntry) {
120+ supplementaryRenderInfo. coverageInfo. append ( coverageEntry)
125121 }
122+ case . none:
123+ break
124+ }
125+
126+ if emitDigest {
127+ let nodeLinkSummaries = entity. externallyLinkableElementSummaries ( context: context, renderNode: renderNode, includeTaskGroups: true )
128+ let nodeIndexingRecords = try renderNode. indexingRecords ( onPage: identifier)
126129
127- if emitDigest {
128- let nodeLinkSummaries = entity. externallyLinkableElementSummaries ( context: context, renderNode: renderNode, includeTaskGroups: true )
129- let nodeIndexingRecords = try renderNode. indexingRecords ( onPage: identifier)
130-
131- supplementaryRenderInfo. assets. merge ( renderNode. assetReferences, uniquingKeysWith: + )
132- supplementaryRenderInfo. linkSummaries. append ( contentsOf: nodeLinkSummaries)
133- supplementaryRenderInfo. indexingRecords. append ( contentsOf: nodeIndexingRecords)
134- } else if FeatureFlags . current. isExperimentalLinkHierarchySerializationEnabled {
135- let nodeLinkSummaries = entity. externallyLinkableElementSummaries ( context: context, renderNode: renderNode, includeTaskGroups: false )
136-
137- supplementaryRenderInfo. linkSummaries. append ( contentsOf: nodeLinkSummaries)
138- }
130+ supplementaryRenderInfo. assets. merge ( renderNode. assetReferences, uniquingKeysWith: + )
131+ supplementaryRenderInfo. linkSummaries. append ( contentsOf: nodeLinkSummaries)
132+ supplementaryRenderInfo. indexingRecords. append ( contentsOf: nodeIndexingRecords)
133+ } else if FeatureFlags . current. isExperimentalLinkHierarchySerializationEnabled {
134+ let nodeLinkSummaries = entity. externallyLinkableElementSummaries ( context: context, renderNode: renderNode, includeTaskGroups: false )
135+
136+ supplementaryRenderInfo. linkSummaries. append ( contentsOf: nodeLinkSummaries)
139137 }
140138 }
139+ }
140+
141+ return supplementaryRenderInfo
142+ }
143+
144+ for _ in 0 ..< maxParallelTasks {
145+ if !remaining. isEmpty {
146+ let slice = remaining. prefix ( numberOfElementsPerTask)
147+ remaining = remaining. dropFirst ( numberOfElementsPerTask)
141148
142- return supplementaryRenderInfo
149+ // Start work of one slice of the known pages
150+ taskGroup. addTask {
151+ return try _render ( referencesIn: slice)
152+ }
143153 }
144154 }
145155
@@ -150,6 +160,16 @@ package enum ConvertActionConverter {
150160 aggregateSupplementaryRenderInfo. linkSummaries. append ( contentsOf: partialInfo. linkSummaries)
151161 aggregateSupplementaryRenderInfo. indexingRecords. append ( contentsOf: partialInfo. indexingRecords)
152162 aggregateSupplementaryRenderInfo. coverageInfo. append ( contentsOf: partialInfo. coverageInfo)
163+
164+ if !remaining. isEmpty {
165+ let slice = remaining. prefix ( numberOfElementsPerTask)
166+ remaining = remaining. dropFirst ( numberOfElementsPerTask)
167+
168+ // Start work of one slice of the known pages
169+ taskGroup. addTask {
170+ return try _render ( referencesIn: slice)
171+ }
172+ }
153173 }
154174
155175 return aggregateSupplementaryRenderInfo
0 commit comments