Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Performance improvements #659

Merged
merged 1 commit into from
Jan 9, 2025
Merged

Performance improvements #659

merged 1 commit into from
Jan 9, 2025

Conversation

gnawf
Copy link
Collaborator

@gnawf gnawf commented Dec 18, 2024

No description provided.

Copy link

github-actions bot commented Dec 18, 2024

Test Results

  139 files  +1  139 suites  +1   55s ⏱️ -5s
1 026 tests +2  959 ✅ +2  67 💤 ±0  0 ❌ ±0 
1 034 runs  +2  967 ✅ +2  67 💤 ±0  0 ❌ ±0 

Results for commit 1e2f9f5. ± Comparison against base commit 157423c.

♻️ This comment has been updated with latest results.

@@ -23,16 +23,20 @@ import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicInteger

class NadelIncrementalResultSupport internal constructor(
private val accumulator: NadelIncrementalResultAccumulator,
lazyAccumulator: Lazy<NadelIncrementalResultAccumulator>,
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a costly object, we should put it behind lazy because most requests aren't using @defer

Either way it should only be instantiated once we actually need it, so that the request can proceed quicker.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just for the record there is very little "performance" to be had by avoiding a single object allocation to later.

But I can see that private val queryPathToExecutions = operation.walkTopDown() would be expensive so this makes sense.

@@ -28,10 +28,6 @@ data class NadelExecutionContext internal constructor(
) {
private val serviceContexts = ConcurrentHashMap<String, CompletableFuture<Any?>>()

@Deprecated("Use incrementalSupport instead", ReplaceWith("incrementalResultSupport"))
internal val deferSupport: NadelIncrementalResultSupport
get() = incrementalResultSupport
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not used

}

return map
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved these from below.

@@ -16,7 +16,7 @@ import graphql.schema.GraphQLSchema
*/
data class NadelOverallExecutionBlueprint(
val engineSchema: GraphQLSchema,
val fieldInstructions: Map<FieldCoordinates, List<NadelFieldInstruction>>,
val fieldInstructions: NadelFieldMap<List<NadelFieldInstruction>>,
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a new construct that lets us query by get(typeName: String, fieldName: String) so we don't have to construct a FieldCoordinates just to perform a lookup.

@@ -60,60 +61,64 @@ internal class NadelExecutionPlanFactory(
rootField: ExecutableNormalizedField,
serviceHydrationDetails: ServiceExecutionHydrationDetails?,
): NadelExecutionPlan {
val executionSteps = mutableListOf<AnyNadelExecutionPlanStep>()
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We used to do .groupBy { it.field } at the end but that is pretty wasteful.

So here we construct the Map directly.

val noForeignTypes = overallField.objectTypeNames
.all { objectTypeName ->
objectTypeName in typeNamesOwnedByService
|| objectTypeName in underlyingTypeNamesOwnedByService
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This first checks if we have any foreign types before running .filter to actually transform it.

Most of the time we should only have types for the service, so we shouldn't need to invoke .filter and create a new list with everything copied over.

// concat 1 giant set and then check
return objectTypeName in typeNamesOwnedByService
|| objectTypeName in underlyingTypeNamesOwnedByService
|| (executionContext.hints.sharedTypeRenames(service) && executionBlueprint.getUnderlyingTypeName(objectTypeName) in underlyingTypeNamesOwnedByService)
Copy link
Collaborator Author

@gnawf gnawf Dec 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was inlined above

@@ -57,7 +57,7 @@ class NadelQueryTransformer private constructor(

private data class TransformContext(
val artificialFields: MutableList<ExecutableNormalizedField> = mutableListOf(),
val overallToUnderlyingFields: MutableMap<ExecutableNormalizedField, List<ExecutableNormalizedField>> = mutableMapOf(),
val overallToUnderlyingFields: MutableMap<ExecutableNormalizedField, MutableList<ExecutableNormalizedField>> = mutableMapOf(),
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mutate list should be faster instead of copying list with new element

var fieldFromPreviousTransform: ExecutableNormalizedField = field
var aggregatedTransformResult: NadelTransformFieldResult? = null
var newField: ExecutableNormalizedField = field
val artificialFields = mutableListOf<ExecutableNormalizedField>()
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add artificial fields to this mutable list intead of creating a new list every time

}

private fun getUnderlyingTypeNames(objectTypeNames: Collection<String>): List<String> {
return if (executionContext.hints.sharedTypeRenames(service)) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shared type renames are not required with the new blueprint

@gnawf gnawf force-pushed the performance-improvements branch from 38f1321 to 1e2f9f5 Compare December 19, 2024 05:00
Copy link

@Juliano-Prado Juliano-Prado left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, but there are parts of code I havent seen before in a domain I dont have much knowledge (nadel), so it was a massive review for me.
I recommend to wait for a second review.

@gnawf gnawf merged commit a215479 into master Jan 9, 2025
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants