int main()

in cachelib/benchmarks/ItemsReaperBench.cpp [62:158]


int main(int argc, char** argv) {
  folly::init(&argc, &argv);

  XLOG(INFO) << "initializing cache";
  LruAllocator::AccessConfig accessConfig(
      folly::findLastSet(FLAGS_num_keys) + 1, 10);
  LruAllocator::Config lruConfig;
  lruConfig.setCacheSize(FLAGS_size_gb * 1024 * 1024 * 1024);
  lruConfig.setAccessConfig(accessConfig);
  lruConfig.enableItemReaperInBackground(
      std::chrono::milliseconds{FLAGS_sleep_ms},
      util::Throttler::Config{FLAGS_sleep_ms, FLAGS_work_ms});
  assert(lruConfig.itemsReaperEnabled());
  LruAllocator cache(lruConfig);
  const auto poolId =
      cache.addPool("default", cache.getCacheMemoryStats().cacheSize);

  XLOG(INFO) << "allocating items";
  std::mt19937 gen(folly::Random::rand32());
  std::normal_distribution<> sizeDis(kAllocSizeMean, kAllocSizeDev);
  std::uniform_int_distribution<uint32_t> keySize(kMinKeySize, kMaxKeySize);
  std::uniform_int_distribution<uint32_t> ttlDist(0,
                                                  FLAGS_benchmark_duration_s);
  std::uniform_int_distribution<uint8_t> charDis(0, 25);
  for (uint64_t i = 0; i < FLAGS_num_keys; ++i) {
    util::allocateAccessible(
        cache, poolId,
        facebook::cachelib::test_util::getRandomAsciiStr(keySize(gen)),
        getRandomAllocSize(sizeDis(gen)), ttlDist(gen));
  }

  auto reaperStatStr = [](const facebook::cachelib::ReaperStats& stats) {
    auto str = folly::sformat(
        "numTraversals: {:8d}, numVisits: {:12d}, lastTraversalMs: {:6d}ms, "
        "avgTraversalMs: {:6d}ms, maxTraversalMs: {:6d}",
        stats.numTraversals, stats.numVisitedItems, stats.lastTraversalTimeMs,
        stats.avgTraversalTimeMs, stats.maxTraversalTimeMs);
    return str;
  };

  struct rusage rUsageBefore = {};
  struct rusage rUsageAfter = {};

  XLOG(INFO) << "Gathering reaper metrics";
  if (::getrusage(RUSAGE_SELF, &rUsageBefore)) {
    XLOG(INFO) << "Error getting rusage" << errno;
    return 0;
  }
  const auto start = std::chrono::steady_clock::now();
  const auto startStats = cache.getReaperStats();
  while (true) {
    std::this_thread::sleep_for(std::chrono::seconds(1));
    if (FLAGS_print_interval_s) {
      XLOG_EVERY_MS(INFO, FLAGS_print_interval_s * 1000)
          << reaperStatStr(cache.getReaperStats());
    }

    if (std::chrono::steady_clock::now() - start >
        std::chrono::seconds(FLAGS_benchmark_duration_s)) {
      break;
    }
  }

  if (::getrusage(RUSAGE_SELF, &rUsageAfter)) {
    XLOG(INFO) << "Error getting rusage" << errno;
    return 0;
  }

  auto finalStats = cache.getReaperStats();
  double memoryScanned =
      FLAGS_size_gb * (finalStats.numTraversals - startStats.numTraversals);
  auto timeTaken = std::chrono::duration_cast<std::chrono::seconds>(
      std::chrono::steady_clock::now() - start);

  XLOG(INFO) << reaperStatStr(finalStats);
  XLOG(INFO) << folly::sformat("bytes scanned  : {:12.2f}gb/sec",
                               memoryScanned / timeTaken.count());

  auto getTimeRUsage = [](const struct rusage& r) {
    double userSeconds = r.ru_utime.tv_sec + r.ru_utime.tv_usec / 1e6;
    double sysSeconds = r.ru_stime.tv_sec + r.ru_stime.tv_usec / 1e6;
    return std::make_tuple(userSeconds, sysSeconds, userSeconds + sysSeconds);
  };

  auto [beforeUser, beforeSys, beforeTot] = getTimeRUsage(rUsageBefore);
  auto [afterUser, afterSys, afterTot] = getTimeRUsage(rUsageAfter);

  // compute core cpu util by divinding the time spent on a core with overall
  // time spent to complete the operation.
  XLOG(INFO) << folly::sformat(
      "cpu util: user: {:3.6}s sys: {:3.6f}s total: {:3.6f}s  util-pct: "
      "{:2.2f}%",
      afterUser - beforeUser, afterSys - beforeSys, afterTot - beforeTot,
      100.0 * (afterTot - beforeTot) / timeTaken.count());

  return 0;
}