【Perfetto】Perfetto 零基础入门

news2024/9/23 11:27:25

前因:视频卡顿问题,为了排除是cpu占用性能问题还是音视频编解码问题,接触到了Perfetto,感觉很好玩,学习一下。突然感觉公司挺好的,给新人很多成长空间,一边解bug,一边碰新技术,一边学习,有什么问题大家都挺乐意教我~在这里插入图片描述

概述

Perfetto - 系统分析、应用程序跟踪和跟踪分析

Perfetto 是一个用于性能检测和跟踪分析的生产级开源堆栈。它提供用于记录系统级和应用程序级跟踪的服务和库、本机 + java 堆分析、使用 SQL 分析跟踪的库以及用于可视化和探索多 GB 跟踪的基于 Web 的 UI。
在这里插入图片描述

记录痕迹

Perfetto 的核心是引入了一种新颖的用户空间到用户空间跟踪协议,该协议基于共享内存缓冲区上的直接 protobuf 序列化。跟踪协议既在内部用于内置数据源,又通过跟踪 SDK 和跟踪事件库公开给 C++ 应用程序。
这个新的跟踪协议允许通过可扩展的基于 protobuf 的功能广告和数据源配置机制动态配置跟踪的各个方面(请参阅跟踪配置文档)。不同的数据源可以多路复用到用户定义的缓冲区的不同子集上,从而还允许将任意长的跟踪流式传输到文件系统中。

Android 和 Linux 上的系统范围跟踪

在 Linux 和 Android 上,Perfetto 捆绑了许多数据源,这些数据源能够从不同的系统界面收集详细的性能数据。有关完整集和详细信息,请参阅文档的数据源部分。一些例子:

  • 内核跟踪:Perfetto 与 Linux 的 ftrace 集成,并允许将内核事件(例如调度事件、系统调用)记录到跟踪中。
  • /proc 和 /sys 轮询器,允许对进程范围或系统范围的 cpu 和内存计数器随时间的状态进行采样。
  • 与 Android HAL 模块集成,用于记录电池和能源使用计数器。
  • 本机堆分析:一种低开销堆分析器,用于挂钩 malloc/free/new/delete 并将内存与调用堆栈相关联,基于进程外展开、可配置采样,可附加到已运行的进程。
  • 使用与 Android 运行时紧密集成的进程外分析器捕获 Java 堆转储,该分析器允许获取托管堆保留图的完整快照(类型、字段名称、保留大小和对其他对象的引用),但无需转储完整的堆内容(字符串和位图),从而减少序列化时间和输出文件大小。

在 Android 上,Perfetto 是下一代系统跟踪系统,取代了基于 chromium 的 systrace。基于 ATrace 的仪器仍然得到完全支持。有关更多详细信息,请参阅 Android 开发人员文档。

跟踪 SDK 和用户空间检测

Perfetto Tracing SDK 使 C++ 开发人员能够使用特定于应用程序的跟踪点来丰富跟踪。您可以灵活地定义自己的强类型事件和创建自定义数据源,也可以选择使用更易于使用的跟踪事件库,该库允许使用 TRACE_EVENT 形式的注释轻松创建有时间限制的切片、计数器和时间标记RACE_EVENT("category", "event_name", "x", "str", "y", 42)(“类别”、“事件名称”、“x”、“str”、“y”、42)。
该SDK专为跟踪多进程系统和多线程进程而设计。它基于 ProtoZero,这是一个用于在线程本地共享内存缓冲区上直接写入 protobuf 事件的库。
相同的代码可以在完全进程模式下工作,在专用线程上托管 Perfetto 跟踪服务的实例,也可以在系统模式下工作,通过 UNIX 套接字连接到 Linux/Android 跟踪守护程序,从而允许结合应用程序具有系统范围跟踪事件的特定检测点。
该 SDK 基于可移植的 C++17 代码,并使用主要的 C++ 清理程序(ASan、TSan、MSan、LSan)进行了测试。它不依赖于运行时代码修改或编译器插件。

