Android应用开发(37)LTPO帧率测试基于Surfaceview(暂存)

news2025/1/16 0:05:46

Android应用开发学习笔记——目录索引

 参考android官网:

  1. Frame rate  |  Android media  |  Android Developers
  2. 多重刷新率  |  Android 开源项目  |  Android Open Source Project
  3. WindowManager.LayoutParams  |  Android Developers

目前市面上旗舰手机基本都是普及了LTPO屏幕,为了验证LTPO屏幕的DDIC(display driver ID)的硬件刷帧行为(屏幕硬件的刷新可以通过屏幕的AVDD电流信号/屏幕硬件内部的Vsync信号检测),写一个可以指定app出图帧率的测试程序(基于Android应用开发(35)SufaceView基本用法 与 Android应用开发(36)帧率API测试基于Surfaceview)。

一、获取屏幕支持的所有帧率

应用程序获取设备实际支持的显示刷新率,可以通过调用 Display.getSupportedModes()获取,Mode.mRefreshRate就是帧率信息,以便安全调用setFrameRate()

// Display.java
Display.Mode[] mSupportedModes = getWindowManager().getDefaultDisplay().getSupportedModes();
for (Display.Mode mode : mSupportedModes) {
   Log.d(TAG, "getSupportedModes: " + mode.toString());
   Log.d(TAG, "getRefreshRate: " + mode.getRefreshRate());
}
 
 
public static final class Mode implements Parcelable {
        public static final Mode[] EMPTY_ARRAY = new Mode[0];
 
        private final int mModeId;
        private final int mWidth;
        private final int mHeight;
        private final float mRefreshRate;
        @NonNull
        private final float[] mAlternativeRefreshRates;
...
}

二、APP设置帧率的API

setFrameRate( )

Android 公开了多种访问和控制界面的方法,因此有多个版本的setFrameRate()API。每个版本的 API 都采用相同的参数,并且与其他版本的工作方式相同:

  • Surface.setFrameRate()
  • SurfaceControl.Transaction.setFrameRate()
  • ANativeWindow_setFrameRate()
  • ASurfaceTransaction_setFrameRate()

要查看调用 是否会导致setFrameRate()显示刷新率发生更改,请通过调用 DisplayManager.registerDisplayListener() 或 来注册显示更改通知AChoreographer_registerRefreshRateCallback()。 

调用时setFrameRate(),最好传递精确的帧速率,而不是四舍五入为整数。例如,当渲染以 29.97Hz 录制的视频时,请传入 29.97,而不是四舍五入到 30。

对于视频应用程序,传递给的兼容性参数setFrameRate()应设置为Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE,以向 Android 平台提供额外提示,即该应用程序将使用pulldown来适应不匹配的显示刷新率(这将导致抖动)。

surface.setFrameRate(contentFrameRate,

    FRAME_RATE_COMPATIBILITY_FIXED_SOURCE,

    CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS);

// 调用setFrameRate()时,最好传入准确的帧速率,而不是四舍五入为整数。例如,在渲染以 29.97Hz 录制的视频时,传入 29.97 而不是四舍五入为 30。

参数:Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE仅适用于视频应用程序。对于非视频用途,请使用FRAME_RATE_COMPATIBILITY_DEFAULT.

选择改变帧速率的策略:

google强烈建议应用在显示电影等长时间运行的视频时调用setFrameRate(fps , FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ALWAYS) ,其中 fps 是视频的帧速率。

当您预计视频播放持续几分钟或更短时间时,我们强烈建议您不要调用应用程序setFrameRate()。CHANGE_FRAME_RATE_ALWAYS

SurfaceControl.Transaction.setFrameRate()

参数和1是一样的

setFrameRate( ) 与 PreferredDisplayModeId

WindowManager.LayoutParams.preferredDisplayModeId 是应用程序向平台指示其帧速率的另一种方式。某些应用程序只想更改显示刷新率,而不是更改其他显示模式设置,例如显示分辨率。一般情况下,使用 setFrameRate()代替preferredDisplayModeId. 该setFrameRate() 功能更易于使用,因为应用程序不需要搜索显示模式列表来查找具有特定帧速率的模式。

