Fork of the espurna firmware for `mhsw` switches
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

115 lines
2.7 KiB

  1. /*
  2. Show extended heap stats when EspClass::getHeapStats() is available
  3. */
  4. #pragma once
  5. #include <type_traits>
  6. struct heap_stats_t {
  7. uint32_t available;
  8. uint16_t usable;
  9. uint8_t frag_pct;
  10. };
  11. namespace EspClass_has_getHeapStats {
  12. struct _detector {
  13. template<typename T, typename = decltype(
  14. std::declval<T>().getHeapStats(0,0,0))>
  15. static std::true_type detect(int);
  16. template<typename>
  17. static std::false_type detect(...);
  18. };
  19. template <typename T>
  20. struct detector : public _detector {
  21. using result = decltype(
  22. std::declval<detector>().detect<T>(0));
  23. };
  24. template <typename T>
  25. struct typed_check : public detector<T>::result {
  26. };
  27. typed_check<EspClass> check{};
  28. };
  29. template <typename T>
  30. void _getHeapStats(std::true_type&, T& instance, heap_stats_t& stats) {
  31. instance.getHeapStats(&stats.available, &stats.usable, &stats.frag_pct);
  32. }
  33. template <typename T>
  34. void _getHeapStats(std::false_type&, T& instance, heap_stats_t& stats) {
  35. stats.available = instance.getFreeHeap();
  36. stats.usable = 0;
  37. stats.frag_pct = 0;
  38. }
  39. void getHeapStats(heap_stats_t& stats) {
  40. _getHeapStats(EspClass_has_getHeapStats::check, ESP, stats);
  41. }
  42. // WTF
  43. // Calling ESP.getFreeHeap() is making the system crash on a specific
  44. // AiLight bulb, but anywhere else it should work as expected
  45. static bool _heap_value_wtf = false;
  46. heap_stats_t getHeapStats() {
  47. heap_stats_t stats;
  48. if (_heap_value_wtf) {
  49. stats.available = 9999;
  50. stats.usable = 9999;
  51. stats.frag_pct = 0;
  52. return stats;
  53. }
  54. getHeapStats(stats);
  55. return stats;
  56. }
  57. void wtfHeap(bool value) {
  58. _heap_value_wtf = value;
  59. }
  60. unsigned int getFreeHeap() {
  61. return getHeapStats().available;
  62. }
  63. static unsigned int _initial_heap_value = 0;
  64. void setInitialFreeHeap() {
  65. _initial_heap_value = getFreeHeap();
  66. }
  67. unsigned int getInitialFreeHeap() {
  68. if (0 == _initial_heap_value) {
  69. setInitialFreeHeap();
  70. }
  71. return _initial_heap_value;
  72. }
  73. void infoMemory(const char* name, const heap_stats_t& stats) {
  74. infoMemory(name, getInitialFreeHeap(), stats.available);
  75. }
  76. void infoHeapStats(const char* name, const heap_stats_t& stats) {
  77. DEBUG_MSG_P(
  78. PSTR("[MAIN] %-6s: %5u bytes available | %5u bytes lost (%2u%%) | %5u bytes free (%2u%%)\n"),
  79. name,
  80. stats.available,
  81. (stats.available - stats.usable),
  82. stats.frag_pct,
  83. stats.usable,
  84. (100 - stats.frag_pct)
  85. );
  86. }
  87. void infoHeapStats(bool show_frag_stats = true) {
  88. const auto stats = getHeapStats();
  89. infoMemory("Heap", stats);
  90. if (show_frag_stats && EspClass_has_getHeapStats::check) {
  91. infoHeapStats("Heap", stats);
  92. }
  93. }