Chromium追踪

Perfetto 的设计初衷是为了取代 chrome://tracing 基础设施的内部结构。 Chromium 中的跟踪及其内部结构基于所有主要平台(Android、CrOS、Linux、MacOS、Windows)上的 Perfetto 代码库。应用相同的基于服务的系统范围跟踪架构,但在内部使用 Chromium Mojo IPC 系统而不是 Perfetto 自己的 UNIX 套接字。
默认情况下,跟踪在 Chromium 中以进程内模式工作,仅记录 Chromium 进程发出的数据。在 Android 上(以及在 Linux 上,如果禁用 Chromium 沙箱)跟踪可以在进程内+系统混合模式下工作,将 chrome 特定的跟踪事件与 Perfetto 系统事件相结合。

Trace分析

除了跟踪记录功能之外,Perfetto 代码库还包括一个用于导入、解析和查询新旧跟踪格式的专用项目:Trace Processor。
Trace Processor 是一个可移植的 C++17 库,提供面向列的表存储,专为高效地将数小时的跟踪数据保存到内存中而设计,并公开基于流行的 SQLite 查询引擎的 SQL 查询接口。跟踪数据模型成为一组 SQL 表,可以通过极其强大且灵活的方式查询和连接这些表来分析跟踪数据。
除此之外,跟踪处理器还包括一个基于跟踪的指标子系统,该子系统由预烘焙和可扩展的查询组成,可以以 JSON 或 protobuf 消息的形式输出有关跟踪的强类型摘要(例如,不同频率下的 CPU 使用情况)状态,按进程和线程细分)。
基于跟踪的指标允许在性能测试场景或批量分析或大型跟踪语料库中轻松集成跟踪。
跟踪处理器还专为低延迟查询和构建跟踪可视化工具而设计。如今,Perfetto UI 将 Trace Processor 用作 Web Assembly 模块,Android Studio 和 Android GPU Inspector 将其用作本机 C++ 库。

Trace可视化

Perfetto 还提供了一个全新的跟踪可视化工具,用于打开和查询长达数小时的跟踪,可从 ui.perfetto.dev 获取。新的可视化工具利用现代网络平台技术。其基于WebWorkers的多线程设计使UI始终保持响应; Trace Processor 和 SQLite 的分析能力通过 WebAssembly 在浏览器中完全可用。
Perfetto UI 打开一次后即可完全离线工作。使用 UI 打开的跟踪由浏览器在本地处理,不需要任何服务器端交互。
在这里插入图片描述

数据源

内存计数器和事件

Perfetto 允许在 Android 和 Linux 上收集大量内存事件和计数器。这些事件来自内核接口,包括 ftrace 和 /proc 接口,并且有两种类型:轮询计数器和内核在 ftrace 缓冲区中推送的事件。

每个进程轮询计数器

进程统计数据源允许按用户定义的时间间隔轮询/proc/<pid>/status/proc/<pid>/oom_score_adj

UI

在这里插入图片描述

SQL

select c.ts, c.value, t.name as counter_name, p.name as proc_name, p.pid
from counter as c left join process_counter_track as t on c.track_id = t.id
left join process as p using (upid)
where t.name like 'mem.%'
tscounter_namevalue_kbproc_namepid
261187015027350mem.virt1326464com.android.vending28815
261187015027350mem.rss85592com.android.vending28815
261187015027350mem.rss.anon36948com.android.vending28815
261187015027350mem.rss.file46560com.android.vending28815
261187015027350mem.swap6908com.android.vending28815
261187015027350mem.rss.watermark102856com.android.vending28815
261187090251420mem.virt1326464com.android.vending28815

跟踪配置

要每 X 毫秒收集一次进程统计计数器,请在进程统计配置中设置 proc_stats_poll_ms = X。 X 必须大于 100ms,以避免 CPU 使用率过高。有关所收集的特定计数器的详细信息可以在 ProcessStats 参考中找到。

