qcacmn: Add major print logic for SKB

Add major print logic for SKB as it is currently done for kmalloc and
dma allocations so that SKB allocations can be profiled.

Change-Id: Ic78cef61bc1519aa54da9823199add92c116aad7
CRs-Fixed: 2769631
This commit is contained in:
Alan Chen
2020-08-27 20:00:10 -07:00
committed by snandini
parent a5219e6980
commit 907c485706
3 changed files with 294 additions and 30 deletions

View File

@@ -148,6 +148,9 @@
#define QDF_NBUF_TX_PKT_STATE_MAX 10 #define QDF_NBUF_TX_PKT_STATE_MAX 10
#define QDF_NBUF_TX_PKT_LI_DP 11 #define QDF_NBUF_TX_PKT_LI_DP 11
/* nbuf allocations only come from one domain */
#define QDF_DEBUG_NBUF_DOMAIN 0
/* qdf_nbuf allocate and map max retry threshold when failed */ /* qdf_nbuf allocate and map max retry threshold when failed */
#define QDF_NBUF_ALLOC_MAP_RETRY_THRESHOLD 20 #define QDF_NBUF_ALLOC_MAP_RETRY_THRESHOLD 20
@@ -408,7 +411,7 @@ struct qdf_radiotap_vendor_ns {
} __attribute__((__packed__)); } __attribute__((__packed__));
/** /**
* strcut qdf_radiotap_vendor_ns_ath - Combined QTI Vendor NS * struct qdf_radiotap_vendor_ns_ath - Combined QTI Vendor NS
* including the Radiotap specified Vendor Namespace header and * including the Radiotap specified Vendor Namespace header and
* QTI specific Vendor Namespace data * QTI specific Vendor Namespace data
* @lsig: L_SIG_A (or L_SIG) * @lsig: L_SIG_A (or L_SIG)
@@ -425,6 +428,8 @@ struct qdf_radiotap_vendor_ns_ath {
uint32_t ppdu_start_timestamp; uint32_t ppdu_start_timestamp;
} __attribute__((__packed__)); } __attribute__((__packed__));
#define QDF_MEM_FUNC_NAME_SIZE 48
/* Masks for HE SIG known fields in mon_rx_status structure */ /* Masks for HE SIG known fields in mon_rx_status structure */
#define QDF_MON_STATUS_HE_SIG_B_COMMON_KNOWN_RU0 0x00000001 #define QDF_MON_STATUS_HE_SIG_B_COMMON_KNOWN_RU0 0x00000001
#define QDF_MON_STATUS_HE_SIG_B_COMMON_KNOWN_RU1 0x00000002 #define QDF_MON_STATUS_HE_SIG_B_COMMON_KNOWN_RU1 0x00000002
@@ -654,6 +659,37 @@ enum cb_ftype {
*/ */
typedef __qdf_nbuf_t qdf_nbuf_t; typedef __qdf_nbuf_t qdf_nbuf_t;
/**
* struct qdf_nbuf_track_t - Network buffer track structure
*
* @p_next: Pointer to next
* @net_buf: Pointer to network buffer
* @func_name: Function name
* @line_num: Line number
* @size: Size
* @map_func_name: nbuf mapping function name
* @map_line_num: mapping function line number
* @unmap_func_name: nbuf unmapping function name
* @unmap_line_num: mapping function line number
* @is_nbuf_mapped: indicate mapped/unmapped nbuf
* @time: mapping function timestamp
*/
struct qdf_nbuf_track_t {
struct qdf_nbuf_track_t *p_next;
qdf_nbuf_t net_buf;
char func_name[QDF_MEM_FUNC_NAME_SIZE];
uint32_t line_num;
size_t size;
char map_func_name[QDF_MEM_FUNC_NAME_SIZE];
uint32_t map_line_num;
char unmap_func_name[QDF_MEM_FUNC_NAME_SIZE];
uint32_t unmap_line_num;
bool is_nbuf_mapped;
qdf_time_t time;
};
typedef struct qdf_nbuf_track_t QDF_NBUF_TRACK;
/** /**
* typedef qdf_nbuf_queue_head_t - Platform indepedent nbuf queue head * typedef qdf_nbuf_queue_head_t - Platform indepedent nbuf queue head
*/ */
@@ -1454,6 +1490,9 @@ static inline qdf_nbuf_t qdf_nbuf_next(qdf_nbuf_t buf)
} }
#ifdef NBUF_MEMORY_DEBUG #ifdef NBUF_MEMORY_DEBUG
#define QDF_NET_BUF_TRACK_MAX_SIZE (1024)
void qdf_net_buf_debug_init(void); void qdf_net_buf_debug_init(void);
void qdf_net_buf_debug_exit(void); void qdf_net_buf_debug_exit(void);
void qdf_net_buf_debug_clean(void); void qdf_net_buf_debug_clean(void);
@@ -3907,6 +3946,39 @@ static inline void qdf_net_buf_debug_release_frag(qdf_nbuf_t buf,
} }
#endif /* NBUF_FRAG_MEMORY_DEBUG */ #endif /* NBUF_FRAG_MEMORY_DEBUG */
#ifdef MEMORY_DEBUG
/**
* qdf_nbuf_acquire_track_lock - acquire the nbuf spinlock at the
* specified index
* @index: index to get the lock
* @irq_flag: lock flag for using nbuf lock
*
* Return: none
*/
void qdf_nbuf_acquire_track_lock(uint32_t index,
unsigned long irq_flag);
/**
* qdf_nbuf_release_track_lock - release the nbuf spinlock at the
* specified index
* @index: index of the lock to be released
* @irq_flag: lock flag for using nbuf lock
*
* Return: none
*/
void qdf_nbuf_release_track_lock(uint32_t index,
unsigned long irq_flag);
/**
* qdf_nbuf_get_track_tbl - get the QDF_NBUF_TRACK entry from the track
* table at the specified index
* @index: index to get the table entry
*
* Return: the QDF_NBUF_TRACK entry at the specified index in the table
*/
QDF_NBUF_TRACK *qdf_nbuf_get_track_tbl(uint32_t index);
#endif /* MEMORY_DEBUG */
#ifdef CONFIG_NBUF_AP_PLATFORM #ifdef CONFIG_NBUF_AP_PLATFORM
#include <i_qdf_nbuf_api_w.h> #include <i_qdf_nbuf_api_w.h>
#else #else

