LCOV - code coverage report
Current view: top level - media/client/ipc/source - PrivateMetricsIpc.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 79.6 % 98 78
Test Date: 2026-09-11 17:36:12 Functions: 91.7 % 12 11

            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 "PrivateMetricsIpc.h"
      21              : #include "IpcClient.h"
      22              : #include "RialtoClientLogging.h"
      23              : #include <cinttypes>
      24              : #include <unistd.h>
      25              : 
      26              : namespace
      27              : {
      28            4 : const char *sampleReasonToString(::firebolt::rialto::MetricsSampleReason reason)
      29              : {
      30            4 :     switch (reason)
      31              :     {
      32            1 :     case firebolt::rialto::METRICS_SAMPLE_REASON_CONNECTED:
      33            1 :         return "CONNECTED";
      34            2 :     case firebolt::rialto::METRICS_SAMPLE_REASON_PERIODIC:
      35            2 :         return "PERIODIC";
      36            1 :     case firebolt::rialto::METRICS_SAMPLE_REASON_STATE_TRANSITION:
      37            1 :         return "STATE_TRANSITION";
      38            0 :     case firebolt::rialto::METRICS_SAMPLE_REASON_UNKNOWN:
      39              :     default:
      40            0 :         return "UNKNOWN";
      41              :     }
      42              : }
      43              : } // namespace
      44              : 
      45              : namespace firebolt::rialto::client
      46              : {
      47            1 : std::shared_ptr<IPrivateMetricsIpcFactory> IPrivateMetricsIpcFactory::createFactory()
      48              : {
      49            1 :     return PrivateMetricsIpcFactory::createFactory();
      50              : }
      51              : 
      52            1 : std::shared_ptr<PrivateMetricsIpcFactory> PrivateMetricsIpcFactory::createFactory()
      53              : {
      54            1 :     std::shared_ptr<PrivateMetricsIpcFactory> factory;
      55              : 
      56              :     try
      57              :     {
      58            1 :         factory = std::make_shared<PrivateMetricsIpcFactory>();
      59              :     }
      60            0 :     catch (const std::exception &e)
      61              :     {
      62            0 :         RIALTO_CLIENT_LOG_ERROR("Failed to create the rialto private metrics ipc factory, reason: %s", e.what());
      63              :     }
      64              : 
      65            1 :     return factory;
      66              : }
      67              : 
      68            0 : std::shared_ptr<IPrivateMetricsIpc> PrivateMetricsIpcFactory::createPrivateMetricsIpc(IPrivateMetricsIpcClient *client)
      69              : {
      70            0 :     auto &ipcClient{IIpcClientAccessor::instance().getIpcClient()};
      71            0 :     return std::make_shared<PrivateMetricsIpc>(client, ipcClient,
      72            0 :                                                firebolt::rialto::common::IEventThreadFactory::createFactory());
      73              : }
      74              : 
      75            2 : PrivateMetricsIpc::PrivateMetricsIpc(IPrivateMetricsIpcClient *client, IIpcClient &ipcClient,
      76            2 :                                      const std::shared_ptr<common::IEventThreadFactory> &eventThreadFactory)
      77            2 :     : IpcModule(ipcClient), m_privateMetricsIpcClient{client},
      78            6 :       m_eventThread(eventThreadFactory->createEventThread("rialto-metrics-events"))
      79              : {
      80            2 :     RIALTO_CLIENT_LOG_MIL("Initialising private metrics IPC, pid=%d", getpid());
      81            2 :     if (!attachChannel())
      82              :     {
      83            0 :         throw std::runtime_error("Failed attach to the ipc channel");
      84              :     }
      85            2 :     if (!notifyClientReady())
      86              :     {
      87            0 :         throw std::runtime_error("Failed to notify private metrics readiness");
      88              :     }
      89            2 : }
      90              : 
      91            4 : PrivateMetricsIpc::~PrivateMetricsIpc()
      92              : {
      93            2 :     RIALTO_CLIENT_LOG_MIL("Terminating private metrics IPC, pid=%d", getpid());
      94            2 :     detachChannel();
      95            2 :     m_eventThread.reset();
      96            4 : }
      97              : 
      98            2 : bool PrivateMetricsIpc::reportClientMetrics(std::uint64_t sampleId, std::uint32_t reason, const std::string &appName,
      99              :                                             std::uint32_t processId, std::uint64_t monotonicTimeMs,
     100              :                                             std::uint64_t epochTimeMs, std::uint64_t processCpuTimeMs,
     101              :                                             std::uint64_t processMemoryKb)
     102              : {
     103            2 :     if (!reattachChannelIfRequired())
     104              :     {
     105            0 :         RIALTO_CLIENT_LOG_ERROR("Reattachment of the ipc channel failed, ipc disconnected");
     106            0 :         return false;
     107              :     }
     108              : 
     109            2 :     firebolt::rialto::ReportClientMetricsRequest request;
     110            2 :     auto metrics{request.mutable_metrics()};
     111            2 :     metrics->set_sample_id(sampleId);
     112            2 :     metrics->set_reason(static_cast<firebolt::rialto::MetricsSampleReason>(reason));
     113              :     metrics->set_app_name(appName);
     114            2 :     metrics->set_process_id(processId);
     115            2 :     metrics->set_monotonic_time_ms(monotonicTimeMs);
     116            2 :     metrics->set_epoch_time_ms(epochTimeMs);
     117            2 :     metrics->set_process_cpu_time_ms(processCpuTimeMs);
     118            2 :     metrics->set_process_memory_kb(processMemoryKb);
     119              : 
     120            2 :     RIALTO_CLIENT_LOG_DEBUG("Reporting metrics sample=%" PRIu64 ", reason=%s, app='%s', pid=%u, cpu_ms=%" PRIu64
     121              :                             ", mem_kb=%" PRIu64,
     122              :                             sampleId, sampleReasonToString(static_cast<firebolt::rialto::MetricsSampleReason>(reason)),
     123              :                             appName.c_str(), processId, processCpuTimeMs, processMemoryKb);
     124              : 
     125            2 :     firebolt::rialto::ReportClientMetricsResponse response;
     126            2 :     auto ipcController = m_ipc.createRpcController();
     127            2 :     auto blockingClosure = m_ipc.createBlockingClosure();
     128            2 :     m_privateMetricsStub->reportClientMetrics(ipcController.get(), &request, &response, blockingClosure.get());
     129              : 
     130            2 :     blockingClosure->wait();
     131              : 
     132            2 :     if (ipcController->Failed())
     133              :     {
     134            1 :         RIALTO_CLIENT_LOG_DEBUG("Failed to report client metrics due to '%s'", ipcController->ErrorText().c_str());
     135            1 :         return false;
     136              :     }
     137              : 
     138            1 :     RIALTO_CLIENT_LOG_DEBUG("Reported metrics sample=%" PRIu64 ", reason=%s", sampleId,
     139              :                             sampleReasonToString(static_cast<firebolt::rialto::MetricsSampleReason>(reason)));
     140              : 
     141            1 :     return true;
     142            2 : }
     143              : 
     144            2 : bool PrivateMetricsIpc::notifyClientReady()
     145              : {
     146            2 :     if (!reattachChannelIfRequired())
     147              :     {
     148            0 :         RIALTO_CLIENT_LOG_ERROR("Reattachment of the ipc channel failed, ipc disconnected");
     149            0 :         return false;
     150              :     }
     151              : 
     152            2 :     RIALTO_CLIENT_LOG_MIL("Notifying server that private metrics IPC is ready, pid=%d", getpid());
     153              : 
     154            2 :     firebolt::rialto::NotifyClientReadyRequest request;
     155            2 :     firebolt::rialto::NotifyClientReadyResponse response;
     156            2 :     auto ipcController = m_ipc.createRpcController();
     157            2 :     auto blockingClosure = m_ipc.createBlockingClosure();
     158            2 :     m_privateMetricsStub->notifyClientReady(ipcController.get(), &request, &response, blockingClosure.get());
     159              : 
     160            2 :     blockingClosure->wait();
     161              : 
     162            2 :     if (ipcController->Failed())
     163              :     {
     164            0 :         RIALTO_CLIENT_LOG_ERROR("failed to notify private metrics readiness due to '%s'",
     165              :                                 ipcController->ErrorText().c_str());
     166            0 :         return false;
     167              :     }
     168              : 
     169            2 :     RIALTO_CLIENT_LOG_MIL("Server acknowledged private metrics IPC readiness, pid=%d", getpid());
     170              : 
     171            2 :     return true;
     172              : }
     173              : 
     174            2 : bool PrivateMetricsIpc::createRpcStubs(const std::shared_ptr<ipc::IChannel> &ipcChannel)
     175              : {
     176            2 :     m_privateMetricsStub = std::make_shared<::firebolt::rialto::PrivateMetricsModule_Stub>(ipcChannel.get());
     177            2 :     return static_cast<bool>(m_privateMetricsStub);
     178              : }
     179              : 
     180            2 : bool PrivateMetricsIpc::subscribeToEvents(const std::shared_ptr<ipc::IChannel> &ipcChannel)
     181              : {
     182            2 :     if (!ipcChannel)
     183              :     {
     184            0 :         return false;
     185              :     }
     186              : 
     187            4 :     int eventTag = ipcChannel->subscribe<firebolt::rialto::MetricsSampleRequestEvent>(
     188            2 :         [this](const std::shared_ptr<firebolt::rialto::MetricsSampleRequestEvent> &event)
     189            3 :         { m_eventThread->add(&PrivateMetricsIpc::onMetricsSampleRequested, this, event); });
     190            2 :     if (eventTag < 0)
     191              :     {
     192            0 :         return false;
     193              :     }
     194            2 :     m_eventTags.push_back(eventTag);
     195              : 
     196            2 :     RIALTO_CLIENT_LOG_MIL("Subscribed to private metrics sample requests, pid=%d, event_tag=%d", getpid(), eventTag);
     197              : 
     198            2 :     return true;
     199              : }
     200              : 
     201            1 : void PrivateMetricsIpc::onMetricsSampleRequested(const std::shared_ptr<firebolt::rialto::MetricsSampleRequestEvent> &event)
     202              : {
     203            1 :     if (!m_privateMetricsIpcClient)
     204              :     {
     205            0 :         RIALTO_CLIENT_LOG_WARN("No private metrics client registered");
     206            0 :         return;
     207              :     }
     208            1 :     RIALTO_CLIENT_LOG_DEBUG("Received metrics sample request sample=%" PRIu64 ", reason=%s, pid=%d", event->sample_id(),
     209              :                             sampleReasonToString(event->reason()), getpid());
     210            1 :     m_privateMetricsIpcClient->reportClientMetrics(event->sample_id(), event->reason());
     211              : }
     212              : } // namespace firebolt::rialto::client
        

Generated by: LCOV version 2.0-1