Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 14 additions & 19 deletions cpp/include/tensorrt_llm/batch_manager/llmRequest.h
Original file line number Diff line number Diff line change
Expand Up @@ -1691,22 +1691,22 @@ class GenericLlmRequest
mDecodingIter = iter;
}

void setKvCacheTransferStart(TimePoint const& time)
void setKvCacheTransferStart(TimePoint time) const
{
mPerfMetrics.timingMetrics.kvCacheTransferStart = maybeToGlobalSteadyClock(time);
}

void setKvCacheTransferEnd(TimePoint const& time)
void setKvCacheTransferEnd(TimePoint time) const
{
mPerfMetrics.timingMetrics.kvCacheTransferEnd = maybeToGlobalSteadyClock(time);
}

TimePoint getKvCacheTransferStart()
TimePoint getKvCacheTransferStart() const
{
return mPerfMetrics.timingMetrics.kvCacheTransferStart;
}

TimePoint getKvCacheTransferEnd()
TimePoint getKvCacheTransferEnd() const
{
return mPerfMetrics.timingMetrics.kvCacheTransferEnd;
}
Expand Down Expand Up @@ -1865,13 +1865,11 @@ class GenericLlmRequest
return mUseDraftModel;
}

// If mGlobalSteadyClockOffset is set, return a global steady clock time point, otherwise return local steady clock
// If sGlobalSteadyClockOffset is set, return a global steady clock time point, otherwise return local steady clock
// time point
[[nodiscard]] TimePoint getSteadyClockNow() const
[[nodiscard]] static TimePoint getSteadyClockNow()
{
const TimePoint time_point = std::chrono::steady_clock::now();

return maybeToGlobalSteadyClock(time_point);
return maybeToGlobalSteadyClock(std::chrono::steady_clock::now());
}

RequestIdType mRequestId;
Expand All @@ -1894,7 +1892,7 @@ class GenericLlmRequest
SizeType32 mPtableCurrentPosition{0};

// The offset between local steady clock and global steady clock (at rank 0)
inline static std::optional<Duration> mGlobalSteadyClockOffset{std::nullopt};
inline static std::optional<Duration> sGlobalSteadyClockOffset{std::nullopt};

protected:
bool mIsStreaming;
Expand Down Expand Up @@ -2028,9 +2026,9 @@ class GenericLlmRequest

std::optional<TensorPtr> mSkipCrossAttnBlocks{std::nullopt};

// Performance metrics.
// Performance metrics. Should be updatable even from a const LlmRequest reference.
bool mReturnPerfMetrics{false};
executor::RequestPerfMetrics mPerfMetrics;
mutable executor::RequestPerfMetrics mPerfMetrics;

// Guided decoding params.
std::optional<executor::GuidedDecodingParams> mGuidedDecodingParams{std::nullopt};
Expand Down Expand Up @@ -2183,16 +2181,13 @@ class GenericLlmRequest
return tensor;
}

TimePoint maybeToGlobalSteadyClock(TimePoint const& time_point) const
static TimePoint maybeToGlobalSteadyClock(TimePoint const& time_point)
{
if (mGlobalSteadyClockOffset.has_value())
{
return time_point + *mGlobalSteadyClockOffset;
}
else
if (sGlobalSteadyClockOffset.has_value())
{
return time_point;
return time_point + *sGlobalSteadyClockOffset;
}
return time_point;
}
};

Expand Down
2 changes: 1 addition & 1 deletion cpp/include/tensorrt_llm/executor/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,7 @@ struct RequestPerfMetrics
/// @brief End time of the KV cache transfer for disaggregated serving
TimePoint kvCacheTransferEnd;
/// @brief KV Cache size transfer for disaggregated serving
mutable size_t kvCacheSize = 0;
size_t kvCacheSize = 0;
};

