stressapptest源码剖析:默认参数和参数解析

一、简介

stressapptest是一个用于对计算机系统进行压力测试的工具,它可以模拟多种场景下的CPU、内存、磁盘、网络等资源的高负载情况,用于评估系统的稳定性和性能表现。本系列文章将对stressapptest的源代码进行深入剖析,本篇重点关注其默认参数的设置和参数解析过程,以解析其内部运行机制和实现原理。

​随着计算机系统的日益复杂和性能需求的不断提升,系统稳定性和高负载下的性能表现成为了至关重要的考量因素。而stressapptest作为一个优秀的压力测试工具,能够帮助有效地评估硬件设备和系统软件在高负载情况下的表现。因此,深入了解stressapptest的实现细节和参数设置机制,将有助于更好地理解其工作原理,提高对系统性能测试的专业水平。

本系列文章将全面剖析stressapptest的源代码,从默认参数的设置到参数解析的过程,逐步揭示其内部运行机制和设计思路。读者将通过本系列文章深入了解stressapptest的内部工作原理,拓展对系统压力测试工具的理解,为系统性能的评估和优化提供参考和帮助。

接下来的章节将详细讲解stressapptest的默认参数设置和参数解析过程,以及相关的代码解析和分析。同时,我们将结合实际代码,带领读者逐步理解stressapptest的内部机制和实现细节。

在这里插入图片描述

二、Sat构造函数初始化默认参数

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;

三、Sat的参数解析ParseArgs()

默认参数可以被命令行参数替换。源代码:

#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 是一个字符指针数组,包含每个参数的字符串表示。

在代码中,有几个主要的部分需要特别关注:

  1. 变量初始化:在函数的开始部分,初始化了局部变量 i(用于循环计数)和 filesize (基于私有成员 page_length_disk_pages_ 计算大小)。

  2. 解析循环:代码通过一个 for 循环遍历所有参数。在循环内部,使用多个宏来处理不同类型的命令行参数:

    • ARG_IVALUE:用于处理带有整数值的参数。
    • ARG_KVALUE:用于处理带有特定标志(键值对)的参数。
    • ARG_SVALUE:用于处理带有字符串值的参数。

    这些宏是私有宏,用于读取或设置类的成员变量。

  3. 错误处理和帮助信息:如果遇到未知的参数或者用户明确要求帮助(通过 -h--help 参数),则调用 PrintVersion()PrintHelp() 函数打印版本信息和帮助信息。如果参数未知且不是请求帮助,程序将打印错误信息并退出(使用 exit(1))。

  4. 特殊参数处理:对于像 -d-f-n 这样的参数,代码采用特殊的处理逻辑。这些参数期待一个额外的值,该值紧跟在参数后面。例如,-d 参数处理磁盘线程和文件名。

  5. 后期验证和设置:在参数解析循环之后,函数执行几项验证和设置任务,这些任务需要所有参数都已经解析完毕才能进行。例如,程序转换从命令行读取的兆字节值到字节数,验证页面长度是否有效,以及确保磁盘页面的计算是基于任何可能发生变化的文件大小。

  6. 内存通道验证:如果提供了内存通道信息,函数会检查通道数量、DRAM模块的数量是否为2的幂,以及通道宽度是否有效。

  7. 命令行字符串构建:代码重新遍历所有参数,将它们拼接成一个完整的命令行字符串,并将其存储在 cmdline_ 成员变量中。

ParseArgs 函数是一个典型的命令行参数解析器。

总结

这篇文章对stressapptest的源码进行了深入剖析,重点讨论了默认参数和参数解析的相关内容。对stressapptest中的参数解析进行了分析,阐述了参数解析的原理和实现方式,以及不同参数对测试效果的影响。
在这里插入图片描述

  • 12
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Lion Long

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值