1 /* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. 2 * 3 * Redistribution and use in source and binary forms, with or without 4 * modification, are permitted provided that the following conditions are 5 * met: 6 * * Redistributions of source code must retain the above copyright 7 * notice, this list of conditions and the following disclaimer. 8 * * Redistributions in binary form must reproduce the above 9 * copyright notice, this list of conditions and the following 10 * disclaimer in the documentation and/or other materials provided 11 * with the distribution. 12 * * Neither the name of The Linux Foundation nor the names of its 13 * contributors may be used to endorse or promote products derived 14 * from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 */ 29 30 #define LOG_TAG "QCameraPerf" 31 32 // To remove 33 #include <cutils/properties.h> 34 35 // System dependencies 36 #include <stdlib.h> 37 #include <dlfcn.h> 38 39 // Camera dependencies 40 #include "QCameraPerf.h" 41 #include "QCameraTrace.h" 42 43 extern "C" { 44 #include "mm_camera_dbg.h" 45 } 46 47 namespace qcamera { 48 49 /*=========================================================================== 50 * FUNCTION : QCameraPerfLock constructor 51 * 52 * DESCRIPTION: initialize member variables 53 * 54 * PARAMETERS : 55 * None 56 * 57 * RETURN : void 58 * 59 *==========================================================================*/ 60 QCameraPerfLock::QCameraPerfLock() : 61 perf_lock_acq(NULL), 62 perf_lock_rel(NULL), 63 mDlHandle(NULL), 64 mPerfLockEnable(0), 65 mPerfLockHandle(-1), 66 mPerfLockHandleTimed(-1), 67 mTimerSet(0), 68 mPerfLockTimeout(0), 69 mStartTimeofLock(0) 70 { 71 } 72 73 /*=========================================================================== 74 * FUNCTION : QCameraPerfLock destructor 75 * 76 * DESCRIPTION: class desctructor 77 * 78 * PARAMETERS : 79 * None 80 * 81 * RETURN : void 82 * 83 *==========================================================================*/ 84 QCameraPerfLock::~QCameraPerfLock() 85 { 86 lock_deinit(); 87 } 88 89 90 /*=========================================================================== 91 * FUNCTION : lock_init 92 * 93 * DESCRIPTION: opens the performance lib and initilizes the perf lock functions 94 * 95 * PARAMETERS : 96 * None 97 * 98 * RETURN : void 99 * 100 *==========================================================================*/ 101 void QCameraPerfLock::lock_init() 102 { 103 const char *rc; 104 char value[PROPERTY_VALUE_MAX]; 105 106 LOGD("E"); 107 Mutex::Autolock lock(mLock); 108 109 // Clear the list of active power hints 110 mActivePowerHints.clear(); 111 mCurrentPowerHint = static_cast<PowerHint>(0); 112 mCurrentPowerHintEnable = false; 113 114 property_get("persist.camera.perflock.enable", value, "1"); 115 mPerfLockEnable = atoi(value); 116 #ifdef HAS_MULTIMEDIA_HINTS 117 mPowerHal = IPower::getService(); 118 if (mPowerHal == nullptr) { 119 ALOGE("Couldn't load PowerHAL module"); 120 } 121 #endif 122 123 if (mPerfLockEnable) { 124 perf_lock_acq = NULL; 125 perf_lock_rel = NULL; 126 mPerfLockHandle = -1; 127 /* Retrieve name of vendor extension library */ 128 if (property_get("ro.vendor.extension_library", value, NULL) <= 0) { 129 goto cleanup; 130 } 131 132 mDlHandle = dlopen(value, RTLD_NOW | RTLD_LOCAL); 133 if (mDlHandle == NULL) { 134 goto cleanup; 135 } 136 137 dlerror(); 138 139 perf_lock_acq = (int (*) (int, int, int[], int))dlsym(mDlHandle, "perf_lock_acq"); 140 if ((rc = dlerror()) != NULL) { 141 LOGE("failed to perf_lock_acq function handle"); 142 goto cleanup; 143 } 144 145 perf_lock_rel = (int (*) (int))dlsym(mDlHandle, "perf_lock_rel"); 146 if ((rc = dlerror()) != NULL) { 147 LOGE("failed to perf_lock_rel function handle"); 148 goto cleanup; 149 } 150 LOGD("X"); 151 return; 152 153 cleanup: 154 perf_lock_acq = NULL; 155 perf_lock_rel = NULL; 156 mPerfLockEnable = 0; 157 if (mDlHandle) { 158 dlclose(mDlHandle); 159 mDlHandle = NULL; 160 } 161 } 162 LOGD("X"); 163 } 164 165 /*=========================================================================== 166 * FUNCTION : lock_deinit 167 * 168 * DESCRIPTION: deinitialize the perf lock parameters 169 * 170 * PARAMETERS : 171 * None 172 * 173 * RETURN : void 174 * 175 *==========================================================================*/ 176 void QCameraPerfLock::lock_deinit() 177 { 178 Mutex::Autolock lock(mLock); 179 if (mPerfLockEnable) { 180 LOGD("E"); 181 182 if (mActivePowerHints.empty() == false) { 183 // Disable the active power hint 184 mCurrentPowerHint = *mActivePowerHints.begin(); 185 powerHintInternal(mCurrentPowerHint, false); 186 mActivePowerHints.clear(); 187 } 188 189 if ((NULL != perf_lock_rel) && (mPerfLockHandleTimed >= 0)) { 190 (*perf_lock_rel)(mPerfLockHandleTimed); 191 } 192 193 if ((NULL != perf_lock_rel) && (mPerfLockHandle >= 0)) { 194 (*perf_lock_rel)(mPerfLockHandle); 195 } 196 197 if (mDlHandle) { 198 perf_lock_acq = NULL; 199 perf_lock_rel = NULL; 200 201 dlclose(mDlHandle); 202 mDlHandle = NULL; 203 } 204 mPerfLockEnable = 0; 205 LOGD("X"); 206 } 207 } 208 209 /*=========================================================================== 210 * FUNCTION : isTimerReset 211 * 212 * DESCRIPTION: Check if timout duration is reached 213 * 214 * PARAMETERS : None 215 * 216 * RETURN : true if timeout reached 217 * false if timeout not reached 218 * 219 *==========================================================================*/ 220 bool QCameraPerfLock::isTimerReset() 221 { 222 Mutex::Autolock lock(mLock); 223 if (mPerfLockEnable && mTimerSet) { 224 nsecs_t timeDiff = systemTime() - mStartTimeofLock; 225 if (ns2ms(timeDiff) > (uint32_t)mPerfLockTimeout) { 226 resetTimer(); 227 return true; 228 } 229 } 230 return false; 231 } 232 233 /*=========================================================================== 234 * FUNCTION : resetTimer 235 * 236 * DESCRIPTION: Reset the timer used in timed perf lock 237 * 238 * PARAMETERS : None 239 * 240 * RETURN : void 241 * 242 *==========================================================================*/ 243 void QCameraPerfLock::resetTimer() 244 { 245 mPerfLockTimeout = 0; 246 mTimerSet = 0; 247 } 248 249 /*=========================================================================== 250 * FUNCTION : start_timer 251 * 252 * DESCRIPTION: get the start of the timer 253 * 254 * PARAMETERS : 255 * @timer_val: timer duration in milliseconds 256 * 257 * RETURN : int32_t type of status 258 * NO_ERROR -- success 259 * none-zero failure code 260 * 261 *==========================================================================*/ 262 void QCameraPerfLock::startTimer(uint32_t timer_val) 263 { 264 mStartTimeofLock = systemTime(); 265 mTimerSet = 1; 266 mPerfLockTimeout = timer_val; 267 } 268 269 /*=========================================================================== 270 * FUNCTION : lock_acq_timed 271 * 272 * DESCRIPTION: Acquire the performance lock for the specified duration. 273 * If an existing lock timeout has not elapsed, extend the 274 * lock further for the specified duration 275 * 276 * PARAMETERS : 277 * @timer_val: lock duration 278 * 279 * RETURN : int32_t type of status 280 * NO_ERROR -- success 281 * none-zero failure code 282 * 283 *==========================================================================*/ 284 int32_t QCameraPerfLock::lock_acq_timed(int32_t timer_val) 285 { 286 int32_t ret = -1; 287 288 LOGD("E"); 289 Mutex::Autolock lock(mLock); 290 291 if (mPerfLockEnable) { 292 int32_t perf_lock_params[] = { 293 ALL_CPUS_PWR_CLPS_DIS, 294 CPU0_MIN_FREQ_TURBO_MAX, 295 CPU4_MIN_FREQ_TURBO_MAX 296 }; 297 if (mTimerSet) { 298 nsecs_t curElapsedTime = systemTime() - mStartTimeofLock; 299 int32_t pendingTimeout = mPerfLockTimeout - ns2ms(curElapsedTime); 300 timer_val += pendingTimeout; 301 } 302 startTimer(timer_val); 303 304 // Disable power hint when acquiring the perf lock 305 if (mCurrentPowerHintEnable) { 306 LOGD("mCurrentPowerHintEnable %d" ,mCurrentPowerHintEnable); 307 powerHintInternal(mCurrentPowerHint, false); 308 } 309 310 if ((NULL != perf_lock_acq) && (mPerfLockHandleTimed < 0)) { 311 ret = (*perf_lock_acq)(mPerfLockHandleTimed, timer_val, perf_lock_params, 312 sizeof(perf_lock_params) / sizeof(int32_t)); 313 LOGD("ret %d", ret); 314 if (ret < 0) { 315 LOGE("failed to acquire lock"); 316 } else { 317 mPerfLockHandleTimed = ret; 318 } 319 } 320 LOGD("perf_handle_acq %d ", mPerfLockHandleTimed); 321 } 322 323 LOGD("X"); 324 return ret; 325 } 326 327 /*=========================================================================== 328 * FUNCTION : lock_acq 329 * 330 * DESCRIPTION: acquire the performance lock 331 * 332 * PARAMETERS : 333 * None 334 * 335 * RETURN : int32_t type of status 336 * NO_ERROR -- success 337 * none-zero failure code 338 * 339 *==========================================================================*/ 340 int32_t QCameraPerfLock::lock_acq() 341 { 342 int32_t ret = -1; 343 344 LOGD("E"); 345 Mutex::Autolock lock(mLock); 346 347 if (mPerfLockEnable) { 348 int32_t perf_lock_params[] = { 349 ALL_CPUS_PWR_CLPS_DIS, 350 CPU0_MIN_FREQ_TURBO_MAX, 351 CPU4_MIN_FREQ_TURBO_MAX 352 }; 353 354 // Disable power hint when acquiring the perf lock 355 if (mCurrentPowerHintEnable) { 356 powerHintInternal(mCurrentPowerHint, false); 357 } 358 359 if ((NULL != perf_lock_acq) && (mPerfLockHandle < 0)) { 360 ret = (*perf_lock_acq)(mPerfLockHandle, ONE_SEC, perf_lock_params, 361 sizeof(perf_lock_params) / sizeof(int32_t)); 362 LOGD("ret %d", ret); 363 if (ret < 0) { 364 LOGE("failed to acquire lock"); 365 } else { 366 mPerfLockHandle = ret; 367 } 368 } 369 LOGD("perf_handle_acq %d ", mPerfLockHandle); 370 } 371 372 LOGD("X"); 373 return ret; 374 } 375 376 /*=========================================================================== 377 * FUNCTION : lock_rel_timed 378 * 379 * DESCRIPTION: release the performance lock 380 * 381 * PARAMETERS : 382 * None 383 * 384 * RETURN : int32_t type of status 385 * NO_ERROR -- success 386 * none-zero failure code 387 * 388 *==========================================================================*/ 389 int32_t QCameraPerfLock::lock_rel_timed() 390 { 391 int ret = -1; 392 Mutex::Autolock lock(mLock); 393 if (mPerfLockEnable) { 394 LOGD("E"); 395 if (mPerfLockHandleTimed < 0) { 396 LOGW("mPerfLockHandle < 0,check if lock is acquired"); 397 return ret; 398 } 399 LOGD("perf_handle_rel %d ", mPerfLockHandleTimed); 400 401 if ((NULL != perf_lock_rel) && (0 <= mPerfLockHandleTimed)) { 402 ret = (*perf_lock_rel)(mPerfLockHandleTimed); 403 if (ret < 0) { 404 LOGE("failed to release lock"); 405 } 406 mPerfLockHandleTimed = -1; 407 resetTimer(); 408 } 409 410 if ((mCurrentPowerHintEnable == 1) && (mTimerSet == 0)) { 411 powerHintInternal(mCurrentPowerHint, mCurrentPowerHintEnable); 412 } 413 LOGD("X"); 414 } 415 return ret; 416 } 417 418 /*=========================================================================== 419 * FUNCTION : lock_rel 420 * 421 * DESCRIPTION: release the performance lock 422 * 423 * PARAMETERS : 424 * None 425 * 426 * RETURN : int32_t type of status 427 * NO_ERROR -- success 428 * none-zero failure code 429 * 430 *==========================================================================*/ 431 int32_t QCameraPerfLock::lock_rel() 432 { 433 int ret = -1; 434 Mutex::Autolock lock(mLock); 435 if (mPerfLockEnable) { 436 LOGD("E"); 437 if (mPerfLockHandle < 0) { 438 LOGW("mPerfLockHandle < 0,check if lock is acquired"); 439 return ret; 440 } 441 LOGD("perf_handle_rel %d ", mPerfLockHandle); 442 443 if ((NULL != perf_lock_rel) && (0 <= mPerfLockHandle)) { 444 ret = (*perf_lock_rel)(mPerfLockHandle); 445 if (ret < 0) { 446 LOGE("failed to release lock"); 447 } 448 mPerfLockHandle = -1; 449 } 450 451 if (mCurrentPowerHintEnable == 1) { 452 powerHintInternal(mCurrentPowerHint, mCurrentPowerHintEnable); 453 } 454 LOGD("X"); 455 } 456 return ret; 457 } 458 459 /*=========================================================================== 460 * FUNCTION : powerHintInternal 461 * 462 * DESCRIPTION: Sets the requested power hint and state to power HAL. 463 * 464 * PARAMETERS : 465 * hint : Power hint 466 * enable : Enable power hint if set to 1. Disable if set to 0. 467 * RETURN : void 468 * 469 *==========================================================================*/ 470 void QCameraPerfLock::powerHintInternal(PowerHint hint, bool enable) 471 { 472 #ifdef HAS_MULTIMEDIA_HINTS 473 if (mPowerHal != nullptr && !mPowerHal->powerHintAsync(hint, enable).isOk()) { 474 LOGE("Send powerhint to PowerHal failed"); 475 } 476 #endif 477 } 478 479 /*=========================================================================== 480 * FUNCTION : powerHint 481 * 482 * DESCRIPTION: Updates the list containing active/enabled power hints. 483 * If needed, calls the internal powerHint function with 484 * requested power hint and state. 485 * PARAMETERS : 486 * hint : Power hint 487 * enable : Enable power hint if set to 1. Disable if set to 0. 488 * RETURN : void 489 * 490 *==========================================================================*/ 491 void QCameraPerfLock::powerHint(PowerHint hint, bool enable) 492 { 493 #ifdef HAS_MULTIMEDIA_HINTS 494 if (enable == true) { 495 if ((hint != mCurrentPowerHint) || (enable != mCurrentPowerHintEnable)) { 496 // Disable the current active power hint 497 if (mCurrentPowerHintEnable == true) { 498 powerHintInternal(mCurrentPowerHint, false); 499 } 500 // Push the new power hint at the head of the active power hint list 501 mActivePowerHints.push_front(hint); 502 503 // Set the new power hint 504 mCurrentPowerHint = hint; 505 mCurrentPowerHintEnable = enable; 506 powerHintInternal(hint, enable); 507 } 508 } else { 509 // Remove the power hint from the list 510 for (List<PowerHint>::iterator it = mActivePowerHints.begin(); 511 it != mActivePowerHints.end(); ++it) { 512 if (*it == hint) { 513 if (it != mActivePowerHints.begin()) { 514 LOGW("Request to remove the previous power hint: %d instead of " 515 "currently active power hint: %d", static_cast<int>(hint), 516 static_cast<int>(mCurrentPowerHint)); 517 } 518 mActivePowerHints.erase(it); 519 break; 520 } 521 } 522 523 if (hint == mCurrentPowerHint) { 524 // Disable the power hint 525 powerHintInternal(hint, false); 526 527 // If the active power hint list is not empty, 528 // restore the previous power hint from the head of the list 529 if (mActivePowerHints.empty() == false) { 530 mCurrentPowerHint = *mActivePowerHints.begin(); 531 mCurrentPowerHintEnable = true; 532 powerHintInternal(mCurrentPowerHint, true); 533 } else { 534 mCurrentPowerHint = static_cast<PowerHint>(0); 535 mCurrentPowerHintEnable = false; 536 } 537 } 538 } 539 #endif 540 } 541 542 }; // namespace qcamera 543