I looked into the orphan node mechanisms in GLEngine a little bit. When a buffer object is orphaned, an OrphanNode is created for it. Based on the buffer object size, a hash is computed: (((size & 0xffffffff) >> 0xc) & 0x3ff) ^ size >> 0x16) % 113. There is one global linked list of all orphan nodes, and 113 linked lists of orphan nodes for each size hash. Every node is present in both the global list and in the list for its size hash. Orphan nodes are created in `gleOrphanBufferObject` and freed in `gleBufferObjectAdoptOrphan` or `gleFreeOrphan`. `gleGetFreeOrphanNode` finds a node for the requested size and two other params. It only iterates the size-hash based linked list, not the global list. If a node was found, it is taken out of both linked lists and returned. Otherwise `gleGetFreeOrphanNode` returns null. If `gleGetFreeOrphanNode` is slow, this probably means that there are a lot of orphan nodes of the same size hash. So if we can't find a matching node, that's either because we're looking for a different size that computed to the same hash, or because one of the other two requested parameters didn't match. We should find out which of these is the case. (I don't know the meaning of the other two parameters yet.) There doesn't seem to be a global limit on the number of orphan nodes. Instead, there is a limit of *total bytes* of orphaned buffer objects. This limit is enforced by `gleCleanupOrphans`, which is called on every call to `gleOrphanBufferObject`. So if we have lots of orphan nodes sticking around, this may mean that those orphan nodes are wrapping very small buffer objects.
Bug 1645716 Comment 11 Edit History
Note: The actual edited comment in the bug view page will always show the original commenter’s name and original timestamp.
I looked into the orphan node mechanisms in GLEngine a little bit. When a buffer object is orphaned, an OrphanNode is created for it. Based on the buffer object size, a hash is computed: (((size & 0xffffffff) >> 0xc) & 0x3ff) ^ size >> 0x16) % 113. There is one global linked list of all orphan nodes, and 113 linked lists of orphan nodes for each size hash. Every node is present in both the global list and in the list for its size hash. Orphan nodes are created in `gleOrphanBufferObject` and freed in `gleBufferObjectAdoptOrphan` or `gleFreeOrphan`. `gleGetFreeOrphanNode` finds a node for the requested size and two other params. It only iterates the size-hash based list, not the global list. If a node was found, it is taken out of both lists and returned. Otherwise `gleGetFreeOrphanNode` returns null. If `gleGetFreeOrphanNode` is slow, this probably means that there are a lot of orphan nodes of the same size hash. So if we can't find a matching node, that's either because we're looking for a different size that computed to the same hash, or because one of the other two requested parameters didn't match. We should find out which of these is the case. (I don't know the meaning of the other two parameters yet.) There doesn't seem to be a global limit on the number of orphan nodes. Instead, there is a limit of *total bytes* of orphaned buffer objects. This limit is enforced by `gleCleanupOrphans`, which is called on every call to `gleOrphanBufferObject`. So if we have lots of orphan nodes sticking around, this may mean that those orphan nodes are wrapping very small buffer objects.
I looked into the orphan node mechanisms in GLIContext a little bit. When a buffer object is orphaned, an OrphanNode is created for it. Based on the buffer object size, a hash is computed: (((roundedSize & 0xffffffff) >> 0xc) & 0x3ff) ^ size >> 0x16) % 113. There is one global linked list of all orphan nodes, and 113 linked lists of orphan nodes for each size hash. Every node is present in both the global list and in the list for its size hash. Orphan nodes are created in `gleOrphanBufferObject` and freed in `gleBufferObjectAdoptOrphan` or `gleFreeOrphan`. `gleGetFreeOrphanNode` finds a node for the requested size and two other params. It only iterates the size-hash based list, not the global list. If a node was found, it is taken out of both lists and returned. Otherwise `gleGetFreeOrphanNode` returns null. If `gleGetFreeOrphanNode` is slow, this probably means that there are a lot of orphan nodes of the same size hash. So if we can't find a matching node, that's either because we're looking for a different size that computed to the same hash, or because one of the other two requested parameters didn't match. We should find out which of these is the case. (I don't know the meaning of the other two parameters yet.) There doesn't seem to be a global limit on the number of orphan nodes. Instead, there is a limit of *total bytes* of orphaned buffer objects. This limit is enforced by `gleCleanupOrphans`, which is called on every call to `gleOrphanBufferObject`. So if we have lots of orphan nodes sticking around, this may mean that those orphan nodes are wrapping very small buffer objects.
I looked into the orphan node mechanisms in GLIContext a little bit. When a buffer object is orphaned, an OrphanNode is created for it. Based on the buffer object size, a hash is computed: (((roundedSize & 0xffffffff) >> 0xc) & 0x3ff) ^ size >> 0x16) % 113. There is one global linked list of all orphan nodes, and 113 linked lists of orphan nodes for each size hash. Every node is present in both the global list and in the list for its size hash. Orphan nodes are created in `gleOrphanBufferObject` and freed in `gleBufferObjectAdoptOrphan` or `gleFreeOrphan`. `gleGetFreeOrphanNode` finds a node for the requested size and two other params: the usage hint and the device ID. It only iterates the size-hash based list, not the global list. If a node was found, it is taken out of both lists and returned. Otherwise `gleGetFreeOrphanNode` returns null. If `gleGetFreeOrphanNode` is slow, this probably means that there are a lot of orphan nodes of the same size hash. So if we can't find a matching node, that's either because we're looking for a different size that computed to the same hash, or because one of the other two requested parameters (usage hint or device ID) didn't match. We recently landed a patch in bug 1642495 comment 10 that makes the usage hint match more often. There doesn't seem to be a global limit on the number of orphan nodes. Instead, there is a limit of *total bytes* of orphaned buffer objects, at around 67MB. This limit is enforced by `gleCleanupOrphans`, which is called on every call to `gleOrphanBufferObject`. So if we have lots of orphan nodes sticking around, this may mean that those orphan nodes are wrapping very small buffer objects.
I looked into the orphan node mechanisms in GLIContext a little bit. When a buffer object is orphaned, an OrphanNode is created for it. Based on the buffer object size, a hash is computed: (((roundedSize & 0xffffffff) >> 0xc) & 0x3ff) ^ size >> 0x16) % 113. There is one global linked list of all orphan nodes, and 113 linked lists of orphan nodes for each size hash. Every node is present in both the global list and in the list for its size hash. Orphan nodes are created in `gleOrphanBufferObject` and freed in `gleBufferObjectAdoptOrphan` or `gleFreeOrphan`. `gleGetFreeOrphanNode` finds a node for the requested size and two other params: the usage hint and the writeCombined. It only iterates the size-hash based list, not the global list. If a node was found, it is taken out of both lists and returned. Otherwise `gleGetFreeOrphanNode` returns null. If `gleGetFreeOrphanNode` is slow, this probably means that there are a lot of orphan nodes of the same size hash. So if we can't find a matching node, that's either because we're looking for a different size that computed to the same hash, or because one of the other two requested parameters (usage hint or writeCombined) didn't match. We recently landed a patch in bug 1642495 comment 10 that makes the usage hint match more often. There doesn't seem to be a global limit on the number of orphan nodes. Instead, there is a limit of *total bytes* of orphaned buffer objects, at around 67MB. This limit is enforced by `gleCleanupOrphans`, which is called on every call to `gleOrphanBufferObject`. So if we have lots of orphan nodes sticking around, this may mean that those orphan nodes are wrapping very small buffer objects.
I looked into the orphan node mechanisms in GLEngine a little bit. When a buffer object is orphaned, an OrphanNode is created for it. Based on the buffer object size, a hash is computed: (((roundedSize & 0xffffffff) >> 0xc) & 0x3ff) ^ size >> 0x16) % 113. There is one global linked list of all orphan nodes, and 113 linked lists of orphan nodes for each size hash. Every node is present in both the global list and in the list for its size hash. Orphan nodes are created in `gleOrphanBufferObject` and freed in `gleBufferObjectAdoptOrphan` or `gleFreeOrphan`. The orphan node lists are shared between GPUs. Each node also contains device-specific user data for each GPU. `gleGetFreeOrphanNode` finds a node for the requested size and two other params: the usage hint and the writeCombined. It only iterates the size-hash based list, not the global list. If a node was found, it is taken out of both lists and returned. Otherwise `gleGetFreeOrphanNode` returns null. If `gleGetFreeOrphanNode` is slow, this probably means that there are a lot of orphan nodes of the same size hash. So if we can't find a matching node, that's either because we're looking for a different size that computed to the same hash, or because one of the other two requested parameters (usage hint or writeCombined) didn't match. We recently landed a patch in bug 1642495 comment 10 that makes the usage hint match more often. There doesn't seem to be a global limit on the number of orphan nodes. Instead, there is a limit of *total bytes* of orphaned buffer objects, at around 67MB. This limit is enforced by `gleCleanupOrphans`, which is called on every call to `gleOrphanBufferObject`. So if we have lots of orphan nodes sticking around, this may mean that those orphan nodes are wrapping very small buffer objects.