rocksdb源码——性能诊断
该文前三部份介绍 statistics、perf context和iostat context和thread status相关内容。最后介绍ThreadLocalPtr实现的原理。
0. 性能诊断类型
statistics:所有线程的所有操作的count/time的累加。
perf context和iostat context: 单个操作(比如get和put)的count/time。
thread status: 用于监视线程的运行时状态
1. statistics
开销:
增加5%-10%
头文件:
include/rocksdb/statistics.h
monitoring/statistics.h
使用方法:
Options options;
options.statistics = rocksdb::CreateDBStatistics();
可选统计级别:
- kExceptDetailedTimers: 除去mutex等待和压缩的计时
- kExceptTimeForMutex: 除去mutex等待的计时
- kAll: 所有
数据统计类型:
ticker:类型是64位无符号整型。用于度量counters (e.g. “rocksdb.block.cache.hit”), cumulative bytes (e.g. “rocksdb.bytes.written”) 或者 time (e.g. “rocksdb.l0.slowdown.micros”)。
histogram:统计数据的统计分布,包括最大值、最小值、平均值、中位数、标准差。
统计函数的接口:
MeasureTime:函数名有歧义。实际上是把value记录到histogram中。
RecordTick:累加ticker。
获取结果的接口:
Statistics::getTickerCount:指定ticker type获得count。
Statistics::histogramData:指定Histograms type,返回一个HistogramData结构体,成员是统计值,包括最大值、最小值、平均值、中位数、标准差。
Statistics::getHistogramString:指定Histograms type,返回直方图可读的字符串。
Statistics::ToString():返回可读的字符串,包括所有的ticker和histogram。
1.1 statistics实现
1.1.1 函数与成员变量
实现了StatisticsImpl类,继承了Statistics的接口。
主要接口:
- getTickerCount
- histogramData
- getHistogramString
- getAndResetTickerCount
- recordTick
- measureTime
- ToString
成员变量:
- TickerInfo tickers_[INTERNAL_TICKER_ENUM_MAX];
- HistogramInfo histograms_[INTERNAL_HISTOGRAM_ENUM_MAX];
这里的TickerInfo和HistogramInfo类型的数据结构是相似的:一个线程局部的counter或者time;加上一个非线程局部的统计值用来累加counter或者time。
TickerInfo类型包含两个参数:
- ThreadLocalPtr类型(真实类型ThreadTickerInfo)的thread_value,包含:
- 整型类型的value
- 指向merged_sum的指针
- 整型类型的merged_sum
HistogreamInfo类型包含两个参数:
- ThreadLocalPtr类型(真实类型ThreadHistogramInfo)的thread_value,包含:
- HistogramImpl类型的value
- 指向merged_hist的指针
- 指向merge_lock的指针
- HistogramImpl类型的merged_hist
- Mutex类型的merge_lock
merged_sum和merged_hist初始化时都是空的,而且当且仅当线程退出时,才调用mergeThreadValue函数将TickerInfo和HistogreamInfo中的线程局部变量累加到merged_sum和merged_hist。这个实现与ThreadLocalPtr
密切相关。
1.1.2 关键函数实现
getTickerCount:
- 用处:指定ticker type获得count
- 实现思路:遍历对应的ticker type的TickerInfo所有线程的线程局部变量的值,累加得到thread_local_sum,再加上当前merged_sum得到最终结果。
- 加锁情况:首先加StatisticsImpl::aggregated_lock锁;调用TickInfo里的ThreadLocalPtr的Fold函数会再加一个保护ThreadData的链表的锁。
histogramData/getHistogramString:
- 实现思路:遍历对应的Histograms type的HistogramInfo所有线程的线程局部变量的值,累加得到类型为HistogramImpl的res_hist,再加上当前merged_hist得到最终结果。histogramData将结果转化成HistogramData的结构体。而getHistogramString将结果转化成可读的string。
- 加锁情况:首先加StatisticsImpl::merge_lock锁;调用HistogramInfo里的ThreadLocalPtr的Fold函数会再加一个保护ThreadData的链表的锁。
ToString:
- 用处:返回可读的字符串,包括所有的ticker和histogram。
- 实现思路:依次对TickerInfo数组调用getTickerCount,打印结果;依次对HistogramInfo数组调用histogramData,打印结果。
2. perf context和iostat context
头文件
include/rocksdb/perf_level.h
include/rocksdb/perf_context.h
include/rocksdb/iostats_context.h
使用方法:
rocksdb::SetPerfLevel(rocksdb::PerfLevel::kEnableTimeExceptForMutex);
rocksdb::perf_context.Reset();
rocksdb::iostats_context.Reset();
... // run your query
rocksdb::SetPerfLevel(rocksdb::PerfLevel::kDisable);
可选统计级别:
- kDisable: 关闭统计
- kEnableCount: 统计count
- kEnableTimeExceptForMutex: 统计count和与mutex无关的time
- kEnableTime: 统计count和time
统计变量:
extern __thread PerfContext perf_context;
extern __thread IOStatsContext iostats_context;
计数函数(宏):
#define PERF_COUNTER_ADD(metric, value) \
perf_context.metric += value;
#define IOSTATS_ADD(metric, value) \ (iostats_context.metric += value)
通过简单调用上述两个宏即可在对应的counter统计值上累加。
而计数相对复杂一点点,使用了一个PerfStepTimer类,实现了start、measure、stop三个函数,类在析构时调用stop函数。
perf context计时宏:
- PERF_TIMER_GUARD(metric):实例化一个PerfStepTimer变量,将perf_context对应的metric指针写到PerfStepTimer中。调用start函数。
- PERF_CONDITIONAL_TIMER_FOR_MUTEX_GUARD(metric, condition) :增加一个开始调用函数的条件。
- PERF_TIMER_START(metric):调用start函数。
- PERF_TIMER_MEASURE(metric):调用measure函数,将计时累加perf_context的metric中,重置start时间。
- PERF_TIMER_STOP(metric) :调用measure函数,将计时累加perf_context的metric中
iostat context计时宏:
- IOSTATS_TIMER_GUARD(metric):实例化一个PerfStepTimer变量,将iostats_context对应的metric指针写到PerfStepTimer中。调用start函数。
3. thread status
参考文档:
docs/_posts/2015-10-27-getthreadlist.markdown
头文件:
include/rocksdb/env.h
include/rocksdb/thread_status.h
util/thread_operation.h
monitoring/thread_status_updater.h
monitoring/thread_status_util.h
使用方法:
将该线程的统计加入ThreadStatusUpdater:
调用ThreadStatusUtil::RegisterThread将该线程的统计从ThreadStatusUpdater删除:
ThreadStatusUtil::UnregisterThread其他修改thread status的函数:
见monitoring/thread_status_util.h通过调用env的GetThreadList()函数可以获得当前后台线程的状态,状态的状态值存放于一个vector中。将其中的内容展现出来,类似于下图:
第一列是统计的一些参数。第二列和第三列分别是对应的两个线程的统计值。
3.1 实现
关键类:
- ThreadStatusUpdater:
存储了各自后台线程的状态和所有后台线程状态的指针。 - ThreadStatusUtil:
该类只有静态变量和静态方法。
源码注释推荐通过该类的方法去更新ThreadStatusUpdater中的状态。
他们之间的关系如下:
{{thread status.png(uploading...)}}
番外: 4. ThreadLocalPtr实现
StatisticsImpl类使用了ThreadLocalPtr的原因:
使用__thread关键字修饰的变量,能做到线程间的隔离,但是并不能做到实例间的隔离。举个例子:
class A{
static __thread int a_;
};
A a1, a2;
虽然不同的线程里,a_
是线程局部的。在同一个线程里这两者使用的是却是同一个a_
。
而使用ThreadLocalPtr能使得线程局部变量既做到线程间隔离,又做到实例间隔离。
如何做到线程间隔离,也能做到实例间隔离?
线程间隔离:
ThreadLocalPtr之间共享一个线程局部变量tls_,tls_是指向ThreadData类型的指针。不同的线程通过不同的tls_地址,指向的是不同的ThreadData。实例间隔离:
ThreadData使用vector存放不同实例之间的value。在ThreadLocalPtr实例化时会获得一个id,id标示它的值存放在vector的位置。这个id能够区分开不同实例对应的不同的线程局部变量。
基本原理如下:
线程的tls初始值为空。在第一次使用时,通过new实例化ThreadData,并且根据id,对ThreadData中的vector进行resize。
ThreadData的数据实际存放在堆上,ThreadLocalPtr如何管理ThreadData的数据?
线程退出:
利用pthread_key的机制,设置线程退出函数OnThreadExit,在线程退出时删除对应的ThreadData。ThreadLocalPtr的实例生命周期结束:
在所有ThreadData的vector中删除对应id的数据,回收id。
rocksdb源码——性能诊断的更多相关文章
- 【性能为王】从PHP源码剖析array_keys和array_unique
之前在[译]更快的方式实现PHP数组去重这篇文章里讨论了使用array_flip后再调用array_keys函数替换直接调用array_unique函数实现数组去重性能较好.由于原文没有给出源码分析和 ...
- 修改Flume-NG的hdfs sink解析时间戳源码大幅提高写入性能
Flume-NG中的hdfs sink的路径名(对应参数"hdfs.path",不允许为空)以及文件前缀(对应参数"hdfs.filePrefix")支持正则解 ...
- lesson8:AtomicInteger源码解析及性能分析
AtomicInteger等对象出现的目的主要是为了解决在多线程环境下变量计数的问题,例如常用的i++,i--操作,它们不是线程安全的,AtomicInteger引入后,就不必在进行i++和i--操作 ...
- 性能秒杀log4net的NLogger日志组件(附测试代码与NLogger源码)
NLogger特性: 一:不依赖于第三方插件和支持.net2.0 二:支持多线程高并发 三:读写双缓冲对列 四:自定义日志缓冲大小 五:支持即时触发刷盘机制 六:先按日期再按文件大小滚动Rolling ...
- [Spark性能调优] 源码补充 : Spark 2.1.X 中 Unified 和 Static MemoryManager
本课主题 Static MemoryManager 的源码鉴赏 Unified MemoryManager 的源码鉴赏 引言 从源码的角度了解 Spark 内存管理是怎么设计的,从而知道应该配置那个参 ...
- Android布局性能优化—从源码角度看ViewStub延迟加载技术
在项目中,难免会遇到这种需求,在程序运行时需要动态根据条件来决定显示哪个View或某个布局,最通常的想法就是把需要动态显示的View都先写在布局中,然后把它们的可见性设为View.GONE,最后在代码 ...
- Java开源生鲜电商平台-性能优化以及服务器优化的设计与架构(源码可下载)
Java开源生鲜电商平台-性能优化以及服务器优化的设计与架构(源码可下载) 说明:Java开源生鲜电商平台-性能优化以及服务器优化的设计与架构,我采用以下三种维度来讲解 1. 代码层面. 2. 数 ...
- IdentityServer4源码颁发token分析及性能优化
IdentityServer4源码地址 IdentityModel源码地址 以下的流程用ResourceOwnerPassword类型获取token作为介绍 分两种获取形式说明 token请求地址为默 ...
- 大数据学习--day14(String--StringBuffer--StringBuilder 源码分析、性能比较)
String--StringBuffer--StringBuilder 源码分析.性能比较 站在优秀博客的肩上看问题:https://www.cnblogs.com/dolphin0520/p/377 ...
随机推荐
- OpenCV从入门到放弃(五):像素!
一.概念 1.图像本质上面是由数值组成的矩阵.矩阵中的一个元素相应一个像素. 2.对于灰度图像(黑白图像),像素是8位无符号数(CV_8U).0表示黑色,255表示白色.对于彩色图像,是用三原色数据合 ...
- [Yarn] Use Yarn to Create an Alternative Import Name of an Installed Library
In this lesson we'll show how to use yarn to alias the names of same npm libraries but install diffe ...
- C++基础学习教程(七)----类编写及类的两个特性解析--->多态&继承
类引入 到眼下为止我们所写的自己定义类型都是keywordstruct,从如今起我们将採用class方式定义类,这样的方式对于学习过其它高级语言包含脚本(Such as Python)的人来说再熟悉只 ...
- [TypeScript] Understand lookup types in TypeScript
Lookup types, introduced in TypeScript 2.1, allow us to dynamically create types based on the proper ...
- 一起talk C栗子吧(第八十三回:C语言实例--进程间通信概述)
各位看官们,大家好,前二回中咱们说的是进程停止的样例,这一回咱们说的样例是:进程间通信.闲话休提,言归正转.让我们一起talk C栗子吧! 看官们.每一个进程都拥有自己的资源,假设不同进程之间须要共享 ...
- Android 应用中十大常见 UX 错误 分类: H1_ANDROID 2013-09-21 13:59 404人阅读 评论(0) 收藏
转载自:http://www.apkbus.com/android-5661-1.html 摘要: Android 开发者关系团队每天都会试用无数的 App 或者受到无数的开发者发来的请求评测的 Ap ...
- 【41.43%】【codeforces 560C】Gerald's Hexagon
time limit per test2 seconds memory limit per test256 megabytes inputstandard input outputstandard o ...
- iframe父页面与子页面的交互
iframe子页面调用父页面的变量.js方法.元素(非跨域): window.parent.varName; //获取父页面js全局变量 window.parent.fnName; //获取父页面js ...
- javax.servlet.WriteListener
http://www.programcreek.com/java-api-examples/index.php?api=javax.servlet.WriteListener
- [Grid Layout] Specify a grid gutter size with grid-gap
It’s beautifully straightforward to add a gutter to our grid layout. Let’s apply one with grid-gap.