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 *==========================================================================*/
QCameraPerfLock()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 *==========================================================================*/
~QCameraPerfLock()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 *==========================================================================*/
lock_init()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 *==========================================================================*/
lock_deinit()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 *==========================================================================*/
isTimerReset()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 *==========================================================================*/
resetTimer()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 *==========================================================================*/
startTimer(uint32_t timer_val)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 *==========================================================================*/
lock_acq_timed(int32_t timer_val)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 *==========================================================================*/
lock_acq()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 *==========================================================================*/
lock_rel_timed()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 *==========================================================================*/
lock_rel()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 *==========================================================================*/
powerHintInternal(PowerHint hint,bool enable)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 *==========================================================================*/
powerHint(PowerHint hint,bool enable)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