mirror of
https://github.com/wolfpld/tracy
synced 2025-01-15 20:08:00 +00:00
Compare commits
10 Commits
cb0bc67790
...
959ddc3501
Author | SHA1 | Date | |
---|---|---|---|
|
959ddc3501 | ||
|
0414473c9f | ||
|
92ae003308 | ||
|
ab830962c8 | ||
|
fe71ae3272 | ||
|
068141abfc | ||
|
7f1f929662 | ||
|
8ea02a4794 | ||
|
6b2de1c8b5 | ||
|
3005d5a939 |
5
NEWS
5
NEWS
@ -22,10 +22,11 @@ v0.x.x (xxxx-xx-xx)
|
||||
- Vulkan contexts can be now calibrated on Linux.
|
||||
- Support loading zstd-compressed chrome traces.
|
||||
- Chrome traces with multiple PID entries (and possibly conflicting TIDs)
|
||||
can be now imported. A pseudo-TID will be created for each PID+TID pair
|
||||
in such circumstances.
|
||||
can be now imported.
|
||||
- Added support for custom source location tag ("loc") in chrome traces.
|
||||
- Sampling frequency can be now controlled using TRACY_SAMPLING_HZ macro.
|
||||
- Trace compression can be now selected when saving a trace.
|
||||
- If a trace cannot be saved, a failure dialog will be displayed.
|
||||
|
||||
|
||||
v0.7.7 (2021-04-01)
|
||||
|
@ -135,10 +135,11 @@ int main( int argc, char** argv )
|
||||
|
||||
// encode a pair of "real pid, real tid" from a trace into a
|
||||
// pseudo thread ID living in the single namespace of Tracy threads.
|
||||
struct PidTidEncoder {
|
||||
uint64_t tid;
|
||||
uint64_t pid;
|
||||
uint64_t pseudo_tid; // fake thread id, unique within Tracy
|
||||
struct PidTidEncoder
|
||||
{
|
||||
uint64_t tid;
|
||||
uint64_t pid;
|
||||
uint64_t pseudo_tid; // fake thread id, unique within Tracy
|
||||
};
|
||||
|
||||
std::vector<PidTidEncoder> tid_encoders;
|
||||
@ -150,24 +151,27 @@ int main( int argc, char** argv )
|
||||
const auto getPseudoTid = [&](json& val) -> uint64_t {
|
||||
const auto real_tid = val["tid"].get<uint64_t>();
|
||||
|
||||
if ( val.contains( "pid" ) ) {
|
||||
if( val.contains( "pid" ) )
|
||||
{
|
||||
// there might be multiple processes so we allocate a pseudo-tid
|
||||
// for each pair (pid, real_tid)
|
||||
const auto pid = val["pid"].get<uint64_t>();
|
||||
|
||||
for ( auto &pair : tid_encoders) {
|
||||
if ( pair.pid == pid && pair.tid == real_tid ) {
|
||||
return pair.pseudo_tid;
|
||||
}
|
||||
for ( auto &pair : tid_encoders)
|
||||
{
|
||||
if( pair.pid == pid && pair.tid == real_tid ) return pair.pseudo_tid;
|
||||
}
|
||||
|
||||
const auto pseudo_tid = tid_encoders.size();
|
||||
assert( pid <= std::numeric_limits<uint32_t>::max() );
|
||||
assert( real_tid <= std::numeric_limits<uint32_t>::max() );
|
||||
|
||||
const auto pseudo_tid = ( real_tid & 0xFFFFFFFF ) | ( pid << 32 );
|
||||
tid_encoders.emplace_back(PidTidEncoder {real_tid, pid, pseudo_tid});
|
||||
return pseudo_tid;
|
||||
}
|
||||
else
|
||||
{
|
||||
return real_tid;
|
||||
return real_tid;
|
||||
}
|
||||
};
|
||||
|
||||
@ -187,14 +191,12 @@ int main( int argc, char** argv )
|
||||
const auto type = v["ph"].get<std::string>();
|
||||
|
||||
std::string zoneText = "";
|
||||
if ( v.contains( "args" ) )
|
||||
if( v.contains( "args" ) )
|
||||
{
|
||||
for ( auto& kv : v["args"].items() )
|
||||
for( auto& kv : v["args"].items() )
|
||||
{
|
||||
const auto val = kv.value();
|
||||
const std::string s =
|
||||
val.is_string() ?
|
||||
val.get<std::string>() : val.dump();
|
||||
const std::string s = val.is_string() ? val.get<std::string>() : val.dump();
|
||||
zoneText += kv.key() + ": " + s + "\n";
|
||||
}
|
||||
}
|
||||
|
@ -1960,7 +1960,7 @@ Both connecting to a client and opening a saved trace will present you with the
|
||||
|
||||
If this is a real-time capture, you will also have access to the connection information pop-up (figure~\ref{connectioninfo}) through the \emph{\faWifi{}~Connection} button, with the capture status similar to the one displayed by the command line utility. This dialog also displays the connection speed graphed over time and the profiled application's current frames per second and frame time measurements. The \emph{Query backlog} consists of two numbers. The first one represents the number of queries that were held back due to the bandwidth volume overwhelming the available network send buffer. The second one shows how many queries are in-flight, meaning requests which were sent to the client, but weren't yet answered. While these numbers drains down to zero, the performance of real time profiling may be temporarily compromised. The circle displayed next to the bandwidth graph signals the connection status. If it's red, the connection is active. If it's gray, the client has disconnected.
|
||||
|
||||
You can use the \faSave{}~\emph{Save trace} button to save the current profile data to a file\footnote{This should be taken literally. If a live capture is in progress and a save is performed, some data may be missing from the capture and won't be saved.}. Use the \faPlug{}~\emph{Stop} button to disconnect from the client\footnote{While requesting disconnect stops retrieval of any new events, the profiler will wait for any data that is still pending for the current set of events.}. The \faExclamationTriangle{}~\emph{Discard} button is used to discard current trace.
|
||||
You can use the \faSave{}~\emph{Save trace} button to save the current profile data to a file\footnote{This should be taken literally. If a live capture is in progress and a save is performed, some data may be missing from the capture and won't be saved.}. The available compression modes are discussed in section~\ref{archival}. Use the \faPlug{}~\emph{Stop} button to disconnect from the client\footnote{While requesting disconnect stops retrieval of any new events, the profiler will wait for any data that is still pending for the current set of events.}. The \faExclamationTriangle{}~\emph{Discard} button is used to discard current trace.
|
||||
|
||||
\begin{figure}[h]
|
||||
\centering\begin{tikzpicture}
|
||||
@ -2017,6 +2017,7 @@ old.tracy (0.3.0) {916.4 MB} -> new.tracy (0.4.0) {349.4 MB, 31.53%} 9.7 s, 38.
|
||||
The new file contains the same data as the old one, but in the updated internal representation. Note that to perform an upgrade, whole trace needs to be loaded to memory.
|
||||
|
||||
\subsubsection{Archival mode}
|
||||
\label{archival}
|
||||
|
||||
The \texttt{update} utility supports optional higher levels of data compression, which reduce disk size of traces, at the cost of increased compression times. With the default settings, the output files have a reasonable size and are quick to save and load. A list of available compression modes and their respective results is available in table~\ref{compressiontimes} and figures~\ref{savesize}, \ref{savetime} and~\ref{loadtime}. Compression mode selection is controlled by the following command line options:
|
||||
|
||||
@ -3401,7 +3402,7 @@ couleur=black!5,
|
||||
logo=\bcattention
|
||||
]{Limitations}
|
||||
\begin{itemize}
|
||||
\item Tracy is a single-process profiler. Should the imported trace contain PID entries, each PID+TID pair will create a new \emph{pseudo-TID} number. If you want to preserve the original TID numbers, your traces should omit PID entries.
|
||||
\item Tracy is a single-process profiler. Should the imported trace contain PID entries, each PID+TID pair will create a new \emph{pseudo-TID} number, which will be then decoded into a PID+TID pair in thread labels. If you want to preserve the original TID numbers, your traces should omit PID entries.
|
||||
\item The imported data may be severely limited, either by not mapping directly to the data structures used by Tracy, or by following undocumented practices.
|
||||
\end{itemize}
|
||||
\end{bclogo}
|
||||
|
@ -36,7 +36,6 @@
|
||||
#include "tracy_pdqsort.h"
|
||||
#include "TracyColor.hpp"
|
||||
#include "TracyFileRead.hpp"
|
||||
#include "TracyFileWrite.hpp"
|
||||
#include "TracyFilesystem.hpp"
|
||||
#include "TracyMouse.hpp"
|
||||
#include "TracyPopcnt.hpp"
|
||||
@ -345,6 +344,24 @@ void View::DrawHelpMarker( const char* desc ) const
|
||||
}
|
||||
}
|
||||
|
||||
static const char* CompressionName[] = {
|
||||
"LZ4",
|
||||
"LZ4 HC",
|
||||
"LZ4 HC extreme",
|
||||
"Zstd",
|
||||
nullptr
|
||||
};
|
||||
|
||||
static const char* CompressionDesc[] = {
|
||||
"Fastest save, fast load time, big file size",
|
||||
"Slow save, fastest load time, reasonable file size",
|
||||
"Very slow save, fastest load time, file smaller than LZ4 HC",
|
||||
"Configurable save time (fast-slowest), reasonable load time, smallest file size",
|
||||
nullptr
|
||||
};
|
||||
|
||||
static_assert( sizeof( CompressionName ) == sizeof( CompressionDesc ), "Unmatched compression names and descriptions" );
|
||||
|
||||
bool View::Draw()
|
||||
{
|
||||
HandshakeStatus status = (HandshakeStatus)s_instance->m_worker.GetHandshakeStatus();
|
||||
@ -606,6 +623,66 @@ bool View::Draw()
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
bool saveFailed = false;
|
||||
if( !s_instance->m_filenameStaging.empty() )
|
||||
{
|
||||
ImGui::OpenPopup( "Save trace" );
|
||||
}
|
||||
if( ImGui::BeginPopupModal( "Save trace", nullptr, ImGuiWindowFlags_AlwaysAutoResize ) )
|
||||
{
|
||||
assert( !s_instance->m_filenameStaging.empty() );
|
||||
auto fn = s_instance->m_filenameStaging.c_str();
|
||||
TextFocused( "Path:", fn );
|
||||
ImGui::Separator();
|
||||
|
||||
static FileWrite::Compression comp = FileWrite::Compression::Fast;
|
||||
static int zlvl = 6;
|
||||
ImGui::TextUnformatted( ICON_FA_FILE_ARCHIVE " Trace compression" );
|
||||
ImGui::SameLine();
|
||||
TextDisabledUnformatted( "Can be changed later with the upgrade utility" );
|
||||
ImGui::Indent();
|
||||
int idx = 0;
|
||||
while( CompressionName[idx] )
|
||||
{
|
||||
if( ImGui::RadioButton( CompressionName[idx], (int)comp == idx ) ) comp = (FileWrite::Compression)idx;
|
||||
ImGui::SameLine();
|
||||
ImGui::TextDisabled( CompressionDesc[idx] );
|
||||
idx++;
|
||||
}
|
||||
ImGui::Unindent();
|
||||
ImGui::TextUnformatted( "Zstd level" );
|
||||
ImGui::SameLine();
|
||||
TextDisabledUnformatted( "Increasing level decreases file size, but increases save and load times" );
|
||||
ImGui::Indent();
|
||||
ImGui::SliderInt( "##zstd", &zlvl, 1, 22, "%d", ImGuiSliderFlags_AlwaysClamp );
|
||||
ImGui::Unindent();
|
||||
|
||||
ImGui::Separator();
|
||||
if( ImGui::Button( ICON_FA_SAVE " Save trace" ) )
|
||||
{
|
||||
saveFailed = !s_instance->Save( fn, comp, zlvl );
|
||||
s_instance->m_filenameStaging.clear();
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if( ImGui::Button( "Cancel" ) )
|
||||
{
|
||||
s_instance->m_filenameStaging.clear();
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
if( saveFailed ) ImGui::OpenPopup( "Save failed" );
|
||||
if( ImGui::BeginPopupModal( "Save failed", nullptr, ImGuiWindowFlags_AlwaysAutoResize ) )
|
||||
{
|
||||
TextCentered( ICON_FA_EXCLAMATION_TRIANGLE );
|
||||
ImGui::TextUnformatted( "Could not save trace at the specified location. Try again somewhere else." );
|
||||
ImGui::Separator();
|
||||
if( ImGui::Button( "Oh well" ) ) ImGui::CloseCurrentPopup();
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
s_time += ImGui::GetIO().DeltaTime;
|
||||
return s_instance->DrawImpl();
|
||||
}
|
||||
@ -1365,7 +1442,7 @@ void View::DrawNotificationArea()
|
||||
}
|
||||
else if( m_notificationTime > 0 )
|
||||
{
|
||||
m_notificationTime -= io.DeltaTime;
|
||||
m_notificationTime -= std::min( io.DeltaTime, 0.25f );
|
||||
ImGui::SameLine();
|
||||
TextDisabledUnformatted( m_notificationText.c_str() );
|
||||
}
|
||||
@ -1466,33 +1543,16 @@ bool View::DrawConnection()
|
||||
const char* fn = "trace.tracy";
|
||||
#endif
|
||||
{
|
||||
std::unique_ptr<FileWrite> f;
|
||||
const auto sz = strlen( fn );
|
||||
if( sz < 7 || memcmp( fn + sz - 6, ".tracy", 6 ) != 0 )
|
||||
{
|
||||
char tmp[1024];
|
||||
sprintf( tmp, "%s.tracy", fn );
|
||||
f.reset( FileWrite::Open( tmp ) );
|
||||
if( f ) m_filename = tmp;
|
||||
m_filenameStaging = tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
f.reset( FileWrite::Open( fn ) );
|
||||
if( f ) m_filename = fn;
|
||||
}
|
||||
if( f )
|
||||
{
|
||||
m_userData.StateShouldBePreserved();
|
||||
m_saveThreadState.store( SaveThreadState::Saving, std::memory_order_relaxed );
|
||||
m_saveThread = std::thread( [this, f{std::move( f )}] {
|
||||
std::lock_guard<std::mutex> lock( m_worker.GetDataLock() );
|
||||
m_worker.Write( *f );
|
||||
f->Finish();
|
||||
const auto stats = f->GetCompressionStatistics();
|
||||
m_srcFileBytes.store( stats.first, std::memory_order_relaxed );
|
||||
m_dstFileBytes.store( stats.second, std::memory_order_relaxed );
|
||||
m_saveThreadState.store( SaveThreadState::NeedsJoin, std::memory_order_release );
|
||||
} );
|
||||
m_filenameStaging = fn;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -17976,4 +18036,24 @@ void View::DrawSourceTooltip( const char* filename, uint32_t srcline, int before
|
||||
if( separateTooltip ) ImGui::EndTooltip();
|
||||
}
|
||||
|
||||
bool View::Save( const char* fn, FileWrite::Compression comp, int zlevel )
|
||||
{
|
||||
std::unique_ptr<FileWrite> f( FileWrite::Open( fn, comp, zlevel ) );
|
||||
if( !f ) return false;
|
||||
|
||||
m_userData.StateShouldBePreserved();
|
||||
m_saveThreadState.store( SaveThreadState::Saving, std::memory_order_relaxed );
|
||||
m_saveThread = std::thread( [this, f{std::move( f )}] {
|
||||
std::lock_guard<std::mutex> lock( m_worker.GetDataLock() );
|
||||
m_worker.Write( *f );
|
||||
f->Finish();
|
||||
const auto stats = f->GetCompressionStatistics();
|
||||
m_srcFileBytes.store( stats.first, std::memory_order_relaxed );
|
||||
m_dstFileBytes.store( stats.second, std::memory_order_relaxed );
|
||||
m_saveThreadState.store( SaveThreadState::NeedsJoin, std::memory_order_release );
|
||||
} );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "TracyBadVersion.hpp"
|
||||
#include "TracyBuzzAnim.hpp"
|
||||
#include "TracyDecayValue.hpp"
|
||||
#include "TracyFileWrite.hpp"
|
||||
#include "TracyImGui.hpp"
|
||||
#include "TracyShortPtr.hpp"
|
||||
#include "TracySourceContents.hpp"
|
||||
@ -282,6 +283,7 @@ private:
|
||||
void CalcZoneTimeDataImpl( const V& children, const ContextSwitch* ctx, unordered_flat_map<int16_t, ZoneTimeData>& data, int64_t& ztime, const ZoneEvent& zone );
|
||||
|
||||
void SetPlaybackFrame( uint32_t idx );
|
||||
bool Save( const char* fn, FileWrite::Compression comp, int zlevel );
|
||||
|
||||
unordered_flat_map<const void*, VisData> m_visData;
|
||||
unordered_flat_map<uint64_t, bool> m_visibleMsgThread;
|
||||
@ -323,7 +325,7 @@ private:
|
||||
void AdjustThreadHeight( View::VisData& vis, int oldOffset, int& offset );
|
||||
|
||||
Worker m_worker;
|
||||
std::string m_filename;
|
||||
std::string m_filename, m_filenameStaging;
|
||||
bool m_staticView;
|
||||
ViewMode m_viewMode;
|
||||
bool m_viewModeHeuristicTry = false;
|
||||
|
@ -432,17 +432,33 @@ Worker::Worker( const char* name, const char* program, const std::vector<ImportE
|
||||
for( auto& t : m_threadMap )
|
||||
{
|
||||
auto name = threadNames.find(t.first);
|
||||
if (name != threadNames.end())
|
||||
if( name != threadNames.end() )
|
||||
{
|
||||
char buf[128];
|
||||
int len = snprintf(buf, sizeof(buf), "(%" PRIu64 ") %s", t.first, name->second.c_str());
|
||||
AddThreadString(t.first, buf, len);
|
||||
int len;
|
||||
if( t.first <= std::numeric_limits<uint32_t>::max() )
|
||||
{
|
||||
len = snprintf( buf, sizeof( buf ), "(%" PRIu64 ") %s", t.first, name->second.c_str() );
|
||||
}
|
||||
else
|
||||
{
|
||||
len = snprintf( buf, sizeof( buf ), "(PID %" PRIu64 " TID %" PRIu64 ") %s", t.first >> 32, t.first & 0xFFFFFFFF, name->second.c_str() );
|
||||
}
|
||||
AddThreadString( t.first, buf, len );
|
||||
}
|
||||
else
|
||||
{
|
||||
char buf[64];
|
||||
sprintf( buf, "%" PRIu64, t.first );
|
||||
AddThreadString( t.first, buf, strlen( buf ) );
|
||||
int len;
|
||||
if( t.first <= std::numeric_limits<uint32_t>::max() )
|
||||
{
|
||||
len = sprintf( buf, "%" PRIu64, t.first );
|
||||
}
|
||||
else
|
||||
{
|
||||
len = sprintf( buf, "PID %" PRIu64 " TID %" PRIu64, t.first >> 32, t.first & 0xFFFFFFFF );
|
||||
}
|
||||
AddThreadString( t.first, buf, len );
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user