All of lore.kernel.org
 help / color / mirror / Atom feed
From: Sergey Senozhatsky <sergey.senozhatsky at gmail.com>
To: powertop@lists.01.org
Subject: Re: [Powertop] [FYI][RFC][PATCH 2/2] MALI GPU profiling support
Date: Tue, 25 Dec 2012 23:58:25 +0300	[thread overview]
Message-ID: <20121225205825.GG3307@swordfish> (raw)
In-Reply-To: 1351771239-18925-3-git-send-email-i.zhbanov@samsung.com

[-- Attachment #1: Type: text/plain, Size: 48245 bytes --]


Hello Igor,

On (11/01/12 16:00), Igor Zhbanov wrote:
> This patch adds MALI GPU profiling support.
> The information is collected from internal tracing mechanism
> (/sys/kernel/debug/mali/profiling/).
> 
> Currently the collected data is written in reports only and not
> on screen in interactive mode.
> 
> Reviewed-by: Kyungmin Park <kyungmin.park(a)samsung.com>
> ---
>  src/Makefile.am                                   |    1 +
>  src/main.cpp                                      |    8 +
>  src/mali-internal-events/mali-events.h            |  143 +++
>  src/mali-internal-events/mali-internal-events.cpp | 1279 +++++++++++++++++++++
>  4 files changed, 1431 insertions(+), 0 deletions(-)
>  create mode 100644 src/mali-internal-events/mali-events.h
>  create mode 100644 src/mali-internal-events/mali-internal-events.cpp
> 
> diff --git a/src/Makefile.am b/src/Makefile.am
> index e3eb6c2..af98867 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -28,6 +28,7 @@ powertop_SOURCES = parameters/persistent.cpp parameters/learn.cpp parameters/par
>  		tuning/tuningsysfs.cpp tuning/wifi.h tuning/runtime.cpp tuning/tunable.h \
>  		tuning/runtime.h tuning/tuningusb.h tuning/iw.h calibrate/calibrate.cpp \
>  		calibrate/calibrate.h measurement/measurement.cpp measurement/power_supply.cpp \
> +		mali-internal-events/mali-events.h mali-internal-events/mali-internal-events.cpp  \
>  		mali-internal-events/proc-scan.cpp mali-internal-events/proc-scan.h \
>  		measurement/measurement.h measurement/acpi.cpp measurement/sysfs.h measurement/sysfs.cpp \
>  		measurement/acpi.h measurement/extech.cpp measurement/power_supply.h measurement/extech.h \
> diff --git a/src/main.cpp b/src/main.cpp
> index 83adfad..c901ce7 100644
> --- a/src/main.cpp
> +++ b/src/main.cpp
> @@ -61,6 +61,7 @@
>  #define DEBUGFS_MAGIC          0x64626720
>  
>  #include "mali-internal-events/proc-scan.h"
> +#include "mali-internal-events/mali-events.h"
>  
>  int debug_learning = 0;
>  unsigned time_out = 20;
> @@ -183,6 +184,7 @@ static void do_sleep(int seconds)
>  	} while (1);
>  }
>  
> +mali_ctx *ctx = NULL;
>  

do we really need mali_ctx in main all the time (even for !mali builds)?
can we hide mali context as a static within mali internals?

side note: '#define __arm__' implies '#define mali'.



