msm: kgsl: Add APIs to provide GPU stats

Add APIs which provide per GPU freq active and total time,
number of GPU frequency corners and number of frames
processed by GPU.

Change-Id: If42e76a435a4766a3de0b9b028d48b6c1759e466
Signed-off-by: Deepak Kumar <dkumar@codeaurora.org>
This commit is contained in:
Deepak Kumar 2021-03-10 18:29:45 +05:30
commit e646feb198
12 changed files with 144 additions and 4 deletions

View file

@ -2948,6 +2948,8 @@ static int a6xx_boot(struct adreno_device *adreno_dev)
kgsl_pwrscale_wake(device);
set_bit(GMU_PRIV_GPU_STARTED, &gmu->flags);
device->pwrctrl.last_stat_updated = ktime_get();
device->state = KGSL_STATE_ACTIVE;
trace_kgsl_pwr_set_state(device, KGSL_STATE_ACTIVE);
@ -3016,6 +3018,7 @@ static int a6xx_first_boot(struct adreno_device *adreno_dev)
set_bit(GMU_PRIV_FIRST_BOOT_DONE, &gmu->flags);
set_bit(GMU_PRIV_GPU_STARTED, &gmu->flags);
device->pwrctrl.last_stat_updated = ktime_get();
device->state = KGSL_STATE_ACTIVE;
trace_kgsl_pwr_set_state(device, KGSL_STATE_ACTIVE);
@ -3277,6 +3280,8 @@ static void a6xx_gmu_touch_wakeup(struct adreno_device *adreno_dev)
kgsl_pwrscale_wake(device);
set_bit(GMU_PRIV_GPU_STARTED, &gmu->flags);
device->pwrctrl.last_stat_updated = ktime_get();
device->state = KGSL_STATE_ACTIVE;
trace_kgsl_pwr_set_state(device, KGSL_STATE_ACTIVE);

View file

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
* Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
*/
#include <linux/clk.h>
@ -500,6 +500,7 @@ static void a6xx_hwsched_touch_wakeup(struct adreno_device *adreno_dev)
set_bit(GMU_PRIV_GPU_STARTED, &gmu->flags);
device->pwrctrl.last_stat_updated = ktime_get();
device->state = KGSL_STATE_ACTIVE;
trace_kgsl_pwr_set_state(device, KGSL_STATE_ACTIVE);
@ -541,6 +542,8 @@ static int a6xx_hwsched_boot(struct adreno_device *adreno_dev)
kgsl_pwrscale_wake(device);
set_bit(GMU_PRIV_GPU_STARTED, &gmu->flags);
device->pwrctrl.last_stat_updated = ktime_get();
device->state = KGSL_STATE_ACTIVE;
trace_kgsl_pwr_set_state(device, KGSL_STATE_ACTIVE);
@ -589,6 +592,7 @@ static int a6xx_hwsched_first_boot(struct adreno_device *adreno_dev)
set_bit(GMU_PRIV_FIRST_BOOT_DONE, &gmu->flags);
set_bit(GMU_PRIV_GPU_STARTED, &gmu->flags);
device->pwrctrl.last_stat_updated = ktime_get();
device->state = KGSL_STATE_ACTIVE;
trace_kgsl_pwr_set_state(device, KGSL_STATE_ACTIVE);

View file

@ -896,6 +896,7 @@ static int a6xx_boot(struct adreno_device *adreno_dev)
set_bit(RGMU_PRIV_GPU_STARTED, &rgmu->flags);
device->pwrctrl.last_stat_updated = ktime_get();
device->state = KGSL_STATE_ACTIVE;
trace_kgsl_pwr_set_state(device, KGSL_STATE_ACTIVE);
@ -934,6 +935,7 @@ static void a6xx_rgmu_touch_wakeup(struct adreno_device *adreno_dev)
set_bit(RGMU_PRIV_GPU_STARTED, &rgmu->flags);
device->pwrctrl.last_stat_updated = ktime_get();
device->state = KGSL_STATE_ACTIVE;
trace_kgsl_pwr_set_state(device, KGSL_STATE_ACTIVE);
@ -1002,6 +1004,7 @@ static int a6xx_first_boot(struct adreno_device *adreno_dev)
set_bit(RGMU_PRIV_FIRST_BOOT_DONE, &rgmu->flags);
set_bit(RGMU_PRIV_GPU_STARTED, &rgmu->flags);
device->pwrctrl.last_stat_updated = ktime_get();
device->state = KGSL_STATE_ACTIVE;
trace_kgsl_pwr_set_state(device, KGSL_STATE_ACTIVE);

