1
0
mirror of https://github.com/wolfpld/tracy synced 2025-01-15 20:08:00 +00:00

Compare commits

...

10 Commits

Author SHA1 Message Date
Bartosz Taudul
959ddc3501
Update manual. 2021-05-15 14:33:10 +02:00
Bartosz Taudul
0414473c9f
Update NEWS. 2021-05-15 14:27:49 +02:00
Bartosz Taudul
92ae003308
Improve trace saving experience.
This adds additional dialog, which allows selection of compression mode. Also,
when a trace cannot be saved, a failure popup will be displayed.
2021-05-15 14:25:45 +02:00
Bartosz Taudul
ab830962c8
Fix notifications disappearing after a long UI lock. 2021-05-15 14:21:45 +02:00
Bartosz Taudul
fe71ae3272
Update manual. 2021-05-15 13:12:54 +02:00
Bartosz Taudul
068141abfc
Update NEWS. 2021-05-15 13:09:46 +02:00
Bartosz Taudul
7f1f929662
Decode PID and TID when generating imported thread names. 2021-05-15 13:08:51 +02:00
Bartosz Taudul
8ea02a4794
Cosmetics. 2021-05-15 13:03:42 +02:00
Bartosz Taudul
6b2de1c8b5
Pack PID + TID. 2021-05-15 12:56:52 +02:00
Bartosz Taudul
3005d5a939
Cosmetics. 2021-05-15 12:54:29 +02:00
6 changed files with 149 additions and 47 deletions

5
NEWS
View File

@ -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)

View File

@ -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";
}
}

View File

@ -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}

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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 );
}
}