Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgseventtracing.cpp 3 : : -------------------------------------- 4 : : Date : October 2019 5 : : Copyright : (C) 2019 by Martin Dobias 6 : : Email : wonder dot sk at gmail dot com 7 : : *************************************************************************** 8 : : * * 9 : : * This program is free software; you can redistribute it and/or modify * 10 : : * it under the terms of the GNU General Public License as published by * 11 : : * the Free Software Foundation; either version 2 of the License, or * 12 : : * (at your option) any later version. * 13 : : * * 14 : : ***************************************************************************/ 15 : : 16 : : #include "qgseventtracing.h" 17 : : 18 : : #include <QCoreApplication> 19 : : #include <QFile> 20 : : #include <QThread> 21 : : 22 : : /// @cond PRIVATE 23 : : 24 : 0 : struct TraceItem 25 : : { 26 : : QgsEventTracing::EventType type; 27 : : uint threadId; 28 : : qint64 timestamp; 29 : : QString category; 30 : : QString name; 31 : : QString id; 32 : : }; 33 : : 34 : : //! Whether we are tracing right now 35 : : static bool sIsTracing = false; 36 : : //! High-precision timer to measure the elapsed time 37 : 0 : Q_GLOBAL_STATIC( QElapsedTimer, sTracingTimer ) 38 : : //! Buffer of captured events in the current tracing session 39 : 0 : Q_GLOBAL_STATIC( QVector<TraceItem>, sTraceEvents ) 40 : : //! Mutex to protect the buffer from being written to from multiple threads 41 : 0 : Q_GLOBAL_STATIC( QMutex, sTraceEventsMutex ) 42 : : 43 : : 44 : 0 : bool QgsEventTracing::startTracing() 45 : : { 46 : 0 : if ( sIsTracing ) 47 : 0 : return false; 48 : : 49 : 0 : sIsTracing = true; 50 : 0 : sTraceEventsMutex()->lock(); 51 : 0 : sTracingTimer()->start(); 52 : 0 : sTraceEvents()->clear(); 53 : 0 : sTraceEvents()->reserve( 1000 ); 54 : 0 : sTraceEventsMutex()->unlock(); 55 : 0 : return true; 56 : 0 : } 57 : : 58 : 0 : bool QgsEventTracing::stopTracing() 59 : : { 60 : 0 : if ( !sIsTracing ) 61 : 0 : return false; 62 : : 63 : 0 : sIsTracing = false; 64 : 0 : sTracingTimer()->invalidate(); 65 : 0 : return false; 66 : 0 : } 67 : : 68 : 0 : bool QgsEventTracing::isTracingEnabled() 69 : : { 70 : 0 : return sIsTracing; 71 : : } 72 : : 73 : 0 : static char _eventTypeToChar( QgsEventTracing::EventType type ) 74 : : { 75 : 0 : switch ( type ) 76 : : { 77 : 0 : case QgsEventTracing::Begin: return 'B'; 78 : 0 : case QgsEventTracing::End: return 'E'; 79 : 0 : case QgsEventTracing::Instant: return 'i'; 80 : 0 : case QgsEventTracing::AsyncBegin: return 'b'; 81 : 0 : case QgsEventTracing::AsyncEnd: return 'e'; 82 : : } 83 : 0 : return '?'; 84 : 0 : } 85 : : 86 : 0 : bool QgsEventTracing::writeTrace( const QString &fileName ) 87 : : { 88 : 0 : if ( sIsTracing ) 89 : 0 : return false; 90 : : 91 : 0 : QFile f( fileName ); 92 : 0 : if ( !f.open( QIODevice::WriteOnly ) ) 93 : 0 : return false; 94 : : 95 : 0 : f.write( "{\n\"traceEvents\": [\n" ); 96 : : 97 : 0 : bool first = true; 98 : 0 : for ( const auto &item : *sTraceEvents() ) 99 : : { 100 : 0 : if ( !first ) 101 : 0 : f.write( ",\n" ); 102 : : else 103 : 0 : first = false; 104 : 0 : char t = _eventTypeToChar( item.type ); 105 : 0 : QString msg = QStringLiteral( " {\"cat\": \"%1\", \"pid\": 1, \"tid\": %2, \"ts\": %3, \"ph\": \"%4\", \"name\": \"%5\"" ) 106 : 0 : .arg( item.category ).arg( item.threadId ).arg( item.timestamp ).arg( t ).arg( item.name ); 107 : : 108 : : // for instant events we always set them as global (currently not supporting instant events at thread scope) 109 : 0 : if ( item.type == Instant ) 110 : 0 : msg += QLatin1String( ", \"s\": \"g\"" ); 111 : : 112 : : // async events also need to have ID associated 113 : 0 : if ( item.type == AsyncBegin || item.type == AsyncEnd ) 114 : 0 : msg += QStringLiteral( ", \"id\": \"%1\"" ).arg( item.id ); 115 : : 116 : 0 : msg += " }"; 117 : : 118 : 0 : f.write( msg.toUtf8() ); 119 : 0 : } 120 : : 121 : 0 : f.write( "\n]\n}\n" ); 122 : 0 : f.close(); 123 : 0 : return true; 124 : 0 : } 125 : : 126 : 0 : void QgsEventTracing::addEvent( QgsEventTracing::EventType type, const QString &category, const QString &name, const QString &id ) 127 : : { 128 : 0 : if ( !sIsTracing ) 129 : 0 : return; 130 : : 131 : 0 : sTraceEventsMutex()->lock(); 132 : 0 : TraceItem item; 133 : 0 : item.type = type; 134 : 0 : item.timestamp = sTracingTimer()->nsecsElapsed() / 1000; 135 : 0 : if ( QThread::currentThread() == QCoreApplication::instance()->thread() ) 136 : 0 : item.threadId = 0; // to make it show up first 137 : : else 138 : 0 : item.threadId = static_cast<uint>( reinterpret_cast<quint64>( QThread::currentThreadId() ) ); 139 : 0 : item.category = category; 140 : 0 : item.name = name; 141 : 0 : item.id = id; 142 : 0 : sTraceEvents()->append( item ); 143 : 0 : sTraceEventsMutex()->unlock(); 144 : 0 : } 145 : : 146 : : ///@endcond