tlbmc: Add shared memory support for Requests Per Second metrics

This change adds the core functionality to `TlbmcMetrics` to calculate and store Requests Per Second (RPS) for both TLBMC and gBMCWeb Redfish requests.

The key additions are:
- `UpdateMetricsRps(absl::Duration)` in `TlbmcMetrics` to calculate RPS based on request count changes over time.
- Atomic member variables to store TLBMC, gBMCWeb, and total RPS values.
- Exposure of the new RPS metrics via `ToJson()` and new getter methods.
- An update to `SharedMemoryServer` to provide access to `UpdateMetricsRps`.

This provides the necessary infrastructure in shared memory for higher-level components to trigger RPS calculation. Unit tests for the RPS calculation logic are included.

#tlbmc
#bmc-offsite

PiperOrigin-RevId: 822722354
Change-Id: I1709e8dd261a657b6ad45402dbe19ac5ca271c51
diff --git a/tlbmc/hal/shared_mem/metrics.cc b/tlbmc/hal/shared_mem/metrics.cc
index 5ccd646..3691337 100644
--- a/tlbmc/hal/shared_mem/metrics.cc
+++ b/tlbmc/hal/shared_mem/metrics.cc
@@ -68,6 +68,31 @@
   }
 }
 
+void TlbmcMetrics::UpdateMetricsRps(absl::Duration time_delta) {
+  if (time_delta > absl::ZeroDuration()) {
+    MetricsIntegerType current_tlbmc_request_count =
+        total_tlbmc_request_count_.load();
+    MetricsIntegerType current_bmcweb_request_count =
+        total_gbmcweb_request_count_.load();
+
+    MetricsIntegerType tlbmc_rate = static_cast<MetricsIntegerType>(
+        (static_cast<double>(current_tlbmc_request_count -
+                   prev_tlbmc_request_count_.load())) /
+                  absl::ToDoubleSeconds(time_delta));
+    MetricsIntegerType bmcweb_rate = static_cast<MetricsIntegerType>(
+        (static_cast<double>(current_bmcweb_request_count -
+                   prev_bmcweb_request_count_.load())) /
+                  absl::ToDoubleSeconds(time_delta));
+
+    tlbmc_requests_per_second_.store(tlbmc_rate);
+    bmcweb_requests_per_second_.store(bmcweb_rate);
+    total_requests_per_second_.store(tlbmc_rate + bmcweb_rate);
+
+    prev_tlbmc_request_count_.store(current_tlbmc_request_count);
+    prev_bmcweb_request_count_.store(current_bmcweb_request_count);
+  }
+}
+
 nlohmann::json TlbmcMetrics::ToJson() const {
   return ToJson(kTopLatencyResourcesCount);
 }
@@ -80,6 +105,9 @@
   nlohmann::json json;
   json["TotalTlbmcRequestCount"] = total_tlbmc_request_count_.load();
   json["TotalGbmcwebRequestCount"] = total_gbmcweb_request_count_.load();