setFrameRate()在存在多个以不同帧速率运行的表面的情况下,使平台有更多机会选择兼容的帧速率。例如,考虑这样一种场景:两个应用程序在 Pixel 4 上以分屏模式运行,其中一个应用程序正在播放 24Hz 视频,另一个应用程序向用户显示可滚动列表。设备支持两种显示刷新率:60Hz 和 90Hz。使用preferredDisplayModeIdAPI,视频表面被迫选择 60Hz 或 90Hz。通过使用 setFrameRate()24Hz 调用,视频表面为平台提供了有关源视频帧速率的更多信息,使平台能够选择 90Hz 的显示刷新率,在此场景中这比 60Hz 更好。

然而,有些场景preferredDisplayModeId应该使用 来代替setFrameRate(),例如:

  • 如果应用程序想要更改分辨率或其他显示模式设置,请使用preferredDisplayModeId
  • setFrameRate()如果模式切换是轻量级的并且不太可能被用户注意到,则平台只会响应调用来切换显示模式 。如果应用程序更喜欢切换显示刷新率,即使它需要大量模式切换(例如,在 Android TV 设备上),请使用preferredDisplayModeId.
  • 无法处理以应用程序帧速率倍数运行的显示的应用程序(这需要在每个帧上设置演示时间戳)应使用preferredDisplayModeId.

WindowManager.LayoutParams params = getWindow().getAttributes();

params.preferredDisplayModeId = mSupportedModes[position].getModeId();

Log.d(TAG, "setRefreshRate:" + mSupportedModes[position].getRefreshRate());

getWindow().setAttributes(params);

setFrameRate( ) 与 PreferredRefreshRate

WindowManager.LayoutParams#preferredRefreshRate 在应用程序窗口上设置首选帧速率,并且该速率适用于窗口内的所有表面。无论设备支持的刷新率如何,应用程序都应指定其首选帧速率,类似于 setFrameRate(),以便为调度程序更好地提示应用程序的预期帧速率。

preferredRefreshRate对于使用 的表面将被忽略setFrameRate()。如果可能的话一般使用setFrameRate()

PreferredRefreshRate 与 PreferredDisplayModeId

如果应用程序只想更改首选刷新率,则最好使用 preferredRefreshRate,而不是preferredDisplayModeId

避免过于频繁地调用setFrameRate( )

尽管该setFrameRate()调用在性能方面的成本并不高,但应用程序应避免setFrameRate()每帧调用或每秒调用多次。调用setFrameRate()可能会导致显示刷新率发生变化,从而可能导致转换期间出现帧丢失。您应该提前计算出正确的帧速率并调用 setFrameRate()一次。

用于游戏或其他非视频应用程序

尽管视频是该 API 的主要用例setFrameRate(),但它也可用于其他应用程序。例如,打算不高于 60Hz 运行的游戏(以减少功耗并实现更长的游戏时间)可以调用 Surface.setFrameRate(60, Surface.FRAME_RATE_COMPATIBILITY_DEFAULT). 这样,默认情况下以 90Hz 运行的设备将在游戏处于活动状态时以 60Hz 运行,这将避免游戏以 60Hz 运行而显示器以 90Hz 运行时出现的抖动。

二、代码分析

1、surface.setFrameRate()

