-
Notifications
You must be signed in to change notification settings - Fork 166
perf(core): cache sorted hooks to optimize HookNotifier execution #271
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
Changes from all commits
a5b04e7
46b40c4
aa8a9f7
17863ba
0289e3e
1daa413
b9c8dc7
15f62c7
a667433
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -25,6 +25,7 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import io.agentscope.core.state.StateModuleBase; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import io.agentscope.core.tracing.TracerRegistry; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.util.ArrayList; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.util.Comparator; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.util.List; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.util.Map; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.util.UUID; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -91,7 +92,12 @@ public abstract class AgentBase extends StateModuleBase implements Agent { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private final AtomicBoolean running = new AtomicBoolean(false); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private final boolean checkRunning; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private final List<Hook> hooks; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Cached sorted hooks (invalidated when hooks list changes) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private transient volatile List<Hook> cachedSortedHooks; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private final AtomicBoolean hooksDirty = new AtomicBoolean(true); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private static final List<Hook> systemHooks = new CopyOnWriteArrayList<>(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private final Map<String, List<AgentBase>> hubSubscribers = new ConcurrentHashMap<>(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Interrupt state management (available to all agents) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -240,6 +246,8 @@ protected Mono<Msg> doCall(List<Msg> msgs, Class<?> structuredOutputClass) { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "Structured output not supported by " + getClass().getSimpleName())); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Note: system hooks are applied at agent construction time; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // dynamic system hook changes do not affect existing agents. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public static void addSystemHook(Hook hook) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| systemHooks.add(hook); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -395,22 +403,66 @@ protected Mono<Void> doObserve(Msg msg) { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Get the list of hooks for this agent. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Protected to allow subclasses to access hooks for custom notification logic. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @return List of hooks | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * <p>Returns an immutable snapshot of the internal hook list. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Callers must not attempt to modify the returned list. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * To add or remove hooks, use {@link #addHook(Hook)} or | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * {@link #removeHook(Hook)}. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * <p>This is a breaking change from previous behavior where | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * callers could mutate the returned list directly. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @return Immutable list of hooks | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public List<Hook> getHooks() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return hooks; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return List.copyOf(hooks); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
402
to
+419
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Add a hook to this agent. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * <p>Hooks should generally be added during agent setup, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * before execution begins. Modifying hooks during execution | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * is not thread-safe and may lead to undefined behavior. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @param hook Hook to add | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public void addHook(Hook hook) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| hooks.add(hook); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| hooksDirty.set(true); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Remove a hook from this agent. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * <p>Hooks should generally be removed during agent setup. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Modifying hooks during execution is not thread-safe. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @param hook Hook to remove | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public void removeHook(Hook hook) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| hooks.remove(hook); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| hooksDirty.set(true); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Get hooks sorted by priority (lower value = higher priority). | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Hooks with the same priority maintain registration order. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * <p>Results may be cached until the hook list changes. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @return Sorted list of hooks | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| protected List<Hook> getSortedHooks() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return hooks.stream().sorted(java.util.Comparator.comparingInt(Hook::priority)).toList(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!hooksDirty.get() && cachedSortedHooks != null) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return cachedSortedHooks; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| List<Hook> sorted = hooks.stream().sorted(Comparator.comparingInt(Hook::priority)).toList(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cachedSortedHooks = sorted; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| hooksDirty.set(false); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+457
to
+464
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Concurrent issue here |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return sorted; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+457
to
+465
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!hooksDirty.get() && cachedSortedHooks != null) { | |
| return cachedSortedHooks; | |
| } | |
| List<Hook> sorted = hooks.stream().sorted(Comparator.comparingInt(Hook::priority)).toList(); | |
| cachedSortedHooks = sorted; | |
| hooksDirty.set(false); | |
| return sorted; | |
| List<Hook> currentCache = cachedSortedHooks; | |
| if (!hooksDirty.get() && currentCache != null) { | |
| return currentCache; | |
| } | |
| synchronized (this) { | |
| if (!hooksDirty.get() && cachedSortedHooks != null) { | |
| return cachedSortedHooks; | |
| } | |
| List<Hook> sorted = hooks.stream() | |
| .sorted(Comparator.comparingInt(Hook::priority)) | |
| .toList(); | |
| cachedSortedHooks = sorted; | |
| hooksDirty.set(false); | |
| return sorted; | |
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also fix here