Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

i915-perf: add GPU frequency plot #56

Merged
merged 7 commits into from
Dec 30, 2020
Merged
Prev Previous commit
Next Next commit
i915-perf: build up tracking of GPU frequency values
  • Loading branch information
llandwerlin-intel committed Dec 30, 2020
commit 784f5721b24a211540b6186d67a375850d3cfd52
19 changes: 18 additions & 1 deletion src/gpuvis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -768,8 +768,16 @@ int MainApp::load_etl_file( loading_info_t *loading_info, TraceEvents &trace_eve

int MainApp::load_i915_perf_file( loading_info_t *loading_info, TraceEvents &trace_events, EventCallback trace_cb )
{
return read_i915_perf_file( loading_info->filename.c_str(), trace_events.m_strpool,
int ret = read_i915_perf_file( loading_info->filename.c_str(), trace_events.m_strpool,
trace_events.m_trace_info, &trace_events.i915_perf_reader, trace_cb );

if ( ret == 0 )
{
trace_events.m_i915.freq_plot.init_empty( "i915-perf-freq" );
trace_events.m_i915.frequency_counter = get_i915_perf_frequency_counter( trace_events.i915_perf_reader );
}

return ret;
}

int SDLCALL MainApp::thread_func( void *data )
Expand Down Expand Up @@ -2119,6 +2127,11 @@ void TraceEvents::init_i915_event( trace_event_t &event )
}
}

void TraceEvents::add_i915_perf_frequency( const trace_event_t &event, int64_t ts, float value )
{
m_i915.freq_plot.add_item( event.id, ts, value );
}

void TraceEvents::init_i915_perf_event( trace_event_t &event )
{
if ( !event.has_duration() )
Expand All @@ -2138,6 +2151,10 @@ void TraceEvents::init_i915_perf_event( trace_event_t &event )
break;
}
}

// Load the GPU frequency data assocated with this event.
I915CounterCallback counter_cb = std::bind( &TraceEvents::add_i915_perf_frequency, this, _1, _2, _3 );
load_i915_perf_counter_values( i915_perf_reader, m_i915.frequency_counter, event, counter_cb );
}

m_i915.perf_locs.push_back( event.id );
Expand Down
13 changes: 13 additions & 0 deletions src/gpuvis.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

extern "C" {
struct intel_perf_data_reader;
struct intel_perf_logical_counter;
}

// Opts singleton
Expand Down Expand Up @@ -150,6 +151,10 @@ class GraphPlot
bool init( TraceEvents &trace_events, const std::string &name,
const std::string &filter_str, const std::string scanf_str );

void init_empty( const std::string &name );

void add_item( uint32_t eventid, int64_t ts, float value );

uint32_t find_ts_index( int64_t ts0 );

public:
Expand Down Expand Up @@ -449,6 +454,8 @@ class TraceEvents
}
uint32_t ts_to_ftrace_print_info_idx( const std::vector< uint32_t > &locs, int64_t ts );

void add_i915_perf_frequency( const trace_event_t &event, int64_t ts, float value );

public:
// Called once on background thread after all events loaded.
void init();
Expand Down Expand Up @@ -537,6 +544,12 @@ class TraceEvents
util_umap< uint32_t, uint32_t > perf_to_req_in;
// Maps a HW context ID to its color
std::map< uint32_t, ImU32 > perf_hw_context_colors;

// Frequency counter, filled right after parsing the i915-perf data.
struct intel_perf_logical_counter *frequency_counter = NULL;
// Plot generated after i915-perf data is parsed with the frequency
// counter values.
GraphPlot freq_plot;
} m_i915;

struct ftrace_pair_t
Expand Down
18 changes: 18 additions & 0 deletions src/gpuvis_plots.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,24 @@ bool GraphPlot::init( TraceEvents &trace_events, const std::string &name,
return !m_plotdata.empty();
}

void GraphPlot::init_empty( const std::string &name )
{
m_name = name;
m_filter_str.clear();
m_scanf_str.clear();

m_minval = FLT_MAX;
m_maxval = FLT_MIN;
m_plotdata.clear();
}

