Linux 性能调优必备:perf 使用指南
perf 是源码源码优化 Linux 内核源码树内嵌的性能剖析工具。
它运用事件采样原理,调优以性能事件为核心,源码源码优化2017小程序源码支持对处理器和操作系统性能指标的调优剖析。通常用于查找性能瓶颈和定位热点代码。源码源码优化
本文目录包括:
安装 perf
在大多数 Linux 发行版中,调优perf 工具包含在linux-tools 包中。源码源码优化使用包管理器安装,调优如 Debian 系统上的源码源码优化:
在 Red Hat/CentOS 系统上:
基本使用
列出所有可用的性能事件,包括硬件事件和软件事件。调优
使用perf record 记录目标程序的源码源码优化性能数据。
例如:-g 表示记录调用栈,调优-a 表示对所有 CPU 进行采样,-F 表示每秒采样 次,sleep 6 是要分析的程序。
这会生成 perf.data 文件,包含采集的性能数据。
可以指定要分析的事件类型,如 CPU 时钟周期、缓存命中等。
支持跟踪点,一种在内核中预定义的事件,用于跟踪系统调用等。
(常用的)可选参数
每个参数的使用取决于具体需求。例如,使用-a 参数对整个系统进行性能分析;使用-p 或 -t 分析特定进程或线程;-g 对理解程序的函数调用关系非常重要。
实际使用中,先使用perf record ./your_program 进行简单性能记录,再尝试添加不同参数。
分析性能数据
使用perf report 分析记录的数据。
可以用-i 指定要分析的性能数据。
这将展示一个交互式报告,可使用键盘导航查看不同视图。
使用示例
以下是一个简单的 C++ 程序示例,创建一个 std::vector 并使用 push_back 和 emplace_back 方法添加元素,以比较这两种方法在性能上的差异。
ComplexObject 类有一个构造函数,接受一个整数参数并存储它。构造函数和析构函数都会输出一条消息,cc支付源码以便看到对象的创建和销毁。创建 万个这样的对象,并比较 push_back 和 emplace_back 的性能。
要编译和运行这个程序,需要一个支持 C++ 或更高版本的编译器。使用以下命令:
这将编译程序并运行生成的 vector_test 可执行文件。
使用 perf 分析程序性能。
确保有权限运行 perf。
使用以下命令记录性能数据:
perf record ./vector_test
运行结束后,使用perf report 查看性能报告。
在报告中,可以看到不同函数的调用次数、执行时间等信息。
进入交互界面后,
其他功能
perf 提供了许多其他工具,如 perf stat(显示程序运行时的性能统计信息),perf top(实时显示性能热点),perf annotate(显示源代码级别的性能分析)等。
使用perf top 查看实时性能数据。
对特定函数或代码行进行性能分析。
统计特定事件(如缓存未命中)的发生次数。
高级用法注意事项可能遇到的问题
问题1
根据错误信息,系统上的 perf_event_paranoid 设置为 4,意味着除了具有特定 Linux 能力的进程外,所有用户都无法使用性能监控和可观察性操作。
要解决这个问题,有几个选项:
使用以下命令临时更改设置:
sudo sysctl -w kernel.perf_event_paranoid=-1
或者,如果你只想允许使用用户空间事件:
sudo sysctl -w kernel.perf_event_paranoid=0
请注意,降低 perf_event_paranoid 的值可能会增加系统安全风险。
问题2
错误信息表明,由于 /proc/sys/kernel/kptr_restrict 设置的值,内核符号(kallsyms)和模块的地址映射被限制了。
当你尝试使用perf record 收集性能数据时,如果无法解析内核样本,将无法得到有关内核函数和模块的详细信息。
为了解决这个问题,你可以采取以下步骤:
你可以临时更改 kptr_restrict 的值,以允许 perf 工具访问内核指针。
这将设置 kptr_restrict 为 0,允许所有用户访问内核指针。
如果你的目录模板源码系统上有 vmlinux 文件,perf 工具可以使用它来解析内核样本。
确保 vmlinux 文件与当前运行的内核版本相匹配。
如果 vmlinux 文件不存在或过时,你可能需要更新它。
降低 kptr_restrict 的值会降低系统的安全性。
一次SQL调优 聊一聊 SQLSERVER 数据页
在一次 SQL 调优的经历中,我意识到深入研究 SQLSERVER 性能优化的首要任务是掌握其存储引擎,特别是核心的数据页。SQLSERVER 的数据管理类似于 Windows 对内存的4k分块,同样将 mdf 文件划分为8k的数据页,以实现高效管理。
要验证这一理论,可以通过 SQLServer 的 dbcc ind 命令,配合 标记,定位到 person 表的数据页。例如,表的记录位于 PagePID= 的数据页,物理位置在 mdf 文件偏移 0n * 0n,即 0x。通过 WinHex,我们确认了这一位置的准确性。
数据页的逻辑关系在内存中由 SQLSERVER 的数据结构承载,DBCC PAGE 命令揭示了内存中的映射范围。尽管内存地址显示习惯上采用大端布局,但可以使用 windbg 的小端布局进行查看。对 SQLSERVER 的源码研究,可以通过硬件断点观察 SQL 请求的执行流程,如查询优化器和执行器等环节。
总的来说,理解数据页的结构和索引布局对于优化 SQL 查询性能至关重要,它能帮助我们减少数据在数据页间的流转,降低逻辑读取,从而提升查询效率。因此,深入研究 SQLSERVER 的数据页是提升性能的关键步骤。
完全体!千字详解:“Java性能调优六大工具”之JConsole工具
在Java性能调优的旅程中,JConsole工具扮演着至关重要的角色。作为JDK的内置神器,它为我们提供了直观且强大的性能监控能力。本文将带你深入了解JConsole的心知天气源码六大功能,带你走进Java应用程序的运行世界。连接与启动
JConsole,隐藏在%JAVA_HOME%/bin的角落里,只需启动它,它就会引导我们连接到本地或远程的Java应用,如图所示。在“新建连接”界面,列出了所有可选的Java进程,轻轻一点,即可与目标程序建立连接。对于远程连接,我们需要在启动Java应用时加入参数,如-Djava.rmi.server.hostname指定IP,-Dcom.sun.management.jmxremote.port指定端口,这样,远程连接就变得轻而易举了。概览与监控
一旦连接,JConsole就像一个透明的窗口,揭示了应用的运行全貌。四张动态折线图实时显示堆内存、线程、类加载和CPU使用情况,如图6.所示,让你一眼洞悉程序的运行状态。内存深度解析
深入到“内存”选项卡,JConsole的细致入微令人惊叹。它不仅追踪堆内存的eden、survivor和老年代,还关注非堆区——永久代的使用。轻轻一点,你可以执行一次Full GC,如图6.所示,洞察内存管理的微妙之处。线程侦探
JConsole的“线程”选项卡是多线程监控的宝地。它展示了活跃线程的总数,单击任何线程,你将看到详细的栈信息。而“检测死锁”按钮,就像X射线,帮助你迅速定位潜在的死锁问题,如图6.所示。web源码保护类加载揭秘
在“类”选项卡中,JConsole揭示了运行时已装载的类和已卸载的类数量,让你对类加载动态了如指掌,如图6.所示。虚拟机视窗
“VM摘要”为你的Java应用提供了全面的运行环境概览,包括虚拟机类型、版本、堆信息,以及JVM参数等,如图6.所示,是深入理解应用的起点。MBean管理大师
MBean选项卡则开启了对系统MBean的管理新世界。你可以查看、设置属性,甚至执行MBean方法。如图6.所示,通过JConsole,你可以动态调整GC输出,让性能调优如丝般顺滑。插件的力量
别忘了,JConsole的潜能远不止于此。自带的JTop插件,如图6.所示,通过CPU占用时间排序,让你快速定位性能瓶颈。此外,你还可以根据兴趣修改JTop源码,扩展其功能。 掌握JConsole,就掌握了Java性能调优的钥匙,让我们在调优的道路上更加游刃有余。现在,就让我们带着这份知识,深入到代码的海洋,探索更高效的运行世界吧!mongodb内核源码实现、性能调优、最佳运维实践系列-表级qps及表级详细时延统计实现原理
针对 MongoDB 内核源码实现中的表级 QPS(查询每秒操作数)及表级详细时延统计实现原理,本文将深入探讨其设计、核心代码实现以及最佳运维实践。作者为 OPPO 文档数据库 MongoDB 负责人,专注于分布式缓存、高性能服务端、数据库、中间件等相关研发工作,持续分享《MongoDB 内核源码设计、性能优化、最佳运维实践》。以下内容将围绕 MongoDB 内核中提供的数据导出及恢复工具(mongodump、mongorestore、mongoexport、mongoimport)、客户端 shell 链接工具(mongo)、IO 测试工具(mongoperf)以及流量 QPS/时延监控统计工具(mongostat、mongotop)进行分析。
Mongostat 和 mongotop 提供的监控统计功能虽然强大,但其功能局限性在于无法实现对表级 QPS 与详细时延的监控。为解决这一问题,MongoDB 实际上提供了内部实现的表级别统计接口。本文将详细解析这些接口的实现原理、核心代码以及如何应用到最佳运维实践中。
### 1. mongostat、mongotop 监控统计信息分析
Mongostat 和 mongotop 工具作为 MongoDB 的官方监控工具,分别提供了集群操作统计与表级别的读写时延统计。接下来,我们将深入探讨这些工具的使用方法、监控项以及功能实现。
#### 1.1 mongostat 监控统计分析
Mongostat 工具能够监控当前集群中各种操作的统计情况,包括增、删、改、查操作,以及 getMore(用于批量拉取数据时的游标操作)和 command(在 mongos 和 mongod 之间的命令处理)。了解 mongostat 帮助参数的详细说明,有助于更深入地掌握其功能。
#### 1.2 mongotop 监控统计分析
mongotop 则专注于对所有表的读写时延进行统计,并按照总耗时排序,直观地输出结果。分析 mongotop 监控输出项各字段的说明,可以帮助运维人员快速定位性能瓶颈。
### 2. 表级详细操作统计及其时延监控统计实现原理与核心代码
在 MongoDB 内核中,对表级别的增、删、改、查、getMore、command 进行了详细的操作统计,并对每种操作的时延进行了记录。每个表都拥有一个 CollectionData 结构,该结构中存储了所有操作统计和时延统计信息。核心代码定义了 UsageMap、CollectionData、UsageData 及 OperationLatencyHistogram 等关键类,以实现表级别的统计功能。
#### 2.1 表级统计实现原理
通过多层次的类结构分层,MongoDB 实现了表级别的详细统计。核心数据结构包括:UsageMap(使用 StringMap 表结构存储所有表名及其对应的表级统计信息)、CollectionData(包含锁统计、详细请求统计、汇总型统计)、以及 OperationLatencyHistogram(实现表级别的操作汇总统计与时延统计)。
#### 2.2 核心代码实现
MongoDB 表级详细统计实现主要集中在 src/mongo/db/stats 目录下的 top.cpp、top.h、operation_latency_histogram.cpp、operation_latency_histogram.h 四个文件中。其中,核心数据结构的代码实现展示了如何通过 UsageMap 结构存储所有表名及其统计信息,CollectionData 结构用于存储锁统计、详细请求统计和汇总型统计,而 OperationLatencyHistogram 类则实现了汇总型统计中的读、写、command 操作及对应时延统计。
### 3. 表级详细统计对外接口
为了便于运维人员使用表级统计信息,MongoDB 提供了对外接口,包括但不限于锁维度及请求类型维度相关统计接口与汇总型表级别统计接口。通过这些接口,运维人员可以执行特定命令获取表级别的锁统计、请求类型统计以及汇总型统计信息。
### 结论
本文通过深入解析 MongoDB 内核中的表级 QPS 及详细时延统计实现原理,详细介绍了核心代码实现以及对外提供的统计接口。了解这些实现细节对于优化数据库性能、进行高效运维具有重要意义。运维人员可以根据本文内容,结合实际应用场景,实施最佳实践,从而提高 MongoDB 的整体性能与稳定性。
线程池调优之动态参数配置
前言线程池的核心参数配置在网上有一大堆的文章介绍,这次结合个人理解写一篇文章记录一下,以便加深印象和后续查阅。线程池配置参数
corePoolSize:线程池核心线程数
maximumPoolSize:线程池最大线程数
keepAliveTime:允许线程空闲时间(对非核心工作线程的回收)
TimeUnit:线程空闲时间单位
workQueue:线程队列(当核心线程数满了,新的任务就会放入这个队列中)
threadFactory:线程工厂(用于创建工作线程,自定义线程工厂可以指定线程名称)
handler:线程池拒绝策略(当线程队列满了且最大线程数也满了,就会执行任务拒绝策略,默认有4种)
allowCoreThreadTimeOut:控制核心工作线程是否需要被回收
常规线程池参数配置-首先提问一个面试题:现有个任务,台服务器,每台机器都是4核,在任务不丢弃情况下,线程池参数该怎么配置最合理呢?
-把这个问题拆分一下,个任务,台机器,那么每台机器就负责个任务(常规轮训负载均衡模式,不考虑其他额外情况),每台机器都是4核,那么就可以设置核心线程数和最大线程数为4,线程队列大小为即可。
-当然也可以把核心和最大线程数设置为5(n+1)个,线程队列大小为,这样是为了防止线程偶尔由于页缺失故障或者其他原因暂停,出多来的一个线程也能确保CPU的调度时钟周期不会被浪费,相当于备用线程。
如果任务是CPU密集型配置:工作线程=cpu核心数+1;
如果任务是IO密集型场景:工作线程=cpu核心数*2;
所以上面例子中就是基于CPU密集型任务配置线程池。而且网上大部分文章描述线程池配置也是基于这两点来分析的。
可惜理想很丰满,现实很骨感。在实际工作场景中,其实没那么容易区分线程中执行的任务是CPU密集还是IO密集,而且服务器上还会有其他应用线程抢占CPU资源,就算还有一些其他的公式计算配置线程池参数,那也是基于理想场景情况下进行配置的,所以上述配置更多的还是应用于面试中。
动态配置线程池参数上述中既然不能一次定义适配所有场景的线程池参数,那么如果可以根据不同业务场景动态配置线程池参数,通过人工干预介入来适配大部分场景也行的
正好在JDK的自定义线程池ThreadPoolExecutor里,提供了动态扩展线程池核心参数的方法
可以在运行期间的线程池使用此方法可以覆盖原来配置的值:
ThreadPoolExecutor线程池提供了5种配置参数可供动态更新:核心线程池,最大线程数,线程工厂,线程空闲时间,拒绝策略。这里主要讨论的是核心线程池和最大线程池两种参数配置:
/****@Author:ZRH*@Date://:*/@Slf4jpublicclassExecutorTest{ publicstaticvoidmain(String[]args)throwsException{ finalThreadPoolExecutorthreadPoolExecutor=newThreadPoolExecutor(2,3,,TimeUnit.SECONDS,newLinkedBlockingQueue<>(7),newThreadPoolExecutor.DiscardPolicy());for(inti=0;i<;i++){ threadPoolExecutor.execute(()->{ try{ logExecutorInfo(threadPoolExecutor);Thread.sleep();}catch(InterruptedExceptione){ }});}logExecutorInfo(threadPoolExecutor);threadPoolExecutor.setCorePoolSize(5);threadPoolExecutor.setMaximumPoolSize(5);logExecutorInfo(threadPoolExecutor);Thread.currentThread().join();}privatestaticvoidlogExecutorInfo(ThreadPoolExecutorexecutor){ log.info("线程池核心线程数="+executor.getCorePoolSize()+",线程池最大线程数="+executor.getMaximumPoolSize()+",线程池队列剩余任务="+executor.getQueue().size()+",线程池活跃线程数="+executor.getActiveCount()+",线程池任务完成数"+executor.getCompletedTaskCount());}}看执行结果:刚开始线程池里核心线程数2个、最大线程数3个、剩下7放队列。活跃的线程也只有3个。
然后更改核心线程和最大线程数为5后,线程池里对应的核心线程数和最大线程数也增加至5个,活跃的工作线程也是5个。说明更改配置成功。
注:更新线程池参数时,核心线程数不能超过最大线程数配置。否则配置最后不会生效。
publicstaticvoidmain(String[]args)throwsException{ finalThreadPoolExecutorthreadPoolExecutor=newThreadPoolExecutor(2,3,,TimeUnit.SECONDS,newLinkedBlockingQueue<>(7),newThreadPoolExecutor.DiscardPolicy());for(inti=0;i<;i++){ threadPoolExecutor.execute(()->{ try{ logExecutorInfo(threadPoolExecutor);Thread.sleep();}catch(InterruptedExceptione){ }});}logExecutorInfo(threadPoolExecutor);threadPoolExecutor.setCorePoolSize(5);//threadPoolExecutor.setMaximumPoolSize(5);logExecutorInfo(threadPoolExecutor);Thread.currentThread().join();}上图中把核心线程数更新为5,最大线程数不改动任为3。最后看执行结果,最终的活跃线程还是3个,说明配置没有生效,具体源码在ThreadPoolExecutor类的getTask()方法里,感兴趣的同学可以去看一下...
动态更新线程队列ThreadPoolExecutor线程池并没有动态配置线程池队列大小的方法
想自己操作一下也是很简单的,只需要自定义实现一个队列,可以直接把LinkedBlockingQueue复制一份,并把capacity参数设定为可更改
publicstaticvoidmain(String[]args)throwsException{ finalThreadPoolExecutorthreadPoolExecutor=newThreadPoolExecutor(2,3,,TimeUnit.SECONDS,newCustomLinkedBlockingQueue<>(7),newThreadPoolExecutor.DiscardPolicy());for(inti=0;i<;i++){ threadPoolExecutor.execute(()->{ try{ logExecutorInfo(threadPoolExecutor);Thread.sleep();}catch(InterruptedExceptione){ }});}logExecutorInfo(threadPoolExecutor);threadPoolExecutor.setCorePoolSize(5);threadPoolExecutor.setMaximumPoolSize(5);CustomLinkedBlockingQueuequeue=(CustomLinkedBlockingQueue)threadPoolExecutor.getQueue();queue.setCapacity();for(inti=0;i<;i++){ threadPoolExecutor.execute(()->{ try{ logExecutorInfo(threadPoolExecutor);Thread.sleep();}catch(InterruptedExceptione){ }});}Thread.currentThread().join();}看结果,后续添加的任务会放入队列中,并且队列大小也超过第一次设置大小,说明配置成功
最后参考:Java线程池实现原理及其在美团业务中的实践
虚心学习,共同进步-_-
Python深度学习系列网格搜索神经网络超参数:丢弃率dropout(案例+源码)
本文探讨了深度学习领域中网格搜索神经网络超参数的技术,以丢弃率dropout为例进行案例分析并提供源码。
一、引言
在深度学习模型训练时,选择合适的超参数至关重要。常见的超参数调整方法包括手动调优、网格搜索、随机搜索以及自动调参算法。本文着重介绍网格搜索方法,特别关注如何通过调整dropout率以实现模型正则化、降低过拟合风险,从而提升模型泛化能力。
二、实现过程
1. 准备数据与数据划分
数据的准备与划分是训练模型的基础步骤,确保数据集的合理分配对于后续模型性能至关重要。
2. 创建模型
构建模型时,需定义一个网格架构函数create_model,并确保其参数与KerasClassifier对象的参数一致。在定义分类器时,自定义表示丢弃率的参数dropout_rate,并设置默认值为0.2。
3. 定义网格搜索参数
定义一个字典param_grid,包含超参数名称及其可选值。在本案例中,需确保参数名称与KerasClassifier对象中的参数一致。
4. 进行参数搜索
利用sklearn库中的GridSearchCV类进行参数搜索,将模型与网格参数传入,系统将自动执行网格搜索,尝试不同组合。
5. 总结搜索结果
经过网格搜索后,确定了丢弃率的最优值为0.2,这一结果有效优化了模型性能。
三、总结
本文通过案例分析与源码分享,展示了如何利用网格搜索方法优化神经网络模型的超参数,特别是通过调整dropout率以实现模型的正则化与泛化能力提升。在实际应用中,通过合理选择超参数,可以显著改善模型性能,降低过拟合风险。
2024-12-24 00:54
2024-12-24 00:40
2024-12-23 23:55
2024-12-23 23:50
2024-12-23 23:28