cpp: Add profiling hooks to Mutex, ReadWriteMutex() classes
Extend the Thrift C++ Concurrency library by allowing a user to register
a callback and a sample rate for lock primitive contention profiling.
The callback will be invoked approximately once every sampleRate calls
to Mutex::lock(), Mutex::timedlock(), ReadWriteLock::acquireRead(), or
ReadWriteLock::acquireWrite().
The callback receives a pointer to the mutex responsible and the time
waited on the lock in micros (whether the lock was successfuly acquire
or not). The user can then implement a registry of his choice to
log/collect this data as needed.
This can all be easily compiled out if it harms performance. By
default, there is no profiling callback, so the overhead is minimal
(one branch).
git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@920681 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/lib/cpp/src/concurrency/Util.h b/lib/cpp/src/concurrency/Util.h
index 4630dbb..18a221d 100644
--- a/lib/cpp/src/concurrency/Util.h
+++ b/lib/cpp/src/concurrency/Util.h
@@ -47,6 +47,7 @@
static const int64_t MS_PER_S = 1000LL;
static const int64_t NS_PER_MS = NS_PER_S / MS_PER_S;
+ static const int64_t NS_PER_US = NS_PER_S / US_PER_S;
static const int64_t US_PER_MS = US_PER_S / MS_PER_S;
public:
@@ -67,32 +68,78 @@
result.tv_usec = (value % MS_PER_S) * US_PER_MS; // ms to us
}
+ static const void toTicks(int64_t& result, int64_t secs, int64_t oldTicks,
+ int64_t oldTicksPerSec, int64_t newTicksPerSec) {
+ result = secs * newTicksPerSec;
+ result += oldTicks * newTicksPerSec / oldTicksPerSec;
+
+ int64_t oldPerNew = oldTicksPerSec / newTicksPerSec;
+ if (oldPerNew && ((oldTicks % oldPerNew) >= (oldPerNew / 2))) {
+ ++result;
+ }
+ }
+ /**
+ * Converts struct timespec to arbitrary-sized ticks since epoch
+ */
+ static const void toTicks(int64_t& result,
+ const struct timespec& value,
+ int64_t ticksPerSec) {
+ return toTicks(result, value.tv_sec, value.tv_nsec, NS_PER_S, ticksPerSec);
+ }
+
+ /**
+ * Converts struct timeval to arbitrary-sized ticks since epoch
+ */
+ static const void toTicks(int64_t& result,
+ const struct timeval& value,
+ int64_t ticksPerSec) {
+ return toTicks(result, value.tv_sec, value.tv_usec, US_PER_S, ticksPerSec);
+ }
+
/**
* Converts struct timespec to milliseconds
*/
- static const void toMilliseconds(int64_t& result, const struct timespec& value) {
- result = (value.tv_sec * MS_PER_S) + (value.tv_nsec / NS_PER_MS);
- // round up -- int64_t cast is to avoid a compiler error for some GCCs
- if (int64_t(value.tv_nsec) % NS_PER_MS >= (NS_PER_MS / 2)) {
- ++result;
- }
+ static const void toMilliseconds(int64_t& result,
+ const struct timespec& value) {
+ return toTicks(result, value, MS_PER_S);
}
/**
* Converts struct timeval to milliseconds
*/
- static const void toMilliseconds(int64_t& result, const struct timeval& value) {
- result = (value.tv_sec * MS_PER_S) + (value.tv_usec / US_PER_MS);
- // round up -- int64_t cast is to avoid a compiler error for some GCCs
- if (int64_t(value.tv_usec) % US_PER_MS >= (US_PER_MS / 2)) {
- ++result;
- }
+ static const void toMilliseconds(int64_t& result,
+ const struct timeval& value) {
+ return toTicks(result, value, MS_PER_S);
}
/**
+ * Converts struct timespec to microseconds
+ */
+ static const void toUsec(int64_t& result, const struct timespec& value) {
+ return toTicks(result, value, US_PER_S);
+ }
+
+ /**
+ * Converts struct timeval to microseconds
+ */
+ static const void toUsec(int64_t& result, const struct timeval& value) {
+ return toTicks(result, value, US_PER_S);
+ }
+
+ /**
+ * Get current time as a number of arbitrary-size ticks from epoch
+ */
+ static const int64_t currentTimeTicks(int64_t ticksPerSec);
+
+ /**
* Get current time as milliseconds from epoch
*/
- static const int64_t currentTime();
+ static const int64_t currentTime() { return currentTimeTicks(MS_PER_S); }
+
+ /**
+ * Get current time as micros from epoch
+ */
+ static const int64_t currentTimeUsec() { return currentTimeTicks(US_PER_S); }
};
}}} // apache::thrift::concurrency