// Surface.java (frameworks\base\core\java\android\view)
    /**
     * Sets the intended frame rate for this surface.
     *
     * <p>On devices that are capable of running the display at different refresh rates,
     * the system may choose a display refresh rate to better match this surface's frame
     * rate. Usage of this API won't introduce frame rate throttling, or affect other
     * aspects of the application's frame production pipeline. However, because the system
     * may change the display refresh rate, calls to this function may result in changes
     * to Choreographer callback timings, and changes to the time interval at which the
     * system releases buffers back to the application.</p>
     *
     * <p>Note that this only has an effect for surfaces presented on the display. If this
     * surface is consumed by something other than the system compositor, e.g. a media
     * codec, this call has no effect.</p>
     *
     * @param frameRate The intended frame rate of this surface, in frames per second. 0
     * is a special value that indicates the app will accept the system's choice for the
     * display frame rate, which is the default behavior if this function isn't
     * called. The <code>frameRate</code> parameter does <em>not</em> need to be a valid refresh
     * rate for this device's display - e.g., it's fine to pass 30fps to a device that can only run
     * the display at 60fps.
     *
     * @param compatibility The frame rate compatibility of this surface. The
     * compatibility value may influence the system's choice of display frame rate.
     * This parameter is ignored when <code>frameRate</code> is 0.
     *
     * @param changeFrameRateStrategy Whether display refresh rate transitions caused by this
     * surface should be seamless. A seamless transition is one that doesn't have any visual
     * interruptions, such as a black screen for a second or two. This parameter is ignored when
     * <code>frameRate</code> is 0.
     *
     * @throws IllegalArgumentException If <code>frameRate</code>, <code>compatibility</code> or
     * <code>changeFrameRateStrategy</code> are invalid.
     */
    public void setFrameRate(@FloatRange(from = 0.0) float frameRate,
            @FrameRateCompatibility int compatibility,
            @ChangeFrameRateStrategy int changeFrameRateStrategy) {
        synchronized (mLock) {
            checkNotReleasedLocked();
            int error = nativeSetFrameRate(mNativeObject, frameRate, compatibility,
                    changeFrameRateStrategy);
            if (error == -EINVAL) {
                throw new IllegalArgumentException("Invalid argument to Surface.setFrameRate()");
            } else if (error != 0) {
                throw new RuntimeException("Failed to set frame rate on Surface");
            }
        }
    }

    /**
     * Sets the intended frame rate for this surface. Any switching of refresh rates is
     * most probably going to be seamless.
     *
     * @see #setFrameRate(float, int, int)
     */
    public void setFrameRate(
            @FloatRange(from = 0.0) float frameRate, @FrameRateCompatibility int compatibility) {
        setFrameRate(frameRate, compatibility, CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS);
    }
// android_view_Surface.cpp (frameworks\base\core\jni)
static jint nativeSetFrameRate(JNIEnv* env, jclass clazz, jlong nativeObject, jfloat frameRate,
                               jint compatibility, jint changeFrameRateStrategy) {
    Surface* surface = reinterpret_cast<Surface*>(nativeObject);
    ANativeWindow* anw = static_cast<ANativeWindow*>(surface);
    // Our compatibility is a Surface.FRAME_RATE_COMPATIBILITY_* value, and
    // NATIVE_WINDOW_SET_FRAME_RATE takes an
    // ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* value. The values are identical
    // though, so no need to explicitly convert.
    return anw->perform(surface, NATIVE_WINDOW_SET_FRAME_RATE, double(frameRate), compatibility,
                        int(changeFrameRateStrategy));
}
// Surface.cpp (frameworks\native\libs\gui)
int Surface::perform(int operation, va_list args)
{
    case NATIVE_WINDOW_SET_FRAME_RATE:
        res = dispatchSetFrameRate(args);
        break;
 
int Surface::dispatchSetFrameRate(va_list args) {
    float frameRate = static_cast<float>(va_arg(args, double));
    int8_t compatibility = static_cast<int8_t>(va_arg(args, int));
    int8_t changeFrameRateStrategy = static_cast<int8_t>(va_arg(args, int));
    return setFrameRate(frameRate, compatibility, changeFrameRateStrategy);
}
 
status_t Surface::setFrameRate(float frameRate, int8_t compatibility,
                               int8_t changeFrameRateStrategy) {
    ATRACE_CALL();
    ALOGV("Surface::setFrameRate");
 
    if (!ValidateFrameRate(frameRate, compatibility, changeFrameRateStrategy,
                           "Surface::setFrameRate")) {
        return BAD_VALUE;
    }
 
    return composerService()->setFrameRate(mGraphicBufferProducer, frameRate, compatibility,
                                           changeFrameRateStrategy);
}
// ISurfaceComposer.cpp (frameworks\native\libs\gui)
    status_t setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate,
                          int8_t compatibility, int8_t changeFrameRateStrategy) override {
 ..
        status_t err = remote()->transact(BnSurfaceComposer::SET_FRAME_RATE, data, &reply);
    }
