r""" Pick the available shared object to which to assign this spec, or create a new one Algorithm details Previous: Look at every spec in chronological order. Find if previously allocated object allows it to fit in. If not, allocate a new object. New: - Sort all the specs
(
shared_objects: List[SharedObject],
spec: TensorSpec,
allow_overlapping_allocations: bool = True,
)
| 794 | |
| 795 | |
| 796 | def pick_shared_obj( |
| 797 | shared_objects: List[SharedObject], |
| 798 | spec: TensorSpec, |
| 799 | allow_overlapping_allocations: bool = True, |
| 800 | ) -> SharedObject: |
| 801 | r""" |
| 802 | Pick the available shared object to which to assign this spec, |
| 803 | or create a new one |
| 804 | Algorithm details |
| 805 | Previous: Look at every spec in chronological order. Find if previously allocated object |
| 806 | allows it to fit in. If not, allocate a new object. |
| 807 | New: |
| 808 | - Sort all the specs by allocation size |
| 809 | - Process the specs in order |
| 810 | - If the spec's size in smaller than previously allocated buckets: |
| 811 | - Conditions under which previously allocated bucket can be used: |
| 812 | - Lifetime of the spec does not overlap with lifetime of the bucket. |
| 813 | - In this case allocate spec to that bucket and expand its lifetime. |
| 814 | - Spec is allocated at offset = 0 in this bucket. |
| 815 | - Add this spec to allocated object's list of specs. |
| 816 | - Lifetime of the spec overlaps with lifetime of the bucket, |
| 817 | partially or fully (e.g. spec's lifetime subset of bucket's lifetime) |
| 818 | - If none of the specs in the bucket overlaps with spec's lifetime. |
| 819 | - Allocate spec to the bucket at offset = 0. |
| 820 | - Add this spec to the bucket's list of specs. |
| 821 | - Expand bucket's lifetime accounting for added spec's lifetime. |
| 822 | - If one or more specs in the bucket overlaps with spec's lifetime. |
| 823 | - Collect offsets (at which the given overlapping spec is allocated in the bucket). |
| 824 | of all the overlapping specs, and find the max offset. |
| 825 | - Allocate spec to the bucket at offset = max_offset + max_offset_spec_size. |
| 826 | - Add this spec to the bucket's list of specs. |
| 827 | - Expand bucket's lifetime accounting for added spec's lifetime. |
| 828 | - If none of these conditions are met, allocate a new bucket. |
| 829 | - Add spec to this bucket. |
| 830 | - Update bucket's lifetime to that of the spec. |
| 831 | - If the spec's size is larger than previously allocated buckets, allocate a new bucket. |
| 832 | - Size and lifetime of this bucket is that of the spec |
| 833 | |
| 834 | Proof of correctness: |
| 835 | - If allocating a new bucket, it is correct. |
| 836 | - If allocating spec to an existing bucket, whose lifetime does not overlap with any |
| 837 | of the previously allocated specs' lifetime, then the allocation is correct. |
| 838 | Proof of correctness by induction when adding spec to an existing bucket: |
| 839 | - If all previous allocations in the given bucket are correct: |
| 840 | - Then the new one being added must be correct because when the requested allocation |
| 841 | overlaps with one or more previous allocations, we find the largest offset among |
| 842 | all the overlapping allocations, and allocate the new spec at that offset. Hence, |
| 843 | the allocation at such an offset, will not overlap with any previous allocations. |
| 844 | Base case: A newly added allocation within a bucket with single allocation is correct: |
| 845 | because a) it must fit and b) its lifetime must not overlap with object's lifetime. |
| 846 | This holds true because of the following invariants: |
| 847 | - Once a bucket is created, it is never resized. |
| 848 | - All the allocations within a bucket follow this: |
| 849 | - Span, defined by allocation's offset + size, of two allocations can only overlap, |
| 850 | if their timelines do not overlap. |
| 851 | """ |
| 852 | picked = None |
| 853 | for sobj in shared_objects: |
no test coverage detected