Entity Member Packing - openmpp/openmpp.github.io GitHub Wiki

Home > Model Development Topics > Entity Member Packing

This topic describes how to pack entity members to reduce memory use.

Related topics

Topic contents

Introduction and Background

The entity_member_packing option can reduce the size of entities with no impact on processing performance. It can be useful for time-based models with large populations. The option does negate a convenience feature for model debugging (see below).

An entity is implemented as a C++ object with data members consisting of the entity's attributes and other data members generated by the OpenM++ compiler. Each entity in a run occupies a block of contiguous memory containing the values of its data members. For example, each Person entity in the RiskPaths model has a block of 776 bytes of memory containing 70 data members (38 attributes and 32 other data members).

Each data member has a size in bytes determined by its type. For example, in the RiskPaths model the value of the built-in attribute age is held in a C++ double which is 8 bytes in size. The attribute in_union is held in a C++ bool which is 1 byte in size. The attribute unions is held in a C++ int which is 4 bytes in size. Below is an extract of a table produced by the resource_use option which lists each data member of the Person entity in RiskPaths and its size in bytes.

+------------------------------------------+
|     Person Members (detail)              |
+----------------------------------+-------+
| member                           | bytes |
+----------------------------------+-------+
| Attributes:                      |       |
|   Built-in:                      |       |
|     age                          |     8 |
|     case_id                      |     8 |
|     case_seed                    |     8 |
|     entity_id                    |     4 |
|     events                       |     4 |
|     time                         |     8 |
|   Simple:                        |       |
|     life_status                  |     1 |
|     parity_status                |     1 |
|     union_period2_change         |     8 |
|     union_status                 |     1 |
|     unions                       |     4 |
|   Maintained:                    |       |
|     age_status                   |     4 |
|     dissolution_duration         |     4 |
|     dissolution_hazard           |     8 |
|     formation_hazard             |     8 |
|     in_union                     |     1 |

...

+----------------------------------+-------+
| Sum of member bytes              |   699 |
| Bytes per entity                 |   776 |
| Storage efficiency (%)           |  90.1 |
+----------------------------------+-------+

A CPU accesses a value in memory efficiently if the memory address of the value is an exact multiple of the size of the value being accessed. For example, for efficient access an 8-byte value is stored at a memory address which is a multiple of 8, and a 4-byte value is stored at a memory address which is a multiple of 4. A C++ compiler will normally place values in memory to respect this principle.

In C++, the declaration of an object (e.g. the Person entity) specifies the order in which data members are laid out in the object's block of memory. If the specified order would cause a data member to be incorrectly aligned for its size, the C++ compiler will insert padding bytes into the object to enforce correct alignment. Such padding can make the object larger.

The option entity_member_packing instructs the OpenM++ compiler to order entity members from larger to smaller to minimize padding and reduce the size of the entity. If two members have the same alignment requirements, they are ordered lexicographically within that alignment requirement group.

In the RiskPaths model, turning entity member packing on changes the summary section of the above table to:

+----------------------------------+-------+
| Sum of member bytes              |   699 |
| Bytes per entity                 |   728 |
| Storage efficiency (%)           |  96.0 |
+----------------------------------+-------+

In RiskPaths, the size of Person decreased from 776 to 728 with entity member packing turned on.

By default, the OpenM++ compiler orders entity members to facilitate debugging in an IDE. The default order is

entity_id 
time 
age 
all attributes declared in model code, ordered lexicographically 
all other members, ordered lexicographically

If entity_member_packing is on, this default order is replaced by a non-intuitive order. So, for debugging sessions, it may be worthwhile to have entity member packing turned off. Note that by default entity_member_packing is off.

[back to topic contents]

Syntax and Use

By default, entity member packing is off. To activate it, include the statement

options entity_member_packing = on;

in the source code of a model. A typical place to insert this statement is the module ompp_framework.ompp.

[back to topic contents]

⚠️ **GitHub.com Fallback** ⚠️