status_t BnSurfaceComposer::onTransact(
...setFrameRate(surface, frameRate, compatibility, changeFrameRateStrategy);
 
// SurfaceFlinger.cpp (miui\frameworks\native\services\surfaceflinger)
status_t SurfaceFlinger::setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate,
                                      int8_t compatibility, int8_t changeFrameRateStrategy)
    layer->setFrameRate(Layer::FrameRate(Fps{frameRate}, Layer::FrameRate::convertCompatibility(compatibility), strategy))

1、surfaceflinger layerinfo保存app传递下来的结构体是FrameRate
    struct FrameRate {
        using Seamlessness = scheduler::Seamlessness;
        Fps rate;
        FrameRateCompatibility type;
        Seamlessness seamlessness;
}
 
enum class FrameRateCompatibility {
    Default, // 图层没有指定任何具体的处理策略
    Exact, // 图层需要准确的帧速率。如视频类
    ExactOrMultiple, // 图层需要精确的帧速率(或它的倍数)来呈现内容。 任何其他值都将导致下拉。
    NoVote, // 图层对刷新率没有任何要求,不考虑显示刷新率
};
 
// The seamlessness requirement of a Layer.
enum class Seamlessness {
    // Indicates a requirement for a seamless mode switch.
    OnlySeamless,
    // Indicates that both seamless and seamed mode switches are allowed.
    SeamedAndSeamless,
    // Indicates no preference for seamlessness. For such layers the system will
    // prefer seamless switches, but also non-seamless switches to the group of the
    // default config are allowed.
    Default
};

2、SurfaceControl.Transaction.setFrameRate()

// SurfaceControl.java (frameworks\base\core\java\android\view)
        /**
         * Sets the intended frame rate for this surface. Any switching of refresh rates is
         * most probably going to be seamless.
         *
         * @see #setFrameRate(SurfaceControl, float, int, int)
         */
        @NonNull
        public Transaction setFrameRate(@NonNull SurfaceControl sc,
                @FloatRange(from = 0.0) float frameRate,
                @Surface.FrameRateCompatibility int compatibility) {
            return setFrameRate(sc, frameRate, compatibility,
                    Surface.CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS);
        }
// android_view_SurfaceControl.cpp (frameworks\base\core\jni)
static void nativeSetFrameRate(JNIEnv* env, jclass clazz, jlong transactionObj, jlong nativeObject,
                               jfloat frameRate, jint compatibility, jint changeFrameRateStrategy) {
    auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
 
    const auto ctrl = reinterpret_cast<SurfaceControl*>(nativeObject);
    // Our compatibility is a Surface.FRAME_RATE_COMPATIBILITY_* value, and
    // Transaction::setFrameRate() takes an ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* value. The
    // values are identical though, so no need to convert anything.
    transaction->setFrameRate(ctrl, frameRate, static_cast<int8_t>(compatibility),
                              static_cast<int8_t>(changeFrameRateStrategy));
}
// SurfaceComposerClient.cpp (frameworks\native\libs\gui)
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameRate(
        const sp<SurfaceControl>& sc, float frameRate, int8_t compatibility,
        int8_t changeFrameRateStrategy) {
    layer_state_t* s = getLayerState(sc);
    if (!s) {
        mStatus = BAD_INDEX;
        return *this;
    }
    // Allow privileged values as well here, those will be ignored by SF if
    // the caller is not privileged
    if (!ValidateFrameRate(frameRate, compatibility, changeFrameRateStrategy,
                           "Transaction::setFrameRate",
                           /*privileged=*/true)) {
        mStatus = BAD_VALUE;
        return *this;
    }
    s->what |= layer_state_t::eFrameRateChanged;
    s->frameRate = frameRate;
    s->frameRateCompatibility = compatibility;
    s->changeFrameRateStrategy = changeFrameRateStrategy;
    return *this;
}
// SurfaceFlinger.cpp (frameworks\native\services\surfaceflinger)
applyTransactionState
    setClientStateLocked
 
