test_preemption.c 3.5 KB

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