Another reason for TM1 10.2.2 to PA memory growth: Preloading Public views and ALL subsets

Do you have a red circle around 30th of September in your calendars as TM1 10.2.2 end of support? As we’re going through the upgrades for our customers, it’s mostly smooth sailing (if you ignore PaW) and we mostly see 3 main types of ‘issues’:

  • Memory growth – it’s reasonable to expect a 20% increase
  • Temporary View names persistence – temporary objects persist in execution chain starting from PA 2.0.5, which is awesome but can cause issues if you’re not using unique object names (you should)
  • Locking – if you’re doing anything ‘fancy’ around parallelisation/thread control, some of these assumptions can change or not work as expected.

There’s a fair bit of consensus in the community that main memory growth driver is MUN pre-caching, as discussed at length on TM1Forums. It’s easy to identify such case: just copy .dim files into an empty server and if it’s massively bigger in PA vs 10.2.2 — you might want to look into splitting all those ‘alternate hierarchies’ via consolidations into proper hierarchies.
But we recently had a project where massive memory growth wasn’t coming from dimensions/hierarchies at all and it took us & IBM a fair bit to figure that out.

Summary:

  • When you run ViewCreate without assigning a subset to a dimension, TM1 will create a special subset called ‘ALL’ to include all elements of the dimension. This subset will be created separately for each such view, so if you have 100 views not specifying a subset, you’d end up with 100 ‘ALL’ subsets in the server. This can cause memory growth if you have large dimensions and thousands of views as we did.
  • TM1 10.2.2 doesn’t load the view definition (and ALL subsets) in memory unless somebody asks for it. PA preloads all public views & subsets in memory to avoid locking the server when view/subset definition is read. This means that all the ‘unused’ views that didn’t cause any issues in 10.2.2 can
  • PA 2.0.8 or 2.0.9 will include a new parameter LoadPublicViewsAndSubsetsAtStartup to allow you to disable pre-loading public views & subsets.
  • On PA 2.0.7 and earlier the easy way to test whether you have a lot of ALL subsets is to remove all the .vue files and restart the server
  • Try to always use temporary views in TIs
  • Always assign a subset to large dimensions

If you’re keen to check your server for this issue, here’s how we ‘fixed’ it:
1) Checked the subset used in views on the large dimensions to see where ALL was used — this is more for making sure that the problem wouldn’t come back later
2) Replaced ALL subsets in the views with a named ‘ALL-ALL’ subset that would be shared & cached

Code samples:
1) REST API script to get all subsets in all views:
– based on tm1py, kudos to the team, it’s a great library
– arguments -s = servername to connect to, -o = outputfile, just a csv with “Cube, View, Dimension, Subset” lines
– it expects a config file like in tm1py.samples to describe how to connect to your server
– I don’t know or investigated why, but it’s dog slow for me, took hours to parse the views on the server. But it’s 18k views and I can see it doing something in TM1TOP, so I don’t think I can do much. Still magnitude slower than parsing .vue files would’ve been 🙁
2) TM1 TI to replace them with a named subset, simple as (based on the output of REST API script):
Prolog:
# List of dimensions we're updating
dimensionList = 'a,b,c,d';
allSubsetName = '}ALL_generated_for_memory_optimisation';
numSubsetsChanged = 0;

Data:
IF (Subset@='ALL');
IF (SCAN(Dimension, dimensionList) <> 0);
# Check if our special subset exists
IF (SubsetExists (Dimension, allSubsetName ) = 0);
ASCIIOUTPUT('subset_change_log.txt', 'Creating special ALL subset for ' | Dimension );
# Create special subset
SubsetCreate(Dimension, allSubsetName);
SubsetIsAllSet( Dimension, allSubsetName, 1 );
ENDIF;
ViewSubsetAssign(Cube, View, Dimension, allSubsetName);
ASCIIOUTPUT('subset_change_log.txt', 'Adjusted subset for ' | Cube | '.' | View | ' dimension ' | Dimension);
numSubsetsChanged = numSubsetsChanged + 1;
ENDIF;
ENDIF;