LCOV - code coverage report
Current view: top level - media/server/ipc/source - PrivateMetricsModuleService.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 97.1 % 140 136
Test Date: 2026-09-11 17:36:12 Functions: 100.0 % 10 10

            Line data    Source code
       1              : /*
       2              :  * If not stated otherwise in this file or this component's LICENSE file the
       3              :  * following copyright and licenses apply:
       4              :  *
       5              :  * Copyright 2026 Sky UK
       6              :  *
       7              :  * Licensed under the Apache License, Version 2.0 (the "License");
       8              :  * you may not use this file except in compliance with the License.
       9              :  * You may obtain a copy of the License at
      10              :  *
      11              :  * http://www.apache.org/licenses/LICENSE-2.0
      12              :  *
      13              :  * Unless required by applicable law or agreed to in writing, software
      14              :  * distributed under the License is distributed on an "AS IS" BASIS,
      15              :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      16              :  * See the License for the specific language governing permissions and
      17              :  * limitations under the License.
      18              :  */
      19              : 
      20              : #include "PrivateMetricsModuleService.h"
      21              : #include "RialtoServerLogging.h"
      22              : #include <IIpcController.h>
      23              : #include <cinttypes>
      24              : 
      25              : namespace firebolt::rialto::server::ipc
      26              : {
      27            1 : std::shared_ptr<IPrivateMetricsModuleServiceFactory> IPrivateMetricsModuleServiceFactory::createFactory()
      28              : {
      29            1 :     std::shared_ptr<IPrivateMetricsModuleServiceFactory> factory;
      30              : 
      31              :     try
      32              :     {
      33            1 :         factory = std::make_shared<PrivateMetricsModuleServiceFactory>();
      34              :     }
      35            0 :     catch (const std::exception &e)
      36              :     {
      37            0 :         RIALTO_SERVER_LOG_ERROR("Failed to create the rialto private metrics module service factory, reason: %s",
      38              :                                 e.what());
      39              :     }
      40              : 
      41            1 :     return factory;
      42              : }
      43              : 
      44              : std::shared_ptr<IPrivateMetricsModuleService>
      45            1 : PrivateMetricsModuleServiceFactory::create(service::IPrivateMetricsService &metricsService) const
      46              : {
      47            1 :     std::shared_ptr<IPrivateMetricsModuleService> privateMetricsModule;
      48              : 
      49              :     try
      50              :     {
      51            1 :         privateMetricsModule = std::make_shared<PrivateMetricsModuleService>(metricsService);
      52              :     }
      53            0 :     catch (const std::exception &e)
      54              :     {
      55            0 :         RIALTO_SERVER_LOG_ERROR("Failed to create the rialto private metrics module service, reason: %s", e.what());
      56              :     }
      57              : 
      58            1 :     return privateMetricsModule;
      59              : }
      60              : 
      61            7 : PrivateMetricsModuleService::PrivateMetricsModuleService(service::IPrivateMetricsService &metricsService)
      62            7 :     : m_metricsService{metricsService}
      63              : {
      64              : }
      65              : 
      66            7 : PrivateMetricsModuleService::~PrivateMetricsModuleService() = default;
      67              : 
      68            1 : void PrivateMetricsModuleService::clientConnected(const std::shared_ptr<::firebolt::rialto::ipc::IClient> &ipcClient)
      69              : {
      70            1 :     RIALTO_SERVER_LOG_INFO("Client connected to private metrics module");
      71              :     {
      72            1 :         std::lock_guard<std::mutex> lock{m_mutex};
      73              :         // Don't assign a clientId yet — wait for notifyClientReady
      74              :     }
      75            1 :     ipcClient->exportService(shared_from_this());
      76              : }
      77              : 
      78            2 : void PrivateMetricsModuleService::clientDisconnected(const std::shared_ptr<::firebolt::rialto::ipc::IClient> &ipcClient)
      79              : {
      80            2 :     RIALTO_SERVER_LOG_INFO("Client disconnected from private metrics module");
      81            2 :     int clientId{0};
      82              :     {
      83            2 :         std::lock_guard<std::mutex> lock{m_mutex};
      84            2 :         auto iter = m_clientIds.find(ipcClient);
      85            2 :         if (iter != m_clientIds.end())
      86              :         {
      87            2 :             clientId = iter->second;
      88            2 :             m_clientIds.erase(iter);
      89            2 :             m_ipcClients.erase(clientId);
      90              :         }
      91              :     }
      92            2 :     if (clientId != 0)
      93              :     {
      94            2 :         m_metricsService.clientDisconnected(clientId);
      95              :     }
      96              : }
      97              : 
      98            6 : void PrivateMetricsModuleService::notifyClientReady(::google::protobuf::RpcController *controller,
      99              :                                                     const ::firebolt::rialto::NotifyClientReadyRequest *request,
     100              :                                                     ::firebolt::rialto::NotifyClientReadyResponse *response,
     101              :                                                     ::google::protobuf::Closure *done)
     102              : {
     103            6 :     RIALTO_SERVER_LOG_DEBUG("entry:");
     104            6 :     auto ipcController = dynamic_cast<firebolt::rialto::ipc::IController *>(controller);
     105            6 :     if (!ipcController)
     106              :     {
     107            1 :         RIALTO_SERVER_LOG_ERROR("ipc library provided incompatible controller object");
     108            2 :         controller->SetFailed("ipc library provided incompatible controller object");
     109            1 :         done->Run();
     110            2 :         return;
     111              :     }
     112              : 
     113            5 :     auto ipcClient{ipcController->getClient()};
     114            5 :     int clientId{0};
     115            5 :     bool isNewClient{false};
     116              :     {
     117            5 :         std::lock_guard<std::mutex> lock{m_mutex};
     118            5 :         auto clientIdIter{m_clientIds.find(ipcClient)};
     119            5 :         if (clientIdIter != m_clientIds.end())
     120              :         {
     121            1 :             clientId = clientIdIter->second;
     122              :         }
     123              :         else
     124              :         {
     125            4 :             clientId = m_nextClientId.fetch_add(1);
     126            4 :             m_clientIds.emplace(ipcClient, clientId);
     127            4 :             m_ipcClients.emplace(clientId, ipcClient);
     128            4 :             isNewClient = true;
     129              :         }
     130            5 :     }
     131              : 
     132            5 :     if (!isNewClient)
     133              :     {
     134              :         // A retried ready notification is redundant: keep the existing collector and client ID.
     135            1 :         RIALTO_SERVER_LOG_INFO("Client already ready for private metrics samples with clientId=%d", clientId);
     136            1 :         done->Run();
     137            1 :         return;
     138              :     }
     139              : 
     140            4 :     RIALTO_SERVER_LOG_MIL("Client ready for private metrics samples, assigned clientId=%d", clientId);
     141            4 :     done->Run();
     142              : 
     143              :     // Create a shared_ptr to this as IMetricsCollectorClient, aliasing with shared_from_this()
     144              :     // so the IPC layer stays alive as long as the MetricsCollector holds a reference.
     145            4 :     auto self = shared_from_this();
     146              :     std::shared_ptr<firebolt::rialto::server::IMetricsCollectorClient>
     147            4 :         clientInterface(self, static_cast<firebolt::rialto::server::IMetricsCollectorClient *>(this));
     148            4 :     m_metricsService.clientReady(clientId, clientInterface);
     149            5 : }
     150              : 
     151            7 : void PrivateMetricsModuleService::reportClientMetrics(::google::protobuf::RpcController *controller,
     152              :                                                       const ::firebolt::rialto::ReportClientMetricsRequest *request,
     153              :                                                       ::firebolt::rialto::ReportClientMetricsResponse *response,
     154              :                                                       ::google::protobuf::Closure *done)
     155              : {
     156            7 :     RIALTO_SERVER_LOG_DEBUG("entry:");
     157            7 :     auto ipcController = dynamic_cast<firebolt::rialto::ipc::IController *>(controller);
     158            7 :     if (!ipcController)
     159              :     {
     160            1 :         RIALTO_SERVER_LOG_ERROR("ipc library provided incompatible controller object");
     161            2 :         controller->SetFailed("ipc library provided incompatible controller object");
     162            1 :         done->Run();
     163            3 :         return;
     164              :     }
     165            6 :     if (!request->has_metrics())
     166              :     {
     167            1 :         RIALTO_SERVER_LOG_ERROR("reportClientMetrics request missing metrics");
     168            2 :         controller->SetFailed("Missing metrics");
     169            1 :         done->Run();
     170            1 :         return;
     171              :     }
     172              : 
     173            5 :     auto ipcClient{ipcController->getClient()};
     174            5 :     int clientId{0};
     175              :     {
     176            5 :         std::lock_guard<std::mutex> lock{m_mutex};
     177            5 :         auto iter = m_clientIds.find(ipcClient);
     178            5 :         if (iter != m_clientIds.end())
     179              :         {
     180            4 :             clientId = iter->second;
     181              :         }
     182            5 :     }
     183              : 
     184            5 :     if (clientId == 0)
     185              :     {
     186            1 :         RIALTO_SERVER_LOG_WARN("reportClientMetrics from unknown client");
     187            1 :         done->Run();
     188            1 :         return;
     189              :     }
     190              : 
     191            4 :     const auto &protoMetrics{request->metrics()};
     192            4 :     firebolt::rialto::server::ClientMetricsData metrics;
     193            4 :     metrics.sampleId = protoMetrics.sample_id();
     194            4 :     metrics.appName = protoMetrics.app_name();
     195            4 :     metrics.processId = protoMetrics.process_id();
     196            4 :     metrics.monotonicTimeMs = protoMetrics.monotonic_time_ms();
     197            4 :     metrics.epochTimeMs = protoMetrics.epoch_time_ms();
     198            4 :     metrics.processCpuTimeMs = protoMetrics.process_cpu_time_ms();
     199            4 :     metrics.processMemoryKb = protoMetrics.process_memory_kb();
     200              : 
     201              :     // Convert proto reason to our enum
     202            4 :     switch (protoMetrics.reason())
     203              :     {
     204            1 :     case firebolt::rialto::METRICS_SAMPLE_REASON_CONNECTED:
     205            1 :         metrics.reason = firebolt::rialto::server::MetricsSampleReason::CONNECTED;
     206            1 :         break;
     207            1 :     case firebolt::rialto::METRICS_SAMPLE_REASON_PERIODIC:
     208            1 :         metrics.reason = firebolt::rialto::server::MetricsSampleReason::PERIODIC;
     209            1 :         break;
     210            1 :     case firebolt::rialto::METRICS_SAMPLE_REASON_STATE_TRANSITION:
     211            1 :         metrics.reason = firebolt::rialto::server::MetricsSampleReason::STATE_TRANSITION;
     212            1 :         break;
     213            1 :     default:
     214            1 :         metrics.reason = firebolt::rialto::server::MetricsSampleReason::UNKNOWN;
     215            1 :         break;
     216              :     }
     217              : 
     218            4 :     done->Run();
     219              : 
     220            4 :     m_metricsService.reportMetrics(clientId, metrics);
     221            5 : }
     222              : 
     223            1 : void PrivateMetricsModuleService::notifyApplicationStateChanged(ApplicationState newState)
     224              : {
     225            1 :     m_metricsService.notifyApplicationStateChanged(newState);
     226              : }
     227              : 
     228            6 : void PrivateMetricsModuleService::requestMetricsSample(int clientId, std::uint64_t sampleId,
     229              :                                                        firebolt::rialto::server::MetricsSampleReason reason)
     230              : {
     231            6 :     std::shared_ptr<::firebolt::rialto::ipc::IClient> ipcClient;
     232              :     {
     233            6 :         std::lock_guard<std::mutex> lock{m_mutex};
     234            6 :         auto iter = m_ipcClients.find(clientId);
     235            6 :         if (iter == m_ipcClients.end())
     236              :         {
     237            1 :             return;
     238              :         }
     239            5 :         ipcClient = iter->second;
     240            6 :     }
     241              : 
     242            5 :     if (!ipcClient || !ipcClient->isConnected())
     243              :     {
     244            1 :         return;
     245              :     }
     246              : 
     247            4 :     auto event{std::make_shared<firebolt::rialto::MetricsSampleRequestEvent>()};
     248            4 :     event->set_sample_id(sampleId);
     249              : 
     250              :     // Convert our enum to proto enum
     251            4 :     switch (reason)
     252              :     {
     253            1 :     case firebolt::rialto::server::MetricsSampleReason::CONNECTED:
     254            1 :         event->set_reason(firebolt::rialto::METRICS_SAMPLE_REASON_CONNECTED);
     255            1 :         break;
     256            1 :     case firebolt::rialto::server::MetricsSampleReason::PERIODIC:
     257            1 :         event->set_reason(firebolt::rialto::METRICS_SAMPLE_REASON_PERIODIC);
     258            1 :         break;
     259            1 :     case firebolt::rialto::server::MetricsSampleReason::STATE_TRANSITION:
     260            1 :         event->set_reason(firebolt::rialto::METRICS_SAMPLE_REASON_STATE_TRANSITION);
     261            1 :         break;
     262            1 :     default:
     263            1 :         event->set_reason(firebolt::rialto::METRICS_SAMPLE_REASON_UNKNOWN);
     264            1 :         break;
     265              :     }
     266              : 
     267            4 :     RIALTO_SERVER_LOG_DEBUG("Requesting metrics sample=%" PRIu64 " from client %d", sampleId, clientId);
     268              : 
     269            4 :     if (!ipcClient->sendEvent(event))
     270              :     {
     271            1 :         RIALTO_SERVER_LOG_DEBUG("Failed to request client metrics sample=%" PRIu64 " from client %d", sampleId, clientId);
     272              :     }
     273            6 : }
     274              : } // namespace firebolt::rialto::server::ipc
        

Generated by: LCOV version 2.0-1