/* * struct i915_syncmap is a layer of a radixtree that maps a u64 fence * context id to the last u32 fence seqno waited upon from that context. * Unlike lib/radixtree it uses a parent pointer that allows traversal back to * the root. This allows us to access the whole tree via a single pointer * to the most recently used layer. We expect fence contexts to be dense * and most reuse to be on the same i915_gem_context but on neighbouring * engines (i.e. on adjacent contexts) and reuse the same leaf, a very * effective lookup cache. If the new lookup is not on the same leaf, we * expect it to be on the neighbouring branch. * * A leaf holds an array of u32 seqno, and has height 0. The bitmap field * allows us to store whether a particular seqno is valid (i.e. allows us * to distinguish unset from 0). * * A branch holds an array of layer pointers, and has height > 0, and always * has at least 2 layers (either branches or leaves) below it. * * For example, * for x in * 0 1 2 0x10 0x11 0x200 0x201 * 0x500000 0x500001 0x503000 0x503001 * 0xE<<60: * i915_syncmap_set(&sync, x, lower_32_bits(x)); * will build a tree like: * 0xXXXXXXXXXXXXXXXX * 0-> 0x0000000000XXXXXX * | 0-> 0x0000000000000XXX * | | 0-> 0x00000000000000XX * | | | 0-> 0x000000000000000X 0:0, 1:1, 2:2 * | | | 1-> 0x000000000000001X 0:10, 1:11 * | | 2-> 0x000000000000020X 0:200, 1:201 * | 5-> 0x000000000050XXXX * | 0-> 0x000000000050000X 0:500000, 1:500001 * | 3-> 0x000000000050300X 0:503000, 1:503001 * e-> 0xe00000000000000X e:e
*/
staticinlinebool seqno_later(u32 a, u32 b)
{ return (s32)(a - b) >= 0;
}
/** * i915_syncmap_is_later -- compare against the last know sync point * @root: pointer to the #i915_syncmap * @id: the context id (other timeline) we are synchronising to * @seqno: the sequence number along the other timeline * * If we have already synchronised this @root timeline with another (@id) then * we can omit any repeated or earlier synchronisation requests. If the two * timelines are already coupled, we can also omit the dependency between the * two as that is already known via the timeline. * * Returns true if the two timelines are already synchronised wrt to @seqno, * false if not and the synchronisation must be emitted.
*/ bool i915_syncmap_is_later(struct i915_syncmap **root, u64 id, u32 seqno)
{ struct i915_syncmap *p; unsignedint idx;
p = *root; if (!p) returnfalse;
if (likely(__sync_leaf_prefix(p, id) == p->prefix)) goto found;
/* First climb the tree back to a parent branch */ do {
p = p->parent; if (!p) returnfalse;
if (__sync_branch_prefix(p, id) == p->prefix) break;
} while (1);
/* And then descend again until we find our leaf */ do { if (!p->height) break;
p = __sync_child(p)[__sync_branch_idx(p, id)]; if (!p) returnfalse;
if (__sync_branch_prefix(p, id) != p->prefix) returnfalse;
} while (1);
if (!p) {
p = __sync_alloc_leaf(NULL, id); if (unlikely(!p)) return -ENOMEM;
goto found;
}
/* Caller handled the likely cached case */
GEM_BUG_ON(__sync_leaf_prefix(p, id) == p->prefix);
/* Climb back up the tree until we find a common prefix */ do { if (!p->parent) break;
p = p->parent;
if (__sync_branch_prefix(p, id) == p->prefix) break;
} while (1);
/* * No shortcut, we have to descend the tree to find the right layer * containing this fence. * * Each layer in the tree holds 16 (KSYNCMAP) pointers, either fences * or lower layers. Leaf nodes (height = 0) contain the fences, all * other nodes (height > 0) are internal layers that point to a lower * node. Each internal layer has at least 2 descendents. * * Starting at the top, we check whether the current prefix matches. If * it doesn't, we have gone past our target and need to insert a join * into the tree, and a new leaf node for the target as a descendent * of the join, as well as the original layer. * * The matching prefix means we are still following the right branch * of the tree. If it has height 0, we have found our leaf and just * need to replace the fence slot with ourselves. If the height is * not zero, our slot contains the next layer in the tree (unless * it is empty, in which case we can add ourselves as a new leaf). * As descend the tree the prefix grows (and height decreases).
*/ do { struct i915_syncmap *next;
if (__sync_branch_prefix(p, id) != p->prefix) { unsignedint above;
/* Insert a join above the current layer */
next = kzalloc(struct_size(next, child, KSYNCMAP),
GFP_KERNEL); if (unlikely(!next)) return -ENOMEM;
/* Compute the height at which these two diverge */
above = fls64(__sync_branch_prefix(p, id) ^ p->prefix);
above = round_up(above, SHIFT);
next->height = above + p->height;
next->prefix = __sync_branch_prefix(next, id);
/* Insert the join into the parent */ if (p->parent) {
idx = __sync_branch_idx(p->parent, id);
__sync_child(p->parent)[idx] = next;
GEM_BUG_ON(!(p->parent->bitmap & BIT(idx)));
}
next->parent = p->parent;
/* Compute the idx of the other branch, not our id! */
idx = p->prefix >> (above - SHIFT) & MASK;
__sync_set_child(next, idx, p);
p->parent = next;
/* Ascend to the join */
p = next;
} else { if (!p->height) break;
}
/* Descend into the next layer */
GEM_BUG_ON(!p->height);
idx = __sync_branch_idx(p, id);
next = __sync_child(p)[idx]; if (!next) {
next = __sync_alloc_leaf(p, id); if (unlikely(!next)) return -ENOMEM;
__sync_set_child(p, idx, next);
p = next; break;
}
/** * i915_syncmap_set -- mark the most recent syncpoint between contexts * @root: pointer to the #i915_syncmap * @id: the context id (other timeline) we have synchronised to * @seqno: the sequence number along the other timeline * * When we synchronise this @root timeline with another (@id), we also know * that we have synchronized with all previous seqno along that timeline. If * we then have a request to synchronise with the same seqno or older, we can * omit it, see i915_syncmap_is_later() * * Returns 0 on success, or a negative error code.
*/ int i915_syncmap_set(struct i915_syncmap **root, u64 id, u32 seqno)
{ struct i915_syncmap *p = *root;
/* * We expect to be called in sequence following is_later(id), which * should have preloaded the root for us.
*/ if (likely(p && __sync_leaf_prefix(p, id) == p->prefix)) {
__sync_set_seqno(p, id, seqno); return 0;
}
return __sync_set(root, id, seqno);
}
staticvoid __sync_free(struct i915_syncmap *p)
{ if (p->height) { unsignedint i;
/** * i915_syncmap_free -- free all memory associated with the syncmap * @root: pointer to the #i915_syncmap * * Either when the timeline is to be freed and we no longer need the sync * point tracking, or when the fences are all known to be signaled and the * sync point tracking is redundant, we can free the #i915_syncmap to recover * its allocations. * * Will reinitialise the @root pointer so that the #i915_syncmap is ready for * reuse.
*/ void i915_syncmap_free(struct i915_syncmap **root)
{ struct i915_syncmap *p;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.