struct KvCacheMetrics
Expand Down
40 changes: 14 additions & 26 deletions cpp/tensorrt_llm/batch_manager/cacheFormatter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ std::vector<size_t> CacheFormatter::pickRecvConnections(
void CacheFormatter::format(tensorrt_llm::batch_manager::TransferSession& session)
{
NVTX3_SCOPED_RANGE(CacheFormatter_format);
session.setTime(TransferSession::kTimeFormatter);
auto const& llmRequest = session.getLlmRequest();
TLLM_LOG_DEBUG(
mpi::MpiComm::world().getRank(), "Start sending KV cache for request ID: %ld.", llmRequest.mRequestId);
Expand All @@ -249,9 +250,6 @@ void CacheFormatter::format(tensorrt_llm::batch_manager::TransferSession& sessio
auto const numPools = blockManager.getNumPools();
// TODO(oargov): are we sure the other side has the same number of pools? this might not hold for pp_size>1...

auto lastTokenTime = llmRequest.getPerfMetrics().timingMetrics.lastTokenTime;
bool recordDelay = lastTokenTime != std::chrono::steady_clock::time_point();

bool layerWise = common::getEnvDisaggLayerwise() && numPools == 1;
if (layerWise)
{
Expand Down Expand Up @@ -420,6 +418,7 @@ void CacheFormatter::format(tensorrt_llm::batch_manager::TransferSession& sessio
inputKvCacheBlocksPerWindow, outputSplitCaches, destConfig, selfConfig, selfIdx, bufferManager);

bufferManager.getStream().synchronize();
session.setTime(TransferSession::kTimePreprocess);

auto preAllocSendBuffer = mCacheTransBufferManager->getSendBuffer(cacheBufferId);
if (preAllocSendBuffer != nullptr)
Expand All @@ -434,7 +433,7 @@ void CacheFormatter::format(tensorrt_llm::batch_manager::TransferSession& sessio
TLLM_CUDA_CHECK(cudaSetDevice(deviceId));
TLLM_CHECK(connections.size() > (processIdx / peerDuplicateHeadFactor));
TLLM_CHECK(outputSplitCaches.size() > (processIdx / peerDuplicateHeadFactor));
auto startTime = llmRequest.getSteadyClockNow();
auto startTime = LlmRequest::getSteadyClockNow();

size_t ppDomainSize = targetInfo.mDomainPPSize;
size_t bufferTpRank = (processIdx / ppDomainSize) / peerDuplicateHeadFactor;
Expand Down Expand Up @@ -481,15 +480,8 @@ void CacheFormatter::format(tensorrt_llm::batch_manager::TransferSession& sessio
}
}

auto endTime = llmRequest.getSteadyClockNow();
double delay = 0.0;
if (recordDelay)
{
delay = std::chrono::duration<double, std::milli>(startTime - lastTokenTime).count();
}
double cacheTransferTime
= std::max(0.0, std::chrono::duration<double, std::milli>(endTime - startTime).count());
session.appendMeasure(delay, cacheTransferTime, size);
auto endTime = LlmRequest::getSteadyClockNow();
session.appendMeasure(startTime, endTime, size);
};

if (connections.size() > 1)
Expand Down Expand Up @@ -534,8 +526,10 @@ void CacheFormatter::format(tensorrt_llm::batch_manager::TransferSession& sessio
{
sendBufferFun(deviceId, 0);
}
session.setTime(TransferSession::kTimeTransmissions);

mCacheTransBufferManager->freeBufferIndexForSend(cacheBufferId);
session.setTime(TransferSession::kTimePostprocess);
}
TLLM_LOG_DEBUG(
mpi::MpiComm::world().getRank(), "End the sending of KV cache for the request ID:%ld ", llmRequest.mRequestId);
Expand All @@ -544,6 +538,7 @@ void CacheFormatter::format(tensorrt_llm::batch_manager::TransferSession& sessio
void CacheFormatter::unformat(tensorrt_llm::batch_manager::TransferSession& session)
{
NVTX3_SCOPED_RANGE(CacheFormatter_unformat);
session.setTime(TransferSession::kTimeFormatter);
auto const& llmRequest = session.getLlmRequest();
auto const ctxReqId = llmRequest.getContextPhaseParams().value().getReqId();
TLLM_LOG_DEBUG(mpi::MpiComm::world().getRank(),
Expand All @@ -555,9 +550,6 @@ void CacheFormatter::unformat(tensorrt_llm::batch_manager::TransferSession& sess
auto& bufferManager = session.getBufferManager();
auto blockRange = getBlockRangeForReceiving(mCacheManager, llmRequest, destConfig.getEnableBlockReuse());

auto arrivalTime = llmRequest.getPerfMetrics().timingMetrics.arrivalTime;
bool recordDelay = arrivalTime != std::chrono::steady_clock::time_point();

auto pickUpConnections = pickRecvConnections(connections.size(), selfConfig, selfIdx, destConfig);

TLLM_LOG_DEBUG("pickUpConnections size: %d connections size: %d", pickUpConnections.size(), connections.size());
Expand Down Expand Up @@ -779,6 +771,7 @@ void CacheFormatter::unformat(tensorrt_llm::batch_manager::TransferSession& sess
// sync to alloc buffer
bufferManager.getStream().synchronize();
}
session.setTime(TransferSession::kTimePreprocess);

runtime::ITensor::SharedPtr preAllocRecvBuffer = nullptr;
if (cacheBufferId.has_value())
Expand All @@ -794,7 +787,7 @@ void CacheFormatter::unformat(tensorrt_llm::batch_manager::TransferSession& sess
TLLM_CUDA_CHECK(cudaSetDevice(deviceId));
TLLM_CHECK(pickUpConnections.size() > processIdx);
TLLM_CHECK(recvSplitCaches.size() > processIdx);
auto startTime = llmRequest.getSteadyClockNow();
auto startTime = LlmRequest::getSteadyClockNow();
size_t size = 0;

if (processIdx >= remainNoCoverTargetNum)
Expand Down Expand Up @@ -835,15 +828,8 @@ void CacheFormatter::unformat(tensorrt_llm::batch_manager::TransferSession& sess
}
}

auto endTime = llmRequest.getSteadyClockNow();
double delay = 0.0;
if (recordDelay)
{
delay = std::chrono::duration<double, std::milli>(startTime - arrivalTime).count();
}
double cacheTransferTime
= std::max(0.0, std::chrono::duration<double, std::milli>(endTime - startTime).count());
session.appendMeasure(delay, cacheTransferTime, size);
auto endTime = LlmRequest::getSteadyClockNow();
session.appendMeasure(startTime, endTime, size);
};
if (pickUpConnections.size() > 1)
{
Expand Down Expand Up @@ -891,6 +877,7 @@ void CacheFormatter::unformat(tensorrt_llm::batch_manager::TransferSession& sess
{
recvBufferFun(deviceId, 0);
}
session.setTime(TransferSession::kTimeTransmissions);

{
NVTX3_SCOPED_RANGE(formatInputConcatenate);
Expand All @@ -904,6 +891,7 @@ void CacheFormatter::unformat(tensorrt_llm::batch_manager::TransferSession& sess
mCacheTransBufferManager->freeBufferIndexForRecv(cacheBufferId);
}
}
session.setTime(TransferSession::kTimePostprocess);
}
}

Expand Down
2 changes: 1 addition & 1 deletion cpp/tensorrt_llm/batch_manager/cacheTransceiver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -603,7 +603,7 @@ void CacheTransceiver::checkGenTransferStatus(std::optional<int> const& atLeastR
it->first->setState(LlmRequestState::kDISAGG_GENERATION_TRANS_COMPLETE);

// Gather the kv cache transfer time from all workers and update to leader rank
if (!common::getEnvKVCacheTransferOutputPath().empty())
if (!common::getEnvKVCacheTimeOutputPath().empty())
{
auto syncComm = mCacheState->getParallelConfig().mEnableAttentionDP ? mGroupDataComm : mGroupComm;
updateKVCacheTransferBW(syncComm, it->first);
Expand Down
65 changes: 48 additions & 17 deletions cpp/tensorrt_llm/batch_manager/dataTransceiver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "tensorrt_llm/executor/cache_transmission/agent_utils/connection.h"
#include "tensorrt_llm/runtime/common.h"
#include "tensorrt_llm/runtime/utils/mpiUtils.h"
#include <chrono>
#include <future>
#include <map>
#include <memory>
Expand Down Expand Up @@ -105,39 +106,65 @@ void TransferSession::setLlmRequest(LlmRequest const& llmRequest)
mRequest = &llmRequest;
}

void TransferSession::appendMeasure(double delay, double duration, size_t size)
void TransferSession::setTime(TimeNames name)
{
if (!mRecordMeasure)
if (mTimes)
{
return;
mTimes->times.at(name) = LlmRequest::getSteadyClockNow();
}
}

void TransferSession::appendMeasure(LlmRequest::TimePoint start, LlmRequest::TimePoint end, size_t size)
{
if (mTimes)
{
mTimes->measures.emplace_back(Measure{start, end, size});
}
auto bandwidth = size * 8 / (duration / 1000) / 1e9; // byte, ms => Gbps
mMeasures.emplace_back(Measure{delay, duration, bandwidth});
}

void TransferSession::exportMeasure(std::ofstream& outFile, bool isContext) const
{
if (mMeasures.empty())
if (!mTimes || mTimes->measures.empty())
{
return;
}
// write header if not exist
if (outFile.tellp() == 0)
{
outFile << "RequestID";
for (size_t i = 0; i < mMeasures.size(); i++)
outFile << "RequestID,RequestInfo,Preparation,Preprocess,Transmissions,Postprocess";
for (size_t i = 0; i < mTimes->measures.size(); i++)
{
outFile << ",Delay(ms),Duration(ms),Bandwidth(Gbps)";
outFile << ",Delay,Duration,Bandwidth(Gbps)";
}
outFile << '\n';
}
// write measures
auto transferStart = mRequest->getPerfMetrics().timingMetrics.kvCacheTransferStart;
using Milliseconds = std::chrono::duration<double, std::milli>;

// write measures, time is in milliseconds
TLLM_CHECK(isContext || mRequest->getContextPhaseParams().has_value());
auto reqId = isContext ? mRequest->mRequestId : mRequest->getContextPhaseParams().value().getReqId();
outFile << reqId;
for (auto const& measure : mMeasures)
auto previousTime = transferStart;
for (auto time : mTimes->times)
{
if (time == LlmRequest::TimePoint())
{
// timepoint is unset, skip
outFile << ",0.0";
continue;
}
double delay = Milliseconds(time - previousTime).count();
previousTime = time;
outFile << "," << delay;
}
previousTime = mTimes->times[kTimePreprocess];
for (auto const& measure : mTimes->measures)
{
outFile << "," << measure.delay << "," << measure.duration << "," << measure.bandwidth;
double delay = Milliseconds(measure.start - previousTime).count();
double duration = Milliseconds(measure.end - measure.start).count();
double bandwidth = static_cast<double>(measure.size) * 8.0 / duration / 1e6; // byte, ms => Gbps
outFile << "," << delay << "," << duration << "," << bandwidth;
}
outFile << '\n' << std::flush;
}
Expand All @@ -158,7 +185,7 @@ int32_t tagFromRequestId(LlmRequest::RequestIdType requestId)
std::filesystem::path getTransferOutputPath(char const* tag)
{
namespace fs = std::filesystem;
auto outputPath = common::getEnvKVCacheTransferOutputPath();
auto outputPath = common::getEnvKVCacheTimeOutputPath();
if (!outputPath.empty())
{
auto rank = mpi::MpiComm::world().getRank();
Expand Down Expand Up @@ -273,6 +300,7 @@ class CacheSender::Impl
{
std::promise<void> promise;
auto future = promise.get_future();
llmRequest.setKvCacheTransferStart(LlmRequest::getSteadyClockNow());
{
{
std::scoped_lock lkResp(mSenderMutex);
Expand Down Expand Up @@ -309,7 +337,7 @@ class CacheSender::Impl
std::unique_lock<std::mutex> lk(mMtxForMap);
auto it = mRequestToSession.find(requestId);
TLLM_CHECK(it != mRequestToSession.end());
if (!common::getEnvKVCacheTransferOutputPath().empty())
if (!common::getEnvKVCacheTimeOutputPath().empty())
{
if (!mMeasuresFile.is_open())
{
Expand Down Expand Up @@ -363,7 +391,8 @@ class CacheSender::Impl
auto session = TransferSession(std::vector<Connection const*>(peerRelativeRanks.size(), nullptr),
DataContext{tagFromRequestId(requestId)}, mSelfState, info.getTransState(), mBufferManager,
info.getIndexFromEnd(), info.getLastBlockKey(), nullptr,
!common::getEnvKVCacheTransferOutputPath().empty());
!common::getEnvKVCacheTimeOutputPath().empty());
session.setTime(TransferSession::kTimeRequestInfo);
it = mRequestToSession.emplace(requestId, std::move(session)).first;
}
it->second.setConnection(peerIdx, connection);
Expand All @@ -382,6 +411,7 @@ class CacheSender::Impl
}
session->setLlmRequest(llmRequest);
mFormatter->format(*session);
llmRequest.setKvCacheTransferEnd(LlmRequest::getSteadyClockNow());
}

bool cancelRequest(LlmRequest const& llmRequest)
Expand Down Expand Up @@ -751,7 +781,7 @@ class CacheReceiver::Impl
void receiveSync(TransferSession& session)
{
mFormatter->unformat(session);
if (!common::getEnvKVCacheTransferOutputPath().empty())
if (!common::getEnvKVCacheTimeOutputPath().empty())
{
std::unique_lock<std::mutex> lock(mMeasuresFileMutex);
if (!mMeasuresFile.is_open())
Expand Down Expand Up @@ -846,7 +876,7 @@ class CacheReceiver::Impl
auto const& resource = getReceiveCacheResource(llmRequest);
return TransferSession(std::move(counterPartConnections), DataContext{tagFromRequestId(requestId)}, mSelfState,
contextState, resource->mBufferManager, requestInfo.getIndexFromEnd(), requestInfo.getLastBlockKey(),
&llmRequest, !common::getEnvKVCacheTransferOutputPath().empty());
&llmRequest, !common::getEnvKVCacheTimeOutputPath().empty());
}

std::unique_ptr<ReceiveCacheResource> const& getReceiveCacheResource(LlmRequest const& llmRequest)
Expand Down Expand Up @@ -957,6 +987,7 @@ class CacheReceiver::Impl
llmRequest.setKvCacheTransferStart(std::chrono::steady_clock::now());
TLLM_CUDA_CHECK(cudaSetDevice(mDeviceId));
auto session = sendRequestInfo(llmRequest);
session.setTime(TransferSession::kTimeRequestInfo);
bool isReady = receiveReadySignal(session);
if (!isReady)
{
Expand Down
Loading