Understanding memory allocation in Sdf_Path: discrepancy between class size and pool element size

I have a technical question regarding the code structure of an API and am seeking assistance from someone with in-depth knowledge of it. During a porting process using clang, I examined the code related to ‘Sdf_Path’ and observed that the ‘Sdf_PathNode’ (edit) class has a size of 16 bytes, which includes 8 bytes for an ‘intrusive_ptr’ (+4 bytes for the reference count and 4 bytes for other variables).

However, I noticed that all elements in the pool are defined as follows:

SDF_INSTANTIATE_POOL(Sdf_PathPrimTag, Sdf_SizeofPrimPathNode, /*regionBits=*/8);
SDF_INSTANTIATE_POOL(Sdf_PathPropTag, Sdf_SizeofPropPathNode, /*regionBits=*/8);

where ‘Sdf_SizeofPrimPathNode’ and ‘Sdf_SizeofPropPathNode’ are each calculated as:

// These are validated below.
static constexpr size_t Sdf_SizeofPrimPathNode = sizeof(void *) * 3;
static constexpr size_t Sdf_SizeofPropPathNode = sizeof(void *) * 3;

This results in 24 bytes on an x86 architecture. I am puzzled because it seems like I might be missing something regarding the utilization of the last 8 bytes. They don’t appear to be allocated for ‘Sdf_PathNode’ storage, and I couldn’t find any code indicating their use. The ‘*3’ multiplier in the ‘Sdf_SizeofPrimPathNode’ calculation particularly stands out as an unexplained or “magic” number. While the rest of the code is logical, well-documented, and structured, this detail seems inconsistent.

I would appreciate any insights or explanations regarding this aspect.

-ms

Hey Mark,

sizeof(SdfPath) is 8 – it has two members:

Sdf_PathPrimNodeHandle _primPart;
Sdf_PathPropNodeHandle _propPart;

Each of which is 4 bytes. These are “pool handles” which are “indexes” into the path node pools. They’re really just “small pointers” to keep sizeof(SdfPath) == 8.

The sizeof(Sdf_PrimPathNode) and sizeof(Sdf_PrimPropertyPathNode) are 24 each as you found. The _primPart and _propPart handles in SdfPath each potentially refer to one of these nodes, which are allocated in the path node pools.

An Sdf_PrimPathNode is 24 bytes because its base class Sdf_PathNode has these members:

    const Sdf_PathNodeConstRefPtr _parent;
    mutable std::atomic<uint32_t> _refCount;
    const uint16_t _elementCount;
    const NodeType _nodeType;
    const uint8_t _nodeFlags;

Which are 8 + 4 + 2 + 1 + 1 = 16 bytes, and then Sdf_PrimPathNode itself adds:

TfToken _name;

Which is an additional 8 bytes, bringing the total to 24. Maybe that token name member is the missing piece?

Hope that helps and lmk if you have more questions!

Alex,

I’m grateful for your response. Firstly, I need to apologize. I just noticed a mistake in my initial question. I was actually referring to the size of Sdf_PathNode, not Sdf_Path, which, fortunately, you seemed to understand correctly. We’re on the same page about the Sdf_PathNode being 16 bytes. However, I completely overlooked the TfToken in Sdf_PrimPathNode. That was the element I was missing. Since my focus was primarily on the creation of the absolute path root, I hadn’t looked for additional members in subclasses. Thank you for your help!

-ms

1 Like