Skip to content

Default IP Intelligence to the Balanced performance profile - #69

Draft
jwrosewell wants to merge 2 commits into
rcfrom
fix/ipi-default-balanced
Draft

jwrosewell wants to merge 2 commits into
rcfrom
fix/ipi-default-balanced

Conversation

@jwrosewell

@jwrosewell jwrosewell commented Nov 7, 2026 •

Copy link
Copy Markdown
Contributor

Problem

The IP Intelligence on-premise specification gives Balanced as the default performance profile (ip-intelligence-on-premise.md, the Performance Profile row). Java gave something else from both of its builders.

  1. IPIntelligenceOnPremisePipelineBuilder defaulted to MaxPerformance, as its javadoc said (lines 64 and 65), and always passed that profile to the engine builder (line 390).
  2. IPIntelligenceOnPremiseEngineBuilder created new ConfigIpiSwig() and applied no profile unless the caller set one (line 67), although setPerformanceProfile says "Default value is Balanced" and carries @DefaultValue("Balanced") (lines 113 to 121). The C++ ConfigIpi() constructor in the C library this repository pins starts from the in-memory configuration (51degrees-cxx src/ipi/ConfigIpi.cpp line 30), so an engine builder left alone, including one a configuration file names without a PerformanceProfile, loaded the whole data file into memory.

Change

  • IPIntelligenceOnPremiseEngineBuilder now starts its native configuration from the Balanced profile, in a field initializer (balancedConfig), so a builder whose caller sets no profile is Balanced whatever configuration the native library starts from, and @DefaultValue("Balanced") is now true. The initializer runs before the constructor's config.setConcurrency(...) line, which is unchanged, because applying a profile replaces the concurrency of every collection (setPerformanceFromExistingConfig copies the whole profile over the configuration).
  • IPIntelligenceOnPremisePipelineBuilder now holds no profile until the caller sets one, and passes a profile to the engine builder only then, so the engine builder's Balanced default applies. Passing Balanced explicitly instead would have replaced the concurrency the engine builder set (the processor count) with the native default of 10.
  • The pipeline builder's javadoc says the default is Balanced. No README, documentation page or example comment named the IP Intelligence default. Most examples name a profile of their own, and the ones that do not are listed below.

A caller who names a profile gets that profile, exactly as before. The C library is changing its own ConfigIpi() starting point separately, and this change does not depend on that.

Two examples build an engine with no profile and so move from the in-memory configuration to Balanced when they take up a release with this change, being the UpdateDataFile console example (pipeline builder) and the getting-started.api web example (engine builder). DataFileHelper.getDatafileMetaData in the examples' shared module does the same to read the data file's details. None of them says which profile it uses.

The comment above the engine in the MetadataOnPrem console example said the max performance profile, while the code sets LowMemory, and gave the C# call for getting the engine from a pipeline. A second commit makes the comment name the low memory profile and give the Java call, pipeline.getElement(IPIntelligenceOnPremiseEngine.class). The example's code, and its profile, are unchanged. I compiled the examples' console module and its shared module with mvn -B -pl console -am compile in examples/ip-intelligence, and the build succeeded.

Tests

  • BuilderTests in ip-intelligence.engine.on-premise. Builder_NoProfile_CollectionsAreBalanced reads the native configuration a new builder hands to its engine and checks that every collection's loaded count and cache capacity equal those of a configuration with setBalanced() applied, and differ from one with setMaxPerformance() applied. Builder_MaxPerformance_CollectionsAreInMemory checks that naming MaxPerformance, as an enum value or by name as a configuration file does, still gives the in-memory settings. Neither needs a data file.
  • OnPremisePerformanceProfileTests in ip-intelligence, new because the existing IPIntelligenceOnPremisePipelineBuilderTest is marked @Ignore. build_NoProfile_EngineIsGivenBalanced builds a pipeline with the profile and the concurrency left at their defaults, reads the native configuration the built engine holds, checks it against Balanced and InMemory as above, and checks that its concurrency is the one a new engine builder sets, so the pipeline did not apply a profile over it. build_LowMemory_EngineIsGivenLowMemory checks that a profile the caller names still reaches the engine. Both need an IP Intelligence data file and are skipped, with a message saying how to get one, when there is none.

The comparison takes the Balanced and InMemory values from the native library itself, by applying each profile to a fresh configuration, so it does not copy numbers from the C code and stays right if the C library changes them. Concurrency is left out of the collection comparison, because the engine builder sets its own.

