一、目的
LwIP能够在嵌入式领域如此出类拔萃,其优异的性能和极少的资源占用令人称赞;除此之外,个人觉得其出色的代码设计和调试技巧也是不可忽略的。
本篇博文我们就来讲讲LwIP中内嵌的性能统计功能。
二、介绍
什么是性能统计?
LwIP中有各种数据包的处理,包括数据包的接收和发送以及各层协议处理;为了记录这些信息,LwIP中专门实现了性能统计模块
涉及的源文件
stats.h
stats.c
性能统计结构体
/** lwIP stats container */
struct stats_ {
#if LINK_STATS
/** Link level */
struct stats_proto link;
#endif
#if ETHARP_STATS
/** ARP */
struct stats_proto etharp;
#endif
#if IPFRAG_STATS
/** Fragmentation */
struct stats_proto ip_frag;
#endif
#if IP_STATS
/** IP */
struct stats_proto ip;
#endif
#if ICMP_STATS
/** ICMP */
struct stats_proto icmp;
#endif
#if IGMP_STATS
/** IGMP */
struct stats_igmp igmp;
#endif
#if UDP_STATS
/** UDP */
struct stats_proto udp;
#endif
#if TCP_STATS
/** TCP */
struct stats_proto tcp;
#endif
#if MEM_STATS
/** Heap */
struct stats_mem mem;
#endif
#if MEMP_STATS
/** Internal memory pools */
struct stats_mem *memp[MEMP_MAX];
#endif
#if SYS_STATS
/** System */
struct stats_sys sys;
#endif
#if IP6_STATS
/** IPv6 */
struct stats_proto ip6;
#endif
#if ICMP6_STATS
/** ICMP6 */
struct stats_proto icmp6;
#endif
#if IP6_FRAG_STATS
/** IPv6 fragmentation */
struct stats_proto ip6_frag;
#endif
#if MLD6_STATS
/** Multicast listener discovery */
struct stats_igmp mld6;
#endif
#if ND6_STATS
/** Neighbor discovery */
struct stats_proto nd6;
#endif
#if MIB2_STATS
/** SNMP MIB2 */
struct stats_mib2 mib2;
#endif
};
从上面的定义来看,在LwIP中可以统计内存使用情况,可以统计协议栈中各层的数据包吞吐量。
此处我们针对struct stats_mem和struct stats_proto这两个结构体的定义进行说明
stats_mem结构体
用于统计内存的使用情况,包括内存堆和各个内存池
/** Memory stats */
struct stats_mem {
#if defined(LWIP_DEBUG) || LWIP_STATS_DISPLAY
const char *name;
#endif /* defined(LWIP_DEBUG) || LWIP_STATS_DISPLAY */
STAT_COUNTER err;
mem_size_t avail;
mem_size_t used;
mem_size_t max;
STAT_COUNTER illegal;
};
各字段含义说明:
err:内存分配出错次数
avail:可使用的内存数量
used:已经使用的内存数量
max:运行过程中最大使用的内存量
illegal:内存操作非法的次数
stats_proto结构体
用于统计数据包的收发情况
/** Protocol related stats */
struct stats_proto {
STAT_COUNTER xmit; /* Transmitted packets. */
STAT_COUNTER recv; /* Received packets. */
STAT_COUNTER fw; /* Forwarded packets. */
STAT_COUNTER drop; /* Dropped packets. */
STAT_COUNTER chkerr; /* Checksum error. */
STAT_COUNTER lenerr; /* Invalid length error. */
STAT_COUNTER memerr; /* Out of memory error. */
STAT_COUNTER rterr; /* Routing error. */
STAT_COUNTER proterr; /* Protocol error. */
STAT_COUNTER opterr; /* Error in options. */
STAT_COUNTER err; /* Misc error. */
STAT_COUNTER cachehit;
};
各个字段含义:
xmit:发送的数据包量
recv:接收到的数据包量
fw:转发的数据包量
drop:丢弃的数据包量
chkerr:校验和出错的数据包数量
lenerr:非法长度的数据包量
memerr:由于内存分配失败的数据量
rterr:路由出错的次数
proterr:协议出错数
opterr:可选字段的错误数
err:其他错误的次数
cachehit:缓存命中次数
为了更好的处理各个字段值,LwIP中定义了一组宏定义
#define STATS_INC(x) ++lwip_stats.x
#define STATS_DEC(x) --lwip_stats.x
#define STATS_INC_USED(x, y, type) do { lwip_stats.x.used = (type)(lwip_stats.x.used + y); \
if (lwip_stats.x.max < lwip_stats.x.used) { \
lwip_stats.x.max = lwip_stats.x.used; \
} \
} while(0)
#define STATS_GET(x) lwip_stats.x
#else /* LWIP_STATS */
#define stats_init()
#define STATS_INC(x)
#define STATS_DEC(x)
#define STATS_INC_USED(x, y, type)
#endif /* LWIP_STATS */
#if TCP_STATS
#define TCP_STATS_INC(x) STATS_INC(x)
#define TCP_STATS_DISPLAY() stats_display_proto(&lwip_stats.tcp, "TCP")
#else
#define TCP_STATS_INC(x)
#define TCP_STATS_DISPLAY()
#endif
#if MEMP_STATS
#define MEMP_STATS_DEC(x, i) STATS_DEC(memp[i]->x)
#define MEMP_STATS_DISPLAY(i) stats_display_memp(lwip_stats.memp[i], i)
#define MEMP_STATS_GET(x, i) STATS_GET(memp[i]->x)
#else
#define MEMP_STATS_DEC(x, i)
#define MEMP_STATS_DISPLAY(i)
#define MEMP_STATS_GET(x, i) 0
#endif
例如在memp.c的实现中针对内存池的统计就有如下的代码
static void
do_memp_free_pool(const struct memp_desc *desc, void *mem)
{
struct memp *memp;
SYS_ARCH_DECL_PROTECT(old_level);
LWIP_ASSERT("memp_free: mem properly aligned",
((mem_ptr_t)mem % MEM_ALIGNMENT) == 0);
/* cast through void* to get rid of alignment warnings */
memp = (struct memp *)(void *)((u8_t *)mem - MEMP_SIZE);
SYS_ARCH_PROTECT(old_level);
#if MEMP_OVERFLOW_CHECK == 1
memp_overflow_check_element(memp, desc);
#endif /* MEMP_OVERFLOW_CHECK */
#if MEMP_STATS
desc->stats->used--;
#endif
#if MEMP_MEM_MALLOC
LWIP_UNUSED_ARG(desc);
SYS_ARCH_UNPROTECT(old_level);
mem_free(memp);
#else /* MEMP_MEM_MALLOC */
memp->next = *desc->tab;
*desc->tab = memp;
#if MEMP_SANITY_CHECK
LWIP_ASSERT("memp sanity", memp_sanity(desc));
#endif /* MEMP_SANITY_CHECK */
SYS_ARCH_UNPROTECT(old_level);
#endif /* !MEMP_MEM_MALLOC */
}
其中代码片段针对内存池已经使用的数量进行了操作
#if MEMP_STATS
desc->stats->used--;
#endif
以上就是LwIP中的性能统计的相关内容。