使用simpleperf跟踪自定义的perf events

news2024/12/23 17:59:56

目录

前言

tracepoint简介

添加tracepoint:

使用simpleperf 跟踪自定义的tracepoint


前言

  1. simpleperf可以跟踪指定的perf events,通过adb shell & simpleperf list可以查看当前设备支持的所有perf event。
  2. 但是如果这些perf event不能满足我们的需求,这时候需要自定义我们需要的event。

tracepoint简介

tracepoint 是内核提供的tracing机制,可以通过打开和关闭来probe 相应函数且对内核影响很小,tracepoint目前工作在ftrace框架内,使用ring buffer传输perf数据,针对开发者来说,tracepoint框架提供了现成的宏来帮助开发者定义和增加tracepoints。

我们直接看下系统现成的tracepoint是怎么定义的:

TRACE_EVENT(sched_switch,
 
 TP_PROTO(struct rq *rq, struct task_struct *prev,
      struct task_struct *next),
 
 TP_ARGS(rq, prev, next),
 
 TP_STRUCT__entry(
     __array(    char,   prev_comm,  TASK_COMM_LEN   )
     __field(    pid_t,  prev_pid            )
     __field(    int,    prev_prio           )
     __field(    long,   prev_state          )
     __array(    char,   next_comm,  TASK_COMM_LEN   )
     __field(    pid_t,  next_pid            )
     __field(    int,    next_prio           )
 ),
 
 TP_fast_assign(
     memcpy(__entry->next_comm, next->comm, TASK_COMM_LEN);
     __entry->prev_pid    = prev->pid;
     __entry->prev_prio   = prev->prio;
     __entry->prev_state  = prev->state;
     memcpy(__entry->prev_comm, prev->comm, TASK_COMM_LEN);
     __entry->next_pid    = next->pid;
     __entry->next_prio   = next->prio;
 ),
 
 TP_printk("prev_comm=%s prev_pid=%d prev_prio=%d prev_state=%s ==> next_comm=%s next_pid=%d next_prio=%d",
     __entry->prev_comm, __entry->prev_pid, __entry->prev_prio,
     __entry->prev_state ?
       __print_flags(__entry->prev_state, "|",
             { 1, "S"} , { 2, "D" }, { 4, "T" }, { 8, "t" },
             { 16, "Z" }, { 32, "X" }, { 64, "x" },
             { 128, "W" }) : "R",
     __entry->next_comm, __entry->next_pid, __entry->next_prio)
);
TRACE_EVENT 宏总共由6部分组成:
  1. name: 自定义的tracepoint名称,使用此tracepoint时,在名称前加trace_,使用trace_defined的方法来追踪指定函数。
  2. TP_PROTO:函数原型,指定参数类型
  3. ARGS: 函数具体参数
  4. TP_STRUCT__entry:需要传输到ring buffer的数据结构体
  5. TP_fast_assign:给TP_STRUCT__entry定义的结构体赋值,括号内是标准c代码,其中_entry是对结构体的引用
  6. TP_printk:将entry结构体中的数据输出

一旦像上面定义好tracepoint,就可以在具体的函数中添加trace:

if (likely(prev != next)) {
    if (!prev->on_rq)
        prev->last_sleep_ts = wallclock;
 
    update_task_ravg(prev, rq, PUT_PREV_TASK, wallclock, );
    update_task_ravg(next, rq, PICK_NEXT_TASK, wallclock, );
    rq->nr_switches++;
    rq->curr = next;
    ++*switch_count;
    // 在具体的方法通过trace_definedname的形式添加trace
    trace_sched_switch(preempt, prev, next);
 
    /* Also unlocks the rq: */
    rq = context_switch(rq, prev, next, &rf);
} else {
    update_task_ravg(prev, rq, TASK_UPDATE, wallclock, );
    rq->clock_update_flags &= ~(RQCF_ACT_SKIP|RQCF_REQ_SKIP);
    rq_unlock_irq(rq, &rf);
}

如果同类型的tracepoint即参数相同,但是使用场景稍有区分,可以使用 DECLARE_EVENT_CLASS 来统一管理,DECLARE_EVENT_CLASS和TRACE_EVENT拥有一模一样的6个部分,不同的是DECLARE_EVENT_CLASS里声明的name 是calss name,当定义具体的event的时候使用DEFINE_EVENT宏,第一个参数先带上这个calss name。