data_sources: {
    config {
        name: "linux.process_stats"
        process_stats_config {
            scan_all_processes_on_start: true
            proc_stats_poll_ms: 1000
        }
    }
}

进程内存事件(ftrace)

RSS_统计
最新版本的 Linux 内核允许在驻留集大小 (RSS) mm 计数器发生变化时报告 ftrace 事件。这与 /proc/pid/status 中可用的计数器与VmRSS 相同。该事件的主要优点是,作为事件驱动的推送事件,它允许检测非常短的内存使用突发,否则使用 /proc 计数器无法检测到这些突发。
数百 MB 的内存使用峰值可能会对 Android 产生巨大的负面影响,即使它们只持续几毫秒,因为它们可能会导致大量低内存杀死以回收内存。
支持此功能的内核功能已在 b3d1411b6 中的 Linux 内核中引入,后来由 e4dcad20 进行了改进。自 Linux v5.5-rc1 起,它们在上游可用。此补丁已向后移植到多个运行 Android 10 (Q) 的 Google Pixel 内核中。

mm_事件
mm_event 是一个 ftrace 事件,用于捕获有关关键内存事件的统计信息(/proc/vmstat 公开的事件的子集)。与 RSS-stat 计数器更新不同,mm 事件的数量非常大,单独跟踪它们是不可行的。 mm_event 只报告跟踪中的周期性直方图,从而显着减少开销。
mm_event 仅在某些运行 Android 10 (Q) 及更高版本的 Google Pixel 内核上可用。
当启用 mm_event 时,会记录以下 mm 事件类型:

  • mem.mm.min_flt:轻微页面错误
  • mem.mm.maj_flt:主要页面错误
  • mem.mm.swp_flt:由交换缓存处理的页面错误
  • mem.mm.read_io:I/O 支持的读取页错误
  • mem.mm…compaction:内存压缩事件
  • mem.mm.reclaim:内存回收事件

对于每种事件类型,事件记录:

  • count:自上一个事件以来该事件发生了多少次。
  • min_lat:自上一个事件以来记录的最小延迟(mm 事件的持续时间)。
  • max_lat:自上次事件以来记录的最高延迟。

ui
ui
SQL
在 SQL 级别,这些事件的导入和公开方式与相应的轮询事件相同。这允许收集两种类型的事件(推送和轮询)并在查询和脚本中统一处理它们。

select c.ts, c.value, t.name as counter_name, p.name as proc_name, p.pid
from counter as c left join process_counter_track as t on c.track_id = t.id
left join process as p using (upid)
where t.name like 'mem.%'
tsvaluecounter_nameproc_namepid
77722786797505518358272mem.rss.anoncom.google.android.apps.safetyhub31386
7772278659953155mem.mm.min_flt.countcom.google.android.apps.safetyhub31386
7772278659953158mem.mm.min_flt.max_latcom.google.android.apps.safetyhub31386
7772278659953154mem.mm.min_flt.avg_latcom.google.android.apps.safetyhub31386
7772278659980233mem.mm.swp_flt.countcom.google.android.apps.safetyhub31386

跟踪配置

data_sources: {
    config {
        name: "linux.ftrace"
        ftrace_config {
            ftrace_events: "kmem/rss_stat"
            ftrace_events: "mm_event/mm_event_record"
        }
    }
}

# This is for getting Thread<>Process associations and full process names.
data_sources: {
    config {
        name: "linux.process_stats"
    }
}

系统范围轮询计数器

该数据源允许定期轮询以下系统数据:

  • /proc/stat
  • /proc/vmstat
  • /proc/meminfo

ui
在这里插入图片描述
可以在跟踪配置中设置跟踪中包含的轮询周期和特定计数器。
SQL

select c.ts, t.name, c.value / 1024 as value_kb from counters as c left join counter_track as t on c.track_id = t.id
tsnamevalue_kb
775177736769834MemAvailable1708956
775177736769834Buffers6208
775177736769834Cached1352960
775177736769834SwapCached8232
775177736769834Active1021108
775177736769834Inactive(file)351496

