主函数main解析和sat类头文件分析
- 一、简介
- 二、入口函数main.cc剖析
- 三、SAT压力测试对象接口和数据结构
- 总结
一、简介
stressapptest(简称SAT)是一种用于在Linux系统上测试系统稳定性和可靠性的工具,通过产生CPU、内存、磁盘等各种负载来测试系统的稳定性。
本文主要剖析入口函数main()
的流程,以及stressapptest的核心类Sat
的头文件定义。从简单开始,一步步分析各个功能模块。
二、入口函数main.cc剖析
main.cc的代码块如下,主打一个简洁。通过注释的方式剖析大致流程。
#include "sattypes.h"
#include "sat.h"
// 入口函数。
int main(int argc, char **argv) {
// Sat是stressapptest的核心类,通过SatFactory返回创建的对象指针。
Sat *sat = SatFactory();
if (sat == NULL) {
logprintf(0, "Process Error: failed to allocate Sat object\n");
return 255;
}
// 创建sat对象后,必须先解析命令行参数
if (!sat->ParseArgs(argc, argv)) {
logprintf(0, "Process Error: Sat::ParseArgs() failed\n");
sat->bad_status();
} else if (!sat->Initialize()) {// 接着进行相关的初始化
logprintf(0, "Process Error: Sat::Initialize() failed\n");
sat->bad_status();
} else if (!sat->Run()) {// 初始化完成后即可运行压力测试
logprintf(0, "Process Error: Sat::Run() failed\n");
sat->bad_status();
}
// 测试完成后通过这个打印结果
sat->PrintResults();
// 进行一些清理工作
if (!sat->Cleanup()) {
logprintf(0, "Process Error: Sat::Cleanup() failed\n");
sat->bad_status();
}
// 检查Sat的状态,以便返回给终端方便用户了解状态
int retval;
if (sat->status() != 0) {
logprintf(0, "Process Error: Fatal issue encountered. See above logs for "
"details.\n");
retval = 1;
} else if (sat->errors() != 0) {
retval = 1;
} else {
retval = 0;
}
// 释放Sat类的内存
delete sat;
return retval;
}
执行流程图:
SatFactory()
的实现在sat_factory.cc
中,声明在sat.h
里。非常的简单,就是new
一个对象,然后返回。
#include "sat.h" // NOLINT
Sat *SatFactory() {
return new Sat();
}
三、SAT压力测试对象接口和数据结构
这是一个为系统级压力测试和分析而设计的综合压力测试类。这里先了解功能函数接口,实现细节后面再分析。
class Sat
代码的简单分析:
- 代码定义了一个名为Sat的类,其中包含各种成员函数和数据成员。
- 有一个构造函数Sat()、一个析构函数~Sat()和几个成员函数来解析参数、初始化、运行测试、打印结果和清理。
- 类还包含获取和返回空页和满页的函数、访问器函数和操作错误注入的函数。
- 包含初始化、线程管理、分析和报告函数。
- 数据成员用来保存配置参数、控制标志、内存和测试配置、资源和结果。
- 代码使用了各种c++特性,如enmu类型、vector 和 map。
- 利用多线程使用pthreads,并包含特定的方法不同类型的压力测试,如内存,文件IO,网络IO,磁盘IO, CPU压力,和缓存一致性测试。
- 类定义并使用多个队列结构进行页面管理,它同时使用单锁和细锁队列实现。
- 包含各种不允许的复制和赋值操作。
// sat.h : sat stress test object interface and data structures
#ifndef STRESSAPPTEST_SAT_H_
#define STRESSAPPTEST_SAT_H_
#include <signal.h>
#include <map>
#include <string>
#include <vector>
// This file must work with autoconf on its public version,
// so these includes are correct.
#include "finelock_queue.h"
#include "queue.h"
#include "sattypes.h"
#include "worker.h"
#include "os.h"
// SAT stress test class.
class Sat {
public:
// Enum for page queue implementation switch.
// 用于页面队列的单锁和细锁模式切换。SAT_ONELOCK和SAT_FINELOCK有不同的实现方式。
enum PageQueueType { SAT_ONELOCK, SAT_FINELOCK };
Sat();
virtual ~Sat();
// Read configuration from arguments. Called first.
// 从命令行参数中读取配置参数,这个必须在所有的操作前调用。
bool ParseArgs(int argc, char **argv);
virtual bool CheckGoogleSpecificArgs(int argc, char **argv, int *i);
// Initialize data structures, subclasses, and resources,
// based on command line args.
// Called after ParseArgs().
// 根据命令行参数初始化数据结构、子类和资源。在ParseArgs()之后调用。
bool Initialize();
// Execute the test. Initialize() and ParseArgs() must be called first.
// This must be called from a single-threaded program.
// 执行测试。Initialize()和ParseArgs()必须先调用;而且不能被多线程或多次调用。
bool Run();
// Pretty print result summary.
// Called after Run().
// Return value is success or failure of the SAT run, *not* of this function!
// 打印结果概括。
bool PrintResults();
// Pretty print version info.
// 打印版本信息
bool PrintVersion();
// Pretty print help.
// 打印帮助信息
virtual void PrintHelp();
// Clean up allocations and resources.
// Called last.
// 清理分配和资源。最后才调用。
bool Cleanup();
// Abort Run(). Only for use by Run()-installed signal handlers.
// 中止运行。仅供Run()使用,而且安装了信号处理才能使用。
void Break() { user_break_ = true; }
// Fetch and return empty and full pages into the empty and full pools.
bool GetValid(struct page_entry *pe); // 获取任何有效的page
bool PutValid(struct page_entry *pe); // 放置有效page,
bool GetEmpty(struct page_entry *pe); // 获取带有任何tag的空page
bool PutEmpty(struct page_entry *pe); // 放置带有任何tag的空page
bool GetValid(struct page_entry *pe, int32 tag); // 获取任何有效的page,并且指定tag
bool GetEmpty(struct page_entry *pe, int32 tag); // 获取指定tag的空page
// Accessor functions.
// 一些获取成员变量值的函数。
int verbosity() const { return verbosity_; }
int logfile() const { return logfile_; }
int page_length() const { return page_length_; }
int disk_pages() const { return disk_pages_; }
int strict() const { return strict_; }
int tag_mode() const { return tag_mode_; }
int status() const { return statuscount_; }
void bad_status() { statuscount_++; }
int errors() const { return errorcount_; }
int warm() const { return warm_; }
bool stop_on_error() const { return stop_on_error_; }
bool use_affinity() const { return use_affinity_; }
int32 region_mask() const { return region_mask_; }
// Semi-accessor to find the "nth" region to avoid replicated bit searching..
// 查找“第n”区域以避免重复bit位搜索。
int32 region_find(int32 num) const {
for (int i = 0; i < 32; i++) {
if ((1 << i) & region_mask_) {
if (num == 0)
return i;
num--;
}
}
return 0;
}
// Causes false errors for unittesting.
// Setting to "true" causes errors to be injected.
// 造成单元测试错误。设置为“true”会导致注入错误。
void set_error_injection(bool errors) { error_injection_ = errors; }
bool error_injection() const { return error_injection_; }
protected:
// Opens log file for writing. Returns 0 on failure.
// 打开并初始化log文件
bool InitializeLogfile();
// Checks for supported environment. Returns 0 on failure.
// 检查环境是否已知并且可以安全运行。
bool CheckEnvironment();
// Allocates size_ bytes of test memory.
// 分配要在其上运行测试的内存
bool AllocateMemory();
// Initializes datapattern reference structures.
// 设置对data pattern的访问
bool InitializePatterns();
// Initializes test memory with datapatterns.
// 初始化页面列表,并用datapatterns填充页面。
bool InitializePages();
// Start up worker threads
// 启动SAT的任务线程.
virtual void InitializeThreads();
// Spawn worker threads.
// 生成工作线程。
void SpawnThreads();
// Reap worker threads.
// 通知并获得工作线程
void JoinThreads();
// Run bandwidth and error analysis.
// 处理工作线程数据获取带宽信息和错误结果。可以在这里添加更多的方法。
virtual void RunAnalysis();
// Delete worker threads.
// 删除已使用的工作线程对象。
void DeleteThreads();
// Return the number of cpus in the system.
// 返回机器中实际存在的cpu数量。
int CpuCount();
// Return the worst-case (largest) cache line size of the system.
// 返回机器中实际存在的各级缓存的最坏情况(最大)缓存行大小。
int CacheLineSize();
// Read int values from kernel file system e.g. sysfs
// 从内核文件系统(例如sysfs)中读取int值
int ReadInt(const char *filename, int *value);
// Collect error counts from threads.
// 获取所有线程的总错误计数。
int64 GetTotalErrorCount();
// Command line arguments.
// 命令行参数字符串
string cmdline_;
// Memory and test configuration.
// 内存和测试配置信息
int runtime_seconds_; // Seconds to run.运行的时间(秒)
int page_length_; // Length of each memory block.每个内存块的长度
int64 pages_; // Number of memory blocks.内存块的数量
int64 size_; // Size of memory tested, in bytes.测试内存的大小,以字节为单位
int64 size_mb_; // Size of memory tested, in MB.测试内存的大小,以MB为单位
int64 reserve_mb_; // Reserve at least this amount of memory
// for the system, in MB.为系统预留至少多少的内存量,单位是MB。
int64 min_hugepages_mbytes_; // Minimum hugepages size.最小的大页面大小
int64 freepages_; // How many invalid pages we need.需要多少无效页面。
int disk_pages_; // Number of pages per temp file.每个临时文件的页数。
uint64 paddr_base_; // Physical address base.物理基地址
uint64 channel_hash_; // Mask of address bits XORed for channel.地址位的掩码为通道xor。
int channel_width_; // Channel width in bits.以bit为单位的channel位宽。
vector< vector<string> > channels_; // Memory module names per channel.每个channel的内存模块名称。
// Control flags.
volatile sig_atomic_t user_break_; // User has signalled early exit. Used as
// a boolean.发出提前退出信号。
int verbosity_; // How much to print.打印的数量级
int print_delay_; // Chatty update frequency.打印频率或间隔时间
int strict_; // Check results per transaction.检查每个事务的结果。
int warm_; // FPU warms CPU while copying.
int address_mode_; // 32 or 64 bit binary.地址的bit数
bool stop_on_error_; // Exit immendiately on any error.一旦出现错误,立即退出。
bool findfiles_; // Autodetect tempfile locations.自动检测临时文件位置。
bool error_injection_; // Simulate errors, for unittests. 模拟错误,用于memory的单元测试。
bool crazy_error_injection_; // Simulate lots of errors.模拟大量错误。
uint64 max_errorcount_; // Number of errors before forced exit.允许的最大错误数,当错误数达到这个设定值将强制退出程序
int run_on_anything_; // Ignore unknown machine ereor.忽略未知机器
bool use_logfile_; // Log to a file.确定要不要向文件中写日志。
char logfilename_[255]; // Name of file to log to.日志文件的路径
int logfile_; // File handle to log to.日志文件的文件句柄。
bool log_timestamps_; // Whether to add timestamps to log lines.是否向日志行添加时间戳。
// Disk thread options.
int read_block_size_; // Size of block to read from disk.要从磁盘读取的块的大小。
int write_block_size_; // Size of block to write to disk.写入磁盘的块大小。
int64 segment_size_; // Size of segment to split disk into.要将磁盘分割成的段大小。
int cache_size_; // Size of disk cache.磁盘缓存大小。
int blocks_per_segment_; // Number of blocks to test per segment.每个段要测试的块数。
int read_threshold_; // Maximum time (in us) a read should take
// before warning of a slow read.在发出慢读警告之前的最长读时间(单位为us)。
int write_threshold_; // Maximum time (in us) a write should
// take before warning of a slow write.在发出慢写警告之前的最长读时间(单位为us)。
int non_destructive_; // Whether to use non-destructive mode for
// the disk test. 无损检测方式进行硬盘测试的标志。
// Generic Options.
int monitor_mode_; // Switch for monitor-only mode SAT.
// This switch trumps most of the other
// argument, as SAT will only run error
// polling threads.
int tag_mode_; // Do tagging of memory and strict
// checking for misplaced cachelines.
bool do_page_map_; // Should we print a list of used pages?
unsigned char *page_bitmap_; // Store bitmap of physical pages seen.
uint64 page_bitmap_size_; // Length of physical memory represented.
// Cpu Cache Coherency Options.
bool cc_test_; // Flag to decide whether to start the
// cache coherency threads.
int cc_cacheline_count_; // Number of cache line size structures.
int cc_cacheline_size_; // Size of a cache line.
int cc_inc_count_; // Number of times to increment the shared
// cache lines structure members.
// Cpu Frequency Options.
bool cpu_freq_test_; // Flag to decide whether to start the
// cpu frequency thread.
int cpu_freq_threshold_; // The MHz threshold which will cause
// the test to fail.
int cpu_freq_round_; // Round the computed frequency to this
// value.
// Thread control.
int file_threads_; // Threads of file IO.
int net_threads_; // Threads of network IO.
int listen_threads_; // Threads for network IO to connect.
int memory_threads_; // Threads of memcpy.
int invert_threads_; // Threads of invert.
int fill_threads_; // Threads of memset.
int check_threads_; // Threads of strcmp.
int cpu_stress_threads_; // Threads of CPU stress workload.
int disk_threads_; // Threads of disk test.
int random_threads_; // Number of random disk threads.
int total_threads_; // Total threads used.
bool error_poll_; // Poll for system errors.
// Resources.
cc_cacheline_data *cc_cacheline_data_; // The cache line sized datastructure
// used by the ccache threads
// (in worker.h).
vector<string> filename_; // Filenames for file IO.
vector<string> ipaddrs_; // Addresses for network IO.
vector<string> diskfilename_; // Filename for disk IO device.
// Block table for IO device.
vector<DiskBlockTable*> blocktables_;
bool use_affinity_; // Should stressapptest set cpu affinity?
int32 region_mask_; // Bitmask of available NUMA regions.
int32 region_count_; // Count of available NUMA regions.
int32 region_[32]; // Pagecount per region.
int region_mode_; // What to do with NUMA hints?
static const int kLocalNuma = 1; // Target local memory.
static const int kRemoteNuma = 2; // Target remote memory.
// Results.
int64 errorcount_; // Total hardware incidents seen.
int statuscount_; // Total test errors seen.
// Thread type constants and types
enum ThreadType {
kMemoryType = 0,
kFileIOType = 1,
kNetIOType = 2,
kNetSlaveType = 3,
kCheckType = 4,
kInvertType = 5,
kDiskType = 6,
kRandomDiskType = 7,
kCPUType = 8,
kErrorType = 9,
kCCType = 10,
kCPUFreqType = 11,
};
// Helper functions.
virtual void AcquireWorkerLock();
virtual void ReleaseWorkerLock();
pthread_mutex_t worker_lock_; // Lock access to the worker thread structure.
typedef vector<WorkerThread*> WorkerVector;
typedef map<int, WorkerVector*> WorkerMap;
// Contains all worker threads.
WorkerMap workers_map_;
// Delay between power spikes.
time_t pause_delay_;
// The duration of each pause (for power spikes).
time_t pause_duration_;
// For the workers we pause and resume to create power spikes.
WorkerStatus power_spike_status_;
// For the workers we never pause.
WorkerStatus continuous_status_;
class OsLayer *os_; // Os abstraction: put hacks here.
class PatternList *patternlist_; // Access to global data patterns.
// RunAnalysis methods
void AnalysisAllStats(); // Summary of all runs.
void MemoryStats();
void FileStats();
void NetStats();
void CheckStats();
void InvertStats();
void DiskStats();
void QueueStats();
// Physical page use reporting.
void AddrMapInit();
void AddrMapUpdate(struct page_entry *pe);
void AddrMapPrint();
// additional memory data from google-specific tests.
// google专用的内存统计方法和选项。
virtual void GoogleMemoryStats(float *memcopy_data,
float *memcopy_bandwidth);
virtual void GoogleOsOptions(std::map<std::string, std::string> *options);
// Page queues, only one of (valid_+empty_) or (finelock_q_) will be used
// at a time. A commandline switch controls which queue implementation will
// be used.
class PageEntryQueue *valid_; // Page queue structure, valid pages.
class PageEntryQueue *empty_; // Page queue structure, free pages.
class FineLockPEQueue *finelock_q_; // Page queue with fine-grain locks
Sat::PageQueueType pe_q_implementation_; // Queue implementation switch
DISALLOW_COPY_AND_ASSIGN(Sat);
};
Sat *SatFactory();
#endif // STRESSAPPTEST_SAT_H_
类结构图:
总结
深入剖析了主函数main.cc。主函数的解析包括各个部分的功能和调用关系,以及参数解析和初始化过程。接着,文章详细分析了SAT压力测试对象的接口和数据结构。通过对SAT类头文件的分析,介绍了SAT类中定义的各种方法和成员变量,以及对应的功能和用途。在这些剖析过程中,读者可以深入了解stressapptest程序的内部结构和实现细节,有助于进一步理解该程序的运行机制和性能压力测试的实现原理。