前言:
当硬件性能足够的情况下,有时候还是会遇到平台编解码耗时较长的问题。此时,就需要检查venus的时钟频率了。时钟频率低必将导致codec速度下降。
时钟频率的查看:
step1: 打开log
adb shell setprop vendor.vidc.debug.level 7
adb shell "echo 0x103F > /d/msm_vidc/debug_level"
adb shell "echo 0x3F > /d/msm_vidc/fw_level"
step2: 复现问题抓取log
adb logcat -b kernel >kernel.log
step3: 查看时钟频率
09-10 17:19:13.552 0 0 I msm_vidc: prof: Scaling clock core1_clk to 100000000
09-10 17:19:13.588 0 0 I msm_vidc: prof: Scaling clock core_clk to 100000000
09-10 17:19:13.588 0 0 I msm_vidc: prof: Scaling clock core0_clk to 100000000
综上我们就可以看到复现问题时venus的时钟频率为100Mhz.
时钟频率的设置:
// kernel/msm-4.14/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
msm_clock_data_reset
msm_comm_scale_clocks_and_bus
msm-4.14/drivers/media/platform/msm/vidc/msm_vidc.c start_streaming
msm_vidc_start_streaming start_streaming = msm_vidc_start_streaming
int msm_comm_scale_clocks(struct msm_vidc_inst *inst)
{
struct msm_vidc_buffer *temp, *next;
unsigned long freq = 0;
u32 filled_len = 0;
u32 device_addr = 0;
bool is_turbo = false;
if (!inst || !inst->core) {
dprintk(VIDC_ERR, "%s Invalid args: Inst = %pK\n",
__func__, inst);
return -EINVAL;
}
mutex_lock(&inst->registeredbufs.lock);
list_for_each_entry_safe(temp, next, &inst->registeredbufs.list, list) {
if (temp->vvb.vb2_buf.type ==
V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
filled_len = max(filled_len,
temp->vvb.vb2_buf.planes[0].bytesused);
if (inst->session_type == MSM_VIDC_ENCODER &&
(temp->vvb.flags &
V4L2_QCOM_BUF_FLAG_PERF_MODE)) {
is_turbo = true;
}
device_addr = temp->smem[0].device_addr;
}
}
mutex_unlock(&inst->registeredbufs.lock);
if (!filled_len || !device_addr) {
dprintk(VIDC_DBG, "%s no input for session %x\n",
__func__, hash32_ptr(inst->session));
goto no_clock_change;
}
freq = call_core_op(inst->core, calc_freq, inst, filled_len);
inst->clk_data.min_freq = freq;
/* update dcvs flags */
msm_dcvs_scale_clocks(inst, freq);
if (inst->clk_data.buffer_counter < DCVS_FTB_WINDOW || is_turbo ||
msm_vidc_clock_voting) {
inst->clk_data.min_freq = msm_vidc_max_freq(inst->core);
inst->clk_data.dcvs_flags = 0;
}
msm_vidc_update_freq_entry(inst, freq, device_addr, is_turbo);
msm_vidc_set_clocks(inst->core);
no_clock_change:
return 0;
}
int msm_vidc_set_clocks(struct msm_vidc_core *core)
{
struct hfi_device *hdev;
unsigned long freq_core_1 = 0, freq_core_2 = 0, rate = 0;
unsigned long freq_core_max = 0;
struct msm_vidc_inst *temp = NULL;
int rc = 0, i = 0;
struct allowed_clock_rates_table *allowed_clks_tbl = NULL;
bool increment, decrement;
hdev = core->device;
allowed_clks_tbl = core->resources.allowed_clks_tbl;
if (!allowed_clks_tbl) {
dprintk(VIDC_ERR,
"%s Invalid parameters\n", __func__);
return -EINVAL;
}
mutex_lock(&core->lock);
increment = false;
decrement = true;
list_for_each_entry(temp, &core->instances, list) {
if (temp->clk_data.core_id == VIDC_CORE_ID_1)
freq_core_1 += temp->clk_data.min_freq;
else if (temp->clk_data.core_id == VIDC_CORE_ID_2)
freq_core_2 += temp->clk_data.min_freq;
else if (temp->clk_data.core_id == VIDC_CORE_ID_3) {
freq_core_1 += temp->clk_data.min_freq;
freq_core_2 += temp->clk_data.min_freq;
}
freq_core_max = max_t(unsigned long, freq_core_1, freq_core_2);
if (msm_vidc_clock_voting) {
dprintk(VIDC_PROF,
"msm_vidc_clock_voting %d\n",
msm_vidc_clock_voting);
freq_core_max = msm_vidc_clock_voting;
decrement = false;
break;
}
if (temp->clk_data.turbo_mode) {
dprintk(VIDC_PROF,
"Found an instance with Turbo request\n");
freq_core_max = msm_vidc_max_freq(core);
decrement = false;
break;
}
/* increment even if one session requested for it */
if (temp->clk_data.dcvs_flags & MSM_VIDC_DCVS_INCR)
increment = true;
/* decrement only if all sessions requested for it */
if (!(temp->clk_data.dcvs_flags & MSM_VIDC_DCVS_DECR))
decrement = false;
}
for (i = core->resources.allowed_clks_tbl_size - 1; i >= 0; i--) {
rate = allowed_clks_tbl[i].clock_rate;
if (rate >= freq_core_max)
break;
}
if (increment) {
if (i > 0)
rate = allowed_clks_tbl[i-1].clock_rate;
} else if (decrement) {
if (i < (core->resources.allowed_clks_tbl_size - 1))
rate = allowed_clks_tbl[i+1].clock_rate;
}
core->min_freq = freq_core_max;
core->curr_freq = rate;
mutex_unlock(&core->lock);
dprintk(VIDC_PROF,
"%s: clock rate %lu requested %lu increment %d decrement %d\n",
__func__, core->curr_freq, core->min_freq,
increment, decrement);
rc = call_hfi_op(hdev, scale_clocks,
hdev->hfi_device_data, core->curr_freq);
return rc;
}
// kernel/msm-4.14/drivers/media/platform/msm/vidc/venus_hfi.c
static void venus_init_hfi_callbacks(struct hfi_device *hdev)
{ ......
hdev->scale_clocks = venus_hfi_scale_clocks;
......
}
static int venus_hfi_scale_clocks(void *dev, u32 freq)
{
int rc = 0;
struct venus_hfi_device *device = dev;
if (!device) {
dprintk(VIDC_ERR, "Invalid args: %pK\n", device);
return -EINVAL;
}
mutex_lock(&device->lock);
if (__resume(device)) {
dprintk(VIDC_ERR, "Resume from power collapse failed\n");
rc = -ENODEV;
goto exit;
}
rc = __set_clocks(device, freq);
exit:
mutex_unlock(&device->lock);
return rc;
}
static int __set_clocks(struct venus_hfi_device *device, u32 freq)
{
struct clock_info *cl;
int rc = 0;
venus_hfi_for_each_clock(device, cl) {
if (cl->has_scaling) {/* has_scaling */
rc = __set_clk_rate(device, cl, freq);
if (rc)
return rc;
trace_msm_vidc_perf_clock_scale(cl->name, freq);
dprintk(VIDC_PROF, "Scaling clock %s to %u\n",
cl->name, freq);
}
}
return 0;
}