跟踪配置

data_sources: {
    config {
        name: "linux.sys_stats"
        sys_stats_config {
            meminfo_period_ms: 1000
            meminfo_counters: MEMINFO_MEM_TOTAL
            meminfo_counters: MEMINFO_MEM_FREE
            meminfo_counters: MEMINFO_MEM_AVAILABLE

            vmstat_period_ms: 1000
            vmstat_counters: VMSTAT_NR_FREE_PAGES
            vmstat_counters: VMSTAT_NR_ALLOC_BATCH
            vmstat_counters: VMSTAT_NR_INACTIVE_ANON
            vmstat_counters: VMSTAT_NR_ACTIVE_ANON

            stat_period_ms: 1000
            stat_counters: STAT_CPU_TIMES
            stat_counters: STAT_FORK_COUNT
        }
    }
}

低内存杀死 (LMK)

背景
Android 框架会杀死应用程序和服务,尤其是后台应用程序和服务,以便在需要内存时为新打开的应用程序腾出空间。这些被称为低内存终止 (LMK)。
注意 LMK 并不总是性能问题的症状。经验法则是,严重性(如:用户感知的影响)与被终止的应用程序的状态成正比。应用程序状态可以从 OOM 调整分数的跟踪中得出。
前台应用程序或服务的 LMK 通常是一个大问题。当用户正在使用的应用程序在他们的手指下消失,或者他们最喜欢的音乐播放器服务突然停止播放音乐时,就会发生这种情况。
相反,缓存的应用程序或服务的 LMK 通常与平常一样,并且在大多数情况下,最终用户不会注意到,直到他们尝试返回应用程序,然后应用程序将冷启动。
这两个极端之间的情况更加微妙。如果缓存的应用程序/服务的 LMK 发生在风暴中(即观察到大多数进程在短时间内获得 LMK),则仍然可能存在问题,并且通常是系统某些组件导致内存峰值的症状。
LowMemorykiller 与 lmkd
内核中的 lowmemorykiller 驱动程序
在 Android 中,LMK 过去由临时内核驱动程序(Linux 的 drivers/staging/android/lowmemorykiller.c)处理。该驱动程序用于在跟踪中发出 ftrace 事件 lowmemorykiller/lowmemory_kill。
用户空间 lmkd
Android 9 引入了一个接管 LMK 职责的用户空间本机守护进程:lmkd。并非所有运行 Android 9 的设备都一定会使用 lmkd,因为内核内还是用户空间的最终选择取决于手机制造商、其内核版本和内核配置。
在 Google Pixel 手机上,自运行 Android 9 的 Pixel 2 起就使用了 lmkd 端查杀。
有关详细信息,请参阅 https://source.android.com/devices/tech/perf/lmkd。
lmkd 发出一个名为kill_one_process 的用户空间atrace 计数器事件。
Android LMK 与 Linux oomkiller
Android 上的 LMK,无论是旧的内核内 lowmemkiller 还是较新的 lmkd,都使用与标准 Linux 内核的 OOM Killer 完全不同的机制。 Perfetto 目前仅支持 Android LMK 事件(内核和用户空间),不支持跟踪 Linux 内核 OOM Killer 事件。 Linux OOMKiller 事件理论上在 Android 上仍然可能发生,但发生的可能性极小。如果发生这种情况,则很可能是 BSP 配置错误的症状。
ui
较新的用户空间 LMK 在 UI 中的 lmkd 轨道下以计数器的形式提供。计数器值是被杀死进程的PID(在下面的示例中,PID=27985)。
在这里插入图片描述SQL
较新的 lmkd 和旧版内核驱动的 lowmemorykiller 事件均在导入时进行标准化,并在即时表中的 mem.lmk 键下可用。

