test_preemption.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. /*
  2. * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. /*
  7. Unit tests for FreeRTOS preemption
  8. */
  9. #include <esp_types.h>
  10. #include <stdio.h>
  11. #include "freertos/FreeRTOS.h"
  12. #include "freertos/task.h"
  13. #include "freertos/semphr.h"
  14. #include "freertos/queue.h"
  15. #include "unity.h"
  16. #include "esp_cpu.h"
  17. #include "test_utils.h"
  18. #include "sdkconfig.h"
  19. static volatile bool trigger;
  20. static volatile bool flag;
  21. #ifndef CONFIG_FREERTOS_SMP
  22. #define MAX_YIELD_COUNT 10000
  23. #else
  24. //TODO: IDF-5081
  25. #define MAX_YIELD_COUNT 17000
  26. #endif // CONFIG_FREERTOS_SMP
  27. /* Task:
  28. - Waits for 'trigger' variable to be set
  29. - Reads the cycle count on this CPU
  30. - Pushes it into a queue supplied as a param
  31. - Busy-waits until the main task terminates it
  32. */
  33. static void task_send_to_queue(void *param)
  34. {
  35. QueueHandle_t queue = (QueueHandle_t) param;
  36. uint32_t ccount;
  37. while(!trigger) {}
  38. ccount = esp_cpu_get_cycle_count();
  39. flag = true;
  40. xQueueSendToBack(queue, &ccount, 0);
  41. /* This is to ensure that higher priority task
  42. won't wake anyhow, due to this task terminating.
  43. The task runs until terminated by the main task.
  44. */
  45. while(1) {}
  46. }
  47. TEST_CASE("Yield from lower priority task, same CPU", "[freertos]")
  48. {
  49. /* Do this 3 times, mostly for the benchmark value - the first
  50. run includes a cache miss so uses more cycles than it should. */
  51. for (int i = 0; i < 3; i++) {
  52. TaskHandle_t sender_task;
  53. QueueHandle_t queue = xQueueCreate(1, sizeof(uint32_t));
  54. flag = false;
  55. trigger = false;
  56. /* "yield" task sits on our CPU, lower priority to us */
  57. xTaskCreatePinnedToCore(task_send_to_queue, "YIELD", 2048, (void *)queue, UNITY_FREERTOS_PRIORITY - 1, &sender_task, UNITY_FREERTOS_CPU);
  58. vTaskDelay(1); /* make sure everything is set up */
  59. trigger = true;
  60. uint32_t yield_ccount, now_ccount, delta;
  61. TEST_ASSERT( xQueueReceive(queue, &yield_ccount, 100 / portTICK_PERIOD_MS) );
  62. now_ccount = esp_cpu_get_cycle_count();
  63. TEST_ASSERT( flag );
  64. delta = now_ccount - yield_ccount;
  65. printf("Yielding from lower priority task took %u cycles\n", delta);
  66. TEST_ASSERT(delta < MAX_YIELD_COUNT);
  67. vTaskDelete(sender_task);
  68. vQueueDelete(queue);
  69. }
  70. }
  71. #if (portNUM_PROCESSORS == 2) && !CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH
  72. TEST_CASE("Yield from lower priority task, other CPU", "[freertos]")
  73. {
  74. uint32_t trigger_ccount, yield_ccount, now_ccount, delta;
  75. /* Do this 3 times, mostly for the benchmark value - the first
  76. run includes a cache miss so uses more cycles than it should. */
  77. for (int i = 0; i < 3; i++) {
  78. TaskHandle_t sender_task;
  79. QueueHandle_t queue = xQueueCreate(1, sizeof(uint32_t));
  80. trigger = false;
  81. flag = false;
  82. /* "send_to_queue" task sits on the other CPU, lower priority to us */
  83. xTaskCreatePinnedToCore(task_send_to_queue, "YIELD", 2048, (void *)queue, UNITY_FREERTOS_PRIORITY - 1,
  84. &sender_task, !UNITY_FREERTOS_CPU);
  85. vTaskDelay(2); /* make sure everything is set up */
  86. trigger = true;
  87. trigger_ccount = esp_cpu_get_cycle_count();
  88. // yield_ccount is not useful in this test as it's the other core's CCOUNT
  89. // so we use trigger_ccount instead
  90. TEST_ASSERT( xQueueReceive(queue, &yield_ccount, 100 / portTICK_PERIOD_MS) );
  91. now_ccount = esp_cpu_get_cycle_count();
  92. TEST_ASSERT( flag );
  93. delta = now_ccount - trigger_ccount;
  94. printf("Yielding from task on other core took %u cycles\n", delta);
  95. TEST_ASSERT(delta < MAX_YIELD_COUNT);
  96. vQueueDelete(queue);
  97. vTaskDelete(sender_task);
  98. }
  99. }
  100. #endif