比如我们已经按照上面TRACE_EVENT的形式定义了一个名为sched_wakeup_template 的event class,后续的define event可以用如下方式定义:

//sched_wakeup_template是DECLARE_EVENT_CLASS定义的event class name
//sched_wakeup 是具体的event name
DEFINE_EVENT(sched_wakeup_template, sched_wakeup,
                TP_PROTO(struct rq *rq, struct task_struct *p, int success),
                TP_ARGS(rq, p, success));
 
 
//sched_wakeup_template是DECLARE_EVENT_CLASS定义的event class name
//sched_wakeup_new 是具体的event name
DEFINE_EVENT(sched_wakeup_template, sched_wakeup_new,
                TP_PROTO(struct rq *rq, struct task_struct *p, int success),
                TP_ARGS(rq, p, success));
通过上面的方式,先定义个event class作为模板,然后定义不同的event就达成了同类型trace event的快速定义。

添加tracepoint:

有了上面的简介铺垫,现在我们来实际添加一个tracepoint,这里的tracepoint添加在ion子系统中,因为ion定义的perf events没有memory alloc相关的事件,而这个事件在我们追踪ion 内存分配和管理时非常关注,所以以此为例。

首先看下ion alloc的相关方法,总共有三个:

struct dma_buf *ion_alloc(size_t len, unsigned int heap_id_mask,
              unsigned int flags)
 
 
int ion_alloc_fd(size_t len, unsigned int heap_id_mask, unsigned int flags)
 
 
struct dma_buf *ion_alloc_dmabuf(size_t len, unsigned int heap_id_mask,
                 unsigned int flags)

观察下三个方法的参数类型完全一致,于是我们在其现有的ion的trace header file中添加如下trace event class 和event:

注:ion的trace header file路径在:/sources/toco/kernel/msm-4.14/include/trace/events/ion.h

//定义一个ion_alloc_mem_class,并指定参数类型,具体参数
DECLARE_EVENT_CLASS(ion_alloc_mem_class,
    TP_PROTO(size_t len, unsigned int heap_id_mask,
              unsigned int flags),
    TP_ARGS(len, heap_id_mask, flags),
    TP_STRUCT__entry(
        __field(size_t, len)
        __field(unsigned int, heap_id_mask)
        __field(unsigned int, flags)
    ),
    TP_fast_assign(
        __entry->len = len;
        __entry->heap_id_mask = heap_id_mask;
        __entry->flags = flags;
    ),
 
 
    TP_printk("len %zu heap_id_mask %u flags %x\n",
        __entry->len,
        __entry->heap_id_mask,
        __entry->flags)
 
);
 
// 定义三个具体的trace event
DEFINE_EVENT(ion_alloc_mem_class, ion_alloc,
    TP_PROTO(size_t len, unsigned int heap_id_mask,
              unsigned int flags),
 
    TP_ARGS(len, heap_id_mask, flags)
);
 
DEFINE_EVENT(ion_alloc_mem_class, ion_alloc_fd,
    TP_PROTO(size_t len, unsigned int heap_id_mask,
              unsigned int flags),
 
    TP_ARGS(len, heap_id_mask, flags)
);
 
DEFINE_EVENT(ion_alloc_mem_class, ion_alloc_dmabuf,
    TP_PROTO(size_t len, unsigned int heap_id_mask,
              unsigned int flags),
 
    TP_ARGS(len, heap_id_mask, flags)
);

然后在具体的代码中添加trace,因为ion_alloc和ion_alloc_fd都会最终调用到ion_alloc_dmabuf中,

我们直接在ion_alloc_dmabuf中添加相应的trace:

struct dma_buf *ion_alloc_dmabuf(size_t len, unsigned int heap_id_mask,
                 unsigned int flags)
{
    struct ion_device *dev = internal_dev;
    struct ion_buffer *buffer = NULL;
    struct ion_heap *heap;
    DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
    struct dma_buf *dmabuf;
    char task_comm[TASK_COMM_LEN];
 
 
    pr_debug("%s: len %zu heap_id_mask %u flags %x\n", __func__,
         len, heap_id_mask, flags);
 
    // 添加的trace
    trace_ion_alloc_dmabuf(len, heap_id_mask, flags);
 
    len = PAGE_ALIGN(len);
 
    if (!len)
        return ERR_PTR(-EINVAL);
 
    down_read(&dev->lock);
    plist_for_each_entry(heap, &dev->heaps, node) {
        /* if the caller didn't specify this heap id */
        if (!((1 << heap->id) & heap_id_mask))
            continue;
        buffer = ion_buffer_create(heap, dev, len, flags);
        if (!IS_ERR(buffer) || PTR_ERR(buffer) == -EINTR)
            break;
    }
    up_read(&dev->lock);
 
    if (!buffer)
        return ERR_PTR(-ENODEV);
 
    if (IS_ERR(buffer))
        return ERR_CAST(buffer);
 
    get_task_comm(task_comm, current->group_leader);
 
    exp_info.ops = &dma_buf_ops;
    exp_info.size = buffer->size;
    exp_info.flags = O_RDWR;
    exp_info.priv = buffer;
    exp_info.exp_name = kasprintf(GFP_KERNEL, "%s-%s-%d-%s", KBUILD_MODNAME,
                      heap->name, current->tgid, task_comm);
 
    dmabuf = dma_buf_export(&exp_info);
    if (IS_ERR(dmabuf)) {
        _ion_buffer_destroy(buffer);
        kfree(exp_info.exp_name);
    }
 
    return dmabuf;
}

至此我们完成了自定义添加的tracepoint

使用simpleperf 跟踪自定义的tracepoint

添加完自定义的tracepoint也就是perf event后,我们需要用simpleperf来追踪这个事件。

重新编译kernel烧写后,使用simpleperf list | grep ion: 来检查添加的tracepoint是否已经成功:

从上图可以看出我们增加的三个tracepoint已经添加成功

然后使用如下命令record camera provider,并且对ion_alloc_dmabuf进行过滤:


adb shell
 
 
simpleperf record -p 764 -e 'ion:ion_alloc_dmabuf' -o /sdcard/perf.data --call-graph dwarf
 
 
按ctrl-c结束record,有以下输出时,说明成功记录相应perf 数据:
simpleperf I cmd_record.cpp:635] Samples recorded: 313. Samples lost: 0.

将 perf.data pull出来之后进行simperf report:

这里使用simpleperf的report_sample脚本加上 --show_tracing_data参数将输出到ring buffer的数据同样打印出来。

最终得到的trace结果如下:

