* Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FUNCTION_PROXY_BUSPROXY_INSTANCE_PROXY_PERF_H
#define FUNCTION_PROXY_BUSPROXY_INSTANCE_PROXY_PERF_H
#include <chrono>
#include <memory>
#include <sstream>
#include "common/logs/logging.h"
#include "common/proto/pb/posix_pb.h"
namespace functionsystem::busproxy {
using TimePoint = std::chrono::time_point<std::chrono::high_resolution_clock>;
inline std::string GetDuration(TimePoint &end, TimePoint &start)
{
return std::to_string(std::chrono::duration<double, std::milli>(end - start).count());
}
struct PerfContext {
std::string traceID;
std::string requestID;
std::string dstInstance;
std::shared_ptr<TimePoint> grpcReceivedTime;
std::shared_ptr<TimePoint> proxyReceivedTime;
std::shared_ptr<TimePoint> proxySendCallTime;
std::shared_ptr<TimePoint> proxyReceivedCallRspTime;
std::shared_ptr<TimePoint> grpcReceivedCallResultTime;
std::shared_ptr<TimePoint> proxyReceivedCallResultTime;
std::shared_ptr<TimePoint> proxySendCallResultTime;
std::shared_ptr<TimePoint> proxyReceviedCallResultAckTime;
void LogPerf()
{
std::ostringstream oss;
perf|asyn call|send call cost|receive rsp cost|receive result cost|asyn result cost|send result cost|ack cost
perf|0.1|0.2|0.3|0.5|0.1|0.1|0.1|total|
*/
oss << "perf";
oss << "|"
<< ((grpcReceivedTime && proxyReceivedTime) ? GetDuration(*proxyReceivedTime, *grpcReceivedTime) : "nil");
oss << "|"
<< ((proxyReceivedTime && proxySendCallTime) ? GetDuration(*proxySendCallTime, *proxyReceivedTime) : "nil");
oss << "|"
<< ((proxySendCallTime && proxyReceivedCallRspTime)
? GetDuration(*proxyReceivedCallRspTime, *proxySendCallTime)
: "nil");
if (grpcReceivedCallResultTime) {
oss << "|"
<< ((proxySendCallTime && grpcReceivedCallResultTime)
? GetDuration(*grpcReceivedCallResultTime, *proxySendCallTime)
: "nil");
oss << "|"
<< ((grpcReceivedCallResultTime && proxyReceivedCallResultTime)
? GetDuration(*proxyReceivedCallResultTime, *grpcReceivedCallResultTime)
: "nil");
} else {
oss << "|"
<< ((proxySendCallTime && proxyReceivedCallResultTime)
? GetDuration(*proxyReceivedCallResultTime, *proxySendCallTime)
: "nil");
oss << "|nil";
}
oss << "|"
<< ((proxySendCallResultTime && proxyReceivedCallResultTime)
? GetDuration(*proxySendCallResultTime, *proxyReceivedCallResultTime)
: "nil");
oss << "||"
<< ((proxySendCallResultTime && proxyReceviedCallResultAckTime)
? GetDuration(*proxyReceviedCallResultAckTime, *proxySendCallResultTime)
: "nil");
if (grpcReceivedTime && proxySendCallResultTime) {
auto timeCost = std::chrono::duration<double, std::milli>(*(proxySendCallResultTime) - *(grpcReceivedTime));
oss << "|total|" << timeCost.count();
}
YRLOG_INFO("{}|{}|dstInstance({})|{}", traceID, requestID, dstInstance, oss.str());
}
};
class Perf {
public:
Perf() = default;
~Perf() = default;
inline void Record(const runtime::CallRequest &callReq, const std::string &dstInstance,
const std::shared_ptr<TimePoint> &time)
{
if (!enable_) {
return;
}
if (perfMap_.find(callReq.requestid()) == perfMap_.end()) {
auto perfCtx = std::make_shared<PerfContext>();
perfCtx->traceID = callReq.traceid();
perfCtx->requestID = callReq.requestid();
perfCtx->dstInstance = dstInstance;
perfMap_[callReq.requestid()] = perfCtx;
}
auto perfCtx = perfMap_[callReq.requestid()];
perfCtx->grpcReceivedTime = time;
perfCtx->proxyReceivedTime = std::make_shared<TimePoint>(std::chrono::high_resolution_clock::now());
}
inline void RecordReceivedCallRsp(const std::string &requestID)
{
if (!enable_) {
return;
}
if (auto iter = perfMap_.find(requestID); iter != perfMap_.end()) {
iter->second->proxyReceivedCallRspTime =
std::make_shared<TimePoint>(std::chrono::high_resolution_clock::now());
}
}
inline void RecordCallResult(const std::string &requestID, const std::shared_ptr<TimePoint> &time)
{
if (!enable_) {
return;
}
if (auto iter = perfMap_.find(requestID); iter != perfMap_.end()) {
iter->second->grpcReceivedCallResultTime = time;
iter->second->proxyReceivedCallResultTime =
std::make_shared<TimePoint>(std::chrono::high_resolution_clock::now());
}
}
inline std::shared_ptr<PerfContext> GetPerfContext(const std::string &requestID)
{
if (!enable_) {
return nullptr;
}
if (auto iter = perfMap_.find(requestID); iter != perfMap_.end()) {
return iter->second;
}
return nullptr;
}
inline void RecordSendCallResult(const std::string &requestID)
{
if (!enable_) {
return;
}
if (auto iter = perfMap_.find(requestID); iter != perfMap_.end()) {
iter->second->proxySendCallResultTime =
std::make_shared<TimePoint>(std::chrono::high_resolution_clock::now());
}
}
inline void RecordSendCall(const std::string &requestID)
{
if (!enable_) {
return;
}
if (auto iter = perfMap_.find(requestID); iter != perfMap_.end()) {
iter->second->proxySendCallTime = std::make_shared<TimePoint>(std::chrono::high_resolution_clock::now());
}
}
inline void EndRecord(const std::string &requestID)
{
if (!enable_) {
return;
}
if (auto iter = perfMap_.find(requestID); iter != perfMap_.end()) {
iter->second->proxyReceviedCallResultAckTime =
std::make_shared<TimePoint>(std::chrono::high_resolution_clock::now());
iter->second->LogPerf();
(void)perfMap_.erase(iter);
}
}
static void Enable(bool enable)
{
enable_ = enable;
}
private:
inline static std::atomic<bool> enable_{ false };
std::unordered_map<std::string, std::shared_ptr<PerfContext>> perfMap_;
};
}
#endif