uint32_t SurfaceFlinger::setClientStateLocked(
        const FrameTimelineInfo& frameTimelineInfo, const ComposerState& composerState,
        int64_t desiredPresentTime, bool isAutoTimestamp, int64_t postTime, uint32_t permissions,
        std::unordered_set<ListenerCallbacks, ListenerCallbacksHash>& outListenerCallbacks) {
...
    if (what & layer_state_t::eFrameRateChanged) {
        if (ValidateFrameRate(s.frameRate, s.frameRateCompatibility, s.changeFrameRateStrategy,
                              "SurfaceFlinger::setClientStateLocked", privileged)) {
            const auto compatibility =
                    Layer::FrameRate::convertCompatibility(s.frameRateCompatibility);
            const auto strategy =
                    Layer::FrameRate::convertChangeFrameRateStrategy(s.changeFrameRateStrategy);
 
            if (layer->setFrameRate(Layer::FrameRate(Fps(s.frameRate), compatibility, strategy))) {
                flags |= eTraversalNeeded;
            }
        }
    }

3、preferredDisplayModeId

// RefreshRatePolicy.java (mframeworks\base\services\core\java\com\android\server\wm)
    int getPreferredModeId(WindowState w) {
        // If app is animating, it's not able to control refresh rate because we want the animation
        // to run in default refresh rate.
        if (w.isAnimating(TRANSITION | PARENTS)) {
            return 0;
        }
 
        return w.mAttrs.preferredDisplayModeId;
    }
// DisplayContent.java (frameworks\base\services\core\java\com\android\server\wm)
会保存到   
private static final class ApplySurfaceChangesTransactionState 的preferredModeId
 
    void applySurfaceChangesTransaction() {
        if (!mWmService.mDisplayFrozen) {
            mWmService.mDisplayManagerInternal.setDisplayProperties(mDisplayId,
                    mLastHasContent,
                    mTmpApplySurfaceChangesTransactionState.preferredRefreshRate,
                    mTmpApplySurfaceChangesTransactionState.preferredModeId,
                    mTmpApplySurfaceChangesTransactionState.preferredMinRefreshRate,
                    mTmpApplySurfaceChangesTransactionState.preferredMaxRefreshRate,
                    mTmpApplySurfaceChangesTransactionState.preferMinimalPostProcessing,
                    true /* inTraversal, must call performTraversalInTrans... below */);
        }
// DisplayManagerService.java (frameworks\base\services\core\java\com\android\server\display)
        public void setDisplayProperties(int displayId, boolean hasContent,
                float requestedRefreshRate, int requestedMode, float requestedMinRefreshRate,
                float requestedMaxRefreshRate, boolean requestedMinimalPostProcessing,
                boolean inTraversal) {
            setDisplayPropertiesInternal(displayId, hasContent, requestedRefreshRate,
                    requestedMode, requestedMinRefreshRate, requestedMaxRefreshRate,
                    requestedMinimalPostProcessing, inTraversal);
        }
setDisplayPropertiesInternal
|--> mDisplayModeDirector.getAppRequestObserver().setAppRequest(
                    displayId, requestedModeId, requestedMinRefreshRate, requestedMaxRefreshRate);
 
// DisplayModeDirector.java (frameworks\base\services\core\java\com\android\server\display)
        public void setAppRequest(int displayId, int modeId, float requestedMinRefreshRateRange,
                float requestedMaxRefreshRateRange) {
            synchronized (mLock) {
                setAppRequestedModeLocked(displayId, modeId);
                setAppPreferredRefreshRateRangeLocked(displayId, requestedMinRefreshRateRange,
                        requestedMaxRefreshRateRange);
            }
        }
 
setAppRequest 最后通过:
updateVoteLocked(displayId, Vote.PRIORITY_APP_REQUEST_REFRESH_RATE_RANGE, vote);
还就是最后调用surfaceflinger的:
setDesiredDisplayModeSpecs // surface的标准API接口

三、写一个APP验证API

运行界面介绍

        

 

四、测试程序

完整源码

百度网盘链接:百度网盘 请输入提取码 提取码:test

RefreshRateSurfaceViewTest目录

点此查看Android应用开发学习笔记的完整目录

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

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

相关文章

wangEditor5实现@评论功能

需求描述&#xff1a;在输入框输入后显示用户列表&#xff0c;实现人功能 当前环境&#xff1a;vue3viteelementPluswangEditor5 需要插件&#xff1a;wangeditor/plugin-mention 安装插件&#xff1a;npm i wangeditor/plugin-mention 输入框组件分两部分&#xff1a;1. wa…

【electron】electron安装过慢和打包报错:Unable to load file:

文章目录 一、安装过慢问题:二、打包报错&#xff1a;Unable to load file: 一、安装过慢问题: 一直处于安装过程 【解决】 #修改npm的配置文件 npm config edit#添加配置 electron_mirrorhttps://cdn.npm.taobao.org/dist/electron/二、打包报错&#xff1a;Unable to load…

CAS服务端入门使用实践

CAS服务端入门使用实践 一、前言 1.简介 CAS 是一个企业多语言单点登录解决方案&#xff0c;支持大量附加身份验证协议和功能&#xff0c;满足身份验证和授权需求的综合平台。 2.环境 Windows 10JDK 1.8git version 2.41.0.windows.3Tomcat 9.0.78Maven 3.5.3cas-overlay-…

类与对象(加深)

目录 1.类的6个默认成员函数 2. 构造函数 2.1 概念 2.2 特性 3.析构函数 3.1 概念 3.2 特性 4. 拷贝构造函数 4.1 概念 4.2 特征 5.赋值运算符重载 5.1 运算符重载 5.2 赋值运算符重载 6.const成员 7.取地址及const取地址操作符重载 1.类的6个默认成员函数 如果…

51.C++继承

今天进行了新的学习关于c继承的知识。 目录 1.继承 基类and派生类 访问控制和继承 单继承 多继承 2.同名隐藏 1.继承 在C中&#xff0c;继承是一种面向对象编程的重要特性&#xff0c;用于构建类之间的层次关系。通过继承&#xff0c;一个类可以从另一个类继承其…

QT网络编程之TCP

QT网络编程之TCP TCP 编程需要用到俩个类: QTcpServer 和 QTcpSocket。 #------------------------------------------------- # # Project created by QtCreator 2023-08-

2023-08-12 LeetCode每日一题(合并 K 个升序链表)

2023-08-12每日一题 一、题目编号 23. 合并 K 个升序链表二、题目链接 点击跳转到题目位置 三、题目描述 给你一个链表数组&#xff0c;每个链表都已经按升序排列。 请你将所有链表合并到一个升序链表中&#xff0c;返回合并后的链表。 示例 1&#xff1a; 示例 2&…

String(字符串)

1、String概述 java.lang.String类代表字符串&#xff0c;Java程序中的所有字符串文字&#xff08;例如“abc”&#xff09;都为此类的对象。 1.1、String的注意点 字符串的内容是不会发生改变的&#xff0c;它的对象在创建后不能被更改。 1.2、总结 String是Java定义好的一个类…

LeetCode 34题:在排序数组中查找元素的第一个和最后一个位置

目录 题目 思路 代码 C语言 Python 题目 给你一个按照非递减顺序排列的整数数组 nums&#xff0c;和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。 如果数组中不存在目标值 target&#xff0c;返回 [-1, -1]。 你必须设计并实现时间复杂度为 O(…

取证--理论

资料&#xff1a; 各比赛 Writeup &#xff1a; https://meiyacup.cn/Mo_index_gci_36.html 哔站比赛复盘视频&#xff1a; https://space.bilibili.com/453117423?spm_id_from333.337.search-card.all.click 自动分析取证四部曲 新建案例添加设备自动取证制作报告 取证大…

腾讯云CVM服务器竞价实例是什么?和按量计费有什么区别?

腾讯云服务器CVM计费模式分为包年包月、按量计费和竞价实例&#xff0c;什么是竞价实例&#xff1f;竞价实例和按量付费相类似&#xff0c;优势是价格更划算&#xff0c;缺点是云服务器实例有被自动释放风险&#xff0c;腾讯云服务器网来详细说下什么是竞价实例&#xff1f;以及…

全志T113-S3 Tina-linux --1. 开发环境搭建

1. 硬件环境 1.1 开发板 型号&#xff1a;100ASK_T113-PRO Base V1.1&#xff08;韦东山&#xff09;配置&#xff1a;CPU&#xff1a;T113-S3&#xff0c;RAM&#xff1a;128MB&#xff0c;ROM&#xff1a;128MB T113-S3配置 1.2 上手使用 1.2.1 串口shell 串口shell配置…

MySQL8安装教程 保姆级(Windows))

下载 官网: mysql官网点击Downloads->MySQL Community(GPL) Downloads->MySQL Community Server(或者点击MySQL installer for Windows) Windows下有两种安装方式 在线安装 一般带有 web字样 这个需要联网离线安装 一般没有web字样 安装 下载好之后,版本号可以不一样&…

【积水成渊】9 个CSS 伪元素

大家好&#xff0c;我是csdn的博主&#xff1a;lqj_本人 这是我的个人博客主页&#xff1a; lqj_本人_python人工智能视觉&#xff08;opencv&#xff09;从入门到实战,前端,微信小程序-CSDN博客 最新的uniapp毕业设计专栏也放在下方了&#xff1a; https://blog.csdn.net/lbcy…

预测知识 | 预测技术流程及模型评价

预测知识 | 预测技术流程及模型评价 目录 预测知识 | 预测技术流程及模型评价技术流程模型评价参考资料 技术流程 1&#xff09;模型训练阶段&#xff1a;预测因素和结局&#xff0c;再加上预测模型进行模型拟合&#xff1b; 2&#xff09;预测阶段&#xff1a;将预测因素代入拟…

如何自学(黑客)网络安全

前言&#xff1a; 想自学网络安全&#xff08;黑客技术&#xff09;首先你得了解什么是网络安全&#xff01;什么是黑客&#xff01; 网络安全可以基于攻击和防御视角来分类&#xff0c;我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术&#xff0c;而“蓝队”、“…

前端一键升级 package.json里面的依赖包管理

升级需谨慎 前端一键升级 package.json里面的依赖包管理 安装&#xff1a;npm-check-updates npm i npm-check-updates -g缩写 ncu 在项目根目录里面执行 ncu 如图&#xff1a;

日撸java_day61-62

决策树 package machineLearning.decisiontree;import weka.core.Instance; import weka.core.Instances;import java.io.FileReader; import java.util.Arrays;/*** ClassName: ID3* Package: machineLearning.decisiontree* Description: The ID3 decision tree inductive …

企业服务器数据库遭到malox勒索病毒攻击后如何解决,勒索病毒解密

网络技术的发展不仅为企业带来了更高的效率&#xff0c;还为企业带来信息安全威胁&#xff0c;其中较为常见的就是勒索病毒攻击。近期&#xff0c;我们公司收到很多企业的求助&#xff0c;企业的服务器数据库遭到了malox勒索病毒攻击&#xff0c;导致系统内部的许多重要数据被加…

YOLOv5基础知识入门(5)— 损失函数(IoU、GIoU、DIoU、CIoU和EIoU)

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。使用YOLOv5训练模型阶段&#xff0c;需要用到损失函数。损失函数是用来衡量模型预测值和真实值不一样的程度&#xff0c;极大程度上决定了模型的性能。本节就给大家介绍IoU系列损失函数&#xff0c;希望大家学习之后能够有…