SELECT ts, process.name, process.pid 
FROM instant 
JOIN process_track ON instant.track_id = process_track.id
JOIN process USING (upid)
WHERE instant.name = 'mem.lmk'
tsnamepid
442206415875043roid.apps.turbo27324
442206446142234android.process.acore27683
442206462090204com.google.process.gapps28198

跟踪配置

data_sources: {
    config {
        name: "linux.ftrace"
        ftrace_config {
            # For old in-kernel events.
            ftrace_events: "lowmemorykiller/lowmemory_kill"

            # For new userspace lmkds.
            atrace_apps: "lmkd"

            # This is not strictly required but is useful to know the state
            # of the process (FG, cached, ...) before it got killed.
            ftrace_events: "oom/oom_score_adj_update"
        }
    }
}

应用程序状态和 OOM 调整分数

Android 应用程序状态可以从进程 oom_score_adj 的跟踪中推断出来。映射不是 1:1,状态多于 oom_score_adj 值组,并且缓存进程的 oom_score_adj 范围从 900 到 1000。

// This is a process only hosting activities that are not visible,
// so it can be killed without any disruption.
static final int CACHED_APP_MAX_ADJ = 999;
static final int CACHED_APP_MIN_ADJ = 900;

// This is the oom_adj level that we allow to die first. This cannot be equal to
// CACHED_APP_MAX_ADJ unless processes are actively being assigned an oom_score_adj of
// CACHED_APP_MAX_ADJ.
static final int CACHED_APP_LMK_FIRST_ADJ = 950;

// The B list of SERVICE_ADJ -- these are the old and decrepit
// services that aren't as shiny and interesting as the ones in the A list.
static final int SERVICE_B_ADJ = 800;

// This is the process of the previous application that the user was in.
// This process is kept above other things, because it is very common to
// switch back to the previous app.  This is important both for recent
// task switch (toggling between the two top recent apps) as well as normal
// UI flow such as clicking on a URI in the e-mail app to view in the browser,
// and then pressing back to return to e-mail.
static final int PREVIOUS_APP_ADJ = 700;

// This is a process holding the home application -- we want to try
// avoiding killing it, even if it would normally be in the background,
// because the user interacts with it so much.
static final int HOME_APP_ADJ = 600;

// This is a process holding an application service -- killing it will not
// have much of an impact as far as the user is concerned.
static final int SERVICE_ADJ = 500;

// This is a process with a heavy-weight application.  It is in the
// background, but we want to try to avoid killing it.  Value set in
// system/rootdir/init.rc on startup.
static final int HEAVY_WEIGHT_APP_ADJ = 400;

// This is a process currently hosting a backup operation.  Killing it
// is not entirely fatal but is generally a bad idea.
static final int BACKUP_APP_ADJ = 300;

// This is a process bound by the system (or other app) that's more important than services but
// not so perceptible that it affects the user immediately if killed.
static final int PERCEPTIBLE_LOW_APP_ADJ = 250;

// This is a process only hosting components that are perceptible to the
// user, and we really want to avoid killing them, but they are not
// immediately visible. An example is background music playback.
static final int PERCEPTIBLE_APP_ADJ = 200;

// This is a process only hosting activities that are visible to the
// user, so we'd prefer they don't disappear.
static final int VISIBLE_APP_ADJ = 100;

// This is a process that was recently TOP and moved to FGS. Continue to treat it almost
// like a foreground app for a while.
// @see TOP_TO_FGS_GRACE_PERIOD
static final int PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ = 50;

// This is the process running the current foreground app.  We'd really
// rather not kill it!
static final int FOREGROUND_APP_ADJ = 0;

// This is a process that the system or a persistent process has bound to,
// and indicated it is important.
static final int PERSISTENT_SERVICE_ADJ = -700;

// This is a system persistent process, such as telephony.  Definitely
// don't want to kill it, but doing so is not completely fatal.
static final int PERSISTENT_PROC_ADJ = -800;

// The system process runs at the default adjustment.
static final int SYSTEM_ADJ = -900;

// Special code for native processes that are not being managed by the system (so
// don't have an oom adj assigned by the system).
static final int NATIVE_ADJ = -1000;

