test_preemption.c 3.4 KB

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