+  json["TlbmcRequestsPerSecond"] = tlbmc_requests_per_second_.load();
+  json["BmcwebRequestsPerSecond"] = bmcweb_requests_per_second_.load();
+  json["TotalRequestsPerSecond"] = total_requests_per_second_.load();
   // Response status code count.
   nlohmann::json::array_t response_status_code_count_json;
   for (int code : kSupportedStatusCodes) {
diff --git a/tlbmc/hal/shared_mem/metrics.h b/tlbmc/hal/shared_mem/metrics.h
index 1df50b6..10a6a5b 100644
--- a/tlbmc/hal/shared_mem/metrics.h
+++ b/tlbmc/hal/shared_mem/metrics.h
@@ -5,6 +5,8 @@
 
 #include <array>
 #include <atomic>
+#include <chrono>  // NOLINT
+#include <cmath>
 #include <cstddef>
 #include <cstdint>
 #include <string_view>
@@ -50,6 +52,8 @@
   void UpdateMetricsRequestCount(bool is_tlbmc_request);
   void UpdateMetricsResponse(absl::Duration response_time, int status_code,
                              std::string_view resource_url);
+  // Calculates the Requests Per Second of TLBMC and gBMCWeb Redfish requests.
+  void UpdateMetricsRps(absl::Duration time_delta);
   // Dumps to a JSON used for metrics collection. Contains the top
   // `kTopLatencyResourcesCount` resources with the highest average latency.
   // This call is expensive. Please call it only periodically, e.g., every
@@ -60,6 +64,23 @@
   nlohmann::json ToJson(int top_latency_resources_count) const;
   // Dumps to a JSON used for debugging.
   nlohmann::json ToDebugJson() const;
+
+  MetricsIntegerType GetTlbmcRequestCount() const {
+    return total_tlbmc_request_count_.load();
+  }
+
+  MetricsIntegerType GetGbmcwebRequestCount() const {
+    return total_gbmcweb_request_count_.load();
+  }
+  MetricsIntegerType GetTlbmcRps() const {
+    return tlbmc_requests_per_second_.load();
+  }
+  MetricsIntegerType GetBmcwebRps() const {
+    return bmcweb_requests_per_second_.load();
+  }
+  MetricsIntegerType GetTotalRps() const {
+    return total_requests_per_second_.load();
+  }
   // copybara:strip_end
 
  private:
@@ -79,6 +100,12 @@
   // TODO(nanzhou): handles overflow.
   std::atomic<MetricsIntegerType>
       response_total_latency_ms_per_resource_[kResourceCount] = {0};
+
+  std::atomic<MetricsIntegerType> tlbmc_requests_per_second_ = 0;
+  std::atomic<MetricsIntegerType> bmcweb_requests_per_second_ = 0;
+  std::atomic<MetricsIntegerType> total_requests_per_second_ = 0;
+  std::atomic<MetricsIntegerType> prev_tlbmc_request_count_ = 0;
+  std::atomic<MetricsIntegerType> prev_bmcweb_request_count_ = 0;
 };
 
 }  // namespace milotic_tlbmc
diff --git a/tlbmc/hal/shared_mem/server.cc b/tlbmc/hal/shared_mem/server.cc
index bf0acd5..1ca9ea5 100644
--- a/tlbmc/hal/shared_mem/server.cc
+++ b/tlbmc/hal/shared_mem/server.cc
@@ -140,6 +140,13 @@
   }
   metrics_->UpdateMetricsResponse(response_time, status_code, resource_url);
 }
+
+void SharedMemoryServer::UpdateMetricsRps(absl::Duration time_delta) {
+  if (metrics_ == nullptr) {
+    return;
+  }
+  metrics_->UpdateMetricsRps(time_delta);
+}
 // copybara:strip_end
 
 }  // namespace milotic_tlbmc
diff --git a/tlbmc/hal/shared_mem/server.h b/tlbmc/hal/shared_mem/server.h
index 6cca6cb..853f1ad 100644
--- a/tlbmc/hal/shared_mem/server.h
+++ b/tlbmc/hal/shared_mem/server.h
@@ -30,6 +30,7 @@
   virtual void UpdateMetricsResponse(absl::Duration response_time,
                                      int status_code,
                                      std::string_view resource_url) = 0;
+  virtual void UpdateMetricsRps(absl::Duration time_delta) = 0;
   // copybara:strip_end
   virtual const TlbmcMetrics* GetMetrics() const = 0;
 };
@@ -73,6 +74,7 @@
   void UpdateMetricsRequestCount(bool is_tlbmc_request) override;
   void UpdateMetricsResponse(absl::Duration response_time, int status_code,
                              std::string_view resource_url) override;
+  void UpdateMetricsRps(absl::Duration time_delta) override;
   // copybara:strip_end
 
   SharedMemoryServer(Token token, const std::string& initialized_file_path,