What the tests prove is that the configuration each builder hands to the engine carries Balanced's collection settings when the caller names no profile. They do not measure memory, which the next section does once by hand.

Checks

The native library was built from the C library this repository pins (51degrees-cxx at e866f6d) with Visual Studio 2022 on Windows x64, as part of the Maven build, and the tests ran against it on Java 21 with the free Lite data file (51Degrees-LiteV41.ipi, 478 MB) given through 51DEGREES_IPI_PATH. From the repository root:

mvn -B -pl ip-intelligence/ip-intelligence -am test -Dtest=BuilderTests,OnPremisePerformanceProfileTests -Dsurefire.failIfNoSpecifiedTests=false
  • With this change, at 4814d1e on rc at 2299507 (the later comment commit, 05a7b2a, touches only an example), BuilderTests ran 3 with 0 failures and OnPremisePerformanceProfileTests ran 2 with 0 failures and 0 skipped.
  • With the same tests and the two builders as they are on rc, Builder_NoProfile_CollectionsAreBalanced and build_NoProfile_EngineIsGivenBalanced failed, each with arrays first differed at element [0]; expected:<1> but was:<0>, which is the strings collection configured as InMemory (nothing loaded at the start) where Balanced loads one entry. The two tests that name a profile passed.
  • On the same build, a fresh configuration with setBalanced() applied reported a concurrency of 10, against 12 processors on the machine, which is why the pipeline builder no longer applies Balanced itself.

I also measured the process with a throwaway test, not committed, that built the pipeline with no profile and then with MaxPerformance, in separate JVMs with a fixed 768 MB heap, and looked up the same 20,000 random IPv4 addresses twice. Private bytes are the process's committed memory as Windows reports it, read after a garbage collection.

Profile Added by building the engine Added after 40,000 lookups Microseconds per lookup, first pass Microseconds per lookup, second pass
Balanced (the new default), run 1 281 MB 325 MB 37 24
Balanced (the new default), run 2 287 MB 320 MB 38 21
MaxPerformance (the old default), run 1 457 MB 493 MB 45 22
MaxPerformance (the old default), run 2 456 MB 499 MB 22 17

So on the Lite file the default engine used about 170 MB less, and a lookup took a few microseconds longer on the second pass, with the data file already in the operating system's file cache. The first pass was too noisy to compare. I did not measure the Enterprise data file.

For the release notes

The IP Intelligence on-premise engine now uses the Balanced performance profile when none is set, as the specification says, where the pipeline builder used MaxPerformance and the engine builder used the native library's in-memory configuration. Anyone relying on the default will use less memory after upgrading, because the data file is no longer loaded into memory as a whole (about 170 MB less with the free Lite data file), and lookups that read from the file will be slower. Naming MaxPerformance with setPerformanceProfile, or <PerformanceProfile>MaxPerformance</PerformanceProfile> in a configuration file, keeps the old behaviour.

What remains

  • CI builds the native library and runs the tests on its own platforms and Java versions. I ran them on Windows x64 with Java 21 only.
  • The C library is changing its own ConfigIpi() starting point separately. This change does not rely on that, and keeps the engine builder's concurrency line as it is.

The IP Intelligence on-premise specification gives Balanced as the
default performance profile. The on-premise pipeline builder defaulted to
MaxPerformance, and the engine builder applied no profile unless the
caller set one, so it ran with whatever configuration the native
ConfigIpi constructor starts from, which is the in-memory one in the C
library this repository pins. Its setPerformanceProfile documentation
and @DefaultValue already said Balanced.

The engine builder now applies Balanced to its native configuration in
a field initializer, before the constructor sets the concurrency, so a
builder whose caller sets no profile is Balanced whatever the native
library starts from. The pipeline builder holds no profile until the
caller sets one and passes it on only then, because applying Balanced
again would replace the concurrency the engine builder set.

BuilderTests and the new OnPremisePerformanceProfileTests compare the
collection settings each builder gives the engine with the Balanced and
in-memory settings the native library defines.
…the engine

The comment above the engine in MetadataOnPrem said the max performance
profile while the code sets LowMemory, and gave the C# call for getting
the engine from a pipeline. It now names the low memory profile and
gives pipeline.getElement(IPIntelligenceOnPremiseEngine.class).
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.

1 participant