provider@2.4-se   1781 [007] 237.483212:        1 ion:ion_alloc_dmabuf:
ffffff870930a588  ion_alloc_dmabuf ([kernel.kallsyms])
ffffff870930a586  ion_alloc_dmabuf ([kernel.kallsyms])
ffffff870930aa9a  ion_alloc ([kernel.kallsyms])
ffffff87091575aa  cam_mem_mgr_alloc_and_map ([kernel.kallsyms])
ffffff8709155156  cam_private_ioctl ([kernel.kallsyms])
ffffff8709098d46  __video_do_ioctl ([kernel.kallsyms])
ffffff8709098806  video_usercopy ([kernel.kallsyms])
ffffff8709098b2a  video_ioctl2 ([kernel.kallsyms])
ffffff8709097f7a  v4l2_ioctl ([kernel.kallsyms])
ffffff870888387e  do_vfs_ioctl ([kernel.kallsyms])
ffffff8708883c56  sys_ioctl ([kernel.kallsyms])
ffffff870868487e  el0_svc_naked ([kernel.kallsyms])
      7db7ed91c8  __ioctl (/apex/com.android.runtime/lib64/bionic/libc.so)
      7db7e937ec  ioctl (/apex/com.android.runtime/lib64/bionic/libc.so)
      7db327b98c  CSLHwInternalDefaultIoctl2(CSLHwDevice const*, unsigned int, void*, unsigned int, unsigned int) (/vendor/lib64/hw/camera.qcom.so)
      7db3270f84  CSLAllocHW(char const*, CSLBufferInfo*, unsigned long, unsigned long, unsigned int, int const*, unsigned int) (/vendor/lib64/hw/camera.qcom.so)
      7db3268f60  CSLAlloc (/vendor/lib64/hw/camera.qcom.so)
      7db31ffd04  CamX::MemPoolGroup::AllocateBuffers(unsigned int) (/vendor/lib64/hw/camera.qcom.so)
      7db32026ac  CamX::MemPoolGroup::GetBufferFromPool(CamX::MemPoolBufferManager*, CSLBufferInfo*, CamX::NativeHandle const**) (/vendor/lib64/hw/camera.qcom.so)
      7db31fbef4  CamX::MemPoolMgr::GetBufferFromPool(void*, CSLBufferInfo*, CamX::NativeHandle const**) (/vendor/lib64/hw/camera.qcom.so)
      7db31dd810  CamX::ImageBuffer::Allocate() (/vendor/lib64/hw/camera.qcom.so)
      7db31e3808  CamX::ImageBufferManager::BindBufferManagerImageBuffer(CamX::ImageBuffer*) (/vendor/lib64/hw/camera.qcom.so)
      7db31dea50  CamX::ImageBuffer::BindBuffer() (/vendor/lib64/hw/camera.qcom.so)
      7db321ea10  CamX::Node::BindInputOutputBuffers(CamX::PerRequestActivePorts const*, int, int) (/vendor/lib64/hw/camera.qcom.so)
      7db321d760  CamX::Node::ProcessRequest(CamX::NodeProcessRequestData*, unsigned long) (/vendor/lib64/hw/camera.qcom.so)
      7db31ce534  CamX::DeferredRequestQueue::DeferredWorkerCore(CamX::Dependency*) (/vendor/lib64/hw/camera.qcom.so)
      7db31ce120  CamX::DeferredRequestQueue::DeferredWorkerWrapper(void*) (/vendor/lib64/hw/camera.qcom.so)
      7db31497a8  CamX::ThreadCore::DispatchJob(CamX::RuntimeJob*) (/vendor/lib64/hw/camera.qcom.so)
      7db314a078  CamX::ThreadCore::ProcessJobQueue() (/vendor/lib64/hw/camera.qcom.so)
      7db31499d0  CamX::ThreadCore::DoWork() (/vendor/lib64/hw/camera.qcom.so)
      7db314988c  CamX::ThreadCore::WorkerThreadBody(void*) (/vendor/lib64/hw/camera.qcom.so)
      7db7eee9d0  __pthread_start(void*) (/apex/com.android.runtime/lib64/bionic/libc.so)
      7db7e8cb6c  __start_thread (/apex/com.android.runtime/lib64/bionic/libc.so)
      tracing data:
            common_type : 971
            common_flags : 0
            common_preempt_count : 1
            common_pid : 1781
            len : 24081792
            heap_id_mask : 34603008
            flags : 1
 
 
 
 