>  void one_measurement(int seconds, char *workload)
>  {
> @@ -191,6 +193,7 @@ void one_measurement(int seconds, char *workload)
>  	devices_start_measurement();
>  	start_process_measurement();
>  	start_cpu_measurement();
> +	start_mali_capture(ctx);
>  
>  	if (workload && workload[0]) {
>  		scanproc(0, 0);
> @@ -206,9 +209,11 @@ void one_measurement(int seconds, char *workload)
>  	collect_open_devices();
>  	devices_end_measurement();
>  	end_power_measurement();
> +	stop_mali_capture(ctx);
>  
>  	process_cpu_data();
>  	process_process_data();
> +	process_mali_events(ctx);
>  
>  	/* output stats */
>  	process_update_display();
> @@ -257,11 +262,14 @@ void make_report(int time, char *workload, int iterations, char *file)
>  	for (int i=0; i != iterations; i++){
>  		init_report_output(file, iterations);
>  		initialize_tuning();
> +		ctx = init_mali_capture();
>  		/* and then the real measurement */
>  		one_measurement(time, workload);
>  		report_show_tunables();
> +		print_mali_stat(ctx);
>  		finish_report_output();
>  		clear_tuning();
> +		cleanup_mali_capture(&ctx);
>  	}
>  	/* and wrap up */
>  	learn_parameters(50, 0);
> diff --git a/src/mali-internal-events/mali-events.h b/src/mali-internal-events/mali-events.h
> new file mode 100644
> index 0000000..825f926
> --- /dev/null
> +++ b/src/mali-internal-events/mali-events.h
> @@ -0,0 +1,143 @@
> +/* Copyright (c) 2012 Samsung Electronics Co., Ltd.
> + *	http://www.samsung.com/
> + *
> + * This file is part of PowerTOP
> + *
> + * This program file is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * This program is distributed in the hope that it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> + * for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program in a file named COPYING; if not, write to the
> + * Free Software Foundation, Inc,
> + * 51 Franklin Street, Fifth Floor,
> + * Boston, MA 02110-1301 USA
> + * or just google for it.
> + *
> + * MALI GPU internal events tracer for r3p0 driver version.
> + * Written by Igor Zhbanov <i.zhbanov(a)samsung.com>,
> + * Alina Litvinova <alina.litvinova(a)gmail.com>
> + * 2012.06 */
> +
> +#ifndef _MALI_EVENTS_H_
> +#define _MALI_EVENTS_H_
> +
> +#include <stdio.h>
> +#include <unistd.h>
> +#include <sys/types.h>
> +
> +struct mali_event {
> +	unsigned long long timestamp;
> +	unsigned int type, channel, data, d0, d1, d2, d3, d4;
> +};
> +
> +/*
> +Event ID bit format:
> + 3         2         1
> +10987654321098765432109876543210
> +RRRRTTTTCCCCCCCCDDDDDDDDDDDDDDDD
> +
> +RRRR -- reserved for future use.
> +
> +TTTT -- type of the event: */
> +#define MALI_PROFILING_EVENT_TYPE_SINGLE	0
> +#define MALI_PROFILING_EVENT_TYPE_START		1
> +#define MALI_PROFILING_EVENT_TYPE_STOP		2
> +#define MALI_PROFILING_EVENT_TYPE_SUSPEND	3
> +#define MALI_PROFILING_EVENT_TYPE_RESUME	4
> +
> +/*
> +CCCCCCCC -- channel/source of the event: */
> +#define MALI_PROFILING_EVENT_CHANNEL_SOFTWARE	0
> +#define MALI_PROFILING_EVENT_CHANNEL_GP0	1
> +#define MALI_PROFILING_EVENT_CHANNEL_PP0	5
> +#define MALI_PROFILING_EVENT_CHANNEL_PP1	6
> +#define MALI_PROFILING_EVENT_CHANNEL_PP2	7
> +#define MALI_PROFILING_EVENT_CHANNEL_PP3	8
> +#define MALI_PROFILING_EVENT_CHANNEL_PP4	9
> +#define MALI_PROFILING_EVENT_CHANNEL_PP5	10
> +#define MALI_PROFILING_EVENT_CHANNEL_PP6	11
> +#define MALI_PROFILING_EVENT_CHANNEL_PP7	12
> +#define MALI_PROFILING_EVENT_CHANNEL_GPU	21
> +
> +#define GP_NUM 1 /* Maximal number of GP units */
> +#define PP_NUM 8 /* Maximal number of PP units */
> +
> +/*
> +DDDDDDDDDDDDDDDD -- event data.
> +
> +Events data for MALI_PROFILING_EVENT_TYPE_SINGLE event type
> +from software channel: */
> +#define MALI_PROFILING_EVENT_REASON_SINGLE_SW_NONE		0 /* Not used */,
> +#define MALI_PROFILING_EVENT_REASON_SINGLE_SW_EGL_NEW_FRAME	1 /* Not used */,
> +#define MALI_PROFILING_EVENT_REASON_SINGLE_SW_FLUSH		2 /* Not used */,
> +#define MALI_PROFILING_EVENT_REASON_SINGLE_SW_EGL_SWAP_BUFFERS	3 /* Not used */,
> +/*#define MALI_PROFILING_EVENT_REASON_SINGLE_SW_FB_EVENT	4 // NOT USED */
> +#define MALI_PROFILING_EVENT_REASON_SINGLE_SW_GPU_FREQ		4
> +#define MALI_PROFILING_EVENT_REASON_SINGLE_SW_GPU_VOLTS		5
> +#define MALI_PROFILING_EVENT_REASON_SINGLE_SW_GLOBAL_TRY_LOCK	6
> +#define MALI_PROFILING_EVENT_REASON_SINGLE_SW_GLOBAL_LOCK	7
> +#define MALI_PROFILING_EVENT_REASON_SINGLE_SW_GLOBAL_UNLOCK	8
> +#define MALI_PROFILING_EVENT_REASON_SINGLE_SW_VBLANK_VSYNC	9
> +
> +/*
> +Events data for MALI_PROFILING_EVENT_TYPE_SINGLE event type
> +from a HW channel (GPx + PPx + GPU): */
> +#define MALI_PROFILING_EVENT_REASON_SINGLE_HW_NONE		0 /* Not used */
> +#define MALI_PROFILING_EVENT_REASON_SINGLE_HW_INTERRUPT		1
> +#define MALI_PROFILING_EVENT_REASON_SINGLE_HW_FLUSH		2
> +#define MALI_PROFILING_EVENT_REASON_SINGLE_GPU_FREQ_VOLT_CHANGE	10
> +
> +#define TIMESTAMP_FACTOR 1000000000ll
> +
> +#define MALI_PROFILING_PATH "/sys/kernel/debug/mali/profiling/"
> +#define MALI_PROFILING_EVENTS MALI_PROFILING_PATH "events"
> +#define MALI_PROFILING_RECORD MALI_PROFILING_PATH "record"
> +#define MALI_PROFILING_ENABLE MALI_PROFILING_PATH "proc/default/enable"
> +
> +enum unit_status {
> +	UNIT_FREE = 0,
> +	UNIT_BUSY
> +};
> +
> +struct unit_state {
> +	long long job_start;
> +	pid_t pid, tid;
> +	unit_status status;
> +};
> +
> +struct mali_state {
> +	unit_state gp[GP_NUM];
> +	unit_state pp[PP_NUM];
> +	int freq, volt; /* I hope GPU frequency will not be above 2 GHz ;-) */
> +	int split_count;
> +};
> +
> +struct mali_ctx {
> +	int old_enable, old_record;
> +	/* For filtering events timestamp */
> +	long long start_time, finish_time;
> +	const char *fname;
> +	mali_state gpu_state;
> +	bool live, error_flag, started, processed;
> +};
> +
> +mali_ctx *init_mali_capture();
> +bool start_mali_capture(mali_ctx *ctx);
> +bool stop_mali_capture(mali_ctx *ctx);
> +bool process_mali_events(mali_ctx *ctx);
> +bool print_mali_stat(mali_ctx *ctx);
> +bool cleanup_mali_capture(mali_ctx **ctx);
> +
> +bool get_pt_proc_info(pid_t pid, const char **name, const char **cmdline);
> +
> +#ifndef UNUSED
> +#define UNUSED __attribute__((unused))
> +#endif /* UNUSED */
> +


so we know everything about mali even in !mali (!arm) builds?



> +#endif /* _MALI_EVENTS_H_ */
> diff --git a/src/mali-internal-events/mali-internal-events.cpp b/src/mali-internal-events/mali-internal-events.cpp
> new file mode 100644
> index 0000000..686d1c3
> --- /dev/null
> +++ b/src/mali-internal-events/mali-internal-events.cpp
> @@ -0,0 +1,1279 @@
> +/* Copyright (c) 2012 Samsung Electronics Co., Ltd.
> + *	http://www.samsung.com/
> + *
> + * This file is part of PowerTOP
> + *
> + * This program file is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * This program is distributed in the hope that it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> + * for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program in a file named COPYING; if not, write to the
> + * Free Software Foundation, Inc,
> + * 51 Franklin Street, Fifth Floor,
> + * Boston, MA 02110-1301 USA
> + * or just google for it.
> + *
> + * MALI GPU internal events tracer for r3p0 driver version.
> + * Written by Igor Zhbanov <i.zhbanov(a)samsung.com>,
> + * Alina Litvinova <alina.litvinova(a)gmail.com>
> + * 2012.06 */
> +
> +#define _POSIX_SOURCE
> +
> +#include <time.h>
> +#include <stdio.h>
> +#include <locale.h>
> +#include <stdarg.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <sys/time.h>
> +#include <sys/types.h>
> +
> +#include "proc-scan.h"
> +#include "mali-events.h"
> +
> +#include "../report/report.h"
> +#include "../report/report-maker.h"
> +
> +#ifdef __arm__
> +
> +enum debug_level_t {
> +	NO_DEBUG = 0,
> +	CRIT,
> +	TOTAL_REPORT,
> +	WARN,
> +	PER_UNIT_REPORT,
> +	TASK_EVENTS,
> +	MISC_EVENTS
> +};
> +
> +static debug_level_t debug_level = CRIT;
> +
> +/* ************************************************************************ */
> +
> +static int dprintf(debug_level_t level, const char *fmt, ...)
> +				__attribute__ ((format (printf, 2, 3)));
> +
> +static int
> +dprintf(debug_level_t level, const char *fmt, ...) {
> +	int ret;
> +
> +	if (level > debug_level)
> +		return 0;
> +
> +	va_list ap;
> +	va_start(ap, fmt);
> +	ret = vprintf(fmt, ap);
> +	va_end(ap);
> +	return ret;
> +}
> +
> +/* ************************************************************************ */
> +
> +static int edprintf(debug_level_t level, const char *fmt, ...)
> +				__attribute__ ((format (printf, 2, 3)));
> +
> +static int
> +edprintf(debug_level_t level, const char *fmt, ...) {
> +	int ret;
> +
> +	if (level > debug_level)
> +		return 0;
> +
> +	va_list ap;
> +	va_start(ap, fmt);
> +	ret = vfprintf(stderr, fmt, ap);
> +	va_end(ap);
> +	return ret;
> +}
> +


side note: to my mind, it's better to have some debugging support in lib, rather than
inside some subsystem.



 
 off topic: I think it'll be nice to have some UI level user reporting, let's say,
 first UI line (white text on red bg).

 e.g. 
 if (toggle() != SUCCESS)
	notify_user("Unable to toggle powersave on %s", _(dev_name));


 for example, something like this (let's return to this later):

	void notify_user(const char *frmt, ...)
	{
	        va_list list;
	
	        start_color();
	        init_pair(1, COLOR_WHITE, COLOR_RED);
	
	        va_start(list, frmt);
	        attron(COLOR_PAIR(1));
	        mvprintw(1, 0, frmt, list);
	        attroff(COLOR_PAIR(1));
	        va_end(list);
	}
	


> +/* ************************************************************************ */
> +
> +static int
> +get_int_value(const char *fname)
> +{
> +	FILE *f;
> +	int value;
> +
> +	f = fopen(fname, "r");
> +	if (!f) {
> +		edprintf(CRIT, "Can't open \"%s\".\n", fname);
> +		return -1;
> +	}
> +
> +	if (fscanf(f, "%d", &value) != 1) {
> +		edprintf(CRIT, "Can't read \"%s\" or its value is in wrong "
> +			       "format.\n", fname);
> +		fclose(f);
> +		return -1;
> +	}
> +
> +	fclose(f);
> +	return value;
> +}
> +
> +/* ************************************************************************ */
> +
> +static bool
> +set_int_value(const char *fname, int value)
> +{
> +	FILE *f;
> +
> +	f = fopen(fname, "w");
> +	if (!f) {
> +		edprintf(CRIT, "Can't open \"%s\".\n", fname);
> +		return false;
> +	}
> +
> +	fprintf(f, "%d\n", value);
> +	fclose(f);
> +	return true;
> +}
> +
> +/* ************************************************************************ */
> +
> +static int
> +get_enable()
> +{
> +	return get_int_value(MALI_PROFILING_ENABLE);
> +}
> +
> +/* ************************************************************************ */
> +
> +static bool
> +set_enable(int value)
> +{
> +	return set_int_value(MALI_PROFILING_ENABLE, value);
> +}
> +
> +/* ************************************************************************ */
> +
> +static int
> +get_record()
> +{
> +	return get_int_value(MALI_PROFILING_RECORD);
> +}
> +
> +/* ************************************************************************ */
> +
> +static bool
> +set_record(int value)
> +{
> +	return set_int_value(MALI_PROFILING_RECORD, value);
> +}
> +
> +/* ************************************************************************ */
> +
> +static bool
> +save_mode(int *old_enable, int *old_record)
> +{
> +	*old_enable = get_enable();
> +	if (*old_enable == -1) {
> +		edprintf(CRIT, "Can't get value of \"" MALI_PROFILING_ENABLE
> +			       "\".\n");
> +		return false;
> +	}
> +
> +	*old_record = get_record();
> +	if (*old_record == -1) {
> +		edprintf(CRIT, "Can't get value of \"" MALI_PROFILING_RECORD
> +			       "\".\n");
> +		return false;
> +	}
> +
> +	return true;
> +}
> +
> +/* ************************************************************************ */
> +
> +static bool
> +set_mode()
> +{
> +	if (!set_enable(1))
> +		return false;
> +
> +	/* Enable recording. Don't clean previous records to collect
> +	 * voltage and frequency information */
> +	if (!set_record(1))
> +		return false;
> +
> +	return true;
> +}
> +
> +/* ************************************************************************ */
> +
> +static bool
> +restore_mode(int old_enable, int old_record)
> +{
> +	/* Clear previous events and disable recording */
> +	if (!set_record(old_record))
> +		return false;
> +
> +	if (!set_enable(old_enable))
> +		return false;
> +
> +	return true;
> +}
> +
> +/* ************************************************************************ */
> +
> +static int
> +gp_number(int channel)
> +{
> +	return channel - MALI_PROFILING_EVENT_CHANNEL_GP0;
> +}
> +
> +/* ************************************************************************ */
> +
> +static int
> +pp_number(int channel)
> +{
> +	return channel - MALI_PROFILING_EVENT_CHANNEL_PP0;
> +}
> +
> +/* ************************************************************************ */
> +
> +static bool
> +is_gp_channel(int channel)
> +{
> +	return (channel == MALI_PROFILING_EVENT_CHANNEL_GP0);
> +}
> +
> +/* ************************************************************************ */
> +
> +static bool
> +is_pp_channel(int channel)
> +{
> +	return (channel == MALI_PROFILING_EVENT_CHANNEL_PP0 ||
> +		channel == MALI_PROFILING_EVENT_CHANNEL_PP1 ||
> +		channel == MALI_PROFILING_EVENT_CHANNEL_PP2 ||
> +		channel == MALI_PROFILING_EVENT_CHANNEL_PP3 ||
> +		channel == MALI_PROFILING_EVENT_CHANNEL_PP4 ||
> +		channel == MALI_PROFILING_EVENT_CHANNEL_PP5 ||
> +		channel == MALI_PROFILING_EVENT_CHANNEL_PP6);
> +}
> +
> +/* ************************************************************************ */
> +
> +static bool
> +is_gp_or_pp_channel(int channel)
> +{
> +	return (is_gp_channel(channel) || is_pp_channel(channel));
> +}
> +
> +/* ************************************************************************ */
> +
> +static bool
> +is_known_channel(int channel)
> +{
> +	return (is_gp_or_pp_channel(channel) ||
> +		channel == MALI_PROFILING_EVENT_CHANNEL_SOFTWARE ||
> +		channel == MALI_PROFILING_EVENT_CHANNEL_GPU);
> +}
> +
> +/* ************************************************************************ */
> +
> +static const char *
> +get_gp_name(int channel)
> +{
> +	switch (channel) {
> +		case MALI_PROFILING_EVENT_CHANNEL_GP0:
> +			return "GP0";
> +		default:
> +			return "NOT A GP UNIT";
> +	}
> +}
> +
> +/* ************************************************************************ */
> +
> +static const char *
> +get_pp_name(int channel)
> +{
> +	switch (channel) {
> +		case MALI_PROFILING_EVENT_CHANNEL_PP0:
> +			return "PP0";
> +		case MALI_PROFILING_EVENT_CHANNEL_PP1:
> +			return "PP1";
> +		case MALI_PROFILING_EVENT_CHANNEL_PP2:
> +			return "PP2";
> +		case MALI_PROFILING_EVENT_CHANNEL_PP3:
> +			return "PP3";
> +		case MALI_PROFILING_EVENT_CHANNEL_PP4:
> +			return "PP4";
> +		case MALI_PROFILING_EVENT_CHANNEL_PP5:
> +			return "PP5";
> +		case MALI_PROFILING_EVENT_CHANNEL_PP6:
> +			return "PP6";
> +		case MALI_PROFILING_EVENT_CHANNEL_PP7:
> +			return "PP7";
> +		default:
> +			return "NOT A PP UNIT";
> +	}
> +}
> +
> +/* ************************************************************************ */
> +
> +static const char *
> +get_channel_name(int channel)
> +{
> +	if (is_pp_channel(channel))
> +		return get_pp_name(channel);
> +	else if (is_gp_channel(channel))
> +		return get_gp_name(channel);
> +	else if (channel == MALI_PROFILING_EVENT_CHANNEL_SOFTWARE)
> +		return "Software";
> +	else if (channel == MALI_PROFILING_EVENT_CHANNEL_GPU)
> +		return "GPU";
> +	else {
> +		static char buf[64];
> +
> +		snprintf(buf, sizeof(buf), "UNKNOWN(%u)", channel);
> +		return buf;
> +	}
> +}
> +
> +/* ************************************************************************ */
> +
> +static int
> +print_date(debug_level_t level, const mali_event *ev)
> +{
> +	time_t t;
> +	char str[256], stz[32];
> +	struct tm *ltm;
> +
> +	if (level > debug_level)
> +		return 0;
> +
> +	t = ev->timestamp / TIMESTAMP_FACTOR;
> +	ltm = localtime(&t);
> +
> +	strftime(str, sizeof(str), "%F %T", ltm);
> +	strftime(stz, sizeof(stz), "%z", ltm);
> +
> +	/* No newline at end */
> +	return dprintf(level, "%s.%010u %s: ", str,
> +		       (unsigned int)(ev->timestamp % TIMESTAMP_FACTOR), stz);
> +}
*> +
> +/* ************************************************************************ */
> +
> +/* Channel is a GP channel here */
> +static bool
> +process_gp_job(mali_ctx *ctx, const mali_event *ev, int un)
> +{
> +	double freq, volt, duration, power;
> +	process_info *proc;
> +	pid_t pid;
> +
> +	if (ctx->gpu_state.freq == -1) {
> +		dprintf(WARN, "GPU Frequency is unknown for finished job. "
> +			"Set it to 440 MHz.\n");
> +		ctx->gpu_state.freq = 440000000;
> +	}
> +
> +	if (ctx->gpu_state.volt == -1) {
> +		dprintf(WARN, "GPU Voltage is unknown for finished job. "
> +			"Set it to 1.075 V.\n");
> +		ctx->gpu_state.volt = 1075000;
> +	}
> +
> +	freq = ctx->gpu_state.freq / 1000000.;
> +	volt = ctx->gpu_state.volt / 1000000.;
> +	pid = ctx->gpu_state.gp[un].pid;
> +	ctx->gpu_state.gp[un].status = UNIT_FREE;
> +	duration = (double)(ev->timestamp - ctx->gpu_state.gp[un].job_start) /
> +		   (double)TIMESTAMP_FACTOR;
> +	/* Consumed power approximately can be computed as this:
> +	 * P = C * V^2 * f, where C is capacitance, V is voltage
> +	 * and f is frequency. We don't need exact Watts so we consider
> +	 * that 1 PW (PseudoWatt) is consumed running one GPU unit
> +	 * (GPx or PPx) on 266 MHz and 1 Volt. */
> +	power = freq * volt * volt * duration / 266.;
> +	dprintf(TASK_EVENTS, "Job was ran on GP%d by pid %d, tid %d "
> +			     "for %lg seconds with GPU frequency = %lg MHz, "
> +			     "voltage = %.03f, "
> +			     "consumed power = %lg PseudoWatts\n",
> +		un, pid, ctx->gpu_state.gp[un].tid, duration, freq, volt,
> +		power);
> +
> +	proc = get_proc_info(pid);
> +	if (!proc)
> +		add_unknown_proc(pid, power);
> +	else
> +		proc->power += power;
> +
> +	return true;
> +}
> +
> +/* ************************************************************************ */
> +
> +/* Channel is a PP channel here */
> +static bool
> +process_pp_job(mali_ctx *ctx, const mali_event *ev, int un)
> +{
> +	double freq, volt, duration, power;
> +	process_info *proc;
> +	pid_t pid;
> +
> +	if (ctx->gpu_state.freq == -1) {
> +		dprintf(WARN, "GPU Frequency is unknown for finished job. "
> +			"Set it to 440 MHz.\n");
> +		ctx->gpu_state.freq = 440000000;
> +	}
> +
> +	if (ctx->gpu_state.volt == -1) {
> +		dprintf(WARN, "GPU Voltage is unknown for finished job. "
> +			"Set it to 1.075 V.\n");
> +		ctx->gpu_state.volt = 1075000;
> +	}
> +
> +	freq = ctx->gpu_state.freq / 1000000.;
> +	volt = ctx->gpu_state.volt / 1000000.;
> +	pid = ctx->gpu_state.pp[un].pid;
> +	ctx->gpu_state.pp[un].status = UNIT_FREE;
> +	duration = (double)(ev->timestamp - ctx->gpu_state.pp[un].job_start) /
> +		   (double)TIMESTAMP_FACTOR;
> +	/* See comment in process_gp_job() above. */
> +	power = freq * volt * volt * duration / 266.;
> +	dprintf(TASK_EVENTS, "Job was ran on PP%d by pid %d, tid %d "
> +			     "for %lg seconds with GPU frequency = %g MHz, "
> +			     "voltage = %.03f, "
> +			     "consumed power = %lg PseudoWatts\n",
> +		un, pid, ctx->gpu_state.pp[un].tid, duration, freq, volt,
> +		power);
> +
> +	proc = get_proc_info(pid);
> +	if (!proc)
> +		add_unknown_proc(pid, power);
> +	else
> +		proc->power += power;
> +
> +	return true;
> +}
> +
> +/* ************************************************************************ */
> +
> +/* Channel is a GP channel here */
> +static bool
> +process_gp_job_start(mali_ctx *ctx, const mali_event *ev)
> +{
> +	int un;
> +
> +	print_date(TASK_EVENTS, ev);
> +	dprintf(TASK_EVENTS, "GP job started at %s by pid = %u, tid = %u\n",
> +		get_gp_name(ev->channel), ev->d0, ev->d1);
> +	un = gp_number(ev->channel);
> +	if (ctx->gpu_state.gp[un].status != UNIT_FREE) {
> +		edprintf(WARN, "We have missed GP Job Stop event. "
> +			       "Considering running task finished.\n");
> +		if (!process_gp_job(ctx, ev, un))
> +			return false;
> +	}
> +
> +	ctx->gpu_state.gp[un].status = UNIT_BUSY;
> +	ctx->gpu_state.gp[un].job_start = ev->timestamp;
> +	ctx->gpu_state.gp[un].pid = ev->d0;
> +	ctx->gpu_state.gp[un].tid = ev->d1;
> +	return true;
> +}
> +
> +/* ************************************************************************ */
> +
> +/* Channel is a PP channel here */
> +static bool
> +process_pp_job_start(mali_ctx *ctx, const mali_event *ev)
> +{
> +	int un;
> +
> +	print_date(TASK_EVENTS, ev);
> +	dprintf(TASK_EVENTS, "PP job started at %s by pid = %u, tid = %u\n",
> +		get_pp_name(ev->channel), ev->d0, ev->d1);
> +	un = pp_number(ev->channel);
> +	if (ctx->gpu_state.pp[un].status != UNIT_FREE) {
> +		edprintf(WARN, "We have missed PP Job Stop event. "
> +			       "Considering running task finished.\n");
> +		if (!process_pp_job(ctx, ev, un))
> +			return false;
> +	}
> +
> +	ctx->gpu_state.pp[un].status = UNIT_BUSY;
> +	ctx->gpu_state.pp[un].job_start = ev->timestamp;
> +	ctx->gpu_state.pp[un].pid = ev->d0;
> +	ctx->gpu_state.pp[un].tid = ev->d1;
> +	return true;
> +}
> +
> +/* ************************************************************************ */
> +
> +static bool
> +process_start_event(mali_ctx *ctx, const mali_event *ev)
> +{
> +	/* Skip events that was before program start
> +	 * or after program finish */
> +	if ((signed long long)ev->timestamp < ctx->start_time ||
> +	    (signed long long)ev->timestamp > ctx->finish_time) {
> +		dprintf(MISC_EVENTS,
> +			"Skipping Start event out of time interval (ts=%lld, "
> +			"st=%lld, fn=%lld).\n",
> +			ev->timestamp, ctx->start_time, ctx->finish_time);
> +		return true;
> +	}
> +
> +	if (!is_gp_or_pp_channel(ev->channel)) {
> +		print_date(MISC_EVENTS, ev);
> +		dprintf(MISC_EVENTS, "Skipping Start event from uninterested "
> +			"channel %s.\n", get_channel_name(ev->channel));
> +		return true;
> +	}
> +
> +	if (is_gp_channel(ev->channel))
> +		return process_gp_job_start(ctx, ev);
> +	else
> +		return process_pp_job_start(ctx, ev);
> +}
> +
> +/* ************************************************************************ */
> +
> +/* Channel is a GP channel here */
> +static bool
> +process_gp_job_stop(mali_ctx *ctx, const mali_event *ev)
> +{
> +	int un;
> +	int src0, src1;
> +
> +	src0 = ev->d2 & 0xff;
> +	src1 = ev->d2 >> 8;
> +	print_date(TASK_EVENTS, ev);
> +	dprintf(TASK_EVENTS,
> +		"GP job stopped at %s with val0 = %u, val1 = %u, "
> +		"src0 = %u, src1 = %u\n",
> +		get_gp_name(ev->channel), ev->d0, ev->d1, src0, src1);
> +	un = gp_number(ev->channel);
> +	if (ctx->gpu_state.gp[un].status != UNIT_BUSY) {
> +		edprintf(WARN, "Skipping GP Job Stop event because unit "
> +			       "is already free.\n");
> +		return true;
> +	}
> +
> +	return process_gp_job(ctx, ev, un);
> +}
> +
> +/* ************************************************************************ */
> +
> +/* Channel is a PP channel here */
> +static bool
> +process_pp_job_stop(mali_ctx *ctx, const mali_event *ev)
> +{
> +	int un;
> +	int src0, src1;
> +
> +	src0 = ev->d2 & 0xff;
> +	src1 = ev->d2 >> 8;
> +	print_date(TASK_EVENTS, ev);
> +	dprintf(TASK_EVENTS,
> +		"PP job stopped at %s with val0 = %u, val1 = %u, "
> +		"src0 = %u, src1 = %u\n",
> +		get_pp_name(ev->channel), ev->d0, ev->d1, src0, src1);
> +	un = pp_number(ev->channel);
> +	if (ctx->gpu_state.pp[un].status != UNIT_BUSY) {
> +		edprintf(WARN, "Skipping PP Job Stop event because unit "
> +			       "is already free.\n");
> +		return true;
> +	}
> +
> +	return process_pp_job(ctx, ev, un);
> +}
> +
> +/* ************************************************************************ */
> +
> +static bool
> +process_stop_event(mali_ctx *ctx, const mali_event *ev)
> +{
> +	/* Skip events that was before program start
> +	 * or after program finish */
> +	if ((signed long long)ev->timestamp < ctx->start_time ||
> +	    (signed long long)ev->timestamp > ctx->finish_time) {
> +		dprintf(MISC_EVENTS,
> +			"Skipping Stop event out of time interval.\n");
> +		return true;
> +	}
> +
> +	if (!is_gp_or_pp_channel(ev->channel)) {
> +		print_date(MISC_EVENTS, ev);
> +		dprintf(MISC_EVENTS,
> +			"Skipping Stop event from uninterested channel %s.\n",
> +			get_channel_name(ev->channel));
> +		return true;
> +	}
> +
> +	if (is_gp_channel(ev->channel))
> +		return process_gp_job_stop(ctx, ev);
> +	else
> +		return process_pp_job_stop(ctx, ev);
> +}
> +
> +/* ************************************************************************ */
> +
> +static bool
> +process_sw_global_try_lock(const mali_event *ev)
> +{
> +	print_date(MISC_EVENTS, ev);
> +	dprintf(MISC_EVENTS,
> +		"SW Global Try Lock by pid = %u, tid = %u, key = %u\n",
> +		ev->d0, ev->d1, ev->d2);
> +	return true;
> +}
> +
> +/* ************************************************************************ */
> +
> +static bool
> +process_sw_global_lock(const mali_event *ev)
> +{
> +	print_date(MISC_EVENTS, ev);
> +	dprintf(MISC_EVENTS,
> +		"SW Global Lock     by pid = %u, tid = %u, key = %u\n",
> +		ev->d0, ev->d1, ev->d2);
> +	return true;
> +}
> +
> +/* ************************************************************************ */
> +
> +static bool
> +process_sw_global_unlock(const mali_event *ev)
> +{
> +	print_date(MISC_EVENTS, ev);
> +	dprintf(MISC_EVENTS,
> +		"SW Global Unlock   by pid = %u, tid = %u, key = %u\n",
> +		ev->d0, ev->d1, ev->d2);
> +	return true;
> +}
> +

can we factor out generic 

	process_sw_global_lock_op(const mali_event *ev, const char *op)
	{
		print_date(MISC_EVENTS, ev);
		dprintf(MISC_EVENTS,
			"%s   by pid = %u, tid = %u, key = %u\n", op,
			ev->d0, ev->d1, ev->d2);
		return true;
	}

and use

	process_sw_global_lock_op(ev, SW_GLOBAL_TRY_LOCK);
	process_sw_global_lock_op(ev, SW_GLOBAL_LOCK);
	process_sw_global_lock_op(ev, SW_GLOBAL_UNLOCK);

where #define SW_GLOBAL_TRY_LOCK "SW Global Try Lock", etc.


for example, 
process_pp_job() and process_pp_job() are identical, with the only difference in
unit_state being addressed: pp or gp.

in other words, if there is no difference from techical point of view (well, almost)
what job we start/stop/process, then *PROBABLY* we can have generic job start/stop/process
function taking UNIT_STATE_TYPE (e.g.) as additional parameter.
what do you think?


	-ss

> +/* ************************************************************************ */
> +
> +/* on:
> + *  0 -- Device is powering up,
> + *  1 -- Device is powering down,
> + * -1 -- Don't care about device state and don't issue warnings. */
> +static void
> +split_gp_jobs(mali_ctx *ctx, const mali_event *ev, int on)
> +{
> +	int i;
> +
> +	for (i = 0; i < GP_NUM; i++) {
> +		if (ctx->gpu_state.gp[i].status == UNIT_FREE)
> +			continue;
> +
> +		if (on == 1)
> +			dprintf(WARN,
> +				"Strange thing. GP%d is turned on while "
> +				"task is already running.\n", i);
> +		else if (on == 0)
> +			dprintf(WARN,
> +				"Strange thing. GP%d is turned off while "
> +				"task is still running.\n", i);
> +
> +		dprintf(MISC_EVENTS, "Next GP job is splitted.\n");
> +		/* Split task and "restart" job with the same pid */
> +		process_gp_job(ctx, ev, i);
> +		ctx->gpu_state.gp[i].status = UNIT_BUSY;
> +		ctx->gpu_state.gp[i].job_start = ev->timestamp;
> +	}
> +}
> +
> +/* ************************************************************************ */
> +
> +static void
> +split_pp_jobs(mali_ctx *ctx, const mali_event *ev, int on)
> +{
> +	int i;
> +
> +	for (i = 0; i < PP_NUM; i++) {
> +		if (ctx->gpu_state.pp[i].status == UNIT_FREE)
> +			continue;
> +
> +		if (on == 1)
> +			dprintf(WARN,
> +				"Strange thing. PP%d is turned on while "
> +				"task is already running.\n", i);
> +		else if (on == 0)
> +			dprintf(WARN,
> +				"Strange thing. PP%d is turned off while "
> +				"task is still running.\n", i);
> +
> +		dprintf(MISC_EVENTS, "Next PP job is splitted.\n");
> +		/* Split task and "restart" job with the same pid */
> +		process_pp_job(ctx, ev, i);
> +		ctx->gpu_state.pp[i].status = UNIT_BUSY;
> +		ctx->gpu_state.pp[i].job_start = ev->timestamp;
> +	}
> +}
> +
> +/* ************************************************************************ */
> +
> +static void
> +split_jobs(mali_ctx *ctx, const mali_event *ev, int on)
> +{
> +	/* It seems that it is impossible to change Only voltage without
> +	 * changing frequency. And it seems that these events are always
> +	 * come in pairs. So we split our jobs at first event and skip
> +	 * second to avoid reports with strange frequency / voltage
> +	 * combination. It would be better to know dependancy between
> +	 * frequency and voltage so we can adjust another when one changes.*/
> +	if (ctx->gpu_state.split_count & 1)
> +		return;
> +
> +	split_gp_jobs(ctx, ev, on);
> +	split_pp_jobs(ctx, ev, on);
> +}
> +
> +/* ************************************************************************ */
> +
> +static bool
> +process_sw_gpu_freq(mali_ctx *ctx, const mali_event *ev)
> +{
> +	if (!ev->d1) {
> +		print_date(MISC_EVENTS, ev);
> +		dprintf(MISC_EVENTS, "SW GPU Freq rate (previous) = %u\n",
> +			ev->d0);
> +		return true;
> +	}
> +
> +	if (ctx->gpu_state.freq == (signed int)ev->d0)
> +		return true;
> +
> +	split_jobs(ctx, ev, -1);
> +	ctx->gpu_state.freq = ev->d0;
> +	ctx->gpu_state.split_count++;
> +	print_date(TASK_EVENTS, ev);
> +	dprintf(TASK_EVENTS, "GPU frequency changed to %d\n",
> +		ctx->gpu_state.freq);
> +	return true;
> +}
> +
> +/* ************************************************************************ */
> +
> +static bool
> +process_sw_gpu_volts(mali_ctx *ctx, const mali_event *ev)
> +{
> +	if (ev->d2 != 2) {
> +		print_date(MISC_EVENTS, ev);
> +		dprintf(MISC_EVENTS,
> +			"SW GPU Volts min_uV = %u, max_uV = %u (Desired)\n",
> +			ev->d0, ev->d1);
> +		return true;
> +	}
> +
> +	if (ctx->gpu_state.volt == (signed int)ev->d0)
> +		return true;
> +
> +	split_jobs(ctx, ev, -1);
> +	ctx->gpu_state.volt = ev->d0;
> +	ctx->gpu_state.split_count++;
> +	print_date(TASK_EVENTS, ev);
> +	dprintf(TASK_EVENTS, "GPU voltage changed to %d\n",
> +		ctx->gpu_state.volt);
> +	return true;
> +}
> +
> +/* ************************************************************************ */
> +
> +static bool
> +process_single_software_event(mali_ctx *ctx, const mali_event *ev)
> +{
> +	switch (ev->data) {
> +		case MALI_PROFILING_EVENT_REASON_SINGLE_SW_GPU_FREQ:
> +			return process_sw_gpu_freq(ctx, ev);
> +		case MALI_PROFILING_EVENT_REASON_SINGLE_SW_GPU_VOLTS:
> +			return process_sw_gpu_volts(ctx, ev);
> +		case MALI_PROFILING_EVENT_REASON_SINGLE_SW_GLOBAL_TRY_LOCK:
> +			return process_sw_global_try_lock(ev);
> +		case MALI_PROFILING_EVENT_REASON_SINGLE_SW_GLOBAL_LOCK:
> +			return process_sw_global_lock(ev);
> +		case MALI_PROFILING_EVENT_REASON_SINGLE_SW_GLOBAL_UNLOCK:
> +			return process_sw_global_unlock(ev);
> +			break;
> +/*		case MALI_PROFILING_EVENT_REASON_SINGLE_SW_VBLANK_VSYNC:*/
> +/*		case MALI_PROFILING_EVENT_REASON_SINGLE_GPU_FREQ_VOLT_CHANGE:*/
> +		default:
> +			print_date(WARN, ev);
> +			dprintf(WARN, "Skipping Single software event "
> +				"with unknown data %d.\n", ev->data);
> +			break;
> +	}
> +
> +	return true;
> +}
> +
> +/* ************************************************************************ */
> +
> +static bool
> +process_hw_interrupt(const mali_event *ev)
> +{
> +	if (!is_gp_or_pp_channel(ev->channel)) {
> +		print_date(WARN, ev);
> +		dprintf(WARN, "Skipping HW Interrupt event from wrong "
> +			"channel %s.\n", get_channel_name(ev->channel));
> +		return true;
> +	}
> +
> +	print_date(MISC_EVENTS, ev);
> +	dprintf(MISC_EVENTS, "HW Interrupt at %s with irq_readout = %u\n",
> +		get_channel_name(ev->channel), ev->d0);
> +	return true;
> +}
> +
> +/* ************************************************************************ */
> +
> +static bool
> +process_hw_flush(const mali_event *ev)
> +{
> +	if (!is_gp_or_pp_channel(ev->channel)) {
> +		print_date(WARN, ev);
> +		dprintf(WARN, "Skipping HW Flush event from wrong "
> +			"channel %s.\n", get_channel_name(ev->channel));
> +		return true;
> +	}
> +
> +	print_date(MISC_EVENTS, ev);
> +	dprintf(MISC_EVENTS,
> +		"HW Flush at %s with frame_builder_id = %u, flush_id, = %u\n",
> +		get_channel_name(ev->channel), ev->d0, ev->d1);
> +	return true;
> +}
> +
> +/* ************************************************************************ */
> +
> +static bool
> +update_jobs(mali_ctx *ctx, const mali_event *ev, int new_freq, int new_volt)
> +{
> +	/* Nothing to change */
> +	if (ctx->gpu_state.freq == new_freq &&
> +	    ctx->gpu_state.volt == new_volt)
> +		return true;
> +
> +	if (new_freq) {
> +		dprintf(TASK_EVENTS, "GPU is ON now\n");
> +		/* Shouldn't have any jobs running but recheck it for sure */
> +		split_jobs(ctx, ev, 1);
> +	} else {
> +		dprintf(TASK_EVENTS, "GPU is OFF now\n");
> +		/* Shouldn't have any jobs running but recheck it for sure */
> +		split_jobs(ctx, ev, 0);
> +	}
> +
> +	ctx->gpu_state.freq = new_freq;
> +	ctx->gpu_state.volt = new_volt;
> +	ctx->gpu_state.split_count = 0;
> +	dprintf(TASK_EVENTS, "GPU frequency changed to %d, voltage to %d\n",
> +		ctx->gpu_state.freq, ctx->gpu_state.volt);
> +	return true;
> +}
> +
> +/* ************************************************************************ */
> +
> +static bool
> +process_gpu_freq_volt_change(mali_ctx *ctx, const mali_event *ev)
> +{
> +	if (ev->channel != MALI_PROFILING_EVENT_CHANNEL_GPU) {
> +		print_date(WARN, ev);
> +		dprintf(WARN,
> +			"Skipping GPU Freq Volt event from wrong channel "
> +			"%s.\n", get_channel_name(ev->channel));
> +		return true;
> +	}
> +
> +	dprintf(MISC_EVENTS, "GPU Volt Change with mali_gpu_clk = %u, "
> +			     "mali_gpu_vol / 1000 = %u\n",
> +		ev->d0, ev->d1);
> +	return update_jobs(ctx, ev, ev->d0 * 1000000, ev->d1 * 1000);
> +}
> +
> +/* ************************************************************************ */
> +
> +static bool
> +process_single_hardware_event(mali_ctx *ctx, const mali_event *ev)
> +{
> +	switch (ev->data) {
> +		case MALI_PROFILING_EVENT_REASON_SINGLE_HW_INTERRUPT:
> +			return process_hw_interrupt(ev);
> +		case MALI_PROFILING_EVENT_REASON_SINGLE_HW_FLUSH:
> +			return process_hw_flush(ev);
> +		case MALI_PROFILING_EVENT_REASON_SINGLE_GPU_FREQ_VOLT_CHANGE:
> +			return process_gpu_freq_volt_change(ctx, ev);
> +		default:
> +			print_date(WARN, ev);
> +			dprintf(WARN, "Skipping Single hardware event "
> +				      "with unknown data %d.\n", ev->data);
> +			break;
> +	}
> +
> +	return true;
> +}
> +
> +/* ************************************************************************ */
> +
> +static bool
> +process_single_event(mali_ctx *ctx, const mali_event *ev)
> +{
> +	if (!is_known_channel(ev->channel)) {
> +		print_date(WARN, ev);
> +		dprintf(WARN,
> +			"Skipping Single event with unknown channel %d.\n",
> +			ev->channel);
> +		return true;
> +	}
> +
> +	if (ev->channel == MALI_PROFILING_EVENT_CHANNEL_SOFTWARE)
> +		return process_single_software_event(ctx, ev);
> +	else
> +		return process_single_hardware_event(ctx, ev);
> +}
> +
> +/* ************************************************************************ */
> +
> +static bool
> +process_unknown_event(const mali_event *ev)
> +{
> +	print_date(WARN, ev);
> +	dprintf(WARN,
> +		"Skipping unknown event: type = %u, channel = %u, data = %u, "
> +		"d0 = %u, d1 = %u, d2 = %u, d3 = %u, d4 = %u.\n",
> +		ev->type, ev->channel, ev->data, ev->d0, ev->d1, ev->d2,
> +		ev->d3, ev->d4);
> +	return true;
> +}
> +
> +
> +/* ************************************************************************ */
> +
> +static bool
> +process_mali_event(mali_ctx *ctx, const mali_event *ev)
> +{
> +	switch (ev->type) {
> +		case MALI_PROFILING_EVENT_TYPE_SINGLE:
> +			return process_single_event(ctx, ev);
> +		case MALI_PROFILING_EVENT_TYPE_START:
> +			return process_start_event(ctx, ev);
> +		case MALI_PROFILING_EVENT_TYPE_STOP:
> +			return process_stop_event(ctx, ev);
> +		case MALI_PROFILING_EVENT_TYPE_SUSPEND:
> +			print_date(MISC_EVENTS, ev);
> +			dprintf(MISC_EVENTS, "Skipping Suspend event.\n");
> +			break;
> +		case MALI_PROFILING_EVENT_TYPE_RESUME:
> +			print_date(MISC_EVENTS, ev);
> +			dprintf(MISC_EVENTS, "Skipping Resume event.\n");
> +			break;
> +		default:
> +			return process_unknown_event(ev);
> +	}
> +
> +	return true;
> +}
> +
> +/* ************************************************************************ */
> +
> +static bool
> +parse_mali_event(mali_ctx *ctx, const char *line)
> +{
> +	mali_event ev;
> +	unsigned int event_id;
> +
> +	if (sscanf(line, "%llu %u %u %u %u %u %u", &ev.timestamp, &event_id,
> +		   &ev.d0, &ev.d1, &ev.d2, &ev.d3, &ev.d4) != 7) {
> +		edprintf(CRIT, "Wrong event line: %s", line);
> +		return false;
> +	}
> +
> +	/* Doesn't skip events here because we need information about current
> +	 * voltage and frequency. Will skip only job-related events later. */
> +
> +	ev.type    = (event_id >> 24) & 0xf;
> +	ev.channel = (event_id >> 16) & 0xff;
> +	ev.data    = event_id & 0xffff;
> +	return process_mali_event(ctx, &ev);
> +}
> +
> +/* ************************************************************************ */
> +
> +bool
> +process_mali_events(mali_ctx *ctx)
> +{
> +	FILE *f;
> +	char line[4096];
> +
> +	if (!ctx || ctx->processed)
> +		return false;
> +
> +	f = fopen(ctx->fname, "r");
> +	if (!f) {
> +		edprintf(CRIT, "Can't open \"%s\".\n", ctx->fname);
> +		ctx->error_flag = 1;
> +		return false;
> +	}
> +
> +	while (fgets(line, sizeof(line), f))
> +		if (parse_mali_event(ctx, line) == -1) {
> +			ctx->error_flag = 1;
> +			return false;
> +		}
> +
> +	fclose(f);
> +	ctx->processed = true;
> +	return true;
> +}
> +
> +/* ************************************************************************ */
> +
> +static void
> +init_gpu_state(mali_ctx *ctx)
> +{
> +	memset(&ctx->gpu_state, '\0', sizeof(mali_state));
> +	ctx->gpu_state.freq = -1; /* Unknown */
> +	ctx->gpu_state.volt = -1; /* Unknown */
> +}
> +
> +/* ************************************************************************ */
> +
> +bool
> +cleanup_mali_capture(mali_ctx **ctx)
> +{
> +	if (!ctx || !*ctx)
> +		return true;
> +
> +	clear_procs_info();
> +
> +	if ((*ctx)->live &&
> +			!restore_mode((*ctx)->old_enable, (*ctx)->old_record))
> +		return false;
> +
> +	free(*ctx);
> +	*ctx = NULL;
> +
> +	return true;
> +}
> +
> +/* ************************************************************************ */
> +
> +static bool
> +stat_callback(const process_info *pinfo, void *data UNUSED)
> +{
> +	const char *comm, *cmdline;
> +
> +	if (pinfo->power == 0) /* Skip empty */
> +		return true;
> +
> +	dprintf(TOTAL_REPORT,
> +		"Total consumed power by pid %d is %lg PseudoWatts*s\n",
> +		pinfo->pid, pinfo->power);
> +
> +	if (!pinfo->unknown_name) {
> +		comm    = pinfo->comm;
> +		cmdline = pinfo->cmdline;
> +	} else if (!get_pt_proc_info(pinfo->pid, &comm, &cmdline)) {
> +		comm    = "(Unknown)";
> +		cmdline = "(Unknown)";
> +	}
> +
> +	report.begin_row(ROW_SOFTWARE);
> +	report.begin_cell();
> +	report.addf("%.4f PWs", pinfo->power);
> +	report.begin_cell();
> +	report.addf("%d", pinfo->pid);
> +	report.begin_cell();
> +	report.add(comm);
> +	report.begin_cell();
> +	report.add(cmdline);
> +	return true;
> +}
> +
> +/* ************************************************************************ */
> +
> +bool
> +print_mali_stat(mali_ctx *ctx)
> +{
> +	char *oldlocale;
> +
> +	if (!ctx)
> +		return false;
> +
> +	if (ctx->error_flag || ctx->started || !ctx->processed) {
> +		edprintf(CRIT,
> +			 "Errors was encountered during processing '%s'\n",
> +			 ctx->fname);
> +		return false;
> +	}
> +
> +	oldlocale = setlocale(LC_NUMERIC, NULL);
> +	oldlocale = strdup(oldlocale);
> +	setlocale(LC_NUMERIC, "C"); /* For dots in %f in printf() */
> +
> +	report.add_header("Overview of MALI GPU power consumers");
> +	report.begin_table(TABLE_WIDE);
> +	report.begin_row();
> +	report.begin_cell(CELL_SOFTWARE_PROCESS);
> +	report.add("Power est. (PseudoWatts*s)");
> +	report.begin_cell(CELL_SOFTWARE_DESCRIPTION);
> +	report.add("PID");
> +	report.begin_cell(CELL_SOFTWARE_DESCRIPTION);
> +	report.add("Name");
> +	report.begin_cell(CELL_SOFTWARE_DESCRIPTION);
> +	report.add("Description");
> +	print_sorted_procs(stat_callback, NULL);
> +
> +	setlocale(LC_NUMERIC, oldlocale);
> +	free(oldlocale);
> +	return true;
> +}
> +
> +/* ************************************************************************ */
> +
> +bool
> +stop_mali_capture(mali_ctx *ctx)
> +{
> +	if (!ctx || !ctx->started)
> +		return false;
> +
> +	if (ctx->live) {
> +		struct timeval tv;
> +
> +		if (!set_record(0)) /* Stop events recording */
> +			return false;
> +
> +		gettimeofday(&tv, NULL);
> +		ctx->finish_time = (tv.tv_sec * 1000000ll + tv.tv_usec) *
> +				   (TIMESTAMP_FACTOR / 1000000ll);
> +	}
> +
> +	ctx->started = false;
> +	return true;
> +}
> +
> +/* ************************************************************************ */
> +
> +bool
> +start_mali_capture(mali_ctx *ctx)
> +{
> +	if (!ctx || ctx->started)
> +		return false;
> +
> +	clear_procs_info();
> +	ctx->processed = false;
> +	ctx->error_flag = false;
> +	init_gpu_state(ctx);
> +
> +	if (ctx->live) {
> +		struct timeval tv;
> +
> +		gettimeofday(&tv, NULL);
> +		/* Could be wrong if TIMESTAMP_FACTOR is not divisible
> +		 * by 1000000 or if TIMESTAMP_FACTOR is less than 1000000. */
> +		ctx->start_time = (tv.tv_sec * 1000000ll + tv.tv_usec) *
> +				  (TIMESTAMP_FACTOR / 1000000ll);
> +
> +		if (!set_mode()) /* Start events recording */
> +			return false;
> +	} else {
> +		ctx->start_time = -1;
> +		ctx->finish_time = 0x7fffffffffffffffll;
> +	}
> +
> +	ctx->started = true;
> +	return true;
> +}
> +
> +/* ************************************************************************ */
> +
> +mali_ctx *
> +init_mali_capture_ex(bool live, const char *fname)
> +{
> +	mali_ctx *ctx;
> +
> +	ctx = (mali_ctx *)malloc(sizeof(mali_ctx));
> +	if (!ctx) {
> +		edprintf(CRIT, "No free memory.\n");
> +		return NULL;
> +	}
> +
> +	memset(ctx, '\0', sizeof(mali_ctx));
> +	ctx->live = live;
> +	ctx->fname = fname;
> +	ctx->started = false;
> +	ctx->processed = false;
> +
> +	if (live && !save_mode(&ctx->old_enable, &ctx->old_record)) {
> +		free(ctx);
> +		return NULL;
> +	}
> +
> +	return ctx;
> +}
> +
> +/* ************************************************************************ */
> +
> +mali_ctx *
> +init_mali_capture()
> +{
> +	return init_mali_capture_ex(true, MALI_PROFILING_EVENTS);
> +}
> +
> +/* ************************************************************************ */
> +
> +#else /* !ARM */
> +
> +/* ************************************************************************ */
> +
> +mali_ctx *
> +init_mali_capture()
> +{
> +	return NULL;
> +}
> +
> +/* ************************************************************************ */
> +
> +bool
> +start_mali_capture(mali_ctx *ctx UNUSED)
> +{
> +	return true;
> +}
> +
> +/* ************************************************************************ */
> +
> +bool
> +stop_mali_capture(mali_ctx *ctx UNUSED)
> +{
> +	return true;
> +}
> +
> +/* ************************************************************************ */
> +
> +bool
> +process_mali_events(mali_ctx *ctx UNUSED)
> +{
> +	return true;
> +}
> +
> +/* ************************************************************************ */
> +
> +bool
> +print_mali_stat(mali_ctx *ctx UNUSED)
> +{
> +	return true;
> +}
> +
> +/* ************************************************************************ */
> +
> +bool
> +cleanup_mali_capture(mali_ctx **ctx UNUSED)
> +{
> +	return true;
> +}
> +
> +#endif /* !ARM */
> -- 
> 1.7.5.4
> 
> _______________________________________________
> PowerTop mailing list
> PowerTop(a)lists.01.org
> https://lists.01.org/mailman/listinfo/powertop
> 

             reply	other threads:[~2012-12-25 20:58 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-12-25 20:58 Sergey Senozhatsky [this message]
  -- strict thread matches above, loose matches on Subject: below --
2012-11-01 12:00 [Powertop] [FYI][RFC][PATCH 2/2] MALI GPU profiling support Igor Zhbanov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20121225205825.GG3307@swordfish \
    --to=powertop@lists.01.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.