1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef android_hardware_automotive_vehicle_utils_include_VehicleObjectPool_H_ 18 #define android_hardware_automotive_vehicle_utils_include_VehicleObjectPool_H_ 19 20 #include <deque> 21 #include <map> 22 #include <memory> 23 #include <mutex> 24 25 #include <VehicleHalTypes.h> 26 27 #include <android-base/thread_annotations.h> 28 29 namespace android { 30 namespace hardware { 31 namespace automotive { 32 namespace vehicle { 33 34 // Handy metric mostly for unit tests and debug. 35 #define INC_METRIC_IF_DEBUG(val) PoolStats::instance()->val++; 36 37 struct PoolStats { 38 std::atomic<uint32_t> Obtained{0}; 39 std::atomic<uint32_t> Created{0}; 40 std::atomic<uint32_t> Recycled{0}; 41 std::atomic<uint32_t> Deleted{0}; 42 instancePoolStats43 static PoolStats* instance() { 44 static PoolStats inst; 45 return &inst; 46 } 47 }; 48 49 template <typename T> 50 struct Deleter { 51 using OnDeleteFunc = std::function<void(T*)>; 52 DeleterDeleter53 explicit Deleter(const OnDeleteFunc& f) : mOnDelete(f){}; 54 55 Deleter() = default; 56 Deleter(const Deleter&) = default; 57 operatorDeleter58 void operator()(T* o) { mOnDelete(o); } 59 60 private: 61 OnDeleteFunc mOnDelete; 62 }; 63 64 // This is std::unique_ptr<> with custom delete operation that typically moves the pointer it holds 65 // back to ObjectPool. 66 template <typename T> 67 using recyclable_ptr = typename std::unique_ptr<T, Deleter<T>>; 68 69 // Generic abstract object pool class. Users of this class must implement {@Code createObject}. 70 // 71 // This class is thread-safe. Concurrent calls to {@Code obtain} from multiple threads is OK, also 72 // client can obtain an object in one thread and then move ownership to another thread. 73 template <typename T> 74 class ObjectPool { 75 public: 76 using GetSizeFunc = std::function<size_t(const T&)>; 77 ObjectPool(size_t maxPoolObjectsSize,GetSizeFunc getSizeFunc)78 ObjectPool(size_t maxPoolObjectsSize, GetSizeFunc getSizeFunc) 79 : mMaxPoolObjectsSize(maxPoolObjectsSize), mGetSizeFunc(getSizeFunc){}; 80 virtual ~ObjectPool() = default; 81 obtain()82 virtual recyclable_ptr<T> obtain() { 83 std::scoped_lock<std::mutex> lock(mLock); 84 INC_METRIC_IF_DEBUG(Obtained) 85 if (mObjects.empty()) { 86 INC_METRIC_IF_DEBUG(Created) 87 return wrap(createObject()); 88 } 89 90 auto o = wrap(mObjects.front().release()); 91 mObjects.pop_front(); 92 mPoolObjectsSize -= mGetSizeFunc(*o); 93 return o; 94 } 95 96 ObjectPool& operator=(const ObjectPool&) = delete; 97 ObjectPool(const ObjectPool&) = delete; 98 99 protected: 100 virtual T* createObject() = 0; 101 recycle(T * o)102 virtual void recycle(T* o) { 103 std::scoped_lock<std::mutex> lock(mLock); 104 size_t objectSize = mGetSizeFunc(*o); 105 106 if (objectSize > mMaxPoolObjectsSize || 107 mPoolObjectsSize > mMaxPoolObjectsSize - objectSize) { 108 INC_METRIC_IF_DEBUG(Deleted) 109 110 // We have no space left in the pool. 111 delete o; 112 return; 113 } 114 115 INC_METRIC_IF_DEBUG(Recycled) 116 117 mObjects.push_back(std::unique_ptr<T>{o}); 118 mPoolObjectsSize += objectSize; 119 } 120 121 const size_t mMaxPoolObjectsSize; 122 123 private: getDeleter()124 const Deleter<T>& getDeleter() { 125 if (!mDeleter.get()) { 126 Deleter<T>* d = 127 new Deleter<T>(std::bind(&ObjectPool::recycle, this, std::placeholders::_1)); 128 mDeleter.reset(d); 129 } 130 return *mDeleter.get(); 131 } 132 wrap(T * raw)133 recyclable_ptr<T> wrap(T* raw) { return recyclable_ptr<T>{raw, getDeleter()}; } 134 135 mutable std::mutex mLock; 136 std::deque<std::unique_ptr<T>> mObjects GUARDED_BY(mLock); 137 std::unique_ptr<Deleter<T>> mDeleter; 138 size_t mPoolObjectsSize GUARDED_BY(mLock); 139 GetSizeFunc mGetSizeFunc; 140 }; 141 142 #undef INC_METRIC_IF_DEBUG 143 144 // This class provides a pool of recyclable VehiclePropertyValue objects. 145 // 146 // It has only one overloaded public method - obtain(...), users must call this method when new 147 // object is needed with given VehiclePropertyType and vector size (for vector properties). This 148 // method returns a recyclable smart pointer to VehiclePropertyValue, essentially this is a 149 // std::unique_ptr with custom delete function, so recyclable object has only one owner and 150 // developers can safely pass it around. Once this object goes out of scope, it will be returned to 151 // the object pool. 152 // 153 // Some objects are not recyclable: strings and vector data types with vector 154 // length > maxRecyclableVectorSize (provided in the constructor). These objects will be deleted 155 // immediately once the go out of scope. There's no synchronization penalty for these objects since 156 // we do not store them in the pool. 157 // 158 // This class is thread-safe. Users can obtain an object in one thread and pass it to another. 159 // 160 // Sample usage: 161 // 162 // VehiclePropValuePool pool; 163 // auto v = pool.obtain(VehiclePropertyType::INT32); 164 // v->propId = VehicleProperty::HVAC_FAN_SPEED; 165 // v->areaId = VehicleAreaSeat::ROW_1_LEFT; 166 // v->timestamp = elapsedRealtimeNano(); 167 // v->value->int32Values[0] = 42; 168 class VehiclePropValuePool { 169 public: 170 using RecyclableType = 171 recyclable_ptr<aidl::android::hardware::automotive::vehicle::VehiclePropValue>; 172 173 // Creates VehiclePropValuePool 174 // 175 // @param maxRecyclableVectorSize - vector value types (e.g. VehiclePropertyType::INT32_VEC) 176 // with size equal or less to this value will be stored in the pool. If users tries to obtain 177 // value with vector size greater than maxRecyclableVectorSize, user will receive a regular 178 // unique pointer instead of a recyclable pointer. The object would not be recycled once it 179 // goes out of scope, but would be deleted. 180 // @param maxPoolObjectsSize - The approximate upper bound of memory each internal recycling 181 // pool could take. We have 4 different type pools, each with 4 different vector size, so 182 // approximately this pool would at-most take 4 * 4 * 10240 = 160k memory. 183 VehiclePropValuePool(size_t maxRecyclableVectorSize = 4, size_t maxPoolObjectsSize = 10240) mMaxRecyclableVectorSize(maxRecyclableVectorSize)184 : mMaxRecyclableVectorSize(maxRecyclableVectorSize), 185 mMaxPoolObjectsSize(maxPoolObjectsSize){}; 186 187 // Obtain a recyclable VehiclePropertyValue object from the pool for the given type. If the 188 // given type is not MIXED or STRING, the internal value vector size would be set to 1. 189 // If the given type is MIXED or STRING, all the internal vector sizes would be initialized to 190 // 0. 191 RecyclableType obtain(aidl::android::hardware::automotive::vehicle::VehiclePropertyType type); 192 193 // Obtain a recyclable VehiclePropertyValue object from the pool for the given type. If the 194 // given type is *_VEC or BYTES, the internal value vector size would be set to vectorSize. If 195 // the given type is BOOLEAN, INT32, FLOAT, or INT64, the internal value vector size would be 196 // set to 1. If the given type is MIXED or STRING, all the internal value vector sizes would be 197 // set to 0. vectorSize must be larger than 0. 198 RecyclableType obtain(aidl::android::hardware::automotive::vehicle::VehiclePropertyType type, 199 size_t vectorSize); 200 // Obtain a recyclable VehicePropertyValue object that is a copy of src. If src does not contain 201 // any value or the src property type is not valid, this function would return an empty 202 // VehiclePropValue. 203 RecyclableType obtain( 204 const aidl::android::hardware::automotive::vehicle::VehiclePropValue& src); 205 // Obtain a recyclable boolean object. 206 RecyclableType obtainBoolean(bool value); 207 // Obtain a recyclable int32 object. 208 RecyclableType obtainInt32(int32_t value); 209 // Obtain a recyclable int64 object. 210 RecyclableType obtainInt64(int64_t value); 211 // Obtain a recyclable float object. 212 RecyclableType obtainFloat(float value); 213 // Obtain a recyclable float object. 214 RecyclableType obtainString(const char* cstr); 215 // Obtain a recyclable mixed object. 216 RecyclableType obtainComplex(); 217 218 VehiclePropValuePool(VehiclePropValuePool&) = delete; 219 VehiclePropValuePool& operator=(VehiclePropValuePool&) = delete; 220 221 private: isSingleValueType(aidl::android::hardware::automotive::vehicle::VehiclePropertyType type)222 static inline bool isSingleValueType( 223 aidl::android::hardware::automotive::vehicle::VehiclePropertyType type) { 224 return type == aidl::android::hardware::automotive::vehicle::VehiclePropertyType::BOOLEAN || 225 type == aidl::android::hardware::automotive::vehicle::VehiclePropertyType::INT32 || 226 type == aidl::android::hardware::automotive::vehicle::VehiclePropertyType::INT64 || 227 type == aidl::android::hardware::automotive::vehicle::VehiclePropertyType::FLOAT; 228 } 229 isComplexType(aidl::android::hardware::automotive::vehicle::VehiclePropertyType type)230 static inline bool isComplexType( 231 aidl::android::hardware::automotive::vehicle::VehiclePropertyType type) { 232 return type == aidl::android::hardware::automotive::vehicle::VehiclePropertyType::MIXED || 233 type == aidl::android::hardware::automotive::vehicle::VehiclePropertyType::STRING; 234 } 235 isDisposable(aidl::android::hardware::automotive::vehicle::VehiclePropertyType type,size_t vectorSize)236 bool isDisposable(aidl::android::hardware::automotive::vehicle::VehiclePropertyType type, 237 size_t vectorSize) const { 238 return vectorSize == 0 || vectorSize > mMaxRecyclableVectorSize || isComplexType(type); 239 } 240 241 RecyclableType obtainDisposable( 242 aidl::android::hardware::automotive::vehicle::VehiclePropertyType valueType, 243 size_t vectorSize) const; 244 RecyclableType obtainRecyclable( 245 aidl::android::hardware::automotive::vehicle::VehiclePropertyType type, 246 size_t vectorSize); 247 248 class InternalPool 249 : public ObjectPool<aidl::android::hardware::automotive::vehicle::VehiclePropValue> { 250 public: InternalPool(aidl::android::hardware::automotive::vehicle::VehiclePropertyType type,size_t vectorSize,size_t maxPoolObjectsSize,ObjectPool::GetSizeFunc getSizeFunc)251 InternalPool(aidl::android::hardware::automotive::vehicle::VehiclePropertyType type, 252 size_t vectorSize, size_t maxPoolObjectsSize, 253 ObjectPool::GetSizeFunc getSizeFunc) 254 : ObjectPool(maxPoolObjectsSize, getSizeFunc), 255 mPropType(type), 256 mVectorSize(vectorSize) {} 257 258 protected: 259 aidl::android::hardware::automotive::vehicle::VehiclePropValue* createObject() override; 260 void recycle(aidl::android::hardware::automotive::vehicle::VehiclePropValue* o) override; 261 262 private: 263 bool check(aidl::android::hardware::automotive::vehicle::RawPropValues* v); 264 265 template <typename VecType> check(std::vector<VecType> * vec,bool isVectorType)266 bool check(std::vector<VecType>* vec, bool isVectorType) { 267 return vec->size() == (isVectorType ? mVectorSize : 0); 268 } 269 270 private: 271 aidl::android::hardware::automotive::vehicle::VehiclePropertyType mPropType; 272 size_t mVectorSize; 273 }; 274 const Deleter<aidl::android::hardware::automotive::vehicle::VehiclePropValue> 275 mDisposableDeleter{ 276 [](aidl::android::hardware::automotive::vehicle::VehiclePropValue* v) { 277 delete v; 278 }}; 279 280 mutable std::mutex mLock; 281 const size_t mMaxRecyclableVectorSize; 282 const size_t mMaxPoolObjectsSize; 283 // A map with 'property_type' | 'value_vector_size' as key and a recyclable object pool as 284 // value. We would create a recyclable pool for each property type and vector size combination. 285 std::map<int32_t, std::unique_ptr<InternalPool>> mValueTypePools GUARDED_BY(mLock); 286 }; 287 288 } // namespace vehicle 289 } // namespace automotive 290 } // namespace hardware 291 } // namespace android 292 293 #endif // android_hardware_automotive_vehicle_utils_include_VehicleObjectPool_H_ 294