Skip to content

Commit

Permalink
refactor(new_metrics): refactor enum definition for metric types and …
Browse files Browse the repository at this point in the history
…units (#1491)

#1490

For the enum classes, such as metric type and unit, in addition to the declaration
of all enumerators, extra code is needed to implement `enum_to_string` for each
enumerator. However, the "extra code" tended to be forgotten, just as what has
been said in the above issue #1490.

Therefore, we should find a way that could share all the enumerators between
the declaration and `enum_to_string`. Each enumerator would be written only
once, and there is no need to remember to add `enum_to_string` for each
enumerator.

We could implement the "sharing" by function-like macros. They have the names
of all the enumerators, and accept an argument to perform custom actions over
the names to implement the "sharing". Both metric types and units would be
refactored in this way.

While building ASAN Github actions failed due to running out of disk space.
This problem is resolved by dropping all directories of `CMakeFiles`, which is
also tracked another issue: 
        #1497
  • Loading branch information
empiredan authored and wangdan committed Aug 9, 2023
1 parent 63cdd63 commit ff43009
Show file tree
Hide file tree
Showing 4 changed files with 328 additions and 56 deletions.
2 changes: 1 addition & 1 deletion src/runtime/task/task_queue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ METRIC_DEFINE_counter(queue,
METRIC_DEFINE_counter(queue,
queue_rejected_tasks,
dsn::metric_unit::kTasks,
"The accumulative number of rejeced tasks by throttling before enqueue");
"The accumulative number of rejected tasks by throttling before enqueue");

namespace dsn {

Expand Down
63 changes: 61 additions & 2 deletions src/utils/enum_helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,14 @@
#pragma once

#include <map>
#include <string>
#include <mutex>
#include <memory>
#include <mutex>
#include <string>

namespace dsn {
template <typename TEnum>
class enum_helper_xxx;
} // namespace dsn

// an invalid enum value must be provided so as to be the default value when parsing failed
#define ENUM_BEGIN2(type, name, invalid_value) \
Expand All @@ -52,6 +57,8 @@
#define ENUM_REG_WITH_CUSTOM_NAME(type, name) helper->register_enum(#name, type);
#define ENUM_REG(e) helper->register_enum(#e, e);

// Argument `type invalid_value` for enum_from_string, albeit unused, has to be provided due to
// overloading.
#define ENUM_END2(type, name) \
return helper; \
} \
Expand All @@ -66,6 +73,58 @@

#define ENUM_END(type) ENUM_END2(type, type)

// Google Style (https://google.github.io/styleguide/cppguide.html#Enumerator_Names) has recommended
// using k-prefixed camelCase to name an enumerator instead of MACRO_CASE. That is, use kEnumName,
// rather than ENUM_NAME.
//
// On the other hand, the string representation for an enumerator is often needed. After declaring
// the enumerator, ENUM_REG* macros would also be used to register the string representation, which
// has some drawbacks:
// * the enumerator has to appear again, leading to redundant code;
// * once there are numerous enumerators, ENUM_REG* tend to be forgotten and the registers for the
// string representation would be missing.
//
// To solve these problems, ENUM_CONST* macros are introduced:
// * firstly, naming for the string representation should be UpperCamelCase style (namely EnumName);
// * ENUM_CONST() could be used to generate the enumerators according to the string representation;
// * only support `enum class` declarations;
// * ENUM_CONST_DEF() could be used to declare enumerators in the enum class;
// * ENUM_CONST_REG_STR could be used to register the string representation.
//
// The usage of these macros would be described as below. For example, Status::code of rocksdb
// (include/rocksdb/status.h) could be defined by ENUM_CONST* as following steps:
//
// 1. List string representation for each enumerator by a user-defined macro:
// --------------------------------------------------------------------------
/*
* #define ENUM_FOREACH_STATUS_CODE(DEF) \
* DEF(Ok) \
* DEF(NotFound) \
* DEF(Corruption) \
* DEF(IOError)
*/
// 2. Declare an enum class by above user-defined macro, with an Invalid and an Count enumerator if
// necessary:
// ------------------------------------------------------------------------------------------------
// enum class status_code
// {
// ENUM_FOREACH_STATUS_CODE(ENUM_CONST_DEF) kCount, kInvalidCode,
// };
//
// 3. Define another user-defined macro to register string representations:
// ------------------------------------------------------------------------
// #define ENUM_CONST_REG_STR_STATUS_CODE(str) ENUM_CONST_REG_STR(status_code, str)
//
// 4. Define enum helper class:
// ----------------------------
// ENUM_BEGIN(status_code, status_code::kInvalidCode)
// ENUM_FOREACH_STATUS_CODE(ENUM_CONST_REG_STR_STATUS_CODE)
// ENUM_END(status_code)
#define ENUM_CONST(str) k##str
#define ENUM_CONST_DEF(str) ENUM_CONST(str),
#define ENUM_CONST_REG_STR(enum_class, str) \
helper->register_enum(#str, enum_class::ENUM_CONST(str));

namespace dsn {

template <typename TEnum>
Expand Down
107 changes: 54 additions & 53 deletions src/utils/metrics.h
Original file line number Diff line number Diff line change
Expand Up @@ -644,62 +644,65 @@ class metric_registry : public utils::singleton<metric_registry>
// On the other hand, it is also needed when some special operation should be done
// for a metric type. For example, percentile should be closed while it's no longer
// used.
#define ENUM_FOREACH_METRIC_TYPE(DEF) \
DEF(Gauge) \
DEF(Counter) \
DEF(VolatileCounter) \
DEF(Percentile)

enum class metric_type
{
kGauge,
kCounter,
kVolatileCounter,
kPercentile,
kInvalidUnit,
ENUM_FOREACH_METRIC_TYPE(ENUM_CONST_DEF) kInvalidType,
};

ENUM_BEGIN(metric_type, metric_type::kInvalidUnit)
ENUM_REG_WITH_CUSTOM_NAME(metric_type::kGauge, gauge)
ENUM_REG_WITH_CUSTOM_NAME(metric_type::kCounter, counter)
ENUM_REG_WITH_CUSTOM_NAME(metric_type::kVolatileCounter, volatile_counter)
ENUM_REG_WITH_CUSTOM_NAME(metric_type::kPercentile, percentile)
#define ENUM_CONST_REG_STR_METRIC_TYPE(str) ENUM_CONST_REG_STR(metric_type, str)

ENUM_BEGIN(metric_type, metric_type::kInvalidType)
ENUM_FOREACH_METRIC_TYPE(ENUM_CONST_REG_STR_METRIC_TYPE)
ENUM_END(metric_type)

#define ENUM_FOREACH_METRIC_UNIT(DEF) \
DEF(NanoSeconds) \
DEF(MicroSeconds) \
DEF(MilliSeconds) \
DEF(Seconds) \
DEF(Bytes) \
DEF(MegaBytes) \
DEF(CapacityUnits) \
DEF(Percent) \
DEF(Replicas) \
DEF(Partitions) \
DEF(PartitionSplittings) \
DEF(Servers) \
DEF(Requests) \
DEF(Responses) \
DEF(Seeks) \
DEF(PointLookups) \
DEF(Values) \
DEF(Keys) \
DEF(Files) \
DEF(Dirs) \
DEF(Amplification) \
DEF(Checkpoints) \
DEF(Flushes) \
DEF(Compactions) \
DEF(Mutations) \
DEF(Writes) \
DEF(Changes) \
DEF(Operations) \
DEF(Tasks) \
DEF(Disconnections) \
DEF(Learns) \
DEF(Rounds) \
DEF(Resets) \
DEF(Backups) \
DEF(FileLoads) \
DEF(FileUploads) \
DEF(BulkLoads)

enum class metric_unit : size_t
{
kNanoSeconds,
kMicroSeconds,
kMilliSeconds,
kSeconds,
kBytes,
kMegaBytes,
kCapacityUnits,
kPercent,
kReplicas,
kPartitions,
kPartitionSplittings,
kServers,
kRequests,
kResponses,
kSeeks,
kPointLookups,
kValues,
kKeys,
kFiles,
kDirs,
kAmplification,
kCheckpoints,
kFlushes,
kCompactions,
kMutations,
kWrites,
kChanges,
kOperations,
kTasks,
kDisconnections,
kLearns,
kRounds,
kResets,
kBackups,
kFileLoads,
kFileUploads,
kBulkLoads,
kInvalidUnit,
ENUM_FOREACH_METRIC_UNIT(ENUM_CONST_DEF) kInvalidUnit,
};

#define METRIC_ASSERT_UNIT_LATENCY(unit, index) \
Expand Down Expand Up @@ -727,12 +730,10 @@ inline uint64_t convert_metric_latency_from_ns(uint64_t latency_ns, metric_unit
return latency_ns / kMetricLatencyConverterFromNS[index];
}

#define ENUM_CONST_REG_STR_METRIC_UNIT(str) ENUM_CONST_REG_STR(metric_unit, str)

ENUM_BEGIN(metric_unit, metric_unit::kInvalidUnit)
ENUM_REG_WITH_CUSTOM_NAME(metric_unit::kNanoSeconds, nanoseconds)
ENUM_REG_WITH_CUSTOM_NAME(metric_unit::kMicroSeconds, microseconds)
ENUM_REG_WITH_CUSTOM_NAME(metric_unit::kMilliSeconds, milliseconds)
ENUM_REG_WITH_CUSTOM_NAME(metric_unit::kSeconds, seconds)
ENUM_REG_WITH_CUSTOM_NAME(metric_unit::kRequests, requests)
ENUM_FOREACH_METRIC_UNIT(ENUM_CONST_REG_STR_METRIC_UNIT)
ENUM_END(metric_unit)

class metric_prototype
Expand Down
Loading

0 comments on commit ff43009

Please sign in to comment.