Uploaded image for project: 'yangtools'
  1. yangtools
  2. YANGTOOLS-1020

Add runtime-generated Immutable maps

XMLWordPrintable

    • Icon: New Feature New Feature
    • Resolution: Unresolved
    • Icon: Medium Medium
    • 14.0.0
    • None
    • data-impl
    • None

      Heap dump analysis of an OFP-related use case is showing that even though we are using ImmutableOffsetMaps to hold children, those maps still account for 2.4M (10%) objects holding 55MiB (9%) shallow memory, with additional 55MiB (9%) retained by their Object[]s.

      The Object array size ranges from 2 to 12 elements, which means they have 60% to 20% overhead.

      We should be able to bring these overheads down by application of runtime code generation, where we'd generate the equivalent of ImmutableOffsetMap.Unordered, where the values are stored directly in fields of the generated class. This would eliminate the need for Object[]s – i.e. 7% of heap occupancy.

      Code generation should be based on Byte-Buddy, i.e. generate bytecode.

      The implementation should assume NodeIdentifier addressing, i.e. the keys are strictly based on QNames. These should be destructured during internal dispatch, so that we first compare QNameModule portion (which is typically unique, but there may be others, i.e. in case of augment), then we should perform a simple switch() on localName.

      The bytecode should be roughly equivalent to:

      // Hand-coded base class
      public abstract class AbstractNodeIdentifierMap<V> extends AbstractMap<NodeIdentifier, V> implements Immutable {
        @Override
        public final V get(Object obj) {
          return obj instanceof NodeIdentifier nid ? get(nid.getType()) : null;
        }
      
        protected abstract V get(QName qname);
      }
      
      // Generated
      final class NodeIdenfierMapXXYYZZ<V> extends AbstractNodeIdentifierMap<V> {
        // ... for each child QNameModule
        private static final QNameModule MODULE0;
        // ... also we may need constants for QNames for things like entrySet(), keySet(), etc.
        
        // actually something reasonably-derived from QName?
        private final V v0_0;
        private final V v0_1;
      
        @Override
        protected V get(QName qnamej) {
          final var module = qname.getModule();
          if (MODULE0.equals(module)) {
              return get0(qname.getLocalName());
          }
          // else ... if we have more QNameModule
      
          return null;
        }
      
        // peeled for each QNameModule
        private V get0(String localName) {
          return switch (localName) {
            case "some-name" -> field0_0;
            case "other-name" -> field0_1;
            default -> null;
          }
        }
      }
      

            Unassigned Unassigned
            rovarga Robert Varga
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated: