Project

General

Profile

Support #4032

block/transaction processing context-local and other performance improvements

Added by Greg Shah over 7 years ago. Updated almost 3 years ago.

Status:
New
Priority:
Normal
Assignee:
-
Target version:
-
Start date:
Due date:
% Done:

0%

billable:
No
vendor_id:
GCD
case_num:
version_reported:
version_resolved:
reviewer:
production:
No
env_name:
topics:

ContextLocalGetTraces.ods (27.1 KB) Constantin Asofiei, 01/05/2023 01:45 PM


Related issues

Related to Base Language - Feature #1970: improve ControlFlowOps method resolution by reflection WIP
Related to Base Language - Bug #4149: BlockManager and TransactionManager handle TransactionType.NONE incorrectly New

History

#1 Updated by Greg Shah over 7 years ago

From Constantin:

TransactionManager is also used in most of the scopeStart/scopeFinished (Scopeables) notifications, to check the current block's type; we should improve those, too.

We could potentially pass the TransactionHelper instance as part of the notification.

#2 Updated by Greg Shah over 7 years ago

  • Subject changed from block/transaction processing performance improvements to block/transaction processing context-local and other performance improvements

From Eric:

ProcedureManager.hasReferent is showing as a minor bottleneck in a particular case, due to its ContextLocal use and the fact that it is invoked almost 400k times from handle._isValid (mostly calls from LogicalTerminal.getChanges).

In LT.getChanges, we iterate the entire frameRegistry map on each call, which is how we get so many calls to handle._isValid. Is this necessary, or is there an "active" subset of frames that actually matter?

#3 Updated by Greg Shah about 7 years ago

ErrorManager should be moved to a TransactionHelper design. For example, ErrorManager.isPendingError() is very expensive and is often used.

LE: see #4828.

#4 Updated by Greg Shah about 7 years ago

Constantin: To what extent do we need to look at additional optimizations in ControlFlowOps and ProcedureManager? The way I recall it, some quick things were done recently but it may deserve a more serious look.

#5 Updated by Greg Shah about 7 years ago