void GraphPlot::add_item( uint32_t eventid, int64_t ts, float value )
{
m_minval = std::min< float >( m_minval, value );
m_maxval = std::max< float >( m_maxval, value );
m_plotdata.push_back( { ts, eventid, value } );
}

uint32_t GraphPlot::find_ts_index( int64_t ts0 )
{
auto lambda = []( const GraphPlot::plotdata_t &lhs, int64_t ts )
Expand Down
66 changes: 66 additions & 0 deletions src/i915-perf/i915-perf-read.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#define _LARGEFILE64_SOURCE
#endif

#include <assert.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
Expand Down Expand Up @@ -111,3 +112,68 @@ int read_i915_perf_file( const char *file, StrPool &strpool, trace_info_t &trace

return 0;
}

#if USE_I915_PERF
static uint32_t record_timestamp( const struct drm_i915_perf_record_header *record )
{
const uint32_t *data = ( const uint32_t * )( record + 1 );
return data[ 1 ];
}
#endif

void load_i915_perf_counter_values( struct intel_perf_data_reader *reader,
struct intel_perf_logical_counter *counter,
const trace_event_t &event, I915CounterCallback &cb )
{
#if USE_I915_PERF
assert( event.i915_perf_timeline < reader->n_timelines );

const struct intel_perf_timeline_item *item = &reader->timelines[ event.i915_perf_timeline ];
const struct drm_i915_perf_record_header *first_record = reader->records[ item->record_start ];
for ( uint32_t j = item->record_start; j < item->record_end; j++ )
{
const struct drm_i915_perf_record_header *record = reader->records[j];
int64_t ts = item->cpu_ts_start +
( record_timestamp( record ) - record_timestamp( first_record ) ) *
( item->cpu_ts_end - item->cpu_ts_start ) / ( item->ts_end - item->ts_start );
struct intel_perf_accumulator acc;

intel_perf_accumulate_reports( &acc, reader->metric_set->perf_oa_format,
reader->records[j], reader->records[j + 1] );

float value;
if ( counter->storage == INTEL_PERF_LOGICAL_COUNTER_STORAGE_DOUBLE ||
counter->storage == INTEL_PERF_LOGICAL_COUNTER_STORAGE_FLOAT )
{
value = counter->read_float( reader->perf, reader->metric_set, acc.deltas );
}
else
{
value = counter->read_uint64( reader->perf, reader->metric_set, acc.deltas );
}

cb( event, ts, value / 1000000.0 ); // Report the frequency in MHz, not Hz
}
#endif
}

struct intel_perf_logical_counter *get_i915_perf_frequency_counter( struct intel_perf_data_reader *reader )
{
#if USE_I915_PERF
struct intel_perf_metric_set *metric_set = reader->metric_set;

for ( uint32_t i = 0; i < metric_set->n_counters; i++ )
{
struct intel_perf_logical_counter *counter = &metric_set->counters[ i ];

if ( strcmp( counter->symbol_name, "AvgGpuCoreFrequency" ) == 0 )
{
return counter;
}
}

return NULL;
#else
return NULL;
#endif
}
16 changes: 15 additions & 1 deletion src/i915-perf/i915-perf-read.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,22 @@
#ifndef I915_PERF_READ_H_
#define I915_PERF_READ_H_

struct intel_perf_data_reader;
#include <functional>

#define __STDC_FORMAT_MACROS
#include <inttypes.h>

extern "C" {
struct intel_perf_data_reader;
struct intel_perf_logical_counter;
}

typedef std::function< void ( const trace_event_t &event, int64_t ts, float value ) > I915CounterCallback;

int read_i915_perf_file( const char *file, StrPool &strpool, trace_info_t &trace_info, struct intel_perf_data_reader **reader, EventCallback &cb );
struct intel_perf_logical_counter *get_i915_perf_frequency_counter( struct intel_perf_data_reader *reader );
void load_i915_perf_counter_values( struct intel_perf_data_reader *reader,
struct intel_perf_logical_counter *counter,
const trace_event_t &event, I915CounterCallback &cb );

#endif // I915_PERF_READ_H_