util/CommonImpl.h (91 lines of code) (raw):
/**
* Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <atomic>
#include <wdt/Reporting.h>
namespace facebook {
namespace wdt {
const int64_t kDiskBlockSize = 4 * 1024;
/// class representing a buffer
class Buffer {
public:
/// @param size size to allocate
explicit Buffer(const int64_t size);
/// @return buffer ptr
char *getData() const;
/// @return whether the allocated buffer is aligned
bool isAligned() const;
/// @return buffer size
int64_t getSize() const;
~Buffer();
// making the object non-copyable and non-moveable
Buffer(const Buffer &stats) = delete;
Buffer &operator=(const Buffer &stats) = delete;
Buffer(Buffer &&stats) = delete;
Buffer &operator=(Buffer &&stats) = delete;
private:
char *data_{nullptr};
int64_t size_{0};
bool isAligned_{false};
};
/// class representing thread context
class ThreadCtx {
public:
/// @param options options to use
/// @param allocateBuffer whether to allocate buffer
ThreadCtx(const WdtOptions &options, bool allocateBuffer);
/// @param options options to use
/// @param allocateBuffer whether to allocate buffer
/// @param threadIndex index of the thread
ThreadCtx(const WdtOptions &options, bool allocateBuffer, int threadIndex);
/// @return options to use
const WdtOptions &getOptions() const;
/// @param thread index
int getThreadIndex() const;
/// @return buffer to use
const Buffer *getBuffer() const;
/// @return perf stat reporter
PerfStatReport &getPerfReport();
/// @param abort checker to use
void setAbortChecker(IAbortChecker const *abortChecker);
/// @return abort checker to use
const IAbortChecker *getAbortChecker() const;
// making the object non-copyable and non-moveable
ThreadCtx(const ThreadCtx &stats) = delete;
ThreadCtx &operator=(const ThreadCtx &stats) = delete;
ThreadCtx(ThreadCtx &&stats) = delete;
ThreadCtx &operator=(ThreadCtx &&stats) = delete;
private:
const WdtOptions &options_;
int threadIndex_{-1};
std::unique_ptr<Buffer> buffer_{nullptr};
PerfStatReport perfReport_;
IAbortChecker const *abortChecker_{nullptr};
};
/// util class to collect perf stat
class PerfStatCollector {
public:
PerfStatCollector(ThreadCtx &threadCtx,
const PerfStatReport::StatType statType)
: threadCtx_(threadCtx), statType_(statType) {
if (threadCtx_.getOptions().enable_perf_stat_collection) {
startTime_ = Clock::now();
}
}
~PerfStatCollector() {
if (threadCtx_.getOptions().enable_perf_stat_collection) {
int64_t duration = durationMicros(Clock::now() - startTime_);
if (duration >= 0) {
// If time goes back due to clock adjustment, ignore the sample.
threadCtx_.getPerfReport().addPerfStat(statType_, duration);
}
}
}
private:
ThreadCtx &threadCtx_;
const PerfStatReport::StatType statType_;
Clock::time_point startTime_;
};
/// util class to broadcast a signal to any number of subscribers.
template <class Tag>
class SignalSubscriber {
public:
SignalSubscriber() : epoch_(globalEpoch_.load(std::memory_order_relaxed)) {
}
// This is async-signal-safe.
static void notify() {
++globalEpoch_;
}
/**
* Returns true if notify() has been called at least once since the
* last invocation.
*/
bool notified() {
auto newEpoch = globalEpoch_.load(std::memory_order_relaxed);
if (newEpoch != epoch_) {
epoch_ = newEpoch;
return true;
}
return false;
}
private:
static std::atomic<uint64_t> globalEpoch_;
uint64_t epoch_;
};
template <class Tag>
std::atomic<uint64_t> SignalSubscriber<Tag>::globalEpoch_ = {};
struct ReportPerfTag {};
typedef SignalSubscriber<ReportPerfTag> ReportPerfSignalSubscriber;
}
}