HwBinder:764_2    11526 [002] 235.334226:       1 ion:ion_alloc_dmabuf:
ffffff870930a588  ion_alloc_dmabuf ([kernel.kallsyms])
ffffff870930a586  ion_alloc_dmabuf ([kernel.kallsyms])
ffffff870930aa9a  ion_alloc ([kernel.kallsyms])
ffffff87091575aa  cam_mem_mgr_alloc_and_map ([kernel.kallsyms])
ffffff8709155156  cam_private_ioctl ([kernel.kallsyms])
ffffff8709098d46  __video_do_ioctl ([kernel.kallsyms])
ffffff8709098806  video_usercopy ([kernel.kallsyms])
ffffff8709098b2a  video_ioctl2 ([kernel.kallsyms])
ffffff8709097f7a  v4l2_ioctl ([kernel.kallsyms])
ffffff870888387e  do_vfs_ioctl ([kernel.kallsyms])
ffffff8708883c56  sys_ioctl ([kernel.kallsyms])
ffffff870868487e  el0_svc_naked ([kernel.kallsyms])
      7db7ed91c8  __ioctl (/apex/com.android.runtime/lib64/bionic/libc.so)
      7db7e937ec  ioctl (/apex/com.android.runtime/lib64/bionic/libc.so)
      7db327b98c  CSLHwInternalDefaultIoctl2(CSLHwDevice const*, unsigned int, void*, unsigned int, unsigned int) (/vendor/lib64/hw/camera.qcom.so)
      7db3270f84  CSLAllocHW(char const*, CSLBufferInfo*, unsigned long, unsigned long, unsigned int, int const*, unsigned int) (/vendor/lib64/hw/camera.qcom.so)
      7db3268f60  CSLAlloc (/vendor/lib64/hw/camera.qcom.so)
      7db31cb85c  CamX::CmdBufferManager::InitializePool() (/vendor/lib64/hw/camera.qcom.so)
      7db31ca8a4  CamX::CmdBufferManager::Initialize(char const*, CamX::ResourceParams const*) (/vendor/lib64/hw/camera.qcom.so)
      7db31ca4a4  CamX::CmdBufferManager::CreateParentManager(CamX::CmdBufferManagerParam*, unsigned int) (/vendor/lib64/hw/camera.qcom.so)
      7db31cab20  CamX::CmdBufferManager::CreateMultiManager(CamX::CmdBufferManagerParam*, unsigned int) (/vendor/lib64/hw/camera.qcom.so)
      7db3226198  CamX::Node::CreateMultiCmdBufferManager(CamX::CmdBufferManagerParam*, unsigned int) (/vendor/lib64/hw/camera.qcom.so)
      7db2fb0ae4  CamX::IPENode::CreateFWCommandBufferManagers() (/vendor/lib64/hw/camera.qcom.so)
      7db2faf864  CamX::IPENode::InitializeStripingParams(_IpeConfigIoData*) (/vendor/lib64/hw/camera.qcom.so)
      7db2fae858  CamX::IPENode::SetupDeviceResource(CSLBufferInfo*, CSLDeviceResource*) (/vendor/lib64/hw/camera.qcom.so)
      7db2f9fbfc  CamX::IPENode::AcquireDevice() (/vendor/lib64/hw/camera.qcom.so)
      7db2f9ecfc  CamX::IPENode::PostPipelineCreate() (/vendor/lib64/hw/camera.qcom.so)
      7db3229894  CamX::Node::NotifyPipelineCreated() (/vendor/lib64/hw/camera.qcom.so)
      7db323cdbc  CamX::Pipeline::FinalizePipeline(CamX::FinalizeInitializationData*) (/vendor/lib64/hw/camera.qcom.so)
      7db3244908  CamX::Session::FinalizeDeferPipeline(unsigned int) (/vendor/lib64/hw/camera.qcom.so)
      7db3248324  CamX::Session::StreamOn(void*) (/vendor/lib64/hw/camera.qcom.so)
      7d8f464cb4  FeatureMFNR::ActivateOfflinePipeline(FeatureMFNR::MFNRStage) (/vendor/lib64/hw/com.qti.chi.override.so)
      7d8f468e30  FeatureMFNR::ExecuteMfnrRequest(FeatureMFNR::MFNRStage, unsigned int, unsigned int, ChiStreamBuffer*, unsigned int, ChiStreamBuffer*, ChiMetadata*, ChiMetadata*) (/vendor/lib64/hw/com.qti.chi.override.so)
      7d8f467b3c  FeatureMFNR::SubmitOfflinePostfilterStageRequest(unsigned int, camera3_capture_request*, FeatureMFNR::MFNRInputInfo*) (/vendor/lib64/hw/com.qti.chi.override.so)
      7d8f46582c  FeatureMFNR::SubmitOfflineMfnrRequest(unsigned int, camera3_capture_request*) (/vendor/lib64/hw/com.qti.chi.override.so)
      7d8f46dc3c  FeatureMFNR::RequestThreadProcessing() (/vendor/lib64/hw/com.qti.chi.override.so)
      7d8f45c924  FeatureMFNR::RequestThread(void*) (/vendor/lib64/hw/com.qti.chi.override.so)
      7db7eee9d0  __pthread_start(void*) (/apex/com.android.runtime/lib64/bionic/libc.so)
      7db7e8cb6c  __start_thread (/apex/com.android.runtime/lib64/bionic/libc.so)
      tracing data:
            common_type : 971
            common_flags : 0
            common_preempt_count : 1
            common_pid : 11526
            len : 3473408
            heap_id_mask : 34603008
            flags : 0

