xref: /aosp_15_r20/external/pytorch/c10/mobile/CPUProfilingAllocator.h (revision da0073e96a02ea20f0ac840b70461e3646d07c45)
1*da0073e9SAndroid Build Coastguard Worker #pragma once
2*da0073e9SAndroid Build Coastguard Worker 
3*da0073e9SAndroid Build Coastguard Worker #include <c10/macros/Export.h>
4*da0073e9SAndroid Build Coastguard Worker #include <c10/util/flat_hash_map.h>
5*da0073e9SAndroid Build Coastguard Worker #include <cstddef>
6*da0073e9SAndroid Build Coastguard Worker #include <cstdint>
7*da0073e9SAndroid Build Coastguard Worker #include <memory>
8*da0073e9SAndroid Build Coastguard Worker #include <vector>
9*da0073e9SAndroid Build Coastguard Worker 
10*da0073e9SAndroid Build Coastguard Worker namespace c10 {
11*da0073e9SAndroid Build Coastguard Worker 
12*da0073e9SAndroid Build Coastguard Worker /*
13*da0073e9SAndroid Build Coastguard Worker  * Given a sequence of allocations in a thread, AllocationPlan records
14*da0073e9SAndroid Build Coastguard Worker  * 1. size of each allocation
15*da0073e9SAndroid Build Coastguard Worker  * 2. Lifetime of each allocation.
16*da0073e9SAndroid Build Coastguard Worker  * 3. allocation offsets: Memory offset for each allocation in a single blob of
17*da0073e9SAndroid Build Coastguard Worker  * memory
18*da0073e9SAndroid Build Coastguard Worker  * 4. Total size of a blob of memory required to satisfy all the allocations.
19*da0073e9SAndroid Build Coastguard Worker  */
20*da0073e9SAndroid Build Coastguard Worker class C10_API AllocationPlan {
21*da0073e9SAndroid Build Coastguard Worker  private:
22*da0073e9SAndroid Build Coastguard Worker   // Records size of each allocation by their sequential allocation ids.
23*da0073e9SAndroid Build Coastguard Worker   std::vector<uint64_t> allocation_sizes;
24*da0073e9SAndroid Build Coastguard Worker   // This maps one allocation id (X) to another allocation id (Y).
25*da0073e9SAndroid Build Coastguard Worker   // Allocation X is alive until allocation Y. From allocation Y onwards
26*da0073e9SAndroid Build Coastguard Worker   // allocation X is not referenced.
27*da0073e9SAndroid Build Coastguard Worker   // Thus Y is the id of the first allocation after X is freed.
28*da0073e9SAndroid Build Coastguard Worker   // NB: When an allocation is recorded, along with recording its size,
29*da0073e9SAndroid Build Coastguard Worker   // we also set the lifetime to be numeric_limits::max()
30*da0073e9SAndroid Build Coastguard Worker   // This is to track allocations that are made during the scope of
31*da0073e9SAndroid Build Coastguard Worker   // profiling but were not freed until after the scope ended.
32*da0073e9SAndroid Build Coastguard Worker   // Such allocations are not managed by profiling allocator.
33*da0073e9SAndroid Build Coastguard Worker   std::vector<uint64_t> allocation_lifetimes;
34*da0073e9SAndroid Build Coastguard Worker   // Maps an allocation to some offset in a blob of memory.
35*da0073e9SAndroid Build Coastguard Worker   std::vector<uint64_t> allocation_offsets;
36*da0073e9SAndroid Build Coastguard Worker   uint64_t total_size{0};
37*da0073e9SAndroid Build Coastguard Worker   void clear();
38*da0073e9SAndroid Build Coastguard Worker   friend class AllocationPlanner;
39*da0073e9SAndroid Build Coastguard Worker   friend class CPUProfilingAllocator;
40*da0073e9SAndroid Build Coastguard Worker };
41*da0073e9SAndroid Build Coastguard Worker 
42*da0073e9SAndroid Build Coastguard Worker /*
43*da0073e9SAndroid Build Coastguard Worker  * Map of memory ptr to allocation id. This is auxiliary information only
44*da0073e9SAndroid Build Coastguard Worker  * used to establish lifetime of allocations.
45*da0073e9SAndroid Build Coastguard Worker  */
46*da0073e9SAndroid Build Coastguard Worker class C10_API AllocationPlanner {
47*da0073e9SAndroid Build Coastguard Worker  private:
48*da0073e9SAndroid Build Coastguard Worker   AllocationPlan* allocation_plan_{nullptr};
49*da0073e9SAndroid Build Coastguard Worker   // Maps allocated ptr to its allocation id.
50*da0073e9SAndroid Build Coastguard Worker   // This is used when freeing the memory to look up the allocation id
51*da0073e9SAndroid Build Coastguard Worker   // in order to establish the lifetime of a particular allocation.
52*da0073e9SAndroid Build Coastguard Worker   ska::flat_hash_map<const void*, uint64_t> allocation_ptr_to_id_;
53*da0073e9SAndroid Build Coastguard Worker   uint64_t allocation_id_{0};
54*da0073e9SAndroid Build Coastguard Worker   bool validation_mode_{false};
55*da0073e9SAndroid Build Coastguard Worker 
56*da0073e9SAndroid Build Coastguard Worker   bool validate_allocation(const uint64_t size, const void* ptr);
57*da0073e9SAndroid Build Coastguard Worker   bool validate_free(const void* ptr);
58*da0073e9SAndroid Build Coastguard Worker 
59*da0073e9SAndroid Build Coastguard Worker  public:
60*da0073e9SAndroid Build Coastguard Worker   bool validation_success{true};
61*da0073e9SAndroid Build Coastguard Worker 
62*da0073e9SAndroid Build Coastguard Worker   AllocationPlanner() = delete;
63*da0073e9SAndroid Build Coastguard Worker   AllocationPlanner(AllocationPlan* plan, bool validate = false)
allocation_plan_(plan)64*da0073e9SAndroid Build Coastguard Worker       : allocation_plan_(plan), validation_mode_(validate) {}
65*da0073e9SAndroid Build Coastguard Worker   void record_allocation(const uint64_t size, const void* ptr);
66*da0073e9SAndroid Build Coastguard Worker   void record_free(const void* ptr);
67*da0073e9SAndroid Build Coastguard Worker   void formulate_plan();
68*da0073e9SAndroid Build Coastguard Worker   void clear();
69*da0073e9SAndroid Build Coastguard Worker };
70*da0073e9SAndroid Build Coastguard Worker 
71*da0073e9SAndroid Build Coastguard Worker // NOT THREAD SAFE profiling allocator.
72*da0073e9SAndroid Build Coastguard Worker class C10_API CPUProfilingAllocator {
73*da0073e9SAndroid Build Coastguard Worker  private:
74*da0073e9SAndroid Build Coastguard Worker   const AllocationPlan* plan_{nullptr};
75*da0073e9SAndroid Build Coastguard Worker   uint64_t allocation_id_{0};
76*da0073e9SAndroid Build Coastguard Worker   uint64_t current_size_{0};
77*da0073e9SAndroid Build Coastguard Worker   void* blob_{nullptr};
78*da0073e9SAndroid Build Coastguard Worker   ska::flat_hash_map<const void*, uint64_t> allocation_ptr_to_id_;
79*da0073e9SAndroid Build Coastguard Worker 
80*da0073e9SAndroid Build Coastguard Worker  public:
81*da0073e9SAndroid Build Coastguard Worker   ~CPUProfilingAllocator();
82*da0073e9SAndroid Build Coastguard Worker   void set_plan(const AllocationPlan* plan);
83*da0073e9SAndroid Build Coastguard Worker   void unset_plan();
84*da0073e9SAndroid Build Coastguard Worker   void* allocate(const size_t bytes);
85*da0073e9SAndroid Build Coastguard Worker   void free(void* const ptr);
86*da0073e9SAndroid Build Coastguard Worker };
87*da0073e9SAndroid Build Coastguard Worker 
88*da0073e9SAndroid Build Coastguard Worker /*
89*da0073e9SAndroid Build Coastguard Worker  * Usage: Profile allocations made by one run of the model.
90*da0073e9SAndroid Build Coastguard Worker  * AllocationPlan plan;
91*da0073e9SAndroid Build Coastguard Worker  * {
92*da0073e9SAndroid Build Coastguard Worker  *   WithProfileAllocationGuard profile_guard(&plan);
93*da0073e9SAndroid Build Coastguard Worker  *   module.forward(...);
94*da0073e9SAndroid Build Coastguard Worker  * }
95*da0073e9SAndroid Build Coastguard Worker  * plan now contains allocation plan.
96*da0073e9SAndroid Build Coastguard Worker  */
97*da0073e9SAndroid Build Coastguard Worker class C10_API WithProfileAllocationsGuard {
98*da0073e9SAndroid Build Coastguard Worker  public:
99*da0073e9SAndroid Build Coastguard Worker   WithProfileAllocationsGuard(AllocationPlan* plan);
100*da0073e9SAndroid Build Coastguard Worker   ~WithProfileAllocationsGuard();
101*da0073e9SAndroid Build Coastguard Worker 
102*da0073e9SAndroid Build Coastguard Worker  private:
103*da0073e9SAndroid Build Coastguard Worker   std::unique_ptr<AllocationPlanner> planner_;
104*da0073e9SAndroid Build Coastguard Worker };
105*da0073e9SAndroid Build Coastguard Worker 
106*da0073e9SAndroid Build Coastguard Worker /*
107*da0073e9SAndroid Build Coastguard Worker  * Usage: Validate allocation plan made with WithProfileAllocationGuard
108*da0073e9SAndroid Build Coastguard Worker  * bool plan_validation_success, success = true;
109*da0073e9SAndroid Build Coastguard Worker  * for (some number of representative inputs)
110*da0073e9SAndroid Build Coastguard Worker  * {
111*da0073e9SAndroid Build Coastguard Worker  *   WithValidateAllocationPlanGuard(&plan, &plan_validation_success);
112*da0073e9SAndroid Build Coastguard Worker  *   module.forward(...);
113*da0073e9SAndroid Build Coastguard Worker  *   success = success && plan_validation_success;
114*da0073e9SAndroid Build Coastguard Worker  * }
115*da0073e9SAndroid Build Coastguard Worker  * success == true means allocations are according to plan
116*da0073e9SAndroid Build Coastguard Worker  * else for some inputs allocation pattern changed.
117*da0073e9SAndroid Build Coastguard Worker  */
118*da0073e9SAndroid Build Coastguard Worker class C10_API WithValidateAllocationPlanGuard {
119*da0073e9SAndroid Build Coastguard Worker  public:
120*da0073e9SAndroid Build Coastguard Worker   WithValidateAllocationPlanGuard(AllocationPlan* plan, bool* success);
121*da0073e9SAndroid Build Coastguard Worker   ~WithValidateAllocationPlanGuard();
122*da0073e9SAndroid Build Coastguard Worker 
123*da0073e9SAndroid Build Coastguard Worker  private:
124*da0073e9SAndroid Build Coastguard Worker   std::unique_ptr<AllocationPlanner> planner_;
125*da0073e9SAndroid Build Coastguard Worker   bool* success_;
126*da0073e9SAndroid Build Coastguard Worker };
127*da0073e9SAndroid Build Coastguard Worker 
128*da0073e9SAndroid Build Coastguard Worker AllocationPlanner* GetThreadLocalAllocationPlanner();
129*da0073e9SAndroid Build Coastguard Worker 
130*da0073e9SAndroid Build Coastguard Worker /*
131*da0073e9SAndroid Build Coastguard Worker  * Usage: Allocate tensors accordingly to allocation plan
132*da0073e9SAndroid Build Coastguard Worker  * First make allocation plan.
133*da0073e9SAndroid Build Coastguard Worker  *  See WithProfileAllocationsGuard usage.
134*da0073e9SAndroid Build Coastguard Worker  * Second validate allocation plan.
135*da0073e9SAndroid Build Coastguard Worker  *  See WithValidateAllocationPlanGuard usage.
136*da0073e9SAndroid Build Coastguard Worker  * CPUProfilingAllocator profiling_allocator;
137*da0073e9SAndroid Build Coastguard Worker  * {
138*da0073e9SAndroid Build Coastguard Worker  *   WithProfilingAllocatorGuard allocator_guard(&profiling_allocator, &plan);
139*da0073e9SAndroid Build Coastguard Worker  *   module.forward(...);
140*da0073e9SAndroid Build Coastguard Worker  * }
141*da0073e9SAndroid Build Coastguard Worker  */
142*da0073e9SAndroid Build Coastguard Worker class C10_API WithProfilingAllocatorGuard {
143*da0073e9SAndroid Build Coastguard Worker  public:
144*da0073e9SAndroid Build Coastguard Worker   WithProfilingAllocatorGuard(
145*da0073e9SAndroid Build Coastguard Worker       CPUProfilingAllocator* allocator,
146*da0073e9SAndroid Build Coastguard Worker       const AllocationPlan* plan);
147*da0073e9SAndroid Build Coastguard Worker   ~WithProfilingAllocatorGuard();
148*da0073e9SAndroid Build Coastguard Worker };
149*da0073e9SAndroid Build Coastguard Worker 
150*da0073e9SAndroid Build Coastguard Worker CPUProfilingAllocator* GetThreadLocalProfilingAllocator();
151*da0073e9SAndroid Build Coastguard Worker 
152*da0073e9SAndroid Build Coastguard Worker } // namespace c10
153