View File

@@ -73,6 +73,7 @@ static struct __qdf_mem_stat {
enum list_type { enum list_type {
LIST_TYPE_MEM = 0, LIST_TYPE_MEM = 0,
LIST_TYPE_DMA = 1, LIST_TYPE_DMA = 1,
LIST_TYPE_NBUF = 2,
LIST_TYPE_MAX, LIST_TYPE_MAX,
}; };
@@ -103,6 +104,13 @@ static struct major_alloc_priv dma_priv = {
50 50
}; };
static struct major_alloc_priv nbuf_priv = {
/* List type set to NBUF */
LIST_TYPE_NBUF,
/* initial threshold to list APIs which allocates nbuf >= 50 times */
50
};
static qdf_list_t qdf_mem_domains[QDF_DEBUG_DOMAIN_COUNT]; static qdf_list_t qdf_mem_domains[QDF_DEBUG_DOMAIN_COUNT];
static qdf_spinlock_t qdf_mem_list_lock; static qdf_spinlock_t qdf_mem_list_lock;
@@ -699,6 +707,181 @@ static ssize_t qdf_major_alloc_set_threshold(struct file *file,
return buf_size; return buf_size;
} }
/**
* qdf_print_major_nbuf_allocs() - output agnostic nbuf print logic
* @threshold: the threshold value set by uset to list top allocations
* @print: the print adapter function
* @print_priv: the private data to be consumed by @print
* @mem_print: pointer to function which prints the memory allocation data
*
* Return: None
*/
static void
qdf_print_major_nbuf_allocs(uint32_t threshold,
qdf_abstract_print print,
void *print_priv,
void (*mem_print)(struct __qdf_mem_info *,
qdf_abstract_print,
void *, uint32_t))
{
uint32_t nbuf_iter;
unsigned long irq_flag = 0;
QDF_NBUF_TRACK *p_node;
QDF_NBUF_TRACK *p_prev;
struct __qdf_mem_info table[QDF_MEM_STAT_TABLE_SIZE];
struct qdf_mem_header meta;
bool is_full;
qdf_mem_zero(table, sizeof(table));
qdf_mem_debug_print_header(print, print_priv, threshold);
if (is_initial_mem_debug_disabled)
return;
qdf_rl_info("major nbuf print with threshold %u", threshold);
for (nbuf_iter = 0; nbuf_iter < QDF_NET_BUF_TRACK_MAX_SIZE;
nbuf_iter++) {
qdf_nbuf_acquire_track_lock(nbuf_iter, irq_flag);
p_node = qdf_nbuf_get_track_tbl(nbuf_iter);
while (p_node) {
meta.line = p_node->line_num;
meta.size = p_node->size;
meta.caller = NULL;
meta.time = p_node->time;
qdf_str_lcopy(meta.func, p_node->func_name,
QDF_MEM_FUNC_NAME_SIZE);
is_full = qdf_mem_meta_table_insert(table, &meta);
if (is_full) {
(*mem_print)(table, print,
print_priv, threshold);
qdf_mem_zero(table, sizeof(table));
}
p_prev = p_node;
p_node = p_node->p_next;
}
qdf_nbuf_release_track_lock(nbuf_iter, irq_flag);
}
(*mem_print)(table, print, print_priv, threshold);
qdf_rl_info("major nbuf print end");
}
/**
* qdf_major_nbuf_alloc_show() - print sequential callback
* @seq: seq_file handle
* @v: current iterator
*
* Return: 0 - success
*/
static int qdf_major_nbuf_alloc_show(struct seq_file *seq, void *v)
{
struct major_alloc_priv *priv = (struct major_alloc_priv *)seq->private;
if (!priv) {
qdf_err("priv is null");
return -EINVAL;
}
qdf_print_major_nbuf_allocs(priv->threshold,
seq_printf_printer,
seq,
qdf_print_major_alloc);
return 0;
}
/**
* qdf_nbuf_seq_start() - sequential callback to start
* @seq: seq_file handle
* @pos: The start position of the sequence
*
* Return: iterator pointer, or NULL if iteration is complete
*/
static void *qdf_nbuf_seq_start(struct seq_file *seq, loff_t *pos)
{
enum qdf_debug_domain domain = *pos;
if (domain > QDF_DEBUG_NBUF_DOMAIN)
return NULL;
return pos;
}
/**
* qdf_nbuf_seq_next() - next sequential callback
* @seq: seq_file handle
* @v: the current iterator
* @pos: the current position
*
* Get the next node and release previous node.
*
* Return: iterator pointer, or NULL if iteration is complete
*/
static void *qdf_nbuf_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
++*pos;
return qdf_nbuf_seq_start(seq, pos);
}
/**
* qdf_nbuf_seq_stop() - stop sequential callback
* @seq: seq_file handle
* @v: current iterator
*
* Return: None
*/
static void qdf_nbuf_seq_stop(struct seq_file *seq, void *v) { }
/* sequential file operation table created to track major skb allocs */
static const struct seq_operations qdf_major_nbuf_allocs_seq_ops = {
.start = qdf_nbuf_seq_start,
.next = qdf_nbuf_seq_next,
.stop = qdf_nbuf_seq_stop,
.show = qdf_major_nbuf_alloc_show,
};
static int qdf_major_nbuf_allocs_open(struct inode *inode, struct file *file)
{
void *private = inode->i_private;
struct seq_file *seq;
int rc;
rc = seq_open(file, &qdf_major_nbuf_allocs_seq_ops);
if (rc == 0) {
seq = file->private_data;
seq->private = private;
}
return rc;
}
static ssize_t qdf_major_nbuf_alloc_set_threshold(struct file *file,
const char __user *user_buf,
size_t count,
loff_t *pos)
{
char buf[32];
ssize_t buf_size;
uint32_t threshold;
struct seq_file *seq = file->private_data;
struct major_alloc_priv *priv = (struct major_alloc_priv *)seq->private;
buf_size = min(count, (sizeof(buf) - 1));
if (buf_size <= 0)
return 0;
if (copy_from_user(buf, user_buf, buf_size))
return -EFAULT;
buf[buf_size] = '\0';
if (!kstrtou32(buf, 10, &threshold))
priv->threshold = threshold;
return buf_size;
}
/* file operation table for listing major allocs */ /* file operation table for listing major allocs */
static const struct file_operations fops_qdf_major_allocs = { static const struct file_operations fops_qdf_major_allocs = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
@@ -718,6 +901,16 @@ static const struct file_operations fops_qdf_mem_debugfs = {
.release = seq_release, .release = seq_release,
}; };
/* file operation table for listing major allocs */
static const struct file_operations fops_qdf_nbuf_major_allocs = {
.owner = THIS_MODULE,
.open = qdf_major_nbuf_allocs_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
.write = qdf_major_nbuf_alloc_set_threshold,
};
static QDF_STATUS qdf_mem_debug_debugfs_init(void) static QDF_STATUS qdf_mem_debug_debugfs_init(void)
{ {
if (is_initial_mem_debug_disabled) if (is_initial_mem_debug_disabled)
@@ -744,6 +937,12 @@ static QDF_STATUS qdf_mem_debug_debugfs_init(void)
&dma_priv, &dma_priv,
&fops_qdf_major_allocs); &fops_qdf_major_allocs);
debugfs_create_file("major_nbuf_allocs",
0600,
qdf_mem_debugfs_root,
&nbuf_priv,
&fops_qdf_nbuf_major_allocs);
return QDF_STATUS_SUCCESS; return QDF_STATUS_SUCCESS;
} }