从用户空间到内核的ion alloc调用一目了然,可以帮助我们了解系统和定位问题。

如果使用simpleperf的report_html脚本: python report_html.py -i perf.data -o iontrace.html得到类似下图的结果:

这样会更加的直观。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1098278.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深入理解操作系统之线程

目录 补充进程知识&#xff1a; 是什么触发了进程的切换&#xff1f; 进程切换时要做什么&#xff1f; 切换进程的时机分为主动和被动。 进程上下文指的是什么&#xff1f; 线程篇&#xff1a; 以进程创建子进程为例引入线程&#xff1a; 线程定义&#xff1a; Motivat…

Spring Cloud Alibaba—Sentinel 控制台安装

1、Sentinel 控制台包含如下功能: 查看机器列表以及健康情况&#xff1a;收集 Sentinel 客户端发送的心跳包&#xff0c;用于判断机器是否在线。 监控 (单机和集群聚合)&#xff1a;通过 Sentinel 客户端暴露的监控 API&#xff0c;定期拉取并且聚合应用监控信息&#xff0c;最…

实验室超声波清洗器如何选择?

实验室是很多科研人员工作的地方&#xff0c;而且他们的工作环境较为特殊&#xff0c;与一般的工作环境有所不同&#xff0c;在大多数实验过程后会通常都会需要使用到效率高实验室超声波清洗机&#xff0c;而且其清洁效率也要比普通的清洗机高。不同实验室会对实验室超声波清洗…

记一次密码重置到后台GetShell

1.尝试登录 打开网页&#xff0c;看到一个登录&#xff0c;尝试点击 2.发现提示 Unknown host 3.因为刚开始是用 IP 访问的网站&#xff0c;点击登录按钮为域名访问该网站&#xff0c;猜测可能使用域名访问不了&#xff0c;于是把域名改为IP加上后... 1.尝试登录 1.打开网页&…

ITextRenderer将PDF转换为HTML详细教程

引入依赖 <dependency><groupId>org.xhtmlrenderer</groupId><artifactId>flying-saucer-pdf-itext5</artifactId><version>9.1.18</version></dependency> 问题一&#xff1a;输出中文字体 下载字体simsun.ttc 下载链接&am…

动态规划:09 0-1背包理论基础I

动态规划&#xff1a;09 0-1背包理论基础I 背包问题概述 对于面试的话&#xff0c;其实掌握01背包&#xff0c;和完全背包&#xff0c;就够用了&#xff0c;最多可以再来一个多重背包。 如果这几种背包&#xff0c;分不清&#xff0c;就看下图 leetcode上连多重背包的题目都…

【MATLAB-Retinex图像增强算法的去雾技术】

续&#xff1a;【MATLAB-基于直方图优化的图像去雾技术】 【MATLAB-Retinex图像增强算法的去雾技术】 1 原图2 MATLAB实现代码3 结果图示 参考书籍&#xff1a;计算机视觉与深度学习实战:以MATLAB、Python为工具&#xff0c; 主编&#xff1a;刘衍琦, 詹福宇&#xff0c; 王德建…

C++入门篇(3)---引用

1.引用 你有没有被人起过外号?比如身边的朋友,喊他的时候不会叫他的全名,像我很好的朋友,我一般都喜欢叫他"阿威",而不会去称呼全名.我叫他"阿威",他还是他没有什么问题. 这里新登场的引用不是新定义一个变量&#xff0c;而是给已存在变量取了一个别名&am…

学会这招,轻松掌握学校教学质量!

在教育领域&#xff0c;教育管理者和学校管理员需要确保教学过程的质量和效率。在线巡课系统是一种强大的工具&#xff0c;可以帮助他们实时监测教学过程、教师绩效和学生学习情况。 在线巡课系统结合了技术和教育的最佳实践&#xff0c;为学校提供了数据驱动的决策支持和资源管…

SGPT: GPT Sentence Embeddings for Semantic Search

