Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ns_monitor.c Source File

ns_monitor.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2019, Arm Limited and affiliates.
00003  * SPDX-License-Identifier: Apache-2.0
00004  *
00005  * Licensed under the Apache License, Version 2.0 (the "License");
00006  * you may not use this file except in compliance with the License.
00007  * You may obtain a copy of the License at
00008  *
00009  *     http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 
00018 /**
00019  * \file ns_monitor.c
00020  * \brief Utility functions for nanostack maintenance
00021  *
00022  * This module tracks stack current heap usage and triggers GC if heap usage is too high.
00023  * GC is triggered by:
00024  *  1. Heap usage is above HEAP_USAGE_HIGH
00025  *  2. Heap usage is above HEAP_USAGE_CRITICAL
00026  *  3. If nsdynmemLIB memory allocation has failed since last check
00027  */
00028 
00029 #include "nsconfig.h"
00030 #include "ns_types.h"
00031 #define HAVE_DEBUG
00032 #include "ns_trace.h"
00033 #include "nsdynmemLIB.h"
00034 #include "ipv6_stack/ipv6_routing_table.h"
00035 #include "NWK_INTERFACE/Include/protocol.h"
00036 #include "6LoWPAN/ws/ws_pae_controller.h"
00037 #include "NWK_INTERFACE/Include/protocol.h"
00038 
00039 #define TRACE_GROUP "mntr"
00040 
00041 typedef enum {
00042     NS_MONITOR_STATE_HEAP_GC_IDLE = 0,
00043     NS_MONITOR_STATE_HEAP_GC_HIGH,
00044     NS_MONITOR_STATE_GC_CRITICAL
00045 } ns_monitor_state_e;
00046 
00047 #define DEFAULT_HEAP_PERCENTAGE_THRESHOLD_HIGH      95
00048 #define DEFAULT_HEAP_PERCENTAGE_THRESHOLD_CRITICAL  99
00049 
00050 #define SET_WATERMARK(SECTOR_SIZE, THRESHOLD)   (SECTOR_SIZE * THRESHOLD / 100)
00051 
00052 #define NS_MAINTENANCE_TIMER_INTERVAL   10  // Maintenance interval
00053 
00054 typedef struct ns_monitor__s {
00055     ns_mem_heap_size_t heap_high_watermark;
00056     ns_mem_heap_size_t heap_critical_watermark;
00057     uint32_t prev_heap_alloc_fail_cnt;
00058     ns_monitor_state_e ns_monitor_heap_gc_state;
00059     const mem_stat_t *mem_stats;
00060     uint16_t ns_maintenance_timer;
00061 } ns_monitor_t;
00062 
00063 static ns_monitor_t *ns_monitor_ptr = NULL;
00064 
00065 typedef void (ns_maintenance_gc_cb)(bool full_gc);
00066 
00067 /*
00068  * Garbage collection functions.
00069  * Add more GC performing functions to the table
00070  *
00071  */
00072 static ns_maintenance_gc_cb *ns_maintenance_gc_functions[] = {
00073     ipv6_destination_cache_forced_gc,
00074     ws_pae_controller_forced_gc
00075 };
00076 
00077 static void ns_monitor_heap_gc(bool full_gc)
00078 {
00079     (void) full_gc;
00080 
00081     for (unsigned int i = 0; i < sizeof(ns_maintenance_gc_functions) / sizeof(ns_maintenance_gc_functions[0]); i++) {
00082         if (ns_maintenance_gc_functions[i]) {
00083             (ns_maintenance_gc_functions[i])(full_gc);
00084         }
00085     }
00086 }
00087 
00088 static void ns_monitor_periodic_heap_health_check(void)
00089 {
00090     if (ns_monitor_ptr->mem_stats->heap_sector_allocated_bytes > ns_monitor_ptr->heap_critical_watermark) {
00091         // Heap usage above CRITICAL
00092         if (ns_monitor_ptr->ns_monitor_heap_gc_state != NS_MONITOR_STATE_GC_CRITICAL) {
00093             ns_mem_heap_size_t prev_heap_sector_allocated_bytes = ns_monitor_ptr->mem_stats->heap_sector_allocated_bytes;
00094             tr_debug("heap %lu/%lu", (unsigned long)ns_monitor_ptr->mem_stats->heap_sector_allocated_bytes, (unsigned long)ns_monitor_ptr->mem_stats->heap_sector_size);
00095             ns_monitor_heap_gc(true);
00096             ns_monitor_ptr->ns_monitor_heap_gc_state = NS_MONITOR_STATE_GC_CRITICAL;
00097             tr_info("Stack GC critical: freed %lu bytes", (unsigned long)(prev_heap_sector_allocated_bytes - ns_monitor_ptr->mem_stats->heap_sector_allocated_bytes));
00098         }
00099     } else if (ns_monitor_ptr->mem_stats->heap_sector_allocated_bytes > ns_monitor_ptr->heap_high_watermark) {
00100         // Heap usage above HIGH
00101         if (ns_monitor_ptr->ns_monitor_heap_gc_state == NS_MONITOR_STATE_HEAP_GC_IDLE) {
00102             ns_mem_heap_size_t prev_heap_sector_allocated_bytes = ns_monitor_ptr->mem_stats->heap_sector_allocated_bytes;
00103             tr_debug("heap %lu/%lu", (unsigned long)ns_monitor_ptr->mem_stats->heap_sector_allocated_bytes, (unsigned long)ns_monitor_ptr->mem_stats->heap_sector_size);
00104             ns_monitor_heap_gc(false);
00105             ns_monitor_ptr->ns_monitor_heap_gc_state = NS_MONITOR_STATE_HEAP_GC_HIGH;
00106             tr_info("Stack GC high: freed %lu bytes", (unsigned long)(prev_heap_sector_allocated_bytes - ns_monitor_ptr->mem_stats->heap_sector_allocated_bytes));
00107         }
00108     } else if (ns_monitor_ptr->mem_stats->heap_sector_allocated_bytes <= ns_monitor_ptr->heap_high_watermark) {
00109         // Heap usage in normal range
00110         ns_monitor_ptr->ns_monitor_heap_gc_state = NS_MONITOR_STATE_HEAP_GC_IDLE;
00111     }
00112 }
00113 
00114 void ns_monitor_timer(uint16_t seconds)
00115 {
00116     if (ns_monitor_ptr) {
00117         ns_monitor_ptr->ns_maintenance_timer += seconds;
00118 
00119         if (ns_monitor_ptr->mem_stats->heap_alloc_fail_cnt > ns_monitor_ptr->prev_heap_alloc_fail_cnt) {
00120             // Heap allocation failure occurred since last check
00121             ns_monitor_ptr->prev_heap_alloc_fail_cnt = ns_monitor_ptr->mem_stats->heap_alloc_fail_cnt;
00122             if (ns_monitor_ptr->ns_monitor_heap_gc_state != NS_MONITOR_STATE_GC_CRITICAL) {
00123                 ns_monitor_ptr->ns_monitor_heap_gc_state = NS_MONITOR_STATE_GC_CRITICAL;
00124                 ns_monitor_heap_gc(true);
00125                 ns_monitor_ptr->ns_maintenance_timer = 0;
00126             }
00127         }
00128 
00129         if (ns_monitor_ptr->ns_maintenance_timer >= NS_MAINTENANCE_TIMER_INTERVAL) {
00130             ns_monitor_ptr->ns_maintenance_timer -= NS_MAINTENANCE_TIMER_INTERVAL;
00131             ns_monitor_periodic_heap_health_check();
00132         }
00133     }
00134 }
00135 
00136 int ns_monitor_init(void)
00137 {
00138     if (ns_monitor_ptr || !ns_dyn_mem_get_mem_stat()) {
00139         // already initialized or memory statistics not available
00140         return -2;
00141     }
00142 
00143     ns_monitor_ptr = ns_dyn_mem_alloc(sizeof(ns_monitor_t));
00144 
00145     if (ns_monitor_ptr) {
00146         ns_monitor_ptr->mem_stats = ns_dyn_mem_get_mem_stat();
00147         ns_monitor_ptr->heap_high_watermark = SET_WATERMARK(
00148                                                   ns_monitor_ptr->mem_stats->heap_sector_size,
00149                                                   DEFAULT_HEAP_PERCENTAGE_THRESHOLD_HIGH
00150                                               );
00151         ns_monitor_ptr->heap_critical_watermark = SET_WATERMARK(
00152                                                       ns_monitor_ptr->mem_stats->heap_sector_size,
00153                                                       DEFAULT_HEAP_PERCENTAGE_THRESHOLD_CRITICAL
00154                                                   );
00155         ns_monitor_ptr->ns_monitor_heap_gc_state = NS_MONITOR_STATE_HEAP_GC_IDLE;
00156         ns_monitor_ptr->ns_maintenance_timer = 0;
00157         ns_monitor_ptr->prev_heap_alloc_fail_cnt = 0;
00158         return 0;
00159     }
00160 
00161     return -1;
00162 }
00163 
00164 int ns_monitor_clear(void)
00165 {
00166     if (ns_monitor_ptr) {
00167         ns_dyn_mem_free(ns_monitor_ptr);
00168         ns_monitor_ptr = NULL;
00169         return 0;
00170     }
00171 
00172     return -1;
00173 }
00174 
00175 int ns_monitor_heap_gc_threshold_set(uint8_t percentage_high, uint8_t percentage_critical)
00176 {
00177     if (ns_monitor_ptr && (percentage_critical <= 100) && (percentage_high < percentage_critical)) {
00178         ns_monitor_ptr->heap_high_watermark = SET_WATERMARK(
00179                                                   ns_monitor_ptr->mem_stats->heap_sector_size,
00180                                                   percentage_high
00181                                               );
00182         ns_monitor_ptr->heap_critical_watermark = SET_WATERMARK(
00183                                                       ns_monitor_ptr->mem_stats->heap_sector_size,
00184                                                       percentage_critical
00185                                                   );
00186         tr_debug("Monitor set high:%lu, critical:%lu total:%lu", (unsigned long)ns_monitor_ptr->heap_high_watermark, (unsigned long)ns_monitor_ptr->heap_critical_watermark, (unsigned long)ns_monitor_ptr->mem_stats->heap_sector_size);
00187         return 0;
00188     }
00189 
00190     return -1;
00191 }