View file

@ -304,6 +304,9 @@ static void _retire_timestamp(struct kgsl_drawobj *drawobj)
context->id, drawobj->timestamp,
!!(drawobj->flags & KGSL_DRAWOBJ_END_OF_FRAME));
if (drawobj->flags & KGSL_DRAWOBJ_END_OF_FRAME)
atomic64_inc(&context->proc_priv->frame_count);
/*
* For A3xx we still get the rptr from the CP_RB_RPTR instead of
* rptr scratch out address. At this point GPU clocks turned off.
@ -2355,6 +2358,9 @@ static void retire_cmdobj(struct adreno_device *adreno_dev,
context->id, drawobj->timestamp,
!!(drawobj->flags & KGSL_DRAWOBJ_END_OF_FRAME));
if (drawobj->flags & KGSL_DRAWOBJ_END_OF_FRAME)
atomic64_inc(&context->proc_priv->frame_count);
/*
* For A3xx we still get the rptr from the CP_RB_RPTR instead of
* rptr scratch out address. At this point GPU clocks turned off.

View file

@ -12,6 +12,7 @@
#include <linux/ion.h>
#include <linux/mman.h>
#include <linux/mm_types.h>
#include <linux/msm_kgsl.h>
#include <linux/of.h>
#include <linux/of_fdt.h>
#include <linux/pm_runtime.h>
@ -1043,6 +1044,24 @@ done:
return private;
}
int kgsl_gpu_frame_count(pid_t pid, u64 *frame_count)
{
struct kgsl_process_private *p;
if (!frame_count)
return -EINVAL;
p = kgsl_process_private_find(pid);
if (!p)
return -ENOENT;
*frame_count = atomic64_read(&p->frame_count);
kgsl_process_private_put(p);
return 0;
}
EXPORT_SYMBOL(kgsl_gpu_frame_count);
static int kgsl_close_device(struct kgsl_device *device)
{
int result = 0;

View file

@ -5,12 +5,12 @@
#ifndef __KGSL_H
#define __KGSL_H
#include <uapi/linux/msm_kgsl.h>
#include <linux/cdev.h>
#include <linux/compat.h>
#include <linux/interrupt.h>
#include <linux/kthread.h>
#include <linux/mm.h>
#include <linux/msm_kgsl.h>
#include <linux/uaccess.h>
#include "kgsl_gmu_core.h"

View file

@ -1,12 +1,12 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2013-2017,2019 The Linux Foundation. All rights reserved.
* Copyright (c) 2013-2017,2019,2021 The Linux Foundation. All rights reserved.
*/
#ifndef __KGSL_COMPAT_H
#define __KGSL_COMPAT_H
#include <uapi/linux/msm_kgsl.h>
#include <linux/compat.h>
#include <linux/msm_kgsl.h>
#ifdef CONFIG_COMPAT

View file