简介 语义搜索分为两个部分&#xff1a; 1.搜索和query 相关的topk文档。 2.理解文档和query后面隐藏的语义信息&#xff0c;而不是字面含义。 这篇论文提出了SGPT模型&#xff0c;只用decoder-only的transformer来进行语义搜索和sentence向量的提取。 1.SGPT-BE&#xff1a;来…

有什么手机软件能分离人声和音乐?

很多人在制作混剪视频&#xff0c;需要二次创作的时候&#xff0c;就经常会把人声分离、背景音乐伴奏提取出来&#xff0c;然后重新加入自己的创意跟想法。下面就一起来看看如何用手机软件分离人声和音乐的吧&#xff01; 音分轨 一款可以分离人声和背景音乐的手机软件&#x…

我才35岁就要面临“人到中年不服老不行”?大龄测试的救赎之路就在其中!

人说“三十而立”&#xff0c;可对于测试来说是“三十而秃”&#xff0c;除了日常秃头&#xff0c;而立之年的测试们的开始焦虑自己的职业未来。 自2017年华为传出“清理35岁以上员工”以来&#xff0c;各企业关于“劝退 35 岁以上员工”、“招聘限 35 岁以下”的传闻此起彼伏…

前端数据可视化之【Echarts介绍】

目录 &#x1f31f;前言&#x1f31f;丰富的可视化类型&#x1f31f;多种数据格式无需转换直接使用&#x1f31f;移动端优化&#x1f31f;多渲染方案&#xff0c;跨平台使用&#xff01;&#x1f31f;写在最后 &#x1f31f;前言 ECharts开源来自百度商业前端数据可视化团队&a…

数据类型转换

一.应用函数或者方法 1.cast 函数 cast&#xff08;变量 as 数据类型&#xff09; 语义&#xff1a;将变量转为这个类型 2. 变量 ::数据类型 将变量转化为xx类型 3.to_date函数 to_date&#xff08;字符串&#xff0c;format&#xff09; 语义&#xff1a;转换成日期类…

运用精益管理思想提升MES管理系统建设水平

随着制造业的不断发展&#xff0c;MES生产管理系统已经成为了企业生产过程中不可或缺的一部分。而在MES管理系统建设过程中&#xff0c;精益管理的思想也越来越受到重视。本文将探讨如何运用精益管理的思想&#xff0c;提高MES系统的建设水平&#xff0c;以更好地服务于企业的生…

故障诊断实验台 | PT600电机电气故障实验台

很多同学因为实验数据而被困扰&#xff0c;目前数据来源有3方面&#xff0c;公开实验数据集、校企合作项目实际数据、自制实验台数据。 公开实验数据集被用烂了&#xff0c;容易被审稿人质疑&#xff1b; 校企合作项目实际数据缺少故障数据&#xff0c;数据需保密&#xff0c;…

SDK和API区别

B站视频&#xff1a;https://www.bilibili.com/video/BV1dA411K7Ps/?spm_id_from333.337.search-card.all.click&vd_source85701dd8aeeae2aaac0299ea796f19bb 假设你在开发一款移动端兽医诊所应用 Lets say youre developing a mobile app for a veterinarian clinic 想法…

vue3怎么创建项目

1、先安装node.js 自行去node.js官网下载 2、创建一个文件夹 终端打开命令 3、执行命令 vue create 项目名称&#xff08;必须是英文开头&#xff0c;可以英文数字&#xff09; 4、选择Manually select features(自定义配置) 5、选择Router(后面要使用,也可以先不安装&am…

Sanic​——Python函数变成API的神器

今天给大家介绍一个超好用的框架&#xff0c;迅速将Python函数变成API&#xff0c;它就是最近越来越火的异步Web框架Sanic。 1. Sanic简介 Sanic 是 Python3.7 Web 服务器和 Web 框架&#xff0c;旨在提高性能。它允许使用 Python3.5 中添加的async/await语法&#xff0c;这使…

GPT4应用讲解,如何获取ChatGPT账号

参加每人均可获得1个独立可永久使用的ChatGPT账号&#xff0c;并提供不用fanqiang使用的方法。 前言 GPT对于每个科研人员已经成为不可或缺的辅助工具&#xff0c;不同的研究领域和项目具有不同的需求。例如在科研编程、绘图领域&#xff1a; 1、编程建议和示例代码: 无论你…