参考学习:官方文档

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

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

相关文章

【共同缔造 情暖襄阳】五社联动聚关怀 健康义诊助成长

为普及视力保护和口腔健康知识&#xff0c;传播眼科和口腔健康理念&#xff0c;结合2023年襄阳市民政局“共同缔造 情暖襄阳”社会工作服务项目&#xff0c;在襄阳市民政局、襄州区民政局支持下&#xff0c;襄州社工协会联合肖湾街道育红社区链接襄州区爱尔眼科医院、车氏口腔共…

Next.js - Loading UI and Streaming

特殊文件 loading.js 可帮助您使用 React Suspense 创建有意义的加载用户界面。使用此约定&#xff0c;您可以在加载路由段内容时显示来自服务器的即时加载状态。渲染完成后&#xff0c;新的内容会自动切换进来。 即时加载状态 即时加载状态是在导航时立即显示的后备用户界面…

基于SSM的超市管理系统

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…

一、进入sql环境,以及sql的查询、新建、删除、使用

1、进入sql环境 》》》mysql -u root -p 》》》输入密码 2、sql语言的分类 3、注意事项&#xff1a; 4、基础操作&#xff1a; &#xff08;1&#xff09;查询所有数据库&#xff1a; show databases; 运行结果&#xff1a; &#xff08;2&#xff09;创建一个新的数据库&…

精细化降水预测:探索分钟级降水预报API的应用前景

天气对人们的生活和社会运行有着重要影响&#xff0c;尤其是降水预测在决策和安全方面具有关键作用。随着科技的不断发展&#xff0c;分钟级降水预报 API 正崭露头角&#xff0c;为精细化降水预测带来了前所未有的机会和挑战。分钟级降水预报 API 结合了先进的气象技术和实时数…

小黑账单 图表渲染失败 父子组件的生命周期钩子函数不会同步调用

项目场景&#xff1a; 记账本ECharts图表&#xff0c;Vue组件间传递数据 问题描述 图表组件中 mounted钩子中获取的list总是空的&#xff0c;表单组件亦然 PayEcharts.vue <template><div class"payEcharts"><div class"right"><…

Codeforces Round 893 (Div. 2) D.Trees and Segments

原题链接&#xff1a;Problem - D - Codeforces 题面&#xff1a; 大概意思就是让你在翻转01串不超过k次的情况下&#xff0c;使得a*&#xff08;0的最大连续长度&#xff09;&#xff08;1的最大连续长度&#xff09;最大&#xff08;1<a<n&#xff09;。输出n个数&…

团团代码生成器V1.0:一键生成完整的CRUD功能(提供Gitee源码)

前言&#xff1a;在日常开发的中&#xff0c;经常会需要重复写一些基础的增删改查接口&#xff0c;虽说不难&#xff0c;但是会耗费我们一些时间&#xff0c;所以我自己开发了一套纯SpringBoot实现的代码生成器&#xff0c;可以为我们生成单条数据的增删改查&#xff0c;还可以…

快速使用Linux系统中SSH

在Linux系统中&#xff0c;使用SSH代理跳板机是一种有效的方式&#xff0c;可以实现安全连接和访问远程服务器。本文将详细介绍SSH代理跳板机的设置和使用方法。 什么是SSH代理跳板机&#xff1f; SSH代理跳板机是一种在Linux系统中使用SSH协议实现的代理服务器。通过配置相关…

突破瓶颈,提升学习效率的考试培训系统

在现代社会中&#xff0c;教育和培训已经成为人们提升自我能力的重要途径。尤其在考试备考过程中&#xff0c;学习效率的提升显得尤为重要。为了帮助学习者突破学习瓶颈&#xff0c;提高学习效果&#xff0c;我们开发了一款全新的考试培训系统。 我们的系统为学习者提供了全方…

浅谈时序:set_ouput_delay