@ -437,6 +437,7 @@ struct kgsl_context {
* @fd_count: Counter for the number of FDs for this process
* @ctxt_count: Count for the number of contexts for this process
* @ctxt_count_lock: Spinlock to protect ctxt_count
* @frame_count: Count for the number of frames processed
*/
struct kgsl_process_private {
unsigned long priv;
@ -460,6 +461,7 @@ struct kgsl_process_private {
int fd_count;
atomic_t ctxt_count;
spinlock_t ctxt_count_lock;
atomic64_t frame_count;
};
/**

View file

@ -4,6 +4,7 @@
*/
#include <linux/interconnect.h>
#include <linux/msm_kgsl.h>
#include <linux/of_device.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
@ -1878,6 +1879,7 @@ static int _wake(struct kgsl_device *device)
kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_ON, KGSL_STATE_ACTIVE);
device->ftbl->deassert_gbif_halt(device);
pwr->last_stat_updated = ktime_get();
/*
* No need to turn on/off irq here as it no longer affects
* power collapse
@ -2258,3 +2260,42 @@ int kgsl_pwrctrl_set_default_gpu_pwrlevel(struct kgsl_device *device)
/* Request adjusted DCVS level */
return device->ftbl->gpu_clock_set(device, pwr->active_pwrlevel);
}
int kgsl_gpu_num_freqs(void)
{
struct kgsl_device *device = kgsl_get_device(0);
if (!device)
return -ENODEV;
return device->pwrctrl.num_pwrlevels;
}
EXPORT_SYMBOL(kgsl_gpu_num_freqs);
int kgsl_gpu_stat(struct kgsl_gpu_freq_stat *stats, u32 numfreq)
{
struct kgsl_device *device = kgsl_get_device(0);
struct kgsl_pwrctrl *pwr;
int i;
if (!device)
return -ENODEV;
pwr = &device->pwrctrl;
if (!stats || (numfreq < pwr->num_pwrlevels))
return -EINVAL;
mutex_lock(&device->mutex);
kgsl_pwrscale_update_stats(device);
for (i = 0; i < pwr->num_pwrlevels; i++) {
stats[i].freq = pwr->pwrlevels[i].gpu_freq;
stats[i].active_time = pwr->clock_times[i];
stats[i].idle_time = pwr->time_in_pwrlevel[i] - pwr->clock_times[i];
}
mutex_unlock(&device->mutex);
return 0;
}
EXPORT_SYMBOL(kgsl_gpu_stat);

View file

@ -175,6 +175,10 @@ struct kgsl_pwrctrl {
u32 minbw_timeout;
/** @ddr_qos_devfreq: Devfreq device for setting DDR qos policy */
struct devfreq *ddr_qos_devfreq;
/** @time_in_pwrlevel: Each pwrlevel active duration in usec */
u64 time_in_pwrlevel[KGSL_MAX_PWRLEVELS];
/** @last_stat_updated: The last time stats were updated */
ktime_t last_stat_updated;
};
int kgsl_pwrctrl_init(struct kgsl_device *device);

View file

@ -122,6 +122,7 @@ void kgsl_pwrscale_update_stats(struct kgsl_device *device)
if (device->state == KGSL_STATE_ACTIVE) {
struct kgsl_power_stats stats;
ktime_t cur_time = ktime_get();
device->ftbl->power_stats(device, &stats);
device->pwrscale.accum_stats.busy_time += stats.busy_time;
@ -129,6 +130,9 @@ void kgsl_pwrscale_update_stats(struct kgsl_device *device)
device->pwrscale.accum_stats.ram_wait += stats.ram_wait;
pwrctrl->clock_times[pwrctrl->active_pwrlevel] +=
stats.busy_time;
pwrctrl->time_in_pwrlevel[pwrctrl->active_pwrlevel] +=
ktime_us_delta(cur_time, pwrctrl->last_stat_updated);
pwrctrl->last_stat_updated = cur_time;
}
}

52
include/linux/msm_kgsl.h Normal file
View file

@ -0,0 +1,52 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
*/
#ifndef _MSM_KGSL_H
#define _MSM_KGSL_H
/**
* struct kgsl_gpu_freq_stat - Per GPU freq stat struct
* @freq: GPU frequency in Hz
* @active_time: GPU busy time in usecs
* @idle_time: GPU idle time in usec
*/
struct kgsl_gpu_freq_stat {
u32 freq;
u64 active_time;
u64 idle_time;
};
/**
* kgsl_gpu_num_freqs - Get number of available GPU frequencies
*
* Return: number of available frequencies on success or negative error
* on failure
*/
int kgsl_gpu_num_freqs(void);
/**
* kgsl_gpu_stat - Get per GPU freq stats
* @stats: Array of struct kgsl_gpu_freq_stat to hold stats
* @numfreq: Number of entries in @stats
*
* This function will populate @stats with per freq stats.
* Number of entries in @stats array must be greater or
* equal to value returned by function kgsl_gpu_num_freqs
*
* Return: 0 on success or negative error on failure
*/
int kgsl_gpu_stat(struct kgsl_gpu_freq_stat *stats, u32 numfreq);
/**
* kgsl_gpu_frame_count - Get number of frames already processed by GPU
* @pid: pid of the process for which frame count is required
* @frame_count: pointer to a u64 to store frame count
*
* Return: zero on success and number of frames processed corresponding
* to @pid in @frame_count or negative error on failure
*/
int kgsl_gpu_frame_count(pid_t pid, u64 *frame_count);
#endif /* _MSM_KGSL_H */