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