summaryrefslogtreecommitdiff
path: root/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/tools/tcp_mem_stats.c
diff options
context:
space:
mode:
Diffstat (limited to 'FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/tools/tcp_mem_stats.c')
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/tools/tcp_mem_stats.c425
1 files changed, 425 insertions, 0 deletions
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/tools/tcp_mem_stats.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/tools/tcp_mem_stats.c
new file mode 100644
index 000000000..d4929b3fa
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/tools/tcp_mem_stats.c
@@ -0,0 +1,425 @@
+/*
+ * FreeRTOS+TCP V2.2.1
+ * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * http://aws.amazon.com/freertos
+ * http://www.FreeRTOS.org
+ */
+/*
+ * tcp_mem_stats.c
+ * Used to create a CSV file with detaild information about the memory usage of FreeRTOS+TCP.
+ * See tools/tcp_mem_stats.md for further description.
+ */
+
+/* Standard includes. */
+#include <stdio.h>
+#include <stdint.h>
+#include <stdarg.h>
+
+/* FreeRTOS includes. */
+#include <FreeRTOS.h>
+#include "task.h"
+
+/* FreeRTOS+TCP includes. */
+#include "FreeRTOS_IP.h"
+#include "FreeRTOS_Sockets.h"
+#include "FreeRTOS_Stream_Buffer.h"
+#include "FreeRTOS_ARP.h"
+#include "FreeRTOS_IP_Private.h"
+
+#include "tcp_mem_stats.h"
+
+#ifndef ipconfigTCP_MEM_STATS_MAX_ALLOCATION
+ #define ipconfigTCP_MEM_STATS_MAX_ALLOCATION 128u
+ #pragma warning "ipconfigTCP_MEM_STATS_MAX_ALLOCATION undefined?"
+#endif
+
+#if( ipconfigUSE_TCP_MEM_STATS != 0 )
+
+/* When a streambuffer is allocated, 4 extra bytes will be reserved. */
+
+#define STREAM_BUFFER_ROUNDUP_BYTES 4
+
+#define STATS_PRINTF( MSG ) \
+ xCurrentLine++; \
+ configPRINTF( MSG )
+
+#define ETH_MAX_PACKET_SIZE ( ( ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER + ipBUFFER_PADDING + 31 ) & ~0x1FuL )
+/*-----------------------------------------------------------*/
+
+/* Objects are allocated and deleted. This structure stores the type
+and the size of the object. */
+typedef struct xTCP_ALLOCATION
+{
+ TCP_MEMORY_t xMemType;
+ void *pxObject;
+ UBaseType_t uxNumber;
+ size_t uxSize;
+} TCP_ALLOCATION_t;
+/*-----------------------------------------------------------*/
+
+
+static void vWriteHeader( void );
+
+static size_t uxCurrentMallocSize;
+static TCP_ALLOCATION_t xAllocations[ ipconfigTCP_MEM_STATS_MAX_ALLOCATION ];
+static size_t uxAllocationCount;
+static BaseType_t xFirstItem = pdTRUE;
+UBaseType_t uxNextObjectNumber;
+static BaseType_t xCurrentLine = 0;
+static BaseType_t xFirstDumpLine = 0;
+static BaseType_t xLastHeaderLineNr = 0;
+static BaseType_t xLoggingStopped = 0;
+/*-----------------------------------------------------------*/
+
+static void vAddAllocation( TCP_MEMORY_t xMemType, void *pxObject, size_t uxSize )
+{
+size_t uxIndex;
+
+ vTaskSuspendAll();
+ {
+ for( uxIndex = 0; uxIndex < uxAllocationCount; uxIndex++ )
+ {
+ if( xAllocations[ uxIndex ].pxObject == pxObject )
+ {
+ /* Already added, strange. */
+ FreeRTOS_printf( ( "vAddAllocation: Pointer %p already added\n", pxObject ) );
+ return;
+ }
+ }
+ if( uxAllocationCount >= ipconfigTCP_MEM_STATS_MAX_ALLOCATION )
+ {
+ /* The table is full. */
+ return;
+ }
+ xAllocations[ uxIndex ].pxObject = pxObject;
+ xAllocations[ uxIndex ].xMemType = xMemType;
+ xAllocations[ uxIndex ].uxSize = uxSize;
+ xAllocations[ uxIndex ].uxNumber = uxNextObjectNumber++;
+ uxAllocationCount++;
+ }
+ xTaskResumeAll();
+}
+/*-----------------------------------------------------------*/
+
+static TCP_ALLOCATION_t *pxRemoveAllocation( void *pxObject )
+{
+size_t uxSource = 0, uxTarget = 0;
+static TCP_ALLOCATION_t xAllocation = { 0 };
+BaseType_t xFound = pdFALSE;
+TCP_ALLOCATION_t *pxReturn;
+
+ vTaskSuspendAll();
+ {
+ for( ; uxSource < uxAllocationCount; uxSource++ )
+ {
+ if( xAllocations[ uxSource ].pxObject == pxObject )
+ {
+ /* This is entry will be removed. */
+ ( void ) memcpy( &( xAllocation ), &( xAllocations[ uxSource ] ), sizeof xAllocation );
+ xFound = pdTRUE;
+ }
+ else
+ {
+ xAllocations[ uxTarget ] = xAllocations[ uxSource ];
+ uxTarget++;
+ }
+ }
+ if( xFound != pdFALSE )
+ {
+ uxAllocationCount--;
+ pxReturn = &( xAllocation );
+ }
+ else
+ {
+ pxReturn = NULL;
+ }
+ }
+ xTaskResumeAll();
+ return pxReturn;
+}
+/*-----------------------------------------------------------*/
+
+static const char *pcTypeName( TCP_MEMORY_t xMemType )
+{
+ switch( xMemType )
+ {
+ case tcpSOCKET_TCP: return "TCP-Socket";
+ case tcpSOCKET_UDP: return "UDP-Socket";
+ case tcpSOCKET_SET: return "SocketSet";
+ case tcpSEMAPHORE: return "Semaphore";
+ case tcpRX_STREAM_BUFFER: return "RX-Buffer";
+ case tcpTX_STREAM_BUFFER: return "TX-Buffer";
+ case tcpNETWORK_BUFFER: return "networkBuffer";
+ }
+ return "Unknown object";
+}
+/*-----------------------------------------------------------*/
+
+static void vWriteHeader()
+{
+size_t uxPacketSize;
+size_t uxTXSize;
+size_t uxStaticSize = 0;
+BaseType_t xFirstLineNr = 0;
+
+char pucComment[ 64 ] = "";
+StreamBuffer_t *pxBuffer = NULL;
+size_t uxTara = sizeof( *pxBuffer ) - sizeof( pxBuffer->ucArray );
+
+ /* The approximate size of a buffer for a Network Packet. */
+ STATS_PRINTF( ( "TCPMemStat,Some important ipconfig items:\n" ) );
+ STATS_PRINTF( ( "TCPMemStat,ipconfig item,Value,Comment\n" ) );
+ STATS_PRINTF( ( "TCPMemStat,NETWORK_MTU,%u\n", ipconfigNETWORK_MTU ) );
+ STATS_PRINTF( ( "TCPMemStat,TCP_MSS,%u\n", ipconfigTCP_MSS ) );
+ STATS_PRINTF( ( "TCPMemStat,USE_TCP,%u\n", ipconfigUSE_TCP ) );
+ STATS_PRINTF( ( "TCPMemStat,USE_TCP_WIN,%u\n", ipconfigUSE_TCP_WIN ) );
+
+ uxTXSize = ( size_t ) FreeRTOS_round_up( ipconfigTCP_TX_BUFFER_LENGTH, ipconfigTCP_MSS );
+
+ STATS_PRINTF( ( "TCPMemStat,TCP_RX_BUFFER_LENGTH,%u,Plus %u bytes\n", ipconfigTCP_RX_BUFFER_LENGTH, uxTara + STREAM_BUFFER_ROUNDUP_BYTES ) );
+ if( uxTXSize > ipconfigTCP_TX_BUFFER_LENGTH )
+ {
+ snprintf( pucComment, sizeof pucComment, ",Rounded up to %u x MSS (plus %u bytes)", uxTXSize / ipconfigTCP_MSS, uxTara + STREAM_BUFFER_ROUNDUP_BYTES );
+ }
+ STATS_PRINTF( ( "TCPMemStat,TCP_TX_BUFFER_LENGTH,%u%s\n", ipconfigTCP_TX_BUFFER_LENGTH, pucComment ) );
+ STATS_PRINTF( ( "TCPMemStat,USE_DHCP,%u\n", ipconfigUSE_DHCP ) );
+
+ /*
+ * Start of fixed RAM allocations.
+ */
+
+ STATS_PRINTF( ( "TCPMemStat,\n" ) );
+ STATS_PRINTF( ( "TCPMemStat,RAM that is always allocated either statically or on the heap:\n" ) );
+ STATS_PRINTF( ( "TCPMemStat,ipconfig item,Value,PerUnit,Total\n" ) );
+ xFirstLineNr = xCurrentLine;
+ if( xBufferAllocFixedSize != 0 )
+ {
+ size_t uxBytes;
+
+ /* Using BufferAllocation_1.c */
+ uxPacketSize = ( ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER + ipBUFFER_PADDING + 31 ) & ~0x1FuL;
+ uxBytes = ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS * ( uxPacketSize + sizeof( NetworkBufferDescriptor_t ) );
+
+ STATS_PRINTF( ( "TCPMemStat,NUM_NETWORK_BUFFER_DESCRIPTORS,%u,%u,=B%d*C%d,Descriptors + buffers\n",
+ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS,
+ uxPacketSize + sizeof( NetworkBufferDescriptor_t ),
+ xCurrentLine,
+ xCurrentLine ) );
+ uxStaticSize += uxBytes;
+ }
+ else
+ {
+ size_t uxBytes;
+
+ /* Using BufferAllocation_2.c */
+ uxBytes = ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS * sizeof( NetworkBufferDescriptor_t );
+ STATS_PRINTF( ( "TCPMemStat,NUM_NETWORK_BUFFER_DESCRIPTORS,%u,%u,=B%d*C%d,Descriptors only\n",
+ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS,
+ sizeof( NetworkBufferDescriptor_t ),
+ xCurrentLine,
+ xCurrentLine ) );
+ uxStaticSize += uxBytes;
+ }
+ {
+ #if( ipconfigUSE_TCP_WIN != 0 )
+ {
+ STATS_PRINTF( ( "TCPMemStat,TCP_WIN_SEG_COUNT,%u,%u,=B%d*C%d\n",
+ ipconfigTCP_WIN_SEG_COUNT, sizeof( TCPSegment_t ), xCurrentLine, xCurrentLine ) );
+ }
+ #else
+ {
+ STATS_PRINTF( ( "TCPMemStat,TCP_WIN_SEG_COUNT,%u,%u\n", 0, 0 ) );
+ }
+ #endif
+ }
+ {
+ size_t uxBytes;
+ size_t uxEntrySize;
+
+ uxBytes = ipconfigEVENT_QUEUE_LENGTH * sizeof( IPStackEvent_t );
+ STATS_PRINTF( ( "TCPMemStat,EVENT_QUEUE_LENGTH,%u,%u,=B%d*C%d\n",
+ ipconfigEVENT_QUEUE_LENGTH,
+ sizeof( IPStackEvent_t ),
+ xCurrentLine,
+ xCurrentLine ) );
+ uxStaticSize += uxBytes;
+
+ uxBytes = ipconfigIP_TASK_STACK_SIZE_WORDS * sizeof( void *);
+ STATS_PRINTF( ( "TCPMemStat,IP_TASK_STACK_SIZE_WORDS,%u,%u,=B%d*C%d\n",
+ ipconfigIP_TASK_STACK_SIZE_WORDS,
+ sizeof( void *),
+ xCurrentLine,
+ xCurrentLine ) );
+ uxStaticSize += uxBytes;
+
+ uxBytes = ipconfigARP_CACHE_ENTRIES * sizeof( ARPCacheRow_t );
+ STATS_PRINTF( ( "TCPMemStat,ARP_CACHE_ENTRIES,%u,%u,=B%d*C%d\n",
+ ipconfigARP_CACHE_ENTRIES,
+ sizeof( ARPCacheRow_t ),
+ xCurrentLine,
+ xCurrentLine ) );
+ uxStaticSize += uxBytes;
+
+ #if( ipconfigUSE_DNS_CACHE == 1 )
+ {
+ uxEntrySize = 3u * sizeof( uint32_t ) + ( ( ipconfigDNS_CACHE_NAME_LENGTH + 3 ) & ~0x3u );
+ STATS_PRINTF( ( "TCPMemStat,DNS_CACHE_ENTRIES,%u,%u,=B%d*C%d\n",
+ ipconfigDNS_CACHE_ENTRIES,
+ uxEntrySize,
+ xCurrentLine,
+ xCurrentLine ) );
+ }
+ #endif
+ }
+ /*
+ * End of fixed RAM allocations.
+ */
+ if( xBufferAllocFixedSize != 0 )
+ {
+ pucComment[0] = 0;
+ }
+ else
+ {
+ size_t uxBytes;
+
+ /* BufferAllocation_2.c uses HEAP to store network packets. */
+ uxPacketSize = ( ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER + ipBUFFER_PADDING + 3 ) & ~0x03uL;
+ uxBytes = ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS * uxPacketSize;
+ STATS_PRINTF( ( "TCPMemStat,Network buffers in HEAP,%u,%u,=B%d*C%d\n",
+ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS,
+ uxPacketSize,
+ xCurrentLine,
+ xCurrentLine ) );
+ uxStaticSize += uxBytes;
+ snprintf( pucComment, sizeof pucComment, "Actual size fluctuates because BufferAllocation_2.c is used" );
+ }
+ xLastHeaderLineNr = xCurrentLine;
+
+ STATS_PRINTF( ( "TCPMemStat,Total,,,=SUM(D%d:D%d),%s\n", xFirstLineNr + 1, xLastHeaderLineNr, pucComment ) );
+
+ STATS_PRINTF( ( "TCPMemStat,\n" ) );
+ STATS_PRINTF( ( "TCPMemStat,\n" ) );
+ STATS_PRINTF( ( "TCPMemStat,The following allocations are done on the heap while running:\n" ) );
+ STATS_PRINTF( ( "TCPMemStat,Create/Remove,Object,Size,Heap use,Pointer,Heap-min,Heap-Cur,comment\n" ) );
+}
+/*-----------------------------------------------------------*/
+
+void vTCPMemStatCreate( TCP_MEMORY_t xMemType, void *pxObject, size_t uxSize )
+{
+ if( xLoggingStopped == pdFALSE )
+ {
+ StreamBuffer_t *pxBuffer = NULL;
+ char pcExtra[ 81 ] = "";
+
+ if( xFirstItem != pdFALSE )
+ {
+ xFirstItem = pdFALSE;
+ vWriteHeader();
+ }
+ if( ( xMemType == tcpRX_STREAM_BUFFER ) || ( xMemType == tcpTX_STREAM_BUFFER ) )
+ {
+ size_t uxTara = sizeof( *pxBuffer ) - sizeof( pxBuffer->ucArray );
+ size_t uxNett = uxSize - uxTara;
+
+ snprintf( pcExtra, sizeof pcExtra, ",%u nett", uxNett );
+ }
+
+ if( xFirstDumpLine == 0 )
+ {
+ xFirstDumpLine = xCurrentLine + 1;
+ }
+
+ xCurrentLine++;
+ configPRINTF( ( "TCPMemStat,CREATE,%s,%lu,%lu,%u,%u,%u%s\n",
+ pcTypeName( xMemType ),
+ uxSize,
+ uxCurrentMallocSize + uxSize,
+ uxNextObjectNumber,
+ xPortGetMinimumEverFreeHeapSize(),
+ xPortGetFreeHeapSize(),
+ pcExtra ) );
+ uxCurrentMallocSize += uxSize;
+ vAddAllocation( xMemType, pxObject, uxSize );
+ }
+}
+/*-----------------------------------------------------------*/
+
+void vTCPMemStatDelete( void *pxObject )
+{
+ if( xLoggingStopped == pdFALSE )
+ {
+ TCP_ALLOCATION_t *pxFound = pxRemoveAllocation( pxObject );
+
+ if( xFirstDumpLine == 0 )
+ {
+ xFirstDumpLine = xCurrentLine + 1;
+ }
+ if( pxFound == NULL )
+ {
+ FreeRTOS_printf( ( "TCPMemStat: can not find pointer %p\n", pxObject ) );
+ }
+ else
+ {
+ xCurrentLine++;
+ configPRINTF( ( "TCPMemStat,REMOVE,%s,-%lu,%lu,%x,%u,%u\n",
+ pcTypeName( pxFound->xMemType ),
+ pxFound->uxSize,
+ uxCurrentMallocSize - pxFound->uxSize,
+ pxFound->uxNumber,
+ xPortGetMinimumEverFreeHeapSize(),
+ xPortGetFreeHeapSize() ) );
+ if( uxCurrentMallocSize < pxFound->uxSize )
+ {
+ uxCurrentMallocSize = 0uL;
+ }
+ else
+ {
+ uxCurrentMallocSize -= pxFound->uxSize;
+ }
+ }
+ }
+}
+/*-----------------------------------------------------------*/
+
+void vTCPMemStatClose()
+{
+ if( xLoggingStopped == pdFALSE )
+ {
+ // name;object;size;Heap;Ppointer;HeapMin;HeapDur;Comment
+ BaseType_t xLastLineNr = xCurrentLine;
+
+ xLoggingStopped = pdTRUE;
+
+ STATS_PRINTF( ( "TCPMemStat,Totals,,,=MAX(D%d:D%d),,=MIN(F%d:F%d),=MAX(G%d:G%d)\n",
+ xFirstDumpLine,
+ xLastLineNr,
+ xFirstDumpLine,
+ xLastLineNr,
+ xFirstDumpLine,
+ xLastLineNr ) );
+ STATS_PRINTF( ( "TCPMemStat,Maximum RAM usage:,,,=SUM(D%d;D%d)\n",
+ xLastHeaderLineNr + 1,
+ xLastLineNr + 1 ) );
+ }
+}
+/*-----------------------------------------------------------*/
+
+#endif /* ( ipconfigUSE_TCP_MEM_STATS != 0 ) */