android_device_xiaomi_clover/camera/QCamera2/util/QCameraPerfTranslator.cpp

777 lines
23 KiB
C++

/* Copyright (c) 2019, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#define LOG_TAG "QCameraPerf"
/* Includes */
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#include<string.h>
#include<stdlib.h>
#include "mm_camera_dbg.h"
#ifdef __cplusplus
} /* extern "C" */
#endif /* __cplusplus */
#include "cam_types.h"
#include "QCameraCommon.h"
#include "QCameraPerfTranslator.h"
static FSMDB_t *FSM=NULL;
/* Functions */
static int32_t readlines(FILE *fp,char *table){
int32_t linesize=0;
int32_t lines=0;
char value;
while(fread((char*)&value,1,1,fp)){
if(value == '\r'){
continue;
} else if (value == '\n') {
table[linesize]='\0';
lines++;
return linesize;
} else {
table[linesize]=value;
linesize++;
}
if(linesize > LINESIZE || lines > LINES) {
LOGE("ERROR: Size allocated for tables exceeded: lines -> %d, linesize -> %d",lines,linesize);
}
}
return 0;
}
/********* Get Params from strcut *********/
static int32_t get_type2(
void *param1,
__attribute__ ((unused))void *param2,
int32_t streamNo,
__attribute__ ((unused))int32_t sensorNo
){
cam_stream_size_info_t *p1 = (cam_stream_size_info_t *)param1;
int32_t temp;
temp=p1->type[streamNo];
return temp;
}
static int32_t get_istype2(
void *param1,
__attribute__ ((unused))void *param2,
int32_t streamNo,
__attribute__ ((unused))int32_t sensorNo
){
cam_stream_size_info_t *p1 = (cam_stream_size_info_t *)param1;
int32_t temp;
temp=p1->is_type[streamNo];
return temp;
}
static int32_t get_width2(
void *param1,
__attribute__ ((unused))void *param2,
int32_t streamNo,
__attribute__ ((unused))int32_t sensorNo
){
cam_stream_size_info_t *p1 = (cam_stream_size_info_t *)param1;
int32_t temp;
temp=p1->stream_sizes[streamNo].width;
return temp;
}
static int32_t get_height2(
void *param1,
__attribute__ ((unused))void *param2,
int32_t streamNo,
__attribute__ ((unused))int32_t sensorNo
){
cam_stream_size_info_t *p1 = (cam_stream_size_info_t *)param1;
int32_t temp;
temp=p1->stream_sizes[streamNo].height;
return temp;
}
static int32_t get_format2(
void *param1,
__attribute__ ((unused))void *param2,
int32_t streamNo,
__attribute__ ((unused))int32_t sensorNo
){
cam_stream_size_info_t *p1 = (cam_stream_size_info_t *)param1;
int32_t temp;
temp=p1->format[streamNo];
return temp;
}
static int32_t get_hfr2(
__attribute__ ((unused))void *param1,
void *param2,
__attribute__ ((unused))int32_t streamNo,
__attribute__ ((unused))int32_t sensorNo
){
meta2 *p2 = (meta2 *)param2;
int32_t temp;
temp=p2->hfr;
return temp;
}
static int32_t get_fd2(
__attribute__ ((unused))void *param1,
void *param2,
__attribute__ ((unused))int32_t streamNo,
__attribute__ ((unused))int32_t sensorNo
){
meta2 *p2 = (meta2 *)param2;
int32_t temp;
temp=p2->fd;
return temp;
}
static int32_t get_tnr2(
__attribute__ ((unused))void *param1,
void *param2,
__attribute__ ((unused))int32_t streamNo,
__attribute__ ((unused))int32_t sensorNo
){
meta2 *p2 = (meta2 *)param2;
int32_t temp;
temp=p2->tnr;
return temp;
}
static int32_t get_sensorW2(
__attribute__ ((unused))void *param1,
void *param2,
__attribute__ ((unused))int32_t streamNo,
int32_t sensorNo
){
meta2 *p2 = (meta2 *)param2;
int32_t temp;
temp=p2->sensorW[sensorNo];
return temp;
}
static int32_t get_sensorH2(
__attribute__ ((unused))void *param1,
void *param2,
__attribute__ ((unused))int32_t streamNo,
int32_t sensorNo
){
meta2 *p2 = (meta2 *)param2;
int32_t temp;
temp=p2->sensorH[sensorNo];
return temp;
}
static int32_t get_sensorC2(
__attribute__ ((unused))void *param1,
void *param2,
__attribute__ ((unused))int32_t streamNo,
int32_t sensorNo
){
meta2 *p2 = (meta2 *)param2;
int32_t temp;
temp=p2->sensorClk[sensorNo];
return temp;
}
static int32_t get_sensorMP(
__attribute__ ((unused))void *param1,
void *param2,
__attribute__ ((unused))int32_t streamNo,
int32_t sensorNo
){
meta2 *p2 = (meta2 *)param2;
int32_t temp;
temp=p2->sensorMP[sensorNo];
return temp;
}
// static int32_t checkFSM(
// void *param1,
// void *param2,
// int32_t *streamNo,
// paramPtr paramType,
// funcPtr func,
// int32_t cmpValue,
// int32_t loop,
// int32_t sensorNo
// ){
// uint32_t i;
// cam_stream_size_info_t *p1 = (cam_stream_size_info_t *)param1;
// if (loop) {
// /* Search through all the streams and find the stream which matches
// * After finding the match return the streamNo. */
// for (i = 0; i < p1->num_streams; i++) {
// if(paramType(func,param1,param2,cmpValue,i)){
// /* Update the streamNo, to be used for further FSM indexing */
// streamNo=i;
// return true;
// }
// }
// /* No match of th cmpValue with any of the params */
// streamNo=MAX_NUM_STREAMS;
// return false;
// } else {
// /* Don't change the streamNo */
// return paramType(func,param1,param2,cmpValue,streamNo);
// }
// }
/********* FSM Version 2 *****************/
/****** End of FSM Version 2 *************/
// static int get_type(void *param1,__attribute__ ((unused))void *param2,int32_t streamno) {
// cam_stream_size_info_t *p1 = (cam_stream_size_info_t *)param1;
// int32_t type=0;
// int32_t temp;
// uint32_t i;
// /* Get param1 info */
// if(streamno == MAX_FROM_STREAMS){
// /* Not a particular stream, but the max value from all the streams */
// for (i = 0; i < p1->num_streams; i++) {
// temp=p1->type[i];
// /* Get the max value */
// if(temp > type){
// type=temp;
// }
// }
// } else {
// /* From a particular stream */
// type=p1->type[streamno];
// }
// /* Get param2 info */
// return type;
// }
// static int get_istype(void *param1,__attribute__ ((unused))void *param2,int32_t streamno) {
// cam_stream_size_info_t *p1 = (cam_stream_size_info_t *)param1;
// int32_t istype=0;
// int32_t temp;
// uint32_t i;
// /* Get param1 info */
// if(streamno == MAX_FROM_STREAMS){
// /* Not a particular stream, but the max value from all the streams */
// for (i = 0; i < p1->num_streams; i++) {
// temp=p1->is_type[i];
// /* Get the max value */
// if(temp > istype){
// istype=temp;
// }
// }
// } else {
// /* From a particular stream */
// istype=p1->is_type[streamno];
// }
// /* Get param2 info */
// return istype;
// }
// static int32_t get_width(void *param1,__attribute__ ((unused))void *param2,int32_t streamno) {
// cam_stream_size_info_t *p1 = (cam_stream_size_info_t *)param1;
// int32_t width=0;
// int32_t temp;
// uint32_t i;
// /* Get param1 info */
// if(streamno == MAX_FROM_STREAMS){
// /* Not a particular stream, but the max value from all the streams */
// for (i = 0; i < p1->num_streams; i++) {
// temp=p1->stream_sizes[i].width;
// /* Get the max value */
// if(temp > width){
// width=temp;
// }
// }
// } else {
// /* From a particular stream */
// width=p1->stream_sizes[streamno].width;
// }
// /* Get param2 info */
// return width;
// }
// static int32_t get_format(void *param1,__attribute__ ((unused))void *param2,int32_t streamno) {
// cam_stream_size_info_t *p1 = (cam_stream_size_info_t *)param1;
// int32_t format=0;
// int32_t temp;
// uint32_t i;
// /* Get param1 info */
// if(streamno == MAX_FROM_STREAMS){
// /* Not a particular stream, but the max value from all the streams */
// for (i = 0; i < p1->num_streams; i++) {
// temp=p1->format[i];
// /* Get the max value */
// if(temp > format){
// format=temp;
// }
// }
// } else {
// /* From a particular stream */
// format=p1->format[streamno];
// }
// /* Get param2 info */
// return format;
// }
// static int32_t get_height(void *param1,__attribute__ ((unused))void *param2,int32_t streamno) {
// cam_stream_size_info_t *p1 = (cam_stream_size_info_t *)param1;
// int32_t height=0;
// int32_t temp;
// uint32_t i;
// /* Get param1 info */
// if(streamno == MAX_FROM_STREAMS){
// /* Not a particular stream, but the max value from all the streams */
// for (i = 0; i < p1->num_streams; i++) {
// temp=p1->stream_sizes[i].height;
// /* Get the max value */
// if(temp > height){
// height=temp;
// }
// }
// } else {
// /* From a particular stream */
// height=p1->stream_sizes[streamno].height;
// }
// /* Get param2 info */
// return height;
// }
// static int32_t get_EIS30(void *param1,__attribute__ ((unused))void *param2,__attribute__ ((unused))int32_t streamno) {
// cam_stream_size_info_t *p1 = (cam_stream_size_info_t *)param1;
// int32_t istype=0;
// int32_t temp;
// uint32_t i;
// /* Get param1 info */
// for (i = 0; i < p1->num_streams; i++) {
// temp=p1->is_type[i];
// /* Get the max value */
// if(temp > istype){
// istype=temp;
// }
// }
// if(istype == IS_TYPE_EIS_3_0){
// return true;
// }
// return false;
// }
// static int32_t get_hfr(__attribute__ ((unused))void *param1,void *param2,__attribute__ ((unused))int32_t streamno) {
// meta2 *p2 = (meta2 *)param2;
// return p2->hfr;
// }
// static int32_t get_tnr(__attribute__ ((unused))void *param1,void *param2,__attribute__ ((unused))int32_t streamno) {
// meta2 *p2 = (meta2 *)param2;
// return p2->tnr;
// }
// static int32_t get_fd(__attribute__ ((unused))void *param1,void *param2,__attribute__ ((unused))int32_t streamno) {
// meta2 *p2 = (meta2 *)param2;
// return p2->fd;
// }
// static int32_t get_sensorW(__attribute__ ((unused))void *param1,void *param2,int32_t streamno) {
// meta2 *p2 = (meta2 *)param2;
// return p2->sensorW[streamno];
// }
// static int32_t get_sensorH(__attribute__ ((unused))void *param1,void *param2,int32_t streamno) {
// meta2 *p2 = (meta2 *)param2;
// return p2->sensorH[streamno];
// }
// static int32_t get_sensorC(__attribute__ ((unused))void *param1,void *param2,int32_t streamno) {
// meta2 *p2 = (meta2 *)param2;
// return p2->sensorClk[streamno];
// }
static paramPtr get_param_type(char *type, int32_t *streamno,int32_t *loop){
char stream_check[7]={'\0'};
char *token;
char *rest=type;
int32_t no_of_tokens=0;
char paramToken[10];
*streamno=MAX_FROM_STREAMS;
strncpy(stream_check,type,6);
if((!strcmp(stream_check,"stream")) || (!strcmp(stream_check,"sensor"))){
/* Stream specific command */
while ((token = strtok_r(rest, "_", &rest))) {
if(!no_of_tokens){
/* First token is stream */
} else if (no_of_tokens == 1){
/* Second token is the command */
strcpy(paramToken,token);
} else if (no_of_tokens == 2){
/* Final token is the stream no */
*streamno=atoi(token);
}
no_of_tokens++;
}
} else {
LOGE("ERROR: function should start with stream_*\n");
}
if (!strcmp(paramToken,"type")) {
*loop = 1;
return &get_type2;
} else if (!strcmp(paramToken,"istype")) {
*loop = 1;
return &get_istype2;
} else if (!strcmp(paramToken,"format")) {
*loop = 0;
return &get_format2;
} else if (!strcmp(paramToken,"width")) {
*loop = 0;
return &get_width2;
} else if (!strcmp(paramToken,"height")) {
*loop = 0;
return &get_height2;
} else if (!strcmp(paramToken,"tnr")) {
*loop = 0;
return &get_tnr2;
} else if (!strcmp(paramToken,"hfr")) {
*loop = 0;
return &get_hfr2;
} else if (!strcmp(paramToken,"fd")) {
*loop = 0;
return &get_fd2;
} else if (!strcmp(paramToken,"sensorW")) {
*loop = 0;
return &get_sensorW2;
} else if (!strcmp(paramToken,"sensorH")) {
*loop = 0;
return &get_sensorH2;
} else if (!strcmp(paramToken,"sensorC")) {
*loop = 0;
return &get_sensorC2;
} else if (!strcmp(paramToken,"sensorMP")) {
*loop = 0;
return &get_sensorMP;
} else {
LOGE("The FSM table in file has errors 3\n");
exit(0);
}
return NULL;
}
/********* END - Get Params from strcut *********/
/********* Decision Tree Comparator funcs **********/
static int32_t func_le(int32_t param_value,int32_t comp_value) {
return (param_value <= comp_value);
}
static int32_t func_lt(int32_t param_value,int32_t comp_value) {
return (param_value < comp_value);
}
static int32_t func_ge(int32_t param_value,int32_t comp_value) {
return (param_value >= comp_value);
}
static int32_t func_gt(int32_t param_value,int32_t comp_value) {
return (param_value > comp_value);
}
static int32_t func_eq(int32_t param_value,int32_t comp_value) {
return (param_value == comp_value);
}
static funcPtr get_func_type(char *type){
if (!strcmp("LE",type))
return &func_le;
else if(!strcmp("LT",type))
return &func_lt;
else if(!strcmp("GT",type))
return &func_gt;
else if(!strcmp("GE",type))
return &func_ge;
else if(!strcmp("EQ",type))
return &func_eq;
else {
LOGE("The FSM table in file has errors 2\n");
exit(0);
}
return NULL;
}
/********* END - Decision Tree Comparator funcs **********/
static uint8_t setupFSMDB(FSMDB_t *FSM,char *line){
FSMStates state=FUNC_RETURN;
int32_t stream_no=MAX_FROM_STREAMS;
char * token;
char * rest=line;
int32_t value;
int32_t loop;
static int32_t FSMrowCount=0;
while ((token = strtok_r(rest, ":", &rest))) {
//LOGE("Token : %s\n", token);
switch(state){
case FUNC_RETURN:
/*
* FUNC = 0
* RETURN = 1
*/
value = atoi(token);
if(value > 1){
LOGE("The FSM table in file has errors 1\n");
return false;
}
FSM->FSMDB_FUNC_RETURN[FSMrowCount]=value;
if (!value) {
state=PARAM_TYPE;
} else {
state=RETURN_TYPE;
}
break;
case RETURN_TYPE:
value = atoi(token);
FSM->FSMDB_RETURN[FSMrowCount]=value;
break;
case PARAM_TYPE:
FSM->FSMDB_PARAM_TYPE[FSMrowCount]=get_param_type(token,&stream_no,&loop);
FSM->FSMDB_PARAM_STREAMNO[FSMrowCount]=stream_no;
FSM->FSMDB_FUNC_TYPE_LOOP[FSMrowCount]=loop;
state=FUNC_TYPE;
break;
case FUNC_TYPE:
FSM->FSMDB_FUNC_TYPE[FSMrowCount]=get_func_type(token);
state=CMP_VALUE;
break;
case CMP_VALUE:
/* Compare Value will be float */
value = atoi(token);
FSM->FSMDB_CMP_VALUE[FSMrowCount]=value;
state=TRUE_VALUE;
break;
case TRUE_VALUE:
/* True value is index - hence integer */
value = atoi(token);
FSM->FSMDB_TRUE_VALUE[FSMrowCount]=value;
state=FALSE_VALUE;
break;
case FALSE_VALUE:
/* False value is index - hence integer */
value = atoi(token);
FSM->FSMDB_FALSE_VALUE[FSMrowCount]=value;
break;
}
}
FSMrowCount++;
if (FSMrowCount>=1)
return true;
else
return false;
}
static int32_t runFSM(FSMDB_t *FSM,int index,void *param1, void* param2,int32_t session,int32_t streamNo){
/*
* Extract data from the structures and crank it through the FSM.
*/
int32_t isReturn;
paramPtr param;
funcPtr func;
int32_t cmpValue;
int32_t trueValue;
int32_t falseValue;
int32_t sensorNo;
int32_t result;
int32_t loop;
uint32_t i;
cam_stream_size_info_t *p1 = (cam_stream_size_info_t *)param1;
isReturn=FSM->FSMDB_FUNC_RETURN[index];
if(!isReturn){
param=FSM->FSMDB_PARAM_TYPE[index];
/* Get params from the structures */
sensorNo=FSM->FSMDB_PARAM_STREAMNO[index];
func=FSM->FSMDB_FUNC_TYPE[index];
cmpValue=FSM->FSMDB_CMP_VALUE[index];
trueValue=FSM->FSMDB_TRUE_VALUE[index];
falseValue=FSM->FSMDB_FALSE_VALUE[index];
/* Compare the paramValue with cmpValue and based
* on the truth value get the index to the next node
*/
loop = FSM->FSMDB_FUNC_TYPE_LOOP[index];
//streamNo=MAX_NUM_STREAMS;
result=false;
if (loop) {
/* Search through all the streams and find the stream which matches
* After finding the match return the streamNo. */
for (i = 0; i < p1->num_streams; i++) {
if(func(param(param1,param2,i,sensorNo),cmpValue)){
/* Update the streamNo, to be used for further FSM indexing */
streamNo=i;
result=true;
break;
}
}
/* No match of th cmpValue with any of the params */
} else {
/* Don't change the streamNo */
result= func(param(param1,param2,streamNo,sensorNo),cmpValue);
}
index = (result?trueValue:falseValue);
LOGH("FSM : Param = %p,StrNo = %d, func= %p, cmp= %d, true = %d, false = %d :: index = %d\n",param,streamNo,func,cmpValue,trueValue,falseValue,index);
return runFSM(FSM,index,param1,param2,session,streamNo);
}else{
return FSM->FSMDB_RETURN[index];
}
}
struct FSMDB* setupFSM(char *fileName){
// 0 - Function execute it
// 1 - Return the value
/* | Func/Return | ParamType | FuncType | CmpValue | TrueValue | FalseValue
* | | | | | |
*/
FILE *fp;
char table[LINESIZE];
int filesizecheck=false;
if(FSM){
/* The FSM has already been setup-> don't create again.
* This can happend for Dual camera
*/
return FSM;
}
FSM=(FSMDB_t *)malloc(sizeof(FSMDB_t));
if(!FSM){
LOGE("Unable to setup the FSM\n");
return NULL;
}
if (!(fp=(FILE *)fopen(fileName,"r"))){
LOGE("Unable to open file\n");
return NULL;
}
while(readlines(fp,(char *)table)){
LOGH("The node is : %s\n",table);
if(!setupFSMDB(FSM,table)){
LOGE("Failed to setup FSMDB from the config file\n");
free(FSM);
FSM=NULL;
break;
}
filesizecheck=true;
// TODO - error handling - file wrong errors
}
if(!filesizecheck) {
LOGE("Failed to setup FSMDB from the config file\n");
free(FSM);
FSM=NULL;
}
fclose(fp);
return FSM;
}
int32_t predictFSM(FSMDB_t *FSM,void *param1, void *param2,int32_t session){
static meta2_t metaData={{0,0},{0,0},{0,0},{0,0},0,0,0};
static int32_t perfLevel[2]={0,0};
int32_t totalPerfLevel=0,prevPerfLevel;
cam_perf_info_t *meta=(cam_perf_info_t *)param2;
// returning value 0 means no-throttling
// IMP: Not tracking no of sessions.
if(!FSM){
LOGE("Unable to predict as NULL FSM passed\n");
return 0;
}
prevPerfLevel=perfLevel[0]+perfLevel[1];
// 1. struct1 & struct2 = NULL indicates session_no is getting closed
if ((NULL == (int32_t *)param1) || (NULL == (int32_t *)param2)) {
// Either structs is NULL, then the session_no is de-activated
perfLevel[session]=0;
} else if( (meta->sensorW * meta->sensorH) == 0) {
// invalid case if either sensorW or sensorH is 0
// sensor values should always be updated
perfLevel[session]=0;
} else {
// 2. Based on Session No compute the perf level
metaData.sensorW[session]=meta->sensorW;
metaData.sensorH[session]=meta->sensorH;
metaData.sensorClk[session]=meta->sensorClk;
metaData.sensorMP[session]=((meta->sensorW)*(meta->sensorH))/(1024*1024);
metaData.hfr=meta->hfr;
metaData.fd=meta->fd;
metaData.tnr=meta->tnr;
perfLevel[session]=runFSM(FSM,0,param1,&metaData,session,8);
}
// 3. Add the perf levels everytime for all sessions
totalPerfLevel=perfLevel[0]+perfLevel[1];
totalPerfLevel=(totalPerfLevel>FSM_MAX_LEVEL?FSM_MAX_LEVEL:totalPerfLevel);
// Return the total perf level based on no of sessions
LOGH("The predicted value from FSM : %d\n",totalPerfLevel);
if (prevPerfLevel > totalPerfLevel) {
// First send 0 then totalPerfLevel
LOGH("Prev Level greater than New Level\n");
} else if (prevPerfLevel == totalPerfLevel) {
// no need to send
LOGH("Prev Level same as New Level\n");
} else {
// send
LOGH("Prev Level smaller than New Level\n");
}
return totalPerfLevel;
}
void closeFSM(){
if (FSM) {
free(FSM);
FSM = NULL;
}
}