赞
踩
stressapptest是一个用于对计算机系统进行压力测试的工具,它可以模拟多种场景下的CPU、内存、磁盘、网络等资源的高负载情况,用于评估系统的稳定性和性能表现。本系列文章将对stressapptest的源代码进行深入剖析,本篇重点关注其默认参数的设置和参数解析过程,以解析其内部运行机制和实现原理。
随着计算机系统的日益复杂和性能需求的不断提升,系统稳定性和高负载下的性能表现成为了至关重要的考量因素。而stressapptest作为一个优秀的压力测试工具,能够帮助有效地评估硬件设备和系统软件在高负载情况下的表现。因此,深入了解stressapptest的实现细节和参数设置机制,将有助于更好地理解其工作原理,提高对系统性能测试的专业水平。
本系列文章将全面剖析stressapptest的源代码,从默认参数的设置到参数解析的过程,逐步揭示其内部运行机制和设计思路。读者将通过本系列文章深入了解stressapptest的内部工作原理,拓展对系统压力测试工具的理解,为系统性能的评估和优化提供参考和帮助。
接下来的章节将详细讲解stressapptest的默认参数设置和参数解析过程,以及相关的代码解析和分析。同时,我们将结合实际代码,带领读者逐步理解stressapptest的内部机制和实现细节。
stressapptest源代码有一个名为Sat
的类,它的构造函数初始化了该类的各个成员变量的默认值。这些默认值包括运行时间、页面长度、磁盘页面数、大小、保留大小、错误注入标志等等。此外,它还初始化了一些与缓存一致性和CPU频率相关的数据。同时,设置了一些线程相关的默认值和一些其他参数的默认值,如锁、区域掩码等等。最后,它初始化了一些文件读取和写入相关的参数。
源代码:
// Constructor and destructor. Sat::Sat() { // Set defaults, command line might override these. runtime_seconds_ = 20;// 默认运行时间,单位为秒 page_length_ = kSatPageSize;// 设置每个内存块的长度为1024LL*1024LL disk_pages_ = kSatDiskPage;// 设置每个临时文件的页数为8 pages_ = 0; size_mb_ = 0; size_ = size_mb_ * kMegabyte;// 设置默认的测试内存为 0 * (1024LL*1024LL) reserve_mb_ = 0; min_hugepages_mbytes_ = 0; freepages_ = 0; paddr_base_ = 0; channel_hash_ = kCacheLineSize;// 地址位的掩码,64。 channel_width_ = 64; user_break_ = false; verbosity_ = 8; Logger::GlobalLogger()->SetVerbosity(verbosity_);//设置日志打印等级,大于8的等级将被忽略。 print_delay_ = 10; strict_ = 1; warm_ = 0; run_on_anything_ = 0; use_logfile_ = false; logfile_ = 0; log_timestamps_ = true; // Detect 32/64 bit binary. void *pvoid = 0; address_mode_ = sizeof(pvoid) * 8; error_injection_ = false; crazy_error_injection_ = false; max_errorcount_ = 0; // Zero means no early exit. stop_on_error_ = false; error_poll_ = true; findfiles_ = false; do_page_map_ = false; page_bitmap_ = 0; page_bitmap_size_ = 0; // Cache coherency data initialization. cc_test_ = false; // Flag to trigger cc threads. cc_cacheline_count_ = 2; // Two datastructures of cache line size. cc_cacheline_size_ = 0; // Size of a cacheline (0 for auto-detect). cc_inc_count_ = 1000; // Number of times to increment the shared variable. cc_cacheline_data_ = 0; // Cache Line size datastructure. // Cpu frequency data initialization. cpu_freq_test_ = false; // Flag to trigger cpu frequency thread. cpu_freq_threshold_ = 0; // Threshold, in MHz, at which a cpu fails. cpu_freq_round_ = 10; // Round the computed frequency to this value. sat_assert(0 == pthread_mutex_init(&worker_lock_, NULL)); file_threads_ = 0; net_threads_ = 0; listen_threads_ = 0; // Default to autodetect number of cpus, and run that many threads. memory_threads_ = -1; invert_threads_ = 0; fill_threads_ = 8; check_threads_ = 0; cpu_stress_threads_ = 0; disk_threads_ = 0; total_threads_ = 0; use_affinity_ = true; region_mask_ = 0; region_count_ = 0; for (int i = 0; i < 32; i++) { region_[i] = 0; } region_mode_ = 0; errorcount_ = 0; statuscount_ = 0; valid_ = 0; empty_ = 0; finelock_q_ = 0; // Default to use fine-grain lock for better performance. pe_q_implementation_ = SAT_FINELOCK; os_ = 0; patternlist_ = 0; logfilename_[0] = 0; read_block_size_ = 512; write_block_size_ = -1; segment_size_ = -1; cache_size_ = -1; blocks_per_segment_ = -1; read_threshold_ = -1; write_threshold_ = -1; non_destructive_ = 1; monitor_mode_ = 0; tag_mode_ = 0; random_threads_ = 0; pause_delay_ = 600; pause_duration_ = 15; }
相关的参数定义:
// Define handy constants here
static const int kTicksPerSec = 100;
static const int kMegabyte = (1024LL*1024LL);
static const int kSatDiskPageMax = 32;
static const int kSatDiskPage = 8;
static const int kSatPageSize = (1024LL*1024LL);
static const int kCacheLineSize = 64;
static const uint16_t kNetworkPort = 19996;
默认参数可以被命令行参数替换。源代码:
#define ARG_KVALUE(argument, variable, value) \ if (!strcmp(argv[i], argument)) { \ variable = value; \ continue; \ } #define ARG_IVALUE(argument, variable) \ if (!strcmp(argv[i], argument)) { \ i++; \ if (i < argc) \ variable = strtoull(argv[i], NULL, 0); \ continue; \ } #define ARG_SVALUE(argument, variable) \ if (!strcmp(argv[i], argument)) { \ i++; \ if (i < argc) \ snprintf(variable, sizeof(variable), "%s", argv[i]); \ continue; \ } // Configures SAT from command line arguments. // This will call exit() given a request for // self-documentation or unexpected args. bool Sat::ParseArgs(int argc, char **argv) { int i; uint64 filesize = page_length_ * disk_pages_; // Parse each argument. for (i = 1; i < argc; i++) { // Switch to fall back to corase-grain-lock queue. (for benchmarking) ARG_KVALUE("--coarse_grain_lock", pe_q_implementation_, SAT_ONELOCK); // Set number of megabyte to use. ARG_IVALUE("-M", size_mb_); // Specify the amount of megabytes to be reserved for system. ARG_IVALUE("--reserve_memory", reserve_mb_); // Set minimum megabytes of hugepages to require. ARG_IVALUE("-H", min_hugepages_mbytes_); // Set number of seconds to run. ARG_IVALUE("-s", runtime_seconds_); // Set number of memory copy threads. ARG_IVALUE("-m", memory_threads_); // Set number of memory invert threads. ARG_IVALUE("-i", invert_threads_); // Set number of check-only threads. ARG_IVALUE("-c", check_threads_); // Set number of cache line size datastructures. ARG_IVALUE("--cc_inc_count", cc_inc_count_); // Set number of cache line size datastructures ARG_IVALUE("--cc_line_count", cc_cacheline_count_); // Override the detected or assumed cache line size. ARG_IVALUE("--cc_line_size", cc_cacheline_size_); // Flag set when cache coherency tests need to be run ARG_KVALUE("--cc_test", cc_test_, true); // Set when the cpu_frequency test needs to be run ARG_KVALUE("--cpu_freq_test", cpu_freq_test_, true); // Set the threshold in MHz at which the cpu frequency test will fail. ARG_IVALUE("--cpu_freq_threshold", cpu_freq_threshold_); // Set the rounding value for the cpu frequency test. The default is to // round to the nearest 10s value. ARG_IVALUE("--cpu_freq_round", cpu_freq_round_); // Set number of CPU stress threads. ARG_IVALUE("-C", cpu_stress_threads_); // Set logfile name. ARG_SVALUE("-l", logfilename_); // Verbosity level. ARG_IVALUE("-v", verbosity_); // Chatty printout level. ARG_IVALUE("--printsec", print_delay_); // Turn off timestamps logging. ARG_KVALUE("--no_timestamps", log_timestamps_, false); // Set maximum number of errors to collect. Stop running after this many. ARG_IVALUE("--max_errors", max_errorcount_); // Set pattern block size. ARG_IVALUE("-p", page_length_); // Set pattern block size. ARG_IVALUE("--filesize", filesize); // NUMA options. ARG_KVALUE("--no_affinity", use_affinity_, false); ARG_KVALUE("--local_numa", region_mode_, kLocalNuma); ARG_KVALUE("--remote_numa", region_mode_, kRemoteNuma); // Autodetect tempfile locations. ARG_KVALUE("--findfiles", findfiles_, 1); // Inject errors to force miscompare code paths ARG_KVALUE("--force_errors", error_injection_, true); ARG_KVALUE("--force_errors_like_crazy", crazy_error_injection_, true); if (crazy_error_injection_) error_injection_ = true; // Stop immediately on any arror, for debugging HW problems. ARG_KVALUE("--stop_on_errors", stop_on_error_, 1); // Don't use internal error polling, allow external detection. ARG_KVALUE("--no_errors", error_poll_, 0); // Never check data as you go. ARG_KVALUE("-F", strict_, 0); // Warm the cpu as you go. ARG_KVALUE("-W", warm_, 1); // Allow runnign on unknown systems with base unimplemented OsLayer ARG_KVALUE("-A", run_on_anything_, 1); // Size of read blocks for disk test. ARG_IVALUE("--read-block-size", read_block_size_); // Size of write blocks for disk test. ARG_IVALUE("--write-block-size", write_block_size_); // Size of segment for disk test. ARG_IVALUE("--segment-size", segment_size_); // Size of disk cache size for disk test. ARG_IVALUE("--cache-size", cache_size_); // Number of blocks to test per segment. ARG_IVALUE("--blocks-per-segment", blocks_per_segment_); // Maximum time a block read should take before warning. ARG_IVALUE("--read-threshold", read_threshold_); // Maximum time a block write should take before warning. ARG_IVALUE("--write-threshold", write_threshold_); // Do not write anything to disk in the disk test. ARG_KVALUE("--destructive", non_destructive_, 0); // Run SAT in monitor mode. No test load at all. ARG_KVALUE("--monitor_mode", monitor_mode_, true); // Run SAT in address mode. Tag all cachelines by virt addr. ARG_KVALUE("--tag_mode", tag_mode_, true); // Dump range map of tested pages.. ARG_KVALUE("--do_page_map", do_page_map_, true); // Specify the physical address base to test. ARG_IVALUE("--paddr_base", paddr_base_); // Specify the frequency for power spikes. ARG_IVALUE("--pause_delay", pause_delay_); // Specify the duration of each pause (for power spikes). ARG_IVALUE("--pause_duration", pause_duration_); // Disk device names if (!strcmp(argv[i], "-d")) { i++; if (i < argc) { disk_threads_++; diskfilename_.push_back(string(argv[i])); blocktables_.push_back(new DiskBlockTable()); } continue; } // Set number of disk random threads for each disk write thread. ARG_IVALUE("--random-threads", random_threads_); // Set a tempfile to use in a file thread. if (!strcmp(argv[i], "-f")) { i++; if (i < argc) { file_threads_++; filename_.push_back(string(argv[i])); } continue; } // Set a hostname to use in a network thread. if (!strcmp(argv[i], "-n")) { i++; if (i < argc) { net_threads_++; ipaddrs_.push_back(string(argv[i])); } continue; } // Run threads that listen for incoming SAT net connections. ARG_KVALUE("--listen", listen_threads_, 1); if (CheckGoogleSpecificArgs(argc, argv, &i)) { continue; } ARG_IVALUE("--channel_hash", channel_hash_); ARG_IVALUE("--channel_width", channel_width_); if (!strcmp(argv[i], "--memory_channel")) { i++; if (i < argc) { char *channel = argv[i]; channels_.push_back(vector<string>()); while (char* next = strchr(channel, ',')) { channels_.back().push_back(string(channel, next - channel)); channel = next + 1; } channels_.back().push_back(string(channel)); } continue; } // Default: PrintVersion(); PrintHelp(); if (strcmp(argv[i], "-h") && strcmp(argv[i], "--help")) { printf("\n Unknown argument %s\n", argv[i]); bad_status(); exit(1); } // Forget it, we printed the help, just bail. // We don't want to print test status, or any log parser stuff. exit(0); } Logger::GlobalLogger()->SetVerbosity(verbosity_); // Update relevant data members with parsed input. // Translate MB into bytes. size_ = static_cast<int64>(size_mb_) * kMegabyte; // Set logfile flag. if (strcmp(logfilename_, "")) use_logfile_ = true; // Checks valid page length. if (page_length_ && !(page_length_ & (page_length_ - 1)) && (page_length_ > 1023)) { // Prints if we have changed from default. if (page_length_ != kSatPageSize) logprintf(12, "Log: Updating page size to %d\n", page_length_); } else { // Revert to default page length. logprintf(6, "Process Error: " "Invalid page size %d\n", page_length_); page_length_ = kSatPageSize; return false; } // Set disk_pages_ if filesize or page size changed. if (filesize != static_cast<uint64>(page_length_) * static_cast<uint64>(disk_pages_)) { disk_pages_ = filesize / page_length_; if (disk_pages_ == 0) disk_pages_ = 1; } // Validate memory channel parameters if supplied if (channels_.size()) { if (channels_.size() == 1) { channel_hash_ = 0; logprintf(7, "Log: " "Only one memory channel...deactivating interleave decoding.\n"); } else if (channels_.size() > 2) { logprintf(6, "Process Error: " "Triple-channel mode not yet supported... sorry.\n"); bad_status(); return false; } for (uint i = 0; i < channels_.size(); i++) if (channels_[i].size() != channels_[0].size()) { logprintf(6, "Process Error: " "Channels 0 and %d have a different count of dram modules.\n", i); bad_status(); return false; } if (channels_[0].size() & (channels_[0].size() - 1)) { logprintf(6, "Process Error: " "Amount of modules per memory channel is not a power of 2.\n"); bad_status(); return false; } if (channel_width_ < 16 || channel_width_ & (channel_width_ - 1)) { logprintf(6, "Process Error: " "Channel width %d is invalid.\n", channel_width_); bad_status(); return false; } if (channel_width_ / channels_[0].size() < 8) { logprintf(6, "Process Error: Chip width x%d must be x8 or greater.\n", channel_width_ / channels_[0].size()); bad_status(); return false; } } // Print each argument. for (int i = 0; i < argc; i++) { if (i) cmdline_ += " "; cmdline_ += argv[i]; } return true; }
stressapptest源代码定义了一个名为 Sat::ParseArgs
的成员函数,用于解析命令行参数并相应地配置名为 Sat
的类的实例。函数接受两个参数:argc
代表命令行参数的数量,argv
是一个字符指针数组,包含每个参数的字符串表示。
在代码中,有几个主要的部分需要特别关注:
变量初始化:在函数的开始部分,初始化了局部变量 i
(用于循环计数)和 filesize
(基于私有成员 page_length_
和 disk_pages_
计算大小)。
解析循环:代码通过一个 for
循环遍历所有参数。在循环内部,使用多个宏来处理不同类型的命令行参数:
ARG_IVALUE
:用于处理带有整数值的参数。ARG_KVALUE
:用于处理带有特定标志(键值对)的参数。ARG_SVALUE
:用于处理带有字符串值的参数。这些宏是私有宏,用于读取或设置类的成员变量。
错误处理和帮助信息:如果遇到未知的参数或者用户明确要求帮助(通过 -h
或 --help
参数),则调用 PrintVersion()
和 PrintHelp()
函数打印版本信息和帮助信息。如果参数未知且不是请求帮助,程序将打印错误信息并退出(使用 exit(1)
)。
特殊参数处理:对于像 -d
、-f
和 -n
这样的参数,代码采用特殊的处理逻辑。这些参数期待一个额外的值,该值紧跟在参数后面。例如,-d
参数处理磁盘线程和文件名。
后期验证和设置:在参数解析循环之后,函数执行几项验证和设置任务,这些任务需要所有参数都已经解析完毕才能进行。例如,程序转换从命令行读取的兆字节值到字节数,验证页面长度是否有效,以及确保磁盘页面的计算是基于任何可能发生变化的文件大小。
内存通道验证:如果提供了内存通道信息,函数会检查通道数量、DRAM模块的数量是否为2的幂,以及通道宽度是否有效。
命令行字符串构建:代码重新遍历所有参数,将它们拼接成一个完整的命令行字符串,并将其存储在 cmdline_
成员变量中。
ParseArgs
函数是一个典型的命令行参数解析器。
这篇文章对stressapptest的源码进行了深入剖析,重点讨论了默认参数和参数解析的相关内容。对stressapptest中的参数解析进行了分析,阐述了参数解析的原理和实现方式,以及不同参数对测试效果的影响。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。