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<power_hint_t>(0);
112 mCurrentPowerHintEnable = false;
113
114 property_get("persist.camera.perflock.enable", value, "1");
115 mPerfLockEnable = atoi(value);
116 #ifdef HAS_MULTIMEDIA_HINTS
117 if (hw_get_module(POWER_HARDWARE_MODULE_ID, (const hw_module_t **)&m_pPowerModule)) {
118 LOGE("%s module not found", POWER_HARDWARE_MODULE_ID);
119 }
120 #endif
121
122 if (mPerfLockEnable) {
123 perf_lock_acq = NULL;
124 perf_lock_rel = NULL;
125 mPerfLockHandle = -1;
126 /* Retrieve name of vendor extension library */
127 if (property_get("ro.vendor.extension_library", value, NULL) <= 0) {
128 goto cleanup;
129 }
130
131 mDlHandle = dlopen(value, RTLD_NOW | RTLD_LOCAL);
132 if (mDlHandle == NULL) {
133 goto cleanup;
134 }
135
136 dlerror();
137
138 perf_lock_acq = (int (*) (int, int, int[], int))dlsym(mDlHandle, "perf_lock_acq");
139 if ((rc = dlerror()) != NULL) {
140 LOGE("failed to perf_lock_acq function handle");
141 goto cleanup;
142 }
143
144 perf_lock_rel = (int (*) (int))dlsym(mDlHandle, "perf_lock_rel");
145 if ((rc = dlerror()) != NULL) {
146 LOGE("failed to perf_lock_rel function handle");
147 goto cleanup;
148 }
149 LOGD("X");
150 return;
151
152 cleanup:
153 perf_lock_acq = NULL;
154 perf_lock_rel = NULL;
155 mPerfLockEnable = 0;
156 if (mDlHandle) {
157 dlclose(mDlHandle);
158 mDlHandle = NULL;
159 }
160 }
161 LOGD("X");
162 }
163
164 /*===========================================================================
165 * FUNCTION : lock_deinit
166 *
167 * DESCRIPTION: deinitialize the perf lock parameters
168 *
169 * PARAMETERS :
170 * None
171 *
172 * RETURN : void
173 *
174 *==========================================================================*/
lock_deinit()175 void QCameraPerfLock::lock_deinit()
176 {
177 Mutex::Autolock lock(mLock);
178 if (mPerfLockEnable) {
179 LOGD("E");
180
181 if (mActivePowerHints.empty() == false) {
182 // Disable the active power hint
183 mCurrentPowerHint = *mActivePowerHints.begin();
184 powerHintInternal(mCurrentPowerHint, false);
185 mActivePowerHints.clear();
186 }
187
188 if ((NULL != perf_lock_rel) && (mPerfLockHandleTimed >= 0)) {
189 (*perf_lock_rel)(mPerfLockHandleTimed);
190 }
191
192 if ((NULL != perf_lock_rel) && (mPerfLockHandle >= 0)) {
193 (*perf_lock_rel)(mPerfLockHandle);
194 }
195
196 if (mDlHandle) {
197 perf_lock_acq = NULL;
198 perf_lock_rel = NULL;
199
200 dlclose(mDlHandle);
201 mDlHandle = NULL;
202 }
203 mPerfLockEnable = 0;
204 LOGD("X");
205 }
206 }
207
208 /*===========================================================================
209 * FUNCTION : isTimerReset
210 *
211 * DESCRIPTION: Check if timout duration is reached
212 *
213 * PARAMETERS : None
214 *
215 * RETURN : true if timeout reached
216 * false if timeout not reached
217 *
218 *==========================================================================*/
isTimerReset()219 bool QCameraPerfLock::isTimerReset()
220 {
221 Mutex::Autolock lock(mLock);
222 if (mPerfLockEnable && mTimerSet) {
223 nsecs_t timeDiff = systemTime() - mStartTimeofLock;
224 if (ns2ms(timeDiff) > (uint32_t)mPerfLockTimeout) {
225 resetTimer();
226 return true;
227 }
228 }
229 return false;
230 }
231
232 /*===========================================================================
233 * FUNCTION : resetTimer
234 *
235 * DESCRIPTION: Reset the timer used in timed perf lock
236 *
237 * PARAMETERS : None
238 *
239 * RETURN : void
240 *
241 *==========================================================================*/
resetTimer()242 void QCameraPerfLock::resetTimer()
243 {
244 mPerfLockTimeout = 0;
245 mTimerSet = 0;
246 }
247
248 /*===========================================================================
249 * FUNCTION : start_timer
250 *
251 * DESCRIPTION: get the start of the timer
252 *
253 * PARAMETERS :
254 * @timer_val: timer duration in milliseconds
255 *
256 * RETURN : int32_t type of status
257 * NO_ERROR -- success
258 * none-zero failure code
259 *
260 *==========================================================================*/
startTimer(uint32_t timer_val)261 void QCameraPerfLock::startTimer(uint32_t timer_val)
262 {
263 mStartTimeofLock = systemTime();
264 mTimerSet = 1;
265 mPerfLockTimeout = timer_val;
266 }
267
268 /*===========================================================================
269 * FUNCTION : lock_acq_timed
270 *
271 * DESCRIPTION: Acquire the performance lock for the specified duration.
272 * If an existing lock timeout has not elapsed, extend the
273 * lock further for the specified duration
274 *
275 * PARAMETERS :
276 * @timer_val: lock duration
277 *
278 * RETURN : int32_t type of status
279 * NO_ERROR -- success
280 * none-zero failure code
281 *
282 *==========================================================================*/
lock_acq_timed(int32_t timer_val)283 int32_t QCameraPerfLock::lock_acq_timed(int32_t timer_val)
284 {
285 int32_t ret = -1;
286
287 LOGD("E");
288 Mutex::Autolock lock(mLock);
289
290 if (mPerfLockEnable) {
291 int32_t perf_lock_params[] = {
292 ALL_CPUS_PWR_CLPS_DIS,
293 CPU0_MIN_FREQ_TURBO_MAX,
294 CPU4_MIN_FREQ_TURBO_MAX
295 };
296 if (mTimerSet) {
297 nsecs_t curElapsedTime = systemTime() - mStartTimeofLock;
298 int32_t pendingTimeout = mPerfLockTimeout - ns2ms(curElapsedTime);
299 timer_val += pendingTimeout;
300 }
301 startTimer(timer_val);
302
303 // Disable power hint when acquiring the perf lock
304 if (mCurrentPowerHintEnable) {
305 LOGD("mCurrentPowerHintEnable %d" ,mCurrentPowerHintEnable);
306 powerHintInternal(mCurrentPowerHint, false);
307 }
308
309 if ((NULL != perf_lock_acq) && (mPerfLockHandleTimed < 0)) {
310 ret = (*perf_lock_acq)(mPerfLockHandleTimed, timer_val, perf_lock_params,
311 sizeof(perf_lock_params) / sizeof(int32_t));
312 LOGD("ret %d", ret);
313 if (ret < 0) {
314 LOGE("failed to acquire lock");
315 } else {
316 mPerfLockHandleTimed = ret;
317 }
318 }
319 LOGD("perf_handle_acq %d ", mPerfLockHandleTimed);
320 }
321
322 LOGD("X");
323 return ret;
324 }
325
326 /*===========================================================================
327 * FUNCTION : lock_acq
328 *
329 * DESCRIPTION: acquire the performance lock
330 *
331 * PARAMETERS :
332 * None
333 *
334 * RETURN : int32_t type of status
335 * NO_ERROR -- success
336 * none-zero failure code
337 *
338 *==========================================================================*/
lock_acq()339 int32_t QCameraPerfLock::lock_acq()
340 {
341 int32_t ret = -1;
342
343 LOGD("E");
344 Mutex::Autolock lock(mLock);
345
346 if (mPerfLockEnable) {
347 int32_t perf_lock_params[] = {
348 ALL_CPUS_PWR_CLPS_DIS,
349 CPU0_MIN_FREQ_TURBO_MAX,
350 CPU4_MIN_FREQ_TURBO_MAX
351 };
352
353 // Disable power hint when acquiring the perf lock
354 if (mCurrentPowerHintEnable) {
355 powerHintInternal(mCurrentPowerHint, false);
356 }
357
358 if ((NULL != perf_lock_acq) && (mPerfLockHandle < 0)) {
359 ret = (*perf_lock_acq)(mPerfLockHandle, ONE_SEC, perf_lock_params,
360 sizeof(perf_lock_params) / sizeof(int32_t));
361 LOGD("ret %d", ret);
362 if (ret < 0) {
363 LOGE("failed to acquire lock");
364 } else {
365 mPerfLockHandle = ret;
366 }
367 }
368 LOGD("perf_handle_acq %d ", mPerfLockHandle);
369 }
370
371 LOGD("X");
372 return ret;
373 }
374
375 /*===========================================================================
376 * FUNCTION : lock_rel_timed
377 *
378 * DESCRIPTION: release the performance lock
379 *
380 * PARAMETERS :
381 * None
382 *
383 * RETURN : int32_t type of status
384 * NO_ERROR -- success
385 * none-zero failure code
386 *
387 *==========================================================================*/
lock_rel_timed()388 int32_t QCameraPerfLock::lock_rel_timed()
389 {
390 int ret = -1;
391 Mutex::Autolock lock(mLock);
392 if (mPerfLockEnable) {
393 LOGD("E");
394 if (mPerfLockHandleTimed < 0) {
395 LOGW("mPerfLockHandle < 0,check if lock is acquired");
396 return ret;
397 }
398 LOGD("perf_handle_rel %d ", mPerfLockHandleTimed);
399
400 if ((NULL != perf_lock_rel) && (0 <= mPerfLockHandleTimed)) {
401 ret = (*perf_lock_rel)(mPerfLockHandleTimed);
402 if (ret < 0) {
403 LOGE("failed to release lock");
404 }
405 mPerfLockHandleTimed = -1;
406 resetTimer();
407 }
408
409 if ((mCurrentPowerHintEnable == 1) && (mTimerSet == 0)) {
410 powerHintInternal(mCurrentPowerHint, mCurrentPowerHintEnable);
411 }
412 LOGD("X");
413 }
414 return ret;
415 }
416
417 /*===========================================================================
418 * FUNCTION : lock_rel
419 *
420 * DESCRIPTION: release the performance lock
421 *
422 * PARAMETERS :
423 * None
424 *
425 * RETURN : int32_t type of status
426 * NO_ERROR -- success
427 * none-zero failure code
428 *
429 *==========================================================================*/
lock_rel()430 int32_t QCameraPerfLock::lock_rel()
431 {
432 int ret = -1;
433 Mutex::Autolock lock(mLock);
434 if (mPerfLockEnable) {
435 LOGD("E");
436 if (mPerfLockHandle < 0) {
437 LOGW("mPerfLockHandle < 0,check if lock is acquired");
438 return ret;
439 }
440 LOGD("perf_handle_rel %d ", mPerfLockHandle);
441
442 if ((NULL != perf_lock_rel) && (0 <= mPerfLockHandle)) {
443 ret = (*perf_lock_rel)(mPerfLockHandle);
444 if (ret < 0) {
445 LOGE("failed to release lock");
446 }
447 mPerfLockHandle = -1;
448 }
449
450 if (mCurrentPowerHintEnable == 1) {
451 powerHintInternal(mCurrentPowerHint, mCurrentPowerHintEnable);
452 }
453 LOGD("X");
454 }
455 return ret;
456 }
457
458 /*===========================================================================
459 * FUNCTION : powerHintInternal
460 *
461 * DESCRIPTION: Sets the requested power hint and state to power HAL.
462 *
463 * PARAMETERS :
464 * hint : Power hint
465 * enable : Enable power hint if set to 1. Disable if set to 0.
466 * RETURN : void
467 *
468 *==========================================================================*/
powerHintInternal(power_hint_t hint,bool enable)469 void QCameraPerfLock::powerHintInternal(power_hint_t hint, bool enable)
470 {
471 #ifdef HAS_MULTIMEDIA_HINTS
472 if (m_pPowerModule != NULL) {
473 if (enable == true) {
474 m_pPowerModule->powerHint(m_pPowerModule, hint, (void *)"state=1");
475 } else {
476 m_pPowerModule->powerHint(m_pPowerModule, hint, (void *)"state=0");
477 }
478 }
479 #endif
480 }
481
482 /*===========================================================================
483 * FUNCTION : powerHint
484 *
485 * DESCRIPTION: Updates the list containing active/enabled power hints.
486 * If needed, calls the internal powerHint function with
487 * requested power hint and state.
488 * PARAMETERS :
489 * hint : Power hint
490 * enable : Enable power hint if set to 1. Disable if set to 0.
491 * RETURN : void
492 *
493 *==========================================================================*/
powerHint(power_hint_t hint,bool enable)494 void QCameraPerfLock::powerHint(power_hint_t hint, bool enable)
495 {
496 #ifdef HAS_MULTIMEDIA_HINTS
497 if (enable == true) {
498 if ((hint != mCurrentPowerHint) || (enable != mCurrentPowerHintEnable)) {
499 // Disable the current active power hint
500 if (mCurrentPowerHintEnable == true) {
501 powerHintInternal(mCurrentPowerHint, false);
502 }
503 // Push the new power hint at the head of the active power hint list
504 mActivePowerHints.push_front(hint);
505
506 // Set the new power hint
507 mCurrentPowerHint = hint;
508 mCurrentPowerHintEnable = enable;
509 powerHintInternal(hint, enable);
510 }
511 } else {
512 // Remove the power hint from the list
513 for (List<power_hint_t>::iterator it = mActivePowerHints.begin();
514 it != mActivePowerHints.end(); ++it) {
515 if (*it == hint) {
516 if (it != mActivePowerHints.begin()) {
517 LOGW("Request to remove the previous power hint: %d instead of "
518 "currently active power hint: %d", static_cast<int>(hint),
519 static_cast<int>(mCurrentPowerHint));
520 }
521 mActivePowerHints.erase(it);
522 break;
523 }
524 }
525
526 if (hint == mCurrentPowerHint) {
527 // Disable the power hint
528 powerHintInternal(hint, false);
529
530 // If the active power hint list is not empty,
531 // restore the previous power hint from the head of the list
532 if (mActivePowerHints.empty() == false) {
533 mCurrentPowerHint = *mActivePowerHints.begin();
534 mCurrentPowerHintEnable = true;
535 powerHintInternal(mCurrentPowerHint, true);
536 } else {
537 mCurrentPowerHint = static_cast<power_hint_t>(0);
538 mCurrentPowerHintEnable = false;
539 }
540 }
541 }
542 #endif
543 }
544
545 }; // namespace qcamera
546