View File

@@ -2109,37 +2109,8 @@ bool __qdf_nbuf_is_bcast_pkt(qdf_nbuf_t nbuf)
qdf_export_symbol(__qdf_nbuf_is_bcast_pkt); qdf_export_symbol(__qdf_nbuf_is_bcast_pkt);
#ifdef NBUF_MEMORY_DEBUG #ifdef NBUF_MEMORY_DEBUG
#define QDF_NET_BUF_TRACK_MAX_SIZE (1024)
/**
* struct qdf_nbuf_track_t - Network buffer track structure
*
* @p_next: Pointer to next
* @net_buf: Pointer to network buffer
* @func_name: Function name
* @line_num: Line number
* @size: Size
* @map_func_name: nbuf mapping function name
* @map_line_num: mapping function line number
* @unmap_func_name: nbuf unmapping function name
* @unmap_line_num: mapping function line number
* @is_nbuf_mapped: indicate mapped/unmapped nbuf
*/
struct qdf_nbuf_track_t {
struct qdf_nbuf_track_t *p_next;
qdf_nbuf_t net_buf;
char func_name[QDF_MEM_FUNC_NAME_SIZE];
uint32_t line_num;
size_t size;
char map_func_name[QDF_MEM_FUNC_NAME_SIZE];
uint32_t map_line_num;
char unmap_func_name[QDF_MEM_FUNC_NAME_SIZE];
uint32_t unmap_line_num;
bool is_nbuf_mapped;
};
static spinlock_t g_qdf_net_buf_track_lock[QDF_NET_BUF_TRACK_MAX_SIZE]; static spinlock_t g_qdf_net_buf_track_lock[QDF_NET_BUF_TRACK_MAX_SIZE];
typedef struct qdf_nbuf_track_t QDF_NBUF_TRACK;
static QDF_NBUF_TRACK *gp_qdf_net_buf_track_tbl[QDF_NET_BUF_TRACK_MAX_SIZE]; static QDF_NBUF_TRACK *gp_qdf_net_buf_track_tbl[QDF_NET_BUF_TRACK_MAX_SIZE];
static struct kmem_cache *nbuf_tracking_cache; static struct kmem_cache *nbuf_tracking_cache;
@@ -2551,6 +2522,7 @@ void qdf_net_buf_debug_add_node(qdf_nbuf_t net_buf, size_t size,
p_node->map_func_name[0] = '\0'; p_node->map_func_name[0] = '\0';
p_node->unmap_func_name[0] = '\0'; p_node->unmap_func_name[0] = '\0';
p_node->size = size; p_node->size = size;
p_node->time = qdf_get_log_timestamp();
qdf_mem_skb_inc(size); qdf_mem_skb_inc(size);
p_node->p_next = gp_qdf_net_buf_track_tbl[i]; p_node->p_next = gp_qdf_net_buf_track_tbl[i];
gp_qdf_net_buf_track_tbl[i] = p_node; gp_qdf_net_buf_track_tbl[i] = p_node;
@@ -4826,3 +4798,24 @@ void qdf_net_buf_debug_release_frag(qdf_nbuf_t buf, const char *func,
qdf_export_symbol(qdf_net_buf_debug_release_frag); qdf_export_symbol(qdf_net_buf_debug_release_frag);
#endif /* NBUF_FRAG_MEMORY_DEBUG */ #endif /* NBUF_FRAG_MEMORY_DEBUG */
#ifdef MEMORY_DEBUG
void qdf_nbuf_acquire_track_lock(uint32_t index,
unsigned long irq_flag)
{
spin_lock_irqsave(&g_qdf_net_buf_track_lock[index],
irq_flag);
}
void qdf_nbuf_release_track_lock(uint32_t index,
unsigned long irq_flag)
{
spin_unlock_irqrestore(&g_qdf_net_buf_track_lock[index],
irq_flag);
}
QDF_NBUF_TRACK *qdf_nbuf_get_track_tbl(uint32_t index)
{
return gp_qdf_net_buf_track_tbl[index];
}
#endif /* MEMORY_DEBUG */