1、set_output_delay的本质 set_output_delay是对模块output信号在模块外部延迟的约束&#xff0c;本质上EDA工具会根据约束调整内部器件&#xff08;UFF0&#xff09;的类型&#xff0c;摆放位置以及组合逻辑&#xff08;C1&#xff09;以满足约束要求&#xff0c;即EDA工具保…

硬件系统工程师宝典(37)-----常用接口之EMC特性电路设计

各位同学大家好&#xff0c;欢迎继续做客电子工程学习圈&#xff0c;今天我们继续来讲这本书&#xff0c;硬件系统工程师宝典。上篇我们介绍了一些常用总线&#xff0c;如I2C、SPI、I2S、CAN总线&#xff0c;另外分析了常用的逻辑电平TTL和CMOS以及电平之间互连的方式。今天我们…

shell脚本基础————表达式

目录 一、shell类型 类型 查看系统中支持的shell 查看系统默认shell 二、变量 一、组成 一、变量名 声明规范 声明方法 二、变量值 二、类型 一、系统内置变量&#xff08;环境变量&#xff09; 二、自定义变量 数字 字符串 引号的用法 三、位置变量 四、预定义…

机器学习深度学习——transformer(机器翻译的再实现)

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位即将上大四&#xff0c;正专攻机器学习的保研er &#x1f30c;上期文章&#xff1a;机器学习&&深度学习——自注意力和位置编码&#xff08;数学推导代码实现&#xff09; &#x1f4da;订阅专栏&#xff1a;机器…

【Python程序设计】基于Python Flask的上海美食信息与可视化宣传网站项目-附下载方式以及往届优秀论文,原创项目其他均为抄袭

基于Python Flask的上海美食信息与可视化宣传网站 一、项目简介二、开发环境三、项目技术四、功能结构五、运行截图六、功能实现七、数据库设计八、源码获取 一、项目简介 随着大数据和人工智能技术的迅速发展&#xff0c;我们设计并开发了一款基于大数据的上海美食系统。该系…

python使用matplotlib实现折线图的绘制

一、意义 数据可视化可以以简洁的方式呈现出数据&#xff0c;发现众多数据中隐藏的规律和意义。Matplotlib是一个数学绘图库。利用它可以制作简单的图表&#xff08;散点图、折线图&#xff09;。然后&#xff0c;将基于漫步概念生成一个更有趣的数据集–根据一系列随机决策生成…

Android学习--JNI

文章目录 JNI(Java Native Interface)NDK(Native Development Kit)一、创建一个JNI项目1.创建项目2.C文件字段说明1. Extern “C”2. JNIEXPORTh和JNICALL3. JNI接口命名规则4. JNIEnv5. jclass和jobject6. 数据类型7.JNI函数签名信息 二、JNI实现1.简单实现2.静态注册3.动态注…

Tomcat 一次请求的生命周期

在使用 Tomcat 的时候&#xff0c;我们只需要在 Servlet 实现类中写我们的业务逻辑代码即可&#xff0c;不需要管 Socket 连接、协议处理要怎么实现&#xff0c;因为这部分作为不经常变动的部分&#xff0c;被封装到了 Tomcat 中&#xff0c;程序员只需要引入 Tomcat 中即可&am…

DNNGP、DeepGS 和 DLGWAS模型构成对比

一、DNNGP DNNGP 是基于深度卷积神经网络&#xff0c;这个结构包括一个输入层&#xff0c;三个卷积层&#xff0c;一个批标准化层&#xff0c;两个dropout层&#xff0c;一个平坦化层&#xff0c;一个 dense层。 dropout层&#xff1a;在神经网络中,dropout层是一个非常有效的正…

拿捏--->打印爱心(小心机表白)

文章目录 题目描述算法思路代码示例思路一思路二 题目描述 利用java语言编写算法在控制台打印爱心算法 算法思路代码示例 思路一 打印心形主要分为上下两部分&#xff0c;如图&#xff1a; 下边主要是一个倒立三角形&#xff0c;容易打印。 上边可以分为左右两部分&#…