From Eric (see #3992-159):

We could save a little bit of time by streamlining HandleOps.getLegacyAnnotation. This method uses introspection to pull out an annotation. This is fine once, but the information is lost after return and subsequent calls must do all the introspection over again. Seems like this information should be cached, but I'm not sure to what a cache would be attached and what exactly the key would be.

#6 Updated by Greg Shah about 7 years ago

From Eric (see #3992-162):

ProcedureManager.hasReferent is showing as a minor bottleneck in some use cases, due to its ContextLocal use and the fact that it is invoked hundreds of thousands of times from handle._isValid() (mostly calls from LogicalTerminal.getChanges()).

#7 Updated by Greg Shah about 7 years ago

From Eric in #3992-163:

SourceNameMapper.removePkg() is called hundreds of thousands of times in some use cases, through ProcedureManager.getName(). Most of those come from ControlFlowOps$InternalResolver.resolve().

The combination of String.startsWith() and String.substring() in removePkg() is what makes this a minor bottleneck.

From Eric in #3992-164:

Although we improved SourceNameMapper$ExternalProgram.search() already (#3992-94), it is still a minor bottleneck, due to lowercasing the legacy name in the InternalEntryKey c'tor. I normalized the keys to use a lowercase legacy name because the old search algorithm did an equalsIgnoreCase comparison. Is this strictly necessary? Is it possible for the search values being passed in to be of inconsistent case? They are coming from RUN statements in 4GL code, right? Which I guess means they could be any case on Windows. If that's true, then there's not much more we can do to improve this search's performance, AFAICT.

#8 Updated by Constantin Asofiei about 7 years ago

Greg Shah wrote:

Constantin: To what extent do we need to look at additional optimizations in ControlFlowOps and ProcedureManager? The way I recall it, some quick things were done recently but it may deserve a more serious look.

Actually I did a pretty thorough replacement of the direct access with the helper approach, for these two files. If anything else would stick out during profiling, we can address them then.

#9 Updated by Greg Shah over 6 years ago

I've documented some ideas related to Constantin's CFS reflection optimization task (#1970).

#10 Updated by Greg Shah over 6 years ago

  • Related to Feature #1970: improve ControlFlowOps method resolution by reflection added

#11 Updated by Greg Shah over 5 years ago

During work on some transaction processing issues, we've seen that we are providing notifications for a range of services in blocks that are marked as BlockManager.TransactionType.NONE/TransactionManager.NO_TRANSACTION. For example, you can register as a Finalizable, Commitable or Undoable even in a NO_TRANSACTION block AND WE WILL DELIVER ALL NOTIFICATIONS! Likewise all the Scopable notifications occur for NO_TRANSACTION blocks. As far as I know, there ARE NO transaction/block properties for such blocks. I think we should carefully review this code and test to see if there is any real reason that we need to notify in these cases. Any registrations probably should be in the nearest containing SUB_TRANSACTION or FULL_TRANSACTION.

In addition to doing a lot of extra work, we may even be incorrectly processing those blocks.

From Constantin on a related note:

I want to expand this a little, as you remind me of something (which maybe I mentioned before, but I don't recall). In profiling this doesn't appear (but I haven't profiled them explicitly lately), there is other unnecessary scope start/finished work for scopeables. Take AccumulatorManager for example - this will be notified of each and every scope, even if accumulator usage is maybe not even 10% of the application.

I was thinking maybe there is some way to 'lazy initialize' some of the scopeables and activate them only when they are needed. But, as I mentioned, I don't have a cost/benefit analysis in terms of application performance impact of these.

#12 Updated by Greg Shah over 5 years ago

I had previously created the NO_TRANSACTION task in #4149.

#13 Updated by Greg Shah over 5 years ago

  • Related to Bug #4149: BlockManager and TransactionManager handle TransactionType.NONE incorrectly added

#14 Updated by Constantin Asofiei over 3 years ago

Attached is a trace file with ContextLocal.get usage in a customer application. This is expanded on 3 levels, level 1 being root (ContextLocal.get()) and level 2 being bold to be easier found.

Some notes:
  • I solved the top callers of UniqueIdGenerator.getUniqueId by lazily computing this UNIQUE-ID value; I don't see any reason why we should have this pre-computed if the application never calls it. There is a place in AbstractTempTable where for some reason a null UNIQUE-ID is expected - but I can't figure out why
  • I have some changes in TableMapper which somehow reduces the ContextLocal.get calls, but there is some other refactoring required on this, I'll post more notes at #6825
  • I think I'll do some experimenting if keeping the reference of ProcedureManager$ProcedureHelper (and maybe others) at the HandleResource instance will help - this way we would have direct access to it. Another related point would be to have the ObjectOps$WorkArea instance at the object instance.

#15 Updated by Constantin Asofiei over 3 years ago

Constantin Asofiei wrote:

  • I think I'll do some experimenting if keeping the reference of ProcedureManager$ProcedureHelper (and maybe others) at the HandleResource instance will help - this way we would have direct access to it. Another related point would be to have the ObjectOps$WorkArea instance at the object instance.

This seems to pay off in performance testing a large app. But a good portion (30%) is still from AnnotatedAst/TRPL usage.

#16 Updated by Constantin Asofiei over 3 years ago

A batch of changes (including #4032-5) are in 6129b/14349

#17 Updated by Constantin Asofiei over 3 years ago

Another batch of changes related to this is in 6129b/14366

#18 Updated by Constantin Asofiei over 3 years ago

Changes mentioned in previous notes:
  • cache the 'helper' instance at the WrappedResource, object and other cases, to avoid resolving the ContextLocal instance on each access.
  • use some other approaches (like delay calculation for UNIQUE-ID) to reduce the number of ContextLocal.get calls

But, 50% of the 15m calls in a large application is from TRPL processing (AstSymbolResolver.getResolver()). This requires some re-thinking of the TRPL engine for dynamic query/temp-table conversion - as currently the state is kept in each context, but the TRPL rule-sets are in a JVM singleton mode, and not context-local.

In ContextLocal.get terms, the completion can be considered at 90%, as what remains is AstSymbolResolver.getResolver()

#19 Updated by Constantin Asofiei almost 3 years ago

4032a was created from trunk rev 14668.

4032a rev 14669 contains another batch of context-local improvements.

#20 Updated by Greg Shah almost 3 years ago

Code Review Task Branch 4032a Revisions 14680 through 14682

The changes look good. They also seem fairly low risk.

#21 Updated by Greg Shah almost 3 years ago

Please merge 4032a to trunk.

#22 Updated by Constantin Asofiei almost 3 years ago

Branch 4032a was merged to trunk rev 14689 and archived.

I've created 4032b from trunk rev 14689 where there will be some other changes.

#24 Updated by Constantin Asofiei almost 3 years ago

4032b was rebased from trunk rev 14721.

4032b rev 14722 contains a small batch of performance improvements related to context-local usage for OUTPUT parameters and object, plus basic for loop iteration for 'finalizables'.

Also available in: Atom PDF