1 // Copyright 2018 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #pragma once
6 
7 #include <atomic>
8 #include <stdint.h>
9 #include <unistd.h>
10 
11 #include <cobalt-client/cpp/metric-options.h>
12 #include <cobalt-client/cpp/types-internal.h>
13 #include <fbl/function.h>
14 #include <fbl/string.h>
15 #include <fbl/vector.h>
16 
17 namespace cobalt_client {
18 namespace internal {
19 // Note: Everything on this namespace is internal, no external users should rely
20 // on the behaviour of any of these classes.
21 
22 // BaseCounter and RemoteCounter differ in that the first is simply a thin wrapper over
23 // an atomic while the second provides Cobalt Fidl specific API and holds more metric related
24 // data for a full fledged metric.
25 //
26 // Thin wrapper on top of an atomic, which provides a fixed memory ordering for all calls.
27 // Calls are inlined to reduce overhead.A
28 template <typename T>
29 class BaseCounter {
30 public:
31     // Alias for the underlying counter type.
32     using Type = T;
33 
34     // All atomic operations use this memory order.
35     static constexpr auto kMemoryOrder = std::memory_order_relaxed;
36 
BaseCounter()37     BaseCounter()
38         : counter_(0) {}
39     BaseCounter(const BaseCounter&) = delete;
BaseCounter(BaseCounter && other)40     BaseCounter(BaseCounter&& other)
41         : counter_(other.Exchange(0)) {}
42     BaseCounter& operator=(const BaseCounter&) = delete;
43     BaseCounter& operator=(BaseCounter&&) = delete;
44     ~BaseCounter() = default;
45 
46     // Increments |counter_| by |val|.
47     void Increment(Type val = 1) { counter_.fetch_add(val, kMemoryOrder); }
48 
49     // Returns the current value of|counter_| and resets it to |val|.
50     Type Exchange(Type val = 0) { return counter_.exchange(val, kMemoryOrder); }
51 
52     // Returns the current value of |counter_|.
Load()53     Type Load() const { return counter_.load(kMemoryOrder); }
54 
55 protected:
56     static_assert(fbl::is_integral<Type>::value, "Can only count integral types");
57 
58     std::atomic<Type> counter_;
59 };
60 
61 // Counter which represents a standalone cobalt metric. Provides API for converting
62 // to cobalt FIDL types.
63 //
64 // This class is moveable and move-assignable.
65 // This class is not copy or copy-assignable.
66 // This class is thread-safe except for |Flushing| which is thread-compatible.
67 class RemoteCounter : public BaseCounter<int64_t>, public FlushInterface {
68 public:
69     RemoteCounter() = default;
70     RemoteCounter(const RemoteMetricInfo& metric_info);
71     RemoteCounter(const RemoteCounter&) = delete;
72     RemoteCounter(RemoteCounter&&);
73     RemoteCounter& operator=(const RemoteCounter&) = delete;
74     RemoteCounter& operator=(RemoteCounter&&) = delete;
75     virtual ~RemoteCounter() = default;
76 
77     bool Flush(Logger* logger) override;
78 
79     void UndoFlush() override;
80 
81     // Should only be called when default constructed.
82     void Initialize(const MetricOptions& metric_options);
83 
84     // Returns the metric_id associated with this remote metric.
metric_info()85     const RemoteMetricInfo& metric_info() const { return metric_info_; }
86 
87 private:
88     int64_t buffer_;
89     // Unique-Id representing this metric in the backend.
90     RemoteMetricInfo metric_info_;
91 };
92 
93 } // namespace internal
94 } // namespace cobalt_client
95