diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2023-10-25 16:27:11 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2023-11-28 14:30:47 +0100 |
commit | cbef884bc95a1c672d2a9b414d026f18a8194bd8 (patch) | |
tree | 1459779e949328f5373ec08a1db89a03fb5e7d4f | |
parent | 9454c5d349c39ea73348e0d7c15a77f6e1426942 (diff) |
testsuites/isvv: New
Import ISVV testsuite from
CSW-RTEMSISVV-2022-TSP-05453_1-rtems-smp-isvv-iva-test-procedures.zip
with an SHA256 hash of
fdbe9ee336fd29da42ea7a0b8de558a369e7b3e0a2009b9a5c500f00fa960b88
87 files changed, 20317 insertions, 0 deletions
diff --git a/spec/build/testsuites/grp.yml b/spec/build/testsuites/grp.yml index a1fd9c4b84..70ed96f06a 100644 --- a/spec/build/testsuites/grp.yml +++ b/spec/build/testsuites/grp.yml @@ -23,6 +23,8 @@ links: - role: build-dependency uid: optfs - role: build-dependency + uid: optisvv +- role: build-dependency uid: optlib - role: build-dependency uid: optlibdl @@ -55,6 +57,8 @@ links: - role: build-dependency uid: fstests/grp - role: build-dependency + uid: isvv/grp +- role: build-dependency uid: libtests/grp - role: build-dependency uid: membench/grp diff --git a/spec/build/testsuites/isvv/00_mrsp_omip_uni.yml b/spec/build/testsuites/isvv/00_mrsp_omip_uni.yml new file mode 100644 index 0000000000..eeba769f41 --- /dev/null +++ b/spec/build/testsuites/isvv/00_mrsp_omip_uni.yml @@ -0,0 +1,22 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +build-type: test-program +cflags: [] +copyrights: +- Copyright (C) 2022 Critical Software SA +cppflags: [] +cxxflags: [] +enabled-by: RTEMS_SMP +features: c cprogram +includes: [] +ldflags: [] +links: [] +source: +- testsuites/isvv/00_uni_test_reference/mrsp_omip_uni.c +- testsuites/isvv/shared/utils.c +- testsuites/isvv/shared/isvv_rtems_aux.c +stlib: [] +target: testsuites/isvv/mrsp_omip_uni_reference.exe +type: build +use-after: +- isvv +use-before: [] diff --git a/spec/build/testsuites/isvv/00_uni_test_reference.yml b/spec/build/testsuites/isvv/00_uni_test_reference.yml new file mode 100644 index 0000000000..b0c4f8b543 --- /dev/null +++ b/spec/build/testsuites/isvv/00_uni_test_reference.yml @@ -0,0 +1,22 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +build-type: test-program +cflags: [] +copyrights: +- Copyright (C) 2022 Critical Software SA +cppflags: [] +cxxflags: [] +enabled-by: RTEMS_SMP +features: c cprogram +includes: [] +ldflags: [] +links: [] +source: +- testsuites/isvv/00_uni_test_reference/basic_smp_uni.c +- testsuites/isvv/shared/utils.c +- testsuites/isvv/shared/isvv_rtems_aux.c +stlib: [] +target: testsuites/isvv/basic_smp_uni.exe +type: build +use-after: +- isvv +use-before: [] diff --git a/spec/build/testsuites/isvv/01_basic_smp_multi.yml b/spec/build/testsuites/isvv/01_basic_smp_multi.yml new file mode 100644 index 0000000000..a4f3fb0063 --- /dev/null +++ b/spec/build/testsuites/isvv/01_basic_smp_multi.yml @@ -0,0 +1,22 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +build-type: test-program +cflags: [] +copyrights: +- Copyright (C) 2022 Critical Software SA +cppflags: [] +cxxflags: [] +enabled-by: RTEMS_SMP +features: c cprogram +includes: [] +ldflags: [] +links: [] +source: + - testsuites/isvv/01_basic_smp_multi/basic_smp_multi.c + - testsuites/isvv/shared/utils.c + - testsuites/isvv/shared/isvv_rtems_aux.c +stlib: [] +target: testsuites/isvv/basic_smp_multi.exe +type: build +use-after: +- isvv +use-before: [] diff --git a/spec/build/testsuites/isvv/02_core_affinity_multi.yml b/spec/build/testsuites/isvv/02_core_affinity_multi.yml new file mode 100644 index 0000000000..18d5991f7c --- /dev/null +++ b/spec/build/testsuites/isvv/02_core_affinity_multi.yml @@ -0,0 +1,22 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +build-type: test-program +cflags: [] +copyrights: +- Copyright (C) 2022 Critical Software SA +cppflags: [] +cxxflags: [] +enabled-by: RTEMS_SMP +features: c cprogram +includes: [] +ldflags: [] +links: [] +source: + - testsuites/isvv/02_core_affinity_multi/core_affinity_multi.c + - testsuites/isvv/shared/utils.c + - testsuites/isvv/shared/isvv_rtems_aux.c +stlib: [] +target: testsuites/isvv/core_affinity_multi.exe +type: build +use-after: +- isvv +use-before: [] diff --git a/spec/build/testsuites/isvv/03_semaphores_multi.yml b/spec/build/testsuites/isvv/03_semaphores_multi.yml new file mode 100644 index 0000000000..eb63c41999 --- /dev/null +++ b/spec/build/testsuites/isvv/03_semaphores_multi.yml @@ -0,0 +1,22 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +build-type: test-program +cflags: [] +copyrights: +- Copyright (C) 2022 Critical Software SA +cppflags: [] +cxxflags: [] +enabled-by: RTEMS_SMP +features: c cprogram +includes: [] +ldflags: [] +links: [] +source: +- testsuites/isvv/03_semaphores_multi/semaphores_multi.c +- testsuites/isvv/shared/utils.c +- testsuites/isvv/shared/isvv_rtems_aux.c +stlib: [] +target: testsuites/isvv/semaphores_multi.exe +type: build +use-after: +- isvv +use-before: [] diff --git a/spec/build/testsuites/isvv/04_messages_multi.yml b/spec/build/testsuites/isvv/04_messages_multi.yml new file mode 100644 index 0000000000..291304940b --- /dev/null +++ b/spec/build/testsuites/isvv/04_messages_multi.yml @@ -0,0 +1,22 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +build-type: test-program +cflags: [] +copyrights: +- Copyright (C) 2022 Critical Software SA +cppflags: [] +cxxflags: [] +enabled-by: RTEMS_SMP +features: c cprogram +includes: [] +ldflags: [] +links: [] +source: +- testsuites/isvv/04_messages_multi/messages_multi.c +- testsuites/isvv/shared/utils.c +- testsuites/isvv/shared/isvv_rtems_aux.c +stlib: [] +target: testsuites/isvv/messages_multi.exe +type: build +use-after: +- isvv +use-before: [] diff --git a/spec/build/testsuites/isvv/05_priorities_multi.yml b/spec/build/testsuites/isvv/05_priorities_multi.yml new file mode 100644 index 0000000000..97fcbca094 --- /dev/null +++ b/spec/build/testsuites/isvv/05_priorities_multi.yml @@ -0,0 +1,22 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +build-type: test-program +cflags: [] +copyrights: +- Copyright (C) 2022 Critical Software SA +cppflags: [] +cxxflags: [] +enabled-by: RTEMS_SMP +features: c cprogram +includes: [] +ldflags: [] +links: [] +source: +- testsuites/isvv/05_priorities_multi/priorities_multi.c +- testsuites/isvv/shared/utils.c +- testsuites/isvv/shared/isvv_rtems_aux.c +stlib: [] +target: testsuites/isvv/priorities_multi.exe +type: build +use-after: +- isvv +use-before: [] diff --git a/spec/build/testsuites/isvv/06_rate_monotonic_multi.yml b/spec/build/testsuites/isvv/06_rate_monotonic_multi.yml new file mode 100644 index 0000000000..97bcd0f2d6 --- /dev/null +++ b/spec/build/testsuites/isvv/06_rate_monotonic_multi.yml @@ -0,0 +1,22 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +build-type: test-program +cflags: [] +copyrights: +- Copyright (C) 2022 Critical Software SA +cppflags: [] +cxxflags: [] +enabled-by: RTEMS_SMP +features: c cprogram +includes: [] +ldflags: [] +links: [] +source: +- testsuites/isvv/06_rate_monotonic_multi/rate_monotonic_multi.c +- testsuites/isvv/shared/utils.c +- testsuites/isvv/shared/isvv_rtems_aux.c +stlib: [] +target: testsuites/isvv/rate_monotonic_multi.exe +type: build +use-after: +- isvv +use-before: [] diff --git a/spec/build/testsuites/isvv/07_timer_multi.yml b/spec/build/testsuites/isvv/07_timer_multi.yml new file mode 100644 index 0000000000..dfbee13909 --- /dev/null +++ b/spec/build/testsuites/isvv/07_timer_multi.yml @@ -0,0 +1,22 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +build-type: test-program +cflags: [] +copyrights: +- Copyright (C) 2022 Critical Software SA +cppflags: [] +cxxflags: [] +enabled-by: RTEMS_SMP +features: c cprogram +includes: [] +ldflags: [] +links: [] +source: +- testsuites/isvv/07_timer_multi/timer_multi.c +- testsuites/isvv/shared/utils.c +- testsuites/isvv/shared/isvv_rtems_aux.c +stlib: [] +target: testsuites/isvv/timer_multi.exe +type: build +use-after: +- isvv +use-before: []
\ No newline at end of file diff --git a/spec/build/testsuites/isvv/10_barrier_multi.yml b/spec/build/testsuites/isvv/10_barrier_multi.yml new file mode 100644 index 0000000000..22025f515a --- /dev/null +++ b/spec/build/testsuites/isvv/10_barrier_multi.yml @@ -0,0 +1,22 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +build-type: test-program +cflags: [] +copyrights: +- Copyright (C) 2022 Critical Software SA +cppflags: [] +cxxflags: [] +enabled-by: RTEMS_SMP +features: c cprogram +includes: [] +ldflags: [] +links: [] +source: +- testsuites/isvv/10_barrier_multi/barrier_multi.c +- testsuites/isvv/shared/utils.c +- testsuites/isvv/shared/isvv_rtems_aux.c +stlib: [] +target: testsuites/isvv/barrier_multi.exe +type: build +use-after: +- isvv +use-before: [] diff --git a/spec/build/testsuites/isvv/10_barrier_multi_timeout.yml b/spec/build/testsuites/isvv/10_barrier_multi_timeout.yml new file mode 100644 index 0000000000..aefbabeda7 --- /dev/null +++ b/spec/build/testsuites/isvv/10_barrier_multi_timeout.yml @@ -0,0 +1,22 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +build-type: test-program +cflags: [] +copyrights: +- Copyright (C) 2022 Critical Software SA +cppflags: [] +cxxflags: [] +enabled-by: RTEMS_SMP +features: c cprogram +includes: [] +ldflags: [] +links: [] +source: +- testsuites/isvv/10_barrier_multi/barrier_multi_timeout.c +- testsuites/isvv/shared/utils.c +- testsuites/isvv/shared/isvv_rtems_aux.c +stlib: [] +target: testsuites/isvv/barrier_multi_timeout.exe +type: build +use-after: +- isvv +use-before: [] diff --git a/spec/build/testsuites/isvv/11_mrsp_multi.yml b/spec/build/testsuites/isvv/11_mrsp_multi.yml new file mode 100644 index 0000000000..45b3373f0a --- /dev/null +++ b/spec/build/testsuites/isvv/11_mrsp_multi.yml @@ -0,0 +1,22 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +build-type: test-program +cflags: [] +copyrights: +- Copyright (C) 2022 Critical Software SA +cppflags: [] +cxxflags: [] +enabled-by: RTEMS_SMP +features: c cprogram +includes: [] +ldflags: [] +links: [] +source: +- testsuites/isvv/11_MrsP_multi/mrsp_multi.c +- testsuites/isvv/shared/utils.c +- testsuites/isvv/shared/isvv_rtems_aux.c +stlib: [] +target: testsuites/isvv/mrsp_multi.exe +type: build +use-after: +- isvv +use-before: [] diff --git a/spec/build/testsuites/isvv/11_mrsp_uni.yml b/spec/build/testsuites/isvv/11_mrsp_uni.yml new file mode 100644 index 0000000000..ccbe57400b --- /dev/null +++ b/spec/build/testsuites/isvv/11_mrsp_uni.yml @@ -0,0 +1,22 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +build-type: test-program +cflags: [] +copyrights: +- Copyright (C) 2022 Critical Software SA +cppflags: [] +cxxflags: [] +enabled-by: RTEMS_SMP +features: c cprogram +includes: [] +ldflags: [] +links: [] +source: +- testsuites/isvv/11_MrsP_uni/mrsp_uni.c +- testsuites/isvv/shared/utils.c +- testsuites/isvv/shared/isvv_rtems_aux.c +stlib: [] +target: testsuites/isvv/mrsp_uni.exe +type: build +use-after: +- isvv +use-before: [] diff --git a/spec/build/testsuites/isvv/12_omip_multi.yml b/spec/build/testsuites/isvv/12_omip_multi.yml new file mode 100644 index 0000000000..bd18511ecc --- /dev/null +++ b/spec/build/testsuites/isvv/12_omip_multi.yml @@ -0,0 +1,22 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +build-type: test-program +cflags: [] +copyrights: +- Copyright (C) 2022 Critical Software SA +cppflags: [] +cxxflags: [] +enabled-by: RTEMS_SMP +features: c cprogram +includes: [] +ldflags: [] +links: [] +source: +- testsuites/isvv/12_OMIP_multi/omip_multi.c +- testsuites/isvv/shared/utils.c +- testsuites/isvv/shared/isvv_rtems_aux.c +stlib: [] +target: testsuites/isvv/omip_multi.exe +type: build +use-after: +- isvv +use-before: [] diff --git a/spec/build/testsuites/isvv/12_omip_uni.yml b/spec/build/testsuites/isvv/12_omip_uni.yml new file mode 100644 index 0000000000..a4e12cc65f --- /dev/null +++ b/spec/build/testsuites/isvv/12_omip_uni.yml @@ -0,0 +1,22 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +build-type: test-program +cflags: [] +copyrights: +- Copyright (C) 2022 Critical Software SA +cppflags: [] +cxxflags: [] +enabled-by: RTEMS_SMP +features: c cprogram +includes: [] +ldflags: [] +links: [] +source: +- testsuites/isvv/12_OMIP_uni/omip_uni.c +- testsuites/isvv/shared/utils.c +- testsuites/isvv/shared/isvv_rtems_aux.c +stlib: [] +target: testsuites/isvv/omip_uni.exe +type: build +use-after: +- isvv +use-before: [] diff --git a/spec/build/testsuites/isvv/13_priority_inheritance_disabled.yml b/spec/build/testsuites/isvv/13_priority_inheritance_disabled.yml new file mode 100644 index 0000000000..d1d3767791 --- /dev/null +++ b/spec/build/testsuites/isvv/13_priority_inheritance_disabled.yml @@ -0,0 +1,22 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +build-type: test-program +cflags: [] +copyrights: +- Copyright (C) 2022 Critical Software SA +cppflags: [] +cxxflags: [] +enabled-by: RTEMS_SMP +features: c cprogram +includes: [] +ldflags: [] +links: [] +source: +- testsuites/isvv/13_priority_inheritance/priority_inheritance.c +- testsuites/isvv/shared/utils.c +- testsuites/isvv/shared/isvv_rtems_aux.c +stlib: [] +target: testsuites/isvv/priority_inheritance_disabled.exe +type: build +use-after: +- isvv +use-before: [] diff --git a/spec/build/testsuites/isvv/13_priority_inheritance_enabled.yml b/spec/build/testsuites/isvv/13_priority_inheritance_enabled.yml new file mode 100644 index 0000000000..dd5a745d3e --- /dev/null +++ b/spec/build/testsuites/isvv/13_priority_inheritance_enabled.yml @@ -0,0 +1,22 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +build-type: test-program +cflags: [] +copyrights: +- Copyright (C) 2022 Critical Software SA +cppflags: [-DPRIO_INHERIT] +cxxflags: [] +enabled-by: RTEMS_SMP +features: c cprogram +includes: [] +ldflags: [] +links: [] +source: +- testsuites/isvv/13_priority_inheritance/priority_inheritance.c +- testsuites/isvv/shared/utils.c +- testsuites/isvv/shared/isvv_rtems_aux.c +stlib: [] +target: testsuites/isvv/priority_inheritance_enabled.exe +type: build +use-after: +- isvv +use-before: [] diff --git a/spec/build/testsuites/isvv/14_immediate_ceiling_disabled.yml b/spec/build/testsuites/isvv/14_immediate_ceiling_disabled.yml new file mode 100644 index 0000000000..9c8f392e72 --- /dev/null +++ b/spec/build/testsuites/isvv/14_immediate_ceiling_disabled.yml @@ -0,0 +1,22 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +build-type: test-program +cflags: [] +copyrights: +- Copyright (C) 2022 Critical Software SA +cppflags: [] +cxxflags: [] +enabled-by: RTEMS_SMP +features: c cprogram +includes: [] +ldflags: [] +links: [] +source: +- testsuites/isvv/14_immediate_ceiling_protocol/immediate_ceiling.c +- testsuites/isvv/shared/utils.c +- testsuites/isvv/shared/isvv_rtems_aux.c +stlib: [] +target: testsuites/isvv/immediate_ceiling_disabled.exe +type: build +use-after: +- isvv +use-before: [] diff --git a/spec/build/testsuites/isvv/14_immediate_ceiling_enabled.yml b/spec/build/testsuites/isvv/14_immediate_ceiling_enabled.yml new file mode 100644 index 0000000000..26ee6a9dab --- /dev/null +++ b/spec/build/testsuites/isvv/14_immediate_ceiling_enabled.yml @@ -0,0 +1,22 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +build-type: test-program +cflags: [] +copyrights: +- Copyright (C) 2022 Critical Software SA +cppflags: [-DPRIO_CEILING] +cxxflags: [] +enabled-by: RTEMS_SMP +features: c cprogram +includes: [] +ldflags: [] +links: [] +source: +- testsuites/isvv/14_immediate_ceiling_protocol/immediate_ceiling.c +- testsuites/isvv/shared/utils.c +- testsuites/isvv/shared/isvv_rtems_aux.c +stlib: [] +target: testsuites/isvv/immediate_ceiling_enabled.exe +type: build +use-after: +- isvv +use-before: [] diff --git a/spec/build/testsuites/isvv/15_clock_manager_undefined_behaviour.yml b/spec/build/testsuites/isvv/15_clock_manager_undefined_behaviour.yml new file mode 100644 index 0000000000..fd6d1fe081 --- /dev/null +++ b/spec/build/testsuites/isvv/15_clock_manager_undefined_behaviour.yml @@ -0,0 +1,22 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +build-type: test-program +cflags: [] +copyrights: +- Copyright (C) 2022 Critical Software SA +cppflags: [] +cxxflags: [] +enabled-by: RTEMS_SMP +features: c cprogram +includes: [] +ldflags: [] +links: [] +source: +- testsuites/isvv/15_clock_manager_undefined_behaviour/clock_manager_undefined_behaviour.c +- testsuites/isvv/shared/utils.c +- testsuites/isvv/shared/isvv_rtems_aux.c +stlib: [] +target: testsuites/isvv/clock_manager_undefined_behaviour.exe +type: build +use-after: +- isvv +use-before: [] diff --git a/spec/build/testsuites/isvv/16_task_manager_undefined_behaviour.yml b/spec/build/testsuites/isvv/16_task_manager_undefined_behaviour.yml new file mode 100644 index 0000000000..bc3b0b5ae5 --- /dev/null +++ b/spec/build/testsuites/isvv/16_task_manager_undefined_behaviour.yml @@ -0,0 +1,22 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +build-type: test-program +cflags: [] +copyrights: +- Copyright (C) 2022 Critical Software SA +cppflags: [] +cxxflags: [] +enabled-by: RTEMS_SMP +features: c cprogram +includes: [] +ldflags: [] +links: [] +source: +- testsuites/isvv/16_task_manager_undefined_behaviour/task_manager_undefined_behaviour.c +- testsuites/isvv/shared/utils.c +- testsuites/isvv/shared/isvv_rtems_aux.c +stlib: [] +target: testsuites/isvv/task_manager_undefined_behaviour.exe +type: build +use-after: +- isvv +use-before: [] diff --git a/spec/build/testsuites/isvv/17_barrier_manager_undefined_behaviour.yml b/spec/build/testsuites/isvv/17_barrier_manager_undefined_behaviour.yml new file mode 100644 index 0000000000..a2274347bf --- /dev/null +++ b/spec/build/testsuites/isvv/17_barrier_manager_undefined_behaviour.yml @@ -0,0 +1,22 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +build-type: test-program +cflags: [] +copyrights: +- Copyright (C) 2022 Critical Software SA +cppflags: [] +cxxflags: [] +enabled-by: RTEMS_SMP +features: c cprogram +includes: [] +ldflags: [] +links: [] +source: +- testsuites/isvv/17_barrier_manager_undefined_behaviour/barrier_manager_undefined_behaviour.c +- testsuites/isvv/shared/utils.c +- testsuites/isvv/shared/isvv_rtems_aux.c +stlib: [] +target: testsuites/isvv/barrier_manager_undefined_behaviour.exe +type: build +use-after: +- isvv +use-before: [] diff --git a/spec/build/testsuites/isvv/18_event_manager_undefined_behaviour.yml b/spec/build/testsuites/isvv/18_event_manager_undefined_behaviour.yml new file mode 100644 index 0000000000..43b8ac8f63 --- /dev/null +++ b/spec/build/testsuites/isvv/18_event_manager_undefined_behaviour.yml @@ -0,0 +1,22 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +build-type: test-program +cflags: [] +copyrights: +- Copyright (C) 2022 Critical Software SA +cppflags: [] +cxxflags: [] +enabled-by: RTEMS_SMP +features: c cprogram +includes: [] +ldflags: [] +links: [] +source: +- testsuites/isvv/18_event_manager_undefined_behaviour/event_manager_undefined_behaviour.c +- testsuites/isvv/shared/utils.c +- testsuites/isvv/shared/isvv_rtems_aux.c +stlib: [] +target: testsuites/isvv/event_manager_undefined_behaviour.exe +type: build +use-after: +- isvv +use-before: [] diff --git a/spec/build/testsuites/isvv/19_message_manager_undefined_behaviour.yml b/spec/build/testsuites/isvv/19_message_manager_undefined_behaviour.yml new file mode 100644 index 0000000000..db2d5fcd89 --- /dev/null +++ b/spec/build/testsuites/isvv/19_message_manager_undefined_behaviour.yml @@ -0,0 +1,22 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +build-type: test-program +cflags: [] +copyrights: +- Copyright (C) 2022 Critical Software SA +cppflags: [] +cxxflags: [] +enabled-by: RTEMS_SMP +features: c cprogram +includes: [] +ldflags: [] +links: [] +source: +- testsuites/isvv/19_message_manager_undefined_behaviour/message_manager_undefined_behaviour.c +- testsuites/isvv/shared/utils.c +- testsuites/isvv/shared/isvv_rtems_aux.c +stlib: [] +target: testsuites/isvv/message_manager_undefined_behaviour.exe +type: build +use-after: +- isvv +use-before: [] diff --git a/spec/build/testsuites/isvv/20_partition_manager_undefined_behaviour.yml b/spec/build/testsuites/isvv/20_partition_manager_undefined_behaviour.yml new file mode 100644 index 0000000000..d4ffe1c389 --- /dev/null +++ b/spec/build/testsuites/isvv/20_partition_manager_undefined_behaviour.yml @@ -0,0 +1,22 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +build-type: test-program +cflags: [] +copyrights: +- Copyright (C) 2022 Critical Software SA +cppflags: [] +cxxflags: [] +enabled-by: RTEMS_SMP +features: c cprogram +includes: [] +ldflags: [] +links: [] +source: +- testsuites/isvv/20_partition_manager_undefined_behaviour/partition_manager_undefined_behaviour.c +- testsuites/isvv/shared/utils.c +- testsuites/isvv/shared/isvv_rtems_aux.c +stlib: [] +target: testsuites/isvv/partition_manager_undefined_behaviour.exe +type: build +use-after: +- isvv +use-before: [] diff --git a/spec/build/testsuites/isvv/21_semaphore_manager_undefined_behaviour.yml b/spec/build/testsuites/isvv/21_semaphore_manager_undefined_behaviour.yml new file mode 100644 index 0000000000..a8b40bc43f --- /dev/null +++ b/spec/build/testsuites/isvv/21_semaphore_manager_undefined_behaviour.yml @@ -0,0 +1,22 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +build-type: test-program +cflags: [] +copyrights: +- Copyright (C) 2022 Critical Software SA +cppflags: [] +cxxflags: [] +enabled-by: RTEMS_SMP +features: c cprogram +includes: [] +ldflags: [] +links: [] +source: +- testsuites/isvv/21_semaphore_manager_undefined_behaviour/semaphore_manager_undefined_behaviour.c +- testsuites/isvv/shared/utils.c +- testsuites/isvv/shared/isvv_rtems_aux.c +stlib: [] +target: testsuites/isvv/semaphore_manager_undefined_behaviour.exe +type: build +use-after: +- isvv +use-before: [] diff --git a/spec/build/testsuites/isvv/22_base_defs_undefined_behaviour.yml b/spec/build/testsuites/isvv/22_base_defs_undefined_behaviour.yml new file mode 100644 index 0000000000..198fe5512e --- /dev/null +++ b/spec/build/testsuites/isvv/22_base_defs_undefined_behaviour.yml @@ -0,0 +1,22 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +build-type: test-program +cflags: [] +copyrights: +- Copyright (C) 2022 Critical Software SA +cppflags: [] +cxxflags: [] +enabled-by: RTEMS_SMP +features: c cprogram +includes: [] +ldflags: [] +links: [] +source: +- testsuites/isvv/22_base_defs_undefined_behaviour/base_defs_undefined_behaviour.c +- testsuites/isvv/shared/utils.c +- testsuites/isvv/shared/isvv_rtems_aux.c +stlib: [] +target: testsuites/isvv/base_defs_undefined_behaviour.exe +type: build +use-after: +- isvv +use-before: [] diff --git a/spec/build/testsuites/isvv/23_10_uni_cache_l2_enabled.yml b/spec/build/testsuites/isvv/23_10_uni_cache_l2_enabled.yml new file mode 100644 index 0000000000..dc4a54bb09 --- /dev/null +++ b/spec/build/testsuites/isvv/23_10_uni_cache_l2_enabled.yml @@ -0,0 +1,26 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +build-type: test-program +cflags: [] +copyrights: +- Copyright (C) 2022 Critical Software SA +cppflags: [ -DGR740_ESA_BOARD ] +cxxflags: [] +enabled-by: + and: + - RTEMS_SMP + - not: sparc/gr712rc +features: c cprogram +includes: [] +ldflags: [] +links: [] +source: +- testsuites/isvv/23.10_uni_cache_l2_enabled/uni_cache_l2_enabled.c +- testsuites/isvv/shared/utils.c +- testsuites/isvv/shared/isvv_rtems_aux.c +- testsuites/isvv/shared/low_level_utils.c +stlib: [] +target: testsuites/isvv/uni_cache_l2_enabled.exe +type: build +use-after: +- isvv +use-before: [] diff --git a/spec/build/testsuites/isvv/23_11_multi_cache_l2_enabled.yml b/spec/build/testsuites/isvv/23_11_multi_cache_l2_enabled.yml new file mode 100644 index 0000000000..1c411f8e32 --- /dev/null +++ b/spec/build/testsuites/isvv/23_11_multi_cache_l2_enabled.yml @@ -0,0 +1,26 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +build-type: test-program +cflags: [] +copyrights: +- Copyright (C) 2022 Critical Software SA +cppflags: [ -DGR740_ESA_BOARD ] +cxxflags: [] +enabled-by: + and: + - RTEMS_SMP + - not: sparc/gr712rc +features: c cprogram +includes: [] +ldflags: [] +links: [] +source: +- testsuites/isvv/23.11_multi_cache_l2_enabled/multi_cache_l2_enabled.c +- testsuites/isvv/shared/utils.c +- testsuites/isvv/shared/isvv_rtems_aux.c +- testsuites/isvv/shared/low_level_utils.c +stlib: [] +target: testsuites/isvv/multi_cache_l2_enabled.exe +type: build +use-after: +- isvv +use-before: [] diff --git a/spec/build/testsuites/isvv/23_12_multi_cache_l2_disable.yml b/spec/build/testsuites/isvv/23_12_multi_cache_l2_disable.yml new file mode 100644 index 0000000000..052e7778c2 --- /dev/null +++ b/spec/build/testsuites/isvv/23_12_multi_cache_l2_disable.yml @@ -0,0 +1,26 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +build-type: test-program +cflags: [] +copyrights: +- Copyright (C) 2022 Critical Software SA +cppflags: [ -DGR740_ESA_BOARD ] +cxxflags: [] +enabled-by: + and: + - RTEMS_SMP + - not: sparc/gr712rc +features: c cprogram +includes: [] +ldflags: [] +links: [] +source: +- testsuites/isvv/23.12_multi_cache_l2_disabled/multi_cache_l2_disabled.c +- testsuites/isvv/shared/utils.c +- testsuites/isvv/shared/isvv_rtems_aux.c +- testsuites/isvv/shared/low_level_utils.c +stlib: [] +target: testsuites/isvv/multi_cache_l2_disabled.exe +type: build +use-after: +- isvv +use-before: [] diff --git a/spec/build/testsuites/isvv/23_1_uni_cache_way_locking_disabled.yml b/spec/build/testsuites/isvv/23_1_uni_cache_way_locking_disabled.yml new file mode 100644 index 0000000000..737b085676 --- /dev/null +++ b/spec/build/testsuites/isvv/23_1_uni_cache_way_locking_disabled.yml @@ -0,0 +1,27 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +build-type: test-program +cflags: [] +copyrights: +- Copyright (C) 2022 Critical Software SA +cppflags: [ -DGR740_ESA_BOARD ] +cxxflags: [] +enabled-by: +enabled-by: + and: + - RTEMS_SMP + - not: sparc/gr712rc +features: c cprogram +includes: [] +ldflags: [] +links: [] +source: +- testsuites/isvv/23.1_uni_cache_way_locking_disabled/uni_cache_way_locking_disabled.c +- testsuites/isvv/shared/utils.c +- testsuites/isvv/shared/isvv_rtems_aux.c +- testsuites/isvv/shared/low_level_utils.c +stlib: [] +target: testsuites/isvv/uni_cache_way_locking_disabled.exe +type: build +use-after: +- isvv +use-before: [] diff --git a/spec/build/testsuites/isvv/23_2_multi_cache_way_locking_disabled.yml b/spec/build/testsuites/isvv/23_2_multi_cache_way_locking_disabled.yml new file mode 100644 index 0000000000..0f900dc7b0 --- /dev/null +++ b/spec/build/testsuites/isvv/23_2_multi_cache_way_locking_disabled.yml @@ -0,0 +1,26 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +build-type: test-program +cflags: [] +copyrights: +- Copyright (C) 2022 Critical Software SA +cppflags: [ -DGR740_ESA_BOARD ] +cxxflags: [] +enabled-by: + and: + - RTEMS_SMP + - not: sparc/gr712rc +features: c cprogram +includes: [] +ldflags: [] +links: [] +source: +- testsuites/isvv/23.2_multi_cache_way_locking_disabled/multi_cache_way_locking_disabled.c +- testsuites/isvv/shared/utils.c +- testsuites/isvv/shared/isvv_rtems_aux.c +- testsuites/isvv/shared/low_level_utils.c +stlib: [] +target: testsuites/isvv/multi_cache_way_locking_disabled.exe +type: build +use-after: +- isvv +use-before: [] diff --git a/spec/build/testsuites/isvv/23_3_multi_cache_way_locking_enabled.yml b/spec/build/testsuites/isvv/23_3_multi_cache_way_locking_enabled.yml new file mode 100644 index 0000000000..14c75f6332 --- /dev/null +++ b/spec/build/testsuites/isvv/23_3_multi_cache_way_locking_enabled.yml @@ -0,0 +1,26 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +build-type: test-program +cflags: [] +copyrights: +- Copyright (C) 2022 Critical Software SA +cppflags: [ -DGR740_ESA_BOARD ] +cxxflags: [] +enabled-by: + and: + - RTEMS_SMP + - not: sparc/gr712rc +features: c cprogram +includes: [] +ldflags: [] +links: [] +source: +- testsuites/isvv/23.3_multi_cache_way_locking_enabled/multi_cache_way_locking_enabled.c +- testsuites/isvv/shared/utils.c +- testsuites/isvv/shared/isvv_rtems_aux.c +- testsuites/isvv/shared/low_level_utils.c +stlib: [] +target: testsuites/isvv/multi_cache_way_locking_enabled.exe +type: build +use-after: +- isvv +use-before: [] diff --git a/spec/build/testsuites/isvv/23_4_uni_cache_split_transactions_disabled.yml b/spec/build/testsuites/isvv/23_4_uni_cache_split_transactions_disabled.yml new file mode 100644 index 0000000000..100438beea --- /dev/null +++ b/spec/build/testsuites/isvv/23_4_uni_cache_split_transactions_disabled.yml @@ -0,0 +1,26 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +build-type: test-program +cflags: [] +copyrights: +- Copyright (C) 2022 Critical Software SA +cppflags: [ -DGR740_ESA_BOARD ] +cxxflags: [] +enabled-by: + and: + - RTEMS_SMP + - not: sparc/gr712rc +features: c cprogram +includes: [] +ldflags: [] +links: [] +source: +- testsuites/isvv/23.4_uni_cache_split_transactions_disabled/uni_cache_split_transactions_disabled.c +- testsuites/isvv/shared/utils.c +- testsuites/isvv/shared/isvv_rtems_aux.c +- testsuites/isvv/shared/low_level_utils.c +stlib: [] +target: testsuites/isvv/uni_cache_split_transactions_disabled.exe +type: build +use-after: +- isvv +use-before: [] diff --git a/spec/build/testsuites/isvv/23_5_multi_cache_split_transactions_disabled.yml b/spec/build/testsuites/isvv/23_5_multi_cache_split_transactions_disabled.yml new file mode 100644 index 0000000000..14bd40b58c --- /dev/null +++ b/spec/build/testsuites/isvv/23_5_multi_cache_split_transactions_disabled.yml @@ -0,0 +1,26 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +build-type: test-program +cflags: [] +copyrights: +- Copyright (C) 2022 Critical Software SA +cppflags: [ -DGR740_ESA_BOARD ] +cxxflags: [] +enabled-by: + and: + - RTEMS_SMP + - not: sparc/gr712rc +features: c cprogram +includes: [] +ldflags: [] +links: [] +source: +- testsuites/isvv/23.5_multi_cache_split_transactions_disabled/multi_cache_split_transactions_disabled.c +- testsuites/isvv/shared/utils.c +- testsuites/isvv/shared/isvv_rtems_aux.c +- testsuites/isvv/shared/low_level_utils.c +stlib: [] +target: testsuites/isvv/multi_cache_split_transactions_disabled.exe +type: build +use-after: +- isvv +use-before: [] diff --git a/spec/build/testsuites/isvv/23_6_multi_cache_split_transactions_enabled.yml b/spec/build/testsuites/isvv/23_6_multi_cache_split_transactions_enabled.yml new file mode 100644 index 0000000000..3401998eeb --- /dev/null +++ b/spec/build/testsuites/isvv/23_6_multi_cache_split_transactions_enabled.yml @@ -0,0 +1,26 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +build-type: test-program +cflags: [] +copyrights: +- Copyright (C) 2022 Critical Software SA +cppflags: [ -DGR740_ESA_BOARD ] +cxxflags: [] +enabled-by: + and: + - RTEMS_SMP + - not: sparc/gr712rc +features: c cprogram +includes: [] +ldflags: [] +links: [] +source: +- testsuites/isvv/23.6_multi_cache_split_transactions_enabled/multi_cache_split_transactions_enabled.c +- testsuites/isvv/shared/utils.c +- testsuites/isvv/shared/isvv_rtems_aux.c +- testsuites/isvv/shared/low_level_utils.c +stlib: [] +target: testsuites/isvv/multi_cache_split_transactions_enabled.exe +type: build +use-after: +- isvv +use-before: [] diff --git a/spec/build/testsuites/isvv/23_7_uni_cache_repl_policy_l2_lru.yml b/spec/build/testsuites/isvv/23_7_uni_cache_repl_policy_l2_lru.yml new file mode 100644 index 0000000000..df49956ed8 --- /dev/null +++ b/spec/build/testsuites/isvv/23_7_uni_cache_repl_policy_l2_lru.yml @@ -0,0 +1,26 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +build-type: test-program +cflags: [] +copyrights: +- Copyright (C) 2022 Critical Software SA +cppflags: [ -DGR740_ESA_BOARD ] +cxxflags: [] +enabled-by: + and: + - RTEMS_SMP + - not: sparc/gr712rc +features: c cprogram +includes: [] +ldflags: [] +links: [] +source: +- testsuites/isvv/23.7_uni_cache_repl_policy_l2_lru/uni_cache_repl_policy_l2_lru.c +- testsuites/isvv/shared/utils.c +- testsuites/isvv/shared/isvv_rtems_aux.c +- testsuites/isvv/shared/low_level_utils.c +stlib: [] +target: testsuites/isvv/uni_cache_repl_policy_l2_lru.exe +type: build +use-after: +- isvv +use-before: [] diff --git a/spec/build/testsuites/isvv/23_8_multi_cache_repl_policy_l2_lru.yml b/spec/build/testsuites/isvv/23_8_multi_cache_repl_policy_l2_lru.yml new file mode 100644 index 0000000000..a07f09e4e5 --- /dev/null +++ b/spec/build/testsuites/isvv/23_8_multi_cache_repl_policy_l2_lru.yml @@ -0,0 +1,26 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +build-type: test-program +cflags: [] +copyrights: +- Copyright (C) 2022 Critical Software SA +cppflags: [ -DGR740_ESA_BOARD ] +cxxflags: [] +enabled-by: + and: + - RTEMS_SMP + - not: sparc/gr712rc +features: c cprogram +includes: [] +ldflags: [] +links: [] +source: +- testsuites/isvv/23.8_multi_cache_repl_policy_l2_lru/multi_cache_repl_policy_l2_lru.c +- testsuites/isvv/shared/utils.c +- testsuites/isvv/shared/isvv_rtems_aux.c +- testsuites/isvv/shared/low_level_utils.c +stlib: [] +target: testsuites/isvv/multi_cache_repl_policy_l2_lru.exe +type: build +use-after: +- isvv +use-before: [] diff --git a/spec/build/testsuites/isvv/23_9_multi_cache_repl_policy_l2_random.yml b/spec/build/testsuites/isvv/23_9_multi_cache_repl_policy_l2_random.yml new file mode 100644 index 0000000000..f2b8ec2890 --- /dev/null +++ b/spec/build/testsuites/isvv/23_9_multi_cache_repl_policy_l2_random.yml @@ -0,0 +1,26 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +build-type: test-program +cflags: [] +copyrights: +- Copyright (C) 2022 Critical Software SA +cppflags: [ -DGR740_ESA_BOARD ] +cxxflags: [] +enabled-by: + and: + - RTEMS_SMP + - not: sparc/gr712rc +features: c cprogram +includes: [] +ldflags: [] +links: [] +source: +- testsuites/isvv/23.9_multi_cache_repl_policy_l2_random/multi_cache_repl_policy_l2_random.c +- testsuites/isvv/shared/utils.c +- testsuites/isvv/shared/isvv_rtems_aux.c +- testsuites/isvv/shared/low_level_utils.c +stlib: [] +target: testsuites/isvv/multi_cache_repl_policy_l2_random.exe +type: build +use-after: +- isvv +use-before: [] diff --git a/spec/build/testsuites/isvv/grp.yml b/spec/build/testsuites/isvv/grp.yml new file mode 100644 index 0000000000..318626487f --- /dev/null +++ b/spec/build/testsuites/isvv/grp.yml @@ -0,0 +1,97 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +build-type: group +cflags: [] +copyrights: +- Copyright (C) 2022 Critical Software SA +cppflags: [] +cxxflags: [] +enabled-by: BUILD_ISVVTESTS +includes: +- ${BSP_INCLUDES} +install: [] +ldflags: [] +links: +- role: build-dependency + uid: optgr712rc +- role: build-dependency + uid: optgr740 +- role: build-dependency + uid: 00_uni_test_reference +- role: build-dependency + uid: 00_mrsp_omip_uni +- role: build-dependency + uid: 01_basic_smp_multi +- role: build-dependency + uid: 02_core_affinity_multi +- role: build-dependency + uid: 03_semaphores_multi +- role: build-dependency + uid: 04_messages_multi +- role: build-dependency + uid: 05_priorities_multi +- role: build-dependency + uid: 06_rate_monotonic_multi +- role: build-dependency + uid: 07_timer_multi +- role: build-dependency + uid: 10_barrier_multi +- role: build-dependency + uid: 10_barrier_multi_timeout +- role: build-dependency + uid: 11_mrsp_multi +- role: build-dependency + uid: 12_omip_multi +- role: build-dependency + uid: 13_priority_inheritance_enabled +- role: build-dependency + uid: 13_priority_inheritance_disabled +- role: build-dependency + uid: 14_immediate_ceiling_enabled +- role: build-dependency + uid: 14_immediate_ceiling_disabled +- role: build-dependency + uid: 15_clock_manager_undefined_behaviour +- role: build-dependency + uid: 16_task_manager_undefined_behaviour +- role: build-dependency + uid: 17_barrier_manager_undefined_behaviour +- role: build-dependency + uid: 18_event_manager_undefined_behaviour +- role: build-dependency + uid: 19_message_manager_undefined_behaviour +- role: build-dependency + uid: 20_partition_manager_undefined_behaviour +- role: build-dependency + uid: 21_semaphore_manager_undefined_behaviour +- role: build-dependency + uid: 22_base_defs_undefined_behaviour +- role: build-dependency + uid: 23_1_uni_cache_way_locking_disabled +- role: build-dependency + uid: 23_2_multi_cache_way_locking_disabled +- role: build-dependency + uid: 23_3_multi_cache_way_locking_enabled +- role: build-dependency + uid: 23_4_uni_cache_split_transactions_disabled +- role: build-dependency + uid: 23_5_multi_cache_split_transactions_disabled +- role: build-dependency + uid: 23_6_multi_cache_split_transactions_enabled +- role: build-dependency + uid: 23_7_uni_cache_repl_policy_l2_lru +- role: build-dependency + uid: 23_8_multi_cache_repl_policy_l2_lru +- role: build-dependency + uid: 23_9_multi_cache_repl_policy_l2_random +- role: build-dependency + uid: 23_10_uni_cache_l2_enabled +- role: build-dependency + uid: 23_11_multi_cache_l2_enabled +- role: build-dependency + uid: 23_12_multi_cache_l2_disable +type: build +use-after: +- rtemstest +- rtemscpu +- rtemsbsp +use-before: [] diff --git a/spec/build/testsuites/isvv/optgr712rc.yml b/spec/build/testsuites/isvv/optgr712rc.yml new file mode 100644 index 0000000000..84751229f0 --- /dev/null +++ b/spec/build/testsuites/isvv/optgr712rc.yml @@ -0,0 +1,17 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +actions: +- set-value: -Dgr712rc=1 +- env-assign: null +- env-append: CFLAGS +build-type: option +copyrights: +- Copyright (C) 2022 Critical Software SA +default: +- enabled-by: true + value: null +description: | + Enable flags to configure ISVV tests for gr712rc +enabled-by: sparc/gr712rc +links: [] +name: ISVV_FLAGS +type: build diff --git a/spec/build/testsuites/isvv/optgr740.yml b/spec/build/testsuites/isvv/optgr740.yml new file mode 100644 index 0000000000..1ff260d05e --- /dev/null +++ b/spec/build/testsuites/isvv/optgr740.yml @@ -0,0 +1,17 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +actions: +- set-value: -Dgr740=1 +- env-assign: null +- env-append: CFLAGS +build-type: option +copyrights: +- Copyright (C) 2022 Critical Software SA +default: +- enabled-by: true + value: null +description: | + Enable flags to configure ISVV tests for gr740 +enabled-by: sparc/gr740 +links: [] +name: ISVV_FLAGS +type: build diff --git a/spec/build/testsuites/optisvv.yml b/spec/build/testsuites/optisvv.yml new file mode 100644 index 0000000000..b592b348bf --- /dev/null +++ b/spec/build/testsuites/optisvv.yml @@ -0,0 +1,16 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +actions: +- get-boolean: null +- env-enable: null +build-type: option +copyrights: +- Copyright (C) 2022 Critical Software SA +default: +- enabled-by: true + value: false +description: | + Build the ISVV test programs +enabled-by: true +links: [] +name: BUILD_ISVVTESTS +type: build diff --git a/testsuites/isvv/00_uni_test_reference/basic_smp_uni.c b/testsuites/isvv/00_uni_test_reference/basic_smp_uni.c new file mode 100644 index 0000000000..89da110ee7 --- /dev/null +++ b/testsuites/isvv/00_uni_test_reference/basic_smp_uni.c @@ -0,0 +1,114 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 2022 Critical Software SA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <rtems/bspIo.h> +#include "../shared/utils.h" +#include "../shared/isvv_rtems_aux.h" + +/** + * + * @brief Tests basic symmetric multiprocessing capabilities on multiple cores + * + * This test case performs the calculation of the Mandelbrot set on 1 core + */ + +#define MAX_TLS_SIZE RTEMS_ALIGN_UP(64, RTEMS_TASK_STORAGE_ALIGNMENT) + +#define TASK_ATTRIBUTES RTEMS_FLOATING_POINT + +#define TASK_STORAGE_SIZE \ + RTEMS_TASK_STORAGE_SIZE( \ + MAX_TLS_SIZE + RTEMS_MINIMUM_STACK_SIZE, \ + TASK_ATTRIBUTES) + +#define ITOA_STR_SIZE (8 * sizeof(int) + 1) + +// test specific global vars +#undef TEST_PROCESSORS +#define TEST_PROCESSORS 1 +#define TASK_COUNT TEST_PROCESSORS + +static void Init(rtems_task_argument arg) +{ + (void)arg; + uint32_t start_time, end_time, elapsed_time; + char str[ITOA_STR_SIZE]; + + start_time = rtems_clock_get_ticks_since_boot(); + mandelbrot_tile(1,1); + end_time = rtems_clock_get_ticks_since_boot(); + elapsed_time = (end_time - start_time); + + print_string("\n"); + print_string("Single Core Elapsed Time -"); + print_string(itoa(elapsed_time, &str[0], 10)); + print_string("\n"); + + print_test_results(); + + rtems_fatal(RTEMS_FATAL_SOURCE_EXIT, 0); +} + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER + +#define CONFIGURE_MAXIMUM_PROCESSORS TEST_PROCESSORS + +#define CONFIGURE_MAXIMUM_TASKS (TEST_PROCESSORS + 2) + +#define CONFIGURE_MINIMUM_TASKS_WITH_USER_PROVIDED_STORAGE \ + CONFIGURE_MAXIMUM_TASKS + +#define CONFIGURE_MAXIMUM_TIMERS 3 + +#define CONFIGURE_MAXIMUM_USER_EXTENSIONS 3 + +#define CONFIGURE_MICROSECONDS_PER_TICK 1000 + +#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 0 + +#define CONFIGURE_DISABLE_NEWLIB_REENTRANCY + +#define CONFIGURE_APPLICATION_DISABLE_FILESYSTEM + +#define CONFIGURE_MAXIMUM_THREAD_LOCAL_STORAGE_SIZE MAX_TLS_SIZE + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT_TASK_ATTRIBUTES TASK_ATTRIBUTES + +#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES + +#define CONFIGURE_INIT_TASK_CONSTRUCT_STORAGE_SIZE TASK_STORAGE_SIZE + +#define CONFIGURE_INIT + +#include <rtems/confdefs.h> diff --git a/testsuites/isvv/00_uni_test_reference/mrsp_omip_uni.c b/testsuites/isvv/00_uni_test_reference/mrsp_omip_uni.c new file mode 100644 index 0000000000..dcfa7eda58 --- /dev/null +++ b/testsuites/isvv/00_uni_test_reference/mrsp_omip_uni.c @@ -0,0 +1,408 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 2022 Critical Software SA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <rtems/bspIo.h> +#include "../shared/isvv_rtems_aux.h" +#include "../shared/utils.h" +#include <string.h> + +/** +- * @brief Assert RTEMS SMP under the stress of multiple core workloads accessing protected data. +- * +- * This test case performs the calculation of orbital frequencies based on readings from sensors +- * with three periodic tasks, and two binary semaphores. The result is stored as a reference set +- * and the elapsed time is measured. +*/ + +#define ITOA_STR_SIZE (8 * sizeof(int) + 1) + +#define MAX_TLS_SIZE RTEMS_ALIGN_UP(64, RTEMS_TASK_STORAGE_ALIGNMENT) + +#define TASK_ATTRIBUTES RTEMS_FLOATING_POINT + +#define TASK_STORAGE_SIZE \ + RTEMS_TASK_STORAGE_SIZE(MAX_TLS_SIZE + RTEMS_MINIMUM_STACK_SIZE, \ + TASK_ATTRIBUTES) + +// test specific global vars +#undef TEST_PROCESSORS +#define TEST_PROCESSORS 1 +#define TASK_COUNT 3 + +#define END_OF_STREAM UINT8_MAX + +#define INCREMENT_AVAILABLE_DATA(x) (x++) + +#define DECREMENT_AVAILABLE_DATA(x) ({if (x>0) x--;}) + +#define TEST_IF_DATA_AVAILABLE_IS_EMPTY(x) (x==0) + +#define TEST_IF_DATA_AVAILABLE_IS_NOT_EMPTY(x) (x!=0) + +#define EVENT_FINISHED_SENSING RTEMS_EVENT_0 +#define EVENT_CALCULATED_DATA RTEMS_EVENT_1 +#define EVENT_WROTE_DATA RTEMS_EVENT_2 +#define EVENT_SENSOR_READY RTEMS_EVENT_3 +#define EVENT_DATA_READY RTEMS_EVENT_4 +#define EVENT_DATA_OUT RTEMS_EVENT_5 + +// For this data set, and given lumosity, the total number of planets found should equal 11 + +#define MAX_ITER (64U) +#define FFT_SIZE (32768U) +#define FFT_SIZE_LOG2 (15U) +#define TC_MAX (16U) +#define FILTER_REPETITIONS (2U) +#define SNR_THRESHOLD (1000000.0f) + +const uint16_t FS = 48000U; +const uint16_t FREQ[TC_MAX] = { 2500U, 1500U, 15000U, 500U, + 1000U, 800U, 440U, 8000U, + 100U, 3500U, 12345U, 1200U, + 20000U, 715U, 5000U, 4500U }; +const float NOISE_FACTOR[TC_MAX] = { 0.0001f, 0.2250f, 0.00068f, 0.30f, + 0.004f, 0.0123f, 0.0054f, 0.00054f, + 0.01f, 0.0325f, 0.012f, 0.00032f, + 0.075f, 0.0423f, 0.0354f, 0.00002f }; + +static float inSensorDataRe[FFT_SIZE]; +static float inSensorDataIm[FFT_SIZE]; +typedef struct +{ + rtems_id main_task_id; + rtems_id read_task_id; + rtems_id calc_task_id; + rtems_id write_task_id; + uint8_t m1_data; + uint32_t iter; + float scaling_fft_factor; + float snr_float; + rtems_id m1_data_mutex; + rtems_id m2_result_mutex; + uint8_t planet_count; + uint8_t planet_locations[MAX_ITER]; + uint16_t value_in_watts_flag_counter; + uint16_t luminosity_flag_counter; + float debug_maxValueIndex; + float debug_maxValue; + float debug_sig; + float debig_noise; +} test_context; + +RTEMS_ALIGNED(RTEMS_TASK_STORAGE_ALIGNMENT) +static char calc_task_storage[TASK_COUNT][TASK_STORAGE_SIZE]; + +// * Task 0 - writes sensors data onto shared memory +static void task_snr_read_sensor_data(rtems_task_argument arg) +{ + test_context *ctx; + ctx = (test_context *)arg; + + while ( ctx->iter < MAX_ITER) + { + ObtainMutex(ctx->m1_data_mutex); + if TEST_IF_DATA_AVAILABLE_IS_EMPTY(ctx->value_in_watts_flag_counter) + { + for (uint32_t i = 0; i < FFT_SIZE; i++) + { + inSensorDataRe[i] = 0.4995f * cos_aprox(i*2.0f*PI*FREQ[ctx->iter%TC_MAX]/FS) + + (noise_generator(0) * NOISE_FACTOR[ctx->iter%TC_MAX]); + inSensorDataIm[i] = 0.4995f * sin_aprox(i*2.0f*PI*FREQ[ctx->iter%TC_MAX]/FS) + + (noise_generator(0) * NOISE_FACTOR[ctx->iter% TC_MAX]); + } + INCREMENT_AVAILABLE_DATA(ctx->value_in_watts_flag_counter); + } + ReleaseMutex(ctx->m1_data_mutex); + rtems_task_wake_after(1); + } + SuspendSelf(); +} + +// * Task 1 - collects data when ready, calculates, and stores the result on the shared memory +static void task_snr_process_data(rtems_task_argument arg) +{ + test_context *ctx; + ctx = (test_context *)arg; + float sig = 0.0f; + float noise = 0.0f; + bool update_luminosity_calc_result = false; + + while ( ctx->iter < MAX_ITER ) + { + ObtainMutex(ctx->m1_data_mutex); + if ( TEST_IF_DATA_AVAILABLE_IS_NOT_EMPTY(ctx->value_in_watts_flag_counter) && + (update_luminosity_calc_result == false) ) + { + update_luminosity_calc_result = true; + + //Apply Blackman-Harris Window + for (uint32_t i = 0; i < FFT_SIZE; i++) + { + inSensorDataRe[i] = inSensorDataRe[i]*blackman_harris(i, FFT_SIZE)/ctx->scaling_fft_factor; + inSensorDataIm[i] = inSensorDataIm[i]*blackman_harris(i, FFT_SIZE)/ctx->scaling_fft_factor; + } + //Calculates FFT + fft(&inSensorDataRe[0], &inSensorDataIm[0], FFT_SIZE_LOG2); + + //Calculates the magnitude^2 values + for (uint32_t i = 0; i < FFT_SIZE; i++) + { + inSensorDataRe[i] = (inSensorDataRe[i] * inSensorDataRe[i] + + inSensorDataIm[i] * inSensorDataIm[i]) / ((float)FFT_SIZE); + } + + //Look for the peak Value and its index (no DC) + float maxValue = 0.0; + int32_t maxValueIndex = -1; + for (uint32_t i = 3; i < (FFT_SIZE / 2); i++) + { + if (inSensorDataRe[i] > maxValue) + { + maxValue = inSensorDataRe[i]; + maxValueIndex = i; + } + } + + //Calculates the signal and noise power (no DC) + sig = 0.0f; + noise = 0.0f; + for (uint32_t i = 3; i < (FFT_SIZE / 2); i++) + { + if ((i > maxValueIndex - 8) && (i < maxValueIndex + 8)) + { + sig += (2 * inSensorDataRe[i]); + } + else + { + noise += (2 * inSensorDataRe[i]); + } + } + ctx->debug_maxValueIndex = maxValueIndex; + ctx->debug_maxValue = maxValue; + ctx->debig_noise = noise; + ctx->debug_sig = sig; + } + + ReleaseMutex(ctx->m1_data_mutex); + + if (!(sig > 0.0f)) { sig = 0.0000000001f; } + if (!(noise > 0.0f)) { noise = 0.0000000001f; } + + if (update_luminosity_calc_result) + { + ObtainMutex(ctx->m2_result_mutex); + if ( TEST_IF_DATA_AVAILABLE_IS_EMPTY(ctx->luminosity_flag_counter) ) + { + update_luminosity_calc_result = false; + + //Calculates SNR + ctx->snr_float = sig/noise; + DECREMENT_AVAILABLE_DATA(ctx->value_in_watts_flag_counter); + INCREMENT_AVAILABLE_DATA(ctx->luminosity_flag_counter); + } + ReleaseMutex(ctx->m2_result_mutex); + } + rtems_task_wake_after(1); + } + SuspendSelf(); +} + +// * Task 2 - reads the results +static void read_and_output(rtems_task_argument arg) +{ + test_context *ctx = (test_context *)arg; + float result; + + // Luminosity threshold to indicate planet, not e.g. star + float luminosity_threshold = 0.005; + + while (ctx->iter < MAX_ITER) + { + ObtainMutex(ctx->m2_result_mutex); + if (TEST_IF_DATA_AVAILABLE_IS_NOT_EMPTY(ctx->luminosity_flag_counter)) + { + if (ctx->snr_float > SNR_THRESHOLD) + { + ctx->planet_locations[ctx->iter] = 1; + ctx->planet_count++; + } + else + { + ctx->planet_locations[ctx->iter] = 0; + } + DECREMENT_AVAILABLE_DATA(ctx->luminosity_flag_counter); + ctx->iter++; + } + ReleaseMutex(ctx->m2_result_mutex); + rtems_task_wake_after(1); + } + rtems_event_send(ctx->main_task_id, EVENT_WROTE_DATA); + SuspendSelf(); +} + +static void Init(rtems_task_argument arg) +{ + (void)arg; + test_context ctx; + + char str[ITOA_STR_SIZE]; + uint32_t start_time, end_time, multi_core_elapsed_time; + + (void) memset(&ctx, 0, sizeof(test_context)); + (void) memset(&inSensorDataRe[0], 0, FFT_SIZE); + (void) memset(&inSensorDataIm[0], 0, FFT_SIZE); + + // Identify main task for communication between tasks + ctx.main_task_id = rtems_task_self(); + SetSelfPriority( PRIO_NORMAL ); + + //Calculates mean of Blackman-Harris terms + ctx.scaling_fft_factor = 0.0; + for (uint32_t i = 0; i<FFT_SIZE; i++) + { + ctx.scaling_fft_factor += blackman_harris( i, FFT_SIZE); + } + ctx.scaling_fft_factor = ctx.scaling_fft_factor/ ((float) FFT_SIZE); + + // Create the binary semaphores and intialize variables + ctx.m1_data_mutex = CreateMutex(rtems_build_name('M', '1', 'M', 'X')); + ctx.m2_result_mutex = CreateMutex(rtems_build_name('M', '2', 'M', 'X')); + + ctx.planet_count = 0; + memset(&ctx.planet_locations, 0, MAX_ITER); + + rtems_task_config calc_task_config = { + .initial_priority = PRIO_NORMAL, + .storage_size = TASK_STORAGE_SIZE, + .maximum_thread_local_storage_size = + MAX_TLS_SIZE, + .initial_modes = RTEMS_DEFAULT_MODES, + .attributes = TASK_ATTRIBUTES}; + + // Setup task for reading data from the sensor + calc_task_config.name = rtems_build_name('R', 'E', 'A', 'D'); + calc_task_config.storage_area = &calc_task_storage[0][0]; + + ctx.read_task_id = DoCreateTask(calc_task_config); + + // Setup task for reading from shared memory location + // And calculating the new result in lumens + calc_task_config.name = rtems_build_name('C', 'A', 'L', 'C'); + calc_task_config.storage_area = &calc_task_storage[1][0]; + + ctx.calc_task_id = DoCreateTask(calc_task_config); + + // Setup task for outputting from shared memory location + calc_task_config.name = rtems_build_name('O', 'U', 'T', 'P'); + calc_task_config.storage_area = &calc_task_storage[2][0]; + + ctx.write_task_id = DoCreateTask(calc_task_config); + + // Start all tasks + StartTask(ctx.read_task_id, task_snr_read_sensor_data, &ctx); + StartTask(ctx.calc_task_id, task_snr_process_data, &ctx); + StartTask(ctx.write_task_id, read_and_output, &ctx); + + start_time = rtems_clock_get_ticks_since_boot(); + + // Wait for all tasks to be completed + ReceiveAllEvents(EVENT_WROTE_DATA); + + end_time = rtems_clock_get_ticks_since_boot(); + + // Output the results + print_string("Planet count: "); + print_string(itoa(ctx.planet_count, &str[0], 10)); + print_string("\n"); + print_string("Planets sensed at sensor positions: "); + for (uint8_t i=0; i<MAX_ITER; i++) + { + if (ctx.planet_locations[i] > 0) + { + print_string(itoa(i, &str[0], 10)); + print_string(" "); + } + } + + multi_core_elapsed_time = end_time - start_time; + print_string("\n"); + print_string("Multicore Elapsed Time - "); + print_string(itoa(multi_core_elapsed_time, &str[0], 10)); + print_string("\n"); + + rtems_task_delete(ctx.read_task_id); + rtems_task_delete(ctx.calc_task_id); + rtems_task_delete(ctx.write_task_id); + + rtems_fatal(RTEMS_FATAL_SOURCE_EXIT, 0); +} + + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER + +#define CONFIGURE_MAXIMUM_PROCESSORS TEST_PROCESSORS + +#define CONFIGURE_MAXIMUM_SEMAPHORES 2 + +#define CONFIGURE_MAXIMUM_TASKS ( TASK_COUNT + 1 ) + +#define CONFIGURE_SCHEDULER_EDF_SMP + +#define CONFIGURE_MINIMUM_TASK_STACK_SIZE \ + RTEMS_MINIMUM_STACK_SIZE + CPU_STACK_ALIGNMENT + +#define CONFIGURE_EXTRA_TASK_STACKS RTEMS_MINIMUM_STACK_SIZE + +#define CONFIGURE_INIT_TASK_CONSTRUCT_STORAGE_SIZE 2 * TASK_STORAGE_SIZE + +#define CONFIGURE_MINIMUM_TASKS_WITH_USER_PROVIDED_STORAGE \ + CONFIGURE_MAXIMUM_TASKS + +#define CONFIGURE_MICROSECONDS_PER_TICK 1000 + +#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 0 + +#define CONFIGURE_DISABLE_NEWLIB_REENTRANCY + +#define CONFIGURE_APPLICATION_DISABLE_FILESYSTEM + +#define CONFIGURE_MAXIMUM_THREAD_LOCAL_STORAGE_SIZE MAX_TLS_SIZE + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT_TASK_ATTRIBUTES (RTEMS_SYSTEM_TASK | TASK_ATTRIBUTES) + +#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES + +#define CONFIGURE_INIT + +#include <rtems/confdefs.h> diff --git a/testsuites/isvv/01_basic_smp_multi/basic_smp_multi.c b/testsuites/isvv/01_basic_smp_multi/basic_smp_multi.c new file mode 100644 index 0000000000..6d3c8e938f --- /dev/null +++ b/testsuites/isvv/01_basic_smp_multi/basic_smp_multi.c @@ -0,0 +1,206 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 2022 Critical Software SA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <rtems/bspIo.h> +#include "../shared/utils.h" +#include "../shared/isvv_rtems_aux.h" + +/** + * + * @brief Tests basic symmetric multiprocessing capabilities on multiple cores + * + * This test case performs the calculation of the Mandelbrot set on 4 cores + */ + +#define MAX_TLS_SIZE RTEMS_ALIGN_UP(64, RTEMS_TASK_STORAGE_ALIGNMENT) + +#define TASK_ATTRIBUTES RTEMS_FLOATING_POINT + +#define TASK_STORAGE_SIZE \ + RTEMS_TASK_STORAGE_SIZE( \ + MAX_TLS_SIZE + RTEMS_MINIMUM_STACK_SIZE, \ + TASK_ATTRIBUTES) +#define ITOA_STR_SIZE (8 * sizeof(int) + 1) + +// test specific global vars +#define TASK_COUNT TEST_PROCESSORS + +static rtems_id start_barrier; +static rtems_id TASK_COUNTER_SEMAPHORE; + +typedef struct +{ + rtems_id task_id[TASK_COUNT]; + uint32_t processor[TASK_COUNT]; + uint8_t tile[TASK_COUNT]; +} test_context; + +test_context ctx; + +/* create storage areas for each worker, using task construct forces +the user to create these manually*/ +RTEMS_ALIGNED(RTEMS_TASK_STORAGE_ALIGNMENT) +static char calc_task_storage[TASK_COUNT][TASK_STORAGE_SIZE]; + +static void calc_task_function(rtems_task_argument tile) +{ + uint8_t tile_n = (uint8_t)tile; + + /* Store tile and processor task is working on */ + ctx.processor[tile-1] = rtems_scheduler_get_processor(); + ctx.tile[tile-1] = tile_n; + + // for some reason this loop is needed for the scheduler to distribute tasks to all the cores + Loop(4); + + WaitAtBarrier(start_barrier); + + mandelbrot_tile(tile_n, TASK_COUNT); + + // Task has finished so increment counter + ReleaseCounterSemaphore(TASK_COUNTER_SEMAPHORE); + // Internal call necessary to free resources for next task processing + SuspendSelf(); +} + +static void Init(rtems_task_argument arg) +{ + (void)arg; + uint32_t start_time, end_time, elapsed_time; + char ch; + char str[ITOA_STR_SIZE]; + uint8_t wait = 0; + + TASK_COUNTER_SEMAPHORE = CreateCounterSemaphore(rtems_build_name('T', 'C', 'S', '0'), 0); + + rtems_task_config calc_task_config = { + .name = rtems_build_name('R', 'U', 'N', ' '), + .initial_priority = 3, + .storage_size = TASK_STORAGE_SIZE, + .maximum_thread_local_storage_size = MAX_TLS_SIZE, + .initial_modes = RTEMS_DEFAULT_MODES, + .attributes = TASK_ATTRIBUTES}; + + start_barrier = CreateAutomaticBarrier(TASK_COUNT); + + // Set Init to have a lower priority than the asynchronous tasks for core distribution + SetTaskPriority(RTEMS_SELF, 4); + + for (uint32_t i = 0; i < TASK_COUNT; i++) + { + ch = '0' + i; + + calc_task_config.name = rtems_build_name('R', 'U', 'N', ch); + calc_task_config.storage_area = &calc_task_storage[i][0]; + + ctx.task_id[i] = DoCreateTask(calc_task_config); + StartTask(ctx.task_id[i], calc_task_function, (void *)(i + 1)); + } + + start_time = rtems_clock_get_ticks_since_boot(); + + // Wait for all tasks to complete + while (wait < TASK_COUNT) + { + ObtainCounterSemaphore(TASK_COUNTER_SEMAPHORE); + wait++; + } + + end_time = rtems_clock_get_ticks_since_boot(); + + elapsed_time = end_time - start_time; + + for (uint32_t i = 0; i < TASK_COUNT; i++) + { + /* Identify tile and processor task worked on */ + print_string("Processor-"); + print_string(itoa(ctx.processor[i], &str[0], 10)); + print_string(",Tile-"); + print_string(itoa(ctx.tile[i], &str[0], 10)); + print_string("\n"); + } + + print_string("\n"); + print_string("Multicore Elapsed Time -"); + print_string(itoa(elapsed_time, &str[0], 10)); + print_string("\n"); + print_test_results(); + + for (uint32_t i = 0; i < TASK_COUNT; i++) + { + DeleteTask(ctx.task_id[i]); + } + + DeleteMutex(TASK_COUNTER_SEMAPHORE); + rtems_fatal(RTEMS_FATAL_SOURCE_EXIT, 0); +} + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER + +#define CONFIGURE_MAXIMUM_PROCESSORS TEST_PROCESSORS + +#define CONFIGURE_MAXIMUM_SEMAPHORES 1 + +#define CONFIGURE_MAXIMUM_BARRIERS 1 + +#define CONFIGURE_MAXIMUM_TASKS ( TEST_PROCESSORS + 1 ) + +#define CONFIGURE_SCHEDULER_EDF_SMP + +#define CONFIGURE_MINIMUM_TASK_STACK_SIZE RTEMS_MINIMUM_STACK_SIZE + CPU_STACK_ALIGNMENT + +#define CONFIGURE_EXTRA_TASK_STACKS RTEMS_MINIMUM_STACK_SIZE + +#define CONFIGURE_INIT_TASK_CONSTRUCT_STORAGE_SIZE 2 * TASK_STORAGE_SIZE + +#define CONFIGURE_MINIMUM_TASKS_WITH_USER_PROVIDED_STORAGE \ + CONFIGURE_MAXIMUM_TASKS + +#define CONFIGURE_MICROSECONDS_PER_TICK 1000 + +#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 0 + +#define CONFIGURE_DISABLE_NEWLIB_REENTRANCY + +#define CONFIGURE_APPLICATION_DISABLE_FILESYSTEM + +#define CONFIGURE_MAXIMUM_THREAD_LOCAL_STORAGE_SIZE MAX_TLS_SIZE + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT_TASK_ATTRIBUTES (RTEMS_SYSTEM_TASK | TASK_ATTRIBUTES) + +#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES + +#define CONFIGURE_INIT + +#include <rtems/confdefs.h> diff --git a/testsuites/isvv/02_core_affinity_multi/core_affinity_multi.c b/testsuites/isvv/02_core_affinity_multi/core_affinity_multi.c new file mode 100644 index 0000000000..112d846443 --- /dev/null +++ b/testsuites/isvv/02_core_affinity_multi/core_affinity_multi.c @@ -0,0 +1,211 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 2022 Critical Software SA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <rtems/bspIo.h> +#include "../shared/utils.h" +#include "../shared/isvv_rtems_aux.h" + +/** + * + * @brief Demonstrate that tasks running in parallel will not execute on separate cores of the + * processor if the processor affinity is set to the same core for all tasks. + * + * This test case performs the calculation of the Mandelbrot set on 4 max cores, pinning to 0th core + */ + +#define MAX_TLS_SIZE RTEMS_ALIGN_UP(64, RTEMS_TASK_STORAGE_ALIGNMENT) + +#define TASK_ATTRIBUTES RTEMS_FLOATING_POINT + +#define TASK_STORAGE_SIZE \ + RTEMS_TASK_STORAGE_SIZE( \ + MAX_TLS_SIZE + RTEMS_MINIMUM_STACK_SIZE, \ + TASK_ATTRIBUTES) + +#define ITOA_STR_SIZE (8 * sizeof(int) + 1) + +// test specific global vars +#define TASK_COUNT TEST_PROCESSORS + +static rtems_id start_barrier; +static rtems_id TASK_COUNTER_SEMAPHORE; + +typedef struct +{ + rtems_id task_id[TASK_COUNT]; + uint32_t processor[TASK_COUNT]; + uint8_t tile[TASK_COUNT]; +} test_context; + +test_context ctx; + +/* create storage areas for each worker, using task construct forces +the user to create these manually*/ +RTEMS_ALIGNED(RTEMS_TASK_STORAGE_ALIGNMENT) +static char calc_task_storage[TASK_COUNT][TASK_STORAGE_SIZE]; + +static void calc_task_function(rtems_task_argument tile) +{ + uint8_t tile_n = (uint8_t)tile; + + /* Store tile and processor task is working on */ + ctx.processor[tile-1] = rtems_scheduler_get_processor(); + ctx.tile[tile-1] = tile_n; + + // for some reason this loop is needed for the scheduler to distribute tasks to all the cores + Loop(4); + + WaitAtBarrier(start_barrier); + + mandelbrot_tile(tile_n, TASK_COUNT); + + // Task has finished so increment counter + ReleaseCounterSemaphore(TASK_COUNTER_SEMAPHORE); + // Internal call necessary to free resources for next task processing + SuspendSelf(); +} + +static void Init(rtems_task_argument arg) +{ + (void)arg; + uint32_t start_time, end_time, elapsed_time; + char ch; + char str[ITOA_STR_SIZE]; + cpu_set_t cpuset; + uint8_t wait = 0; + + TASK_COUNTER_SEMAPHORE = CreateCounterSemaphore(rtems_build_name('T', 'C', 'S', '0'), 0); + + rtems_task_config calc_task_config = { + .name = rtems_build_name('R', 'U', 'N', ' '), + .initial_priority = 3, + .storage_size = TASK_STORAGE_SIZE, + .maximum_thread_local_storage_size = MAX_TLS_SIZE, + .initial_modes = RTEMS_DEFAULT_MODES, + .attributes = TASK_ATTRIBUTES}; + + start_barrier = CreateAutomaticBarrier(TASK_COUNT); + + for (uint32_t i = 0; i < TASK_COUNT; i++) + { + ch = '0' + i; + + calc_task_config.name = rtems_build_name('R', 'U', 'N', ch); + calc_task_config.storage_area = &calc_task_storage[i][0]; + + ctx.task_id[i] = DoCreateTask(calc_task_config); + + CPU_ZERO(&cpuset); + CPU_SET(0, &cpuset); + rtems_task_set_affinity(ctx.task_id[i], sizeof(cpuset), &cpuset); + + StartTask(ctx.task_id[i], calc_task_function, (void *)(i + 1)); + } + + start_time = rtems_clock_get_ticks_since_boot(); + + // Wait for all tasks to complete + while (wait < TASK_COUNT) + { + ObtainCounterSemaphore(TASK_COUNTER_SEMAPHORE); + wait++; + } + + end_time = rtems_clock_get_ticks_since_boot(); + + elapsed_time = end_time - start_time; + + for (uint32_t i = 0; i < TASK_COUNT; i++) + { + /* Identify tile and processor task worked on */ + print_string("Processor-"); + print_string(itoa(ctx.processor[i], &str[0], 10)); + print_string(",Tile-"); + print_string(itoa(ctx.tile[i], &str[0], 10)); + print_string("\n"); + } + + print_string("\n"); + print_string("Multicore Elapsed Time -"); + print_string(itoa(elapsed_time, &str[0], 10)); + print_string("\n"); + print_test_results(); + + for (uint32_t i = 0; i < TASK_COUNT; i++) + { + DeleteTask(ctx.task_id[i]); + } + + DeleteMutex(TASK_COUNTER_SEMAPHORE); + rtems_fatal(RTEMS_FATAL_SOURCE_EXIT, 0); +} + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER + +#define CONFIGURE_MAXIMUM_PROCESSORS TEST_PROCESSORS + +#define CONFIGURE_MAXIMUM_SEMAPHORES 1 + +#define CONFIGURE_MAXIMUM_BARRIERS 1 + +#define CONFIGURE_MAXIMUM_TASKS ( TEST_PROCESSORS + 1 ) + +#define CONFIGURE_SCHEDULER_EDF_SMP + +#define CONFIGURE_MINIMUM_TASK_STACK_SIZE RTEMS_MINIMUM_STACK_SIZE + CPU_STACK_ALIGNMENT + +#define CONFIGURE_EXTRA_TASK_STACKS RTEMS_MINIMUM_STACK_SIZE + +#define CONFIGURE_INIT_TASK_CONSTRUCT_STORAGE_SIZE 2 * TASK_STORAGE_SIZE + +#define CONFIGURE_MINIMUM_TASKS_WITH_USER_PROVIDED_STORAGE \ + CONFIGURE_MAXIMUM_TASKS + +#define CONFIGURE_MICROSECONDS_PER_TICK 1000 + +#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 0 + +#define CONFIGURE_DISABLE_NEWLIB_REENTRANCY + +#define CONFIGURE_APPLICATION_DISABLE_FILESYSTEM + +#define CONFIGURE_MAXIMUM_THREAD_LOCAL_STORAGE_SIZE MAX_TLS_SIZE + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT_TASK_ATTRIBUTES (RTEMS_SYSTEM_TASK | TASK_ATTRIBUTES) + +#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES + +#define CONFIGURE_INIT + +#include <rtems/confdefs.h> diff --git a/testsuites/isvv/03_semaphores_multi/semaphores_multi.c b/testsuites/isvv/03_semaphores_multi/semaphores_multi.c new file mode 100644 index 0000000000..b46fce2358 --- /dev/null +++ b/testsuites/isvv/03_semaphores_multi/semaphores_multi.c @@ -0,0 +1,244 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 2022 Critical Software SA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <rtems/bspIo.h> +#include "../shared/utils.h" +#include "../shared/isvv_rtems_aux.h" + +/** + * + * @brief Demonstrate the use of semaphores to protect access to objects. + * + * For the multi-core calculation, the Mandelbrot set is divided into tiles which are distributed + * between the calculation tasks; when a task completes a tile it starts on the next available tile. + * There is one task for each core. + * + * A binary semaphore is used to protect the variable containing the next tile information against + * simultaneous modification by multiple tasks. + */ + +#define MAX_TLS_SIZE RTEMS_ALIGN_UP(64, RTEMS_TASK_STORAGE_ALIGNMENT) + +#define TASK_ATTRIBUTES RTEMS_FLOATING_POINT + +#define TASK_STORAGE_SIZE \ + RTEMS_TASK_STORAGE_SIZE( \ + MAX_TLS_SIZE + RTEMS_MINIMUM_STACK_SIZE, \ + TASK_ATTRIBUTES) + +#define ITOA_STR_SIZE (8 * sizeof(int) + 1) + +// test specific global vars +#define TASK_COUNT TEST_PROCESSORS + +rtems_event_set event_send[4] = {RTEMS_EVENT_1, + RTEMS_EVENT_2, + RTEMS_EVENT_3, + RTEMS_EVENT_4 + }; + +uint8_t count_process[64]; + +typedef struct { + rtems_id mutex_id; + rtems_id main_task; + uint8_t ntiles; + uint8_t next_tile; + rtems_id task_id[TASK_COUNT]; +} test_context; + +typedef test_context Context; + +RTEMS_ALIGNED(RTEMS_TASK_STORAGE_ALIGNMENT) +static char calc_task_storage[TASK_COUNT][TASK_STORAGE_SIZE]; + +static void calc_task_function(rtems_task_argument arg) { + Context *ctx; + + ctx = (Context *)arg; + + uint8_t tile; + rtems_id local_id = TaskSelfId(); + uint8_t task_idx = 255; + + for (int i = 0; i < TASK_COUNT; i++) { + if (ctx->task_id[i] == local_id) { + task_idx = i; + break; + } + } + + ObtainMutex(ctx->mutex_id); + tile = ctx->next_tile; + ctx->next_tile++; + ReleaseMutex(ctx->mutex_id); + + while (tile <= ctx->ntiles) { + count_process[tile-1]++; + mandelbrot_tile(tile, ctx->ntiles); + + ObtainMutex(ctx->mutex_id); + tile = ctx->next_tile; + ctx->next_tile++; + ReleaseMutex(ctx->mutex_id); + } + + SendEvents(ctx->main_task, event_send[task_idx]); + SuspendSelf(); +} + +static void Init(rtems_task_argument arg) { + (void)arg; + test_context ctx; + uint32_t start_time, end_time, elapsed_time; + char ch; + char str[ITOA_STR_SIZE]; + rtems_event_set received = 0; + rtems_event_set total_events = 0; + bool correctly_processed = true; + + ctx.main_task = rtems_task_self(); + ctx.mutex_id = CreateMutex(rtems_build_name('S', 'E', 'M', '1')); + ctx.ntiles = 64; + ctx.next_tile = 1; + + for (uint8_t i = 0; i < ctx.ntiles; i++) { + count_process[i] = 0; + } + + start_time = rtems_clock_get_ticks_since_boot(); + rtems_task_config calc_task_config = { + .initial_priority = PRIO_VERY_HIGH, + .storage_size = TASK_STORAGE_SIZE, + .maximum_thread_local_storage_size = + MAX_TLS_SIZE, + .initial_modes = RTEMS_DEFAULT_MODES, + .attributes = TASK_ATTRIBUTES + }; + + ObtainMutex(ctx.mutex_id); + + for (uint32_t i = 0; i < TASK_COUNT; i++) { + ch = '0' + i; + + calc_task_config.name = rtems_build_name('R', 'U', 'N', ch); + calc_task_config.storage_area = &calc_task_storage[i][0]; + + ctx.task_id[i] = DoCreateTask(calc_task_config); + StartTask(ctx.task_id[i], calc_task_function, &ctx); + total_events += event_send[i]; + } + ReleaseMutex(ctx.mutex_id); + + while (received != total_events) + { + received |= ReceiveAllEvents(total_events); + } + + end_time = rtems_clock_get_ticks_since_boot(); + + elapsed_time = end_time - start_time; + + print_string("\n"); + print_string("Multicore Elapsed Time -"); + print_string(itoa(elapsed_time, &str[0], 10)); + print_string("\n"); + + for (uint8_t i = 0; i < ctx.ntiles; i++) + { + if (count_process[i] != 1) + { + correctly_processed = false; + break; + } + } + + if (correctly_processed) + { + print_string("Each tile only processed once: true\n"); + } + else + { + print_string("Each tile only processed once: false\n"); + } + + print_test_results(); + + for (uint32_t i = 0; i < TASK_COUNT; i++) + { + DeleteTask(ctx.task_id[i]); + } + + rtems_fatal(RTEMS_FATAL_SOURCE_EXIT, 0); +} + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER + +#define CONFIGURE_MAXIMUM_PROCESSORS 4 + +#define CONFIGURE_MAXIMUM_SEMAPHORES 1 + +#define CONFIGURE_MAXIMUM_BARRIERS 1 + +#define CONFIGURE_MAXIMUM_TASKS (TEST_PROCESSORS + 1) + +#define CONFIGURE_SCHEDULER_EDF_SMP + +#define CONFIGURE_MINIMUM_TASK_STACK_SIZE \ + RTEMS_MINIMUM_STACK_SIZE + CPU_STACK_ALIGNMENT + +#define CONFIGURE_EXTRA_TASK_STACKS RTEMS_MINIMUM_STACK_SIZE + +#define CONFIGURE_INIT_TASK_CONSTRUCT_STORAGE_SIZE 2 * TASK_STORAGE_SIZE + +#define CONFIGURE_MINIMUM_TASKS_WITH_USER_PROVIDED_STORAGE \ + CONFIGURE_MAXIMUM_TASKS + +#define CONFIGURE_MICROSECONDS_PER_TICK 1000 + +#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 0 + +#define CONFIGURE_DISABLE_NEWLIB_REENTRANCY + +#define CONFIGURE_APPLICATION_DISABLE_FILESYSTEM + +#define CONFIGURE_MAXIMUM_THREAD_LOCAL_STORAGE_SIZE MAX_TLS_SIZE + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT_TASK_ATTRIBUTES (RTEMS_SYSTEM_TASK | TASK_ATTRIBUTES) + +#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES + +#define CONFIGURE_INIT + +#include <rtems/confdefs.h> diff --git a/testsuites/isvv/04_messages_multi/messages_multi.c b/testsuites/isvv/04_messages_multi/messages_multi.c new file mode 100644 index 0000000000..b63733ed6c --- /dev/null +++ b/testsuites/isvv/04_messages_multi/messages_multi.c @@ -0,0 +1,273 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 2022 Critical Software SA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stddef.h> +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <rtems/bspIo.h> +#include "../shared/utils.h" +#include "../shared/isvv_rtems_aux.h" + +/** + * + * @brief Demonstrate the use of messages between different tasks. + * + * The Mandelbrot calculation of the Mandelbrot set is divided into tiles which are distributed + * between the calculation tasks; when a task completes a tile, it sends a message to get the + * next tile to be calculated. + */ + +#define MAX_TLS_SIZE RTEMS_ALIGN_UP(64, RTEMS_TASK_STORAGE_ALIGNMENT) + +#define TASK_ATTRIBUTES RTEMS_FLOATING_POINT + +#define TASK_STORAGE_SIZE \ + RTEMS_TASK_STORAGE_SIZE( \ + MAX_TLS_SIZE + RTEMS_MINIMUM_STACK_SIZE, \ + TASK_ATTRIBUTES) + +#define ITOA_STR_SIZE (8 * sizeof(int) + 1) + +// test specific global vars +#define TASK_COUNT TEST_PROCESSORS +#define TOTAL_TILES 64 + +#define MAX_MESSAGE_QUEUES 5 +#define MAX_MESSAGE_SIZE sizeof(uint8_t) +#define MAX_PENDING_MESSAGES 10 // TASK_COUNT + +rtems_event_set event_send[4] = {RTEMS_EVENT_1, + RTEMS_EVENT_2, + RTEMS_EVENT_3, + RTEMS_EVENT_4}; + +uint8_t count_process[TOTAL_TILES] = {0}; + +typedef struct +{ + rtems_id main_task; + uint8_t ntiles; + uint8_t next_tile; + rtems_id task_id[TASK_COUNT]; + rtems_id tile_queue; + rtems_id message_queue[TASK_COUNT]; +} test_context; + +typedef test_context Context; + +RTEMS_ALIGNED(RTEMS_TASK_STORAGE_ALIGNMENT) +static char calc_task_storage[TASK_COUNT][TASK_STORAGE_SIZE]; + +RTEMS_MESSAGE_QUEUE_BUFFER(MAX_MESSAGE_SIZE) +msg_tile_queue_storage[MAX_PENDING_MESSAGES]; + +RTEMS_MESSAGE_QUEUE_BUFFER(MAX_MESSAGE_SIZE) +msg_task_queue_storage[TASK_COUNT][MAX_PENDING_MESSAGES]; + +static void calc_task_function(rtems_task_argument arg) +{ + Context *ctx; + + ctx = (Context *)arg; + + uint8_t tile; + rtems_id local_id = TaskSelfId(); + uint8_t task_idx = 255; + + for (int i = 0; i < TASK_COUNT; i++) + { + if (ctx->task_id[i] == local_id) + { + task_idx = i; + break; + } + } + + char ch = '0' + task_idx; + + rtems_message_queue_config msg_config = { + .name = rtems_build_name('M', 'S', 'G', ch), + .maximum_pending_messages = MAX_PENDING_MESSAGES, + .maximum_message_size = MAX_MESSAGE_SIZE, + .storage_size = sizeof(msg_task_queue_storage[task_idx]), + .storage_area = &msg_task_queue_storage[task_idx], + .attributes = RTEMS_FIFO | RTEMS_GLOBAL}; + ctx->message_queue[task_idx] = CreateMessageQueue(msg_config); + + SendMessage(ctx->tile_queue, &task_idx, sizeof(task_idx)); + ReceiveMessage(ctx->message_queue[task_idx], &tile); + + while (tile <= ctx->ntiles) + { + count_process[tile - 1]++; + mandelbrot_tile(tile, ctx->ntiles); + + SendMessage(ctx->tile_queue, &task_idx, sizeof(task_idx)); + ReceiveMessage(ctx->message_queue[task_idx], &tile); + } + + SendMessage(ctx->tile_queue, &task_idx, sizeof(task_idx)); + SendEvents(ctx->main_task, event_send[task_idx]); + SuspendSelf(); +} + +static void Init(rtems_task_argument arg) +{ + (void)arg; + test_context ctx; + uint32_t start_time, end_time, elapsed_time; + char ch; + char str[ITOA_STR_SIZE]; + int total_events = 0; + uint8_t task = 255; + bool correctly_processed = true; + + rtems_message_queue_config msg_config = { + .name = rtems_build_name('M', 'S', 'G', 'T'), + .maximum_pending_messages = RTEMS_ARRAY_SIZE(msg_tile_queue_storage), + .maximum_message_size = MAX_MESSAGE_SIZE, + .storage_size = sizeof(msg_tile_queue_storage), + .storage_area = &msg_tile_queue_storage, + .attributes = RTEMS_FIFO | RTEMS_GLOBAL}; + + ctx.main_task = rtems_task_self(); + ctx.tile_queue = CreateMessageQueue(msg_config); + ctx.ntiles = TOTAL_TILES; + ctx.next_tile = 1; + + start_time = rtems_clock_get_ticks_since_boot(); + rtems_task_config calc_task_config = { + .initial_priority = PRIO_NORMAL, + .storage_size = TASK_STORAGE_SIZE, + .maximum_thread_local_storage_size = + MAX_TLS_SIZE, + .initial_modes = RTEMS_DEFAULT_MODES, + .attributes = TASK_ATTRIBUTES}; + + for (uint32_t i = 0; i < TASK_COUNT; i++) + { + ch = '0' + i; + calc_task_config.name = rtems_build_name('R', 'U', 'N', ch); + calc_task_config.storage_area = &calc_task_storage[i][0]; + + ctx.task_id[i] = DoCreateTask(calc_task_config); + StartTask(ctx.task_id[i], calc_task_function, &ctx); + total_events += event_send[i]; + } + + while (ReceiveAvailableEvents() != total_events) + { + ReceiveMessage(ctx.tile_queue, &task); + SendMessage(ctx.message_queue[task], &ctx.next_tile, sizeof(ctx.next_tile)); + + ctx.next_tile++; + } + + print_string("printing results\n"); + end_time = rtems_clock_get_ticks_since_boot(); + + elapsed_time = end_time - start_time; + + print_string("\n"); + print_string("Multicore Elapsed Time -"); + print_string(itoa(elapsed_time, &str[0], 10)); + print_string("\n"); + + for (uint8_t i = 0; i < ctx.ntiles; i++) + { + if (count_process[i] != 1) + { + correctly_processed = false; + break; + } + } + + print_test_results(); + + if (correctly_processed) + { + print_string("Each tile only processed once: true\n"); + } + else + { + print_string("Each tile only processed once: false\n"); + } + + for (uint32_t i = 0; i < TASK_COUNT; i++) + { + DeleteTask(ctx.task_id[i]); + DeleteMessageQueue(ctx.message_queue[i]); + } + DeleteMessageQueue(ctx.tile_queue); + + rtems_fatal(RTEMS_FATAL_SOURCE_EXIT, 0); +} + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER + +#define CONFIGURE_MAXIMUM_PROCESSORS TEST_PROCESSORS + +#define CONFIGURE_MAXIMUM_MESSAGE_QUEUES MAX_MESSAGE_QUEUES + +#define CONFIGURE_MAXIMUM_SEMAPHORES 1 + +#define CONFIGURE_MAXIMUM_TASKS ( TEST_PROCESSORS + 1 ) + +#define CONFIGURE_SCHEDULER_EDF_SMP + +#define CONFIGURE_MINIMUM_TASK_STACK_SIZE \ + RTEMS_MINIMUM_STACK_SIZE + CPU_STACK_ALIGNMENT + +#define CONFIGURE_EXTRA_TASK_STACKS RTEMS_MINIMUM_STACK_SIZE + +#define CONFIGURE_INIT_TASK_CONSTRUCT_STORAGE_SIZE 2 * TASK_STORAGE_SIZE + +#define CONFIGURE_MINIMUM_TASKS_WITH_USER_PROVIDED_STORAGE \ + CONFIGURE_MAXIMUM_TASKS + +#define CONFIGURE_MICROSECONDS_PER_TICK 1000 + +#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 0 + +#define CONFIGURE_DISABLE_NEWLIB_REENTRANCY + +#define CONFIGURE_APPLICATION_DISABLE_FILESYSTEM + +#define CONFIGURE_MAXIMUM_THREAD_LOCAL_STORAGE_SIZE MAX_TLS_SIZE + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT_TASK_ATTRIBUTES (RTEMS_SYSTEM_TASK | TASK_ATTRIBUTES) + +#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES + +#define CONFIGURE_INIT + +#include <rtems/confdefs.h> diff --git a/testsuites/isvv/05_priorities_multi/priorities_multi.c b/testsuites/isvv/05_priorities_multi/priorities_multi.c new file mode 100644 index 0000000000..1b6a8fef60 --- /dev/null +++ b/testsuites/isvv/05_priorities_multi/priorities_multi.c @@ -0,0 +1,283 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 2022 Critical Software SA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stddef.h> +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <rtems/bspIo.h> +#include "../shared/isvv_rtems_aux.h" +#include "../shared/utils.h" + +/** + * + * @brief Demonstrate the use of messages between different tasks with tasks running at + * different priorities. + * + * The Mandelbrot set is divided into tiles which are distributed between the calculation tasks. + * When a task completes a tile it sends a message to get the next tile to be calculated. + * A separate task receives a request for the next tile to be calculated and sends that information + * to the requesting task by means of another message. Two calculation tasks are started for each + * core and the calculation tasks are running at a higher priority than the tile allocation task. + * This ensures that there are always tasks waiting to receive a tile allocation. It is checked + * that the result of the parallel calculation is the same as when generated on a single-core and + * that the multi-core calculation is faster than the single-core calculation. + */ + +#define MAX_TLS_SIZE RTEMS_ALIGN_UP(64, RTEMS_TASK_STORAGE_ALIGNMENT) + +#define TASK_ATTRIBUTES RTEMS_FLOATING_POINT + +#define TASK_STORAGE_SIZE \ + RTEMS_TASK_STORAGE_SIZE(MAX_TLS_SIZE + RTEMS_MINIMUM_STACK_SIZE, \ + TASK_ATTRIBUTES) + +#define ITOA_STR_SIZE (8 * sizeof(int) + 1) + +// test specific global vars +#define TASK_COUNT (TEST_PROCESSORS * 2) +#define TOTAL_TILES 64 + +#define MAX_MESSAGE_QUEUES (TASK_COUNT + 1) +#define MAX_MESSAGE_SIZE sizeof(uint8_t) +#define MAX_PENDING_MESSAGES TASK_COUNT + +rtems_event_set event_send[8] = {RTEMS_EVENT_1, + RTEMS_EVENT_2, + RTEMS_EVENT_3, + RTEMS_EVENT_4, + RTEMS_EVENT_5, + RTEMS_EVENT_6, + RTEMS_EVENT_7, + RTEMS_EVENT_8}; + +uint8_t count_process[TOTAL_TILES] = {0}; + +typedef struct +{ + rtems_id main_task; + uint8_t ntiles; + uint8_t next_tile; + rtems_id task_id[TASK_COUNT]; + rtems_id tile_queue; + rtems_id message_queue[TASK_COUNT]; +} test_context; + +typedef test_context Context; + +RTEMS_ALIGNED(RTEMS_TASK_STORAGE_ALIGNMENT) +static char calc_task_storage[TASK_COUNT][TASK_STORAGE_SIZE]; + +RTEMS_MESSAGE_QUEUE_BUFFER(MAX_MESSAGE_SIZE) +msg_tile_queue_storage[MAX_PENDING_MESSAGES]; + +RTEMS_MESSAGE_QUEUE_BUFFER(MAX_MESSAGE_SIZE) +msg_task_queue_storage[TASK_COUNT][MAX_PENDING_MESSAGES]; + +static void calc_task_function(rtems_task_argument arg) +{ + Context *ctx; + + ctx = (Context *)arg; + + uint8_t tile; + rtems_id local_id = TaskSelfId(); + uint8_t task_idx = 255; + + for (int i = 0; i < TASK_COUNT; i++) + { + if (ctx->task_id[i] == local_id) + { + task_idx = i; + break; + } + } + + char ch = '0' + task_idx; + + rtems_message_queue_config msg_config = { + .name = rtems_build_name('M', 'S', 'G', ch), + .maximum_pending_messages = MAX_PENDING_MESSAGES, + .maximum_message_size = MAX_MESSAGE_SIZE, + .storage_size = sizeof(msg_task_queue_storage[task_idx]), + .storage_area = &msg_task_queue_storage[task_idx], + .attributes = RTEMS_FIFO | RTEMS_GLOBAL}; + ctx->message_queue[task_idx] = CreateMessageQueue(msg_config); + + SendMessage(ctx->tile_queue, &task_idx, sizeof(task_idx)); + ReceiveMessage(ctx->message_queue[task_idx], &tile); + + while (tile <= ctx->ntiles) + { + count_process[tile - 1]++; + mandelbrot_tile(tile, ctx->ntiles); + + SendMessage(ctx->tile_queue, &task_idx, sizeof(task_idx)); + ReceiveMessage(ctx->message_queue[task_idx], &tile); + } + + SendMessage(ctx->tile_queue, &task_idx, sizeof(task_idx)); + SendEvents(ctx->main_task, event_send[task_idx]); + SuspendSelf(); +} + +static void Init(rtems_task_argument arg) +{ + (void)arg; + test_context ctx; + uint32_t start_time, end_time, elapsed_time; + char ch; + char str[ITOA_STR_SIZE]; + int total_events = 0; + uint8_t task = 255; + bool correctly_processed = true; + + rtems_message_queue_config msg_config = { + .name = rtems_build_name('M', 'S', 'G', 'T'), + .maximum_pending_messages = RTEMS_ARRAY_SIZE(msg_tile_queue_storage), + .maximum_message_size = MAX_MESSAGE_SIZE, + .storage_size = sizeof(msg_tile_queue_storage), + .storage_area = &msg_tile_queue_storage, + .attributes = RTEMS_FIFO | RTEMS_GLOBAL}; + + ctx.main_task = rtems_task_self(); + ctx.tile_queue = CreateMessageQueue(msg_config); + ctx.ntiles = TOTAL_TILES; + ctx.next_tile = 1; + + start_time = rtems_clock_get_ticks_since_boot(); + rtems_task_config calc_task_config = { + .initial_priority = PRIO_VERY_HIGH, + .storage_size = TASK_STORAGE_SIZE, + .maximum_thread_local_storage_size = + MAX_TLS_SIZE, + .initial_modes = RTEMS_DEFAULT_MODES, + .attributes = TASK_ATTRIBUTES}; + + for (uint32_t i = 0; i < TASK_COUNT; i++) + { + ch = '0' + i; + + calc_task_config.name = rtems_build_name('R', 'U', 'N', ch); + calc_task_config.storage_area = &calc_task_storage[i][0]; + + ctx.task_id[i] = DoCreateTask(calc_task_config); + StartTask(ctx.task_id[i], calc_task_function, &ctx); + total_events += event_send[i]; + } + + while (ReceiveAvailableEvents() != total_events) + { + ReceiveMessage(ctx.tile_queue, &task); + SendMessage(ctx.message_queue[task], &ctx.next_tile, sizeof(ctx.next_tile)); + + ctx.next_tile++; + } + + print_string("printing results\n"); + end_time = rtems_clock_get_ticks_since_boot(); + + elapsed_time = end_time - start_time; + + print_string("\n"); + print_string("Multicore Elapsed Time -"); + print_string(itoa(elapsed_time, &str[0], 10)); + print_string("\n"); + + print_test_results(); + + for (uint8_t i = 0; i < ctx.ntiles; i++) + { + if (count_process[i] != 1) + { + correctly_processed = false; + break; + } + } + + if (correctly_processed) + { + print_string("Each tile only processed once: true\n"); + } + else + { + print_string("Each tile only processed once: false\n"); + } + + for (uint32_t i = 0; i < TASK_COUNT; i++) + { + DeleteTask(ctx.task_id[i]); + DeleteMessageQueue(ctx.message_queue[i]); + } + DeleteMessageQueue(ctx.tile_queue); + + rtems_fatal(RTEMS_FATAL_SOURCE_EXIT, 0); +} + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER + +#define CONFIGURE_MAXIMUM_PROCESSORS TEST_PROCESSORS + +#define CONFIGURE_MAXIMUM_MESSAGE_QUEUES MAX_MESSAGE_QUEUES + +#define CONFIGURE_MAXIMUM_SEMAPHORES 1 + +#define CONFIGURE_MAXIMUM_TASKS (TASK_COUNT + 1) + +#define CONFIGURE_SCHEDULER_EDF_SMP + +#define CONFIGURE_MINIMUM_TASK_STACK_SIZE \ + RTEMS_MINIMUM_STACK_SIZE + CPU_STACK_ALIGNMENT + +#define CONFIGURE_EXTRA_TASK_STACKS RTEMS_MINIMUM_STACK_SIZE + +#define CONFIGURE_INIT_TASK_CONSTRUCT_STORAGE_SIZE 2 * TASK_STORAGE_SIZE + +#define CONFIGURE_MINIMUM_TASKS_WITH_USER_PROVIDED_STORAGE \ + CONFIGURE_MAXIMUM_TASKS + +#define CONFIGURE_MICROSECONDS_PER_TICK 1000 + +#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 0 + +#define CONFIGURE_DISABLE_NEWLIB_REENTRANCY + +#define CONFIGURE_APPLICATION_DISABLE_FILESYSTEM + +#define CONFIGURE_MAXIMUM_THREAD_LOCAL_STORAGE_SIZE MAX_TLS_SIZE + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT_TASK_ATTRIBUTES (RTEMS_SYSTEM_TASK | TASK_ATTRIBUTES) + +#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES + +#define CONFIGURE_INIT + +#include <rtems/confdefs.h> diff --git a/testsuites/isvv/06_rate_monotonic_multi/rate_monotonic_multi.c b/testsuites/isvv/06_rate_monotonic_multi/rate_monotonic_multi.c new file mode 100644 index 0000000000..6f5dc1348f --- /dev/null +++ b/testsuites/isvv/06_rate_monotonic_multi/rate_monotonic_multi.c @@ -0,0 +1,292 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 2022 Critical Software SA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <rtems/bspIo.h> +#include "../shared/isvv_rtems_aux.h" +#include "../shared/utils.h" + +/** +- * @brief Assert RTEMS SMP under the stress of multiple core workloads with periodic tasks and +- * accessing protected data. +- * +- * This test case performs the calculation of the mandelbrot set divided by tiles and distributed +- * with periodic tasks. The result is stored as a reference set and the elapsed time is measured. +*/ + +#define MAX_TLS_SIZE RTEMS_ALIGN_UP(64, RTEMS_TASK_STORAGE_ALIGNMENT) + +#define TASK_ATTRIBUTES RTEMS_FLOATING_POINT + +#define TASK_STORAGE_SIZE \ + RTEMS_TASK_STORAGE_SIZE(MAX_TLS_SIZE + RTEMS_MINIMUM_STACK_SIZE, \ + TASK_ATTRIBUTES) + +#define ITOA_STR_SIZE (8 * sizeof(int) + 1) + +/* Given the board, define rate monotonic period length + to approx. the mean time needed to calculate a single tile */ +#ifdef gr740 + const rtems_interval PERIOD_LENGTH = 800; +#endif +#ifdef gr712rc + const rtems_interval PERIOD_LENGTH = 2500; +#endif + +// test specific global vars +#define TASK_COUNT TEST_PROCESSORS +#define TOTAL_TILES 64 + +rtems_event_set event_send[4] = {RTEMS_EVENT_1, + RTEMS_EVENT_2, + RTEMS_EVENT_3, + RTEMS_EVENT_4}; + +uint8_t count_process[TOTAL_TILES] = {0}; + +typedef struct +{ + rtems_id mutex_id; + rtems_id main_task; + rtems_id monoperiod; + uint8_t ntiles; + uint8_t next_tile; + rtems_id task_id[TASK_COUNT]; + uint16_t periods_executed; + uint16_t deadlines_missed; + rtems_id manual_barrier_id; +} test_context; + +typedef test_context Context; + +RTEMS_ALIGNED(RTEMS_TASK_STORAGE_ALIGNMENT) +static char calc_task_storage[TASK_COUNT][TASK_STORAGE_SIZE]; + +static void calc_task_function(rtems_task_argument arg) +{ + Context *ctx; + ctx = (Context *)arg; + + uint8_t tile = 0; + rtems_id local_id = TaskSelfId(); + uint8_t task_idx = 255; + + for (int i = 0; i < TASK_COUNT; i++) + { + if (ctx->task_id[i] == local_id) + { + task_idx = i; + break; + } + } + + while (tile < ctx->ntiles) + { + WaitAtBarrier(ctx->manual_barrier_id); + + ObtainMutex(ctx->mutex_id); + tile = ctx->next_tile; + count_process[tile - 1]++; + ctx->next_tile++; + ReleaseMutex(ctx->mutex_id); + + mandelbrot_tile(tile, ctx->ntiles); + + SendEvents(ctx->main_task, event_send[task_idx]); + } + SuspendSelf(); +} + +static void Init(rtems_task_argument arg) +{ + (void)arg; + test_context ctx; + uint32_t start_time, end_time, elapsed_time; + char ch; + char str[ITOA_STR_SIZE]; + int total_events = 0; + bool correctly_processed = true; + + rtems_event_set received = 0; + + ctx.main_task = rtems_task_self(); + ctx.mutex_id = CreateMutex(rtems_build_name('R', 'M', 'O', '1')); + ctx.ntiles = TOTAL_TILES; + ctx.next_tile = 1; + ctx.monoperiod = CreateRateMonotonic(); + ctx.periods_executed = 0; + ctx.deadlines_missed = 0; + + ctx.manual_barrier_id = CreateManualBarrier(); + + rtems_id main_sched_id; + rtems_task_get_scheduler(ctx.main_task, &main_sched_id); + + rtems_task_priority init_task_priority; + rtems_task_get_priority(ctx.main_task, main_sched_id, &init_task_priority); + + + rtems_task_config calc_task_config = { + .initial_priority = init_task_priority, + .storage_size = TASK_STORAGE_SIZE, + .maximum_thread_local_storage_size = + MAX_TLS_SIZE, + .initial_modes = RTEMS_DEFAULT_MODES, + .attributes = TASK_ATTRIBUTES}; + + ObtainMutex(ctx.mutex_id); + + for (uint32_t i = 0; i < TASK_COUNT; i++) + { + ch = '0' + i; + + calc_task_config.name = rtems_build_name('R', 'U', 'N', ch); + calc_task_config.storage_area = &calc_task_storage[i][0]; + + ctx.task_id[i] = DoCreateTask(calc_task_config); + StartTask(ctx.task_id[i], calc_task_function, &ctx); + total_events += event_send[i]; + } + start_time = rtems_clock_get_ticks_since_boot(); + + ReleaseMutex(ctx.mutex_id); + + WaitPeriod(ctx.monoperiod, PERIOD_LENGTH); + uint8_t tile = 0; + while (tile < ctx.ntiles ) + { + ReleaseManualBarrier(ctx.manual_barrier_id, TASK_COUNT); + + while (received != total_events) + { + received |= ReceiveAllEvents(total_events); + } + + if (DoesPeriodTimeOut(ctx.monoperiod, PERIOD_LENGTH)) + { + ctx.deadlines_missed++; + } + + ctx.periods_executed++; + ObtainMutex(ctx.mutex_id); + tile = ctx.next_tile-1; + ReleaseMutex(ctx.mutex_id); + received = 0; + } + + for (uint32_t i = 0; i < TASK_COUNT; i++) + { + DeleteTask(ctx.task_id[i]); + } + DeleteMutex(ctx.mutex_id); + DeleteRateMonotonic(ctx.monoperiod); + end_time = rtems_clock_get_ticks_since_boot(); + + elapsed_time = end_time - start_time; + + print_string("\n"); + print_string("Multicore Elapsed Time = "); + print_string(itoa(elapsed_time, &str[0], 10)); + print_string("\n\r"); + + for (uint8_t i = 0; i < ctx.ntiles; i++) + { + if (count_process[i] != 1) + { + correctly_processed = false; + break; + } + } + + if (correctly_processed) + { + print_string("Each tile only processed once: true\n"); + } + else + { + print_string("Each tile only processed once: false\n"); + } + + print_test_results(); + + print_string("Number of rate monotonic periods executed: "); + print_string(itoa(ctx.periods_executed, &str[0], 10)); + print_string("\n"); + print_string("Number of rate monotonic deadlines missed: "); + print_string(itoa(ctx.deadlines_missed, &str[0], 10)); + print_string("\n"); + + rtems_fatal(RTEMS_FATAL_SOURCE_EXIT, 0); +} + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER + +#define CONFIGURE_MAXIMUM_PROCESSORS TEST_PROCESSORS + +#define CONFIGURE_MAXIMUM_SEMAPHORES 1 + +#define CONFIGURE_MAXIMUM_PERIODS 1 + +#define CONFIGURE_MAXIMUM_BARRIERS 1 + +#define CONFIGURE_MAXIMUM_TASKS (TEST_PROCESSORS + 1) + +#define CONFIGURE_SCHEDULER_EDF_SMP + +#define CONFIGURE_MINIMUM_TASK_STACK_SIZE \ + RTEMS_MINIMUM_STACK_SIZE + CPU_STACK_ALIGNMENT + +#define CONFIGURE_EXTRA_TASK_STACKS RTEMS_MINIMUM_STACK_SIZE + +#define CONFIGURE_INIT_TASK_CONSTRUCT_STORAGE_SIZE 2 * TASK_STORAGE_SIZE + +#define CONFIGURE_MINIMUM_TASKS_WITH_USER_PROVIDED_STORAGE \ + CONFIGURE_MAXIMUM_TASKS + +#define CONFIGURE_MICROSECONDS_PER_TICK 1000 + +#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 0 + +#define CONFIGURE_DISABLE_NEWLIB_REENTRANCY + +#define CONFIGURE_APPLICATION_DISABLE_FILESYSTEM + +#define CONFIGURE_MAXIMUM_THREAD_LOCAL_STORAGE_SIZE MAX_TLS_SIZE + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT_TASK_ATTRIBUTES (RTEMS_SYSTEM_TASK | TASK_ATTRIBUTES) + +#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES + +#define CONFIGURE_INIT + +#include <rtems/confdefs.h> diff --git a/testsuites/isvv/07_timer_multi/timer_multi.c b/testsuites/isvv/07_timer_multi/timer_multi.c new file mode 100644 index 0000000000..2848350ca4 --- /dev/null +++ b/testsuites/isvv/07_timer_multi/timer_multi.c @@ -0,0 +1,291 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 2022 Critical Software SA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <rtems/bspIo.h> +#include <rtems/counter.h> +#include "../shared/isvv_rtems_aux.h" +#include "../shared/utils.h" + +#include <stdlib.h> + +/** + * + * @brief Demonstrate the use of the Timer. + * + * The Mandelbrot calculation of the Mandelbrot set is divided into tiles which are distributed + * between the calculation tasks; when a task completes a tile, it sends a message to get the + * next tile to be calculated. + * + * Two timers are set up to increment counters at different rates. It is checked that the result + * of the parallel calculation is the same as when generated on a single-core and that the + * multi-core calculation is faster than the single-core calculation. The number of timer service + * routines that have been executed is checked. + */ + +#define MAX_TLS_SIZE RTEMS_ALIGN_UP(64, RTEMS_TASK_STORAGE_ALIGNMENT) + +#define TASK_ATTRIBUTES RTEMS_FLOATING_POINT + +#define TASK_STORAGE_SIZE \ + RTEMS_TASK_STORAGE_SIZE(MAX_TLS_SIZE + RTEMS_MINIMUM_STACK_SIZE, \ + TASK_ATTRIBUTES) + +#define ITOA_STR_SIZE (8 * sizeof(int) + 1) + +// test specific global vars +#define TASK_COUNT TEST_PROCESSORS +#define TOTAL_TILES 64 + +void service_timer(rtems_id timer_id, void *user_data); + +rtems_event_set event_send[4] = {RTEMS_EVENT_1, + RTEMS_EVENT_2, + RTEMS_EVENT_3, + RTEMS_EVENT_4}; + + +uint8_t count_process[TOTAL_TILES] = {0}; + +typedef struct +{ + rtems_id id; + uint16_t counter; +} timer; + +typedef struct +{ + rtems_id mutex_id; + rtems_id main_task; + uint8_t ntiles; + uint8_t next_tile; + rtems_id task_id[TASK_COUNT]; + timer fast_timer; + timer slow_timer; +} test_context; + +typedef test_context Context; + +RTEMS_ALIGNED(RTEMS_TASK_STORAGE_ALIGNMENT) +static char calc_task_storage[TASK_COUNT][TASK_STORAGE_SIZE]; + +static void calc_task_function(rtems_task_argument arg) +{ + Context *ctx; + + ctx = (Context *)arg; + + uint8_t tile; + rtems_id local_id = TaskSelfId(); + uint8_t task_idx = 255; + + for (int i = 0; i < TASK_COUNT; i++) + { + if (ctx->task_id[i] == local_id) + { + task_idx = i; + break; + } + } + + ObtainMutex(ctx->mutex_id); + tile = ctx->next_tile; + ctx->next_tile++; + ReleaseMutex(ctx->mutex_id); + + while (tile <= ctx->ntiles) + { + count_process[tile - 1]++; + mandelbrot_tile(tile, ctx->ntiles); + + ObtainMutex(ctx->mutex_id); + tile = ctx->next_tile; + ctx->next_tile++; + ReleaseMutex(ctx->mutex_id); + } + + SendEvents(ctx->main_task, event_send[task_idx]); + SuspendSelf(); +} + +void service_timer(rtems_id timer_id, void *user_data) +{ + timer *tmr = user_data; + + tmr->counter++; + ResetTimer(timer_id); +} + +static void Init(rtems_task_argument arg) +{ + (void)arg; + test_context ctx; + uint32_t start_time, end_time, elapsed_time; + char ch; + char str[ITOA_STR_SIZE]; + int total_events = 0; + bool correctly_processed = true; + + ctx.main_task = rtems_task_self(); + SetSelfPriority(PRIO_HIGH); + ctx.mutex_id = CreateMutex(rtems_build_name('T', 'M', 'U', '1')); + ctx.ntiles = TOTAL_TILES; + ctx.next_tile = 1; + + start_time = rtems_clock_get_ticks_since_boot(); + rtems_task_config calc_task_config = { + .initial_priority = PRIO_VERY_HIGH, + .storage_size = TASK_STORAGE_SIZE, + .maximum_thread_local_storage_size = + MAX_TLS_SIZE, + .initial_modes = RTEMS_DEFAULT_MODES, + .attributes = TASK_ATTRIBUTES}; + + ObtainMutex(ctx.mutex_id); + + for (uint32_t i = 0; i < TASK_COUNT; i++) + { + ch = '0' + i; + + calc_task_config.name = rtems_build_name('R', 'U', 'N', ch); + calc_task_config.storage_area = &calc_task_storage[i][0]; + + ctx.task_id[i] = DoCreateTask(calc_task_config); + StartTask(ctx.task_id[i], calc_task_function, &ctx); + total_events += event_send[i]; + } + + ctx.fast_timer.id = CreateTimer(rtems_build_name('F', 'T', 'M', 'R')); + ctx.fast_timer.counter = 0; + ctx.slow_timer.id = CreateTimer(rtems_build_name('S', 'T', 'M', 'R')); + ctx.slow_timer.counter = 0; + + LaunchFunctionAfter(ctx.fast_timer.id, 11, service_timer, &ctx.fast_timer); + LaunchFunctionAfter(ctx.slow_timer.id, 23, service_timer, &ctx.slow_timer); + + ReleaseMutex(ctx.mutex_id); + + while (ReceiveAvailableEvents() != total_events) + { + } + + end_time = rtems_clock_get_ticks_since_boot(); + + print_string("Fast timer counter: "); + print_string(itoa(ctx.fast_timer.counter, &str[0], 10)); + print_string("\n"); + print_string("Slow timer counter: "); + print_string(itoa(ctx.slow_timer.counter, &str[0], 10)); + print_string("\n"); + + elapsed_time = end_time - start_time; + + print_string("\n"); + print_string("Multicore Elapsed Time -"); + print_string(itoa(elapsed_time, &str[0], 10)); + print_string("\n"); + + print_test_results(); + + for (uint8_t i = 0; i < ctx.ntiles; i++) + { + if (count_process[i] != 1) + { + correctly_processed = false; + break; + } + } + + if (correctly_processed) + { + print_string("Each tile only processed once: true\n"); + } + else + { + print_string("Each tile only processed once: false\n"); + } + + for (uint32_t i = 0; i < TASK_COUNT; i++) + { + DeleteTask(ctx.task_id[i]); + } + DeleteMutex(ctx.mutex_id); + DeleteTimer(ctx.fast_timer.id); + DeleteTimer(ctx.slow_timer.id); + + rtems_fatal(RTEMS_FATAL_SOURCE_EXIT, 0); +} + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER + +#define CONFIGURE_MAXIMUM_PROCESSORS TEST_PROCESSORS + +#define CONFIGURE_MAXIMUM_SEMAPHORES 1 + +#define CONFIGURE_MAXIMUM_PERIODS 1 + +#define CONFIGURE_MAXIMUM_BARRIERS 1 + +#define CONFIGURE_MAXIMUM_TIMERS 2 + +#define CONFIGURE_MAXIMUM_TASKS (TEST_PROCESSORS + 1) + +#define CONFIGURE_SCHEDULER_EDF_SMP + +#define CONFIGURE_MINIMUM_TASK_STACK_SIZE \ + RTEMS_MINIMUM_STACK_SIZE + CPU_STACK_ALIGNMENT + +#define CONFIGURE_EXTRA_TASK_STACKS RTEMS_MINIMUM_STACK_SIZE + +#define CONFIGURE_INIT_TASK_CONSTRUCT_STORAGE_SIZE 2 * TASK_STORAGE_SIZE + +#define CONFIGURE_MINIMUM_TASKS_WITH_USER_PROVIDED_STORAGE \ + CONFIGURE_MAXIMUM_TASKS + +#define CONFIGURE_MICROSECONDS_PER_TICK 1000 + +#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 0 + +#define CONFIGURE_DISABLE_NEWLIB_REENTRANCY + +#define CONFIGURE_APPLICATION_DISABLE_FILESYSTEM + +#define CONFIGURE_MAXIMUM_THREAD_LOCAL_STORAGE_SIZE MAX_TLS_SIZE + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT_TASK_ATTRIBUTES (RTEMS_SYSTEM_TASK | TASK_ATTRIBUTES) + +#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES + +#define CONFIGURE_INIT + +#include <rtems/confdefs.h> diff --git a/testsuites/isvv/09_timer_server_multi/timer_server_multi.c b/testsuites/isvv/09_timer_server_multi/timer_server_multi.c new file mode 100644 index 0000000000..02a8d5ddfd --- /dev/null +++ b/testsuites/isvv/09_timer_server_multi/timer_server_multi.c @@ -0,0 +1,269 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 2022 Critical Software SA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <rtems/bspIo.h> +#include <rtems/counter.h> + +#include "../shared/isvv_rtems_aux.h" +#include "../shared/utils.h" + +#include <stdlib.h> + +/** + * + * @brief Demonstrate the use of the Timer Service. + * + * This test case uses a timer server to execute the service routines. The timer server is started + * at the default priority so that it interrupts the calculation tasks. This means that the service + * routine will not execute until the next calculation task completes. + * + * The Mandelbrot calculation of the Mandelbrot set is divided into tiles which are distributed + * between the calculation tasks; when a task completes a tile, it sends a message to get the + * next tile to be calculated. + * + * Two timers are set up to increment counters at different rates. It is checked that the result + * of the parallel calculation is the same as when generated on a single-core and that the + * multi-core calculation is faster than the single-core calculation. The number of timer service + * routines that have been executed is checked. + */ + +#define MAX_TLS_SIZE RTEMS_ALIGN_UP(64, RTEMS_TASK_STORAGE_ALIGNMENT) + +#define TASK_ATTRIBUTES RTEMS_FLOATING_POINT + +#define TASK_STORAGE_SIZE \ + RTEMS_TASK_STORAGE_SIZE(MAX_TLS_SIZE + RTEMS_MINIMUM_STACK_SIZE, \ + TASK_ATTRIBUTES) + +#define ITOA_STR_SIZE (8 * sizeof(int) + 1) + +// test specific global vars +#define TASK_COUNT TEST_PROCESSORS + +rtems_event_set event_send[4] = {RTEMS_EVENT_1, + RTEMS_EVENT_2, + RTEMS_EVENT_3, + RTEMS_EVENT_4 + }; + +typedef struct { + rtems_id id; + uint16_t counter; +} timer; + +typedef struct { + rtems_id mutex_id; + rtems_id main_task; + uint8_t ntiles; + uint8_t next_tile; + rtems_id task_id[TASK_COUNT]; + timer fast_timer; + timer slow_timer; +} test_context; + +typedef test_context Context; + +RTEMS_ALIGNED(RTEMS_TASK_STORAGE_ALIGNMENT) +static char calc_task_storage[TASK_COUNT][TASK_STORAGE_SIZE]; + +static void calc_task_function(rtems_task_argument arg) { + Context *ctx; + + ctx = (Context *)arg; + + uint8_t tile; + rtems_id local_id = TaskSelfId(); + uint8_t task_idx = 255; + char str; + + for (int i = 0; i < TASK_COUNT; i++) { + if (ctx->task_id[i] == local_id) { + task_idx = i; + break; + } + } + + ObtainMutex(ctx->mutex_id); + tile = ctx->next_tile; + ctx->next_tile++; + ReleaseMutex(ctx->mutex_id); + + while (tile <= ctx->ntiles) { + mandelbrot_tile(tile, ctx->ntiles); + + ObtainMutex(ctx->mutex_id); + tile = ctx->next_tile; + ctx->next_tile++; + ReleaseMutex(ctx->mutex_id); + } + + SendEvents(ctx->main_task, event_send[task_idx]); + SuspendSelf(); +} + + +void service_timer( rtems_id timer_id, void *user_data ) +{ + timer *tmr = user_data; + + tmr->counter++; + ResetTimer(timer_id); +} + +static void Init( rtems_task_argument arg ) { + (void)arg; + rtems_status_code sc; + test_context ctx; + uint32_t start_time, end_time, elapsed_time; + char ch; + char str[ITOA_STR_SIZE]; + uint32_t current_cpu; + bool allDone; + rtems_task_argument tile; + rtems_event_set received = 0; + int total_events = 0; + + ctx.main_task = rtems_task_self(); + ctx.mutex_id = CreateMutex(rtems_build_name('T', 'S', 'M', '1')); + ctx.ntiles = 64; + ctx.next_tile = 1; + + sc = rtems_timer_initiate_server(RTEMS_TIMER_SERVER_DEFAULT_PRIORITY, + RTEMS_MINIMUM_STACK_SIZE, + RTEMS_DEFAULT_ATTRIBUTES); + + start_time = rtems_clock_get_ticks_since_boot(); + rtems_task_config calc_task_config = { + .initial_priority = PRIO_NORMAL, + .storage_size = TASK_STORAGE_SIZE, + .maximum_thread_local_storage_size = + MAX_TLS_SIZE, + .initial_modes = RTEMS_DEFAULT_MODES, + .attributes = TASK_ATTRIBUTES + }; + + ObtainMutex(ctx.mutex_id); + + for (uint32_t i = 0; i < TASK_COUNT; i++) { + ch = '0' + i; + + calc_task_config.name = rtems_build_name('R', 'U', 'N', ch); + calc_task_config.storage_area = &calc_task_storage[i][0]; + + ctx.task_id[i] = DoCreateTask(calc_task_config); + StartTask(ctx.task_id[i], calc_task_function, &ctx); + total_events += event_send[i]; + } + + + + ctx.fast_timer.id = CreateTimer(rtems_build_name( 'F', 'T', 'M', 'R' )); + ctx.fast_timer.counter = 0; + ctx.slow_timer.id = CreateTimer(rtems_build_name( 'S', 'T', 'M', 'R' )); + ctx.slow_timer.counter = 0; + + LaunchFunctionAfter(ctx.fast_timer.id, 11, service_timer, &ctx.fast_timer); + LaunchFunctionAfter(ctx.slow_timer.id, 23, service_timer, &ctx.slow_timer); + + ReleaseMutex(ctx.mutex_id); + + while (ReceiveAvailableEvents() != total_events) { + } + + print_string("printing results"); + rtems_putc('\n'); + end_time = rtems_clock_get_ticks_since_boot(); + + print_string(itoa(ctx.fast_timer.counter, &str[0], 10)); + rtems_putc(' '); + print_string(itoa(ctx.slow_timer.counter, &str[0], 10)); + rtems_putc('\n'); + + + elapsed_time = end_time - start_time; + + print_test_results(); + for (uint32_t i = 0; i < TASK_COUNT; i++) { + DeleteTask(ctx.task_id[i]); + } + DeleteMutex(ctx.mutex_id); + DeleteTimer(ctx.fast_timer.id); + DeleteTimer(ctx.slow_timer.id); + + rtems_fatal(RTEMS_FATAL_SOURCE_EXIT, 0); +} + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER + +#define CONFIGURE_MAXIMUM_PROCESSORS TEST_PROCESSORS + +#define CONFIGURE_MAXIMUM_SEMAPHORES 1 + +#define CONFIGURE_MAXIMUM_PERIODS 1 + +#define CONFIGURE_MAXIMUM_BARRIERS 1 + +#define CONFIGURE_MAXIMUM_TIMERS 2 + +#define CONFIGURE_MAXIMUM_TASKS (TEST_PROCESSORS + 1) + +#define CONFIGURE_SCHEDULER_EDF_SMP + +#define CONFIGURE_MINIMUM_TASK_STACK_SIZE \ + RTEMS_MINIMUM_STACK_SIZE + CPU_STACK_ALIGNMENT + +#define CONFIGURE_EXTRA_TASK_STACKS RTEMS_MINIMUM_STACK_SIZE + +#define CONFIGURE_INIT_TASK_CONSTRUCT_STORAGE_SIZE 2 * TASK_STORAGE_SIZE + +#define CONFIGURE_MINIMUM_TASKS_WITH_USER_PROVIDED_STORAGE \ + CONFIGURE_MAXIMUM_TASKS + +#define CONFIGURE_MICROSECONDS_PER_TICK 1000 + +#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 0 + +#define CONFIGURE_DISABLE_NEWLIB_REENTRANCY + +#define CONFIGURE_APPLICATION_DISABLE_FILESYSTEM + +#define CONFIGURE_MAXIMUM_THREAD_LOCAL_STORAGE_SIZE MAX_TLS_SIZE + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT_TASK_ATTRIBUTES (RTEMS_SYSTEM_TASK | TASK_ATTRIBUTES) + +#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES + +#define CONFIGURE_INIT + +#include <rtems/confdefs.h> diff --git a/testsuites/isvv/10_barrier_multi/barrier_multi.c b/testsuites/isvv/10_barrier_multi/barrier_multi.c new file mode 100644 index 0000000000..1c60f62d95 --- /dev/null +++ b/testsuites/isvv/10_barrier_multi/barrier_multi.c @@ -0,0 +1,302 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 2022 Critical Software SA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stddef.h> +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <rtems/bspIo.h> +#include "../shared/isvv_rtems_aux.h" +#include "../shared/utils.h" + +/** + * + * @brief Demonstrate the use of barriers in SMP context. + * + * The Mandelbrot set tiles are distributed between worker tasks to perform the calculation. + * Before starting each set, worker tasks are freed by a manual barrier owned by a controlling + * thread that releases the barrier after distributing the set, one tile per core. + * + * Then a set of worker tasks perform the tile calculations in parallel. Only when all of them finish + * the controlling task will distribute a new set. This is controlled by an automatic barrier that + * releases when all of the worker tasks complete calculations. + */ + +#define MAX_TLS_SIZE RTEMS_ALIGN_UP(64, RTEMS_TASK_STORAGE_ALIGNMENT) + +#define TASK_ATTRIBUTES RTEMS_FLOATING_POINT + +#define TASK_STORAGE_SIZE \ + RTEMS_TASK_STORAGE_SIZE(MAX_TLS_SIZE + RTEMS_MINIMUM_STACK_SIZE, \ + TASK_ATTRIBUTES) + +#define ITOA_STR_SIZE (8 * sizeof(int) + 1) + +// test specific global vars +#define TASK_COUNT TEST_PROCESSORS +#define TOTAL_TILES 64 + +rtems_event_set event_send[] = {RTEMS_EVENT_1, + RTEMS_EVENT_2, + RTEMS_EVENT_3, + RTEMS_EVENT_4}; + +#define MAX_MESSAGE_QUEUES 5 +#define MAX_MESSAGE_SIZE sizeof(uint8_t) +#define MAX_PENDING_MESSAGES TASK_COUNT + +uint8_t count_process[TOTAL_TILES] = {0}; + +typedef struct +{ + rtems_id main_task; + uint8_t ntiles; + uint8_t next_tile; + rtems_id task_id[TASK_COUNT]; + rtems_id tile_queue; + rtems_id message_queue[TASK_COUNT]; + rtems_id auto_barrier_id; + rtems_id manual_barrier_id; +} test_context; + +RTEMS_ALIGNED(RTEMS_TASK_STORAGE_ALIGNMENT) +static char calc_task_storage[TASK_COUNT][TASK_STORAGE_SIZE]; + +RTEMS_MESSAGE_QUEUE_BUFFER(MAX_MESSAGE_SIZE) +msg_tile_queue_storage[MAX_PENDING_MESSAGES]; + +RTEMS_MESSAGE_QUEUE_BUFFER(MAX_MESSAGE_SIZE) +msg_task_queue_storage[TASK_COUNT][MAX_PENDING_MESSAGES]; + +static void calc_task_function(rtems_task_argument arg) +{ + test_context *ctx; + + ctx = (test_context *)arg; + + uint8_t tile = 0; + rtems_id local_id = TaskSelfId(); + uint8_t task_idx = 0; + + for (int i = 0; i < TASK_COUNT; i++) + { + if (ctx->task_id[i] == local_id) + { + task_idx = i; + break; + } + } + + char ch = '0' + task_idx; + + rtems_message_queue_config msg_config = { + .name = rtems_build_name('M', 'S', 'G', ch), + .maximum_pending_messages = MAX_PENDING_MESSAGES, + .maximum_message_size = MAX_MESSAGE_SIZE, + .storage_size = sizeof(msg_task_queue_storage[task_idx]), + .storage_area = &msg_task_queue_storage[task_idx], + .attributes = RTEMS_FIFO | RTEMS_GLOBAL}; + ctx->message_queue[task_idx] = CreateMessageQueue(msg_config); + + SendMessage(ctx->tile_queue, &task_idx, sizeof(task_idx)); + ReceiveMessage(ctx->message_queue[task_idx], &tile); + while (tile <= ctx->ntiles) + { + WaitAtBarrier(ctx->manual_barrier_id); + + count_process[tile - 1]++; + mandelbrot_tile(tile, ctx->ntiles); + + WaitAtBarrier(ctx->auto_barrier_id); + + SendMessage(ctx->tile_queue, &task_idx, sizeof(task_idx)); + ReceiveMessage(ctx->message_queue[task_idx], &tile); + } + + SendEvents(ctx->main_task, event_send[task_idx]); + SuspendSelf(); +} + +static void Init(rtems_task_argument arg) +{ + (void)arg; + test_context ctx; + uint32_t start_time, end_time, elapsed_time; + char ch; + uint8_t task = 255; + rtems_event_set received = 0; + rtems_event_set total_events = 0; + bool correctly_processed = true; + char str[ITOA_STR_SIZE]; + + rtems_message_queue_config msg_config = { + .name = rtems_build_name('M', 'S', 'G', 'T'), + .maximum_pending_messages = RTEMS_ARRAY_SIZE(msg_tile_queue_storage), + .maximum_message_size = MAX_MESSAGE_SIZE, + .storage_size = sizeof(msg_tile_queue_storage), + .storage_area = &msg_tile_queue_storage, + .attributes = RTEMS_FIFO | RTEMS_GLOBAL}; + + ctx.main_task = rtems_task_self(); + ctx.tile_queue = CreateMessageQueue(msg_config); + ctx.ntiles = TOTAL_TILES; + ctx.next_tile = 1; + uint8_t nwaiting = TASK_COUNT; + ctx.auto_barrier_id = CreateAutomaticBarrier(nwaiting); + ctx.manual_barrier_id = CreateManualBarrier(); + + start_time = rtems_clock_get_ticks_since_boot(); + rtems_task_config calc_task_config = { + .initial_priority = PRIO_NORMAL, + .storage_size = TASK_STORAGE_SIZE, + .maximum_thread_local_storage_size = + MAX_TLS_SIZE, + .initial_modes = RTEMS_DEFAULT_MODES, + .attributes = TASK_ATTRIBUTES}; + + for (uint32_t i = 0; i < TASK_COUNT; i++) + { + ch = '0' + i; + calc_task_config.name = rtems_build_name('R', 'U', 'N', ch); + calc_task_config.storage_area = &calc_task_storage[i][0]; + + ctx.task_id[i] = DoCreateTask(calc_task_config); + StartTask(ctx.task_id[i], calc_task_function, &ctx); + total_events += event_send[i]; + } + + while (ctx.next_tile <= ctx.ntiles + TASK_COUNT) + { + ReceiveMessage(ctx.tile_queue, &task); + SendMessage(ctx.message_queue[task], &ctx.next_tile, sizeof(ctx.next_tile)); + + if (ctx.next_tile <= ctx.ntiles) + { + if (ctx.next_tile % TASK_COUNT == 0) + { + ReleaseManualBarrier(ctx.manual_barrier_id, TASK_COUNT); + } + else if (ctx.next_tile == ctx.ntiles) + { + ReleaseManualBarrier(ctx.manual_barrier_id, ctx.next_tile % TASK_COUNT); + } + } + + ctx.next_tile++; + } + + while (received != total_events) + { + received |= ReceiveAllEvents(total_events); + } + + end_time = rtems_clock_get_ticks_since_boot(); + + elapsed_time = end_time - start_time; + + print_string("\n"); + print_string("Multicore Elapsed Time -"); + print_string(itoa(elapsed_time, &str[0], 10)); + print_string("\n"); + + print_test_results(); + + for (uint8_t i = 0; i < ctx.ntiles; i++) + { + if (count_process[i] != 1) + { + correctly_processed = false; + break; + } + } + + if (correctly_processed) + { + print_string("Each tile only processed once: true\n"); + } + else + { + print_string("Each tile only processed once: false\n"); + } + + for (uint32_t i = 0; i < TASK_COUNT; i++) + { + DeleteTask(ctx.task_id[i]); + DeleteMessageQueue(ctx.message_queue[i]); + } + DeleteMessageQueue(ctx.tile_queue); + DeleteBarrier(ctx.auto_barrier_id); + DeleteBarrier(ctx.manual_barrier_id); + + rtems_fatal(RTEMS_FATAL_SOURCE_EXIT, 0); +} + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER + +#define CONFIGURE_MAXIMUM_PROCESSORS TEST_PROCESSORS + +#define CONFIGURE_MAXIMUM_MESSAGE_QUEUES MAX_MESSAGE_QUEUES + +#define CONFIGURE_MAXIMUM_SEMAPHORES 1 + +#define CONFIGURE_MAXIMUM_BARRIERS 2 + +#define CONFIGURE_MAXIMUM_TASKS (TEST_PROCESSORS + 1) + +#define CONFIGURE_SCHEDULER_EDF_SMP + +#define CONFIGURE_MINIMUM_TASK_STACK_SIZE \ + RTEMS_MINIMUM_STACK_SIZE + CPU_STACK_ALIGNMENT + +#define CONFIGURE_EXTRA_TASK_STACKS RTEMS_MINIMUM_STACK_SIZE + +#define CONFIGURE_INIT_TASK_CONSTRUCT_STORAGE_SIZE 2 * TASK_STORAGE_SIZE + +#define CONFIGURE_MINIMUM_TASKS_WITH_USER_PROVIDED_STORAGE \ + CONFIGURE_MAXIMUM_TASKS + +#define CONFIGURE_MICROSECONDS_PER_TICK 1000 + +#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 0 + +#define CONFIGURE_DISABLE_NEWLIB_REENTRANCY + +#define CONFIGURE_APPLICATION_DISABLE_FILESYSTEM + +#define CONFIGURE_MAXIMUM_THREAD_LOCAL_STORAGE_SIZE MAX_TLS_SIZE + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT_TASK_ATTRIBUTES (RTEMS_SYSTEM_TASK | TASK_ATTRIBUTES) + +#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES + +#define CONFIGURE_INIT + +#include <rtems/confdefs.h> diff --git a/testsuites/isvv/10_barrier_multi/barrier_multi_timeout.c b/testsuites/isvv/10_barrier_multi/barrier_multi_timeout.c new file mode 100644 index 0000000000..80b48dd7b5 --- /dev/null +++ b/testsuites/isvv/10_barrier_multi/barrier_multi_timeout.c @@ -0,0 +1,337 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 2022 Critical Software SA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stddef.h> +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <rtems/bspIo.h> +#include "../shared/isvv_rtems_aux.h" +#include "../shared/utils.h" + +/** + * + * @brief Demonstrate the use of barriers in SMP context. + * + * The Mandelbrot set tiles are distributed between worker tasks to perform the calculation. + * Before starting each set, worker tasks are freed by a manual barrier owned by a controlling + * thread that releases the barrier after distributing the set, one tile per core. + * + * Then a set of worker tasks perform the tile calculations in parallel. Only when all of them finish + * the controlling task will distribute a new set. This is controlled by an automatic barrier that + * releases when all of the worker tasks complete calculations. + * + * A final step runs the same but induces a lock (e.g. a delay on one of the workers, leading to + * the barrier not to be released), to check whether timeout is reached. + */ + +#define MAX_TLS_SIZE RTEMS_ALIGN_UP(64, RTEMS_TASK_STORAGE_ALIGNMENT) + +#define TASK_ATTRIBUTES RTEMS_FLOATING_POINT + +#define TASK_STORAGE_SIZE \ + RTEMS_TASK_STORAGE_SIZE(MAX_TLS_SIZE + RTEMS_MINIMUM_STACK_SIZE, \ + TASK_ATTRIBUTES) + +#define ITOA_STR_SIZE (8 * sizeof(int) + 1) + +// test specific global vars +#define TASK_COUNT TEST_PROCESSORS +#define TOTAL_TILES 64 + +rtems_event_set event_send[] = {RTEMS_EVENT_1, + RTEMS_EVENT_2, + RTEMS_EVENT_3, + RTEMS_EVENT_4}; + +#define MAX_MESSAGE_QUEUES 5 +#define MAX_MESSAGE_SIZE sizeof(uint8_t) +#define MAX_PENDING_MESSAGES TASK_COUNT + +uint8_t count_process[TOTAL_TILES] = {0}; + +typedef struct +{ + rtems_id main_task; + uint8_t ntiles; + uint8_t next_tile; + rtems_id task_id[TASK_COUNT]; + rtems_id tile_queue; + rtems_id message_queue[TASK_COUNT]; + rtems_id auto_barrier_id; + rtems_id manual_barrier_id; + rtems_id timeout_mutex; + uint8_t timeout_flag; +} test_context; + +RTEMS_ALIGNED(RTEMS_TASK_STORAGE_ALIGNMENT) +static char calc_task_storage[TASK_COUNT][TASK_STORAGE_SIZE]; + +RTEMS_MESSAGE_QUEUE_BUFFER(MAX_MESSAGE_SIZE) +msg_tile_queue_storage[MAX_PENDING_MESSAGES]; + +RTEMS_MESSAGE_QUEUE_BUFFER(MAX_MESSAGE_SIZE) +msg_task_queue_storage[TASK_COUNT][MAX_PENDING_MESSAGES]; + +static void calc_task_function(rtems_task_argument arg) +{ + test_context *ctx; + + ctx = (test_context *)arg; + uint8_t tile = 0; + rtems_id local_id = TaskSelfId(); + uint8_t task_idx = 0; + + for (int i = 0; i < TASK_COUNT; i++) + { + if (ctx->task_id[i] == local_id) + { + task_idx = i; + break; + } + } + + char ch = '0' + task_idx; + + rtems_message_queue_config msg_config = { + .name = rtems_build_name('M', 'S', 'G', ch), + .maximum_pending_messages = MAX_PENDING_MESSAGES, + .maximum_message_size = MAX_MESSAGE_SIZE, + .storage_size = sizeof(msg_task_queue_storage[task_idx]), + .storage_area = &msg_task_queue_storage[task_idx], + .attributes = RTEMS_FIFO | RTEMS_GLOBAL}; + ctx->message_queue[task_idx] = CreateMessageQueue(msg_config); + + SendMessage(ctx->tile_queue, &task_idx, sizeof(task_idx)); + ReceiveMessage(ctx->message_queue[task_idx], &tile); + while (tile <= ctx->ntiles) + { + rtems_status_code sc; + char *timeout = "RTEMS_TIMEOUT"; + + WaitAtBarrier(ctx->manual_barrier_id); + + count_process[tile - 1]++; + mandelbrot_tile(tile, ctx->ntiles); + + // Cause infinite loop so that automatic barrier times out. + if (task_idx == 3) + { + while (1); + } + + sc = rtems_barrier_wait(ctx->auto_barrier_id, BARRIER_TIMEOUT); + if(rtems_status_text(sc) == timeout) + { + // First thread that registers the timeout reports it. + ObtainMutex(ctx->timeout_mutex); + if(ctx->timeout_flag == 0) + { + ctx->timeout_flag = 1; + } + ReleaseMutex(ctx->timeout_mutex); + } + + SendMessage(ctx->tile_queue, &task_idx, sizeof(task_idx)); + ReceiveMessage(ctx->message_queue[task_idx], &tile); + } + + SendEvents(ctx->main_task, event_send[task_idx]); + SuspendSelf(); +} + +static void Init(rtems_task_argument arg) +{ + (void)arg; + test_context ctx; + uint32_t start_time, end_time, elapsed_time; + char ch; + uint8_t task = 255; + rtems_event_set received = 0; + rtems_event_set total_events = 0; + bool correctly_processed = true; + char str[ITOA_STR_SIZE]; + + rtems_message_queue_config msg_config = { + .name = rtems_build_name('M', 'S', 'G', 'T'), + .maximum_pending_messages = RTEMS_ARRAY_SIZE(msg_tile_queue_storage), + .maximum_message_size = MAX_MESSAGE_SIZE, + .storage_size = sizeof(msg_tile_queue_storage), + .storage_area = &msg_tile_queue_storage, + .attributes = RTEMS_FIFO | RTEMS_GLOBAL}; + + ctx.main_task = rtems_task_self(); + ctx.tile_queue = CreateMessageQueue(msg_config); + ctx.ntiles = TOTAL_TILES; + ctx.next_tile = 1; + uint8_t nwaiting = TASK_COUNT; + ctx.auto_barrier_id = CreateAutomaticBarrier(nwaiting); + ctx.manual_barrier_id = CreateManualBarrier(); + ctx.timeout_mutex = CreateMutex(rtems_build_name('B', 'M', 'T', '1')); + ctx.timeout_flag = 0; + + start_time = rtems_clock_get_ticks_since_boot(); + rtems_task_config calc_task_config = { + .initial_priority = PRIO_NORMAL, + .storage_size = TASK_STORAGE_SIZE, + .maximum_thread_local_storage_size = + MAX_TLS_SIZE, + .initial_modes = RTEMS_DEFAULT_MODES, + .attributes = TASK_ATTRIBUTES}; + + for (uint32_t i = 0; i < TASK_COUNT; i++) + { + ch = '0' + i; + calc_task_config.name = rtems_build_name('R', 'U', 'N', ch); + calc_task_config.storage_area = &calc_task_storage[i][0]; + + ctx.task_id[i] = DoCreateTask(calc_task_config); + + StartTask(ctx.task_id[i], calc_task_function, &ctx); + total_events += event_send[i]; + } + + while ((ctx.next_tile <= ctx.ntiles + TASK_COUNT) && (ctx.timeout_flag == 0)) + { + ReceiveMessage(ctx.tile_queue, &task); + SendMessage(ctx.message_queue[task], &ctx.next_tile, sizeof(ctx.next_tile)); + + if (ctx.next_tile <= ctx.ntiles) + { + if (ctx.next_tile % TASK_COUNT == 0) + { + ReleaseManualBarrier(ctx.manual_barrier_id, TASK_COUNT); + } + else if (ctx.next_tile == ctx.ntiles) + { + ReleaseManualBarrier(ctx.manual_barrier_id, ctx.next_tile % TASK_COUNT); + } + } + + ctx.next_tile++; + } + + while (received != total_events) + { + received |= ReceiveAllEvents(total_events); + } + + end_time = rtems_clock_get_ticks_since_boot(); + + elapsed_time = end_time - start_time; + + print_string("\n"); + print_string("Multicore Elapsed Time -"); + print_string(itoa(elapsed_time, &str[0], 10)); + print_string("\n"); + + print_test_results(); + + for (uint8_t i = 0; i < ctx.ntiles; i++) + { + if (count_process[i] != 1) + { + correctly_processed = false; + break; + } + } + + if (correctly_processed) + { + print_string("Each tile only processed once: true\n"); + } + else + { + print_string("Each tile only processed once: false\n"); + } + + if(ctx.timeout_flag == 1) + { + print_string("RTEMS_TIMEOUT ocurred: true\n"); + } + else + { + print_string("RTEMS_TIMEOUT ocurred: false\n"); + } + + for (uint32_t i = 0; i < TASK_COUNT; i++) + { + DeleteTask(ctx.task_id[i]); + DeleteMessageQueue(ctx.message_queue[i]); + } + DeleteMessageQueue(ctx.tile_queue); + DeleteBarrier(ctx.auto_barrier_id); + DeleteBarrier(ctx.manual_barrier_id); + + rtems_fatal(RTEMS_FATAL_SOURCE_EXIT, 0); +} + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER + +#define CONFIGURE_MAXIMUM_PROCESSORS TEST_PROCESSORS + +#define CONFIGURE_MAXIMUM_MESSAGE_QUEUES MAX_MESSAGE_QUEUES + +#define CONFIGURE_MAXIMUM_SEMAPHORES 1 + +#define CONFIGURE_MAXIMUM_BARRIERS 2 + +#define CONFIGURE_MAXIMUM_TASKS (TEST_PROCESSORS + 1) + +#define CONFIGURE_SCHEDULER_EDF_SMP + +#define CONFIGURE_MINIMUM_TASK_STACK_SIZE \ + RTEMS_MINIMUM_STACK_SIZE + CPU_STACK_ALIGNMENT + +#define CONFIGURE_EXTRA_TASK_STACKS RTEMS_MINIMUM_STACK_SIZE + +#define CONFIGURE_INIT_TASK_CONSTRUCT_STORAGE_SIZE 2 * TASK_STORAGE_SIZE + +#define CONFIGURE_MINIMUM_TASKS_WITH_USER_PROVIDED_STORAGE \ + CONFIGURE_MAXIMUM_TASKS + +#define CONFIGURE_MICROSECONDS_PER_TICK 1000 + +#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 0 + +#define CONFIGURE_DISABLE_NEWLIB_REENTRANCY + +#define CONFIGURE_APPLICATION_DISABLE_FILESYSTEM + +#define CONFIGURE_MAXIMUM_THREAD_LOCAL_STORAGE_SIZE MAX_TLS_SIZE + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT_TASK_ATTRIBUTES (RTEMS_SYSTEM_TASK | TASK_ATTRIBUTES) + +#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES + +#define CONFIGURE_INIT + +#include <rtems/confdefs.h> diff --git a/testsuites/isvv/11_MrsP_multi/mrsp_multi.c b/testsuites/isvv/11_MrsP_multi/mrsp_multi.c new file mode 100644 index 0000000000..b6253185f0 --- /dev/null +++ b/testsuites/isvv/11_MrsP_multi/mrsp_multi.c @@ -0,0 +1,436 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 2022 Critical Software SA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <rtems/bspIo.h> +#include "../shared/isvv_rtems_aux.h" +#include "../shared/utils.h" +#include <string.h> + +/** +- * @brief Assert RTEMS SMP under the stress of multiple core workloads accessing protected data. +- * +- * This test case performs the calculation of orbital frequencies based on readings from sensors +- * with three periodic tasks, and two binary semaphores. The result is stored as a reference set +- * and the elapsed time is measured. +*/ + +#define ITOA_STR_SIZE (8 * sizeof(int) + 1) + +#define MAX_TLS_SIZE RTEMS_ALIGN_UP(64, RTEMS_TASK_STORAGE_ALIGNMENT) + +#define TASK_ATTRIBUTES RTEMS_FLOATING_POINT + +#define TASK_STORAGE_SIZE \ + RTEMS_TASK_STORAGE_SIZE(MAX_TLS_SIZE + RTEMS_MINIMUM_STACK_SIZE, \ + TASK_ATTRIBUTES) + +// test specific global vars +#undef TEST_PROCESSORS +#define TEST_PROCESSORS 2 +#define TASK_COUNT 3 + +#define END_OF_STREAM UINT8_MAX + +#define INCREMENT_AVAILABLE_DATA(x) (x++) + +#define DECREMENT_AVAILABLE_DATA(x) ({if (x>0) x--;}) + +#define TEST_IF_DATA_AVAILABLE_IS_EMPTY(x) (x==0) + +#define TEST_IF_DATA_AVAILABLE_IS_NOT_EMPTY(x) (x!=0) + +#define EVENT_FINISHED_SENSING RTEMS_EVENT_0 +#define EVENT_CALCULATED_DATA RTEMS_EVENT_1 +#define EVENT_WROTE_DATA RTEMS_EVENT_2 +#define EVENT_SENSOR_READY RTEMS_EVENT_3 +#define EVENT_DATA_READY RTEMS_EVENT_4 +#define EVENT_DATA_OUT RTEMS_EVENT_5 + +// For this data set, and given lumosity, the total number of planets found should equal 11 + +#define MAX_ITER (64U) +#define FFT_SIZE (32768U) +#define FFT_SIZE_LOG2 (15U) +#define TC_MAX (16U) +#define FILTER_REPETITIONS (2U) +#define SNR_THRESHOLD (1000000.0f) + +const uint16_t FS = 48000U; +const uint16_t FREQ[TC_MAX] = { 2500U, 1500U, 15000U, 500U, + 1000U, 800U, 440U, 8000U, + 100U, 3500U, 12345U, 1200U, + 20000U, 715U, 5000U, 4500U }; +const float NOISE_FACTOR[TC_MAX] = { 0.0001f, 0.2250f, 0.00068f, 0.30f, + 0.004f, 0.0123f, 0.0054f, 0.00054f, + 0.01f, 0.0325f, 0.012f, 0.00032f, + 0.075f, 0.0423f, 0.0354f, 0.00002f }; + +static float inSensorDataRe[FFT_SIZE]; +static float inSensorDataIm[FFT_SIZE]; +typedef struct +{ + rtems_id main_task_id; + rtems_id read_task_id; + rtems_id calc_task_id; + rtems_id write_task_id; + uint8_t m1_data; + uint32_t iter; + float scaling_fft_factor; + float snr_float; + rtems_id m1_data_mutex; + rtems_id m2_result_mutex; + uint8_t planet_count; + uint8_t planet_locations[MAX_ITER]; + uint16_t value_in_watts_flag_counter; + uint16_t luminosity_flag_counter; + float debug_maxValueIndex; + float debug_maxValue; + float debug_sig; + float debig_noise; +} test_context; + +RTEMS_ALIGNED(RTEMS_TASK_STORAGE_ALIGNMENT) +static char calc_task_storage[TASK_COUNT][TASK_STORAGE_SIZE]; + +// * Task 0 - writes sensors data onto shared memory +static void task_snr_read_sensor_data(rtems_task_argument arg) +{ + test_context *ctx; + ctx = (test_context *)arg; + + while ( ctx->iter < MAX_ITER) + { + ObtainMutex(ctx->m1_data_mutex); + if TEST_IF_DATA_AVAILABLE_IS_EMPTY(ctx->value_in_watts_flag_counter) + { + for (uint32_t i = 0; i < FFT_SIZE; i++) + { + inSensorDataRe[i] = 0.4995f * cos_aprox(i*2.0f*PI*FREQ[ctx->iter%TC_MAX]/FS) + + (noise_generator(0) * NOISE_FACTOR[ctx->iter%TC_MAX]); + inSensorDataIm[i] = 0.4995f * sin_aprox(i*2.0f*PI*FREQ[ctx->iter%TC_MAX]/FS) + + (noise_generator(0) * NOISE_FACTOR[ctx->iter% TC_MAX]); + } + INCREMENT_AVAILABLE_DATA(ctx->value_in_watts_flag_counter); + } + ReleaseMutex(ctx->m1_data_mutex); + rtems_task_wake_after(1); + } + SuspendSelf(); +} + +// * Task 1 - collects data when ready, calculates, and stores the result on the shared memory +static void task_snr_process_data(rtems_task_argument arg) +{ + test_context *ctx; + ctx = (test_context *)arg; + float sig = 0.0f; + float noise = 0.0f; + bool update_luminosity_calc_result = false; + + while ( ctx->iter < MAX_ITER ) + { + ObtainMutex(ctx->m1_data_mutex); + if ( TEST_IF_DATA_AVAILABLE_IS_NOT_EMPTY(ctx->value_in_watts_flag_counter) && + (update_luminosity_calc_result == false) ) + { + update_luminosity_calc_result = true; + + //Apply Blackman-Harris Window + for (uint32_t i = 0; i < FFT_SIZE; i++) + { + inSensorDataRe[i] = inSensorDataRe[i]*blackman_harris(i, FFT_SIZE)/ctx->scaling_fft_factor; + inSensorDataIm[i] = inSensorDataIm[i]*blackman_harris(i, FFT_SIZE)/ctx->scaling_fft_factor; + } + //Calculates FFT + fft(&inSensorDataRe[0], &inSensorDataIm[0], FFT_SIZE_LOG2); + + //Calculates the magnitude^2 values + for (uint32_t i = 0; i < FFT_SIZE; i++) + { + inSensorDataRe[i] = (inSensorDataRe[i] * inSensorDataRe[i] + + inSensorDataIm[i] * inSensorDataIm[i]) / ((float)FFT_SIZE); + } + + //Look for the peak Value and its index (no DC) + float maxValue = 0.0; + int32_t maxValueIndex = -1; + for (uint32_t i = 3; i < (FFT_SIZE / 2); i++) + { + if (inSensorDataRe[i] > maxValue) + { + maxValue = inSensorDataRe[i]; + maxValueIndex = i; + } + } + + //Calculates the signal and noise power (no DC) + sig = 0.0f; + noise = 0.0f; + for (uint32_t i = 3; i < (FFT_SIZE / 2); i++) + { + if ((i > maxValueIndex - 8) && (i < maxValueIndex + 8)) + { + sig += (2 * inSensorDataRe[i]); + } + else + { + noise += (2 * inSensorDataRe[i]); + } + } + ctx->debug_maxValueIndex = maxValueIndex; + ctx->debug_maxValue = maxValue; + ctx->debig_noise = noise; + ctx->debug_sig = sig; + } + + ReleaseMutex(ctx->m1_data_mutex); + + if (!(sig > 0.0f)) { sig = 0.0000000001f; } + if (!(noise > 0.0f)) { noise = 0.0000000001f; } + + if (update_luminosity_calc_result) + { + ObtainMutex(ctx->m2_result_mutex); + if ( TEST_IF_DATA_AVAILABLE_IS_EMPTY(ctx->luminosity_flag_counter) ) + { + update_luminosity_calc_result = false; + + //Calculates SNR + ctx->snr_float = sig/noise; + DECREMENT_AVAILABLE_DATA(ctx->value_in_watts_flag_counter); + INCREMENT_AVAILABLE_DATA(ctx->luminosity_flag_counter); + } + ReleaseMutex(ctx->m2_result_mutex); + } + rtems_task_wake_after(1); + } + SuspendSelf(); +} + +// * Task 2 - reads the results +static void read_and_output(rtems_task_argument arg) +{ + test_context *ctx = (test_context *)arg; + float result; + + // Luminosity threshold to indicate planet, not e.g. star + float luminosity_threshold = 0.005; + + while (ctx->iter < MAX_ITER) + { + ObtainMutex(ctx->m2_result_mutex); + if (TEST_IF_DATA_AVAILABLE_IS_NOT_EMPTY(ctx->luminosity_flag_counter)) + { + if (ctx->snr_float > SNR_THRESHOLD) + { + ctx->planet_locations[ctx->iter] = 1; + ctx->planet_count++; + } + else + { + ctx->planet_locations[ctx->iter] = 0; + } + DECREMENT_AVAILABLE_DATA(ctx->luminosity_flag_counter); + ctx->iter++; + } + ReleaseMutex(ctx->m2_result_mutex); + rtems_task_wake_after(1); + } + rtems_event_send(ctx->main_task_id, EVENT_WROTE_DATA); + SuspendSelf(); +} + +static void Init(rtems_task_argument arg) +{ + (void)arg; + test_context ctx; + + char str[ITOA_STR_SIZE]; + uint32_t start_time, end_time, multi_core_elapsed_time; + + rtems_id scsw_core_id; + rtems_id aocs_core_id; + + (void) memset(&ctx, 0, sizeof(test_context)); + (void) memset(&inSensorDataRe[0], 0, FFT_SIZE); + (void) memset(&inSensorDataIm[0], 0, FFT_SIZE); + + // Identify main task for communication between tasks + ctx.main_task_id = rtems_task_self(); + SetSelfPriority( PRIO_NORMAL ); + + //Calculates mean of Blackman-Harris terms + ctx.scaling_fft_factor = 0.0; + for (uint32_t i = 0; i<FFT_SIZE; i++) + { + ctx.scaling_fft_factor += blackman_harris( i, FFT_SIZE); + } + ctx.scaling_fft_factor = ctx.scaling_fft_factor/ ((float) FFT_SIZE); + + // Create the binary semaphores and intialize variables + ctx.m1_data_mutex = CreateMutexMrsP(rtems_build_name('M', '1', 'M', 'X')); + ctx.m2_result_mutex = CreateMutexMrsP(rtems_build_name('M', '2', 'M', 'X')); + + ctx.planet_count = 0; + memset(&ctx.planet_locations, 0, MAX_ITER); + + rtems_task_config calc_task_config = { + .initial_priority = PRIO_NORMAL, + .storage_size = TASK_STORAGE_SIZE, + .maximum_thread_local_storage_size = + MAX_TLS_SIZE, + .initial_modes = RTEMS_DEFAULT_MODES, + .attributes = TASK_ATTRIBUTES}; + + scsw_core_id = IdentifyScheduler(SCHEDULER_A_NAME); + aocs_core_id = IdentifyScheduler(SCHEDULER_B_NAME); + + // Setup task for reading data from the sensor + calc_task_config.name = rtems_build_name('R', 'E', 'A', 'D'); + calc_task_config.storage_area = &calc_task_storage[0][0]; + + ctx.read_task_id = DoCreateTask(calc_task_config); + SetScheduler(ctx.read_task_id, scsw_core_id, PRIO_LOW); + + // Setup task for reading from shared memory location + // And calculating the new result in lumens + calc_task_config.name = rtems_build_name('C', 'A', 'L', 'C'); + calc_task_config.storage_area = &calc_task_storage[1][0]; + + ctx.calc_task_id = DoCreateTask(calc_task_config); + SetScheduler(ctx.calc_task_id, aocs_core_id, PRIO_NORMAL); + + // Setup task for outputting from shared memory location + calc_task_config.name = rtems_build_name('O', 'U', 'T', 'P'); + calc_task_config.storage_area = &calc_task_storage[2][0]; + + ctx.write_task_id = DoCreateTask(calc_task_config); + SetScheduler(ctx.write_task_id, scsw_core_id, PRIO_HIGH); + + // Start all tasks + StartTask(ctx.read_task_id, task_snr_read_sensor_data, &ctx); + StartTask(ctx.calc_task_id, task_snr_process_data, &ctx); + StartTask(ctx.write_task_id, read_and_output, &ctx); + + start_time = rtems_clock_get_ticks_since_boot(); + + // Wait for all tasks to be completed + ReceiveAllEvents(EVENT_WROTE_DATA); + + end_time = rtems_clock_get_ticks_since_boot(); + + // Output the results + print_string("Planet count: "); + print_string(itoa(ctx.planet_count, &str[0], 10)); + print_string("\n"); + print_string("Planets sensed at sensor positions: "); + for (uint8_t i=0; i<MAX_ITER; i++) + { + if (ctx.planet_locations[i] > 0) + { + print_string(itoa(i, &str[0], 10)); + print_string(" "); + } + } + + multi_core_elapsed_time = end_time - start_time; + print_string("\n"); + print_string("Multicore Elapsed Time - "); + print_string(itoa(multi_core_elapsed_time, &str[0], 10)); + print_string("\n"); + + rtems_task_delete(ctx.read_task_id); + rtems_task_delete(ctx.calc_task_id); + rtems_task_delete(ctx.write_task_id); + + rtems_fatal(RTEMS_FATAL_SOURCE_EXIT, 0); +} + + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER + +#define CONFIGURE_MAXIMUM_PROCESSORS TEST_PROCESSORS + +#define CONFIGURE_MAXIMUM_SEMAPHORES 2 + +#define CONFIGURE_MAXIMUM_TASKS ( TASK_COUNT + 1 ) + +#define CONFIGURE_SCHEDULER_EDF_SMP + +#define CONFIGURE_MINIMUM_TASK_STACK_SIZE \ + RTEMS_MINIMUM_STACK_SIZE + CPU_STACK_ALIGNMENT + +#define CONFIGURE_EXTRA_TASK_STACKS RTEMS_MINIMUM_STACK_SIZE + +#define CONFIGURE_INIT_TASK_CONSTRUCT_STORAGE_SIZE 2 * TASK_STORAGE_SIZE + +#define CONFIGURE_MINIMUM_TASKS_WITH_USER_PROVIDED_STORAGE \ + CONFIGURE_MAXIMUM_TASKS + +#define CONFIGURE_MICROSECONDS_PER_TICK 1000 + +#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 0 + +#include <rtems/scheduler.h> + +RTEMS_SCHEDULER_EDF_SMP( a ); +RTEMS_SCHEDULER_EDF_SMP( b ); + +#define CONFIGURE_SCHEDULER_TABLE_ENTRIES \ + RTEMS_SCHEDULER_TABLE_EDF_SMP(a, SCHEDULER_A_NAME), \ + RTEMS_SCHEDULER_TABLE_EDF_SMP(b, SCHEDULER_B_NAME) + +#define CONFIGURE_SCHEDULER_ASSIGNMENTS \ + RTEMS_SCHEDULER_ASSIGN(0, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_MANDATORY), \ + RTEMS_SCHEDULER_ASSIGN(1, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_MANDATORY) + + +#define CONFIGURE_SCHEDULER_NAME SCHEDULER_A_NAME + +#define CONFIGURE_SCHEDULER_PRIORITY + + +#define CONFIGURE_DISABLE_NEWLIB_REENTRANCY + +#define CONFIGURE_APPLICATION_DISABLE_FILESYSTEM + +#define CONFIGURE_MAXIMUM_THREAD_LOCAL_STORAGE_SIZE MAX_TLS_SIZE + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT_TASK_ATTRIBUTES (RTEMS_SYSTEM_TASK | TASK_ATTRIBUTES) + +#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES + +#define CONFIGURE_INIT + +#include <rtems/confdefs.h> diff --git a/testsuites/isvv/12_OMIP_multi/omip_multi.c b/testsuites/isvv/12_OMIP_multi/omip_multi.c new file mode 100644 index 0000000000..162a24a46e --- /dev/null +++ b/testsuites/isvv/12_OMIP_multi/omip_multi.c @@ -0,0 +1,436 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 2022 Critical Software SA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <rtems/bspIo.h> +#include "../shared/isvv_rtems_aux.h" +#include "../shared/utils.h" +#include <string.h> + +/** +- * @brief Assert RTEMS SMP under the stress of multiple core workloads accessing protected data. +- * +- * This test case performs the calculation of orbital frequencies based on readings from sensors +- * with three periodic tasks, and two binary semaphores. The result is stored as a reference set +- * and the elapsed time is measured. +*/ + +#define ITOA_STR_SIZE (8 * sizeof(int) + 1) + +#define MAX_TLS_SIZE RTEMS_ALIGN_UP(64, RTEMS_TASK_STORAGE_ALIGNMENT) + +#define TASK_ATTRIBUTES RTEMS_FLOATING_POINT + +#define TASK_STORAGE_SIZE \ + RTEMS_TASK_STORAGE_SIZE(MAX_TLS_SIZE + RTEMS_MINIMUM_STACK_SIZE, \ + TASK_ATTRIBUTES) + +// test specific global vars +#undef TEST_PROCESSORS +#define TEST_PROCESSORS 2 +#define TASK_COUNT 3 + +#define END_OF_STREAM UINT8_MAX + +#define INCREMENT_AVAILABLE_DATA(x) (x++) + +#define DECREMENT_AVAILABLE_DATA(x) ({if (x>0) x--;}) + +#define TEST_IF_DATA_AVAILABLE_IS_EMPTY(x) (x==0) + +#define TEST_IF_DATA_AVAILABLE_IS_NOT_EMPTY(x) (x!=0) + +#define EVENT_FINISHED_SENSING RTEMS_EVENT_0 +#define EVENT_CALCULATED_DATA RTEMS_EVENT_1 +#define EVENT_WROTE_DATA RTEMS_EVENT_2 +#define EVENT_SENSOR_READY RTEMS_EVENT_3 +#define EVENT_DATA_READY RTEMS_EVENT_4 +#define EVENT_DATA_OUT RTEMS_EVENT_5 + +// For this data set, and given lumosity, the total number of planets found should equal 11 + +#define MAX_ITER (64U) +#define FFT_SIZE (32768U) +#define FFT_SIZE_LOG2 (15U) +#define TC_MAX (16U) +#define FILTER_REPETITIONS (2U) +#define SNR_THRESHOLD (1000000.0f) + +const uint16_t FS = 48000U; +const uint16_t FREQ[TC_MAX] = { 2500U, 1500U, 15000U, 500U, + 1000U, 800U, 440U, 8000U, + 100U, 3500U, 12345U, 1200U, + 20000U, 715U, 5000U, 4500U }; +const float NOISE_FACTOR[TC_MAX] = { 0.0001f, 0.2250f, 0.00068f, 0.30f, + 0.004f, 0.0123f, 0.0054f, 0.00054f, + 0.01f, 0.0325f, 0.012f, 0.00032f, + 0.075f, 0.0423f, 0.0354f, 0.00002f }; + +static float inSensorDataRe[FFT_SIZE]; +static float inSensorDataIm[FFT_SIZE]; +typedef struct +{ + rtems_id main_task_id; + rtems_id read_task_id; + rtems_id calc_task_id; + rtems_id write_task_id; + uint8_t m1_data; + uint32_t iter; + float scaling_fft_factor; + float snr_float; + rtems_id m1_data_mutex; + rtems_id m2_result_mutex; + uint8_t planet_count; + uint8_t planet_locations[MAX_ITER]; + uint16_t value_in_watts_flag_counter; + uint16_t luminosity_flag_counter; + float debug_maxValueIndex; + float debug_maxValue; + float debug_sig; + float debig_noise; +} test_context; + +RTEMS_ALIGNED(RTEMS_TASK_STORAGE_ALIGNMENT) +static char calc_task_storage[TASK_COUNT][TASK_STORAGE_SIZE]; + +// * Task 0 - writes sensors data onto shared memory +static void task_snr_read_sensor_data(rtems_task_argument arg) +{ + test_context *ctx; + ctx = (test_context *)arg; + + while ( ctx->iter < MAX_ITER) + { + ObtainMutex(ctx->m1_data_mutex); + if TEST_IF_DATA_AVAILABLE_IS_EMPTY(ctx->value_in_watts_flag_counter) + { + for (uint32_t i = 0; i < FFT_SIZE; i++) + { + inSensorDataRe[i] = 0.4995f * cos_aprox(i*2.0f*PI*FREQ[ctx->iter%TC_MAX]/FS) + + (noise_generator(0) * NOISE_FACTOR[ctx->iter%TC_MAX]); + inSensorDataIm[i] = 0.4995f * sin_aprox(i*2.0f*PI*FREQ[ctx->iter%TC_MAX]/FS) + + (noise_generator(0) * NOISE_FACTOR[ctx->iter% TC_MAX]); + } + INCREMENT_AVAILABLE_DATA(ctx->value_in_watts_flag_counter); + } + ReleaseMutex(ctx->m1_data_mutex); + rtems_task_wake_after(1); + } + SuspendSelf(); +} + +// * Task 1 - collects data when ready, calculates, and stores the result on the shared memory +static void task_snr_process_data(rtems_task_argument arg) +{ + test_context *ctx; + ctx = (test_context *)arg; + float sig = 0.0f; + float noise = 0.0f; + bool update_luminosity_calc_result = false; + + while ( ctx->iter < MAX_ITER ) + { + ObtainMutex(ctx->m1_data_mutex); + if ( TEST_IF_DATA_AVAILABLE_IS_NOT_EMPTY(ctx->value_in_watts_flag_counter) && + (update_luminosity_calc_result == false) ) + { + update_luminosity_calc_result = true; + + //Apply Blackman-Harris Window + for (uint32_t i = 0; i < FFT_SIZE; i++) + { + inSensorDataRe[i] = inSensorDataRe[i]*blackman_harris(i, FFT_SIZE)/ctx->scaling_fft_factor; + inSensorDataIm[i] = inSensorDataIm[i]*blackman_harris(i, FFT_SIZE)/ctx->scaling_fft_factor; + } + //Calculates FFT + fft(&inSensorDataRe[0], &inSensorDataIm[0], FFT_SIZE_LOG2); + + //Calculates the magnitude^2 values + for (uint32_t i = 0; i < FFT_SIZE; i++) + { + inSensorDataRe[i] = (inSensorDataRe[i] * inSensorDataRe[i] + + inSensorDataIm[i] * inSensorDataIm[i]) / ((float)FFT_SIZE); + } + + //Look for the peak Value and its index (no DC) + float maxValue = 0.0; + int32_t maxValueIndex = -1; + for (uint32_t i = 3; i < (FFT_SIZE / 2); i++) + { + if (inSensorDataRe[i] > maxValue) + { + maxValue = inSensorDataRe[i]; + maxValueIndex = i; + } + } + + //Calculates the signal and noise power (no DC) + sig = 0.0f; + noise = 0.0f; + for (uint32_t i = 3; i < (FFT_SIZE / 2); i++) + { + if ((i > maxValueIndex - 8) && (i < maxValueIndex + 8)) + { + sig += (2 * inSensorDataRe[i]); + } + else + { + noise += (2 * inSensorDataRe[i]); + } + } + ctx->debug_maxValueIndex = maxValueIndex; + ctx->debug_maxValue = maxValue; + ctx->debig_noise = noise; + ctx->debug_sig = sig; + } + + ReleaseMutex(ctx->m1_data_mutex); + + if (!(sig > 0.0f)) { sig = 0.0000000001f; } + if (!(noise > 0.0f)) { noise = 0.0000000001f; } + + if (update_luminosity_calc_result) + { + ObtainMutex(ctx->m2_result_mutex); + if ( TEST_IF_DATA_AVAILABLE_IS_EMPTY(ctx->luminosity_flag_counter) ) + { + update_luminosity_calc_result = false; + + //Calculates SNR + ctx->snr_float = sig/noise; + DECREMENT_AVAILABLE_DATA(ctx->value_in_watts_flag_counter); + INCREMENT_AVAILABLE_DATA(ctx->luminosity_flag_counter); + } + ReleaseMutex(ctx->m2_result_mutex); + } + rtems_task_wake_after(1); + } + SuspendSelf(); +} + +// * Task 2 - reads the results +static void read_and_output(rtems_task_argument arg) +{ + test_context *ctx = (test_context *)arg; + float result; + + // Luminosity threshold to indicate planet, not e.g. star + float luminosity_threshold = 0.005; + + while (ctx->iter < MAX_ITER) + { + ObtainMutex(ctx->m2_result_mutex); + if (TEST_IF_DATA_AVAILABLE_IS_NOT_EMPTY(ctx->luminosity_flag_counter)) + { + if (ctx->snr_float > SNR_THRESHOLD) + { + ctx->planet_locations[ctx->iter] = 1; + ctx->planet_count++; + } + else + { + ctx->planet_locations[ctx->iter] = 0; + } + DECREMENT_AVAILABLE_DATA(ctx->luminosity_flag_counter); + ctx->iter++; + } + ReleaseMutex(ctx->m2_result_mutex); + rtems_task_wake_after(1); + } + rtems_event_send(ctx->main_task_id, EVENT_WROTE_DATA); + SuspendSelf(); +} + +static void Init(rtems_task_argument arg) +{ + (void)arg; + test_context ctx; + + char str[ITOA_STR_SIZE]; + uint32_t start_time, end_time, multi_core_elapsed_time; + + rtems_id scsw_core_id; + rtems_id aocs_core_id; + + (void) memset(&ctx, 0, sizeof(test_context)); + (void) memset(&inSensorDataRe[0], 0, FFT_SIZE); + (void) memset(&inSensorDataIm[0], 0, FFT_SIZE); + + // Identify main task for communication between tasks + ctx.main_task_id = rtems_task_self(); + SetSelfPriority( PRIO_NORMAL ); + + //Calculates mean of Blackman-Harris terms + ctx.scaling_fft_factor = 0.0; + for (uint32_t i = 0; i<FFT_SIZE; i++) + { + ctx.scaling_fft_factor += blackman_harris( i, FFT_SIZE); + } + ctx.scaling_fft_factor = ctx.scaling_fft_factor/ ((float) FFT_SIZE); + + // Create the binary semaphores and intialize variables + ctx.m1_data_mutex = CreateMutex(rtems_build_name('M', '1', 'M', 'X')); + ctx.m2_result_mutex = CreateMutex(rtems_build_name('M', '2', 'M', 'X')); + + ctx.planet_count = 0; + memset(&ctx.planet_locations, 0, MAX_ITER); + + rtems_task_config calc_task_config = { + .initial_priority = PRIO_NORMAL, + .storage_size = TASK_STORAGE_SIZE, + .maximum_thread_local_storage_size = + MAX_TLS_SIZE, + .initial_modes = RTEMS_DEFAULT_MODES, + .attributes = TASK_ATTRIBUTES}; + + scsw_core_id = IdentifyScheduler(SCHEDULER_A_NAME); + aocs_core_id = IdentifyScheduler(SCHEDULER_B_NAME); + + // Setup task for reading data from the sensor + calc_task_config.name = rtems_build_name('R', 'E', 'A', 'D'); + calc_task_config.storage_area = &calc_task_storage[0][0]; + + ctx.read_task_id = DoCreateTask(calc_task_config); + SetScheduler(ctx.read_task_id, scsw_core_id, PRIO_LOW); + + // Setup task for reading from shared memory location + // And calculating the new result in lumens + calc_task_config.name = rtems_build_name('C', 'A', 'L', 'C'); + calc_task_config.storage_area = &calc_task_storage[1][0]; + + ctx.calc_task_id = DoCreateTask(calc_task_config); + SetScheduler(ctx.calc_task_id, aocs_core_id, PRIO_NORMAL); + + // Setup task for outputting from shared memory location + calc_task_config.name = rtems_build_name('O', 'U', 'T', 'P'); + calc_task_config.storage_area = &calc_task_storage[2][0]; + + ctx.write_task_id = DoCreateTask(calc_task_config); + SetScheduler(ctx.write_task_id, scsw_core_id, PRIO_HIGH); + + // Start all tasks + StartTask(ctx.read_task_id, task_snr_read_sensor_data, &ctx); + StartTask(ctx.calc_task_id, task_snr_process_data, &ctx); + StartTask(ctx.write_task_id, read_and_output, &ctx); + + start_time = rtems_clock_get_ticks_since_boot(); + + // Wait for all tasks to be completed + ReceiveAllEvents(EVENT_WROTE_DATA); + + end_time = rtems_clock_get_ticks_since_boot(); + + // Output the results + print_string("Planet count: "); + print_string(itoa(ctx.planet_count, &str[0], 10)); + print_string("\n"); + print_string("Planets sensed at sensor positions: "); + for (uint8_t i=0; i<MAX_ITER; i++) + { + if (ctx.planet_locations[i] > 0) + { + print_string(itoa(i, &str[0], 10)); + print_string(" "); + } + } + + multi_core_elapsed_time = end_time - start_time; + print_string("\n"); + print_string("Multicore Elapsed Time - "); + print_string(itoa(multi_core_elapsed_time, &str[0], 10)); + print_string("\n"); + + rtems_task_delete(ctx.read_task_id); + rtems_task_delete(ctx.calc_task_id); + rtems_task_delete(ctx.write_task_id); + + rtems_fatal(RTEMS_FATAL_SOURCE_EXIT, 0); +} + + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER + +#define CONFIGURE_MAXIMUM_PROCESSORS TEST_PROCESSORS + +#define CONFIGURE_MAXIMUM_SEMAPHORES 2 + +#define CONFIGURE_MAXIMUM_TASKS ( TASK_COUNT + 1 ) + +#define CONFIGURE_SCHEDULER_EDF_SMP + +#define CONFIGURE_MINIMUM_TASK_STACK_SIZE \ + RTEMS_MINIMUM_STACK_SIZE + CPU_STACK_ALIGNMENT + +#define CONFIGURE_EXTRA_TASK_STACKS RTEMS_MINIMUM_STACK_SIZE + +#define CONFIGURE_INIT_TASK_CONSTRUCT_STORAGE_SIZE 2 * TASK_STORAGE_SIZE + +#define CONFIGURE_MINIMUM_TASKS_WITH_USER_PROVIDED_STORAGE \ + CONFIGURE_MAXIMUM_TASKS + +#define CONFIGURE_MICROSECONDS_PER_TICK 1000 + +#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 0 + +#include <rtems/scheduler.h> + +RTEMS_SCHEDULER_EDF_SMP( a ); +RTEMS_SCHEDULER_EDF_SMP( b ); + +#define CONFIGURE_SCHEDULER_TABLE_ENTRIES \ + RTEMS_SCHEDULER_TABLE_EDF_SMP(a, SCHEDULER_A_NAME), \ + RTEMS_SCHEDULER_TABLE_EDF_SMP(b, SCHEDULER_B_NAME) + +#define CONFIGURE_SCHEDULER_ASSIGNMENTS \ + RTEMS_SCHEDULER_ASSIGN(0, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_MANDATORY), \ + RTEMS_SCHEDULER_ASSIGN(1, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_MANDATORY) + + +#define CONFIGURE_SCHEDULER_NAME SCHEDULER_A_NAME + +#define CONFIGURE_SCHEDULER_PRIORITY + + +#define CONFIGURE_DISABLE_NEWLIB_REENTRANCY + +#define CONFIGURE_APPLICATION_DISABLE_FILESYSTEM + +#define CONFIGURE_MAXIMUM_THREAD_LOCAL_STORAGE_SIZE MAX_TLS_SIZE + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT_TASK_ATTRIBUTES (RTEMS_SYSTEM_TASK | TASK_ATTRIBUTES) + +#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES + +#define CONFIGURE_INIT + +#include <rtems/confdefs.h> diff --git a/testsuites/isvv/13_priority_inheritance/priority_inheritance.c b/testsuites/isvv/13_priority_inheritance/priority_inheritance.c new file mode 100644 index 0000000000..e8b4484744 --- /dev/null +++ b/testsuites/isvv/13_priority_inheritance/priority_inheritance.c @@ -0,0 +1,449 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 2022 Critical Software SA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <rtems/bspIo.h> +#include "../shared/utils.h" +#include "../shared/isvv_rtems_aux.h" +#include <string.h> + +/** + * + * @brief Tests Priority Inheritance protocol of semaphores with two configurations: + * + * 1. Configured WITH Priority Inheritance + * One test case which creates a mutex WITH Priority Inheritance configured, + * and shows that our high priority task NEVER overruns the time in its critical region + * + * 2. Configured WITHOUT Priority Inheritance + * One test case which creates a mutex WITHOUT Priority Inheritance configured, + * and shows that our high priority task will FREQUENTLY overrun the time in its critical region + */ + +// Different periods for our periodic tasks needed for robustness and reliability as +// Execution is dependant on processor clock speed i.e 250 MHz for gr740 and 80 MHz for gr712rc +#ifdef gr740 +#define T0_PERIOD 400 +#define T1_PERIOD 200 +#else +#define T0_PERIOD 600 +#define T1_PERIOD 300 +#endif + +#ifdef PRIO_INHERIT +#define PRIO_PROTOCOL_SWITCH RTEMS_INHERIT_PRIORITY +#else +#define PRIO_PROTOCOL_SWITCH RTEMS_NO_INHERIT_PRIORITY +#endif + +#define MAX_ITER (256U) +#define FFT_SIZE (1024U) +#define FFT_SIZE_LOG2 (10U) +#define TC_MAX (16U) +#define FILTER_REPETITIONS (2U) +#define SNR_THRESHOLD (1000000.0f) + +const uint16_t FS = 48000U; +const uint16_t FREQ[TC_MAX] = {2500U, 1500U, 15000U, 500U, + 1000U, 800U, 440U, 8000U, + 100U, 3500U, 12345U, 1200U, + 20000U, 715U, 5000U, 4500U}; + +const float NOISE_FACTOR[TC_MAX] = {0.0001f, 0.2250f, 0.00068f, 0.30f, + 0.004f, 0.0123f, 0.0054f, 0.00054f, + 0.01f, 0.0325f, 0.012f, 0.00032f, + 0.075f, 0.0423f, 0.0354f, 0.00002f}; + +static float inSensorDataRe[FFT_SIZE]; +static float inSensorDataIm[FFT_SIZE]; + +#define ITOA_STR_SIZE (8 * sizeof(int) + 1) + +#define MAX_TLS_SIZE RTEMS_ALIGN_UP(64, RTEMS_TASK_STORAGE_ALIGNMENT) + +#define TASK_ATTRIBUTES RTEMS_FLOATING_POINT + +#define TASK_STORAGE_SIZE \ + RTEMS_TASK_STORAGE_SIZE( \ + MAX_TLS_SIZE + RTEMS_MINIMUM_STACK_SIZE, \ + TASK_ATTRIBUTES) + +#undef TEST_PROCESSORS +#define TEST_PROCESSORS 1 +#define TASK_COUNT 3 +#define EVENT_FINISHED_PROCESSING RTEMS_EVENT_0 + +#define T1_TUNE_REPS 50 +#define T2_COARSE_TUNING_REPS 2 +#define T2_FINE_TUNING_REPS 1300 + +typedef struct +{ + rtems_id main_task; + rtems_id task_ids[TASK_COUNT]; + rtems_id period_0_id; + rtems_id period_1_id; + int64_t t2_max_ticks; + uint16_t priority_inversion_occurrences; + float m1_data; + rtems_id m1_data_mutex; + float scaling_fft_factor; +} test_context; + +/* create storage areas for each worker, using task construct forces +the user to create these manually*/ +RTEMS_ALIGNED(RTEMS_TASK_STORAGE_ALIGNMENT) +static char task_storage[TASK_COUNT][TASK_STORAGE_SIZE]; + +// TASK 0 - (highest priority w.r.t. the other two) - a SC S/W task +// Checks data after request for recent evidence of solar flare +static void solar_flare_analysis(rtems_task_argument arg) +{ + test_context *ctx = (test_context *)arg; + + uint16_t flare_count = 0; + uint32_t start_time, end_time, time_in_critical_region; + + ctx->period_0_id = CreateRateMonotonic(); + + while (1) + { + WaitPeriod(ctx->period_0_id, T0_PERIOD); + + // Timer to see how long it takes to enter and exit critical region + start_time = rtems_clock_get_ticks_since_boot(); + ObtainMutex(ctx->m1_data_mutex); + + if (ctx->m1_data >= SNR_THRESHOLD) + flare_count++; + + ReleaseMutex(ctx->m1_data_mutex); + + end_time = rtems_clock_get_ticks_since_boot(); + time_in_critical_region = end_time - start_time; + + // If time spent in critical region is greater than bound for T2 then we know priority inversion has occurred + if (time_in_critical_region > ctx->t2_max_ticks) + ctx->priority_inversion_occurrences++; + } + + // Although this periodic task is executed ad infinitum it is good practice to finalize tasks + rtems_task_exit(); +} + +// Task 1 - (medium priority w.r.t. the other two) - a COMS task +// A communication task which periodically receives and has to decode a message +// To simulate this, we are running the lucas-lehmer primality test +static void decode_communications(rtems_task_argument arg) +{ + uint32_t start_time, end_time, elapsed_time; + test_context *ctx = (test_context *)arg; + + uint32_t res = 0; + + ctx->period_1_id = CreateRateMonotonic(); + + while (1) + { + WaitPeriod(ctx->period_1_id, T1_PERIOD); + + start_time = rtems_clock_get_ticks_since_boot(); + + for (uint16_t i = 0; i < T1_TUNE_REPS; i++) + { + for (uint8_t p = 2; p < 100; p++) + { + if (is_prime(p) && is_mersenne_prime(p)) + { + res = p; + } + } + } + + end_time = rtems_clock_get_ticks_since_boot(); + elapsed_time = end_time - start_time; + + // If the execution time is greater than the period, and hence implicit deadline, then + // this test cannot sufficiently be completed with the resources and parameters must be changed + if (elapsed_time >= T1_PERIOD) + print_string("[ERROR] Execution time of T1 is greater than period. Please reduce T1_TUNE_REPS \n"); + } + + (void)res; + // Although this periodic task is executed ad infinitum it is good practice to finalize tasks + rtems_task_exit(); +} + +// Computes the signal-to-noise ratio for our given data at a given position +static float compute_snr(float scaling_factor, uint32_t iter) +{ + for (uint32_t i = 0; i < FFT_SIZE; i++) + { + inSensorDataRe[i] = 0.4995f * cos_aprox(i * 2.0f * PI * FREQ[iter % TC_MAX] / FS) + (noise_generator(0) * NOISE_FACTOR[iter % TC_MAX]); + inSensorDataIm[i] = 0.4995f * sin_aprox(i * 2.0f * PI * FREQ[iter % TC_MAX] / FS) + (noise_generator(0) * NOISE_FACTOR[iter % TC_MAX]); + } + + for (uint32_t i = 0; i < FFT_SIZE; i++) + { + inSensorDataRe[i] = inSensorDataRe[i] * blackman_harris(i, FFT_SIZE) / scaling_factor; + inSensorDataIm[i] = inSensorDataIm[i] * blackman_harris(i, FFT_SIZE) / scaling_factor; + } + + fft(&inSensorDataRe[0], &inSensorDataIm[0], FFT_SIZE_LOG2); + + // Look for the peak Value and its index (no DC) + float maxValue = 0.0; + int32_t maxValueIndex = -1; + for (uint32_t i = 3; i < (FFT_SIZE / 2); i++) + { + if (inSensorDataRe[i] > maxValue) + { + maxValue = inSensorDataRe[i]; + maxValueIndex = i; + } + } + + // Calculates the signal and noise power (no DC) + float sig = 0.0f; + float noise = 0.0f; + + for (uint32_t i = 3; i < (FFT_SIZE / 2); i++) + { + if ((i > maxValueIndex - 8) && (i < maxValueIndex + 8)) + { + sig += (2 * inSensorDataRe[i]); + } + else + { + noise += (2 * inSensorDataRe[i]); + } + } + + if (!(sig > 0.0f)) + { + sig = 0.0000000001f; + } + if (!(noise > 0.0f)) + { + noise = 0.0000000001f; + } + + return sig / noise; +} + +// Task 2 - (lowest priority w.r.t. the other two) - a SC S/W task +// Gathers signal data from sensors, computes the signal to noise ratio, then writes to a shared buffer +static void gather_meteorological_data(rtems_task_argument arg) +{ + test_context *ctx = (test_context *)arg; + + uint32_t iter = 0; + + while (iter < MAX_ITER) + { + ObtainMutex(ctx->m1_data_mutex); + + ctx->m1_data = compute_snr(ctx->scaling_fft_factor, iter); + + ReleaseMutex(ctx->m1_data_mutex); + + iter++; + } + + print_string("Finished Processing Data \n"); + SendEvents(ctx->main_task, EVENT_FINISHED_PROCESSING); + rtems_task_exit(); +} + +static void Init(rtems_task_argument arg) +{ + (void)arg; + test_context ctx; + + char str[ITOA_STR_SIZE]; + + uint32_t t1_start_time, t1_end_time, t1_elapsed_time; + uint32_t t2_start_time, t2_end_time, t2_elapsed_time_in_critical_region; + + rtems_status_code sc; + sc = rtems_semaphore_create(rtems_build_name('M', '1', 'M', 'X'), 1, + RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | + PRIO_PROTOCOL_SWITCH, + 0, &ctx.m1_data_mutex); + ASSERT_SUCCESS(sc); + + // FFT Initialization + (void)memset(&inSensorDataRe[0], 0, FFT_SIZE); + (void)memset(&inSensorDataIm[0], 0, FFT_SIZE); + + // Calculates mean of Blackman-Harris terms + ctx.scaling_fft_factor = 0.0; + for (uint32_t i = 0; i < FFT_SIZE; i++) + { + ctx.scaling_fft_factor += blackman_harris(i, FFT_SIZE); + } + + ctx.scaling_fft_factor = ctx.scaling_fft_factor / ((float)FFT_SIZE); + + // Find length of time T1 to execute + uint32_t res = 0; + + t1_start_time = rtems_clock_get_ticks_since_boot(); + + for (uint16_t i = 0; i < T1_TUNE_REPS; i++) + { + for (uint8_t p = 2; p < 100; p++) + { + if (is_prime(p) && is_mersenne_prime(p)) + { + res = p; + } + } + } + + t1_end_time = rtems_clock_get_ticks_since_boot(); + t1_elapsed_time = t1_end_time - t1_start_time; + + print_string("[DEBUG] e(T1) is: "); + print_string(itoa(t1_elapsed_time, &str[0], 10)); + print_string("\n"); + + (void)res; + + // Find the amount of time it takes for T2 to complete its critical region on + // an empirical basis of the max, for any of our given data, to find the upper bound + // that T0 should wait, enabling us to detect priority inversion + ctx.t2_max_ticks = -1; + + for (uint8_t i = 0; i < TC_MAX; i++) + { + t2_start_time = rtems_clock_get_ticks_since_boot(); + + ObtainMutex(ctx.m1_data_mutex); + + ctx.m1_data = compute_snr(ctx.scaling_fft_factor, i); + + ReleaseMutex(ctx.m1_data_mutex); + + t2_end_time = rtems_clock_get_ticks_since_boot(); + t2_elapsed_time_in_critical_region = t2_end_time - t2_start_time; + + ctx.t2_max_ticks = MAX(ctx.t2_max_ticks, t2_elapsed_time_in_critical_region); + } + + print_string("[DEBUG] MAX eCR(T2) is: "); + print_string(itoa(ctx.t2_max_ticks, &str[0], 10)); + print_string("\n"); + + // Build up our task configs + rtems_task_config configs[TASK_COUNT]; + for (uint8_t i = 0; i < TASK_COUNT; i++) + { + configs[i] = (rtems_task_config){ + .name = rtems_build_name('T', 'S', 'K', (char)i), + .storage_size = TASK_STORAGE_SIZE, + .storage_area = &task_storage[i][0], + .maximum_thread_local_storage_size = MAX_TLS_SIZE, + .initial_modes = RTEMS_DEFAULT_MODES, + .attributes = RTEMS_FLOATING_POINT}; + } + + // Initialize relevant test variables + ctx.main_task = rtems_task_self(); + ctx.priority_inversion_occurrences = 0; + ctx.period_0_id = INVALID_ID; + ctx.period_1_id = INVALID_ID; + + // Explicitly set the priorities of our tasks + configs[2].initial_priority = PRIO_VERY_LOW; + ctx.task_ids[2] = DoCreateTask(configs[2]); + + configs[1].initial_priority = PRIO_NORMAL; + ctx.task_ids[1] = DoCreateTask(configs[1]); + + configs[0].initial_priority = PRIO_VERY_HIGH; + ctx.task_ids[0] = DoCreateTask(configs[0]); + + // Start Tasks + StartTask(ctx.task_ids[2], gather_meteorological_data, &ctx); + StartTask(ctx.task_ids[1], decode_communications, &ctx); + StartTask(ctx.task_ids[0], solar_flare_analysis, &ctx); + + // Blocking wait for relevant event until T2 is finished + ReceiveAllEvents(EVENT_FINISHED_PROCESSING); + + print_string("Total Priority Inversion occurrences: "); + print_string(itoa(ctx.priority_inversion_occurrences, &str[0], 10)); + print_string("\n"); + + rtems_rate_monotonic_delete(ctx.period_0_id); + rtems_rate_monotonic_delete(ctx.period_1_id); + rtems_fatal(RTEMS_FATAL_SOURCE_EXIT, 0); +} + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER + +#define CONFIGURE_MAXIMUM_PROCESSORS TEST_PROCESSORS + +#define CONFIGURE_MAXIMUM_TASKS (TASK_COUNT + 1) + +#define CONFIGURE_MAXIMUM_PERIODS 2 + +#define CONFIGURE_MAXIMUM_SEMAPHORES 1 + +#define CONFIGURE_MINIMUM_TASK_STACK_SIZE RTEMS_MINIMUM_STACK_SIZE + CPU_STACK_ALIGNMENT + +#define CONFIGURE_EXTRA_TASK_STACKS RTEMS_MINIMUM_STACK_SIZE + +#define CONFIGURE_INIT_TASK_CONSTRUCT_STORAGE_SIZE 2 * TASK_STORAGE_SIZE + +#define CONFIGURE_MINIMUM_TASKS_WITH_USER_PROVIDED_STORAGE \ + CONFIGURE_MAXIMUM_TASKS + +#define CONFIGURE_MICROSECONDS_PER_TICK 1000 + +#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 0 + +#define CONFIGURE_DISABLE_NEWLIB_REENTRANCY + +#define CONFIGURE_APPLICATION_DISABLE_FILESYSTEM + +#define CONFIGURE_MAXIMUM_THREAD_LOCAL_STORAGE_SIZE MAX_TLS_SIZE + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT_TASK_ATTRIBUTES (RTEMS_SYSTEM_TASK | TASK_ATTRIBUTES) + +#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES + +#define CONFIGURE_INIT + +#include <rtems/confdefs.h> diff --git a/testsuites/isvv/14_immediate_ceiling_protocol/immediate_ceiling.c b/testsuites/isvv/14_immediate_ceiling_protocol/immediate_ceiling.c new file mode 100644 index 0000000000..a33b131c06 --- /dev/null +++ b/testsuites/isvv/14_immediate_ceiling_protocol/immediate_ceiling.c @@ -0,0 +1,468 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 2022 Critical Software SA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <rtems/bspIo.h> +#include "../shared/utils.h" +#include "../shared/isvv_rtems_aux.h" +#include <string.h> + +/** + * + * @brief Tests ICPP of semaphores with two configurations: + * + * 1. Configured WITH ICPP + * One test case which creates a mutex WITH the priority ceiling configured, + * and shows that our high priority task NEVER overruns the time in its critical region + * + * 2. Configured WITHOUT ICPP + * One test case which creates a mutex WITHOUT the priority ceiling configured, + * and shows that our high priority task will FREQUENTLY overrun the time in its critical region + */ + +// Different periods for our periodic tasks needed for robustness and reliability as +// Execution is dependant on processor clock speed i.e 250 MHz for gr740 and 80 MHz for gr712rc +#ifdef gr740 +#define T0_PERIOD 400 +#define T1_PERIOD 200 +#else +#define T0_PERIOD 600 +#define T1_PERIOD 300 +#endif + +#ifdef PRIO_CEILING +#define PRIO_PROTOCOL_SWITCH RTEMS_PRIORITY_CEILING +#else +#define PRIO_PROTOCOL_SWITCH RTEMS_NO_PRIORITY_CEILING +#endif + +#define MAX_ITER (256U) +#define FFT_SIZE (1024U) +#define FFT_SIZE_LOG2 (10U) +#define TC_MAX (16U) +#define FILTER_REPETITIONS (2U) +#define SNR_THRESHOLD (1000000.0f) + +const uint16_t FS = 48000U; +const uint16_t FREQ[TC_MAX] = {2500U, 1500U, 15000U, 500U, + 1000U, 800U, 440U, 8000U, + 100U, 3500U, 12345U, 1200U, + 20000U, 715U, 5000U, 4500U}; + +const float NOISE_FACTOR[TC_MAX] = {0.0001f, 0.2250f, 0.00068f, 0.30f, + 0.004f, 0.0123f, 0.0054f, 0.00054f, + 0.01f, 0.0325f, 0.012f, 0.00032f, + 0.075f, 0.0423f, 0.0354f, 0.00002f}; + +static float inSensorDataRe[FFT_SIZE]; +static float inSensorDataIm[FFT_SIZE]; + +#define ITOA_STR_SIZE (8 * sizeof(int) + 1) + +#define MAX_TLS_SIZE RTEMS_ALIGN_UP(64, RTEMS_TASK_STORAGE_ALIGNMENT) + +#define TASK_ATTRIBUTES RTEMS_FLOATING_POINT + +#define TASK_STORAGE_SIZE \ + RTEMS_TASK_STORAGE_SIZE( \ + MAX_TLS_SIZE + RTEMS_MINIMUM_STACK_SIZE, \ + TASK_ATTRIBUTES) + +#undef TEST_PROCESSORS +#define TEST_PROCESSORS 1 +#define TASK_COUNT 3 +#define EVENT_FINISHED_PROCESSING RTEMS_EVENT_0 + +#define T1_TUNE_REPS 50 +#define T2_COARSE_TUNING_REPS 2 +#define T2_FINE_TUNING_REPS 1300 + +typedef struct +{ + rtems_id main_task; + rtems_id task_ids[TASK_COUNT]; + rtems_id period_0_id; + rtems_id period_1_id; + int64_t t2_max_ticks; + uint16_t priority_inversion_occurrences; + float m1_data; + rtems_id m1_data_mutex; + float scaling_fft_factor; +} test_context; + +/* create storage areas for each worker, using task construct forces +the user to create these manually*/ +RTEMS_ALIGNED(RTEMS_TASK_STORAGE_ALIGNMENT) +static char task_storage[TASK_COUNT][TASK_STORAGE_SIZE]; + +// TASK 0 - (highest priority w.r.t. the other two) - a SC S/W task +// Checks data after request for recent evidence of solar flare +static void solar_flare_analysis(rtems_task_argument arg) +{ + test_context *ctx = (test_context *)arg; + + uint16_t flare_count = 0; + uint32_t start_time, end_time, time_in_critical_region; + + ctx->period_0_id = CreateRateMonotonic(); + + while (1) + { + WaitPeriod(ctx->period_0_id, T0_PERIOD); + + // Timer to see how long it takes to enter and exit critical region + start_time = rtems_clock_get_ticks_since_boot(); + ObtainMutex(ctx->m1_data_mutex); + + if (ctx->m1_data >= SNR_THRESHOLD) + flare_count++; + + ReleaseMutex(ctx->m1_data_mutex); + + end_time = rtems_clock_get_ticks_since_boot(); + time_in_critical_region = end_time - start_time; + + // If time spent in critical region is greater than bound for T2 then we know priority inversion has occurred + if (time_in_critical_region > ctx->t2_max_ticks) + ctx->priority_inversion_occurrences++; + } + + // Although this periodic task is executed ad infinitum it is good practice to finalize tasks + rtems_task_exit(); +} + +// Task 1 - (medium priority w.r.t. the other two) - a COMS task +// A communication task which periodically receives and has to decode a message +// To simulate this, we are running the lucas-lehmer primality test +static void decode_communications(rtems_task_argument arg) +{ + uint32_t start_time, end_time, elapsed_time; + test_context *ctx = (test_context *)arg; + + uint32_t res = 0; + + ctx->period_1_id = CreateRateMonotonic(); + + while (1) + { + WaitPeriod(ctx->period_1_id, T1_PERIOD); + + start_time = rtems_clock_get_ticks_since_boot(); + + for (uint16_t i = 0; i < T1_TUNE_REPS; i++) + { + for (uint8_t p = 2; p < 100; p++) + { + if (is_prime(p) && is_mersenne_prime(p)) + { + res = p; + } + } + } + + end_time = rtems_clock_get_ticks_since_boot(); + elapsed_time = end_time - start_time; + + // If the execution time is greater than the period, and hence implicit deadline, then + // this test cannot sufficiently be completed with the resources and parameters must be changed + if (elapsed_time >= T1_PERIOD) + print_string("[ERROR] Execution time of T1 is greater than period. Please reduce T1_TUNE_REPS \n"); + } + + (void)res; + // Although this periodic task is executed ad infinitum it is good practice to finalize tasks + rtems_task_exit(); +} + +// Computes the signal-to-noise ratio for our given data at a given position +static float compute_snr(float scaling_factor, uint32_t iter) +{ + for (uint32_t i = 0; i < FFT_SIZE; i++) + { + inSensorDataRe[i] = 0.4995f * cos_aprox(i * 2.0f * PI * FREQ[iter % TC_MAX] / FS) + (noise_generator(0) * NOISE_FACTOR[iter % TC_MAX]); + inSensorDataIm[i] = 0.4995f * sin_aprox(i * 2.0f * PI * FREQ[iter % TC_MAX] / FS) + (noise_generator(0) * NOISE_FACTOR[iter % TC_MAX]); + } + + for (uint32_t i = 0; i < FFT_SIZE; i++) + { + // Real & Imaginary + inSensorDataRe[i] = inSensorDataRe[i] * blackman_harris(i, FFT_SIZE) / scaling_factor; + inSensorDataIm[i] = inSensorDataIm[i] * blackman_harris(i, FFT_SIZE) / scaling_factor; + } + + fft(&inSensorDataRe[0], &inSensorDataIm[0], FFT_SIZE_LOG2); + + // Look for the peak Value and its index (no DC) + float maxValue = 0.0; + int32_t maxValueIndex = -1; + for (uint32_t i = 3; i < (FFT_SIZE / 2); i++) + { + if (inSensorDataRe[i] > maxValue) + { + maxValue = inSensorDataRe[i]; + maxValueIndex = i; + } + } + + // Calculates the signal and noise power (no DC) + float sig = 0.0f; + float noise = 0.0f; + + for (uint32_t i = 3; i < (FFT_SIZE / 2); i++) + { + if ((i > maxValueIndex - 8) && (i < maxValueIndex + 8)) + { + sig += (2 * inSensorDataRe[i]); + } + else + { + noise += (2 * inSensorDataRe[i]); + } + } + + if (!(sig > 0.0f)) + { + sig = 0.0000000001f; + } + if (!(noise > 0.0f)) + { + noise = 0.0000000001f; + } + + return sig / noise; +} + +// Task 2 - (lowest priority w.r.t. the other two) - a SC S/W task +// Gathers signal data from sensors, computes the signal to noise ratio, then writes to a shared buffer +static void gather_meteorological_data(rtems_task_argument arg) +{ + test_context *ctx = (test_context *)arg; + + uint32_t iter = 0; + + while (iter < MAX_ITER) + { + ObtainMutex(ctx->m1_data_mutex); + + ctx->m1_data = compute_snr(ctx->scaling_fft_factor, iter); + + ReleaseMutex(ctx->m1_data_mutex); + + iter++; + } + + print_string("Finished Processing Data \n"); + SendEvents(ctx->main_task, EVENT_FINISHED_PROCESSING); + rtems_task_exit(); +} + +static void Init(rtems_task_argument arg) +{ + (void)arg; + test_context ctx; + + char str[ITOA_STR_SIZE]; + + uint32_t t1_start_time, t1_end_time, t1_elapsed_time; + uint32_t t2_start_time, t2_end_time, t2_elapsed_time_in_critical_region; + + // With the ICPP we set the ceiling priority to the highest priority of any task that may hold it, + // In this case it should be T0 with priority PRIO_VERY_HIGH. + rtems_status_code sc; + sc = rtems_semaphore_create(rtems_build_name('M', '1', 'M', 'X'), 1, + RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | + PRIO_PROTOCOL_SWITCH, + PRIO_VERY_HIGH, &ctx.m1_data_mutex); + ASSERT_SUCCESS(sc); + + /* + * Due to the logic of the ICPP, and the fact that the Init task automatically has a priority + * of 1 (PRIO_VERY_ULTRA_HIGH, the highest possible for any user defined task) we must either decrease + * the priority of the Init task or increase the priority of the ceiling to be equal to the Init task, + * and configure the priorities of our defined tasks (T0, T1, T2) + * + * For consistency, we will keep our defined tasks with the same priority as in Test Case 13 and reduce the priority + * of the Init task, which only needs to acquire the semaphore to find the time T2 spends in its critical region + * + * See (https://docs.rtems.org/branches/master/c-user/key_concepts.html#immediate-ceiling-priority-protocol-icpp) + */ + + rtems_task_priority task_prio; + sc = rtems_task_set_priority(RTEMS_SELF, PRIO_VERY_HIGH, &task_prio); + ASSERT_SUCCESS(sc); + + // FFT Initialization + (void)memset(&inSensorDataRe[0], 0, FFT_SIZE); + (void)memset(&inSensorDataIm[0], 0, FFT_SIZE); + + // Calculates mean of Blackman-Harris terms + ctx.scaling_fft_factor = 0.0; + for (uint32_t i = 0; i < FFT_SIZE; i++) + { + ctx.scaling_fft_factor += blackman_harris(i, FFT_SIZE); + } + + ctx.scaling_fft_factor = ctx.scaling_fft_factor / ((float)FFT_SIZE); + + // Find length of time T1 takes to execute + uint32_t res = 0; + + t1_start_time = rtems_clock_get_ticks_since_boot(); + + for (uint16_t i = 0; i < T1_TUNE_REPS; i++) + { + for (uint8_t p = 2; p < 100; p++) + { + if (is_prime(p) && is_mersenne_prime(p)) + { + res = p; + } + } + } + + t1_end_time = rtems_clock_get_ticks_since_boot(); + t1_elapsed_time = t1_end_time - t1_start_time; + + print_string("[DEBUG] e(T1) is: "); + print_string(itoa(t1_elapsed_time, &str[0], 10)); + print_string("\n"); + + (void)res; + + // Find the amount of time it takes for T2 to complete its critical region on + // an empirical basis of the max, for any of our given data, to find the upper bound + // that T0 should wait, enabling us to detect priority inversion + ctx.t2_max_ticks = -1; + + for (uint8_t i = 0; i < TC_MAX; i++) + { + t2_start_time = rtems_clock_get_ticks_since_boot(); + + ObtainMutex(ctx.m1_data_mutex); + + ctx.m1_data = compute_snr(ctx.scaling_fft_factor, i); + + ReleaseMutex(ctx.m1_data_mutex); + + t2_end_time = rtems_clock_get_ticks_since_boot(); + t2_elapsed_time_in_critical_region = t2_end_time - t2_start_time; + + ctx.t2_max_ticks = MAX(ctx.t2_max_ticks, t2_elapsed_time_in_critical_region); + } + + print_string("[DEBUG] MAX eCR(T2) is: "); + print_string(itoa(ctx.t2_max_ticks, &str[0], 10)); + print_string("\n"); + + // Build up our task configs + rtems_task_config configs[TASK_COUNT]; + for (uint8_t i = 0; i < TASK_COUNT; i++) + { + configs[i] = (rtems_task_config){ + .name = rtems_build_name('T', 'S', 'K', (char)i), + .storage_size = TASK_STORAGE_SIZE, + .storage_area = &task_storage[i][0], + .maximum_thread_local_storage_size = MAX_TLS_SIZE, + .initial_modes = RTEMS_DEFAULT_MODES, + .attributes = RTEMS_FLOATING_POINT}; + } + + // Initialize relevant test variables + ctx.main_task = rtems_task_self(); + ctx.priority_inversion_occurrences = 0; + ctx.period_0_id = INVALID_ID; + ctx.period_1_id = INVALID_ID; + + // Explicitly set the priorities of our tasks + configs[2].initial_priority = PRIO_VERY_LOW; + ctx.task_ids[2] = DoCreateTask(configs[2]); + + configs[1].initial_priority = PRIO_NORMAL; + ctx.task_ids[1] = DoCreateTask(configs[1]); + + configs[0].initial_priority = PRIO_VERY_HIGH; + ctx.task_ids[0] = DoCreateTask(configs[0]); + + // Start Tasks + StartTask(ctx.task_ids[2], gather_meteorological_data, &ctx); + StartTask(ctx.task_ids[1], decode_communications, &ctx); + StartTask(ctx.task_ids[0], solar_flare_analysis, &ctx); + + // Blocking wait for relevant event until T2 is finished + ReceiveAllEvents(EVENT_FINISHED_PROCESSING); + + print_string("Total Priority Inversion occurrences: "); + print_string(itoa(ctx.priority_inversion_occurrences, &str[0], 10)); + print_string("\n"); + + rtems_rate_monotonic_delete(ctx.period_0_id); + rtems_rate_monotonic_delete(ctx.period_1_id); + rtems_fatal(RTEMS_FATAL_SOURCE_EXIT, 0); +} + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER + +#define CONFIGURE_MAXIMUM_PROCESSORS TEST_PROCESSORS + +#define CONFIGURE_MAXIMUM_TASKS (TASK_COUNT + 1) + +#define CONFIGURE_MAXIMUM_PERIODS 2 + +#define CONFIGURE_MAXIMUM_SEMAPHORES 1 + +#define CONFIGURE_MINIMUM_TASK_STACK_SIZE RTEMS_MINIMUM_STACK_SIZE + CPU_STACK_ALIGNMENT + +#define CONFIGURE_EXTRA_TASK_STACKS RTEMS_MINIMUM_STACK_SIZE + +#define CONFIGURE_INIT_TASK_CONSTRUCT_STORAGE_SIZE 2 * TASK_STORAGE_SIZE + +#define CONFIGURE_MINIMUM_TASKS_WITH_USER_PROVIDED_STORAGE \ + CONFIGURE_MAXIMUM_TASKS + +#define CONFIGURE_MICROSECONDS_PER_TICK 1000 + +#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 0 + +#define CONFIGURE_DISABLE_NEWLIB_REENTRANCY + +#define CONFIGURE_APPLICATION_DISABLE_FILESYSTEM + +#define CONFIGURE_MAXIMUM_THREAD_LOCAL_STORAGE_SIZE MAX_TLS_SIZE + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT_TASK_ATTRIBUTES (RTEMS_SYSTEM_TASK | TASK_ATTRIBUTES) + +#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES + +#define CONFIGURE_INIT + +#include <rtems/confdefs.h> diff --git a/testsuites/isvv/15_clock_manager_undefined_behaviour/clock_manager_undefined_behaviour.c b/testsuites/isvv/15_clock_manager_undefined_behaviour/clock_manager_undefined_behaviour.c new file mode 100644 index 0000000000..bb69f1b8b2 --- /dev/null +++ b/testsuites/isvv/15_clock_manager_undefined_behaviour/clock_manager_undefined_behaviour.c @@ -0,0 +1,579 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 2022 Critical Software SA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <rtems/bspIo.h> +#include "../shared/utils.h" +#include "../shared/isvv_rtems_aux.h" +#include <string.h> + +/** + * + * @brief Tests impact of undefined behaviours + * + * This test case performs the calculation of the Mandelbrot set in parallel with + * execution of various clock-related functions + */ + +#define MAX_TLS_SIZE RTEMS_ALIGN_UP(64, RTEMS_TASK_STORAGE_ALIGNMENT) + +#define TASK_STORAGE_SIZE \ + RTEMS_TASK_STORAGE_SIZE( \ + MAX_TLS_SIZE + RTEMS_MINIMUM_STACK_SIZE, \ + TASK_ATTRIBUTES) + +#define TASK_ATTRIBUTES RTEMS_FLOATING_POINT + +// test specific global vars +#define TASK_COUNT (TEST_PROCESSORS - 1) + +#define ITOA_STR_SIZE (8 * sizeof(int) + 1) + +// 1 (microsecond) is equal to (2^64 - 1)*10^-6 (64 bit fraction seconds). +// Using 7 significant figures (enough to preserve microsecond precision) this is 18446740000000. +#define FRAC_BINTIME_TO_USEC_CONV_FACTOR 18446740000000LLU + +#define NUM_TEST_FUNCTIONS 15 +#define RELATIVE_SLEEP 0 +#define FUNCTION_WAIT_MICROSECONDS 100 +#define FUNCTION_WAIT_NANOSECONDS (FUNCTION_WAIT_MICROSECONDS * 1000) +// Acceptable difference returned by subsequent clock-related function call +#define MARGIN_USEC 8 + +static rtems_id start_barrier; +static rtems_id TASK_COUNTER_SEMAPHORE; + +typedef struct timespec timespec_t; +typedef struct bintime bintime_t; +typedef struct timeval timeval_t; + +typedef enum +{ + TIMESPEC, + BINTIME, + TIMEVAL +} struct_type; + +// Create storage areas for each worker, using task construct forces +RTEMS_ALIGNED(RTEMS_TASK_STORAGE_ALIGNMENT) +static char calc_task_storage[TASK_COUNT][TASK_STORAGE_SIZE]; + +/* debug +RTEMS_ALIGNED(RTEMS_TASK_STORAGE_ALIGNMENT) +static uint32_t task_processor[TASK_COUNT]; +*/ + +RTEMS_ALIGNED(RTEMS_TASK_STORAGE_ALIGNMENT) +static uint32_t task_before_mandelbrot[TASK_COUNT]; + +RTEMS_ALIGNED(RTEMS_TASK_STORAGE_ALIGNMENT) +static uint32_t task_after_mandelbrot[TASK_COUNT]; + +/* + * Find whether later time struct is within margin_usec of same type time struct earlier. + */ +static bool close_in_time(void *earlier, void *later, uint32_t margin_usec, struct_type type) +{ + bool ret = false; + uint64_t earlier_total, later_total; + + /* + char str[ITOA_STR_SIZE]; + */ + + switch(type) + { + case TIMESPEC: + earlier_total = (uint64_t)(((timespec_t *)earlier)->tv_sec * 1000000 + ((timespec_t *)earlier)->tv_nsec / 1000); + later_total = (uint64_t)(((timespec_t *)later)->tv_sec * 1000000 + ((timespec_t *)later)->tv_nsec / 1000); + /* debug + print_string("timespec earlier: "); + print_string(itoa((int)earlier_total, &str[0], 10)); + print_string("\n"); + print_string("timespec later: "); + print_string(itoa((int)later_total, &str[0], 10)); + print_string("\n"); + */ + break; + case BINTIME: + earlier_total = (uint64_t)(((bintime_t *)earlier)->sec * 1000000 + ((bintime_t *)earlier)->frac / FRAC_BINTIME_TO_USEC_CONV_FACTOR); + later_total = (uint64_t)(((bintime_t *)later)->sec * 1000000 + ((bintime_t *)later)->frac / FRAC_BINTIME_TO_USEC_CONV_FACTOR); + /* debug + print_string("bintime earlier: "); + print_string(itoa((int)earlier_total, &str[0], 10)); + print_string("\n"); + print_string("bintime later: "); + print_string(itoa((int)later_total, &str[0], 10)); + print_string("\n"); + */ + break; + case TIMEVAL: + earlier_total = (uint64_t)(((timeval_t *)earlier)->tv_sec * 1000000 + ((timeval_t *)earlier)->tv_usec); + later_total = (uint64_t)(((timeval_t *)later)->tv_sec * 1000000 + ((timeval_t *)later)->tv_usec); + /* debug + print_string("timeval earlier: "); + print_string(itoa((int)earlier_total, &str[0], 10)); + print_string("\n"); + print_string("timeval later: "); + print_string(itoa((int)later_total, &str[0], 10)); + print_string("\n"); + */ + break; + default: + return ret; + } + + if(earlier_total + margin_usec >= later_total) + ret = true; + + return ret; +} + +static void calc_task_function(rtems_task_argument arg) +{ + uint8_t tile = (uint8_t) arg; + struct timespec uptime; + + WaitAtBarrier(start_barrier); + + rtems_clock_get_uptime(&uptime); + task_before_mandelbrot[tile - 1] = (uint32_t) (uptime.tv_sec * 1000000 + uptime.tv_nsec/1000); + + mandelbrot_tile(tile, TASK_COUNT); + + rtems_clock_get_uptime(&uptime); + task_after_mandelbrot[tile - 1] = (uint32_t) (uptime.tv_sec * 1000000 + uptime.tv_nsec/1000); + + // Task has finished so increment counter + ReleaseCounterSemaphore(TASK_COUNTER_SEMAPHORE); + SuspendSelf(); +} + +static void Init(rtems_task_argument arg) +{ + (void)arg; + /* debug + uint32_t main_task_processor; + */ + uint32_t functions_start, functions_end; + rtems_id task_id[TASK_COUNT]; + char ch; + /* debug + str[ITOA_STR_SIZE]; + */ + struct timespec uptime, function_wait; + uint8_t wait = 0; + uint8_t unaffected[NUM_TEST_FUNCTIONS]; + + function_wait.tv_sec = 0; + function_wait.tv_nsec = FUNCTION_WAIT_NANOSECONDS; + memset(&unaffected, 0, NUM_TEST_FUNCTIONS); + + TASK_COUNTER_SEMAPHORE = CreateCounterSemaphore(rtems_build_name('T', 'C', 'S', '0'), 0); + + rtems_task_config calc_task_config = { + .initial_priority = PRIO_VERY_HIGH, + .storage_size = TASK_STORAGE_SIZE, + .maximum_thread_local_storage_size = MAX_TLS_SIZE, + .initial_modes = RTEMS_DEFAULT_MODES, + .attributes = TASK_ATTRIBUTES}; + + start_barrier = CreateAutomaticBarrier(TASK_COUNT + 1); + + for (uint32_t i = 0; i < TASK_COUNT; i++) + { + ch = '0' + i; + + calc_task_config.name = rtems_build_name('R', 'U', 'N', ch); + calc_task_config.storage_area = &calc_task_storage[i][0]; + + task_id[i] = DoCreateTask(calc_task_config); + StartTask(task_id[i], calc_task_function, (void *)(i + 1)); + } + + /* + * Start execution of clock functions following formula of: + * Defined behaviour + * Undefined behaviour + * Defined behaviour + */ + + timespec_t ts_first, ts_third; + timespec_t *ts_null = NULL; + + bintime_t bt_first, bt_third; + bintime_t *bt_null = NULL; + + timeval_t tv_first, tv_third; + timeval_t *tv_null = NULL; + + WaitAtBarrier(start_barrier); + + /* debug + main_task_processor = rtems_scheduler_get_processor(); + */ + + // Wait FUNCTION_WAIT_MICROSECONDS microseconds to ensure function calls are concurrent with mandelbrot calculation + clock_nanosleep(CLOCK_MONOTONIC, RELATIVE_SLEEP, &function_wait, NULL); + + rtems_clock_get_uptime(&uptime); + functions_start = (uint32_t) (uptime.tv_sec* 1000000 + uptime.tv_nsec/1000); + + /* + * Check that BOOT_TIME subsequent call is not affected by undefined call. + * Boot time should not change so if the third call does not match the first + * an error has been found. + */ + rtems_clock_get_boot_time(&ts_first); + rtems_clock_get_boot_time_bintime(&bt_first); + rtems_clock_get_boot_time_timeval(&tv_first); + + rtems_clock_get_boot_time(ts_null); + rtems_clock_get_boot_time(&ts_third); + if ((ts_third.tv_sec == ts_first.tv_sec) && (ts_third.tv_nsec == ts_first.tv_nsec)) + unaffected[0] = true; + + rtems_clock_get_boot_time_bintime(bt_null); + rtems_clock_get_boot_time_bintime(&bt_third); + if ((bt_third.sec == bt_first.sec) && (bt_third.frac == bt_first.frac)) + unaffected[1] = true; + + rtems_clock_get_boot_time_timeval(tv_null); + rtems_clock_get_boot_time_timeval(&tv_third); + if ((tv_third.tv_sec == tv_first.tv_sec) && (tv_third.tv_usec == tv_first.tv_usec)) + unaffected[2] = true; + + /* + * Check that CLOCK_MONOTONIC subsequent call is not affected by undefined call. + * If third call is not close in time to the first call an error has been found. + */ + rtems_clock_get_monotonic(&ts_first); + rtems_clock_get_monotonic(ts_null); + rtems_clock_get_monotonic(&ts_third); + if(close_in_time(&ts_first, &ts_third, MARGIN_USEC, TIMESPEC)) + unaffected[3] = true; + + /* debug + print_string("clock_get_monotonic ts first tv_sec: "); + print_string(itoa(ts_first.tv_sec, &str[0], 10)); + print_string("\n"); + print_string("clock_get_monotonic ts first tv_nsec: "); + print_string(itoa(ts_first.tv_nsec, &str[0], 10)); + print_string("\n"); + print_string("clock_get_monotonic ts third tv_sec: "); + print_string(itoa(ts_third.tv_sec, &str[0], 10)); + print_string("\n"); + print_string("clock_get_monotonic ts third tv_nsec: "); + print_string(itoa(ts_third.tv_nsec, &str[0], 10)); + print_string("\n"); + */ + + rtems_clock_get_monotonic_bintime(&bt_first); + rtems_clock_get_monotonic_bintime(bt_null); + rtems_clock_get_monotonic_bintime(&bt_third); + if(close_in_time(&bt_first, &bt_third, MARGIN_USEC, BINTIME)) + unaffected[4] = true; + + /* debug + print_string("clock_get_monotonic bt first sec: "); + print_string(itoa(bt_first.sec, &str[0], 10)); + print_string("\n"); + print_string("clock_get_monotonic bt first frac: "); + print_string(itoa(bt_first.frac, &str[0], 10)); + print_string("\n"); + print_string("clock_get_monotonic bt third sec: "); + print_string(itoa(bt_third.sec, &str[0], 10)); + print_string("\n"); + print_string("clock_get_monotonic bt third frac: "); + print_string(itoa(bt_third.frac, &str[0], 10)); + print_string("\n"); + */ + + rtems_clock_get_monotonic_timeval(&tv_first); + rtems_clock_get_monotonic_timeval(tv_null); + rtems_clock_get_monotonic_timeval(&tv_third); + if(close_in_time(&tv_first, &tv_third, MARGIN_USEC, TIMEVAL)) + unaffected[5] = true; + + /* debug + print_string("clock_get_monotonic tv first tv_sec: "); + print_string(itoa(tv_first.tv_sec, &str[0], 10)); + print_string("\n"); + print_string("clock_get_monotonic tv first tv_nsec: "); + print_string(itoa(tv_first.tv_usec, &str[0], 10)); + print_string("\n"); + print_string("clock_get_monotonic tv third tv_sec: "); + print_string(itoa(tv_third.tv_sec, &str[0], 10)); + print_string("\n"); + print_string("clock_get_monotonic tv third tv_nsec: "); + print_string(itoa(tv_third.tv_usec, &str[0], 10)); + print_string("\n"); + */ + + /* + * Check that coarse CLOCK_MONOTONIC subsequent call is not affected by undefined call. + * If third call is not close in time to the first call an error has been found. + */ + rtems_clock_get_monotonic_coarse(&ts_first); + rtems_clock_get_monotonic_coarse(ts_null); + rtems_clock_get_monotonic_coarse(&ts_third); + if(close_in_time(&ts_first, &ts_third, MARGIN_USEC, TIMESPEC)) + unaffected[6] = true; + + rtems_clock_get_monotonic_coarse_bintime(&bt_first); + rtems_clock_get_monotonic_coarse_bintime(bt_null); + rtems_clock_get_monotonic_coarse_bintime(&bt_third); + if(close_in_time(&bt_first, &bt_third, MARGIN_USEC, BINTIME)) + unaffected[7] = true; + + rtems_clock_get_monotonic_coarse_timeval(&tv_first); + rtems_clock_get_monotonic_coarse_timeval(tv_null); + rtems_clock_get_monotonic_coarse_timeval(&tv_third); + if(close_in_time(&tv_first, &tv_third, MARGIN_USEC, TIMEVAL)) + unaffected[8] = true; + + /* + * Check that CLOCK_REALTIME subsequent call is not affected by undefined call. + * If third call is not close in time to the first call an error has been found. + */ + rtems_clock_get_realtime(&ts_first); + rtems_clock_get_realtime(ts_null); + rtems_clock_get_realtime(&ts_third); + if(close_in_time(&ts_first, &ts_third, MARGIN_USEC, TIMESPEC)) + unaffected[9] = true; + + rtems_clock_get_realtime_bintime(&bt_first); + rtems_clock_get_realtime_bintime(bt_null); + rtems_clock_get_realtime_bintime(&bt_third); + if(close_in_time(&bt_first, &bt_third, MARGIN_USEC, BINTIME)) + unaffected[10] = true; + + rtems_clock_get_realtime_timeval(&tv_first); + rtems_clock_get_realtime_timeval(tv_null); + rtems_clock_get_realtime_timeval(&tv_third); + if(close_in_time(&tv_first, &tv_third, MARGIN_USEC, TIMEVAL)) + unaffected[11] = true; + + /* + * Check that coarse CLOCK_REALTIME subsequent call is not affected by undefined call. + * If third call is not close in time to the first call an error has been found. + */ + rtems_clock_get_realtime_coarse(&ts_first); + rtems_clock_get_realtime_coarse(ts_null); + rtems_clock_get_realtime_coarse(&ts_third); + if(close_in_time(&ts_first, &ts_third, MARGIN_USEC, TIMESPEC)) + unaffected[12] = true; + + rtems_clock_get_realtime_coarse_bintime(&bt_first); + rtems_clock_get_realtime_coarse_bintime(bt_null); + rtems_clock_get_realtime_coarse_bintime(&bt_third); + if(close_in_time(&bt_first, &bt_third, MARGIN_USEC, BINTIME)) + unaffected[13] = true; + + rtems_clock_get_realtime_coarse_timeval(&tv_first); + rtems_clock_get_realtime_coarse_timeval(tv_null); + rtems_clock_get_realtime_coarse_timeval(&tv_third); + if(close_in_time(&tv_first, &tv_third, MARGIN_USEC, TIMEVAL)) + unaffected[14] = true; + + rtems_clock_get_uptime(&uptime); + functions_end = (uint32_t) (uptime.tv_sec* 1000000 + uptime.tv_nsec/1000) ; + + // Wait for all tasks to complete + while (wait < TASK_COUNT) + { + ObtainCounterSemaphore(TASK_COUNTER_SEMAPHORE); + wait++; + } + + // Ensure clock-based functions were executed at the same time as the mandlebrot set + uint32_t latest_task_start = 0; + uint32_t earliest_task_finish = -1; + + for(uint32_t task = 0; task < TASK_COUNT; task++) + { + if(task_before_mandelbrot[task] > latest_task_start) + latest_task_start = task_before_mandelbrot[task]; + + if(task_after_mandelbrot[task] < earliest_task_finish) + earliest_task_finish = task_after_mandelbrot[task]; + } + + if(functions_start > latest_task_start && functions_end < earliest_task_finish) + { + print_string("Functions and mandelbrot executed concurrently: true\n\n"); + } + else + { + print_string("Functions and mandelbrot executed concurrently: false\n\n"); + } + + if(unaffected[0] && unaffected[1] && unaffected[2]) + { + print_string("Boot time subsequent call unaffected: true\n"); + } + else + { + print_string("Boot time subsequent call unaffected: false\n"); + } + + if(unaffected[3] && unaffected[4] && unaffected[5]) + { + print_string("Clock monotonic subsequent call unaffected: true\n"); + } + else + { + print_string("Clock monotonic subsequent call unaffected: false\n"); + } + + if(unaffected[6] && unaffected[7] && unaffected[8]) + { + print_string("Coarse clock monotonic subsequent call unaffected: true\n"); + } + else + { + print_string("Coarse clock monotonic subsequent call unaffected: false\n"); + } + + if(unaffected[9] && unaffected[10] && unaffected[11]) + { + print_string("Clock realtime subsequent call unaffected: true\n"); + } + else + { + print_string("Clock realtime subsequent call unaffected: false\n"); + } + + if(unaffected[12] && unaffected[13] && unaffected[14]) + { + print_string("Coarse clock realtime subsequent call unaffected: true\n"); + } + else + { + print_string("Coarse clock realtime subsequent call unaffected: false\n"); + } + + print_test_results(); + /* debug + print_string("Functions processor: "); + print_string(itoa(main_task_processor, &str[0], 10)); + print_string("\n"); + print_string("Functions start time: "); + print_string(itoa(functions_start, &str[0], 10)); + print_string("\n"); +// -------------------------------------------------------------------------------------------- + print_string("\n\n\n"); + print_string("CheckPoints:"); + print_string("\n|TILE |PROC | START | END |TIME SPENT| (us)"); + print_string("\n"); + for (uint32_t task = 0; task < TASK_COUNT; task++) + { + print_string("| "); + print_string(itoa(task+1, &str[0], 10)); + print_string(" | "); + print_string(itoa(task_processor[task], &str[0], 10)); + print_string(" | "); + print_string(itoa(task_before_mandelbrot[task], &str[0], 10)); + print_string(" | "); + print_string(itoa(task_after_mandelbrot[task], &str[0], 10)); + print_string(" | "); + print_string(itoa(task_after_mandelbrot[task]-task_before_mandelbrot[task], &str[0], 10)); + print_string(" |\n"); + } + print_string("\n\nTICKS Per second: "); + print_string(itoa(rtems_clock_get_ticks_per_second(), &str[0], 10)); + print_string("\n\n"); +// -------------------------------------------------------------------------------------------- + print_string("Functions end time: "); + print_string(itoa(functions_end, &str[0], 10)); + print_string("\n"); + + for(uint8_t i = 0; i < NUM_TEST_FUNCTIONS; i++) + { + print_string("unaffected "); + print_string(itoa(i, &str[0], 10)); + print_string(": "); + print_string(itoa(unaffected[i], &str[0], 10)); + print_string("\n"); + } + */ + + for (uint32_t i = 0; i < TASK_COUNT; i++) + { + DeleteTask(task_id[i]); + } + + DeleteMutex(TASK_COUNTER_SEMAPHORE); + DeleteBarrier(start_barrier); + + rtems_fatal(RTEMS_FATAL_SOURCE_EXIT, 0); +} + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER + +#define CONFIGURE_MAXIMUM_PROCESSORS TEST_PROCESSORS + +#define CONFIGURE_MAXIMUM_SEMAPHORES 1 + +#define CONFIGURE_MAXIMUM_BARRIERS 1 + +#define CONFIGURE_MAXIMUM_TASKS (TEST_PROCESSORS + 1) + +#define CONFIGURE_SCHEDULER_EDF_SMP + +#define CONFIGURE_MINIMUM_TASK_STACK_SIZE RTEMS_MINIMUM_STACK_SIZE + CPU_STACK_ALIGNMENT + +#define CONFIGURE_EXTRA_TASK_STACKS RTEMS_MINIMUM_STACK_SIZE + +#define CONFIGURE_INIT_TASK_CONSTRUCT_STORAGE_SIZE 2 * TASK_STORAGE_SIZE + +#define CONFIGURE_MINIMUM_TASKS_WITH_USER_PROVIDED_STORAGE \ + CONFIGURE_MAXIMUM_TASKS + +#define CONFIGURE_MICROSECONDS_PER_TICK 1000 + +#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 0 + +#define CONFIGURE_DISABLE_NEWLIB_REENTRANCY + +#define CONFIGURE_APPLICATION_DISABLE_FILESYSTEM + +#define CONFIGURE_MAXIMUM_THREAD_LOCAL_STORAGE_SIZE MAX_TLS_SIZE + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT_TASK_ATTRIBUTES (RTEMS_SYSTEM_TASK | TASK_ATTRIBUTES) + +#define CONFIGURE_INIT_TASK_INITIAL_MODE + +#define CONFIGURE_INIT + +#include <rtems/confdefs.h> diff --git a/testsuites/isvv/16_task_manager_undefined_behaviour/task_manager_undefined_behaviour.c b/testsuites/isvv/16_task_manager_undefined_behaviour/task_manager_undefined_behaviour.c new file mode 100644 index 0000000000..1a7cc4f928 --- /dev/null +++ b/testsuites/isvv/16_task_manager_undefined_behaviour/task_manager_undefined_behaviour.c @@ -0,0 +1,468 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 2022 Critical Software SA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <rtems/bspIo.h> +#include "../shared/utils.h" +#include "../shared/isvv_rtems_aux.h" + +/** + * + * @brief Tests impact of undefined behaviour for task manager + * + * This test case performs the calculation of the Mandelbrot set in parallel with + * execution of task related functions with conditions which may lead to + * undefined behaviour, and seeks to clarify the impact of them. + * + */ + +#define ITOA_STR_SIZE (8 * sizeof(int) + 1) + +#define MAX_TLS_SIZE RTEMS_ALIGN_UP(64, RTEMS_TASK_STORAGE_ALIGNMENT) + +#define TASK_STORAGE_SIZE \ + RTEMS_TASK_STORAGE_SIZE( \ + MAX_TLS_SIZE + RTEMS_MINIMUM_STACK_SIZE, \ + TASK_ATTRIBUTES) + +#define TASK_ATTRIBUTES RTEMS_FLOATING_POINT + +// We want to create mandelbrot executions whilst our task manager functions +// are executed on another core +#define TASK_COUNT TEST_PROCESSORS +#define CALCULATION_TASKS ((TASK_COUNT) - 1) + +// Timing related variables to ensure concurrent executions +#define RELATIVE_SLEEP 0 +#define FUNCTION_WAIT_MICROSECONDS 10 +#define FUNCTION_WAIT_NANOSECONDS (FUNCTION_WAIT_MICROSECONDS * 1000) + +static rtems_id start_barrier; +static rtems_id TASK_COUNTER_SEMAPHORE; + +typedef struct +{ + rtems_id calc_task_id[CALCULATION_TASKS]; + rtems_id undefined_task_id; + uint32_t functions_start, functions_end; + bool expected_timeslice_calls; + bool expected_ASR_calls; + bool expected_preempt_calls; + bool expected_interrupt_calls; + bool expected_combination_calls; + bool preempt_not_impl; + bool interrupts_not_impl; +} test_context; + +// Create storage areas for each worker, using task construct forces +RTEMS_ALIGNED(RTEMS_TASK_STORAGE_ALIGNMENT) +static char task_storage[TASK_COUNT][TASK_STORAGE_SIZE]; + +// Storage space for timings +RTEMS_ALIGNED(RTEMS_TASK_STORAGE_ALIGNMENT) +static uint32_t task_before_mandelbrot[CALCULATION_TASKS]; + +RTEMS_ALIGNED(RTEMS_TASK_STORAGE_ALIGNMENT) +static uint32_t task_after_mandelbrot[CALCULATION_TASKS]; + +static void calc_task_function(rtems_task_argument *tile) +{ + uint8_t tile_n = (uint8_t) *tile; + struct timespec uptime; + + WaitAtBarrier(start_barrier); + + // Check time function begins execution of mandelbrot executions + rtems_clock_get_uptime(&uptime); + task_before_mandelbrot[tile_n - 1] = (uint32_t)(uptime.tv_sec * 1000000 + uptime.tv_nsec / 1000); + + mandelbrot_tile(tile_n, CALCULATION_TASKS); + + // Check time function finishes execution of mandelbrot executions + rtems_clock_get_uptime(&uptime); + task_after_mandelbrot[tile_n - 1] = (uint32_t)(uptime.tv_sec * 1000000 + uptime.tv_nsec / 1000); + + // Task has finished so increment counter + ReleaseCounterSemaphore(TASK_COUNTER_SEMAPHORE); + rtems_task_exit(); +} + +static void undefined_behaviour_task(rtems_task_argument arg) +{ + test_context *ctx = (test_context *)arg; + struct timespec uptime, function_wait; + + WaitAtBarrier(start_barrier); + + // Wait for 10us to ensure concurrent executions + function_wait.tv_sec = 0; + function_wait.tv_nsec = FUNCTION_WAIT_NANOSECONDS; + clock_nanosleep(CLOCK_MONOTONIC, 0, &function_wait, NULL); + + rtems_clock_get_uptime(&uptime); + ctx->functions_start = (uint32_t)(uptime.tv_sec * 1000000 + uptime.tv_nsec / 1000); + + /* + * Start execution of task-manager related functions following formula of: + * + * Defined behaviour + * Undefined behaviour + * Defined behaviour + * + * NOTE REGARDING SPECIFICATION: + * This test of undefined behaviour shall be conducted for: + * - rtems_task_mode() + * This test of undefined behaviour shall NOT be conducted for: + * - rtems_task_create() + * As confirmed in RTEMS-SMP-VAL-001 implementation in the space profile for this directive + * is not allowed, and therefore testing is defunct. + * + * To check the current status of the task execution mode, we must call rtems_task_mode + * passing in RTEMS_CURRENT_MODE as the mask, which causes the first parameter to be ignored + * and returns the state in the third parameter. As such we will use this to check possible + * invalidation of state from undefined behaviour calls with appropriate assertions. + * + * When we set mutually exclusive options which are combined with a bitwise OR, what we see + * is the non-default option being applied. Where setting certain options isn't possible due + * to the SMP and space profile configuration, we will assert that appropriate errors being + * thrown, and that our configuration hasn't been invalidated or corrupted. + */ + + // Define test specific variables + rtems_mode mode_set; + rtems_status_code sc; + + const rtems_mode TIMESLICE_MODE = RTEMS_TIMESLICE; + const rtems_mode NO_ASR_MODE = RTEMS_NO_ASR; + const rtems_mode NO_ASR_TIMESLICE_MODE = RTEMS_TIMESLICE | RTEMS_NO_ASR; + + /* + * TIMESLICE + */ + + SetTaskMode(RTEMS_NO_TIMESLICE, RTEMS_TIMESLICE_MASK, mode_set); + mode_set = GetTaskMode(); + ctx->expected_timeslice_calls &= ASSERT_TASK_MODES_EQ(mode_set, RTEMS_DEFAULT_MODES); + + // INVALID CALL + SetTaskMode(RTEMS_NO_TIMESLICE | RTEMS_TIMESLICE, RTEMS_TIMESLICE_MASK, mode_set); + mode_set = GetTaskMode(); + ctx->expected_timeslice_calls &= ASSERT_TASK_MODES_EQ(mode_set, TIMESLICE_MODE); + + SetTaskMode(RTEMS_NO_TIMESLICE, RTEMS_TIMESLICE_MASK, mode_set); + mode_set = GetTaskMode(); + ctx->expected_timeslice_calls &= ASSERT_TASK_MODES_EQ(mode_set, RTEMS_DEFAULT_MODES); + + /* + * Asynchronous Signal Routine (ASR) + */ + + // First with ASR being set + + SetTaskMode(RTEMS_ASR, RTEMS_ASR_MASK, mode_set); + mode_set = GetTaskMode(); + ctx->expected_ASR_calls &= ASSERT_TASK_MODES_EQ(mode_set, RTEMS_DEFAULT_MODES); + + // INVALID CALL + SetTaskMode(RTEMS_NO_ASR | RTEMS_ASR, RTEMS_ASR_MASK, mode_set); + mode_set = GetTaskMode(); + ctx->expected_ASR_calls &= ASSERT_TASK_MODES_EQ(mode_set, NO_ASR_MODE); + + SetTaskMode(RTEMS_ASR, RTEMS_ASR_MASK, mode_set); + mode_set = GetTaskMode(); + ctx->expected_ASR_calls &= ASSERT_TASK_MODES_EQ(mode_set, RTEMS_DEFAULT_MODES); + + // Then with NO_ASR being set + + SetTaskMode(RTEMS_NO_ASR, RTEMS_ASR_MASK, mode_set); + mode_set = GetTaskMode(); + ctx->expected_ASR_calls &= ASSERT_TASK_MODES_EQ(mode_set, NO_ASR_MODE); + + // INVALID CALL + SetTaskMode(RTEMS_NO_ASR | RTEMS_ASR, RTEMS_ASR_MASK, mode_set); + mode_set = GetTaskMode(); + ctx->expected_ASR_calls &= ASSERT_TASK_MODES_EQ(mode_set, NO_ASR_MODE); + + SetTaskMode(RTEMS_ASR, RTEMS_ASR_MASK, mode_set); + mode_set = GetTaskMode(); + ctx->expected_ASR_calls &= ASSERT_TASK_MODES_EQ(mode_set, RTEMS_DEFAULT_MODES); + + /* + * PREEMPT + * + * Disabling Preemption on SMP systems is not possible, and any attempt to do so results in an + * RTEMS_NOT_IMPLEMENTED error. + */ + + SetTaskMode(RTEMS_PREEMPT, RTEMS_PREEMPT_MASK, mode_set); + mode_set = GetTaskMode(); + ctx->expected_preempt_calls &= ASSERT_TASK_MODES_EQ(mode_set, RTEMS_DEFAULT_MODES); + + // INVALID CALL + // We are expecting RTEMS_NOT_IMPLEMENTED due to interrupts not being enabled so don't assert success + sc = rtems_task_mode(RTEMS_PREEMPT | RTEMS_NO_PREEMPT, RTEMS_PREEMPT_MASK, &mode_set); + ctx->preempt_not_impl = (RTEMS_NOT_IMPLEMENTED == sc); + mode_set = GetTaskMode(); + ctx->expected_preempt_calls &= ASSERT_TASK_MODES_EQ(mode_set, RTEMS_DEFAULT_MODES); + + SetTaskMode(RTEMS_PREEMPT, RTEMS_PREEMPT_MASK, mode_set); + mode_set = GetTaskMode(); + ctx->expected_preempt_calls &= ASSERT_TASK_MODES_EQ(mode_set, RTEMS_DEFAULT_MODES); + + /* + * INTERRUPT LEVEL + * + * RTEMS allows up to 256 values depending on processor architecture to set the interrupt level, + * where a level of 0 indicates all interrupts are disabled (identical regardless of architecture) + * and progressive levels indicating more and more interrupts enabled. + * + * According to RTEMS CPU Architecture Documentation, maskable interrupts allowed range for the + * LEON3 / LEON4 processors is from 0 to 15 (16 levels, where 0 indicates all interrupts disabled). + * + * However in the RTEMS Qualification SRS for both GR712 and GR740, there exists a constraint + * (spec:/constraint/interrupts-disabled-smp) which states that 'Where the system was built with + * SMP support enabled, maskable interrupts are disabled for the executing thread.' + * + * Therefore as we are using SMP configuration for these tests, trying to combine mutually exclusive + * attributes, in this case enabling various interrupt levels through the maskable interrupt passed into + * the mode_set for this task with values e.g. 0 | 1 | 2 violates this constant and will result in an + * RTEMS_NOT_IMPLEMENTED error. This is the extent to which we can provide + * assertions on the correctness of this undefined behaviour. + */ + + SetTaskMode(RTEMS_INTERRUPT_LEVEL(0), RTEMS_INTERRUPT_MASK, mode_set); + mode_set = GetTaskMode(); + ctx->expected_interrupt_calls &= ASSERT_TASK_MODES_EQ(mode_set, RTEMS_DEFAULT_MODES); + + // INVALID CALL + // We are expecting RTEMS_NOT_IMPLEMENTED due to interrupts not being enabled so don't assert success + sc = rtems_task_mode(RTEMS_INTERRUPT_LEVEL(1) | RTEMS_INTERRUPT_LEVEL(2) | RTEMS_INTERRUPT_LEVEL(3), RTEMS_INTERRUPT_MASK, &mode_set); + ctx->interrupts_not_impl = (RTEMS_NOT_IMPLEMENTED == sc); + mode_set = GetTaskMode(); + ctx->expected_interrupt_calls &= ASSERT_TASK_MODES_EQ(mode_set, RTEMS_DEFAULT_MODES); + + SetTaskMode(RTEMS_INTERRUPT_LEVEL(0), RTEMS_INTERRUPT_MASK, mode_set); + mode_set = GetTaskMode(); + ctx->expected_interrupt_calls &= ASSERT_TASK_MODES_EQ(mode_set, RTEMS_DEFAULT_MODES); + + /* + * COMBINATIONS OF MUTUALLY EXCLUSIVE & MUTUALLY INCLUSIVE ATTRIBUTES + */ + + SetTaskMode(RTEMS_DEFAULT_MODES, RTEMS_ALL_MODE_MASKS, mode_set); + mode_set = GetTaskMode(); + ctx->expected_combination_calls &= ASSERT_TASK_MODES_EQ(mode_set, RTEMS_DEFAULT_MODES); + + // INVALID CALL + SetTaskMode(RTEMS_NO_ASR | RTEMS_ASR | RTEMS_TIMESLICE | RTEMS_NO_TIMESLICE, RTEMS_ASR_MASK | RTEMS_TIMESLICE_MASK, mode_set); + mode_set = GetTaskMode(); + ctx->expected_combination_calls &= ASSERT_TASK_MODES_EQ(mode_set, NO_ASR_TIMESLICE_MODE); + + SetTaskMode(RTEMS_DEFAULT_MODES, RTEMS_ALL_MODE_MASKS, mode_set); + mode_set = GetTaskMode(); + ctx->expected_combination_calls &= ASSERT_TASK_MODES_EQ(mode_set, RTEMS_DEFAULT_MODES); + + /* + * FINISHED EXECUTION OF TASK RELATED FUNCTIONS + */ + + rtems_clock_get_uptime(&uptime); + ctx->functions_end = (uint32_t)(uptime.tv_sec * 1000000 + uptime.tv_nsec / 1000); + + // Only once this task has finished do we know we can progress + ReleaseCounterSemaphore(TASK_COUNTER_SEMAPHORE); + rtems_task_exit(); +} + +static void Init(rtems_task_argument arg) +{ + (void)arg; + test_context ctx; + uint8_t wait = 0; + uint32_t args[CALCULATION_TASKS] = {0}; + + TASK_COUNTER_SEMAPHORE = CreateCounterSemaphore(rtems_build_name('T', 'C', 'S', '0'), 0); + + // Config for our mandelbrot tile function + rtems_task_config calc_task_config = { + .initial_priority = PRIO_NORMAL, + .storage_size = TASK_STORAGE_SIZE, + .maximum_thread_local_storage_size = MAX_TLS_SIZE, + .initial_modes = RTEMS_DEFAULT_MODES, + .attributes = TASK_ATTRIBUTES}; + + // Create our barrier for mandelbrot tasks + undefined behaviour tasks + start_barrier = CreateAutomaticBarrier(TASK_COUNT); + + // Finish config for our mandelbrot tile functions and start them + for (uint32_t i = 0; i < CALCULATION_TASKS; i++) + { + calc_task_config.name = rtems_build_name('R', 'U', 'N', (char)i); + calc_task_config.storage_area = &task_storage[i][0]; + + ctx.calc_task_id[i] = DoCreateTask(calc_task_config); + args[i] = (i + 1); + + StartTask(ctx.calc_task_id[i], (void *)calc_task_function, (void *)&args[i]); + } + + // Set initial properties to check validity directives and results + ctx.expected_timeslice_calls = ctx.expected_ASR_calls = ctx.expected_preempt_calls = ctx.expected_interrupt_calls = ctx.expected_combination_calls = TRUE; + + // Config our undefined behaviour task and start it + rtems_task_config undef_task_config = { + .name = rtems_build_name('U', 'N', 'D', 'F'), + .initial_priority = PRIO_NORMAL, + .storage_size = TASK_STORAGE_SIZE, + .maximum_thread_local_storage_size = MAX_TLS_SIZE, + .initial_modes = RTEMS_DEFAULT_MODES, + .attributes = TASK_ATTRIBUTES, + .storage_area = &task_storage[TASK_COUNT-1][0]}; + + ctx.undefined_task_id = DoCreateTask(undef_task_config); + StartTask(ctx.undefined_task_id, undefined_behaviour_task, (void *)&ctx); + + // Wait for all tasks to complete + while (wait < TASK_COUNT) + { + ObtainCounterSemaphore(TASK_COUNTER_SEMAPHORE); + wait++; + } + + // Check concurrent executions + uint32_t latest_task_start = 0; + // Wraps around to effectively be maximum allowed value + uint32_t earliest_task_finish = -1; + + for (uint8_t task = 0; task < CALCULATION_TASKS; task++) + { + latest_task_start = MAX(latest_task_start, task_before_mandelbrot[task]); + earliest_task_finish = MIN(earliest_task_finish, task_after_mandelbrot[task]); + } + + print_string("\n\n"); + if ((ctx.functions_start >= latest_task_start && ctx.functions_end <= earliest_task_finish)) + { + print_string("Functions and mandelbrot executed concurrently: true\n\n"); + } + else + { + print_string("Functions and mandelbrot executed concurrently: false\n\n"); + } + + // Check all directives yielded expected results + if (ctx.expected_timeslice_calls && ctx.expected_ASR_calls && ctx.expected_preempt_calls && ctx.expected_timeslice_calls && ctx.expected_combination_calls) + { + print_string("Directives all yielded expected results and configuration is valid: true\n"); + } + else + { + print_string("Directives all yielded expected results and configuration is valid: false\n"); + } + + // Check individual directives themselves + (ctx.expected_timeslice_calls) ? print_string("Timeslice directives: SUCCEEDED\n") : print_string("Timeslice directives: FAILED\n"); + (ctx.expected_ASR_calls) ? print_string("ASR directives: SUCCEEDED\n") : print_string("ASR directives: FAILED\n"); + (ctx.expected_preempt_calls) ? print_string("Preempt directives: SUCCEEDED\n") : print_string("Preempt directives: FAILED\n"); + (ctx.expected_interrupt_calls) ? print_string("Interrupt directives: SUCCEEDED\n") : print_string("Interrupt directives: FAILED\n"); + (ctx.expected_combination_calls) ? print_string("Combination directives: SUCCEEDED\n") : print_string("Combination directives: FAILED\n"); + + // Check status codes returned are expected i.e. disallowed by config + if (ctx.preempt_not_impl) + { + print_string("Status code returned for RTEMS_PREEMPT is expected: true\n"); + } + else + { + print_string("Status code returned for RTEMS_PREEMPT is expected: false\n"); + } + + if (ctx.interrupts_not_impl) + { + print_string("Status code returned for RTEMS_INTERRUPT_LEVEL > 0 is expected: true\n"); + } + else + { + print_string("Status code returned for RTEMS_INTERRUPT_LEVEL > 0 is expected: false\n"); + } + + // Print mandelbrot set + print_test_results(); + + // Perform tidy up operations + rtems_barrier_delete(start_barrier); + rtems_semaphore_delete(TASK_COUNTER_SEMAPHORE); + rtems_fatal(RTEMS_FATAL_SOURCE_EXIT, 0); +} + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER + +#define CONFIGURE_MAXIMUM_PROCESSORS TEST_PROCESSORS + +#define CONFIGURE_MAXIMUM_SEMAPHORES 1 + +// Reduce the priority of the Init task so all other tasks can be schedules to all other cores +#define CONFIGURE_INIT_TASK_PRIORITY PRIO_LOW + +#define CONFIGURE_MAXIMUM_BARRIERS 1 + +#define CONFIGURE_MAXIMUM_TASKS (TEST_PROCESSORS + 1) + +#define CONFIGURE_SCHEDULER_EDF_SMP + +#define CONFIGURE_MINIMUM_TASK_STACK_SIZE RTEMS_MINIMUM_STACK_SIZE + CPU_STACK_ALIGNMENT + +#define CONFIGURE_EXTRA_TASK_STACKS RTEMS_MINIMUM_STACK_SIZE + +#define CONFIGURE_INIT_TASK_CONSTRUCT_STORAGE_SIZE 2 * TASK_STORAGE_SIZE + +#define CONFIGURE_MINIMUM_TASKS_WITH_USER_PROVIDED_STORAGE \ + CONFIGURE_MAXIMUM_TASKS + +#define CONFIGURE_MICROSECONDS_PER_TICK 1000 + +#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 0 + +#define CONFIGURE_DISABLE_NEWLIB_REENTRANCY + +#define CONFIGURE_APPLICATION_DISABLE_FILESYSTEM + +#define CONFIGURE_MAXIMUM_THREAD_LOCAL_STORAGE_SIZE MAX_TLS_SIZE + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT_TASK_ATTRIBUTES (RTEMS_SYSTEM_TASK | TASK_ATTRIBUTES) + +#define CONFIGURE_INIT_TASK_INITIAL_MODE + +#define CONFIGURE_INIT + +#include <rtems/confdefs.h> diff --git a/testsuites/isvv/17_barrier_manager_undefined_behaviour/barrier_manager_undefined_behaviour.c b/testsuites/isvv/17_barrier_manager_undefined_behaviour/barrier_manager_undefined_behaviour.c new file mode 100644 index 0000000000..ddeafe5352 --- /dev/null +++ b/testsuites/isvv/17_barrier_manager_undefined_behaviour/barrier_manager_undefined_behaviour.c @@ -0,0 +1,445 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 2022 Critical Software SA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stddef.h> +#include <stdint.h> +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <rtems/bspIo.h> +#include "../shared/isvv_rtems_aux.h" +#include "../shared/utils.h" +#include <string.h> + +/** + * + * @brief Tests impact of undefined behaviours + * + * This test case performs the calculation of the Mandelbrot set in + * parallel with execution of calls to barriers configured with + * attributes with undefined behaviour. + */ + +#define ITOA_STR_SIZE (8 * sizeof(int) + 1) + +#define MAX_TLS_SIZE RTEMS_ALIGN_UP(64, RTEMS_TASK_STORAGE_ALIGNMENT) + +#define TASK_ATTRIBUTES RTEMS_FLOATING_POINT + +#define TASK_STORAGE_SIZE \ + RTEMS_TASK_STORAGE_SIZE(MAX_TLS_SIZE + RTEMS_MINIMUM_STACK_SIZE, \ + TASK_ATTRIBUTES) + +// test specific global vars +#define TEST_BARRIERS_COUNT 3 + +#define TASK_COUNT TEST_PROCESSORS +#define TOTAL_TILES 64 + +#define EVENT_BARRIER RTEMS_EVENT_5 + +// Timing related variables to ensure concurrent executions +#define FUNCTION_WAIT_MICROSECONDS 10 +#define FUNCTION_WAIT_NANOSECONDS (FUNCTION_WAIT_MICROSECONDS * 1000) + +rtems_event_set event_send[] = {RTEMS_EVENT_1, RTEMS_EVENT_2, RTEMS_EVENT_3, + RTEMS_EVENT_4}; + +typedef struct +{ + rtems_id main_task; + uint8_t ntiles; + uint8_t next_tile; + rtems_id task_id[TASK_COUNT]; + rtems_id tile_queue; + rtems_id problem_barrier_id; + rtems_id test_barriers[TEST_BARRIERS_COUNT]; + uint8_t barrier_task_x; + uint8_t barrier_results[TEST_BARRIERS_COUNT]; +} test_context; + +RTEMS_ALIGNED(RTEMS_TASK_STORAGE_ALIGNMENT) +static char calc_task_storage[TASK_COUNT][TASK_STORAGE_SIZE]; + +RTEMS_ALIGNED(RTEMS_TASK_STORAGE_ALIGNMENT) +static uint32_t task_before_mandelbrot[TASK_COUNT-1]; + +RTEMS_ALIGNED(RTEMS_TASK_STORAGE_ALIGNMENT) +static uint32_t task_after_mandelbrot[TASK_COUNT-1]; + +static void calc_task_function(rtems_task_argument arg) +{ + test_context *ctx; + + ctx = (test_context *)arg; + struct timespec uptime; + + rtems_id local_id = TaskSelfId(); + uint8_t task_idx = 0; + + for (int i = 0; i < TASK_COUNT - 1; i++) + { + if (ctx->task_id[i] == local_id) + { + task_idx = i; + break; + } + } + + WaitAtBarrier(ctx->problem_barrier_id); + + rtems_clock_get_uptime(&uptime); + task_before_mandelbrot[task_idx] = (uint32_t) (uptime.tv_sec * 1000000 + uptime.tv_nsec/1000); + + mandelbrot_tile(task_idx+1, ctx->ntiles); + + rtems_clock_get_uptime(&uptime); + task_after_mandelbrot[task_idx] = (uint32_t) (uptime.tv_sec * 1000000 + uptime.tv_nsec/1000); + + SendEvents(ctx->main_task, event_send[task_idx]); + + SuspendSelf(); +} + +static void barrier_test_task(rtems_task_argument arg) +{ + test_context *ctx; + rtems_status_code sc; + + ctx = (test_context *)arg; + /* char str[ITOA_STR_SIZE]; */ + /* print_string(itoa(ctx->barrier_task_x, &str, 10)); */ + sc = rtems_barrier_wait(ctx->test_barriers[ctx->barrier_task_x], BARRIER_TIMEOUT); + if(sc == RTEMS_SUCCESSFUL) + { + ctx->barrier_results[ctx->barrier_task_x] = 1; + } + else + { + ctx->barrier_results[ctx->barrier_task_x] = 0; + } + + SendEvents(ctx->main_task, EVENT_BARRIER); + SuspendSelf(); +} + +static void Init(rtems_task_argument arg) +{ + (void)arg; + test_context ctx; + uint32_t start_time, end_time, elapsed_time; + char ch; + rtems_event_set received = 0; + rtems_event_set total_events = 0; + char str[ITOA_STR_SIZE]; + rtems_status_code sc; + struct timespec uptime; + uint32_t functions_start = 0, functions_end = 0; + struct timespec function_wait; + + function_wait.tv_sec = 0; + function_wait.tv_nsec = FUNCTION_WAIT_NANOSECONDS; + + memset(ctx.barrier_results, 0, sizeof(ctx.barrier_results)/sizeof(ctx.barrier_results[0])); + ctx.main_task = rtems_task_self(); + ctx.ntiles = TASK_COUNT - 1; + ctx.next_tile = 1; + uint8_t nwaiting = ctx.ntiles; + // create a normal automatic barrier + ctx.problem_barrier_id = CreateAutomaticBarrier(nwaiting); + + start_time = rtems_clock_get_ticks_since_boot(); + rtems_task_config calc_task_config = { + .initial_priority = PRIO_NORMAL, + .storage_size = TASK_STORAGE_SIZE, + .maximum_thread_local_storage_size = + MAX_TLS_SIZE, + .initial_modes = RTEMS_DEFAULT_MODES, + .attributes = TASK_ATTRIBUTES}; + + // create the mandlebrot set using all available cores minus one + for (uint32_t i = 0; i < TASK_COUNT - 1; i++) + { + ch = '0' + i; + calc_task_config.name = rtems_build_name('R', 'U', 'N', ch); + calc_task_config.storage_area = &calc_task_storage[i][0]; + + ctx.task_id[i] = DoCreateTask(calc_task_config); + StartTask(ctx.task_id[i], calc_task_function, &ctx); + total_events += event_send[i]; + } + + // Wait for 10us to ensure concurrent executions + clock_nanosleep(CLOCK_MONOTONIC, 0, &function_wait, NULL); + + rtems_name barrier_name; + rtems_attribute barrier_attributes; + // with the last available core test the undefined behaviour barrier + for (uint32_t i = 0; i < TEST_BARRIERS_COUNT; i++) { + + ctx.barrier_task_x = i; + ch = '0' + i; + + // create a normal automatic barrier, a barrier with undefined behaviour + // and again a normal automatic barrier + if (i==1) { + barrier_attributes = RTEMS_BARRIER_MANUAL_RELEASE | RTEMS_BARRIER_AUTOMATIC_RELEASE; + } + else { + barrier_attributes = RTEMS_BARRIER_AUTOMATIC_RELEASE; + } + + barrier_name = rtems_build_name('B', 'A', 'R', ch); + + sc = rtems_barrier_create(barrier_name, barrier_attributes, 1, + &ctx.test_barriers[i]); + if(sc == RTEMS_SUCCESSFUL) + ctx.barrier_results[ctx.barrier_task_x] = 1; + + calc_task_config.name = rtems_build_name('T', 'A', 'B', ch); + calc_task_config.storage_area = &calc_task_storage[TASK_COUNT - 1][0]; + + ctx.task_id[TASK_COUNT - 1] = DoCreateTask(calc_task_config); + // execute task that will be using the created barriers + if (i == 0) { + rtems_clock_get_uptime(&uptime); + functions_start = (uint32_t)(uptime.tv_sec * 1000000 + uptime.tv_nsec / 1000); + } + + StartTask(ctx.task_id[TASK_COUNT - 1], barrier_test_task, &ctx); + ReceiveAllEvents(EVENT_BARRIER); + DeleteTask(ctx.task_id[TASK_COUNT - 1]); + DeleteBarrier(ctx.test_barriers[i]); + } + rtems_clock_get_uptime(&uptime); + functions_end = (uint32_t) (uptime.tv_sec* 1000000 + uptime.tv_nsec/1000) ; + + while (received != total_events) + { + received |= ReceiveAllEvents(total_events); + } + + end_time = rtems_clock_get_ticks_since_boot(); + + elapsed_time = end_time - start_time; + + uint32_t latest_task_start = 0; + uint32_t earliest_task_finish = -1; + for (uint32_t task = 0; task < TASK_COUNT - 1; task++) { + if (task_before_mandelbrot[task] > latest_task_start) + latest_task_start = task_before_mandelbrot[task]; + if (task_after_mandelbrot[task] < earliest_task_finish) + earliest_task_finish = task_after_mandelbrot[task]; + } + + print_string("\n\n"); + if (functions_start > latest_task_start && functions_end < earliest_task_finish) { + print_string("Functions and normal Mandelbrot executed concurrently: true\n\n"); + } else { + print_string("Functions and normal Mandelbrot executed concurrently: false\n\n"); + } + + print_string("Multicore Elapsed Time normal barrier - "); + print_string(itoa(elapsed_time, &str[0], 10)); + print_string("\n"); + + if(ctx.barrier_results[0] == 1 && ctx.barrier_results[1] == 1 && ctx.barrier_results[2] == 1) + { + print_string("Normal Mandelbrot task barrier functions executed correctly: true\n"); + } + else + { + print_string("Normal Mandelbrot task barrier functions executed correctly: false\n"); + } + + print_test_results(); + + for (uint32_t i = 0; i < TASK_COUNT - 1; i++) + { + DeleteTask(ctx.task_id[i]); + } + + DeleteBarrier(ctx.problem_barrier_id); + // Reset results for second run + memset(ctx.barrier_results, 0, sizeof(ctx.barrier_results)/sizeof(ctx.barrier_results[0])); + latest_task_start = 0; + earliest_task_finish = -1; + total_events = 0; + received = 0; + + // repeat the previous process, but the main task uses a barrier with undefined behaviour + sc = rtems_barrier_create(rtems_build_name('B', 'A', 'R', 'P'), + RTEMS_BARRIER_MANUAL_RELEASE | RTEMS_BARRIER_AUTOMATIC_RELEASE, + nwaiting, &ctx.problem_barrier_id); + ASSERT_SUCCESS(sc); + + start_time = rtems_clock_get_ticks_since_boot(); + for (uint32_t i = 0; i < TASK_COUNT - 1; i++) + { + ch = '0' + i; + calc_task_config.name = rtems_build_name('R', 'U', 'N', ch); + calc_task_config.storage_area = &calc_task_storage[i][0]; + + ctx.task_id[i] = DoCreateTask(calc_task_config); + StartTask(ctx.task_id[i], calc_task_function, &ctx); + total_events += event_send[i]; + } + + // Wait for 10us to ensure concurrent executions + clock_nanosleep(CLOCK_MONOTONIC, 0, &function_wait, NULL); + + for (uint32_t i = 0; i < TEST_BARRIERS_COUNT; i++) { + + ctx.barrier_task_x = i; + ch = '0' + i; + + // create a normal automatic barrier, a barrier with undefined behaviour + // and again a normal automatic barrier + if (i==1) { + barrier_attributes = RTEMS_BARRIER_MANUAL_RELEASE | RTEMS_BARRIER_AUTOMATIC_RELEASE; + } else { + barrier_attributes = RTEMS_BARRIER_AUTOMATIC_RELEASE; + } + + barrier_name = rtems_build_name('B', 'A', 'R', ch); + + sc = rtems_barrier_create(barrier_name, barrier_attributes, 1, + &ctx.test_barriers[i]); + if(sc == RTEMS_SUCCESSFUL) + ctx.barrier_results[ctx.barrier_task_x] = 1; + + calc_task_config.name = rtems_build_name('T', 'A', 'B', ch); + calc_task_config.storage_area = &calc_task_storage[TASK_COUNT - 1][0]; + + ctx.task_id[TASK_COUNT - 1] = DoCreateTask(calc_task_config); + // execute task that will be using the created barriers + if (i == 0) { + rtems_clock_get_uptime(&uptime); + functions_start = (uint32_t)(uptime.tv_sec * 1000000 + uptime.tv_nsec / 1000); + } + + StartTask(ctx.task_id[TASK_COUNT - 1], barrier_test_task, &ctx); + ReceiveAllEvents(EVENT_BARRIER); + DeleteTask(ctx.task_id[TASK_COUNT - 1]); + DeleteBarrier(ctx.test_barriers[i]); + } + + rtems_clock_get_uptime(&uptime); + functions_end = (uint32_t) (uptime.tv_sec* 1000000 + uptime.tv_nsec/1000) ; + + while (received != total_events) + { + received |= ReceiveAllEvents(total_events); + } + + end_time = rtems_clock_get_ticks_since_boot(); + + elapsed_time = end_time - start_time; + + for (uint32_t task = 0; task < TASK_COUNT - 1; task++) { + if (task_before_mandelbrot[task] > latest_task_start) + latest_task_start = task_before_mandelbrot[task]; + if (task_after_mandelbrot[task] < earliest_task_finish) + earliest_task_finish = task_after_mandelbrot[task]; + } + + print_string("\n\n"); + if (functions_start > latest_task_start && functions_end < earliest_task_finish) { + print_string("Functions and undefined Mandelbrot executed concurrently: true\n\n"); + } else { + print_string("Functions and undefined Mandelbrot executed concurrently: false\n\n"); + } + + print_string("\n"); + print_string("Multicore Elapsed Time undefined behaviour barrier - "); + print_string(itoa(elapsed_time, &str[0], 10)); + print_string("\n"); + + if(ctx.barrier_results[0] == 1 && ctx.barrier_results[1] == 1 && ctx.barrier_results[2] == 1) + { + print_string("Undefined Mandelbrot task barrier functions executed correctly: true\n"); + } + else + { + print_string("Undefined Mandelbrot task barrier functions executed correctly: false\n"); + } + + print_test_results(); + + /* ############################################ */ + for (uint32_t i = 0; i < TASK_COUNT - 1; i++) + { + DeleteTask(ctx.task_id[i]); + } + DeleteBarrier(ctx.problem_barrier_id); + + rtems_fatal(RTEMS_FATAL_SOURCE_EXIT, 0); +} + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER + +#define CONFIGURE_MAXIMUM_PROCESSORS TEST_PROCESSORS + +#define CONFIGURE_MAXIMUM_SEMAPHORES 1 + +#define CONFIGURE_MAXIMUM_BARRIERS 5 + +#define CONFIGURE_MAXIMUM_TASKS (TEST_PROCESSORS + 1) + +#define CONFIGURE_SCHEDULER_EDF_SMP + +#define CONFIGURE_MINIMUM_TASK_STACK_SIZE \ + RTEMS_MINIMUM_STACK_SIZE + CPU_STACK_ALIGNMENT + +#define CONFIGURE_EXTRA_TASK_STACKS RTEMS_MINIMUM_STACK_SIZE + +#define CONFIGURE_INIT_TASK_CONSTRUCT_STORAGE_SIZE 2 * TASK_STORAGE_SIZE + +#define CONFIGURE_MINIMUM_TASKS_WITH_USER_PROVIDED_STORAGE \ + CONFIGURE_MAXIMUM_TASKS + +#define CONFIGURE_MICROSECONDS_PER_TICK 1000 + +#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 0 + +#define CONFIGURE_DISABLE_NEWLIB_REENTRANCY + +#define CONFIGURE_APPLICATION_DISABLE_FILESYSTEM + +#define CONFIGURE_MAXIMUM_THREAD_LOCAL_STORAGE_SIZE MAX_TLS_SIZE + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT_TASK_ATTRIBUTES (RTEMS_SYSTEM_TASK | TASK_ATTRIBUTES) + +#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES + +#define CONFIGURE_INIT + +#include <rtems/confdefs.h> diff --git a/testsuites/isvv/18_event_manager_undefined_behaviour/event_manager_undefined_behaviour.c b/testsuites/isvv/18_event_manager_undefined_behaviour/event_manager_undefined_behaviour.c new file mode 100644 index 0000000000..2223b16f77 --- /dev/null +++ b/testsuites/isvv/18_event_manager_undefined_behaviour/event_manager_undefined_behaviour.c @@ -0,0 +1,423 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 2022 Critical Software SA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <rtems/bspIo.h> +#include "../shared/utils.h" +#include "../shared/isvv_rtems_aux.h" + +/** + * + * @brief Tests impact of undefined behaviours for events manager + * + * This test case performs the calculation of the Mandelbrot set in parallel with + * execution of various events-related functions with conditions which lead to + * undefined behaviour + */ + +#define ITOA_STR_SIZE (4 * sizeof(int) + 1) + +#define NUM_TEST_FUNCTIONS 15 +#define RELATIVE_SLEEP 0 +#define FUNCTION_WAIT_MICROSECONDS 100 +#define FUNCTION_WAIT_NANOSECONDS (FUNCTION_WAIT_MICROSECONDS * 1000) + +#define MAX_TLS_SIZE RTEMS_ALIGN_UP(64, RTEMS_TASK_STORAGE_ALIGNMENT) + +#define TASK_STORAGE_SIZE \ + RTEMS_TASK_STORAGE_SIZE( \ + MAX_TLS_SIZE + RTEMS_MINIMUM_STACK_SIZE, \ + TASK_ATTRIBUTES) + +#define TASK_ATTRIBUTES RTEMS_FLOATING_POINT + +// test specific global vars +#define SEND_EVENTS_PERIOD 2 + +// One task for sending events, one task for receiving events, and n-1 calculation tasks +#define TASK_COUNT (TEST_PROCESSORS) + 1 + +// We want to create mandelbrot executions whilst our events manager functions execute +#define CALCULATION_TASKS (TEST_PROCESSORS) - 1 + +#define EVENT_CALLS 15 +const rtems_event_set TEST_EVENTS[EVENT_CALLS] = {RTEMS_EVENT_0, + RTEMS_EVENT_1, + RTEMS_EVENT_2, + RTEMS_EVENT_3, + RTEMS_EVENT_4, + RTEMS_EVENT_5, + RTEMS_EVENT_6, + RTEMS_EVENT_7, + RTEMS_EVENT_8, + RTEMS_EVENT_9, + RTEMS_EVENT_10, + RTEMS_EVENT_11, + RTEMS_EVENT_12, + RTEMS_EVENT_13, + RTEMS_EVENT_14}; + +// Barrier to ensure calculation tasks and undefined behaviour tasks occur concurrently +static rtems_id start_barrier; +static rtems_id TASK_COUNTER_SEMAPHORE; + +typedef struct +{ + rtems_id calc_task_id[CALCULATION_TASKS]; + rtems_id undefined_task_id; + rtems_id send_events_task_id; + uint32_t functions_start, functions_end; + bool is_expected_events; + rtems_event_set received_events_set; +} test_context; + +// Create storage areas for each worker, using task construct forces +RTEMS_ALIGNED(RTEMS_TASK_STORAGE_ALIGNMENT) +static char task_storage[TASK_COUNT][TASK_STORAGE_SIZE]; + +// Storage space for timings +RTEMS_ALIGNED(RTEMS_TASK_STORAGE_ALIGNMENT) +static uint32_t task_before_mandelbrot[CALCULATION_TASKS]; + +RTEMS_ALIGNED(RTEMS_TASK_STORAGE_ALIGNMENT) +static uint32_t task_after_mandelbrot[CALCULATION_TASKS]; + +static void calc_task_function(rtems_task_argument tile) +{ + uint8_t tile_n = (uint8_t)tile; + struct timespec uptime; + + WaitAtBarrier(start_barrier); + + // Check time function begins execution of mandelbrot executions + rtems_clock_get_uptime(&uptime); + task_before_mandelbrot[tile_n - 1] = (uint32_t)(uptime.tv_sec * 1000000 + uptime.tv_nsec / 1000); + + mandelbrot_tile(tile_n, CALCULATION_TASKS); + + // Check time function finishes execution of mandelbrot executions + rtems_clock_get_uptime(&uptime); + task_after_mandelbrot[tile_n - 1] = (uint32_t)(uptime.tv_sec * 1000000 + uptime.tv_nsec / 1000); + + // Task has finished so increment counter + ReleaseCounterSemaphore(TASK_COUNTER_SEMAPHORE); + rtems_task_exit(); +} + +// Task to send an event to test the rtems_receive_event directive under scrutiny +static void send_events_task(rtems_task_argument arg) +{ + test_context *ctx = (test_context *)arg; + + rtems_id period = CreateRateMonotonic(); + + for (uint8_t i = 0; i < EVENT_CALLS; i++) + { + WaitPeriod(period, SEND_EVENTS_PERIOD); + SendEvents(ctx->undefined_task_id, TEST_EVENTS[i]); + } + + // Once all the events that should be sent are sent, perform cleanup activities + rtems_rate_monotonic_delete(period); + rtems_task_exit(); +} + +// When using a directive with NO_WAIT, we need to do ensure an event has been provided from our +// send event task without consuming the event which we want to test with the directive +inline void WaitUntilPendingEvent(void) { + while (!QueryPendingEvents()) {} +} + +static void undefined_behaviour_task(rtems_task_argument arg) +{ + test_context *ctx = (test_context *)arg; + struct timespec uptime, function_wait; + + function_wait.tv_sec = 0; + function_wait.tv_nsec = FUNCTION_WAIT_NANOSECONDS; + + WaitAtBarrier(start_barrier); + + // Wait FUNCTION_WAIT_MICROSECONDS microseconds to ensure function calls are concurrent with mandelbrot calculation + clock_nanosleep(CLOCK_MONOTONIC, RELATIVE_SLEEP, &function_wait, NULL); + + rtems_clock_get_uptime(&uptime); + ctx->functions_start = (uint32_t)(uptime.tv_sec * 1000000 + uptime.tv_nsec / 1000); + + /* Start execution of events related functions following formula of: + * + * Defined behaviour + * Undefined behaviour + * Defined behaviour + * + * Where option_set has certain values combined with a bitwise OR. Some options are mutually exclusive. + * If mutually exclusive options are combined, the behaviour is undefined + * + * What we see when combining these values is the non-default options take precedence and are applied. + * When not provided to the directive, default options are applied. + * However we will specify these regardless for greater clarity. + * + * WaitUntilPendingEvent() is used before directives to ensure an event from our periodic send event + * is ready to be consumed + */ + + // Define test relevant variables + rtems_status_code sc; + rtems_event_set received; + rtems_event_set total_events = 0; + + /* + * Testing RTEMS_EVENT_ALL | RTEMS_EVENT_ANY with RTEMS_WAIT + */ + + total_events |= ReceiveAllEvents(TEST_EVENTS[0]); + + // INVALID CALL + WaitUntilPendingEvent(); + sc = rtems_event_receive(TEST_EVENTS[1], RTEMS_WAIT | RTEMS_EVENT_ALL | RTEMS_EVENT_ANY, RTEMS_NO_TIMEOUT, &received); + ASSERT_SUCCESS_WITHOUT_FAILING(sc); + total_events |= received; + + total_events |= ReceiveAllEvents(TEST_EVENTS[2]); + + /* + * Testing RTEMS_EVENT_ALL | RTEMS_EVENT_ANY with RTEMS_NO_WAIT + */ + + total_events |= ReceiveAllEvents(TEST_EVENTS[3]); + + // INVALID CALL + WaitUntilPendingEvent(); + sc = rtems_event_receive(TEST_EVENTS[4], RTEMS_NO_WAIT | RTEMS_EVENT_ALL | RTEMS_EVENT_ANY, RTEMS_NO_TIMEOUT, &received); + ASSERT_SUCCESS_WITHOUT_FAILING(sc); + total_events |= received; + + total_events |= ReceiveAllEvents(TEST_EVENTS[5]); + + /* + * Testing RTEMS_NO_WAIT | RTEMS_WAIT with RTEMS_EVENT_ALL + */ + + total_events |= ReceiveAllEvents(TEST_EVENTS[6]); + + // INVALID CALL + WaitUntilPendingEvent(); + sc = rtems_event_receive(TEST_EVENTS[7], RTEMS_NO_WAIT | RTEMS_WAIT | RTEMS_EVENT_ALL, RTEMS_NO_TIMEOUT, &received); + ASSERT_SUCCESS_WITHOUT_FAILING(sc); + total_events |= received; + + total_events |= ReceiveAllEvents(TEST_EVENTS[8]); + + /* + * Testing RTEMS_NO_WAIT | RTEMS_WAIT with RTEMS_EVENT_ANY + */ + + total_events |= ReceiveAllEvents(TEST_EVENTS[9]); + + // INVALID CALL + WaitUntilPendingEvent(); + sc = rtems_event_receive(TEST_EVENTS[10], RTEMS_NO_WAIT | RTEMS_WAIT | RTEMS_EVENT_ANY, RTEMS_NO_TIMEOUT, &received); + ASSERT_SUCCESS_WITHOUT_FAILING(sc); + total_events |= received; + + total_events |= ReceiveAllEvents(TEST_EVENTS[11]); + + /* + * Testing RTEMS_NO_WAIT | RTEMS_WAIT | RTEMS_EVENT_ALL | RTEMS_EVENT_ANY + */ + + total_events |= ReceiveAllEvents(TEST_EVENTS[12]); + + // INVALID CALL + WaitUntilPendingEvent(); + sc = rtems_event_receive(TEST_EVENTS[13], RTEMS_NO_WAIT | RTEMS_WAIT | RTEMS_EVENT_ALL | RTEMS_EVENT_ANY, RTEMS_NO_TIMEOUT, &received); + ASSERT_SUCCESS_WITHOUT_FAILING(sc); + total_events |= received; + + total_events |= ReceiveAllEvents(TEST_EVENTS[14]); + + // DEBUG + // print_string("FINISHED EXECUTION OF EVENTS DIRECTIVES\n"); + + // Check total received events against expected events and pass back to main task + ctx->is_expected_events = (total_events == (power(2, EVENT_CALLS) - 1)); + ctx->received_events_set = total_events; + + rtems_clock_get_uptime(&uptime); + ctx->functions_end = (uint32_t)(uptime.tv_sec * 1000000 + uptime.tv_nsec / 1000); + + // Only once this task has finished do we know we can progress + // Task has finished so increment counter + ReleaseCounterSemaphore(TASK_COUNTER_SEMAPHORE); + rtems_task_exit(); +} + +static void Init(rtems_task_argument arg) +{ + (void)arg; + test_context ctx; + char str[ITOA_STR_SIZE]; + uint8_t wait = 0; + + TASK_COUNTER_SEMAPHORE = CreateCounterSemaphore(rtems_build_name('T', 'C', 'S', '0'), 0); + + start_barrier = CreateAutomaticBarrier(CALCULATION_TASKS + 1); + + // Config for our mandelbrot tile function, with priority high as we don't want this to be preempted + rtems_task_config calc_task_config = { + .initial_priority = PRIO_HIGH, + .storage_size = TASK_STORAGE_SIZE, + .maximum_thread_local_storage_size = MAX_TLS_SIZE, + .initial_modes = RTEMS_DEFAULT_MODES, + .attributes = TASK_ATTRIBUTES}; + + // Finish config for our mandelbrot tile functions and start them + for (uint32_t i = 0; i < CALCULATION_TASKS; i++) + { + calc_task_config.name = rtems_build_name('R', 'U', 'N', (char)i); + calc_task_config.storage_area = &task_storage[i][0]; + + ctx.calc_task_id[i] = DoCreateTask(calc_task_config); + StartTask(ctx.calc_task_id[i], calc_task_function, (void *)(i + 1)); + } + + // Config our undefined behaviour task and start it + rtems_task_config undef_task_config = { + .name = rtems_build_name('U', 'N', 'D', 'F'), + .initial_priority = PRIO_NORMAL, + .storage_size = TASK_STORAGE_SIZE, + .maximum_thread_local_storage_size = MAX_TLS_SIZE, + .initial_modes = RTEMS_DEFAULT_MODES, + .attributes = TASK_ATTRIBUTES, + .storage_area = &task_storage[TASK_COUNT - 2][0]}; + + ctx.undefined_task_id = DoCreateTask(undef_task_config); + StartTask(ctx.undefined_task_id, undefined_behaviour_task, (void *)&ctx); + + // Config our event sending task and start it + rtems_task_config send_events_task_config = { + .name = rtems_build_name('T', 'S', 'T', 'E'), + .initial_priority = PRIO_NORMAL, + .storage_size = TASK_STORAGE_SIZE, + .maximum_thread_local_storage_size = MAX_TLS_SIZE, + .initial_modes = RTEMS_DEFAULT_MODES, + .attributes = TASK_ATTRIBUTES, + .storage_area = &task_storage[TASK_COUNT - 1][0]}; + + ctx.send_events_task_id = DoCreateTask(send_events_task_config); + StartTask(ctx.send_events_task_id, send_events_task, (void *)&ctx); + + // Wait for all tasks to complete + while (wait < CALCULATION_TASKS + 1) + { + ObtainCounterSemaphore(TASK_COUNTER_SEMAPHORE); + wait++; + } + + // Check concurrent executions + uint32_t latest_task_start = 0; + // Wraps around to effectively be maximum allowed value + uint32_t earliest_task_finish = -1; + + for (uint8_t task = 0; task < CALCULATION_TASKS; task++) + { + latest_task_start = MAX(latest_task_start, task_before_mandelbrot[task]); + earliest_task_finish = MIN(earliest_task_finish, task_after_mandelbrot[task]); + } + + if ((ctx.functions_start >= latest_task_start && ctx.functions_end <= earliest_task_finish)) + { + print_string("Functions and Mandelbrot executed concurrently: true\n\n"); + } + else + { + print_string("Functions and Mandelbrot executed concurrently: false\n\n"); + } + + (ctx.is_expected_events) ? print_string("EXPECTED EVENTS: TRUE\n") + : print_string("EXPECTED EVENTS: FALSE\n"); + + // Where each binary digit represents a passing / failing test + print_string("CUMULATIVE TOTAL OF EVENTS RECEIVED IN BINARY: "); + print_string(itoa(ctx.received_events_set, &str[0], 2)); + print_string("\n"); + + print_test_results(); + + rtems_fatal(RTEMS_FATAL_SOURCE_EXIT, 0); +} + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER + +#define CONFIGURE_MAXIMUM_PROCESSORS TEST_PROCESSORS + +// Reduce the priority of the Init task so all other tasks can be scheduled to all other cores +#define CONFIGURE_INIT_TASK_PRIORITY PRIO_LOW + +#define CONFIGURE_MAXIMUM_BARRIERS 1 + +#define CONFIGURE_MAXIMUM_SEMAPHORES 1 + +#define CONFIGURE_MAXIMUM_PERIODS 1 + +// Number of Tasks configured + 1 for the INIT task +#define CONFIGURE_MAXIMUM_TASKS (TASK_COUNT) + 1 + +#define CONFIGURE_SCHEDULER_EDF_SMP + +#define CONFIGURE_MINIMUM_TASK_STACK_SIZE RTEMS_MINIMUM_STACK_SIZE + CPU_STACK_ALIGNMENT + +#define CONFIGURE_EXTRA_TASK_STACKS RTEMS_MINIMUM_STACK_SIZE + +#define CONFIGURE_INIT_TASK_CONSTRUCT_STORAGE_SIZE 2 * TASK_STORAGE_SIZE + +#define CONFIGURE_MINIMUM_TASKS_WITH_USER_PROVIDED_STORAGE \ + CONFIGURE_MAXIMUM_TASKS + +#define CONFIGURE_MICROSECONDS_PER_TICK 1000 + +#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 0 + +#define CONFIGURE_DISABLE_NEWLIB_REENTRANCY + +#define CONFIGURE_APPLICATION_DISABLE_FILESYSTEM + +#define CONFIGURE_MAXIMUM_THREAD_LOCAL_STORAGE_SIZE MAX_TLS_SIZE + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT_TASK_ATTRIBUTES (RTEMS_SYSTEM_TASK | TASK_ATTRIBUTES) + +#define CONFIGURE_INIT_TASK_INITIAL_MODE + +#define CONFIGURE_INIT + +#include <rtems/confdefs.h> diff --git a/testsuites/isvv/19_message_manager_undefined_behaviour/message_manager_undefined_behaviour.c b/testsuites/isvv/19_message_manager_undefined_behaviour/message_manager_undefined_behaviour.c new file mode 100644 index 0000000000..b13604dc64 --- /dev/null +++ b/testsuites/isvv/19_message_manager_undefined_behaviour/message_manager_undefined_behaviour.c @@ -0,0 +1,346 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 2022 Critical Software SA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stddef.h> +#include <stdint.h> +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <rtems/bspIo.h> +#include "../shared/isvv_rtems_aux.h" +#include "../shared/utils.h" + +/** + * + * @brief Tests impact of undefined behaviours + * + * This test case performs the calculation of the Mandelbrot set in + * parallel with execution of calls to message queues configured with + * attributes with undefined behaviour. + */ + +#define ITOA_STR_SIZE (8 * sizeof(int) + 1) + +#define MAX_TLS_SIZE RTEMS_ALIGN_UP(64, RTEMS_TASK_STORAGE_ALIGNMENT) + +#define TASK_ATTRIBUTES RTEMS_FLOATING_POINT + +#define TASK_STORAGE_SIZE \ + RTEMS_TASK_STORAGE_SIZE(MAX_TLS_SIZE + RTEMS_MINIMUM_STACK_SIZE, \ + TASK_ATTRIBUTES) + +#define TEST_MESSAGE_QUEUES_COUNT 3 + +#define TASK_COUNT TEST_PROCESSORS +#define TEST_TASK (TASK_COUNT - 1) +#define MANDL_TASKS (TASK_COUNT - 1) +#define TOTAL_TILES 64 + +#define MAX_MESSAGE_QUEUES 2 +#define MAX_MESSAGE_SIZE sizeof(uint8_t) +#define MAX_PENDING_MESSAGES TASK_COUNT + +#define MESSAGE_TEST_SEND 12 +#define MESSAGE_TASK_SEND 24 + +rtems_event_set event_send[] = {RTEMS_EVENT_1, RTEMS_EVENT_2, RTEMS_EVENT_3, + RTEMS_EVENT_4}; + +typedef struct +{ + rtems_id main_task; + uint8_t ntiles; + rtems_id task_id[TASK_COUNT]; + rtems_id tile_queue; + rtems_id barrier_id; + rtems_id msg_init_queue_id; + rtems_id msg_task_queue_id; +} test_context; + +RTEMS_ALIGNED(RTEMS_TASK_STORAGE_ALIGNMENT) +static char calc_task_storage[TASK_COUNT][TASK_STORAGE_SIZE]; + +RTEMS_MESSAGE_QUEUE_BUFFER(MAX_MESSAGE_SIZE) +msg_tile_queue_storage[MAX_PENDING_MESSAGES]; + +RTEMS_MESSAGE_QUEUE_BUFFER(MAX_MESSAGE_SIZE) +msg_task_queue_storage[MAX_PENDING_MESSAGES]; + +RTEMS_ALIGNED(RTEMS_TASK_STORAGE_ALIGNMENT) +static uint32_t task_before_mandelbrot[TASK_COUNT-1]; + +RTEMS_ALIGNED(RTEMS_TASK_STORAGE_ALIGNMENT) +static uint32_t task_after_mandelbrot[TASK_COUNT-1]; + +static void calc_task_function(rtems_task_argument arg) +{ + test_context *ctx; + + ctx = (test_context *)arg; + struct timespec uptime; + + rtems_id local_id = TaskSelfId(); + uint8_t task_idx = 0; + + rtems_clock_get_uptime(&uptime); + task_before_mandelbrot[task_idx] = (uint32_t) (uptime.tv_sec * 1000000 + uptime.tv_nsec/1000); + + for (int i = 0; i < MANDL_TASKS; i++) + { + if (ctx->task_id[i] == local_id) + { + task_idx = i; + break; + } + } + + WaitAtBarrier(ctx->barrier_id); + mandelbrot_tile(task_idx+1, ctx->ntiles); + + rtems_clock_get_uptime(&uptime); + task_after_mandelbrot[task_idx] = (uint32_t) (uptime.tv_sec * 1000000 + uptime.tv_nsec/1000); + + SendEvents(ctx->main_task, event_send[task_idx]); + + SuspendSelf(); +} + +static void message_test_task(rtems_task_argument arg) +{ + test_context *ctx; + + ctx = (test_context *)arg; + + uint8_t val_receive = 0, val_send = 0; + + ReceiveMessage(ctx->msg_task_queue_id, &val_receive); + if (val_receive == MESSAGE_TASK_SEND) { + val_send = MESSAGE_TEST_SEND; + SendMessage(ctx->msg_init_queue_id, &val_send, sizeof(uint8_t)); + } + SuspendSelf(); +} + +static void Init(rtems_task_argument arg) +{ + (void)arg; + test_context ctx; + uint32_t start_time, end_time, elapsed_time; + char ch; + rtems_event_set received = 0; + rtems_event_set total_events = 0; + bool defined_process = false; + bool undefined_process = false; + char str[ITOA_STR_SIZE]; + struct timespec uptime; + uint32_t functions_start = 0, functions_end; + + ctx.main_task = rtems_task_self(); + ctx.ntiles = MANDL_TASKS; + uint8_t nwaiting = ctx.ntiles; + // create an automatic barrier + ctx.barrier_id = CreateAutomaticBarrier(nwaiting); + + start_time = rtems_clock_get_ticks_since_boot(); + rtems_task_config calc_task_config = { + .initial_priority = PRIO_NORMAL, + .storage_size = TASK_STORAGE_SIZE, + .maximum_thread_local_storage_size = + MAX_TLS_SIZE, + .initial_modes = RTEMS_DEFAULT_MODES, + .attributes = TASK_ATTRIBUTES}; + + // create the mandlebrot set using all available cores minus one + for (uint32_t i = 0; i < MANDL_TASKS; i++) + { + ch = '0' + i; + calc_task_config.name = rtems_build_name('R', 'U', 'N', ch); + calc_task_config.storage_area = &calc_task_storage[i][0]; + + ctx.task_id[i] = DoCreateTask(calc_task_config); + StartTask(ctx.task_id[i], calc_task_function, &ctx); + total_events += event_send[i]; + } + + // with the last available core test the undefined behaviour message queue + rtems_message_queue_config msg_config = { + .name = rtems_build_name('M', 'S', 'G', 'T'), + .maximum_pending_messages = RTEMS_ARRAY_SIZE(msg_tile_queue_storage), + .maximum_message_size = MAX_MESSAGE_SIZE, + .storage_size = sizeof(msg_tile_queue_storage), + .storage_area = &msg_tile_queue_storage, + .attributes = RTEMS_FIFO | RTEMS_GLOBAL}; + + // create a normal message queue to send messages to the tasks that will + // receive messages in the undefined behaviour message queues + + uint8_t val_send = 0, val_receive = 0; + for (uint32_t i = 0; i < TEST_MESSAGE_QUEUES_COUNT; i++) + { + ctx.msg_task_queue_id = CreateMessageQueue(msg_config); + // create a normal message queue, a message queue with undefined + // behaviour and again a normal message queue + if (i==1) + { + msg_config.name = rtems_build_name('M', 'S', 'G', '0'); + msg_config.attributes = RTEMS_FIFO | RTEMS_LOCAL | RTEMS_GLOBAL; + } + else + { + msg_config.name = rtems_build_name('M', 'S', 'G', '1'); + msg_config.attributes = RTEMS_FIFO | RTEMS_GLOBAL; + } + + ctx.msg_init_queue_id = CreateMessageQueue(msg_config); + + ch = '0' + i; + calc_task_config.name = rtems_build_name('T', 'M', 'S', ch); + calc_task_config.storage_area = &calc_task_storage[TEST_TASK][0]; + + ctx.task_id[TEST_TASK] = DoCreateTask(calc_task_config); + // execute task that receives and sends messages + if (i == 0) { + rtems_clock_get_uptime(&uptime); + functions_start = (uint32_t)(uptime.tv_sec * 1000000 + uptime.tv_nsec / 1000); + } + StartTask(ctx.task_id[TEST_TASK], message_test_task, &ctx); + + val_send = MESSAGE_TASK_SEND; + + SendMessage(ctx.msg_task_queue_id, &val_send, sizeof(val_send)); + ReceiveMessage(ctx.msg_init_queue_id, &val_receive); + + if (i==1) { + undefined_process = (val_receive == MESSAGE_TEST_SEND); + } else { + defined_process = (val_receive == MESSAGE_TEST_SEND); + } + + DeleteTask(ctx.task_id[TEST_TASK]); + DeleteMessageQueue(ctx.msg_init_queue_id); + DeleteMessageQueue(ctx.msg_task_queue_id); + } + rtems_clock_get_uptime(&uptime); + functions_end = (uint32_t) (uptime.tv_sec* 1000000 + uptime.tv_nsec/1000) ; + + while (received != total_events) + { + received |= ReceiveAllEvents(total_events); + } + + end_time = rtems_clock_get_ticks_since_boot(); + + elapsed_time = end_time - start_time; + + uint32_t latest_task_start = 0; + uint32_t earliest_task_finish = -1; + for (uint32_t task = 0; task < MANDL_TASKS; task++) { + if (task_before_mandelbrot[task] > latest_task_start) + latest_task_start = task_before_mandelbrot[task]; + if (task_after_mandelbrot[task] < earliest_task_finish) + earliest_task_finish = task_after_mandelbrot[task]; + } + + print_string("\n"); + if (functions_start > latest_task_start && functions_end < earliest_task_finish) { + print_string("Functions and mandelbrot executed concurrently: true\n\n"); + } else { + print_string("Functions and mandelbrot executed concurrently: false\n\n"); + } + + print_string("Mandelbrot task and defined message functions executed correctly: "); + if (defined_process) { + print_string("true\n"); + } else { + print_string("false\n"); + } + + print_string("Mandelbrot task and undefined message functions executed correctly: "); + if (undefined_process) { + print_string("true\n"); + } else { + print_string("false\n"); + } + + print_string("Multicore Elapsed Time - "); + print_string(itoa(elapsed_time, &str[0], 10)); + print_string("\n"); + + print_test_results(); + + for (uint32_t i = 0; i < MANDL_TASKS; i++) + { + DeleteTask(ctx.task_id[i]); + } + DeleteBarrier(ctx.barrier_id); + + rtems_fatal(RTEMS_FATAL_SOURCE_EXIT, 0); +} + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER + +#define CONFIGURE_MAXIMUM_PROCESSORS TEST_PROCESSORS + +#define CONFIGURE_MAXIMUM_MESSAGE_QUEUES MAX_MESSAGE_QUEUES + +#define CONFIGURE_MAXIMUM_BARRIERS 1 + +#define CONFIGURE_MAXIMUM_TASKS (TEST_PROCESSORS + 1) + +#define CONFIGURE_SCHEDULER_EDF_SMP + +#define CONFIGURE_MINIMUM_TASK_STACK_SIZE \ + RTEMS_MINIMUM_STACK_SIZE + CPU_STACK_ALIGNMENT + +#define CONFIGURE_EXTRA_TASK_STACKS RTEMS_MINIMUM_STACK_SIZE + +#define CONFIGURE_INIT_TASK_CONSTRUCT_STORAGE_SIZE 2 * TASK_STORAGE_SIZE + +#define CONFIGURE_MINIMUM_TASKS_WITH_USER_PROVIDED_STORAGE \ + CONFIGURE_MAXIMUM_TASKS + +#define CONFIGURE_MICROSECONDS_PER_TICK 1000 + +#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 0 + +#define CONFIGURE_DISABLE_NEWLIB_REENTRANCY + +#define CONFIGURE_APPLICATION_DISABLE_FILESYSTEM + +#define CONFIGURE_MAXIMUM_THREAD_LOCAL_STORAGE_SIZE MAX_TLS_SIZE + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT_TASK_ATTRIBUTES (RTEMS_SYSTEM_TASK | TASK_ATTRIBUTES) + +#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES + +#define CONFIGURE_INIT + +#include <rtems/confdefs.h> diff --git a/testsuites/isvv/20_partition_manager_undefined_behaviour/partition_manager_undefined_behaviour.c b/testsuites/isvv/20_partition_manager_undefined_behaviour/partition_manager_undefined_behaviour.c new file mode 100644 index 0000000000..76d1576dcc --- /dev/null +++ b/testsuites/isvv/20_partition_manager_undefined_behaviour/partition_manager_undefined_behaviour.c @@ -0,0 +1,359 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 2022 Critical Software SA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <rtems/bspIo.h> +#include "../shared/utils.h" +#include "../shared/isvv_rtems_aux.h" + +/** + * + * @brief Tests impact of undefined behaviour for partition manager + * + * This test case performs the calculation of the Mandelbrot set in parallel with + * execution of partition related functions with conditions which lead to + * undefined behaviour + * @{ + */ + +#define ITOA_STR_SIZE (8 * sizeof(int) + 1) + +#define MAX_TLS_SIZE RTEMS_ALIGN_UP(64, RTEMS_TASK_STORAGE_ALIGNMENT) + +#define TASK_STORAGE_SIZE \ + RTEMS_TASK_STORAGE_SIZE( \ + MAX_TLS_SIZE + RTEMS_MINIMUM_STACK_SIZE, \ + TASK_ATTRIBUTES) + +#define TASK_ATTRIBUTES RTEMS_FLOATING_POINT + +// test specific global vars + +// We want to create mandelbrot executions whilst our manager functions +// Are executed on another core +#define TASK_COUNT TEST_PROCESSORS +#define CALCULATION_TASKS ((TEST_PROCESSORS) - 1) + +// Timing related variables to ensure concurrent executions +#define RELATIVE_SLEEP 0 +#define FUNCTION_WAIT_MICROSECONDS 10 +#define FUNCTION_WAIT_NANOSECONDS (FUNCTION_WAIT_MICROSECONDS * 1000) + +static rtems_id start_barrier; +static rtems_id TASK_COUNTER_SEMAPHORE; + +typedef struct +{ + rtems_id calc_task_id[CALCULATION_TASKS]; + rtems_id undefined_task_id; + uint32_t functions_start, functions_end; + bool valid_call_RES_IN_USE_1, valid_call_RES_IN_USE_2, invalid_call_RES_IN_USE; +} test_context; + +// Create storage areas from which to create our partitions +RTEMS_ALIGNED(CPU_STACK_ALIGNMENT) +static char partition_storage[65536]; + +// Create storage areas for each worker, using task construct forces +RTEMS_ALIGNED(RTEMS_TASK_STORAGE_ALIGNMENT) +static char task_storage[TASK_COUNT][TASK_STORAGE_SIZE]; + +// Storage space for timings +RTEMS_ALIGNED(RTEMS_TASK_STORAGE_ALIGNMENT) +static uint32_t task_before_mandelbrot[CALCULATION_TASKS]; + +RTEMS_ALIGNED(RTEMS_TASK_STORAGE_ALIGNMENT) +static uint32_t task_after_mandelbrot[CALCULATION_TASKS]; + +static void calc_task_function(rtems_task_argument tile) +{ + uint8_t tile_n = (uint8_t)tile; + struct timespec uptime; + + WaitAtBarrier(start_barrier); + + // Check time function begins execution of mandelbrot executions + rtems_clock_get_uptime(&uptime); + task_before_mandelbrot[tile_n - 1] = (uint32_t)(uptime.tv_sec * 1000000 + uptime.tv_nsec / 1000); + + mandelbrot_tile(tile_n, CALCULATION_TASKS); + + // Check time function finishes execution of mandelbrot executions + rtems_clock_get_uptime(&uptime); + task_after_mandelbrot[tile_n - 1] = (uint32_t)(uptime.tv_sec * 1000000 + uptime.tv_nsec / 1000); + + // Task has finished so increment counter + ReleaseCounterSemaphore(TASK_COUNTER_SEMAPHORE); + rtems_task_exit(); +} + +static void undefined_behaviour_task(rtems_task_argument arg) +{ + test_context *ctx = (test_context *)arg; + struct timespec uptime, function_wait; + + WaitAtBarrier(start_barrier); + + // Wait for 10us to ensure concurrent executions + function_wait.tv_sec = 0; + function_wait.tv_nsec = FUNCTION_WAIT_NANOSECONDS; + clock_nanosleep(CLOCK_MONOTONIC, 0, &function_wait, NULL); + + rtems_clock_get_uptime(&uptime); + ctx->functions_start = (uint32_t)(uptime.tv_sec * 1000000 + uptime.tv_nsec / 1000); + + /* Start execution of partition related functions following formula of: + * Defined behaviour + * Undefined behaviour + * Defined behaviour + * + * Where attribute_set has certain values combined with a bitwise OR. Values combined that are mutually + * exclusive is categorised as undefined behaviour. What we see when combining these values is the + * non-default option takes precedence and is applied, in this case that is the RTEMS_GLOBAL attribute. + * + * According to the RTEMS documentation, setting the global attribute in a single node system has no effect. + * As we are restricted to a single-node system with this qualification pack, and the goal is to assert + * SMP functionality (rather than MPCI functionality) we will not be testing multiple nodes when using the + * RTEMS_GLOBAL attribute. + * + * Therefore to check the functionality and correctness for the directive rtems_create_partition, we will + * perform an assertion on the returned status code, as well as both request and return a buffer + * of a size pre-defined in the _create call. Before returning the buffer, we will attempt to delete + * the partition. In correct program function, this should not be allowed, and will allow us to + * match correct program behaviour when using undefined behaviour. + */ + + // Define test relevant variables + rtems_status_code sc; + rtems_id partition_id; + void *starting_address; + void *buffer_ptr; + + // We will reuse the same starting address as the memory from previous partition SHOULD have been returned to RTEMS + starting_address = &partition_storage; + + /* + * VALID CALL - attribute_set = RTEMS_LOCAL + */ + + // Create our partition in the designated aligned space + ASSERT_SUCCESS(rtems_partition_create(rtems_build_name('P', 'R', 'T', '1'), &starting_address, 128, 32, RTEMS_LOCAL, &partition_id)); + // Try to create a buffer from the partition + ASSERT_SUCCESS(rtems_partition_get_buffer(partition_id, &buffer_ptr)); + + // Status code returned should indicate action is not allowed + sc = rtems_partition_delete(partition_id); + ctx->valid_call_RES_IN_USE_1 = (RTEMS_RESOURCE_IN_USE == sc); + + // Now return the buffer and clean up the partition + ASSERT_SUCCESS(rtems_partition_return_buffer(partition_id, buffer_ptr)); + ASSERT_SUCCESS(rtems_partition_delete(partition_id)); + + /* + * INVALID CALL - attribute_set = RTEMS_LOCAL | RTEMS_GLOBAL + */ + + ASSERT_SUCCESS(rtems_partition_create(rtems_build_name('P', 'R', 'T', 'I'), &starting_address, 128, 32, RTEMS_LOCAL | RTEMS_GLOBAL, &partition_id)); + ASSERT_SUCCESS(rtems_partition_get_buffer(partition_id, &buffer_ptr)); + + // To assess the effectiveness of the directive in question, we will try to match with known correct program behaviour. + // Trying to delete a partition with an unreturned buffer should throw the same error as in the valid call. + sc = rtems_partition_delete(partition_id); + ctx->invalid_call_RES_IN_USE = (RTEMS_RESOURCE_IN_USE == sc); + + ASSERT_SUCCESS(rtems_partition_return_buffer(partition_id, buffer_ptr)); + ASSERT_SUCCESS(rtems_partition_delete(partition_id)); + + /* + * VALID CALL - attribute_set = RTEMS_LOCAL + */ + + ASSERT_SUCCESS(rtems_partition_create(rtems_build_name('P', 'R', 'T', '2'), &starting_address, 128, 32, RTEMS_LOCAL, &partition_id)); + ASSERT_SUCCESS(rtems_partition_get_buffer(partition_id, &buffer_ptr)); + + sc = rtems_partition_delete(partition_id); + ctx->valid_call_RES_IN_USE_2 = (RTEMS_RESOURCE_IN_USE == sc); + + ASSERT_SUCCESS(rtems_partition_return_buffer(partition_id, buffer_ptr)); + ASSERT_SUCCESS(rtems_partition_delete(partition_id)); + + /* + * FINISHED EXECUTION OF PARTITION RELATED FUNCTIONS + */ + + rtems_clock_get_uptime(&uptime); + ctx->functions_end = (uint32_t)(uptime.tv_sec * 1000000 + uptime.tv_nsec / 1000); + + // Only once this task has finished do we know we can progress + // Task has finished so increment counter + ReleaseCounterSemaphore(TASK_COUNTER_SEMAPHORE); + rtems_task_exit(); +} + +static void Init(rtems_task_argument arg) +{ + (void)arg; + test_context ctx; + uint8_t wait = 0; + + TASK_COUNTER_SEMAPHORE = CreateCounterSemaphore(rtems_build_name('T', 'C', 'S', '0'), 0); + + // Config for our mandelbrot tile function + rtems_task_config calc_task_config = { + .initial_priority = PRIO_NORMAL, + .storage_size = TASK_STORAGE_SIZE, + .maximum_thread_local_storage_size = MAX_TLS_SIZE, + .initial_modes = RTEMS_DEFAULT_MODES, + .attributes = TASK_ATTRIBUTES}; + + // Create our barrier for mandelbrot tasks + undefined behaviour task + start_barrier = CreateAutomaticBarrier(TASK_COUNT); + + // Finish config for our mandelbrot tile functions and start them + for (uint32_t i = 0; i < CALCULATION_TASKS; i++) + { + calc_task_config.name = rtems_build_name('R', 'U', 'N', (char)i); + calc_task_config.storage_area = &task_storage[i][0]; + + ctx.calc_task_id[i] = DoCreateTask(calc_task_config); + StartTask(ctx.calc_task_id[i], calc_task_function, (void *)(i + 1)); + } + + // Config our undefined behaviour task and start it + rtems_task_config undef_task_config = { + .name = rtems_build_name('U', 'N', 'D', 'F'), + .initial_priority = PRIO_NORMAL, + .storage_size = TASK_STORAGE_SIZE, + .maximum_thread_local_storage_size = MAX_TLS_SIZE, + .initial_modes = RTEMS_DEFAULT_MODES, + .attributes = TASK_ATTRIBUTES, + .storage_area = &task_storage[TASK_COUNT-1][0]}; + + // Set properties to check for functionality of directives + ctx.valid_call_RES_IN_USE_1 = ctx.invalid_call_RES_IN_USE = ctx.valid_call_RES_IN_USE_2 = FALSE; + + ctx.undefined_task_id = DoCreateTask(undef_task_config); + StartTask(ctx.undefined_task_id, undefined_behaviour_task, (void *)&ctx); + + // Wait for all tasks to complete + while (wait < TASK_COUNT) + { + ObtainCounterSemaphore(TASK_COUNTER_SEMAPHORE); + wait++; + } + + // Check RESOURCE_IN_USE errors which should've been thrown + if (ctx.valid_call_RES_IN_USE_1 && ctx.invalid_call_RES_IN_USE && ctx.valid_call_RES_IN_USE_2) + { + print_string("Incorrectly deleting partitions throws expected errors: true\n"); + } + else + { + print_string("Incorrectly deleting partitions throws expected errors: false\n"); + (ctx.valid_call_RES_IN_USE_1) ? print_string("1st call - SUCCEEDED\n") : print_string("1st call - FAILED\n"); + (ctx.invalid_call_RES_IN_USE) ? print_string("2nd call - SUCCEEDED\n") : print_string("2nd call - FAILED\n"); + (ctx.valid_call_RES_IN_USE_2) ? print_string("3rd call - SUCCEEDED\n") : print_string("3rd call - FAILED\n"); + } + + // Check concurrent executions + + uint32_t latest_task_start = 0; + // Wraps around to effectively be maximum allowed value + uint32_t earliest_task_finish = -1; + + for (uint8_t task = 0; task < CALCULATION_TASKS; task++) + { + latest_task_start = MAX(latest_task_start, task_before_mandelbrot[task]); + earliest_task_finish = MIN(earliest_task_finish, task_after_mandelbrot[task]); + } + + print_string("\n\n"); + if ((ctx.functions_start >= latest_task_start && ctx.functions_end <= earliest_task_finish)) + { + print_string("Functions and mandelbrot executed concurrently: true\n\n"); + } + else + { + print_string("Functions and mandelbrot executed concurrently: false\n\n"); + } + + print_test_results(); + + // Perform tidy up activities and exit application + rtems_semaphore_delete(TASK_COUNTER_SEMAPHORE); + rtems_fatal(RTEMS_FATAL_SOURCE_EXIT, 0); +} + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER + +#define CONFIGURE_MAXIMUM_PROCESSORS TEST_PROCESSORS + +#define CONFIGURE_MAXIMUM_SEMAPHORES 1 + +// Reduce the priority of the Init task so all other tasks can be schedules to all other cores +#define CONFIGURE_INIT_TASK_PRIORITY PRIO_LOW + +#define CONFIGURE_MAXIMUM_PARTITIONS 1 + +#define CONFIGURE_MAXIMUM_BARRIERS 1 + +#define CONFIGURE_MAXIMUM_TASKS ((TEST_PROCESSORS) + 1) + +#define CONFIGURE_SCHEDULER_EDF_SMP + +#define CONFIGURE_MINIMUM_TASK_STACK_SIZE RTEMS_MINIMUM_STACK_SIZE + CPU_STACK_ALIGNMENT + +#define CONFIGURE_EXTRA_TASK_STACKS RTEMS_MINIMUM_STACK_SIZE + +#define CONFIGURE_INIT_TASK_CONSTRUCT_STORAGE_SIZE 2 * (TASK_STORAGE_SIZE) + +#define CONFIGURE_MINIMUM_TASKS_WITH_USER_PROVIDED_STORAGE \ + CONFIGURE_MAXIMUM_TASKS + +#define CONFIGURE_MICROSECONDS_PER_TICK 1000 + +#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 0 + +#define CONFIGURE_DISABLE_NEWLIB_REENTRANCY + +#define CONFIGURE_APPLICATION_DISABLE_FILESYSTEM + +#define CONFIGURE_MAXIMUM_THREAD_LOCAL_STORAGE_SIZE MAX_TLS_SIZE + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT_TASK_ATTRIBUTES (RTEMS_SYSTEM_TASK | TASK_ATTRIBUTES) + +#define CONFIGURE_INIT_TASK_INITIAL_MODE + +#define CONFIGURE_INIT + +#include <rtems/confdefs.h>
\ No newline at end of file diff --git a/testsuites/isvv/21_semaphore_manager_undefined_behaviour/semaphore_manager_undefined_behaviour.c b/testsuites/isvv/21_semaphore_manager_undefined_behaviour/semaphore_manager_undefined_behaviour.c new file mode 100644 index 0000000000..dd12550321 --- /dev/null +++ b/testsuites/isvv/21_semaphore_manager_undefined_behaviour/semaphore_manager_undefined_behaviour.c @@ -0,0 +1,661 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 2022 Critical Software SA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "../shared/isvv_rtems_aux.h" +#include "../shared/utils.h" +#include <rtems.h> +#include <rtems/bspIo.h> + +/** + * + * @brief Tests impact of undefined behaviours + * + * This test case performs the calculation of the Mandelbrot set in + * parallel with execution of calls to semaphores configured with + * attributes with undefined behaviour + * + */ + +#define ITOA_STR_SIZE (8 * sizeof(int) + 1) + +#define MAX_TLS_SIZE RTEMS_ALIGN_UP(64, RTEMS_TASK_STORAGE_ALIGNMENT) + +#define TASK_ATTRIBUTES RTEMS_FLOATING_POINT + +#define TASK_STORAGE_SIZE \ + RTEMS_TASK_STORAGE_SIZE(MAX_TLS_SIZE + RTEMS_MINIMUM_STACK_SIZE, \ + TASK_ATTRIBUTES) + +// test specific global vars +#define TASK_COUNT TEST_PROCESSORS + +#define MANDL_TASKS (TASK_COUNT - 1) +#define LAST_TASK (TASK_COUNT - 1) +#define TOTAL_TILES 64 + +#define NUMBER_OF_SEM_CREATE_TESTS 10 +#define CREATE_TEST_MUTEX_FAILED 0xfffffffe +#define NUMBER_OF_SEM_SET_PRIO_TESTS 4 +#define LOOPS_PER_TEST 3 +#define RELATIVE_SLEEP 0 +#define FUNCTION_WAIT_MICROSECONDS 8 +#define FUNCTION_WAIT_NANOSECONDS (FUNCTION_WAIT_MICROSECONDS * 1000) + +rtems_event_set event_send[] = {RTEMS_EVENT_1, RTEMS_EVENT_2, RTEMS_EVENT_3, + RTEMS_EVENT_4}; +// MUST NOT overlap event_send[] +#define FLUSH_EVENT RTEMS_EVENT_8 + +typedef struct { + rtems_attribute att_config; + char str_output[133]; +} semaphore_attribute; + +typedef struct { + rtems_id main_task; + uint8_t ntiles; + rtems_id task_id[TASK_COUNT]; + rtems_id barrier_id; + rtems_id sem_id; + bool sem_obtained; + rtems_attribute sem_obtain_attributes; +} test_context; + +static semaphore_attribute sem_create_attributes[NUMBER_OF_SEM_CREATE_TESTS] = +{ + {RTEMS_LOCAL | RTEMS_GLOBAL, "RTEMS_LOCAL | RTEMS_GLOBAL"}, + {RTEMS_BINARY_SEMAPHORE | RTEMS_FIFO | RTEMS_PRIORITY, "RTEMS_BINARY_SEMAPHORE | RTEMS_FIFO | RTEMS_PRIORITY"}, + {RTEMS_COUNTING_SEMAPHORE | RTEMS_BINARY_SEMAPHORE, "RTEMS_COUNTING_SEMAPHORE | RTEMS_BINARY_SEMAPHORE"}, + {RTEMS_COUNTING_SEMAPHORE | RTEMS_SIMPLE_BINARY_SEMAPHORE, "RTEMS_COUNTING_SEMAPHORE | RTEMS_SIMPLE_BINARY_SEMAPHORE"}, + {RTEMS_BINARY_SEMAPHORE | RTEMS_SIMPLE_BINARY_SEMAPHORE, "RTEMS_BINARY_SEMAPHORE | RTEMS_SIMPLE_BINARY_SEMAPHORE"}, + {RTEMS_COUNTING_SEMAPHORE | RTEMS_BINARY_SEMAPHORE | RTEMS_SIMPLE_BINARY_SEMAPHORE, "RTEMS_COUNTING_SEMAPHORE | RTEMS_BINARY_SEMAPHORE | " "RTEMS_SIMPLE_BINARY_SEMAPHORE"}, + {RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_PRIORITY_CEILING | RTEMS_INHERIT_PRIORITY, "RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_PRIORITY_CEILING | " "RTEMS_INHERIT_PRIORITY"}, + {RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_PRIORITY_CEILING | RTEMS_MULTIPROCESSOR_RESOURCE_SHARING, "RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_PRIORITY_CEILING | " "RTEMS_MULTIPROCESSOR_RESOURCE_SHARING"}, + {RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_INHERIT_PRIORITY | RTEMS_MULTIPROCESSOR_RESOURCE_SHARING, "RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_INHERIT_PRIORITY | " "RTEMS_MULTIPROCESSOR_RESOURCE_SHARING"}, + {RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_INHERIT_PRIORITY | RTEMS_PRIORITY_CEILING | RTEMS_MULTIPROCESSOR_RESOURCE_SHARING, "RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_INHERIT_PRIORITY | " "RTEMS_PRIORITY_CEILING | RTEMS_MULTIPROCESSOR_RESOURCE_SHARING"} +}; + +#define NO_LOCKING_PROTOCOL ( RTEMS_NO_INHERIT_PRIORITY | RTEMS_NO_PRIORITY_CEILING | RTEMS_NO_MULTIPROCESSOR_RESOURCE_SHARING ) +// These are the only attribute set configurations that are both allowed by rtems_semaphore_create() and +// are not explicitly not undefined behaviour for rtems_semaphore_set_priority(). +static semaphore_attribute sem_set_prio_attributes[NUMBER_OF_SEM_SET_PRIO_TESTS] = +{ + {RTEMS_COUNTING_SEMAPHORE | RTEMS_PRIORITY | NO_LOCKING_PROTOCOL, "RTEMS_COUNTING_SEMAPHORE | RTEMS_PRIORITY | NO_LOCKING_PROTOCOL"}, + {RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | NO_LOCKING_PROTOCOL, "RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | NO_LOCKING_PROTOCOL"}, + {RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_INHERIT_PRIORITY, "RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_INHERIT_PRIORITY"}, + {RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_PRIORITY | NO_LOCKING_PROTOCOL, "RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_PRIORITY | NO_LOCKING_PROTOCOL"} +}; + +RTEMS_ALIGNED(RTEMS_TASK_STORAGE_ALIGNMENT) +static char calc_task_storage[TASK_COUNT][TASK_STORAGE_SIZE]; + +RTEMS_ALIGNED(RTEMS_TASK_STORAGE_ALIGNMENT) +static uint32_t task_before_mandelbrot[TASK_COUNT - 1]; + +RTEMS_ALIGNED(RTEMS_TASK_STORAGE_ALIGNMENT) +static uint32_t task_after_mandelbrot[TASK_COUNT - 1]; + +static void calc_task_function(rtems_task_argument arg) { + test_context *ctx; + + ctx = (test_context *)arg; + struct timespec uptime; + + rtems_id local_id = TaskSelfId(); + uint8_t task_idx = 0; + + for (int i = 0; i < MANDL_TASKS; i++) { + if (ctx->task_id[i] == local_id) { + task_idx = i; + break; + } + } + + WaitAtBarrier(ctx->barrier_id); + + rtems_clock_get_uptime(&uptime); + task_before_mandelbrot[task_idx] = + (uint32_t)(uptime.tv_sec * 1000000 + uptime.tv_nsec / 1000); + + mandelbrot_tile(task_idx + 1, ctx->ntiles); + + rtems_clock_get_uptime(&uptime); + task_after_mandelbrot[task_idx] = + (uint32_t)(uptime.tv_sec * 1000000 + uptime.tv_nsec / 1000); + + SendEvents(ctx->main_task, event_send[task_idx]); + + SuspendSelf(); +} + +static void semaphore_test_task(rtems_task_argument arg) +{ + test_context *ctx; + + ctx = (test_context *)arg; + + ObtainMutex(ctx->sem_id); + ctx->sem_obtained = true; + ReleaseMutex(ctx->sem_id); + + SendEvents(ctx->main_task, event_send[LAST_TASK]); + SuspendSelf(); +} + +static void semaphore_create_test_task(rtems_task_argument arg) +{ + semaphore_test_task(arg); +} + +static void semaphore_set_prio_run_task(rtems_task_argument arg) +{ + semaphore_test_task(arg); +} + +static void semaphore_obtain_test_task(rtems_task_argument arg) { + test_context *ctx; + + ctx = (test_context *)arg; + rtems_status_code sc; + + sc = rtems_semaphore_obtain(ctx->sem_id, ctx->sem_obtain_attributes, RTEMS_NO_TIMEOUT); + if(sc == RTEMS_SUCCESSFUL) + { + ctx->sem_obtained = true; + ReleaseMutex(ctx->sem_id); + } + + SendEvents(ctx->main_task, event_send[LAST_TASK]); + SuspendSelf(); +} + +static void semaphore_flush_test_task(rtems_task_argument arg) { + test_context *ctx; + ctx = (test_context *)arg; + + ObtainMutex(ctx->sem_id); + // Let the main task know this task has been started and owns the mutex. + SendEvents(ctx->main_task, FLUSH_EVENT); + // Wait for event from main task to ensure this function still holds the + // mutex when rtems_semaphore_flush() is called. + ReceiveAllEvents(FLUSH_EVENT); + ReleaseMutex(ctx->sem_id); + + SendEvents(ctx->main_task, event_send[LAST_TASK]); + + SuspendSelf(); +} + +static rtems_id CreateTestMutex(rtems_attribute attr) { + rtems_status_code sc; + rtems_id id; + + id = INVALID_ID; + sc = rtems_semaphore_create(rtems_build_name('S', 'E', 'M', '0'), 1, attr, 0, &id); + if (sc == RTEMS_NOT_DEFINED) + return id; + + if(sc != RTEMS_SUCCESSFUL) + return CREATE_TEST_MUTEX_FAILED; + + return id; +} + +static void Init(rtems_task_argument arg) { + (void)arg; + test_context ctx; + char ch; + rtems_event_set received = 0; + rtems_event_set total_events = 0; + char str[ITOA_STR_SIZE]; + struct timespec uptime, function_wait; + uint32_t functions_start, functions_end; + rtems_status_code sc; + bool sem_create_results[NUMBER_OF_SEM_CREATE_TESTS * LOOPS_PER_TEST] = {false}; + uint8_t sem_create_index = 0; + bool sem_obtain_results[LOOPS_PER_TEST] = {false}; + bool sem_flush_results[LOOPS_PER_TEST] = {false}; + bool sem_set_prio_results[NUMBER_OF_SEM_SET_PRIO_TESTS * LOOPS_PER_TEST] = {false}; + uint8_t sem_set_prio_index = 0; + + SetSelfPriority(PRIO_VERY_ULTRA_HIGH); + + function_wait.tv_sec = 0; + function_wait.tv_nsec = FUNCTION_WAIT_NANOSECONDS; + ctx.main_task = rtems_task_self(); + ctx.ntiles = MANDL_TASKS; + uint8_t nwaiting = ctx.ntiles; + + ctx.barrier_id = CreateAutomaticBarrier(nwaiting); + + rtems_task_config calc_task_config = {.initial_priority = PRIO_NORMAL, + .storage_size = TASK_STORAGE_SIZE, + .maximum_thread_local_storage_size = + MAX_TLS_SIZE, + .initial_modes = RTEMS_DEFAULT_MODES, + .attributes = TASK_ATTRIBUTES}; + + // create the mandlebrot set using all available cores minus one + for (uint32_t i = 0; i < MANDL_TASKS; i++) { + ch = '0' + i; + calc_task_config.name = rtems_build_name('R', 'U', 'N', ch); + calc_task_config.storage_area = &calc_task_storage[i][0]; + + ctx.task_id[i] = DoCreateTask(calc_task_config); + StartTask(ctx.task_id[i], calc_task_function, &ctx); + total_events += event_send[i]; + } + + // with the last available core test undefined behaviour semaphores + + // Wait FUNCTION_WAIT_MICROSECONDS microseconds to ensure function calls are concurrent with mandelbrot calculation + clock_nanosleep(CLOCK_MONOTONIC, RELATIVE_SLEEP, &function_wait, NULL); + rtems_clock_get_uptime(&uptime); + functions_start = (uint32_t)(uptime.tv_sec * 1000000 + uptime.tv_nsec / 1000); + + // #################### rtems_semaphore_create #################### + // run each trio of tests + for (uint32_t tested_sem = 0; tested_sem < NUMBER_OF_SEM_CREATE_TESTS; tested_sem++) + { + // the first and last run are with a normal configuration, the middle run + // is with configuration with undefined behaviour + for (uint32_t i = 0; i < LOOPS_PER_TEST; i++) + { + ctx.sem_obtained = false; + + if (i == 1) + { + ctx.sem_id = CreateTestMutex(sem_create_attributes[tested_sem].att_config); + } + else + { + ctx.sem_id = CreateTestMutex(RTEMS_DEFAULT_ATTRIBUTES); + } + + if (ctx.sem_id == INVALID_ID) + { + // If rtems_semaphore_create() returns RTEMS_NOT_DEFINED for a bad + // attribute set this is okay. + if(i == 1) + { + sem_create_results[sem_create_index] = true; + } + + sem_create_index++; + continue; + } + else if(ctx.sem_id == CREATE_TEST_MUTEX_FAILED) + { + sem_create_index++; + continue; + } + + calc_task_config.name = rtems_build_name('T', 'S', 'E', 'M'); + calc_task_config.storage_area = &calc_task_storage[LAST_TASK][0]; + + ctx.task_id[LAST_TASK] = DoCreateTask(calc_task_config); + // execute task that uses the created semaphores + ObtainMutex(ctx.sem_id); + StartTask(ctx.task_id[LAST_TASK], semaphore_create_test_task, &ctx); + ReleaseMutex(ctx.sem_id); + + ReceiveAllEvents(event_send[LAST_TASK]); + DeleteMutex(ctx.sem_id); + DeleteTask(ctx.task_id[LAST_TASK]); + + // If we get to this point the attribute set was usable and we have not + // been able to detect an error from previous attribute sets. + if(ctx.sem_obtained == true) + { + sem_create_results[sem_create_index] = true; + } + + sem_create_index++; + } + } + + // #################### rtems_semaphore_obtain #################### + for (uint32_t i = 0; i < LOOPS_PER_TEST; i++) + { + // test the obtain semaphore function with undefined behaviour attributes + ctx.sem_obtained = false; + ctx.sem_obtain_attributes = RTEMS_WAIT; + ctx.sem_id = CreateMutex(rtems_build_name('S', 'E', 'M', '1')); + + if (i == 1) + { + ctx.sem_obtain_attributes |= RTEMS_NO_WAIT; + } + + calc_task_config.name = rtems_build_name('T', 'S', 'E', 'M'); + calc_task_config.storage_area = &calc_task_storage[LAST_TASK][0]; + + ctx.task_id[LAST_TASK] = DoCreateTask(calc_task_config); + // execute task that uses the created semaphores + StartTask(ctx.task_id[LAST_TASK], semaphore_obtain_test_task, &ctx); + ReceiveAllEvents(event_send[LAST_TASK]); + if(ctx.sem_obtained == true) + { + sem_obtain_results[i] = true; + } + + DeleteMutex(ctx.sem_id); + DeleteTask(ctx.task_id[LAST_TASK]); + } + + // #################### rtems_semaphore_flush #################### + for (uint32_t i = 0; i < LOOPS_PER_TEST; i++) + { + if (i == 1) { + ctx.sem_id = CreateMutexMrsP(rtems_build_name('S', 'E', 'M', '2')); + } else { + ctx.sem_id = CreateMutex(rtems_build_name('S', 'E', 'M', '2')); + } + + calc_task_config.name = rtems_build_name('T', 'S', 'E', 'M'); + calc_task_config.storage_area = &calc_task_storage[LAST_TASK][0]; + + ctx.task_id[LAST_TASK] = DoCreateTask(calc_task_config); + // execute task that uses the created semaphores + StartTask(ctx.task_id[LAST_TASK], semaphore_flush_test_task, &ctx); + + // Ensure flush task has the mutex. + ReceiveAllEvents(FLUSH_EVENT); + sc = rtems_semaphore_flush(ctx.sem_id); + // Allow flush task to continue after we have flushed. + SendEvents(ctx.task_id[LAST_TASK], FLUSH_EVENT); + if(i == 1) + { + // We expect RTEMS_NOT_DEFINED for MrsP. + if(sc == RTEMS_NOT_DEFINED) + sem_flush_results[i] = true; + } + else + { + if(sc == RTEMS_SUCCESSFUL) + sem_flush_results[i] = true; + } + + ReceiveAllEvents(event_send[LAST_TASK]); + DeleteMutex(ctx.sem_id); + DeleteTask(ctx.task_id[LAST_TASK]); + } + + rtems_task_priority old_prio; + rtems_id sched_id; + // #################### rtems_semaphore_set_priority #################### + // run each trio of tests + for (uint32_t tested_sem = 0; tested_sem < NUMBER_OF_SEM_SET_PRIO_TESTS; tested_sem++) + { + for (uint32_t i = 0; i < LOOPS_PER_TEST; i++) + { + ctx.sem_obtained = false; + // test the obtain semaphore function with undefined behaviour attributes + if(i == 1) + { + ctx.sem_id = CreateTestMutex(sem_set_prio_attributes[tested_sem].att_config); + } + else + { + // Documentation explicitly states this attribute set makes for a semaphore with configurable priority. + ctx.sem_id = CreateTestMutex(RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_PRIORITY_CEILING); + } + + if(ctx.sem_id == INVALID_ID || ctx.sem_id == CREATE_TEST_MUTEX_FAILED) + { + // Failed to create semaphore with given attribute set so it cannot be tested. + sem_set_prio_index++; + continue; + } + + sc = rtems_task_get_scheduler(RTEMS_SELF, &sched_id); + ASSERT_SUCCESS(sc); + + calc_task_config.name = rtems_build_name('T', 'S', 'E', 'M'); + calc_task_config.storage_area = &calc_task_storage[LAST_TASK][0]; + + ctx.task_id[LAST_TASK] = DoCreateTask(calc_task_config); + SetScheduler(ctx.task_id[LAST_TASK], sched_id, PRIO_LOW); + + sc = rtems_semaphore_set_priority(ctx.sem_id, sched_id, PRIO_ULTRA_HIGH, &old_prio); + if(sc == RTEMS_NOT_DEFINED) + { + if(i == 1) + { + sem_set_prio_results[sem_set_prio_index] = true; + } + } + else if(sc == RTEMS_SUCCESSFUL) + { + StartTask(ctx.task_id[LAST_TASK], semaphore_set_prio_run_task, &ctx); + ReceiveAllEvents(event_send[LAST_TASK]); + if(ctx.sem_obtained == true) + { + sem_set_prio_results[sem_set_prio_index] = true; + } + } + + DeleteMutex(ctx.sem_id); + DeleteTask(ctx.task_id[LAST_TASK]); + sem_set_prio_index++; + } + } + + rtems_clock_get_uptime(&uptime); + functions_end = (uint32_t)(uptime.tv_sec * 1000000 + uptime.tv_nsec / 1000); + + while (received != total_events) { + received |= ReceiveAllEvents(total_events); + } + + uint32_t latest_task_start = 0; + uint32_t earliest_task_finish = -1; + for (uint32_t task = 0; task < MANDL_TASKS; task++) { + if (task_before_mandelbrot[task] > latest_task_start) + latest_task_start = task_before_mandelbrot[task]; + if (task_after_mandelbrot[task] < earliest_task_finish) + earliest_task_finish = task_after_mandelbrot[task]; + } + + print_string("Functions and mandelbrot executed concurrently: "); + if (functions_start > latest_task_start && functions_end < earliest_task_finish) + { + print_string("true\n"); + } + else + { + print_string("false\n"); + + print_string("functions start ("); + print_string(itoa(functions_start, &str[0], 10)); + print_string(") must be greater than latest task start ("); + print_string(itoa(latest_task_start, &str[0], 10)); + print_string(") and functions end ("); + print_string(itoa(functions_end, &str[0], 10)); + print_string(") must be less than earliest task finish ("); + print_string(itoa(earliest_task_finish, &str[0], 10)); + print_string(")\n"); + } + + + // If any of the rtems_semaphore_create() calls went wrong the test failed. + bool create_success = true; + for(uint8_t i = 0; i < sizeof(sem_create_results)/sizeof(sem_create_results[0]); i++) + { + if(sem_create_results[i] == false) + { + print_string("First failing sem create index: "); + print_string(itoa(i, &str[0], 10)); + print_string("\n"); + print_string("Test attribute set of failing trio: "); + print_string(sem_create_attributes[i / LOOPS_PER_TEST].str_output); + print_string("\n"); + create_success = false; + break; + } + } + + print_string("rtems_semaphore_create() unaffected: "); + if(create_success) + { + print_string("true\n"); + } + else + { + print_string("false\n"); + } + + // If any of the rtems_semaphore_obtain() calls went wrong the test failed. + bool obtain_success = true; + for(uint8_t i = 0; i < sizeof(sem_obtain_results)/sizeof(sem_obtain_results[0]); i++) + { + if(sem_obtain_results[i] == false) + { + print_string("First failing sem obtain index: "); + print_string(itoa(i, &str[0], 10)); + print_string("\n"); + obtain_success = false; + break; + } + } + + print_string("rtems_semaphore_obtain() unaffected: "); + if(obtain_success) + { + print_string("true\n"); + } + else + { + print_string("false\n"); + } + + // If any of the rtems_semaphore_flush() calls went wrong the test failed. + bool flush_success = true; + for(uint8_t i = 0; i < sizeof(sem_flush_results)/sizeof(sem_flush_results[0]); i++) + { + if(sem_flush_results[i] == false) + { + print_string("First failing sem flush index: "); + print_string(itoa(i, &str[0], 10)); + print_string("\n"); + flush_success = false; + break; + } + } + + print_string("rtems_semaphore_flush() unaffected: "); + if(flush_success) + { + print_string("true\n"); + } + else + { + print_string("false\n"); + } + + // If any of the rtems_semaphore_set_priority() calls went wrong the test failed. + bool set_prio_success = true; + for(uint8_t i = 0; i < sizeof(sem_set_prio_results)/sizeof(sem_set_prio_results[0]); i++) + { + if(sem_set_prio_results[i] == false) + { + print_string("First failing sem set priority index: "); + print_string(itoa(i, &str[0], 10)); + print_string("\n"); + print_string("Test attribute set of failing trio: "); + print_string(sem_set_prio_attributes[i / LOOPS_PER_TEST].str_output); + print_string("\n"); + set_prio_success = false; + break; + } + } + + print_string("rtems_semaphore_set_priority() unaffected: "); + if(set_prio_success) + { + print_string("true\n"); + } + else + { + print_string("false\n"); + } + + print_test_results(); + + for (uint32_t i = 0; i < MANDL_TASKS; i++) { + DeleteTask(ctx.task_id[i]); + } + DeleteBarrier(ctx.barrier_id); + + rtems_fatal(RTEMS_FATAL_SOURCE_EXIT, 0); +} + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER + +#define CONFIGURE_MAXIMUM_PROCESSORS TEST_PROCESSORS + +#define CONFIGURE_MAXIMUM_SEMAPHORES 1 + +#define CONFIGURE_MAXIMUM_BARRIERS 1 + +#define CONFIGURE_MAXIMUM_TASKS (TEST_PROCESSORS + 1) + +#define CONFIGURE_SCHEDULER_EDF_SMP + +#define CONFIGURE_MINIMUM_TASK_STACK_SIZE \ + RTEMS_MINIMUM_STACK_SIZE + CPU_STACK_ALIGNMENT + +#define CONFIGURE_EXTRA_TASK_STACKS RTEMS_MINIMUM_STACK_SIZE + +#define CONFIGURE_INIT_TASK_CONSTRUCT_STORAGE_SIZE 2 * TASK_STORAGE_SIZE + +#define CONFIGURE_MINIMUM_TASKS_WITH_USER_PROVIDED_STORAGE \ + CONFIGURE_MAXIMUM_TASKS + +#define CONFIGURE_MICROSECONDS_PER_TICK 1000 + +#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 0 + +#define CONFIGURE_DISABLE_NEWLIB_REENTRANCY + +#define CONFIGURE_APPLICATION_DISABLE_FILESYSTEM + +#define CONFIGURE_MAXIMUM_THREAD_LOCAL_STORAGE_SIZE MAX_TLS_SIZE + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT_TASK_ATTRIBUTES (RTEMS_SYSTEM_TASK | TASK_ATTRIBUTES) + +#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES + +#define CONFIGURE_INIT + +#include <rtems/confdefs.h> diff --git a/testsuites/isvv/22_base_defs_undefined_behaviour/base_defs_undefined_behaviour.c b/testsuites/isvv/22_base_defs_undefined_behaviour/base_defs_undefined_behaviour.c new file mode 100644 index 0000000000..a26b881285 --- /dev/null +++ b/testsuites/isvv/22_base_defs_undefined_behaviour/base_defs_undefined_behaviour.c @@ -0,0 +1,338 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 2022 Critical Software SA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <rtems/bspIo.h> +#include "../shared/utils.h" +#include "../shared/isvv_rtems_aux.h" + +/** + * + * @brief Tests impact of undefined behaviour when using RTEMS_ALIGN_DOWN + * + * This test case performs the calculation of the Mandelbrot set in parallel with + * execution of RTEMS_ALIGN_DOWN directive calls with conditions which lead to + * undefined behaviour + * + */ + +#define ITOA_STR_SIZE (8 * sizeof(int) + 1) + +#define MAX_TLS_SIZE RTEMS_ALIGN_UP(64, RTEMS_TASK_STORAGE_ALIGNMENT) + +#define TASK_STORAGE_SIZE \ + RTEMS_TASK_STORAGE_SIZE( \ + MAX_TLS_SIZE + RTEMS_MINIMUM_STACK_SIZE, \ + TASK_ATTRIBUTES) + +#define TASK_ATTRIBUTES RTEMS_FLOATING_POINT + +// One task for undefined task, and n-1 calculation tasks +#define TASK_COUNT TEST_PROCESSORS + +// We want to create mandelbrot executions whilst our undefined calls are executing +#define CALCULATION_TASKS ((TEST_PROCESSORS)-1) + +#define FUNCTION_CALLS 32 +#define UNDEF_FUNC_CALLS (FUNCTION_CALLS / 2) + +uint16_t align_value[FUNCTION_CALLS] = {0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 64, 127, 255, 256, 257, 511, 512, 513, 1022, 1023, 1024, 1025, 1026, 1027, 1028, 10000, 20000, 30000}; +uint16_t size_target[FUNCTION_CALLS] = {1, 4, 2, 2, 2, 2, 2, 4, 8, 8, 2, 4, 8, 8, 8, 8, 16, 16, 16, 32, 32, 32, 32, 64, 64, 64, 128, 128, 128, 2, 4, 8 }; +int64_t expected_results[FUNCTION_CALLS] = {0, 0, 0, 2, 2, 4, 4, 4, 0, 8, 10, 12, 8, 16, 64, 120, 240, 256, 256, 480, 512, 512, 992, 960, 1024, 1024, 1024, 1024, 1024, 10000, 20000, 30000}; + +int64_t undef_align_value[UNDEF_FUNC_CALLS] = {0, 3, 10, 6, 16, 100, 128, 312, 10, 10, 2, 3 , 4 , 65535, 65537, 4294967295 }; +int64_t undef_size_target[UNDEF_FUNC_CALLS] = {0, 5, 6, 13, -1, -8, 100,-128, 15, -127, -128, (-2147483647 - 1), 2147483647, 65535, 65537, 4294967295 }; + +// Barrier to ensure calculation tasks and undefined behaviour tasks occur concurrently +static rtems_id start_barrier; +static rtems_id TASK_COUNTER_SEMAPHORE; + +// Timing related variables to ensure concurrent executions +#define RELATIVE_SLEEP 0 +#define FUNCTION_WAIT_MICROSECONDS 10 +#define FUNCTION_WAIT_NANOSECONDS (FUNCTION_WAIT_MICROSECONDS * 1000) + +typedef struct +{ + rtems_id calc_task_id[CALCULATION_TASKS]; + rtems_id undefined_task_id; + int64_t results[FUNCTION_CALLS]; + uint32_t functions_start, functions_end; +} test_context; + +// Create storage areas for each worker, using task construct forces +RTEMS_ALIGNED(RTEMS_TASK_STORAGE_ALIGNMENT) +static char task_storage[TASK_COUNT][TASK_STORAGE_SIZE]; + +RTEMS_ALIGNED(CPU_STACK_ALIGNMENT) +static uint32_t task_before_mandelbrot[CALCULATION_TASKS]; + +RTEMS_ALIGNED(CPU_STACK_ALIGNMENT) +static uint32_t task_after_mandelbrot[CALCULATION_TASKS]; + +static void calc_task_function(rtems_task_argument *tile) +{ + uint8_t tile_n = (uint8_t) *tile; + struct timespec uptime; + + WaitAtBarrier(start_barrier); + + // Check time function begins execution of mandelbrot executions + rtems_clock_get_uptime(&uptime); + task_before_mandelbrot[tile_n - 1] = (uint32_t)(uptime.tv_sec * 1000000 + uptime.tv_nsec / 1000); + + mandelbrot_tile(tile_n, CALCULATION_TASKS); + + // Check time function finishes execution of mandelbrot executions + rtems_clock_get_uptime(&uptime); + task_after_mandelbrot[tile_n - 1] = (uint32_t)(uptime.tv_sec * 1000000 + uptime.tv_nsec / 1000); + + // Task has finished so increment counter + ReleaseCounterSemaphore(TASK_COUNTER_SEMAPHORE); + rtems_task_exit(); +} + +static void undefined_behaviour_task(rtems_task_argument arg) +{ + test_context *ctx; + ctx = (test_context *)arg; + struct timespec uptime, function_wait; + + WaitAtBarrier(start_barrier); + + // Wait for 10us to ensure concurrent executions + function_wait.tv_sec = 0; + function_wait.tv_nsec = FUNCTION_WAIT_NANOSECONDS; + clock_nanosleep(CLOCK_MONOTONIC, 0, &function_wait, NULL); + + rtems_clock_get_uptime(&uptime); + ctx->functions_start = (uint32_t)(uptime.tv_sec * 1000000 + uptime.tv_nsec / 1000); + + /* Start execution of events related functions following formula of: + * + * Defined behaviour + * Undefined behaviour + * Defined behaviour + * + * The alignment shall be a power of two, otherwise the returned value is undefined. + * + * Check that RTEMS_ALIGN_DOWN() calculates the expected result and is + * side-effect free. + * + * Alignment downwards aligns this value * down to the nearest multiple of a given size. + * This is to proper utilization of a given amount of memory and improve performance. + * + * The target of this alignment is for computer memory, which for RTEMS is always a power of two, + * however the result of the function RTEMS_ALIGN_DOWN should be ensured to be used carefully in + * actual program construction as other numbers can be used for the size. + * + * NOTE: There is a comment in the definition of the RTEMS_ALIGN_DOWN which states that 'the + * alignment parameter is evaluated twice.' however this is not the case. This is the case, however, + * for RTEMS_ALIGN_UP which performs two evaluations of the alignment parameter and therefore + * potentially the cause for the miscommunication. + */ + + int32_t target; + int32_t size; + + for (uint8_t i = 0; i < FUNCTION_CALLS; i+=2) { + ctx->results[i] = RTEMS_ALIGN_DOWN(align_value[i], size_target[i]); + + target = undef_align_value[i / 2]; + size = undef_size_target[i / 2]; + (void)RTEMS_ALIGN_DOWN(target, size); + + ctx->results[i + 1] = RTEMS_ALIGN_DOWN(align_value[i + 1], size_target[i + 1]); + } + + rtems_clock_get_uptime(&uptime); + ctx->functions_end = (uint32_t)(uptime.tv_sec * 1000000 + uptime.tv_nsec / 1000); + + // Task has finished so increment counter + ReleaseCounterSemaphore(TASK_COUNTER_SEMAPHORE); + rtems_task_exit(); +} + +static void Init(rtems_task_argument arg) +{ + (void)arg; + test_context ctx; + char str[ITOA_STR_SIZE]; + uint8_t wait = 0; + uint32_t args[CALCULATION_TASKS] = {0}; + + TASK_COUNTER_SEMAPHORE = CreateCounterSemaphore(rtems_build_name('T', 'C', 'S', '0'), 0); + + start_barrier = CreateAutomaticBarrier(TASK_COUNT); + + // Config for our mandelbrot tile function, with priority high as we don't want this to be preempted + rtems_task_config calc_task_config = { + .initial_priority = PRIO_HIGH, + .storage_size = TASK_STORAGE_SIZE, + .maximum_thread_local_storage_size = MAX_TLS_SIZE, + .initial_modes = RTEMS_DEFAULT_MODES, + .attributes = TASK_ATTRIBUTES}; + + // Finish config for our mandelbrot tile functions and start them + for (uint32_t i = 0; i < CALCULATION_TASKS; i++) + { + calc_task_config.name = rtems_build_name('R', 'U', 'N', (char)i); + calc_task_config.storage_area = &task_storage[i][0]; + + ctx.calc_task_id[i] = DoCreateTask(calc_task_config); + + args[i] = (i + 1); + StartTask(ctx.calc_task_id[i], (void *) calc_task_function, (void *) &args[i]); + } + + // Config our undefined behaviour task and start it + rtems_task_config undef_task_config = { + .name = rtems_build_name('U', 'N', 'D', 'F'), + .initial_priority = PRIO_NORMAL, + .storage_size = TASK_STORAGE_SIZE, + .maximum_thread_local_storage_size = MAX_TLS_SIZE, + .initial_modes = RTEMS_DEFAULT_MODES, + .attributes = TASK_ATTRIBUTES, + .storage_area = &task_storage[TASK_COUNT-1][0]}; + + ctx.undefined_task_id = DoCreateTask(undef_task_config); + StartTask(ctx.undefined_task_id, undefined_behaviour_task, (void *)&ctx); + + // Wait for all tasks to complete + while (wait < TASK_COUNT) + { + ObtainCounterSemaphore(TASK_COUNTER_SEMAPHORE); + wait++; + } + + // Check concurrent execution + uint32_t latest_task_start = 0; + // Wraps around to effectively be maximum allowed value + uint32_t earliest_task_finish = -1; + + for (uint8_t task = 0; task < CALCULATION_TASKS; task++) + { + latest_task_start = MAX(latest_task_start, task_before_mandelbrot[task]); + earliest_task_finish = MIN(earliest_task_finish, task_after_mandelbrot[task]); + } + + if ((ctx.functions_start >= latest_task_start && ctx.functions_end <= earliest_task_finish)) + { + print_string("Functions and mandelbrot executed concurrently: true\n\n"); + } + else + { + print_string("Functions and mandelbrot executed concurrently: false\n\n"); + } + + // Now check validity of all calls + bool all_correct_flag = TRUE; + for (uint8_t i = 0; i < FUNCTION_CALLS; i++) + { + // If our result isn't true like we expect, print out which are unexpected + if (ctx.results[i] != expected_results[i]) + { + all_correct_flag = FALSE; + print_string("RTEMS_ALIGN_DOWN unexpected result detected: #"); + print_string(itoa(i, &str[0], 10)); + print_string(" is not correct and what was received was: "); + print_string(itoa(ctx.results[i], &str[0], 10)); + print_string(" and should have been: "); + print_string(itoa(expected_results[i], &str[0], 10)); + print_string(" for given value: "); + print_string(itoa(align_value[i], &str[0], 10)); + print_string(", and size: "); + print_string(itoa(size_target[i], &str[0], 10)); + print_string("\n"); + } + } + + if (all_correct_flag) + { + print_string("All alignment calls return expected results: true\n\n"); + } + else + { + print_string("All alignment calls return expected results: false\n\n"); + } + + // Print results of mandelbrot test + print_test_results(); + + rtems_barrier_delete(start_barrier); + rtems_semaphore_delete(TASK_COUNTER_SEMAPHORE); + rtems_fatal(RTEMS_FATAL_SOURCE_EXIT, 0); +} + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER + +#define CONFIGURE_MAXIMUM_PROCESSORS TEST_PROCESSORS + +// Reduce the priority of the Init task so all other tasks can be schedules to all other cores +#define CONFIGURE_INIT_TASK_PRIORITY PRIO_LOW + +#define CONFIGURE_MAXIMUM_BARRIERS 1 + +#define CONFIGURE_MAXIMUM_SEMAPHORES 1 + +// Number of Tasks configured + 1 for the INIT task +#define CONFIGURE_MAXIMUM_TASKS ((TASK_COUNT) + 1) + +#define CONFIGURE_SCHEDULER_EDF_SMP + +#define CONFIGURE_MINIMUM_TASK_STACK_SIZE RTEMS_MINIMUM_STACK_SIZE + CPU_STACK_ALIGNMENT + +#define CONFIGURE_EXTRA_TASK_STACKS RTEMS_MINIMUM_STACK_SIZE + +#define CONFIGURE_INIT_TASK_CONSTRUCT_STORAGE_SIZE 2 * TASK_STORAGE_SIZE + +#define CONFIGURE_MINIMUM_TASKS_WITH_USER_PROVIDED_STORAGE \ + CONFIGURE_MAXIMUM_TASKS + +#define CONFIGURE_MICROSECONDS_PER_TICK 1000 + +#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 0 + +#define CONFIGURE_DISABLE_NEWLIB_REENTRANCY + +#define CONFIGURE_APPLICATION_DISABLE_FILESYSTEM + +#define CONFIGURE_MAXIMUM_THREAD_LOCAL_STORAGE_SIZE MAX_TLS_SIZE + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT_TASK_ATTRIBUTES (RTEMS_SYSTEM_TASK | TASK_ATTRIBUTES) + +#define CONFIGURE_INIT_TASK_INITIAL_MODE + +#define CONFIGURE_INIT + +#include <rtems/confdefs.h>
\ No newline at end of file diff --git a/testsuites/isvv/23.10_uni_cache_l2_enabled/uni_cache_l2_enabled.c b/testsuites/isvv/23.10_uni_cache_l2_enabled/uni_cache_l2_enabled.c new file mode 100644 index 0000000000..25bba95bd4 --- /dev/null +++ b/testsuites/isvv/23.10_uni_cache_l2_enabled/uni_cache_l2_enabled.c @@ -0,0 +1,366 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 2022 Critical Software SA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stddef.h> +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <rtems/bspIo.h> +#include <string.h> +#include "../shared/utils.h" +#include "../shared/isvv_rtems_aux.h" +#include "../shared/low_level_utils.h" + + +/** + * + * @brief Tests impact performing of L2 cache disable/enable + * + * Step 1: Uniprocessor case + * + * In this step the same set of math equations used by several tasks in the + * Multiprocessor version are run in an Uniprocessor and ONE task only environment + * in order to achieve a reference output result for comparison. + * + * There is only one set of math equations processed here: + * - named "filter_simulation" + * + * Result values are obtained for later comparison with multiprocessor + * versions. Also some internal cache statistics are shown. Most relevant one is the + * Elapsed time and L2 cache misses. + * + */ + + +/** + * + * For standalone tests in the actual hardware boards the following options can be used: + * + * 1) make XFLAGS="-Dgr740 -DGR740_ESA_BOARD" + * 2) declare #define GR740_ESA_BOARD at the beginning of this file + * + */ + +#define MAX_TLS_SIZE RTEMS_ALIGN_UP(64, RTEMS_TASK_STORAGE_ALIGNMENT) + +#define TASK_ATTRIBUTES RTEMS_FLOATING_POINT + +#define TASK_STORAGE_SIZE \ + RTEMS_TASK_STORAGE_SIZE( \ + MAX_TLS_SIZE + RTEMS_MINIMUM_STACK_SIZE, \ + TASK_ATTRIBUTES) + +// test specific global vars +#undef TEST_PROCESSORS +#define TEST_PROCESSORS 1 + +#define TASK_COUNT TEST_PROCESSORS +#define TOTAL_TILES 64 + +#define MAX_MESSAGE_SIZE sizeof(uint8_t) +#define MAX_PENDING_MESSAGES 10 + +rtems_event_set event_send[4] = {RTEMS_EVENT_1, + RTEMS_EVENT_2, + RTEMS_EVENT_3, + RTEMS_EVENT_4}; + +uint8_t count_process[TOTAL_TILES]; + +typedef struct{ + uint8_t ntiles; + uint8_t next_tile; + rtems_id task_id[TASK_COUNT]; + rtems_id tile_queue; + uint64_t accxL2; +} test_context; + +#define ITOA_STR_SIZE (8*sizeof(int)+1) + +//----------------------------------------------------------------------------------------- +#define L2_CACHE_SIZE (4U*512U*1024U) // 2Mbytes +#define L2_CACHE_WAY_SIZE (512U*1024U) // 512kbytes +#define xL2_ELEM (L2_CACHE_SIZE/sizeof(uint32_t)) // 512k elements + +#ifdef GR740_ESA_BOARD +RTEMS_ALIGNED(L2_CACHE_SIZE) +#endif +static uint32_t xL2[xL2_ELEM]; + +//----------------------------------------------------------------------------------------- +#define COEFS_SIZE (128U) +const uint32_t coefs[COEFS_SIZE] = + { 29, 31, 37, 41, 43, 47, 53, 59, + 61, 67, 71, 73, 79, 83, 89, 97, + 101, 103, 107, 109, 113, 127, 131, 137, + 139, 149, 151, 157, 163, 167, 173, 179, + 181, 191, 193, 197, 199, 211, 223, 227, + 229, 233, 239, 241, 251, 257, 263, 269, + 271, 277, 281, 283, 293, 307, 311, 313, + 317, 331, 337, 347, 349, 353, 359, 367, + 373, 379, 383, 389, 397, 401, 409, 419, + 421, 431, 433, 439, 443, 449, 457, 461, + 463, 467, 479, 487, 491, 499, 503, 509, + 521, 523, 541, 547, 557, 563, 569, 571, + 577, 587, 593, 599, 601, 607, 613, 617, + 619, 631, 641, 643, 647, 653, 659, 661, + 673, 677, 683, 691, 701, 709, 719, 727, + 733, 739, 743, 751, 757, 761, 769, 773}; + +static void fill_main_memory_with_data(void){ + // Store to memory + for ( uint32_t j = 0 ; j < xL2_ELEM; j ++) + xL2[j] = j; +} + +static uint64_t warmup_caches(void){ + uint64_t acc = 0; + for ( uint32_t j = 0 ; j < xL2_ELEM; j++) + acc += xL2[j]; + return acc; +} + +static uint64_t calc_filter_simulation_equation(uint8_t tile, uint32_t total_elems){ + uint64_t acc = 0; + const uint32_t begin_idx = tile*xL2_ELEM/total_elems; + const uint32_t end_idx = begin_idx + (xL2_ELEM/total_elems) - 1; + + for ( uint32_t j = begin_idx ; j <= end_idx; j ++) { + uint32_t i; + // Simulating filtering/convolution + uint32_t t1 = 0, t2 = 0, t3 = 0, t4 = 0; + for (i = 0 ; i < 128; i++) + t1 += xL2[(j+i) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < 128; i++) + t1 += xL2[(j+i+L2_CACHE_WAY_SIZE*1/8/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < 128; i++) + t1 += xL2[(j+i+L2_CACHE_WAY_SIZE*2/8/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < 128; i++) + t1 += xL2[(j+i+L2_CACHE_WAY_SIZE*3/8/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < 128; i++) + t2 += xL2[(j+i+L2_CACHE_WAY_SIZE*4/8/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < 128; i++) + t2 += xL2[(j+i+L2_CACHE_WAY_SIZE*5/8/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < 128; i++) + t2 += xL2[(j+i+L2_CACHE_WAY_SIZE*6/8/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < 128; i++) + t2 += xL2[(j+i+L2_CACHE_WAY_SIZE*7/8/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + // Simulating normalization + t3 = ((t1*1000)/(42*137)) + 1; + t4 = ((t2*10)/(96*137)) + 1; + uint64_t t5 = (uint64_t)t3 * (uint64_t)t3; + uint64_t t6 = (uint64_t)t4 * (uint64_t)t4; + acc += (t5+t6)/((uint64_t)isqrt(t4+t3)); + } + return acc; +} + +static void Init(rtems_task_argument arg){ + (void)arg; + test_context ctx; + uint32_t start_time, end_time, elapsed_time; + char str[ITOA_STR_SIZE]; + bool correctly_processed = true; + (void) memset(&ctx, 0, sizeof(test_context)); + (void) memset(&count_process[0], 0, TOTAL_TILES); + (void) memset(&xL2[0], 0, xL2_ELEM); + +#ifdef GR740_ESA_BOARD + soc_stats_regs soc_stats; +#endif + + +//----------------------------------------------------------------------------- +// Create/Initialize Objects +//----------------------------------------------------------------------------- + ctx.ntiles = TOTAL_TILES; + ctx.next_tile = 1; + SetSelfPriority( PRIO_NORMAL ); + + +//----------------------------------------------------------------------------- +// Setup the testcase +//----------------------------------------------------------------------------- + fill_main_memory_with_data(); + l1_dcache_flush(); + l1_dcache_disable(); + +#ifdef GR740_ESA_BOARD + l2_cache_disable(); + l2_cache_flush(); + l2_cache_enable(); +#endif + + l1_dcache_enable(); + uint32_t control_data_word = warmup_caches(); + +#ifdef GR740_ESA_BOARD + clockgating_enable_l4stat(); + soc_stats_configure_regs(); + soc_stats_init(&soc_stats); +#endif + +//----------------------------------------------------------------------------- +// Do the work +//----------------------------------------------------------------------------- + start_time = rtems_clock_get_ticks_since_boot(); + ctx.accxL2 = calc_filter_simulation_equation(0, 1); + + end_time = rtems_clock_get_ticks_since_boot(); + elapsed_time = end_time - start_time; + +#ifdef GR740_ESA_BOARD + soc_stats_update(&soc_stats); +#endif + +//----------------------------------------------------------------------------- +// Show Results +//----------------------------------------------------------------------------- + print_string("\n"); + print_string("Single Core Elapsed Time -"); + print_string(itoa(elapsed_time, &str[0], 10)); + print_string("\n"); + + for (uint8_t i = 0; i < ctx.ntiles; i++){ + if (count_process[i] != 1){ + correctly_processed = false; + break; + } + } + if (correctly_processed){ + print_string("Each tile only processed once : true\n"); + } + else{ + print_string("Each tile only processed once : false\n"); + } + + print_string("Input Data Result Value : 0x"); + print_string(itoa(control_data_word , &str[0], 16)); + print_string("\n"); + + print_string("Ouput Data Result Value : 0x"); + if (ctx.accxL2>=UINT32_MAX) { + print_string(itoa( (int32_t) ((ctx.accxL2 >> 32U) & ((uint64_t)UINT32_MAX)) , &str[0], 16)); + print_string(itoa( (int32_t) (ctx.accxL2 & ((uint64_t)UINT32_MAX)) , &str[0], 16)); + } + else { + print_string(itoa((int32_t)ctx.accxL2 , &str[0], 16)); + } + print_string("\n"); + + +#ifdef GR740_ESA_BOARD + print_string("L1 Instr Cache misses (read) CPU_0 : "); + print_string(itoa(soc_stats.l1_inst_cache_miss[0], &str[0], 10)); + print_string("\n"); + print_string("L1 Instr Cache misses (read) CPU_1 : "); + print_string(itoa(soc_stats.l1_inst_cache_miss[1], &str[0], 10)); + print_string("\n"); + print_string("L1 Instr Cache misses (read) CPU_2 : "); + print_string(itoa(soc_stats.l1_inst_cache_miss[2], &str[0], 10)); + print_string("\n"); + print_string("L1 Instr Cache misses (read) CPU_3 : "); + print_string(itoa(soc_stats.l1_inst_cache_miss[3], &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses (read) CPU_0 : "); + print_string(itoa(soc_stats.l1_data_cache_miss[0], &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses (read) CPU_1 : "); + print_string(itoa(soc_stats.l1_data_cache_miss[1], &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses (read) CPU_2 : "); + print_string(itoa(soc_stats.l1_data_cache_miss[2], &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses (read) CPU_3 : "); + print_string(itoa(soc_stats.l1_data_cache_miss[3], &str[0], 10)); + print_string("\n"); + print_string("L2 Cache hits (read + writes) : "); + print_string(itoa(soc_stats.l2_cache_hits, &str[0], 10)); + print_string("\n"); + print_string("L2 Cache misses (read + writes) : "); + print_string(itoa(soc_stats.l2_cache_miss, &str[0], 10)); + print_string("\n"); + print_string("AHB Splits : "); + print_string(itoa(soc_stats.ahb_split_delay, &str[0], 10)); + print_string("\n"); + print_string("\n"); +#endif + +// -------------------------------------------------------------------------- +// Delete Objects and Finalize testcase +// -------------------------------------------------------------------------- + + rtems_fatal(RTEMS_FATAL_SOURCE_EXIT, 0); +} + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER + +#define CONFIGURE_MAXIMUM_PROCESSORS TEST_PROCESSORS + +#define CONFIGURE_MAXIMUM_TASKS TEST_PROCESSORS + +#define CONFIGURE_SCHEDULER_EDF_SMP + +#define CONFIGURE_MINIMUM_TASK_STACK_SIZE \ + RTEMS_MINIMUM_STACK_SIZE + CPU_STACK_ALIGNMENT + +#define CONFIGURE_EXTRA_TASK_STACKS RTEMS_MINIMUM_STACK_SIZE + +#define CONFIGURE_INIT_TASK_CONSTRUCT_STORAGE_SIZE 2 * TASK_STORAGE_SIZE + +#define CONFIGURE_MINIMUM_TASKS_WITH_USER_PROVIDED_STORAGE \ + CONFIGURE_MAXIMUM_TASKS + +#define CONFIGURE_MICROSECONDS_PER_TICK 1000 + +#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 0 + +#define CONFIGURE_DISABLE_NEWLIB_REENTRANCY + +#define CONFIGURE_APPLICATION_DISABLE_FILESYSTEM + +#define CONFIGURE_MAXIMUM_THREAD_LOCAL_STORAGE_SIZE MAX_TLS_SIZE + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT_TASK_ATTRIBUTES (RTEMS_SYSTEM_TASK | TASK_ATTRIBUTES) + +#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES + +#define CONFIGURE_INIT + +#include <rtems/confdefs.h> diff --git a/testsuites/isvv/23.11_multi_cache_l2_enabled/multi_cache_l2_enabled.c b/testsuites/isvv/23.11_multi_cache_l2_enabled/multi_cache_l2_enabled.c new file mode 100644 index 0000000000..99b2abcf33 --- /dev/null +++ b/testsuites/isvv/23.11_multi_cache_l2_enabled/multi_cache_l2_enabled.c @@ -0,0 +1,489 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 2022 Critical Software SA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stddef.h> +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <rtems/bspIo.h> +#include <string.h> +#include "../shared/utils.h" +#include "../shared/isvv_rtems_aux.h" +#include "../shared/low_level_utils.h" + + +/** + * + * @brief Tests impact performing of L2 cache enabled/disable + * + * Step 2: Multiprocessor with L2 cache enabled + * + * There is one set of math equations processed: + * - named "filter_simulation" + * + * The equations for "filter_simulation" are used by TEST_PROCESSORS tasks that + * processes small sections of a "data array" in parallel. + * + * The locations in memory for acessing the small sections of the "data arrays" do + * overlap in terms of cache memory positions, and when acessing one section of the + * "data array", or even a smaller part of one, other sections of that "data array" + * should be kicked out of the cache. Sometimes that may happen within the same task. + * + * With the "L2 cache" disabled, every data word missed in l1 cache must be retreived + * from the main memory which can be significantly slower that L2 Cache. With the + * "L2 cache" enabled, in the case of a l2 cache hit a small number of data words + * are transactioned with the L1 cache right away, avoiding acessing the slower main + * memory. + * + * Expected Results: + * - The Tiles must be processed only once. + * - "Ouput Data Result Value" must match with the Uniprocessor version and with the + * Multiprocessor version with L2 cache disabled. + * - Elapsed Time should be lower than the Uniprocessor version, and also lower + * than Multiprocessor version with L2 cache disable. + * - Significant number of L2 cache misses + * + */ + +/** + * + * For standalone tests in the actual hardware boards the following options can be used: + * + * 1) make XFLAGS="-Dgr740 -DGR740_ESA_BOARD" + * 2) declare #define GR740_ESA_BOARD at the beginning of this file + * + */ + +#define MAX_TLS_SIZE RTEMS_ALIGN_UP(64, RTEMS_TASK_STORAGE_ALIGNMENT) + +#define TASK_ATTRIBUTES RTEMS_FLOATING_POINT + +#define TASK_STORAGE_SIZE \ + RTEMS_TASK_STORAGE_SIZE( \ + MAX_TLS_SIZE + RTEMS_MINIMUM_STACK_SIZE, \ + TASK_ATTRIBUTES) + +// test specific global vars +#define TASK_COUNT TEST_PROCESSORS +#define TOTAL_TILES 64 + +#define MAX_MESSAGE_QUEUES 5 +#define MAX_MESSAGE_SIZE sizeof(uint8_t) +#define MAX_PENDING_MESSAGES 10 + +rtems_event_set event_send[4] = {RTEMS_EVENT_1, + RTEMS_EVENT_2, + RTEMS_EVENT_3, + RTEMS_EVENT_4}; + +uint8_t count_process[TOTAL_TILES]; + +typedef struct{ + rtems_id main_task; + uint8_t ntiles; + uint8_t next_tile; + rtems_id task_id[TASK_COUNT]; + rtems_id tile_queue; + rtems_id message_queue[TASK_COUNT]; + rtems_id mutex_id; + uint64_t accxL2; +} test_context; + +RTEMS_ALIGNED(RTEMS_TASK_STORAGE_ALIGNMENT) +static char calc_task_storage[TASK_COUNT][TASK_STORAGE_SIZE]; + +RTEMS_MESSAGE_QUEUE_BUFFER(MAX_MESSAGE_SIZE) +msg_tile_queue_storage[MAX_PENDING_MESSAGES]; + +RTEMS_MESSAGE_QUEUE_BUFFER(MAX_MESSAGE_SIZE) +msg_task_queue_storage[TASK_COUNT][MAX_PENDING_MESSAGES]; + + +#define ITOA_STR_SIZE (8*sizeof(int)+1) + +//----------------------------------------------------------------------------------------- +#define L2_CACHE_SIZE (4U*512U*1024U) // 2Mbytes +#define L2_CACHE_WAY_SIZE (512U*1024U) // 512kbytes +#define xL2_ELEM (L2_CACHE_SIZE/sizeof(uint32_t)) // 512k elements + +#ifdef GR740_ESA_BOARD +RTEMS_ALIGNED(L2_CACHE_SIZE) +#endif +static uint32_t xL2[xL2_ELEM]; + +//----------------------------------------------------------------------------------------- +#define COEFS_SIZE (128U) +const uint32_t coefs[COEFS_SIZE] = + { 29, 31, 37, 41, 43, 47, 53, 59, + 61, 67, 71, 73, 79, 83, 89, 97, + 101, 103, 107, 109, 113, 127, 131, 137, + 139, 149, 151, 157, 163, 167, 173, 179, + 181, 191, 193, 197, 199, 211, 223, 227, + 229, 233, 239, 241, 251, 257, 263, 269, + 271, 277, 281, 283, 293, 307, 311, 313, + 317, 331, 337, 347, 349, 353, 359, 367, + 373, 379, 383, 389, 397, 401, 409, 419, + 421, 431, 433, 439, 443, 449, 457, 461, + 463, 467, 479, 487, 491, 499, 503, 509, + 521, 523, 541, 547, 557, 563, 569, 571, + 577, 587, 593, 599, 601, 607, 613, 617, + 619, 631, 641, 643, 647, 653, 659, 661, + 673, 677, 683, 691, 701, 709, 719, 727, + 733, 739, 743, 751, 757, 761, 769, 773}; + +static void fill_main_memory_with_data(void){ + // Store to memory + for ( uint32_t j = 0 ; j < xL2_ELEM; j ++) + xL2[j] = j; +} + +static uint64_t warmup_caches(void){ + uint64_t acc = 0; + for ( uint32_t j = 0 ; j < xL2_ELEM; j++) + acc += xL2[j]; + return acc; +} + +static uint64_t calc_filter_simulation_equation(uint8_t tile, uint32_t total_elems){ + uint64_t acc = 0; + const uint32_t begin_idx = tile*xL2_ELEM/total_elems; + const uint32_t end_idx = begin_idx + (xL2_ELEM/total_elems) - 1; + + for ( uint32_t j = begin_idx ; j <= end_idx; j ++) { + uint32_t i; + // Simulating filtering/convolution + uint32_t t1 = 0, t2 = 0, t3 = 0, t4 = 0; + for (i = 0 ; i < 128; i++) + t1 += xL2[(j+i) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < 128; i++) + t1 += xL2[(j+i+L2_CACHE_WAY_SIZE*1/8/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < 128; i++) + t1 += xL2[(j+i+L2_CACHE_WAY_SIZE*2/8/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < 128; i++) + t1 += xL2[(j+i+L2_CACHE_WAY_SIZE*3/8/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < 128; i++) + t2 += xL2[(j+i+L2_CACHE_WAY_SIZE*4/8/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < 128; i++) + t2 += xL2[(j+i+L2_CACHE_WAY_SIZE*5/8/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < 128; i++) + t2 += xL2[(j+i+L2_CACHE_WAY_SIZE*6/8/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < 128; i++) + t2 += xL2[(j+i+L2_CACHE_WAY_SIZE*7/8/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + // Simulating normalization + t3 = ((t1*1000)/(42*137)) + 1; + t4 = ((t2*10)/(96*137)) + 1; + uint64_t t5 = (uint64_t)t3 * (uint64_t)t3; + uint64_t t6 = (uint64_t)t4 * (uint64_t)t4; + acc += (t5+t6)/((uint64_t)isqrt(t4+t3)); + } + return acc; +} + + +static void calc_task_function(rtems_task_argument arg) +{ + test_context *ctx; + uint64_t acc; + + ctx = (test_context *)arg; + + uint8_t tile; + rtems_id local_id = TaskSelfId(); + uint8_t task_idx = 255; + + for (int i = 0; i < TASK_COUNT; i++){ + if (ctx->task_id[i] == local_id){ + task_idx = i; + break; + } + } + + char ch = '0' + task_idx; + + rtems_message_queue_config msg_config = { + .name = rtems_build_name('M', 'S', 'G', ch), + .maximum_pending_messages = MAX_PENDING_MESSAGES, + .maximum_message_size = MAX_MESSAGE_SIZE, + .storage_size = sizeof(msg_task_queue_storage[task_idx]), + .storage_area = &msg_task_queue_storage[task_idx], + .attributes = RTEMS_FIFO | RTEMS_GLOBAL}; + + ctx->message_queue[task_idx] = CreateMessageQueue(msg_config); + + SendMessage(ctx->tile_queue, &task_idx, sizeof(task_idx)); + ReceiveMessage(ctx->message_queue[task_idx], &tile); + + while (tile <= ctx->ntiles) { + acc = 0; + count_process[tile - 1]++; + acc = calc_filter_simulation_equation(tile-1, ctx->ntiles); + + ObtainMutex(ctx->mutex_id); + ctx->accxL2 += acc; + ReleaseMutex(ctx->mutex_id); + + SendMessage(ctx->tile_queue, &task_idx, sizeof(task_idx)); + ReceiveMessage(ctx->message_queue[task_idx], &tile); + } + + SendMessage(ctx->tile_queue, &task_idx, sizeof(task_idx)); + SendEvents(ctx->main_task, event_send[task_idx]); + SuspendSelf(); +} + +static void Init(rtems_task_argument arg) +{ + (void)arg; + test_context ctx; + uint32_t start_time, end_time, elapsed_time; + char ch, str[ITOA_STR_SIZE]; + uint32_t total_events = 0; + uint8_t task = 255; + bool correctly_processed = true; + (void) memset(&ctx, 0, sizeof(test_context)); + (void) memset(&count_process[0], 0, TOTAL_TILES); + (void) memset(&xL2[0], 0, xL2_ELEM); + +#ifdef GR740_ESA_BOARD + soc_stats_regs soc_stats; +#endif + + +//----------------------------------------------------------------------------- +// Create/Initialize Objects +//----------------------------------------------------------------------------- + rtems_message_queue_config msg_config = { + .name = rtems_build_name('M', 'S', 'G', 'T'), + .maximum_pending_messages = RTEMS_ARRAY_SIZE(msg_tile_queue_storage), + .maximum_message_size = MAX_MESSAGE_SIZE, + .storage_size = sizeof(msg_tile_queue_storage), + .storage_area = &msg_tile_queue_storage, + .attributes = RTEMS_FIFO | RTEMS_GLOBAL}; + + ctx.main_task = rtems_task_self(); + ctx.tile_queue = CreateMessageQueue(msg_config); + ctx.ntiles = TOTAL_TILES; + ctx.next_tile = 1; + + rtems_task_config calc_task_config = { + .initial_priority = PRIO_NORMAL, + .storage_size = TASK_STORAGE_SIZE, + .maximum_thread_local_storage_size = MAX_TLS_SIZE, + .initial_modes = RTEMS_DEFAULT_MODES, + .attributes = TASK_ATTRIBUTES}; + + ctx.mutex_id = CreateMutex(rtems_build_name('M', 'U', 'T', 'X')); + + for (uint32_t i = 0; i < TASK_COUNT; i++){ + ch = '0' + i; + calc_task_config.name = rtems_build_name('R', 'U', 'N', ch); + calc_task_config.storage_area = &calc_task_storage[i][0]; + + ctx.task_id[i] = DoCreateTask(calc_task_config); + StartTask(ctx.task_id[i], calc_task_function, &ctx); + total_events += event_send[i]; + } + SetSelfPriority( PRIO_NORMAL ); + + +//----------------------------------------------------------------------------- +// Setup the testcase +//----------------------------------------------------------------------------- + fill_main_memory_with_data(); + l1_dcache_flush(); + l1_dcache_disable(); + +#ifdef GR740_ESA_BOARD + l2_cache_disable(); + l2_cache_flush(); + l2_cache_enable(); +#endif + + l1_dcache_enable(); + uint32_t control_data_word = warmup_caches(); + +#ifdef GR740_ESA_BOARD + clockgating_enable_l4stat(); + soc_stats_configure_regs(); + soc_stats_init(&soc_stats); +#endif + +//----------------------------------------------------------------------------- +// Do the work: distribute the work through the tasks +//----------------------------------------------------------------------------- + start_time = rtems_clock_get_ticks_since_boot(); + while (ReceiveAvailableEvents() != total_events) + { + ReceiveMessage(ctx.tile_queue, &task); + SendMessage(ctx.message_queue[task], &ctx.next_tile, sizeof(ctx.next_tile)); + ctx.next_tile++; + } + end_time = rtems_clock_get_ticks_since_boot(); + elapsed_time = end_time - start_time; + +#ifdef GR740_ESA_BOARD + soc_stats_update(&soc_stats); +#endif + +//----------------------------------------------------------------------------- +// Show Results +//----------------------------------------------------------------------------- + print_string("\n"); + print_string("Multicore Elapsed Time -"); + print_string(itoa(elapsed_time, &str[0], 10)); + print_string("\n"); + + for (uint8_t i = 0; i < ctx.ntiles; i++){ + if (count_process[i] != 1){ + correctly_processed = false; + break; + } + } + if (correctly_processed){ + print_string("Each tile only processed once : true\n"); + } + else{ + print_string("Each tile only processed once : false\n"); + } + + print_string("Input Data Result Value : 0x"); + print_string(itoa(control_data_word , &str[0], 16)); + print_string("\n"); + + print_string("Ouput Data Result Value : 0x"); + if (ctx.accxL2>=UINT32_MAX) { + print_string(itoa( (int32_t) ((ctx.accxL2 >> 32U) & ((uint64_t)UINT32_MAX)) , &str[0], 16)); + print_string(itoa( (int32_t) (ctx.accxL2 & ((uint64_t)UINT32_MAX)) , &str[0], 16)); + } + else { + print_string(itoa((int32_t)ctx.accxL2 , &str[0], 16)); + } + print_string("\n"); + + +#ifdef GR740_ESA_BOARD + print_string("L1 Instr Cache misses (read) CPU_0 : "); + print_string(itoa(soc_stats.l1_inst_cache_miss[0], &str[0], 10)); + print_string("\n"); + print_string("L1 Instr Cache misses (read) CPU_1 : "); + print_string(itoa(soc_stats.l1_inst_cache_miss[1], &str[0], 10)); + print_string("\n"); + print_string("L1 Instr Cache misses (read) CPU_2 : "); + print_string(itoa(soc_stats.l1_inst_cache_miss[2], &str[0], 10)); + print_string("\n"); + print_string("L1 Instr Cache misses (read) CPU_3 : "); + print_string(itoa(soc_stats.l1_inst_cache_miss[3], &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses (read) CPU_0 : "); + print_string(itoa(soc_stats.l1_data_cache_miss[0], &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses (read) CPU_1 : "); + print_string(itoa(soc_stats.l1_data_cache_miss[1], &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses (read) CPU_2 : "); + print_string(itoa(soc_stats.l1_data_cache_miss[2], &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses (read) CPU_3 : "); + print_string(itoa(soc_stats.l1_data_cache_miss[3], &str[0], 10)); + print_string("\n"); + print_string("L2 Cache hits (read + writes) : "); + print_string(itoa(soc_stats.l2_cache_hits, &str[0], 10)); + print_string("\n"); + print_string("L2 Cache misses (read + writes) : "); + print_string(itoa(soc_stats.l2_cache_miss, &str[0], 10)); + print_string("\n"); + print_string("AHB Splits : "); + print_string(itoa(soc_stats.ahb_split_delay, &str[0], 10)); + print_string("\n"); + print_string("\n"); +#endif + +// -------------------------------------------------------------------------- +// Delete Objects and Finalize testcase +// -------------------------------------------------------------------------- + for (uint32_t i = 0; i < TASK_COUNT; i++){ + DeleteTask(ctx.task_id[i]); + DeleteMessageQueue(ctx.message_queue[i]); + } + DeleteMessageQueue(ctx.tile_queue); + + DeleteMutex(ctx.mutex_id); + + rtems_fatal(RTEMS_FATAL_SOURCE_EXIT, 0); +} + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER + +#define CONFIGURE_MAXIMUM_PROCESSORS TEST_PROCESSORS + +#define CONFIGURE_MAXIMUM_MESSAGE_QUEUES MAX_MESSAGE_QUEUES + +#define CONFIGURE_MAXIMUM_SEMAPHORES 1 + +#define CONFIGURE_MAXIMUM_TASKS ( TEST_PROCESSORS + 1 ) + +#define CONFIGURE_SCHEDULER_EDF_SMP + +#define CONFIGURE_MINIMUM_TASK_STACK_SIZE \ + RTEMS_MINIMUM_STACK_SIZE + CPU_STACK_ALIGNMENT + +#define CONFIGURE_EXTRA_TASK_STACKS RTEMS_MINIMUM_STACK_SIZE + +#define CONFIGURE_INIT_TASK_CONSTRUCT_STORAGE_SIZE 2 * TASK_STORAGE_SIZE + +#define CONFIGURE_MINIMUM_TASKS_WITH_USER_PROVIDED_STORAGE \ + CONFIGURE_MAXIMUM_TASKS + +#define CONFIGURE_MICROSECONDS_PER_TICK 1000 + +#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 0 + +#define CONFIGURE_DISABLE_NEWLIB_REENTRANCY + +#define CONFIGURE_APPLICATION_DISABLE_FILESYSTEM + +#define CONFIGURE_MAXIMUM_THREAD_LOCAL_STORAGE_SIZE MAX_TLS_SIZE + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT_TASK_ATTRIBUTES (RTEMS_SYSTEM_TASK | TASK_ATTRIBUTES) + +#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES + +#define CONFIGURE_INIT + +#include <rtems/confdefs.h> diff --git a/testsuites/isvv/23.12_multi_cache_l2_disabled/multi_cache_l2_disabled.c b/testsuites/isvv/23.12_multi_cache_l2_disabled/multi_cache_l2_disabled.c new file mode 100644 index 0000000000..dbdcee164f --- /dev/null +++ b/testsuites/isvv/23.12_multi_cache_l2_disabled/multi_cache_l2_disabled.c @@ -0,0 +1,491 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 2022 Critical Software SA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stddef.h> +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <rtems/bspIo.h> +#include <string.h> +#include "../shared/utils.h" +#include "../shared/isvv_rtems_aux.h" +#include "../shared/low_level_utils.h" + + +/** + * + * @brief Tests impact performing of L2 cache enabled/disable + * + * Step 3: Multiprocessor with L2 cache disable + * + * There is one set of math equations processed: + * - named "filter_simulation" + * + * The equations for "filter_simulation" are used by TEST_PROCESSORS tasks that + * processes small sections of a "data array" in parallel. + * + * The locations in memory for acessing the small sections of the "data arrays" do + * overlap in terms of cache memory positions, and when acessing one section of the + * "data array", or even a smaller part of one, other sections of that "data array" + * should be kicked out of the cache. Sometimes that may happen within the same task. + * + * With the "L2 cache" disabled, every data word missed in l1 cache must be retreived + * from the main memory which can be significantly slower that L2 Cache. With the + * "L2 cache" enabled, in the case of a l2 cache hit a small number of data words + * are transactioned with the L1 cache right away, avoiding acessing the slower main + * memory. + * + * Expected Results: + * - The Tiles must be processed only once. + * - "Ouput Data Result Value" must match with the Uniprocessor version with the + * Multiprocessor version with L2 cache enabled. + * - Elapsed Time should be lower than the Uniprocessor version, but higher + * than Multiprocessor version with L2 cache disable. + * - Zero L2 cache misses reported + * + */ + + +/** + * + * For standalone tests in the actual hardware boards the following options can be used: + * + * 1) make XFLAGS="-Dgr740 -DGR740_ESA_BOARD" + * 2) declare #define GR740_ESA_BOARD at the beginning of this file + * + */ + +#define MAX_TLS_SIZE RTEMS_ALIGN_UP(64, RTEMS_TASK_STORAGE_ALIGNMENT) + +#define TASK_ATTRIBUTES RTEMS_FLOATING_POINT + +#define TASK_STORAGE_SIZE \ + RTEMS_TASK_STORAGE_SIZE( \ + MAX_TLS_SIZE + RTEMS_MINIMUM_STACK_SIZE, \ + TASK_ATTRIBUTES) + +// test specific global vars +#define TASK_COUNT TEST_PROCESSORS +#define TOTAL_TILES 64 + +#define MAX_MESSAGE_QUEUES 5 +#define MAX_MESSAGE_SIZE sizeof(uint8_t) +#define MAX_PENDING_MESSAGES 10 + +rtems_event_set event_send[4] = {RTEMS_EVENT_1, + RTEMS_EVENT_2, + RTEMS_EVENT_3, + RTEMS_EVENT_4}; + +uint8_t count_process[TOTAL_TILES]; + +typedef struct{ + rtems_id main_task; + uint8_t ntiles; + uint8_t next_tile; + rtems_id task_id[TASK_COUNT]; + rtems_id tile_queue; + rtems_id message_queue[TASK_COUNT]; + rtems_id mutex_id; + uint64_t accxL2; +} test_context; + +RTEMS_ALIGNED(RTEMS_TASK_STORAGE_ALIGNMENT) +static char calc_task_storage[TASK_COUNT][TASK_STORAGE_SIZE]; + +RTEMS_MESSAGE_QUEUE_BUFFER(MAX_MESSAGE_SIZE) +msg_tile_queue_storage[MAX_PENDING_MESSAGES]; + +RTEMS_MESSAGE_QUEUE_BUFFER(MAX_MESSAGE_SIZE) +msg_task_queue_storage[TASK_COUNT][MAX_PENDING_MESSAGES]; + + +#define ITOA_STR_SIZE (8*sizeof(int)+1) + +//----------------------------------------------------------------------------------------- +#define L2_CACHE_SIZE (4U*512U*1024U) // 2Mbytes +#define L2_CACHE_WAY_SIZE (512U*1024U) // 512kbytes +#define xL2_ELEM (L2_CACHE_SIZE/sizeof(uint32_t)) // 512k elements + +#ifdef GR740_ESA_BOARD +RTEMS_ALIGNED(L2_CACHE_SIZE) +#endif +static uint32_t xL2[xL2_ELEM]; + +//----------------------------------------------------------------------------------------- +#define COEFS_SIZE (128U) +const uint32_t coefs[COEFS_SIZE] = + { 29, 31, 37, 41, 43, 47, 53, 59, + 61, 67, 71, 73, 79, 83, 89, 97, + 101, 103, 107, 109, 113, 127, 131, 137, + 139, 149, 151, 157, 163, 167, 173, 179, + 181, 191, 193, 197, 199, 211, 223, 227, + 229, 233, 239, 241, 251, 257, 263, 269, + 271, 277, 281, 283, 293, 307, 311, 313, + 317, 331, 337, 347, 349, 353, 359, 367, + 373, 379, 383, 389, 397, 401, 409, 419, + 421, 431, 433, 439, 443, 449, 457, 461, + 463, 467, 479, 487, 491, 499, 503, 509, + 521, 523, 541, 547, 557, 563, 569, 571, + 577, 587, 593, 599, 601, 607, 613, 617, + 619, 631, 641, 643, 647, 653, 659, 661, + 673, 677, 683, 691, 701, 709, 719, 727, + 733, 739, 743, 751, 757, 761, 769, 773}; + +static void fill_main_memory_with_data(void){ + // Store to memory + for ( uint32_t j = 0 ; j < xL2_ELEM; j ++) + xL2[j] = j; +} + +static uint64_t warmup_caches(void){ + uint64_t acc = 0; + for ( uint32_t j = 0 ; j < xL2_ELEM; j++) + acc += xL2[j]; + return acc; +} + +static uint64_t calc_filter_simulation_equation(uint8_t tile, uint32_t total_elems){ + uint64_t acc = 0; + const uint32_t begin_idx = tile*xL2_ELEM/total_elems; + const uint32_t end_idx = begin_idx + (xL2_ELEM/total_elems) - 1; + + for ( uint32_t j = begin_idx ; j <= end_idx; j ++) { + uint32_t i; + // Simulating filtering/convolution + uint32_t t1 = 0, t2 = 0, t3 = 0, t4 = 0; + for (i = 0 ; i < 128; i++) + t1 += xL2[(j+i) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < 128; i++) + t1 += xL2[(j+i+L2_CACHE_WAY_SIZE*1/8/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < 128; i++) + t1 += xL2[(j+i+L2_CACHE_WAY_SIZE*2/8/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < 128; i++) + t1 += xL2[(j+i+L2_CACHE_WAY_SIZE*3/8/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < 128; i++) + t2 += xL2[(j+i+L2_CACHE_WAY_SIZE*4/8/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < 128; i++) + t2 += xL2[(j+i+L2_CACHE_WAY_SIZE*5/8/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < 128; i++) + t2 += xL2[(j+i+L2_CACHE_WAY_SIZE*6/8/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < 128; i++) + t2 += xL2[(j+i+L2_CACHE_WAY_SIZE*7/8/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + // Simulating normalization + t3 = ((t1*1000)/(42*137)) + 1; + t4 = ((t2*10)/(96*137)) + 1; + uint64_t t5 = (uint64_t)t3 * (uint64_t)t3; + uint64_t t6 = (uint64_t)t4 * (uint64_t)t4; + acc += (t5+t6)/((uint64_t)isqrt(t4+t3)); + } + return acc; +} + + +static void calc_task_function(rtems_task_argument arg) +{ + test_context *ctx; + uint64_t acc; + + ctx = (test_context *)arg; + + uint8_t tile; + rtems_id local_id = TaskSelfId(); + uint8_t task_idx = 255; + + for (int i = 0; i < TASK_COUNT; i++){ + if (ctx->task_id[i] == local_id){ + task_idx = i; + break; + } + } + + char ch = '0' + task_idx; + + rtems_message_queue_config msg_config = { + .name = rtems_build_name('M', 'S', 'G', ch), + .maximum_pending_messages = MAX_PENDING_MESSAGES, + .maximum_message_size = MAX_MESSAGE_SIZE, + .storage_size = sizeof(msg_task_queue_storage[task_idx]), + .storage_area = &msg_task_queue_storage[task_idx], + .attributes = RTEMS_FIFO | RTEMS_GLOBAL}; + + ctx->message_queue[task_idx] = CreateMessageQueue(msg_config); + + SendMessage(ctx->tile_queue, &task_idx, sizeof(task_idx)); + ReceiveMessage(ctx->message_queue[task_idx], &tile); + + while (tile <= ctx->ntiles) { + acc = 0; + count_process[tile - 1]++; + acc = calc_filter_simulation_equation(tile-1, ctx->ntiles); + + ObtainMutex(ctx->mutex_id); + ctx->accxL2 += acc; + ReleaseMutex(ctx->mutex_id); + + SendMessage(ctx->tile_queue, &task_idx, sizeof(task_idx)); + ReceiveMessage(ctx->message_queue[task_idx], &tile); + } + + SendMessage(ctx->tile_queue, &task_idx, sizeof(task_idx)); + SendEvents(ctx->main_task, event_send[task_idx]); + SuspendSelf(); +} + +static void Init(rtems_task_argument arg) +{ + (void)arg; + test_context ctx; + uint32_t start_time, end_time, elapsed_time; + char ch, str[ITOA_STR_SIZE]; + uint32_t total_events = 0; + uint8_t task = 255; + bool correctly_processed = true; + (void) memset(&ctx, 0, sizeof(test_context)); + (void) memset(&count_process[0], 0, TOTAL_TILES); + (void) memset(&xL2[0], 0, xL2_ELEM); + +#ifdef GR740_ESA_BOARD + soc_stats_regs soc_stats; +#endif + + +//----------------------------------------------------------------------------- +// Create/Initialize Objects +//----------------------------------------------------------------------------- + rtems_message_queue_config msg_config = { + .name = rtems_build_name('M', 'S', 'G', 'T'), + .maximum_pending_messages = RTEMS_ARRAY_SIZE(msg_tile_queue_storage), + .maximum_message_size = MAX_MESSAGE_SIZE, + .storage_size = sizeof(msg_tile_queue_storage), + .storage_area = &msg_tile_queue_storage, + .attributes = RTEMS_FIFO | RTEMS_GLOBAL}; + + ctx.main_task = rtems_task_self(); + ctx.tile_queue = CreateMessageQueue(msg_config); + ctx.ntiles = TOTAL_TILES; + ctx.next_tile = 1; + + rtems_task_config calc_task_config = { + .initial_priority = PRIO_NORMAL, + .storage_size = TASK_STORAGE_SIZE, + .maximum_thread_local_storage_size = MAX_TLS_SIZE, + .initial_modes = RTEMS_DEFAULT_MODES, + .attributes = TASK_ATTRIBUTES}; + + ctx.mutex_id = CreateMutex(rtems_build_name('M', 'U', 'T', 'X')); + + for (uint32_t i = 0; i < TASK_COUNT; i++){ + ch = '0' + i; + calc_task_config.name = rtems_build_name('R', 'U', 'N', ch); + calc_task_config.storage_area = &calc_task_storage[i][0]; + + ctx.task_id[i] = DoCreateTask(calc_task_config); + StartTask(ctx.task_id[i], calc_task_function, &ctx); + total_events += event_send[i]; + } + SetSelfPriority( PRIO_NORMAL ); + + +//----------------------------------------------------------------------------- +// Setup the testcase +//----------------------------------------------------------------------------- + fill_main_memory_with_data(); + l1_dcache_flush(); + l1_dcache_disable(); + +#ifdef GR740_ESA_BOARD + l2_cache_disable(); + l2_cache_flush(); + +#endif + + l1_dcache_enable(); + uint32_t control_data_word = warmup_caches(); + +#ifdef GR740_ESA_BOARD + clockgating_enable_l4stat(); + soc_stats_configure_regs(); + soc_stats_init(&soc_stats); +#endif + +//----------------------------------------------------------------------------- +// Do the work: distribute the work through the tasks +//----------------------------------------------------------------------------- + start_time = rtems_clock_get_ticks_since_boot(); + while (ReceiveAvailableEvents() != total_events) + { + ReceiveMessage(ctx.tile_queue, &task); + SendMessage(ctx.message_queue[task], &ctx.next_tile, sizeof(ctx.next_tile)); + ctx.next_tile++; + } + end_time = rtems_clock_get_ticks_since_boot(); + elapsed_time = end_time - start_time; + +#ifdef GR740_ESA_BOARD + soc_stats_update(&soc_stats); +#endif + +//----------------------------------------------------------------------------- +// Show Results +//----------------------------------------------------------------------------- + print_string("\n"); + print_string("Multicore Elapsed Time -"); + print_string(itoa(elapsed_time, &str[0], 10)); + print_string("\n"); + + for (uint8_t i = 0; i < ctx.ntiles; i++){ + if (count_process[i] != 1){ + correctly_processed = false; + break; + } + } + if (correctly_processed){ + print_string("Each tile only processed once : true\n"); + } + else{ + print_string("Each tile only processed once : false\n"); + } + + print_string("Input Data Result Value : 0x"); + print_string(itoa(control_data_word , &str[0], 16)); + print_string("\n"); + + print_string("Ouput Data Result Value : 0x"); + if (ctx.accxL2>=UINT32_MAX) { + print_string(itoa( (int32_t) ((ctx.accxL2 >> 32U) & ((uint64_t)UINT32_MAX)) , &str[0], 16)); + print_string(itoa( (int32_t) (ctx.accxL2 & ((uint64_t)UINT32_MAX)) , &str[0], 16)); + } + else { + print_string(itoa((int32_t)ctx.accxL2 , &str[0], 16)); + } + print_string("\n"); + + +#ifdef GR740_ESA_BOARD + print_string("L1 Instr Cache misses (read) CPU_0 : "); + print_string(itoa(soc_stats.l1_inst_cache_miss[0], &str[0], 10)); + print_string("\n"); + print_string("L1 Instr Cache misses (read) CPU_1 : "); + print_string(itoa(soc_stats.l1_inst_cache_miss[1], &str[0], 10)); + print_string("\n"); + print_string("L1 Instr Cache misses (read) CPU_2 : "); + print_string(itoa(soc_stats.l1_inst_cache_miss[2], &str[0], 10)); + print_string("\n"); + print_string("L1 Instr Cache misses (read) CPU_3 : "); + print_string(itoa(soc_stats.l1_inst_cache_miss[3], &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses (read) CPU_0 : "); + print_string(itoa(soc_stats.l1_data_cache_miss[0], &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses (read) CPU_1 : "); + print_string(itoa(soc_stats.l1_data_cache_miss[1], &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses (read) CPU_2 : "); + print_string(itoa(soc_stats.l1_data_cache_miss[2], &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses (read) CPU_3 : "); + print_string(itoa(soc_stats.l1_data_cache_miss[3], &str[0], 10)); + print_string("\n"); + print_string("L2 Cache hits (read + writes) : "); + print_string(itoa(soc_stats.l2_cache_hits, &str[0], 10)); + print_string("\n"); + print_string("L2 Cache misses (read + writes) : "); + print_string(itoa(soc_stats.l2_cache_miss, &str[0], 10)); + print_string("\n"); + print_string("AHB Splits : "); + print_string(itoa(soc_stats.ahb_split_delay, &str[0], 10)); + print_string("\n"); + print_string("\n"); +#endif + + print_string("\n"); +// -------------------------------------------------------------------------- +// Delete Objects and Finalize testcase +// -------------------------------------------------------------------------- + for (uint32_t i = 0; i < TASK_COUNT; i++){ + DeleteTask(ctx.task_id[i]); + DeleteMessageQueue(ctx.message_queue[i]); + } + DeleteMessageQueue(ctx.tile_queue); + + DeleteMutex(ctx.mutex_id); + + rtems_fatal(RTEMS_FATAL_SOURCE_EXIT, 0); +} + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER + +#define CONFIGURE_MAXIMUM_PROCESSORS TEST_PROCESSORS + +#define CONFIGURE_MAXIMUM_MESSAGE_QUEUES MAX_MESSAGE_QUEUES + +#define CONFIGURE_MAXIMUM_SEMAPHORES 1 + +#define CONFIGURE_MAXIMUM_TASKS ( TEST_PROCESSORS + 1 ) + +#define CONFIGURE_SCHEDULER_EDF_SMP + +#define CONFIGURE_MINIMUM_TASK_STACK_SIZE \ + RTEMS_MINIMUM_STACK_SIZE + CPU_STACK_ALIGNMENT + +#define CONFIGURE_EXTRA_TASK_STACKS RTEMS_MINIMUM_STACK_SIZE + +#define CONFIGURE_INIT_TASK_CONSTRUCT_STORAGE_SIZE 2 * TASK_STORAGE_SIZE + +#define CONFIGURE_MINIMUM_TASKS_WITH_USER_PROVIDED_STORAGE \ + CONFIGURE_MAXIMUM_TASKS + +#define CONFIGURE_MICROSECONDS_PER_TICK 1000 + +#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 0 + +#define CONFIGURE_DISABLE_NEWLIB_REENTRANCY + +#define CONFIGURE_APPLICATION_DISABLE_FILESYSTEM + +#define CONFIGURE_MAXIMUM_THREAD_LOCAL_STORAGE_SIZE MAX_TLS_SIZE + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT_TASK_ATTRIBUTES (RTEMS_SYSTEM_TASK | TASK_ATTRIBUTES) + +#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES + +#define CONFIGURE_INIT + +#include <rtems/confdefs.h> diff --git a/testsuites/isvv/23.1_uni_cache_way_locking_disabled/uni_cache_way_locking_disabled.c b/testsuites/isvv/23.1_uni_cache_way_locking_disabled/uni_cache_way_locking_disabled.c new file mode 100644 index 0000000000..217e1fa972 --- /dev/null +++ b/testsuites/isvv/23.1_uni_cache_way_locking_disabled/uni_cache_way_locking_disabled.c @@ -0,0 +1,538 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 2022 Critical Software SA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stddef.h> +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <rtems/bspIo.h> +#include <string.h> +#include "../shared/utils.h" +#include "../shared/isvv_rtems_aux.h" +#include "../shared/low_level_utils.h" + + +/** + * + * @brief Tests impact performing of L2 cache way locking + * + * Step 1: Uniprocessor case + * + * In this step the same set of math equations used by several tasks in the + * Multiprocessor version are run in an Uniprocessor and ONE task only environment + * in order to achieve a reference output result for comparison . + * + * There are two main sets of math equations processed here: + * - one named "filter_simulation" + * - and other named "snr_processing" + * + * For each one, result values are obtained for later comparison with multiprocessor + * versions. Also some internal cache statistics are shown. Most relevant one is the number of + * L2 cache misses, which when increased significantly, may delay the data processing. + * + */ + +/** + * + * For standalone tests in the actual hardware boards the following options can be used: + * + * 1) use make XFLAGS="-Dgr740 -DGR740_ESA_BOARD" + * 2) use and declare #define GR740_ESA_BOARD at the beginning of this file + * + */ + +#define MAX_TLS_SIZE RTEMS_ALIGN_UP(64, RTEMS_TASK_STORAGE_ALIGNMENT) + +#define TASK_ATTRIBUTES RTEMS_FLOATING_POINT + +#define TASK_STORAGE_SIZE \ + RTEMS_TASK_STORAGE_SIZE( \ + MAX_TLS_SIZE + RTEMS_MINIMUM_STACK_SIZE, \ + TASK_ATTRIBUTES) + + +// test specific global vars +#undef TEST_PROCESSORS +#define TEST_PROCESSORS 1 + +#define TASK_COUNT (2+2) //2 parallel tasks for "filter simulation" and + // another 2 sequential tasks for "snr processing" +#define TOTAL_TILES 192 + +#define MAX_MESSAGE_SIZE sizeof(uint8_t) +#define MAX_PENDING_MESSAGES 10 + +const rtems_event_set event_send[6] = {RTEMS_EVENT_1, + RTEMS_EVENT_2, + RTEMS_EVENT_3, + RTEMS_EVENT_4, + RTEMS_EVENT_5, + RTEMS_EVENT_6 + }; + +uint8_t count_process[TOTAL_TILES]; + +typedef struct{ + uint8_t ntiles; + uint8_t next_tile; + float filter_sim_process_time; + uint64_t accxL2; + float snr_process_time; + float scaling_fft_factor; +} test_context; + +#define ITOA_STR_SIZE (8*sizeof(int)+1) + +//------------------------------------------------------------------------------- +#define L2_CACHE_SIZE (4U*512U*1024U) // 2M bytes +#define L2_CACHE_WAY_SIZE (512U*1024U) // 512k bytes +#define xL2_ELEM (2*L2_CACHE_SIZE/sizeof(uint32_t)) // 1M elements + +#ifdef GR740_ESA_BOARD +RTEMS_ALIGNED(L2_CACHE_SIZE) +#endif +static uint32_t xL2[xL2_ELEM]; + +#define COEFS_SIZE (128U) +const uint32_t coefs[COEFS_SIZE] = + { 29, 31, 37, 41, 43, 47, 53, 59, + 61, 67, 71, 73, 79, 83, 89, 97, + 101, 103, 107, 109, 113, 127, 131, 137, + 139, 149, 151, 157, 163, 167, 173, 179, + 181, 191, 193, 197, 199, 211, 223, 227, + 229, 233, 239, 241, 251, 257, 263, 269, + 271, 277, 281, 283, 293, 307, 311, 313, + 317, 331, 337, 347, 349, 353, 359, 367, + 373, 379, 383, 389, 397, 401, 409, 419, + 421, 431, 433, 439, 443, 449, 457, 461, + 463, 467, 479, 487, 491, 499, 503, 509, + 521, 523, 541, 547, 557, 563, 569, 571, + 577, 587, 593, 599, 601, 607, 613, 617, + 619, 631, 641, 643, 647, 653, 659, 661, + 673, 677, 683, 691, 701, 709, 719, 727, + 733, 739, 743, 751, 757, 761, 769, 773}; + +//------------------------------------------------------------------------------- +#define MAX_ITER (TOTAL_TILES*1/3) +#define FFT_SIZE (65536U) +#define FFT_SIZE_LOG2 (16U) +#define TC_MAX (16U) +#define FILTER_REPETITIONS (2U) +#define SNR_THRESHOLD (1000000.0f) +const uint16_t FS = 48000U; +const uint16_t FREQ[TC_MAX] = { 2500U, 1500U, 15000U, 500U, + 1000U, 800U, 440U, 8000U, + 100U, 3500U, 12345U, 1200U, + 20000U, 715U, 5000U, 4500U }; +const float NOISE_FACTOR[TC_MAX] = { 0.0001f, 0.2250f, 0.00068f, 0.30f, + 0.004f, 0.0123f, 0.0054f, 0.00054f, + 0.01f, 0.0325f, 0.012f, 0.00032f, + 0.075f, 0.0423f, 0.0354f, 0.00002f }; +#ifdef GR740_ESA_BOARD +RTEMS_ALIGNED(L2_CACHE_WAY_SIZE) +#endif +static float inSensorDataRe[FFT_SIZE]; + +#ifdef GR740_ESA_BOARD +RTEMS_ALIGNED(L2_CACHE_WAY_SIZE) +#endif +static float inSensorDataIm[FFT_SIZE]; +static uint8_t dsp_result[MAX_ITER]; + + +//======================================================================================= +// Auxiliary Functions +//======================================================================================= +static void fill_main_memory_with_data(void){ + // Store to memory + for ( uint32_t j = 0 ; j < xL2_ELEM; j ++) + xL2[j] = j; +} + +static uint64_t warmup_caches(void) { + uint32_t j; + uint64_t volatile acc = 0; + + // This data should be cached in way #1 + for ( j = 0 ; j < FFT_SIZE; j++) + acc += xL2[j]; + + // This data should be cached in way #2 + for ( j = 0 ; j < FFT_SIZE; j++) + acc += xL2[j+(L2_CACHE_WAY_SIZE/sizeof(uint32_t))]; + + // This data should be cached in way #3 + for ( j = 0 ; j < FFT_SIZE; j++) + acc += inSensorDataRe[j]; + + // This data should be cached in way #4 + for ( j = 0 ; j < FFT_SIZE; j++) + acc += inSensorDataIm[j]; + + return acc; +} + + +//======================================================================================= +// "filter_simulation" Tasks/Functions +//======================================================================================= +static uint64_t calc_filter_simulation_equation(uint8_t tile, uint32_t total_elems) { + uint64_t acc = 0; + const uint32_t begin_idx = tile*xL2_ELEM/total_elems; + const uint32_t end_idx = begin_idx + (xL2_ELEM/total_elems) - 1; + + for ( uint32_t j = 0 ; j <= FILTER_REPETITIONS; j++ ) { + uint32_t i; + + // Simulating filtering/convolution + uint32_t t1 = 0, t2 = 0, t3 = 0, t4 = 0; + for (i = 0 ; i < FFT_SIZE; i++) { + t1 += xL2[(j+i+0*(L2_CACHE_WAY_SIZE/sizeof(uint32_t))) % xL2_ELEM] * coefs[i % COEFS_SIZE]; + t1 += xL2[(j+i+1*(L2_CACHE_WAY_SIZE/sizeof(uint32_t))) % xL2_ELEM] * coefs[i % COEFS_SIZE]; + t1 += xL2[(j+i+2*(L2_CACHE_WAY_SIZE/sizeof(uint32_t))) % xL2_ELEM] * coefs[i % COEFS_SIZE]; + t1 += xL2[(j+i+3*(L2_CACHE_WAY_SIZE/sizeof(uint32_t))) % xL2_ELEM] * coefs[i % COEFS_SIZE]; + t1 += xL2[(j+i+4*(L2_CACHE_WAY_SIZE/sizeof(uint32_t))) % xL2_ELEM] * coefs[i % COEFS_SIZE]; + t1 += xL2[(j+i+5*(L2_CACHE_WAY_SIZE/sizeof(uint32_t))) % xL2_ELEM] * coefs[i % COEFS_SIZE]; + t1 += xL2[(j+i+6*(L2_CACHE_WAY_SIZE/sizeof(uint32_t))) % xL2_ELEM] * coefs[i % COEFS_SIZE]; + t1 += xL2[(j+i+7*(L2_CACHE_WAY_SIZE/sizeof(uint32_t))) % xL2_ELEM] * coefs[i % COEFS_SIZE]; + } + + // Simulating normalization + t3 = ((t1*100)/(42*137)) + xL2[(begin_idx) % xL2_ELEM] ; + t4 = ((t2*10)/(96*137)) + xL2[(end_idx) % xL2_ELEM] ; + acc += (t3+t4); + } + return acc; +} + +static uint64_t function_calc_filter_simulation(test_context *ctx) { + struct timespec begin_time; + struct timespec end_time; + static uint64_t acc = 0; + + rtems_clock_get_uptime(&begin_time); + + for (uint32_t i = 0; i < TOTAL_TILES; i++) + acc += calc_filter_simulation_equation(i, TOTAL_TILES); + + rtems_clock_get_uptime(&end_time); + ctx->filter_sim_process_time += + (float)(end_time.tv_sec - begin_time.tv_sec) + + ( (float)((end_time.tv_nsec/1000) - (begin_time.tv_nsec/1000))/1000000.0); + + return acc; +} + + +//======================================================================================= +// "snr_processing" Tasks/Functions +//======================================================================================= +static void function_snr_read_sensor_data( uint32_t iter) { + for (uint32_t i = 0; i < FFT_SIZE; i++) { + inSensorDataRe[i] = 0.4995f * cos_aprox(i*2.0f*PI*FREQ[iter%TC_MAX]/FS) + + (noise_generator(0) * NOISE_FACTOR[iter%TC_MAX]); + inSensorDataIm[i] = 0.4995f * sin_aprox(i*2.0f*PI*FREQ[iter%TC_MAX]/FS) + + (noise_generator(0) * NOISE_FACTOR[iter % TC_MAX]); + } +} + +static void function_snr_process_data(test_context *ctx, uint32_t iter) { + struct timespec begin_time; + struct timespec end_time; + + rtems_clock_get_uptime(&begin_time); + + //Apply Blackman-Harris Window + for (uint32_t i = 0; i < FFT_SIZE; i++) { + inSensorDataRe[i] = inSensorDataRe[i]*blackman_harris(i, FFT_SIZE)/ctx->scaling_fft_factor; + inSensorDataIm[i] = inSensorDataIm[i]*blackman_harris(i, FFT_SIZE)/ctx->scaling_fft_factor; + } + + //Calculates FFT + fft(&inSensorDataRe[0], &inSensorDataIm[0], FFT_SIZE_LOG2); + + //Calculates the magnitude values + for (uint32_t i = 0; i < FFT_SIZE; i++) { + inSensorDataRe[i] = (inSensorDataRe[i] * inSensorDataRe[i] + + inSensorDataIm[i] * inSensorDataIm[i]) / ((float)FFT_SIZE); + } + + //Look for the peak Value and its index (no DC) + float maxValue = 0.0; + float maxValueIndex = -1; + for (uint32_t i = 3; i < (FFT_SIZE / 2); i++) { + if (inSensorDataRe[i] > maxValue) { + maxValue = inSensorDataRe[i]; + maxValueIndex = i; + } + } + + //Calculates the signal and noise power (no DC) + float sig = 0.0f; + float noise = 0.0f; + for (uint32_t i = 3; i < (FFT_SIZE / 2); i++) { + if ((i > maxValueIndex - 8) && (i < maxValueIndex + 8)) { + sig += (2 * inSensorDataRe[i]); + } + else { + noise += (2 * inSensorDataRe[i]); + } + } + + if (!(sig > 0.0f)) { sig = 0.0000000001f; } + if (!(noise > 0.0f)) { noise = 0.0000000001f; } + + //Calculates SNR + float snr_float = sig/noise; + + if (snr_float > SNR_THRESHOLD) { + dsp_result[iter] = 1; + } + else { + dsp_result[iter] = 0; + } + rtems_clock_get_uptime(&end_time); + + ctx->snr_process_time += + (float)(end_time.tv_sec - begin_time.tv_sec) + + ( (float)((end_time.tv_nsec/1000) - (begin_time.tv_nsec/1000))/1000000.0); +} + + +//======================================================================================= +// INIT/MAIN Task +//======================================================================================= +static void Init(rtems_task_argument arg){ + (void)arg; + test_context ctx; + uint32_t start_time, end_time, elapsed_time; + char str[ITOA_STR_SIZE]; + bool correctly_processed = true; + (void) memset(&ctx, 0, sizeof(test_context)); + (void) memset(&count_process[0], 0, TOTAL_TILES); + (void) memset(&xL2[0], 0, xL2_ELEM); + (void) memset(&inSensorDataRe[0], 0, FFT_SIZE); + (void) memset(&inSensorDataIm[0], 0, FFT_SIZE); + +#ifdef GR740_ESA_BOARD + soc_stats_regs soc_stats; +#endif + + +//----------------------------------------------------------------------------- +// Create/Initialize Objects +//----------------------------------------------------------------------------- + ctx.ntiles = TOTAL_TILES; + ctx.next_tile = 1; + SetSelfPriority( PRIO_NORMAL ); + + +//----------------------------------------------------------------------------- +// Setup the testcase +//----------------------------------------------------------------------------- + fill_main_memory_with_data(); + l1_dcache_flush(); + l1_dcache_disable(); + +#ifdef GR740_ESA_BOARD + l2_cache_disable(); + l2_cache_flush(); + l2_cache_enable(); +#endif + + l1_dcache_enable(); + uint32_t control_data_word = warmup_caches(); + +#ifdef GR740_ESA_BOARD + l2_cache_enable_split_responses(); + clockgating_enable_l4stat(); + soc_stats_configure_regs(); + soc_stats_init(&soc_stats); +#endif + + //Calculates mean of Blackman-Harris terms + ctx.scaling_fft_factor = 0.0; + for (uint32_t i = 0; i<FFT_SIZE; i++){ + ctx.scaling_fft_factor += blackman_harris( i, FFT_SIZE); + } + ctx.scaling_fft_factor = ctx.scaling_fft_factor/ ((float) FFT_SIZE); + +//----------------------------------------------------------------------------- +// Do the work +//----------------------------------------------------------------------------- + start_time = rtems_clock_get_ticks_since_boot(); + ctx.accxL2 = function_calc_filter_simulation(&ctx); + + uint32_t start_idx = 0; + for (uint32_t iter=0; iter<MAX_ITER; iter++, start_idx += FFT_SIZE) { + function_snr_read_sensor_data(iter); + function_snr_process_data(&ctx, iter) ; + } + + end_time = rtems_clock_get_ticks_since_boot(); + elapsed_time = end_time - start_time; + +#ifdef GR740_ESA_BOARD + soc_stats_update(&soc_stats); +#endif + +//----------------------------------------------------------------------------- +// Show Results +//----------------------------------------------------------------------------- + print_string("\n"); + print_string("Single Core Elapsed Time -"); + print_string(itoa(elapsed_time, &str[0], 10)); + print_string("\n"); + + for (uint8_t i = 0; i < ctx.ntiles; i++){ + if (count_process[i] != 1){ + correctly_processed = false; + break; + } + } + + if (correctly_processed){ + print_string("Each tile only processed once : true\n"); + } + else{ + print_string("Each tile only processed once : false\n"); + } + + print_string("Input Data Result Value : 0x"); + print_string(itoa(control_data_word , &str[0], 16)); + print_string("\n"); + + print_string("Ouput Data Result Value : 0x"); + if (ctx.accxL2>=UINT32_MAX) { + print_string(itoa( (int32_t) ((ctx.accxL2 >> 32U) & ((uint64_t)UINT32_MAX)) , &str[0], 16)); + print_string(itoa( (int32_t) (ctx.accxL2 & ((uint64_t)UINT32_MAX)) , &str[0], 16)); + } + else { + print_string(itoa((int32_t)ctx.accxL2 , &str[0], 16)); + } + print_string("\n"); + print_string("Time used in filter sim processing : "); + print_string(itoa( (int32_t) (ctx.filter_sim_process_time *1000) , &str[0], 10)); + print_string(" ms\n"); + + print_string("Time used in SNR processing : "); + print_string(itoa( (int32_t) (ctx.snr_process_time *1000) , &str[0], 10)); + print_string(" ms\n"); + + print_string("SNR triggers found at : "); + for (uint32_t j = 0; j < MAX_ITER; j++) + if (dsp_result[j] > 0.0){ + print_string(itoa(j, &str[0], 10)); + print_string(" "); + } + print_string("\n"); + + +#ifdef GR740_ESA_BOARD + print_string("L1 Instr Cache misses (read) CPU_0 : "); + print_string(itoa(soc_stats.l1_inst_cache_miss[0], &str[0], 10)); + print_string("\n"); + print_string("L1 Instr Cache misses (read) CPU_1 : "); + print_string(itoa(soc_stats.l1_inst_cache_miss[1], &str[0], 10)); + print_string("\n"); + print_string("L1 Instr Cache misses (read) CPU_2 : "); + print_string(itoa(soc_stats.l1_inst_cache_miss[2], &str[0], 10)); + print_string("\n"); + print_string("L1 Instr Cache misses (read) CPU_3 : "); + print_string(itoa(soc_stats.l1_inst_cache_miss[3], &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses (read) CPU_0 : "); + print_string(itoa(soc_stats.l1_data_cache_miss[0], &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses (read) CPU_1 : "); + print_string(itoa(soc_stats.l1_data_cache_miss[1], &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses (read) CPU_2 : "); + print_string(itoa(soc_stats.l1_data_cache_miss[2], &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses (read) CPU_3 : "); + print_string(itoa(soc_stats.l1_data_cache_miss[3], &str[0], 10)); + print_string("\n"); + print_string("L2 Cache hits (read + writes) : "); + print_string(itoa(soc_stats.l2_cache_hits, &str[0], 10)); + print_string("\n"); + print_string("L2 Cache misses (read + writes) : "); + print_string(itoa(soc_stats.l2_cache_miss, &str[0], 10)); + print_string("\n"); + print_string("AHB Splits : "); + print_string(itoa(soc_stats.ahb_split_delay, &str[0], 10)); + print_string("\n"); + print_string("\n"); +#endif + + +// -------------------------------------------------------------------------- +// Delete Objects and Finalize testcase +// -------------------------------------------------------------------------- + + rtems_fatal(RTEMS_FATAL_SOURCE_EXIT, 0); +} + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER + +#define CONFIGURE_MAXIMUM_PROCESSORS TEST_PROCESSORS + +#define CONFIGURE_MAXIMUM_TASKS TEST_PROCESSORS + +#define CONFIGURE_SCHEDULER_EDF_SMP + +#define CONFIGURE_MINIMUM_TASK_STACK_SIZE \ + RTEMS_MINIMUM_STACK_SIZE + CPU_STACK_ALIGNMENT + +#define CONFIGURE_EXTRA_TASK_STACKS RTEMS_MINIMUM_STACK_SIZE + +#define CONFIGURE_INIT_TASK_CONSTRUCT_STORAGE_SIZE 2 * TASK_STORAGE_SIZE + +#define CONFIGURE_MINIMUM_TASKS_WITH_USER_PROVIDED_STORAGE \ + CONFIGURE_MAXIMUM_TASKS + +#define CONFIGURE_MICROSECONDS_PER_TICK 1000 + +#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 0 + +#define CONFIGURE_DISABLE_NEWLIB_REENTRANCY + +#define CONFIGURE_APPLICATION_DISABLE_FILESYSTEM + +#define CONFIGURE_MAXIMUM_THREAD_LOCAL_STORAGE_SIZE MAX_TLS_SIZE + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT_TASK_ATTRIBUTES (RTEMS_SYSTEM_TASK | TASK_ATTRIBUTES) + +#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES + +#define CONFIGURE_INIT + +#include <rtems/confdefs.h> diff --git a/testsuites/isvv/23.2_multi_cache_way_locking_disabled/multi_cache_way_locking_disabled.c b/testsuites/isvv/23.2_multi_cache_way_locking_disabled/multi_cache_way_locking_disabled.c new file mode 100644 index 0000000000..8f88b196ec --- /dev/null +++ b/testsuites/isvv/23.2_multi_cache_way_locking_disabled/multi_cache_way_locking_disabled.c @@ -0,0 +1,699 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 2022 Critical Software SA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stddef.h> +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <rtems/bspIo.h> +#include <string.h> +#include "../shared/utils.h" +#include "../shared/isvv_rtems_aux.h" +#include "../shared/low_level_utils.h" + + +/** + * + * @brief Tests impact performing of L2 cache way locking + * + * Step 2: Multiprocessor with L2 cache way locking disable + * + * There are two main math set of equations used here: + * - one named "filter_simulation" + * - and other named "snr_processing" + * + * The equations for "filter_simulation" are used by TWO tasks that processes small + * sections of a "data array" in parallel. + * The equations for "snr_processing" are used by TWO tasks that processes small + * sections of other "data array" in sequential order, but in parallel with the other + * tasks. + * + * The locations in memory for both "data arrays" do overlap in terms of cache memory + * positions, and when acessing one "data array", or part of one, other sections of + * the other "data array" should be kicked out of the cache. Sometimes that should + * also happen within the same "data array". + * + * Expected Results: + * - The Tiles must be processed only once. + * - "Ouput Data Result Value" must match with the Uniprocessor version. + * - SNR triggers index positions must match with the ones from the Uniprocessor version. + * + */ + +/** + * + * For standalone tests in the actual hardware boards the following options can be used: + * + * 1) use make XFLAGS="-Dgr740 -DGR740_ESA_BOARD" + * 2) use and declare #define GR740_ESA_BOARD at the beginning of this file + * + */ + +#define MAX_TLS_SIZE RTEMS_ALIGN_UP(64, RTEMS_TASK_STORAGE_ALIGNMENT) + +#define TASK_ATTRIBUTES RTEMS_FLOATING_POINT + +#define TASK_STORAGE_SIZE \ + RTEMS_TASK_STORAGE_SIZE( \ + MAX_TLS_SIZE + RTEMS_MINIMUM_STACK_SIZE, \ + TASK_ATTRIBUTES) + + +// test specific global vars +#define TASK_COUNT (2+2) //2 parallel tasks for "filter simulation" and + // another 2 sequential tasks for "snr processing" +#define TOTAL_TILES 192 + +#define MAX_MESSAGE_QUEUES 6 +#define MAX_MESSAGE_SIZE sizeof(uint8_t) +#define MAX_PENDING_MESSAGES 10 + +const rtems_event_set event_send[6] = {RTEMS_EVENT_1, + RTEMS_EVENT_2, + RTEMS_EVENT_3, + RTEMS_EVENT_4, + RTEMS_EVENT_5, + RTEMS_EVENT_6 + }; + +#define EVENT_GO_READ_SENSOR RTEMS_EVENT_10 +#define EVENT_DATA_READY RTEMS_EVENT_11 +#define EVENT_DATA_WAS_PROCESSED RTEMS_EVENT_12 + +uint8_t count_process[TOTAL_TILES]; + +typedef struct{ + rtems_id main_task; + uint8_t ntiles; + uint8_t next_tile; + rtems_id task_filter_simulation_id[TEST_PROCESSORS]; + rtems_id tile_queue; + rtems_id message_queue[TEST_PROCESSORS]; + rtems_id filter_mutex_id; + float filter_sim_process_time; + uint64_t accxL2; + rtems_id task_snr_process_data_id; + rtems_id task_snr_read_sensor_data_id; + rtems_id snr_mutex_id; + float snr_process_time; + float scaling_fft_factor; +} test_context; + +RTEMS_ALIGNED(RTEMS_TASK_STORAGE_ALIGNMENT) +static char calc_task_storage[TASK_COUNT][TASK_STORAGE_SIZE]; + +RTEMS_MESSAGE_QUEUE_BUFFER(MAX_MESSAGE_SIZE) +msg_tile_queue_storage[MAX_PENDING_MESSAGES]; + +RTEMS_MESSAGE_QUEUE_BUFFER(MAX_MESSAGE_SIZE) +msg_task_queue_storage[TASK_COUNT][MAX_PENDING_MESSAGES]; + +#define ITOA_STR_SIZE (8*sizeof(int)+1) + +//------------------------------------------------------------------------------- +#define L2_CACHE_SIZE (4U*512U*1024U) // 2M bytes +#define L2_CACHE_WAY_SIZE (512U*1024U) // 512k bytes +#define xL2_ELEM (2*L2_CACHE_SIZE/sizeof(uint32_t)) // 1M elements + +#ifdef GR740_ESA_BOARD +RTEMS_ALIGNED(L2_CACHE_SIZE) +#endif +static uint32_t xL2[xL2_ELEM]; + +#define COEFS_SIZE (128U) +const uint32_t coefs[COEFS_SIZE] = + { 29, 31, 37, 41, 43, 47, 53, 59, + 61, 67, 71, 73, 79, 83, 89, 97, + 101, 103, 107, 109, 113, 127, 131, 137, + 139, 149, 151, 157, 163, 167, 173, 179, + 181, 191, 193, 197, 199, 211, 223, 227, + 229, 233, 239, 241, 251, 257, 263, 269, + 271, 277, 281, 283, 293, 307, 311, 313, + 317, 331, 337, 347, 349, 353, 359, 367, + 373, 379, 383, 389, 397, 401, 409, 419, + 421, 431, 433, 439, 443, 449, 457, 461, + 463, 467, 479, 487, 491, 499, 503, 509, + 521, 523, 541, 547, 557, 563, 569, 571, + 577, 587, 593, 599, 601, 607, 613, 617, + 619, 631, 641, 643, 647, 653, 659, 661, + 673, 677, 683, 691, 701, 709, 719, 727, + 733, 739, 743, 751, 757, 761, 769, 773}; + +//------------------------------------------------------------------------------- +#define MAX_ITER (TOTAL_TILES*1/3) +#define FFT_SIZE (65536U) +#define FFT_SIZE_LOG2 (16U) +#define TC_MAX (16U) +#define FILTER_REPETITIONS (2U) +#define SNR_THRESHOLD (1000000.0f) +const uint16_t FS = 48000U; +const uint16_t FREQ[TC_MAX] = { 2500U, 1500U, 15000U, 500U, + 1000U, 800U, 440U, 8000U, + 100U, 3500U, 12345U, 1200U, + 20000U, 715U, 5000U, 4500U }; +const float NOISE_FACTOR[TC_MAX] = { 0.0001f, 0.2250f, 0.00068f, 0.30f, + 0.004f, 0.0123f, 0.0054f, 0.00054f, + 0.01f, 0.0325f, 0.012f, 0.00032f, + 0.075f, 0.0423f, 0.0354f, 0.00002f }; +#ifdef GR740_ESA_BOARD +RTEMS_ALIGNED(L2_CACHE_WAY_SIZE) +#endif +static float inSensorDataRe[FFT_SIZE]; + +#ifdef GR740_ESA_BOARD +RTEMS_ALIGNED(L2_CACHE_WAY_SIZE) +#endif +static float inSensorDataIm[FFT_SIZE]; +static uint8_t dsp_result[MAX_ITER]; + + +//======================================================================================= +// Auxiliary /Functions +//======================================================================================= +static void fill_main_memory_with_data(void){ + // Store to memory + for ( uint32_t j = 0 ; j < xL2_ELEM; j ++) + xL2[j] = j; +} + +static uint64_t warmup_caches(void) { + uint32_t j; + uint64_t volatile acc = 0; + + // This data should be cached in way #1 + for ( j = 0 ; j < FFT_SIZE; j++) + acc += xL2[j]; + + // This data should be cached in way #2 + for ( j = 0 ; j < FFT_SIZE; j++) + acc += xL2[j+(L2_CACHE_WAY_SIZE/sizeof(uint32_t))]; + + // This data should be cached in way #3 + for ( j = 0 ; j < FFT_SIZE; j++) + acc += inSensorDataRe[j]; + + // This data should be cached in way #4 + for ( j = 0 ; j < FFT_SIZE; j++) + acc += inSensorDataIm[j]; + + return acc; +} + + +//======================================================================================= +// "filter_simulation" Tasks/Functions +//======================================================================================= +static uint64_t calc_filter_simulation_equation(uint8_t tile, uint32_t total_elems) { + uint64_t acc = 0; + const uint32_t begin_idx = tile*xL2_ELEM/total_elems; + const uint32_t end_idx = begin_idx + (xL2_ELEM/total_elems) - 1; + + for ( uint32_t j = 0 ; j <= FILTER_REPETITIONS; j++ ) { + uint32_t i; + + // Simulating filtering/convolution + uint32_t t1 = 0, t2 = 0, t3 = 0, t4 = 0; + for (i = 0 ; i < FFT_SIZE; i++) { + t1 += xL2[(j+i+0*(L2_CACHE_WAY_SIZE/sizeof(uint32_t))) % xL2_ELEM] * coefs[i % COEFS_SIZE]; + t1 += xL2[(j+i+1*(L2_CACHE_WAY_SIZE/sizeof(uint32_t))) % xL2_ELEM] * coefs[i % COEFS_SIZE]; + t1 += xL2[(j+i+2*(L2_CACHE_WAY_SIZE/sizeof(uint32_t))) % xL2_ELEM] * coefs[i % COEFS_SIZE]; + t1 += xL2[(j+i+3*(L2_CACHE_WAY_SIZE/sizeof(uint32_t))) % xL2_ELEM] * coefs[i % COEFS_SIZE]; + t1 += xL2[(j+i+4*(L2_CACHE_WAY_SIZE/sizeof(uint32_t))) % xL2_ELEM] * coefs[i % COEFS_SIZE]; + t1 += xL2[(j+i+5*(L2_CACHE_WAY_SIZE/sizeof(uint32_t))) % xL2_ELEM] * coefs[i % COEFS_SIZE]; + t1 += xL2[(j+i+6*(L2_CACHE_WAY_SIZE/sizeof(uint32_t))) % xL2_ELEM] * coefs[i % COEFS_SIZE]; + t1 += xL2[(j+i+7*(L2_CACHE_WAY_SIZE/sizeof(uint32_t))) % xL2_ELEM] * coefs[i % COEFS_SIZE]; + } + + // Simulating normalization + t3 = ((t1*100)/(42*137)) + xL2[(begin_idx) % xL2_ELEM] ; + t4 = ((t2*10)/(96*137)) + xL2[(end_idx) % xL2_ELEM] ; + acc += (t3+t4); + } + return acc; +} + + +static void calc_task_function(rtems_task_argument arg) { + test_context *ctx; + uint64_t acc; + struct timespec begin_time; + struct timespec end_time; + uint8_t tile = 0; + uint8_t task_idx = 255; + + ctx = (test_context *)arg; + rtems_id local_id = TaskSelfId(); + + for (int i = 0; i < TASK_COUNT; i++){ + if (ctx->task_filter_simulation_id[i] == local_id){ + task_idx = i; + break; + } + } + + char ch = '0' + task_idx; + + rtems_message_queue_config msg_config = { + .name = rtems_build_name('M', 'S', 'G', ch), + .maximum_pending_messages = MAX_PENDING_MESSAGES, + .maximum_message_size = MAX_MESSAGE_SIZE, + .storage_size = sizeof(msg_task_queue_storage[task_idx]), + .storage_area = &msg_task_queue_storage[task_idx], + .attributes = RTEMS_FIFO | RTEMS_GLOBAL}; + + ctx->message_queue[task_idx] = CreateMessageQueue(msg_config); + + SendMessage(ctx->tile_queue, &task_idx, sizeof(task_idx)); + ReceiveMessage(ctx->message_queue[task_idx], &tile); + + while (tile <= ctx->ntiles) { + count_process[tile - 1]++; + rtems_clock_get_uptime(&begin_time); + acc = calc_filter_simulation_equation(tile-1, ctx->ntiles); + rtems_clock_get_uptime(&end_time); + + ObtainMutex(ctx->filter_mutex_id); + ctx->filter_sim_process_time += (float)(end_time.tv_sec - begin_time.tv_sec) + + ( (float)(end_time.tv_nsec/1000 - begin_time.tv_nsec/1000)/1000000.0); + ctx->accxL2 += acc; + ReleaseMutex(ctx->filter_mutex_id); + + SendMessage(ctx->tile_queue, &task_idx, sizeof(task_idx)); + ReceiveMessage(ctx->message_queue[task_idx], &tile); + } + + SendMessage(ctx->tile_queue, &task_idx, sizeof(task_idx)); + SendEvents(ctx->main_task, event_send[task_idx]); + SuspendSelf(); +} + + +//======================================================================================= +// "snr_processing" Tasks/Functions +//======================================================================================= +static void task_snr_read_sensor_data(rtems_task_argument arg){ + test_context *ctx; + uint32_t iter = 0; + + ctx = (test_context *)arg; + + ReceiveAllEvents(EVENT_GO_READ_SENSOR); + + while ( iter < MAX_ITER) { + ObtainMutex(ctx->snr_mutex_id); + + for (uint32_t i = 0; i < FFT_SIZE; i++) { + inSensorDataRe[i] = 0.4995f * cos_aprox(i*2.0f*PI*FREQ[iter%TC_MAX]/FS) + + (noise_generator(0) * NOISE_FACTOR[iter%TC_MAX]); + inSensorDataIm[i] = 0.4995f * sin_aprox(i*2.0f*PI*FREQ[iter%TC_MAX]/FS) + + (noise_generator(0) * NOISE_FACTOR[iter % TC_MAX]); + } + + ReleaseMutex(ctx->snr_mutex_id); + SendEvents(ctx->task_snr_process_data_id, EVENT_DATA_READY); + + iter++; + ReceiveAllEvents(EVENT_DATA_WAS_PROCESSED); + } + + rtems_event_send(ctx->main_task, event_send[(TASK_COUNT-2)]); + SuspendSelf(); +} + +static void task_snr_process_data(rtems_task_argument arg) { + test_context *ctx; + ctx = (test_context *)arg; + uint32_t iter = 0; + struct timespec begin_time; + struct timespec end_time; + + while ( iter < MAX_ITER ) { + ReceiveAllEvents(EVENT_DATA_READY); + ObtainMutex(ctx->snr_mutex_id); + rtems_clock_get_uptime(&begin_time); + + //Apply Blackman-Harris Window + for (uint32_t i = 0; i < FFT_SIZE; i++) { + inSensorDataRe[i] = inSensorDataRe[i]*blackman_harris(i, FFT_SIZE)/ctx->scaling_fft_factor; + inSensorDataIm[i] = inSensorDataIm[i]*blackman_harris(i, FFT_SIZE)/ctx->scaling_fft_factor; + } + + //Calculates FFT + fft(&inSensorDataRe[0], &inSensorDataIm[0], FFT_SIZE_LOG2); + + //Calculates the magnitude values + for (uint32_t i = 0; i < FFT_SIZE; i++) { + inSensorDataRe[i] = (inSensorDataRe[i] * inSensorDataRe[i] + + inSensorDataIm[i] * inSensorDataIm[i]) / ((float)FFT_SIZE); + } + + //Look for the peak Value and its index (no DC) + float maxValue = 0.0; + float maxValueIndex = -1; + for (uint32_t i = 3; i < (FFT_SIZE / 2); i++) { + if (inSensorDataRe[i] > maxValue) { + maxValue = inSensorDataRe[i]; + maxValueIndex = i; + } + } + + //Calculates the signal and noise power (no DC) + float sig = 0.0f; + float noise = 0.0f; + for (uint32_t i = 3; i < (FFT_SIZE / 2); i++) { + if ((i > maxValueIndex - 8) && (i < maxValueIndex + 8)) { + sig += (2 * inSensorDataRe[i]); + } + else { + noise += (2 * inSensorDataRe[i]); + } + } + + if (!(sig > 0.0f)) { sig = 0.0000000001f; } + if (!(noise > 0.0f)) { noise = 0.0000000001f; } + + //Calculates SNR + float snr_float = sig/noise; + + if (snr_float > SNR_THRESHOLD) { + dsp_result[iter] = 1; + } + else { + dsp_result[iter] = 0; + } + rtems_clock_get_uptime(&end_time); + + ctx->snr_process_time += + (float)(end_time.tv_sec - begin_time.tv_sec) + + ( (float)((end_time.tv_nsec/1000) - (begin_time.tv_nsec/1000))/1000000.0); + + ReleaseMutex(ctx->snr_mutex_id); + iter++; + SendEvents(ctx->task_snr_read_sensor_data_id, EVENT_DATA_WAS_PROCESSED); + } + + rtems_event_send(ctx->main_task, event_send[(TASK_COUNT-1)]); + SuspendSelf(); +} + + +//======================================================================================= +// INIT/MAIN Task +//======================================================================================= +static void Init(rtems_task_argument arg){ + (void)arg; + test_context ctx; + uint32_t start_time, end_time, elapsed_time; + char ch, str[ITOA_STR_SIZE]; + uint32_t total_events = 0; + uint8_t task = 255; + bool correctly_processed = true; + (void) memset(&ctx, 0, sizeof(test_context)); + (void) memset(&count_process[0], 0, TOTAL_TILES); + (void) memset(&xL2[0], 0, xL2_ELEM); + (void) memset(&inSensorDataRe[0], 0, FFT_SIZE); + (void) memset(&inSensorDataIm[0], 0, FFT_SIZE); + +#ifdef GR740_ESA_BOARD + soc_stats_regs soc_stats; +#endif + + +//----------------------------------------------------------------------------- +// Create/Initialize Objects +//----------------------------------------------------------------------------- + rtems_message_queue_config msg_config = { + .name = rtems_build_name('M', 'S', 'G', 'T'), + .maximum_pending_messages = RTEMS_ARRAY_SIZE(msg_tile_queue_storage), + .maximum_message_size = MAX_MESSAGE_SIZE, + .storage_size = sizeof(msg_tile_queue_storage), + .storage_area = &msg_tile_queue_storage, + .attributes = RTEMS_FIFO | RTEMS_GLOBAL}; + + ctx.main_task = rtems_task_self(); + ctx.tile_queue = CreateMessageQueue(msg_config); + ctx.ntiles = TOTAL_TILES; + ctx.next_tile = 1; + + rtems_task_config calc_task_config = { + .initial_priority = PRIO_NORMAL, + .storage_size = TASK_STORAGE_SIZE, + .maximum_thread_local_storage_size = MAX_TLS_SIZE, + .initial_modes = RTEMS_DEFAULT_MODES, + .attributes = TASK_ATTRIBUTES}; + + ctx.filter_mutex_id = CreateMutex(rtems_build_name('M', 'U', 'T', '0')); + ctx.snr_mutex_id = CreateMutex(rtems_build_name('M', 'U', 'T', '1')); + SetSelfPriority( PRIO_NORMAL ); + + for (uint32_t i = 0; i < TASK_COUNT-2; i++){ + ch = '0' + i; + calc_task_config.name = rtems_build_name('R', 'U', 'N', ch); + calc_task_config.storage_area = &calc_task_storage[i][0]; + + ctx.task_filter_simulation_id[i] = DoCreateTask(calc_task_config); + StartTask(ctx.task_filter_simulation_id[i], calc_task_function, &ctx); + total_events += event_send[i]; + } + + ch = '0' + (TASK_COUNT-2); + calc_task_config.name = rtems_build_name('R', 'U', 'N', ch); + calc_task_config.storage_area = &calc_task_storage[(TASK_COUNT-2)][0]; + ctx.task_snr_read_sensor_data_id = DoCreateTask(calc_task_config); + StartTask(ctx.task_snr_read_sensor_data_id, task_snr_read_sensor_data, &ctx); + + ch = '0' + (TASK_COUNT-1); + calc_task_config.name = rtems_build_name('R', 'U', 'N', ch); + calc_task_config.storage_area = &calc_task_storage[(TASK_COUNT-1)][0]; + ctx.task_snr_process_data_id = DoCreateTask(calc_task_config); + StartTask(ctx.task_snr_process_data_id, task_snr_process_data, &ctx); + +//----------------------------------------------------------------------------- +// Setup the testcase +//----------------------------------------------------------------------------- + fill_main_memory_with_data(); + l1_dcache_flush(); + l1_dcache_disable(); + +#ifdef GR740_ESA_BOARD + l2_cache_disable(); + l2_cache_flush(); + l2_cache_enable(); +#endif + + l1_dcache_enable(); + uint32_t control_data_word = warmup_caches(); + +#ifdef GR740_ESA_BOARD + l2_cache_enable_split_responses(); + clockgating_enable_l4stat(); + soc_stats_configure_regs(); + soc_stats_init(&soc_stats); +#endif + + //Calculates mean of Blackman-Harris terms --> to scale a bit the FFT + ctx.scaling_fft_factor = 0.0; + for (uint32_t i = 0; i<FFT_SIZE; i++){ + ctx.scaling_fft_factor += blackman_harris( i, FFT_SIZE); + } + ctx.scaling_fft_factor = ctx.scaling_fft_factor/ ((float) FFT_SIZE); + +//----------------------------------------------------------------------------- +// Do the work: distribute the work through the tasks +//----------------------------------------------------------------------------- + SendEvents(ctx.task_snr_read_sensor_data_id, EVENT_GO_READ_SENSOR); + start_time = rtems_clock_get_ticks_since_boot(); + + rtems_event_set revents = ReceiveAvailableEvents(); + while ( (revents & total_events) != total_events ) { + ReceiveMessage(ctx.tile_queue, &task); + SendMessage(ctx.message_queue[task], &ctx.next_tile, sizeof(ctx.next_tile)); + ctx.next_tile++; + revents = ReceiveAvailableEvents(); + } + // Wait for the SNR tasks to finish + ReceiveAllEvents(event_send[(TASK_COUNT-2)]); + ReceiveAllEvents(event_send[(TASK_COUNT-1)]); + + end_time = rtems_clock_get_ticks_since_boot(); + elapsed_time = end_time - start_time; + +#ifdef GR740_ESA_BOARD + soc_stats_update(&soc_stats); +#endif + +//----------------------------------------------------------------------------- +// Show Results +//----------------------------------------------------------------------------- + print_string("\n"); + print_string("Multicore Elapsed Time -"); + print_string(itoa(elapsed_time, &str[0], 10)); + print_string("\n"); + + for (uint8_t i = 0; i < ctx.ntiles; i++){ + if (count_process[i] != 1){ + correctly_processed = false; + break; + } + } + + if (correctly_processed){ + print_string("Each tile only processed once : true\n"); + } + else{ + print_string("Each tile only processed once : false\n"); + } + + print_string("Input Data Result Value : 0x"); + print_string(itoa(control_data_word , &str[0], 16)); + print_string("\n"); + + print_string("Ouput Data Result Value : 0x"); + if (ctx.accxL2>=UINT32_MAX) { + print_string(itoa( (int32_t) ((ctx.accxL2 >> 32U) & ((uint64_t)UINT32_MAX)) , &str[0], 16)); + print_string(itoa( (int32_t) (ctx.accxL2 & ((uint64_t)UINT32_MAX)) , &str[0], 16)); + } + else { + print_string(itoa((int32_t)ctx.accxL2 , &str[0], 16)); + } + print_string("\n"); + print_string("Time used in filter sim processing : "); + print_string(itoa( (int32_t) (ctx.filter_sim_process_time *1000) , &str[0], 10)); + print_string(" ms\n"); + + print_string("Time used in SNR processing : "); + print_string(itoa( (int32_t) (ctx.snr_process_time *1000) , &str[0], 10)); + print_string(" ms\n"); + + print_string("SNR triggers found at : "); + for (uint32_t j = 0; j < MAX_ITER; j++) + if (dsp_result[j] > 0.0){ + print_string(itoa(j, &str[0], 10)); + print_string(" "); + } + print_string("\n"); + + +#ifdef GR740_ESA_BOARD + print_string("L1 Instr Cache misses (read) CPU_0 : "); + print_string(itoa(soc_stats.l1_inst_cache_miss[0], &str[0], 10)); + print_string("\n"); + print_string("L1 Instr Cache misses (read) CPU_1 : "); + print_string(itoa(soc_stats.l1_inst_cache_miss[1], &str[0], 10)); + print_string("\n"); + print_string("L1 Instr Cache misses (read) CPU_2 : "); + print_string(itoa(soc_stats.l1_inst_cache_miss[2], &str[0], 10)); + print_string("\n"); + print_string("L1 Instr Cache misses (read) CPU_3 : "); + print_string(itoa(soc_stats.l1_inst_cache_miss[3], &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses (read) CPU_0 : "); + print_string(itoa(soc_stats.l1_data_cache_miss[0], &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses (read) CPU_1 : "); + print_string(itoa(soc_stats.l1_data_cache_miss[1], &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses (read) CPU_2 : "); + print_string(itoa(soc_stats.l1_data_cache_miss[2], &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses (read) CPU_3 : "); + print_string(itoa(soc_stats.l1_data_cache_miss[3], &str[0], 10)); + print_string("\n"); + print_string("L2 Cache hits (read + writes) : "); + print_string(itoa(soc_stats.l2_cache_hits, &str[0], 10)); + print_string("\n"); + print_string("L2 Cache misses (read + writes) : "); + print_string(itoa(soc_stats.l2_cache_miss, &str[0], 10)); + print_string("\n"); + print_string("AHB Splits : "); + print_string(itoa(soc_stats.ahb_split_delay, &str[0], 10)); + print_string("\n"); + print_string("\n"); +#endif + + +// -------------------------------------------------------------------------- +// Delete Objects and Finalize testcase +// -------------------------------------------------------------------------- + for (uint32_t i = 0; i < (TASK_COUNT-2); i++){ + DeleteTask(ctx.task_filter_simulation_id[i]); + DeleteMessageQueue(ctx.message_queue[i]); + } + + DeleteTask(ctx.task_snr_process_data_id); + DeleteTask(ctx.task_snr_read_sensor_data_id); + + DeleteMutex(ctx.filter_mutex_id); + DeleteMutex(ctx.snr_mutex_id); + + DeleteMessageQueue(ctx.tile_queue); + rtems_fatal(RTEMS_FATAL_SOURCE_EXIT, 0); +} + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER + +#define CONFIGURE_MAXIMUM_PROCESSORS TEST_PROCESSORS + +#define CONFIGURE_MAXIMUM_MESSAGE_QUEUES MAX_MESSAGE_QUEUES + +#define CONFIGURE_MAXIMUM_SEMAPHORES 2 + +#define CONFIGURE_MAXIMUM_TASKS ( TASK_COUNT + 1 ) + +#define CONFIGURE_SCHEDULER_EDF_SMP + +#define CONFIGURE_MINIMUM_TASK_STACK_SIZE \ + RTEMS_MINIMUM_STACK_SIZE + CPU_STACK_ALIGNMENT + +#define CONFIGURE_EXTRA_TASK_STACKS RTEMS_MINIMUM_STACK_SIZE + +#define CONFIGURE_INIT_TASK_CONSTRUCT_STORAGE_SIZE 2 * TASK_STORAGE_SIZE + +#define CONFIGURE_MINIMUM_TASKS_WITH_USER_PROVIDED_STORAGE \ + CONFIGURE_MAXIMUM_TASKS + +#define CONFIGURE_MICROSECONDS_PER_TICK 1000 + +#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 0 + +#define CONFIGURE_DISABLE_NEWLIB_REENTRANCY + +#define CONFIGURE_APPLICATION_DISABLE_FILESYSTEM + +#define CONFIGURE_MAXIMUM_THREAD_LOCAL_STORAGE_SIZE MAX_TLS_SIZE + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT_TASK_ATTRIBUTES (RTEMS_SYSTEM_TASK | TASK_ATTRIBUTES) + +#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES + +#define CONFIGURE_INIT + +#include <rtems/confdefs.h> diff --git a/testsuites/isvv/23.3_multi_cache_way_locking_enabled/multi_cache_way_locking_enabled.c b/testsuites/isvv/23.3_multi_cache_way_locking_enabled/multi_cache_way_locking_enabled.c new file mode 100644 index 0000000000..e6efbc9f15 --- /dev/null +++ b/testsuites/isvv/23.3_multi_cache_way_locking_enabled/multi_cache_way_locking_enabled.c @@ -0,0 +1,713 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 2022 Critical Software SA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stddef.h> +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <rtems/bspIo.h> +#include <string.h> +#include "../shared/utils.h" +#include "../shared/isvv_rtems_aux.h" +#include "../shared/low_level_utils.h" + + +/** + * + * @brief Tests impact performing of L2 cache way locking + * + * Step 3: Multiprocessor with L2 cache way locking enable + * + * There are two main math set of equations used here: + * - one named "filter_simulation" + * - and other named "snr_processing" + * + * The equations for "filter_simulation" are used by TWO tasks that processes small + * sections of a "data array" in parallel. + * The equations for "snr_processing" are used by TWO tasks that processes small + * sections of other "data array" in sequential order, but in parallel with the other + * tasks. + * + * The locations in memory for both "data arrays" do overlap in terms of cache memory + * positions, and when acessing one "data array", or part of one, other sections of + * the other "data array" should be kicked out of the cache. Sometimes that should + * also happen within the same "data array". + * + * With the "L2 cache way locking" enabled for 2 of the 4 cache ways, the data array + * associated with the "snr_processing" is never kicked out the L2 cache. But in other + * hand but there is less ways available for the "filter_simulation" processing, and + * its stumbles a lot during the processing of its "data array". + * + * Expected Results: + * - The Tiles must be processed only once. + * - "Ouput Data Result Value" must match with the Uniprocessor version + * and Multiprocessor version with L2 cache way locking disable. + * - SNR triggers index positions must match with the ones from the Multiprocessor + * version with L2 cache way locking disable version and with the Uniprocessor + * version. + * - Time spent for "snr_processing" should be slightly lower than the Multiprocessor + * version with L2 cache way locking disable (due to the L2 cache way locking + * enabled for the arrays associated to way#3 and way#4). + * + */ + +/** + * + * For standalone tests in the actual hardware boards the following options can be used: + * + * 1) use make XFLAGS="-Dgr740 -DGR740_ESA_BOARD" + * 2) use and declare #define GR740_ESA_BOARD at the beginning of this file + * + */ + + +#define MAX_TLS_SIZE RTEMS_ALIGN_UP(64, RTEMS_TASK_STORAGE_ALIGNMENT) + +#define TASK_ATTRIBUTES RTEMS_FLOATING_POINT + +#define TASK_STORAGE_SIZE \ + RTEMS_TASK_STORAGE_SIZE( \ + MAX_TLS_SIZE + RTEMS_MINIMUM_STACK_SIZE, \ + TASK_ATTRIBUTES) + + +// test specific global vars +#define TASK_COUNT (2+2) //2 parallel tasks for "filter simulation" and + // another 2 sequential tasks for "snr processing" +#define TOTAL_TILES 192 + +#define MAX_MESSAGE_QUEUES 6 +#define MAX_MESSAGE_SIZE sizeof(uint8_t) +#define MAX_PENDING_MESSAGES 10 + +const rtems_event_set event_send[6] = {RTEMS_EVENT_1, + RTEMS_EVENT_2, + RTEMS_EVENT_3, + RTEMS_EVENT_4, + RTEMS_EVENT_5, + RTEMS_EVENT_6 + }; + +#define EVENT_GO_READ_SENSOR RTEMS_EVENT_10 +#define EVENT_DATA_READY RTEMS_EVENT_11 +#define EVENT_DATA_WAS_PROCESSED RTEMS_EVENT_12 + +uint8_t count_process[TOTAL_TILES]; + +typedef struct{ + rtems_id main_task; + uint8_t ntiles; + uint8_t next_tile; + rtems_id task_filter_simulation_id[TEST_PROCESSORS]; + rtems_id tile_queue; + rtems_id message_queue[TEST_PROCESSORS]; + rtems_id filter_mutex_id; + float filter_sim_process_time; + uint64_t accxL2; + rtems_id task_snr_process_data_id; + rtems_id task_snr_read_sensor_data_id; + rtems_id snr_mutex_id; + float snr_process_time; + float scaling_fft_factor; +} test_context; + +RTEMS_ALIGNED(RTEMS_TASK_STORAGE_ALIGNMENT) +static char calc_task_storage[TASK_COUNT][TASK_STORAGE_SIZE]; + +RTEMS_MESSAGE_QUEUE_BUFFER(MAX_MESSAGE_SIZE) +msg_tile_queue_storage[MAX_PENDING_MESSAGES]; + +RTEMS_MESSAGE_QUEUE_BUFFER(MAX_MESSAGE_SIZE) +msg_task_queue_storage[TASK_COUNT][MAX_PENDING_MESSAGES]; + +#define ITOA_STR_SIZE (8*sizeof(int)+1) + +//------------------------------------------------------------------------------- +#define L2_CACHE_SIZE (4U*512U*1024U) // 2M bytes +#define L2_CACHE_WAY_SIZE (512U*1024U) // 512k bytes +#define xL2_ELEM (2*L2_CACHE_SIZE/sizeof(uint32_t)) // 1M elements + +#ifdef GR740_ESA_BOARD +RTEMS_ALIGNED(L2_CACHE_SIZE) +#endif +static uint32_t xL2[xL2_ELEM]; + +#define COEFS_SIZE (128U) +const uint32_t coefs[COEFS_SIZE] = + { 29, 31, 37, 41, 43, 47, 53, 59, + 61, 67, 71, 73, 79, 83, 89, 97, + 101, 103, 107, 109, 113, 127, 131, 137, + 139, 149, 151, 157, 163, 167, 173, 179, + 181, 191, 193, 197, 199, 211, 223, 227, + 229, 233, 239, 241, 251, 257, 263, 269, + 271, 277, 281, 283, 293, 307, 311, 313, + 317, 331, 337, 347, 349, 353, 359, 367, + 373, 379, 383, 389, 397, 401, 409, 419, + 421, 431, 433, 439, 443, 449, 457, 461, + 463, 467, 479, 487, 491, 499, 503, 509, + 521, 523, 541, 547, 557, 563, 569, 571, + 577, 587, 593, 599, 601, 607, 613, 617, + 619, 631, 641, 643, 647, 653, 659, 661, + 673, 677, 683, 691, 701, 709, 719, 727, + 733, 739, 743, 751, 757, 761, 769, 773}; + +//------------------------------------------------------------------------------- +#define MAX_ITER (TOTAL_TILES*1/3) +#define FFT_SIZE (65536U) +#define FFT_SIZE_LOG2 (16U) +#define TC_MAX (16U) +#define FILTER_REPETITIONS (2U) +#define SNR_THRESHOLD (1000000.0f) +const uint16_t FS = 48000U; +const uint16_t FREQ[TC_MAX] = { 2500U, 1500U, 15000U, 500U, + 1000U, 800U, 440U, 8000U, + 100U, 3500U, 12345U, 1200U, + 20000U, 715U, 5000U, 4500U }; +const float NOISE_FACTOR[TC_MAX] = { 0.0001f, 0.2250f, 0.00068f, 0.30f, + 0.004f, 0.0123f, 0.0054f, 0.00054f, + 0.01f, 0.0325f, 0.012f, 0.00032f, + 0.075f, 0.0423f, 0.0354f, 0.00002f }; +#ifdef GR740_ESA_BOARD +RTEMS_ALIGNED(L2_CACHE_WAY_SIZE) +#endif +static float inSensorDataRe[FFT_SIZE]; + +#ifdef GR740_ESA_BOARD +RTEMS_ALIGNED(L2_CACHE_WAY_SIZE) +#endif +static float inSensorDataIm[FFT_SIZE]; +static uint8_t dsp_result[MAX_ITER]; + + +//======================================================================================= +// Auxiliary /Functions +//======================================================================================= +static void fill_main_memory_with_data(void){ + // Store to memory + for ( uint32_t j = 0 ; j < xL2_ELEM; j ++) + xL2[j] = j; +} + +static uint64_t warmup_caches(void) { + uint32_t j; + uint64_t volatile acc = 0; + + // This data should be cached in way #1 + for ( j = 0 ; j < FFT_SIZE; j++) + acc += xL2[j]; + + // This data should be cached in way #2 + for ( j = 0 ; j < FFT_SIZE; j++) + acc += xL2[j+(L2_CACHE_WAY_SIZE/sizeof(uint32_t))]; + + // This data should be cached in way #3 + for ( j = 0 ; j < FFT_SIZE; j++) + acc += inSensorDataRe[j]; + + // This data should be cached in way #4 + for ( j = 0 ; j < FFT_SIZE; j++) + acc += inSensorDataIm[j]; + + return acc; +} + + +//======================================================================================= +// "filter_simulation" Tasks/Functions +//======================================================================================= +static uint64_t calc_filter_simulation_equation(uint8_t tile, uint32_t total_elems) { + uint64_t acc = 0; + const uint32_t begin_idx = tile*xL2_ELEM/total_elems; + const uint32_t end_idx = begin_idx + (xL2_ELEM/total_elems) - 1; + + for ( uint32_t j = 0 ; j <= FILTER_REPETITIONS; j++ ) { + uint32_t i; + + // Simulating filtering/convolution + uint32_t t1 = 0, t2 = 0, t3 = 0, t4 = 0; + for (i = 0 ; i < FFT_SIZE; i++) { + t1 += xL2[(j+i+0*(L2_CACHE_WAY_SIZE/sizeof(uint32_t))) % xL2_ELEM] * coefs[i % COEFS_SIZE]; + t1 += xL2[(j+i+1*(L2_CACHE_WAY_SIZE/sizeof(uint32_t))) % xL2_ELEM] * coefs[i % COEFS_SIZE]; + t1 += xL2[(j+i+2*(L2_CACHE_WAY_SIZE/sizeof(uint32_t))) % xL2_ELEM] * coefs[i % COEFS_SIZE]; + t1 += xL2[(j+i+3*(L2_CACHE_WAY_SIZE/sizeof(uint32_t))) % xL2_ELEM] * coefs[i % COEFS_SIZE]; + t1 += xL2[(j+i+4*(L2_CACHE_WAY_SIZE/sizeof(uint32_t))) % xL2_ELEM] * coefs[i % COEFS_SIZE]; + t1 += xL2[(j+i+5*(L2_CACHE_WAY_SIZE/sizeof(uint32_t))) % xL2_ELEM] * coefs[i % COEFS_SIZE]; + t1 += xL2[(j+i+6*(L2_CACHE_WAY_SIZE/sizeof(uint32_t))) % xL2_ELEM] * coefs[i % COEFS_SIZE]; + t1 += xL2[(j+i+7*(L2_CACHE_WAY_SIZE/sizeof(uint32_t))) % xL2_ELEM] * coefs[i % COEFS_SIZE]; + } + + // Simulating normalization + t3 = ((t1*100)/(42*137)) + xL2[(begin_idx) % xL2_ELEM] ; + t4 = ((t2*10)/(96*137)) + xL2[(end_idx) % xL2_ELEM] ; + acc += (t3+t4); + } + return acc; +} + + +static void calc_task_function(rtems_task_argument arg) { + test_context *ctx; + uint64_t acc; + struct timespec begin_time; + struct timespec end_time; + uint8_t tile = 0; + uint8_t task_idx = 255; + + ctx = (test_context *)arg; + rtems_id local_id = TaskSelfId(); + + for (int i = 0; i < TASK_COUNT; i++){ + if (ctx->task_filter_simulation_id[i] == local_id){ + task_idx = i; + break; + } + } + + char ch = '0' + task_idx; + + rtems_message_queue_config msg_config = { + .name = rtems_build_name('M', 'S', 'G', ch), + .maximum_pending_messages = MAX_PENDING_MESSAGES, + .maximum_message_size = MAX_MESSAGE_SIZE, + .storage_size = sizeof(msg_task_queue_storage[task_idx]), + .storage_area = &msg_task_queue_storage[task_idx], + .attributes = RTEMS_FIFO | RTEMS_GLOBAL}; + + ctx->message_queue[task_idx] = CreateMessageQueue(msg_config); + + SendMessage(ctx->tile_queue, &task_idx, sizeof(task_idx)); + ReceiveMessage(ctx->message_queue[task_idx], &tile); + + while (tile <= ctx->ntiles) { + count_process[tile - 1]++; + rtems_clock_get_uptime(&begin_time); + acc = calc_filter_simulation_equation(tile-1, ctx->ntiles); + rtems_clock_get_uptime(&end_time); + + ObtainMutex(ctx->filter_mutex_id); + ctx->filter_sim_process_time += (float)(end_time.tv_sec - begin_time.tv_sec) + + ( (float)(end_time.tv_nsec/1000 - begin_time.tv_nsec/1000)/1000000.0); + ctx->accxL2 += acc; + ReleaseMutex(ctx->filter_mutex_id); + + SendMessage(ctx->tile_queue, &task_idx, sizeof(task_idx)); + ReceiveMessage(ctx->message_queue[task_idx], &tile); + } + + SendMessage(ctx->tile_queue, &task_idx, sizeof(task_idx)); + SendEvents(ctx->main_task, event_send[task_idx]); + SuspendSelf(); +} + + +//======================================================================================= +// "snr_processing" Tasks/Functions +//======================================================================================= +static void task_snr_read_sensor_data(rtems_task_argument arg){ + test_context *ctx; + uint32_t iter = 0; + + ctx = (test_context *)arg; + + ReceiveAllEvents(EVENT_GO_READ_SENSOR); + + while ( iter < MAX_ITER) { + ObtainMutex(ctx->snr_mutex_id); + + for (uint32_t i = 0; i < FFT_SIZE; i++) { + inSensorDataRe[i] = 0.4995f * cos_aprox(i*2.0f*PI*FREQ[iter%TC_MAX]/FS) + + (noise_generator(0) * NOISE_FACTOR[iter%TC_MAX]); + inSensorDataIm[i] = 0.4995f * sin_aprox(i*2.0f*PI*FREQ[iter%TC_MAX]/FS) + + (noise_generator(0) * NOISE_FACTOR[iter % TC_MAX]); + } + + ReleaseMutex(ctx->snr_mutex_id); + SendEvents(ctx->task_snr_process_data_id, EVENT_DATA_READY); + + iter++; + ReceiveAllEvents(EVENT_DATA_WAS_PROCESSED); + } + + rtems_event_send(ctx->main_task, event_send[(TASK_COUNT-2)]); + SuspendSelf(); +} + +static void task_snr_process_data(rtems_task_argument arg) { + test_context *ctx; + ctx = (test_context *)arg; + uint32_t iter = 0; + struct timespec begin_time; + struct timespec end_time; + + while ( iter < MAX_ITER ) { + ReceiveAllEvents(EVENT_DATA_READY); + ObtainMutex(ctx->snr_mutex_id); + rtems_clock_get_uptime(&begin_time); + + //Apply Blackman-Harris Window + for (uint32_t i = 0; i < FFT_SIZE; i++) { + inSensorDataRe[i] = inSensorDataRe[i]*blackman_harris(i, FFT_SIZE)/ctx->scaling_fft_factor; + inSensorDataIm[i] = inSensorDataIm[i]*blackman_harris(i, FFT_SIZE)/ctx->scaling_fft_factor; + } + + //Calculates FFT + fft(&inSensorDataRe[0], &inSensorDataIm[0], FFT_SIZE_LOG2); + + //Calculates the magnitude values + for (uint32_t i = 0; i < FFT_SIZE; i++) { + inSensorDataRe[i] = (inSensorDataRe[i] * inSensorDataRe[i] + + inSensorDataIm[i] * inSensorDataIm[i]) / ((float)FFT_SIZE); + } + + //Look for the peak Value and its index (no DC) + float maxValue = 0.0; + float maxValueIndex = -1; + for (uint32_t i = 3; i < (FFT_SIZE / 2); i++) { + if (inSensorDataRe[i] > maxValue) { + maxValue = inSensorDataRe[i]; + maxValueIndex = i; + } + } + + //Calculates the signal and noise power (no DC) + float sig = 0.0f; + float noise = 0.0f; + for (uint32_t i = 3; i < (FFT_SIZE / 2); i++) { + if ((i > maxValueIndex - 8) && (i < maxValueIndex + 8)) { + sig += (2 * inSensorDataRe[i]); + } + else { + noise += (2 * inSensorDataRe[i]); + } + } + + if (!(sig > 0.0f)) { sig = 0.0000000001f; } + if (!(noise > 0.0f)) { noise = 0.0000000001f; } + + //Calculates SNR + float snr_float = sig/noise; + + if (snr_float > SNR_THRESHOLD) { + dsp_result[iter] = 1; + } + else { + dsp_result[iter] = 0; + } + rtems_clock_get_uptime(&end_time); + + ctx->snr_process_time += + (float)(end_time.tv_sec - begin_time.tv_sec) + + ( (float)((end_time.tv_nsec/1000) - (begin_time.tv_nsec/1000))/1000000.0); + + ReleaseMutex(ctx->snr_mutex_id); + iter++; + SendEvents(ctx->task_snr_read_sensor_data_id, EVENT_DATA_WAS_PROCESSED); + } + + rtems_event_send(ctx->main_task, event_send[(TASK_COUNT-1)]); + SuspendSelf(); +} + + +//======================================================================================= +// INIT/MAIN Task +//======================================================================================= +static void Init(rtems_task_argument arg){ + (void)arg; + test_context ctx; + uint32_t start_time, end_time, elapsed_time; + char ch, str[ITOA_STR_SIZE]; + uint32_t total_events = 0; + uint8_t task = 255; + bool correctly_processed = true; + (void) memset(&ctx, 0, sizeof(test_context)); + (void) memset(&count_process[0], 0, TOTAL_TILES); + (void) memset(&xL2[0], 0, xL2_ELEM); + (void) memset(&inSensorDataRe[0], 0, FFT_SIZE); + (void) memset(&inSensorDataIm[0], 0, FFT_SIZE); + +#ifdef GR740_ESA_BOARD + soc_stats_regs soc_stats; +#endif + + +//----------------------------------------------------------------------------- +// Create/Initialize Objects +//----------------------------------------------------------------------------- + rtems_message_queue_config msg_config = { + .name = rtems_build_name('M', 'S', 'G', 'T'), + .maximum_pending_messages = RTEMS_ARRAY_SIZE(msg_tile_queue_storage), + .maximum_message_size = MAX_MESSAGE_SIZE, + .storage_size = sizeof(msg_tile_queue_storage), + .storage_area = &msg_tile_queue_storage, + .attributes = RTEMS_FIFO | RTEMS_GLOBAL}; + + ctx.main_task = rtems_task_self(); + ctx.tile_queue = CreateMessageQueue(msg_config); + ctx.ntiles = TOTAL_TILES; + ctx.next_tile = 1; + + rtems_task_config calc_task_config = { + .initial_priority = PRIO_NORMAL, + .storage_size = TASK_STORAGE_SIZE, + .maximum_thread_local_storage_size = MAX_TLS_SIZE, + .initial_modes = RTEMS_DEFAULT_MODES, + .attributes = TASK_ATTRIBUTES}; + + ctx.filter_mutex_id = CreateMutex(rtems_build_name('M', 'U', 'T', '0')); + ctx.snr_mutex_id = CreateMutex(rtems_build_name('M', 'U', 'T', '1')); + SetSelfPriority( PRIO_NORMAL ); + + for (uint32_t i = 0; i < TASK_COUNT-2; i++){ + ch = '0' + i; + calc_task_config.name = rtems_build_name('R', 'U', 'N', ch); + calc_task_config.storage_area = &calc_task_storage[i][0]; + + ctx.task_filter_simulation_id[i] = DoCreateTask(calc_task_config); + StartTask(ctx.task_filter_simulation_id[i], calc_task_function, &ctx); + total_events += event_send[i]; + } + + ch = '0' + (TASK_COUNT-2); + calc_task_config.name = rtems_build_name('R', 'U', 'N', ch); + calc_task_config.storage_area = &calc_task_storage[(TASK_COUNT-2)][0]; + ctx.task_snr_read_sensor_data_id = DoCreateTask(calc_task_config); + StartTask(ctx.task_snr_read_sensor_data_id, task_snr_read_sensor_data, &ctx); + + ch = '0' + (TASK_COUNT-1); + calc_task_config.name = rtems_build_name('R', 'U', 'N', ch); + calc_task_config.storage_area = &calc_task_storage[(TASK_COUNT-1)][0]; + ctx.task_snr_process_data_id = DoCreateTask(calc_task_config); + StartTask(ctx.task_snr_process_data_id, task_snr_process_data, &ctx); + +//----------------------------------------------------------------------------- +// Setup the testcase +//----------------------------------------------------------------------------- + fill_main_memory_with_data(); + l1_dcache_flush(); + l1_dcache_disable(); + +#ifdef GR740_ESA_BOARD + l2_cache_disable(); + l2_cache_flush(); + l2_cache_enable(); +#endif + + l1_dcache_enable(); + uint32_t control_data_word = warmup_caches(); + +#ifdef GR740_ESA_BOARD + // Locking cache way #3 and #4 + l2_cache_set_way_lock(2); + l2_cache_enable_split_responses(); + clockgating_enable_l4stat(); + soc_stats_configure_regs(); + soc_stats_init(&soc_stats); +#endif + + //Calculates mean of Blackman-Harris terms --> to scale a bit the FFT + ctx.scaling_fft_factor = 0.0; + for (uint32_t i = 0; i<FFT_SIZE; i++){ + ctx.scaling_fft_factor += blackman_harris( i, FFT_SIZE); + } + ctx.scaling_fft_factor = ctx.scaling_fft_factor/ ((float) FFT_SIZE); + +//----------------------------------------------------------------------------- +// Do the work: distribute the work through the tasks +//----------------------------------------------------------------------------- + SendEvents(ctx.task_snr_read_sensor_data_id, EVENT_GO_READ_SENSOR); + start_time = rtems_clock_get_ticks_since_boot(); + + rtems_event_set revents = ReceiveAvailableEvents(); + while ( (revents & total_events) != total_events ) { + ReceiveMessage(ctx.tile_queue, &task); + SendMessage(ctx.message_queue[task], &ctx.next_tile, sizeof(ctx.next_tile)); + ctx.next_tile++; + revents = ReceiveAvailableEvents(); + } + // Wait for the SNR tasks to finish + ReceiveAllEvents(event_send[(TASK_COUNT-2)]); + ReceiveAllEvents(event_send[(TASK_COUNT-1)]); + + end_time = rtems_clock_get_ticks_since_boot(); + elapsed_time = end_time - start_time; + +#ifdef GR740_ESA_BOARD + soc_stats_update(&soc_stats); +#endif + +//----------------------------------------------------------------------------- +// Show Results +//----------------------------------------------------------------------------- + print_string("\n"); + print_string("Multicore Elapsed Time -"); + print_string(itoa(elapsed_time, &str[0], 10)); + print_string("\n"); + + for (uint8_t i = 0; i < ctx.ntiles; i++){ + if (count_process[i] != 1){ + correctly_processed = false; + break; + } + } + + if (correctly_processed){ + print_string("Each tile only processed once : true\n"); + } + else{ + print_string("Each tile only processed once : false\n"); + } + + print_string("Input Data Result Value : 0x"); + print_string(itoa(control_data_word , &str[0], 16)); + print_string("\n"); + + print_string("Ouput Data Result Value : 0x"); + if (ctx.accxL2>=UINT32_MAX) { + print_string(itoa( (int32_t) ((ctx.accxL2 >> 32U) & ((uint64_t)UINT32_MAX)) , &str[0], 16)); + print_string(itoa( (int32_t) (ctx.accxL2 & ((uint64_t)UINT32_MAX)) , &str[0], 16)); + } + else { + print_string(itoa((int32_t)ctx.accxL2 , &str[0], 16)); + } + print_string("\n"); + print_string("Time used in filter sim processing : "); + print_string(itoa( (int32_t) (ctx.filter_sim_process_time *1000) , &str[0], 10)); + print_string(" ms\n"); + + print_string("Time used in SNR processing : "); + print_string(itoa( (int32_t) (ctx.snr_process_time *1000) , &str[0], 10)); + print_string(" ms\n"); + + print_string("SNR triggers found at : "); + for (uint32_t j = 0; j < MAX_ITER; j++) + if (dsp_result[j] > 0.0){ + print_string(itoa(j, &str[0], 10)); + print_string(" "); + } + print_string("\n"); + + +#ifdef GR740_ESA_BOARD + print_string("L1 Instr Cache misses (read) CPU_0 : "); + print_string(itoa(soc_stats.l1_inst_cache_miss[0], &str[0], 10)); + print_string("\n"); + print_string("L1 Instr Cache misses (read) CPU_1 : "); + print_string(itoa(soc_stats.l1_inst_cache_miss[1], &str[0], 10)); + print_string("\n"); + print_string("L1 Instr Cache misses (read) CPU_2 : "); + print_string(itoa(soc_stats.l1_inst_cache_miss[2], &str[0], 10)); + print_string("\n"); + print_string("L1 Instr Cache misses (read) CPU_3 : "); + print_string(itoa(soc_stats.l1_inst_cache_miss[3], &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses (read) CPU_0 : "); + print_string(itoa(soc_stats.l1_data_cache_miss[0], &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses (read) CPU_1 : "); + print_string(itoa(soc_stats.l1_data_cache_miss[1], &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses (read) CPU_2 : "); + print_string(itoa(soc_stats.l1_data_cache_miss[2], &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses (read) CPU_3 : "); + print_string(itoa(soc_stats.l1_data_cache_miss[3], &str[0], 10)); + print_string("\n"); + print_string("L2 Cache hits (read + writes) : "); + print_string(itoa(soc_stats.l2_cache_hits, &str[0], 10)); + print_string("\n"); + print_string("L2 Cache misses (read + writes) : "); + print_string(itoa(soc_stats.l2_cache_miss, &str[0], 10)); + print_string("\n"); + print_string("AHB Splits : "); + print_string(itoa(soc_stats.ahb_split_delay, &str[0], 10)); + print_string("\n"); + print_string("\n"); +#endif + + +// -------------------------------------------------------------------------- +// Delete Objects and Finalize testcase +// -------------------------------------------------------------------------- + for (uint32_t i = 0; i < (TASK_COUNT-2); i++){ + DeleteTask(ctx.task_filter_simulation_id[i]); + DeleteMessageQueue(ctx.message_queue[i]); + } + + DeleteTask(ctx.task_snr_process_data_id); + DeleteTask(ctx.task_snr_read_sensor_data_id); + + DeleteMutex(ctx.filter_mutex_id); + DeleteMutex(ctx.snr_mutex_id); + + DeleteMessageQueue(ctx.tile_queue); + rtems_fatal(RTEMS_FATAL_SOURCE_EXIT, 0); +} + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER + +#define CONFIGURE_MAXIMUM_PROCESSORS TEST_PROCESSORS + +#define CONFIGURE_MAXIMUM_MESSAGE_QUEUES MAX_MESSAGE_QUEUES + +#define CONFIGURE_MAXIMUM_SEMAPHORES 2 + +#define CONFIGURE_MAXIMUM_TASKS ( TASK_COUNT + 1 ) + +#define CONFIGURE_SCHEDULER_EDF_SMP + +#define CONFIGURE_MINIMUM_TASK_STACK_SIZE \ + RTEMS_MINIMUM_STACK_SIZE + CPU_STACK_ALIGNMENT + +#define CONFIGURE_EXTRA_TASK_STACKS RTEMS_MINIMUM_STACK_SIZE + +#define CONFIGURE_INIT_TASK_CONSTRUCT_STORAGE_SIZE 2 * TASK_STORAGE_SIZE + +#define CONFIGURE_MINIMUM_TASKS_WITH_USER_PROVIDED_STORAGE \ + CONFIGURE_MAXIMUM_TASKS + +#define CONFIGURE_MICROSECONDS_PER_TICK 1000 + +#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 0 + +#define CONFIGURE_DISABLE_NEWLIB_REENTRANCY + +#define CONFIGURE_APPLICATION_DISABLE_FILESYSTEM + +#define CONFIGURE_MAXIMUM_THREAD_LOCAL_STORAGE_SIZE MAX_TLS_SIZE + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT_TASK_ATTRIBUTES (RTEMS_SYSTEM_TASK | TASK_ATTRIBUTES) + +#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES + +#define CONFIGURE_INIT + +#include <rtems/confdefs.h> diff --git a/testsuites/isvv/23.4_uni_cache_split_transactions_disabled/uni_cache_split_transactions_disabled.c b/testsuites/isvv/23.4_uni_cache_split_transactions_disabled/uni_cache_split_transactions_disabled.c new file mode 100644 index 0000000000..4e73adeaac --- /dev/null +++ b/testsuites/isvv/23.4_uni_cache_split_transactions_disabled/uni_cache_split_transactions_disabled.c @@ -0,0 +1,370 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 2022 Critical Software SA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stddef.h> +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <rtems/bspIo.h> +#include <string.h> +#include "../shared/utils.h" +#include "../shared/isvv_rtems_aux.h" +#include "../shared/low_level_utils.h" + + +/** + * + * @brief Tests impact performing of L2 cache split transactions + * + * Step 1: Uniprocessor case + * + * In this step the same set of math equations used by several tasks in the + * Multiprocessor version are run in an Uniprocessor and ONE task only environment + * in order to achieve a reference output result for comparison. + * + * There is only one set of math equations processed here: + * - named "filter_simulation" + * + * Result values are obtained for later comparison with multiprocessor + * versions. Also some internal cache statistics are shown. Most relevant ones are the + * number of L2 cache misses, which when increased significantly, may delay the data + * processing and the number of split transactions which when enable should lower + * the number of time wasted in waiting for other bus transactions to finish. + * + */ + +/** + * + * For standalone tests in the actual hardware boards the following options can be used: + * + * 1) use make XFLAGS="-Dgr740 -DGR740_ESA_BOARD" + * 2) declare #define GR740_ESA_BOARD at the beginning of this file + * + */ + +#define MAX_TLS_SIZE RTEMS_ALIGN_UP(64, RTEMS_TASK_STORAGE_ALIGNMENT) + +#define TASK_ATTRIBUTES RTEMS_FLOATING_POINT + +#define TASK_STORAGE_SIZE \ + RTEMS_TASK_STORAGE_SIZE( \ + MAX_TLS_SIZE + RTEMS_MINIMUM_STACK_SIZE, \ + TASK_ATTRIBUTES) + +// test specific global vars +#undef TEST_PROCESSORS +#define TEST_PROCESSORS 1 + +#define TASK_COUNT TEST_PROCESSORS +#define TOTAL_TILES 64 + +#define MAX_MESSAGE_SIZE sizeof(uint8_t) +#define MAX_PENDING_MESSAGES 10 + +rtems_event_set event_send[4] = {RTEMS_EVENT_1, + RTEMS_EVENT_2, + RTEMS_EVENT_3, + RTEMS_EVENT_4}; + +uint8_t count_process[TOTAL_TILES]; + +typedef struct{ + uint8_t ntiles; + uint8_t next_tile; + rtems_id task_id[TASK_COUNT]; + rtems_id tile_queue; + uint64_t accxL2; +} test_context; + +#define ITOA_STR_SIZE (8*sizeof(int)+1) + +//----------------------------------------------------------------------------------------- +#define L2_CACHE_SIZE (4U*512U*1024U) // 2Mbytes +#define L2_CACHE_WAY_SIZE (512U*1024U) // 512kbytes +#define xL2_ELEM (8*L2_CACHE_SIZE/sizeof(uint32_t)) // 4M elements + +#ifdef GR740_ESA_BOARD +RTEMS_ALIGNED(L2_CACHE_SIZE) +#endif +static uint32_t xL2[xL2_ELEM]; + +//----------------------------------------------------------------------------------------- +#define FILTER_TAPS (16U) +#define COEFS_SIZE (128U) +const uint32_t coefs[COEFS_SIZE] = + { 29, 31, 37, 41, 43, 47, 53, 59, + 61, 67, 71, 73, 79, 83, 89, 97, + 101, 103, 107, 109, 113, 127, 131, 137, + 139, 149, 151, 157, 163, 167, 173, 179, + 181, 191, 193, 197, 199, 211, 223, 227, + 229, 233, 239, 241, 251, 257, 263, 269, + 271, 277, 281, 283, 293, 307, 311, 313, + 317, 331, 337, 347, 349, 353, 359, 367, + 373, 379, 383, 389, 397, 401, 409, 419, + 421, 431, 433, 439, 443, 449, 457, 461, + 463, 467, 479, 487, 491, 499, 503, 509, + 521, 523, 541, 547, 557, 563, 569, 571, + 577, 587, 593, 599, 601, 607, 613, 617, + 619, 631, 641, 643, 647, 653, 659, 661, + 673, 677, 683, 691, 701, 709, 719, 727, + 733, 739, 743, 751, 757, 761, 769, 773}; + +static void fill_main_memory_with_data(void){ + // Store to memory + for ( uint32_t j = 0 ; j < xL2_ELEM; j ++) + xL2[j] = j; +} + +static uint64_t warmup_caches(void){ + uint64_t acc = 0; + for ( uint32_t j = 0 ; j < xL2_ELEM; j++) + acc += xL2[j]; + return acc; +} + +static uint64_t calc_filter_simulation_equation(uint8_t tile, uint32_t total_elems){ + uint64_t acc = 0; + const uint32_t begin_idx = tile*xL2_ELEM/total_elems; + const uint32_t end_idx = begin_idx + (xL2_ELEM/total_elems) - 1; + + for ( uint32_t j = begin_idx ; j <= end_idx; j ++) { + uint32_t i; + + // Simulating filtering/convolution + uint32_t t1 = 0, t2 = 0, t3 = 0, t4 = 0; + for (i = 0 ; i < FILTER_TAPS; i++) + t1 += xL2[(j+i) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < FILTER_TAPS; i++) + t1 += xL2[(j+i+xL2_ELEM*1/8/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < FILTER_TAPS; i++) + t1 += xL2[(j+i+xL2_ELEM*2/8/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < FILTER_TAPS; i++) + t1 += xL2[(j+i+xL2_ELEM*3/8/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < FILTER_TAPS; i++) + t2 += xL2[(j+i+xL2_ELEM*4/8/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < FILTER_TAPS; i++) + t2 += xL2[(j+i+xL2_ELEM*5/8/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < FILTER_TAPS; i++) + t2 += xL2[(j+i+xL2_ELEM*6/8/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < FILTER_TAPS; i++) + t2 += xL2[(j+i+xL2_ELEM*7/8/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + // Simulating normalization + t3 = ((t1*1000)/(42*137)) + 1; + t4 = ((t2*10)/(96*137)) + 1; + uint64_t t5 = (uint64_t)t3 * (uint64_t)t3; + uint64_t t6 = (uint64_t)t4 * (uint64_t)t4; + acc += (t5+t6)/((uint64_t)isqrt(t4+t3)); + } + return acc; +} + +static void Init(rtems_task_argument arg){ + (void)arg; + test_context ctx; + uint32_t start_time, end_time, elapsed_time; + char str[ITOA_STR_SIZE]; + bool correctly_processed = true; + (void) memset(&ctx, 0, sizeof(test_context)); + (void) memset(&count_process[0], 0, TOTAL_TILES); + (void) memset(&xL2[0], 0, xL2_ELEM); + +#ifdef GR740_ESA_BOARD + soc_stats_regs soc_stats; +#endif + + +//----------------------------------------------------------------------------- +// Create/Initialize Objects +//----------------------------------------------------------------------------- + ctx.ntiles = TOTAL_TILES; + ctx.next_tile = 1; + SetSelfPriority( PRIO_NORMAL ); + + +//----------------------------------------------------------------------------- +// Setup the testcase +//----------------------------------------------------------------------------- + fill_main_memory_with_data(); + l1_dcache_flush(); + l1_dcache_disable(); + +#ifdef GR740_ESA_BOARD + l2_cache_disable(); + l2_cache_flush(); + l2_cache_enable(); +#endif + + l1_dcache_enable(); + uint32_t control_data_word = warmup_caches(); + +#ifdef GR740_ESA_BOARD + l2_cache_disable_split_responses(); + clockgating_enable_l4stat(); + soc_stats_configure_regs(); + soc_stats_init(&soc_stats); +#endif + +//----------------------------------------------------------------------------- +// Do the work +//----------------------------------------------------------------------------- + start_time = rtems_clock_get_ticks_since_boot(); + ctx.accxL2 = calc_filter_simulation_equation(0, 1); + + end_time = rtems_clock_get_ticks_since_boot(); + elapsed_time = end_time - start_time; + +#ifdef GR740_ESA_BOARD + soc_stats_update(&soc_stats); +#endif + +//----------------------------------------------------------------------------- +// Show Results +//----------------------------------------------------------------------------- + print_string("\n"); + print_string("Single Core Elapsed Time -"); + print_string(itoa(elapsed_time, &str[0], 10)); + print_string("\n"); + + for (uint8_t i = 0; i < ctx.ntiles; i++){ + if (count_process[i] != 1){ + correctly_processed = false; + break; + } + } + if (correctly_processed){ + print_string("Each tile only processed once : true\n"); + } + else{ + print_string("Each tile only processed once : false\n"); + } + + print_string("Input Data Result Value : 0x"); + print_string(itoa(control_data_word , &str[0], 16)); + print_string("\n"); + + print_string("Ouput Data Result Value : 0x"); + if (ctx.accxL2>=UINT32_MAX) { + print_string(itoa( (int32_t) ((ctx.accxL2 >> 32U) & ((uint64_t)UINT32_MAX)) , &str[0], 16)); + print_string(itoa( (int32_t) (ctx.accxL2 & ((uint64_t)UINT32_MAX)) , &str[0], 16)); + } + else { + print_string(itoa((int32_t)ctx.accxL2 , &str[0], 16)); + } + print_string("\n"); + + +#ifdef GR740_ESA_BOARD + print_string("L1 Instr Cache misses (read) CPU_0 : "); + print_string(itoa(soc_stats.l1_inst_cache_miss[0], &str[0], 10)); + print_string("\n"); + print_string("L1 Instr Cache misses (read) CPU_1 : "); + print_string(itoa(soc_stats.l1_inst_cache_miss[1], &str[0], 10)); + print_string("\n"); + print_string("L1 Instr Cache misses (read) CPU_2 : "); + print_string(itoa(soc_stats.l1_inst_cache_miss[2], &str[0], 10)); + print_string("\n"); + print_string("L1 Instr Cache misses (read) CPU_3 : "); + print_string(itoa(soc_stats.l1_inst_cache_miss[3], &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses (read) CPU_0 : "); + print_string(itoa(soc_stats.l1_data_cache_miss[0], &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses (read) CPU_1 : "); + print_string(itoa(soc_stats.l1_data_cache_miss[1], &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses (read) CPU_2 : "); + print_string(itoa(soc_stats.l1_data_cache_miss[2], &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses (read) CPU_3 : "); + print_string(itoa(soc_stats.l1_data_cache_miss[3], &str[0], 10)); + print_string("\n"); + print_string("L2 Cache hits (read + writes) : "); + print_string(itoa(soc_stats.l2_cache_hits, &str[0], 10)); + print_string("\n"); + print_string("L2 Cache misses (read + writes) : "); + print_string(itoa(soc_stats.l2_cache_miss, &str[0], 10)); + print_string("\n"); + print_string("AHB Splits : "); + print_string(itoa(soc_stats.ahb_split_delay, &str[0], 10)); + print_string("\n"); + print_string("\n"); +#endif + +// -------------------------------------------------------------------------- +// Delete Objects and Finalize testcase +// -------------------------------------------------------------------------- + + rtems_fatal(RTEMS_FATAL_SOURCE_EXIT, 0); +} + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER + +#define CONFIGURE_MAXIMUM_PROCESSORS TEST_PROCESSORS + +#define CONFIGURE_MAXIMUM_TASKS TEST_PROCESSORS + +#define CONFIGURE_SCHEDULER_EDF_SMP + +#define CONFIGURE_MINIMUM_TASK_STACK_SIZE \ + RTEMS_MINIMUM_STACK_SIZE + CPU_STACK_ALIGNMENT + +#define CONFIGURE_EXTRA_TASK_STACKS RTEMS_MINIMUM_STACK_SIZE + +#define CONFIGURE_INIT_TASK_CONSTRUCT_STORAGE_SIZE 2 * TASK_STORAGE_SIZE + +#define CONFIGURE_MINIMUM_TASKS_WITH_USER_PROVIDED_STORAGE \ + CONFIGURE_MAXIMUM_TASKS + +#define CONFIGURE_MICROSECONDS_PER_TICK 1000 + +#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 0 + +#define CONFIGURE_DISABLE_NEWLIB_REENTRANCY + +#define CONFIGURE_APPLICATION_DISABLE_FILESYSTEM + +#define CONFIGURE_MAXIMUM_THREAD_LOCAL_STORAGE_SIZE MAX_TLS_SIZE + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT_TASK_ATTRIBUTES (RTEMS_SYSTEM_TASK | TASK_ATTRIBUTES) + +#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES + +#define CONFIGURE_INIT + +#include <rtems/confdefs.h> diff --git a/testsuites/isvv/23.5_multi_cache_split_transactions_disabled/multi_cache_split_transactions_disabled.c b/testsuites/isvv/23.5_multi_cache_split_transactions_disabled/multi_cache_split_transactions_disabled.c new file mode 100644 index 0000000000..9e02c793a0 --- /dev/null +++ b/testsuites/isvv/23.5_multi_cache_split_transactions_disabled/multi_cache_split_transactions_disabled.c @@ -0,0 +1,491 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 2022 Critical Software SA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stddef.h> +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <rtems/bspIo.h> +#include <string.h> +#include "../shared/utils.h" +#include "../shared/isvv_rtems_aux.h" +#include "../shared/low_level_utils.h" + + +/** + * + * @brief Tests impact performing of L2 cache split transactions + * + * Step 2: Multiprocessor with L2 cache split transactions disabled + * + * There is one set of math equations processed: + * - named "filter_simulation" + * + * The equations for "filter_simulation" are used by TEST_PROCESSORS tasks that + * processes small sections of a "data array" in parallel. + * + * The locations in memory for acessing the small sections of the "data arrays" do + * overlap in terms of cache memory positions, and when acessing one section of the + * "data array", or even a smaller part of one, other sections of that "data array" + * should be kicked out of the cache. Sometimes that may happen within the same task. + * + * With the "L2 cache split transactions" disabled, everytime a data word is required + * by the CPU from L2 cache, it may happen that the L2 cache is busy retrieving other + * data from the main memory, and the first transaction related to the first data word + * needs to wait for the other transaction to finish, wasting processing time in these + * cases. + * + * Expected Results: + * - The Tiles must be processed only once. + * - "Ouput Data Result Value" must match in the Uniprocessor version with the + * Multiprocessor version with L2 cache split transactions disabled. + * - Elapsed Time should be lower than the Uniprocessor version, but slightly higher + * than Multiprocessor version with L2 cache split transactions enabled. + * - The number of AHB Splits transactions reported must be 0 + * + */ + +/** + * + * For standalone tests in the actual hardware boards the following options can be used: + * + * 1) use make XFLAGS="-Dgr740 -DGR740_ESA_BOARD" + * 2) declare #define GR740_ESA_BOARD at the beginning of this file + * + */ + +#define MAX_TLS_SIZE RTEMS_ALIGN_UP(64, RTEMS_TASK_STORAGE_ALIGNMENT) + +#define TASK_ATTRIBUTES RTEMS_FLOATING_POINT + +#define TASK_STORAGE_SIZE \ + RTEMS_TASK_STORAGE_SIZE( \ + MAX_TLS_SIZE + RTEMS_MINIMUM_STACK_SIZE, \ + TASK_ATTRIBUTES) + +// test specific global vars +#define TASK_COUNT TEST_PROCESSORS +#define TOTAL_TILES 64 + +#define MAX_MESSAGE_QUEUES 5 +#define MAX_MESSAGE_SIZE sizeof(uint8_t) +#define MAX_PENDING_MESSAGES 10 + +rtems_event_set event_send[4] = {RTEMS_EVENT_1, + RTEMS_EVENT_2, + RTEMS_EVENT_3, + RTEMS_EVENT_4}; + +uint8_t count_process[TOTAL_TILES]; + +typedef struct +{ + rtems_id main_task; + uint8_t ntiles; + uint8_t next_tile; + rtems_id task_id[TASK_COUNT]; + rtems_id tile_queue; + rtems_id message_queue[TASK_COUNT]; + rtems_id mutex_id; + uint64_t accxL2; +} test_context; + +RTEMS_ALIGNED(RTEMS_TASK_STORAGE_ALIGNMENT) +static char calc_task_storage[TASK_COUNT][TASK_STORAGE_SIZE]; + +RTEMS_MESSAGE_QUEUE_BUFFER(MAX_MESSAGE_SIZE) +msg_tile_queue_storage[MAX_PENDING_MESSAGES]; + +RTEMS_MESSAGE_QUEUE_BUFFER(MAX_MESSAGE_SIZE) +msg_task_queue_storage[TASK_COUNT][MAX_PENDING_MESSAGES]; + + +#define ITOA_STR_SIZE (8*sizeof(int)+1) + +//----------------------------------------------------------------------------------------- +#define L2_CACHE_SIZE (4U*512U*1024U) // 2Mbytes +#define L2_CACHE_WAY_SIZE (512U*1024U) // 512kbytes +#define xL2_ELEM (8*L2_CACHE_SIZE/sizeof(uint32_t)) // 4M elements + +#ifdef GR740_ESA_BOARD +RTEMS_ALIGNED(L2_CACHE_SIZE) +#endif +static uint32_t xL2[xL2_ELEM]; + +//----------------------------------------------------------------------------------------- +#define FILTER_TAPS (16U) +#define COEFS_SIZE (128U) +const uint32_t coefs[COEFS_SIZE] = + { 29, 31, 37, 41, 43, 47, 53, 59, + 61, 67, 71, 73, 79, 83, 89, 97, + 101, 103, 107, 109, 113, 127, 131, 137, + 139, 149, 151, 157, 163, 167, 173, 179, + 181, 191, 193, 197, 199, 211, 223, 227, + 229, 233, 239, 241, 251, 257, 263, 269, + 271, 277, 281, 283, 293, 307, 311, 313, + 317, 331, 337, 347, 349, 353, 359, 367, + 373, 379, 383, 389, 397, 401, 409, 419, + 421, 431, 433, 439, 443, 449, 457, 461, + 463, 467, 479, 487, 491, 499, 503, 509, + 521, 523, 541, 547, 557, 563, 569, 571, + 577, 587, 593, 599, 601, 607, 613, 617, + 619, 631, 641, 643, 647, 653, 659, 661, + 673, 677, 683, 691, 701, 709, 719, 727, + 733, 739, 743, 751, 757, 761, 769, 773}; + +static void fill_main_memory_with_data(void){ + // Store to memory + for ( uint32_t j = 0 ; j < xL2_ELEM; j ++) + xL2[j] = j; +} + +static uint64_t warmup_caches(void){ + uint64_t acc = 0; + for ( uint32_t j = 0 ; j < xL2_ELEM; j++) + acc += xL2[j]; + return acc; +} + +static uint64_t calc_filter_simulation_equation(uint8_t tile, uint32_t total_elems){ + uint64_t acc = 0; + const uint32_t begin_idx = tile*xL2_ELEM/total_elems; + const uint32_t end_idx = begin_idx + (xL2_ELEM/total_elems) - 1; + + for ( uint32_t j = begin_idx ; j <= end_idx; j ++) { + uint32_t i; + + // Simulating filtering/convolution + uint32_t t1 = 0, t2 = 0, t3 = 0, t4 = 0; + for (i = 0 ; i < FILTER_TAPS; i++) + t1 += xL2[(j+i) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < FILTER_TAPS; i++) + t1 += xL2[(j+i+xL2_ELEM*1/8/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < FILTER_TAPS; i++) + t1 += xL2[(j+i+xL2_ELEM*2/8/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < FILTER_TAPS; i++) + t1 += xL2[(j+i+xL2_ELEM*3/8/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < FILTER_TAPS; i++) + t2 += xL2[(j+i+xL2_ELEM*4/8/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < FILTER_TAPS; i++) + t2 += xL2[(j+i+xL2_ELEM*5/8/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < FILTER_TAPS; i++) + t2 += xL2[(j+i+xL2_ELEM*6/8/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < FILTER_TAPS; i++) + t2 += xL2[(j+i+xL2_ELEM*7/8/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + // Simulating normalization + t3 = ((t1*1000)/(42*137)) + 1; + t4 = ((t2*10)/(96*137)) + 1; + uint64_t t5 = (uint64_t)t3 * (uint64_t)t3; + uint64_t t6 = (uint64_t)t4 * (uint64_t)t4; + acc += (t5+t6)/((uint64_t)isqrt(t4+t3)); + } + return acc; +} + + +static void calc_task_function(rtems_task_argument arg) +{ + test_context *ctx; + uint64_t acc; + + ctx = (test_context *)arg; + + uint8_t tile; + rtems_id local_id = TaskSelfId(); + uint8_t task_idx = 255; + + for (int i = 0; i < TASK_COUNT; i++){ + if (ctx->task_id[i] == local_id){ + task_idx = i; + break; + } + } + + char ch = '0' + task_idx; + + rtems_message_queue_config msg_config = { + .name = rtems_build_name('M', 'S', 'G', ch), + .maximum_pending_messages = MAX_PENDING_MESSAGES, + .maximum_message_size = MAX_MESSAGE_SIZE, + .storage_size = sizeof(msg_task_queue_storage[task_idx]), + .storage_area = &msg_task_queue_storage[task_idx], + .attributes = RTEMS_FIFO | RTEMS_GLOBAL}; + + ctx->message_queue[task_idx] = CreateMessageQueue(msg_config); + + SendMessage(ctx->tile_queue, &task_idx, sizeof(task_idx)); + ReceiveMessage(ctx->message_queue[task_idx], &tile); + + while (tile <= ctx->ntiles) { + acc = 0; + count_process[tile - 1]++; + acc = calc_filter_simulation_equation(tile-1, ctx->ntiles); + + ObtainMutex(ctx->mutex_id); + ctx->accxL2 += acc; + ReleaseMutex(ctx->mutex_id); + + SendMessage(ctx->tile_queue, &task_idx, sizeof(task_idx)); + ReceiveMessage(ctx->message_queue[task_idx], &tile); + } + + SendMessage(ctx->tile_queue, &task_idx, sizeof(task_idx)); + SendEvents(ctx->main_task, event_send[task_idx]); + SuspendSelf(); +} + +static void Init(rtems_task_argument arg){ + (void)arg; + test_context ctx; + uint32_t start_time, end_time, elapsed_time; + char ch, str[ITOA_STR_SIZE]; + uint32_t total_events = 0; + uint8_t task = 255; + bool correctly_processed = true; + (void) memset(&ctx, 0, sizeof(test_context)); + (void) memset(&count_process[0], 0, TOTAL_TILES); + (void) memset(&xL2[0], 0, xL2_ELEM); + +#ifdef GR740_ESA_BOARD + soc_stats_regs soc_stats; +#endif + + +//----------------------------------------------------------------------------- +// Create/Initialize Objects +//----------------------------------------------------------------------------- + rtems_message_queue_config msg_config = { + .name = rtems_build_name('M', 'S', 'G', 'T'), + .maximum_pending_messages = RTEMS_ARRAY_SIZE(msg_tile_queue_storage), + .maximum_message_size = MAX_MESSAGE_SIZE, + .storage_size = sizeof(msg_tile_queue_storage), + .storage_area = &msg_tile_queue_storage, + .attributes = RTEMS_FIFO | RTEMS_GLOBAL}; + + ctx.main_task = rtems_task_self(); + ctx.tile_queue = CreateMessageQueue(msg_config); + ctx.ntiles = TOTAL_TILES; + ctx.next_tile = 1; + + rtems_task_config calc_task_config = { + .initial_priority = PRIO_NORMAL, + .storage_size = TASK_STORAGE_SIZE, + .maximum_thread_local_storage_size = MAX_TLS_SIZE, + .initial_modes = RTEMS_DEFAULT_MODES, + .attributes = TASK_ATTRIBUTES}; + + ctx.mutex_id = CreateMutex(rtems_build_name('M', 'U', 'T', 'X')); + + for (uint32_t i = 0; i < TASK_COUNT; i++){ + ch = '0' + i; + calc_task_config.name = rtems_build_name('R', 'U', 'N', ch); + calc_task_config.storage_area = &calc_task_storage[i][0]; + + ctx.task_id[i] = DoCreateTask(calc_task_config); + StartTask(ctx.task_id[i], calc_task_function, &ctx); + total_events += event_send[i]; + } + SetSelfPriority( PRIO_NORMAL ); + + +//----------------------------------------------------------------------------- +// Setup the testcase +//----------------------------------------------------------------------------- + fill_main_memory_with_data(); + l1_dcache_flush(); + l1_dcache_disable(); + +#ifdef GR740_ESA_BOARD + l2_cache_disable(); + l2_cache_flush(); + l2_cache_enable(); +#endif + + l1_dcache_enable(); + uint32_t control_data_word = warmup_caches(); + +#ifdef GR740_ESA_BOARD + l2_cache_disable_split_responses(); + clockgating_enable_l4stat(); + soc_stats_configure_regs(); + soc_stats_init(&soc_stats); +#endif + +//----------------------------------------------------------------------------- +// Do the work: distribute the work through the tasks +//----------------------------------------------------------------------------- + start_time = rtems_clock_get_ticks_since_boot(); + while (ReceiveAvailableEvents() != total_events) { + ReceiveMessage(ctx.tile_queue, &task); + SendMessage(ctx.message_queue[task], &ctx.next_tile, sizeof(ctx.next_tile)); + ctx.next_tile++; + } + end_time = rtems_clock_get_ticks_since_boot(); + elapsed_time = end_time - start_time; + +#ifdef GR740_ESA_BOARD + soc_stats_update(&soc_stats); +#endif + +//----------------------------------------------------------------------------- +// Show Results +//----------------------------------------------------------------------------- + print_string("\n"); + print_string("Multicore Elapsed Time -"); + print_string(itoa(elapsed_time, &str[0], 10)); + print_string("\n"); + + for (uint8_t i = 0; i < ctx.ntiles; i++){ + if (count_process[i] != 1){ + correctly_processed = false; + break; + } + } + if (correctly_processed){ + print_string("Each tile only processed once : true\n"); + } + else{ + print_string("Each tile only processed once : false\n"); + } + + print_string("Input Data Result Value : 0x"); + print_string(itoa(control_data_word , &str[0], 16)); + print_string("\n"); + + print_string("Ouput Data Result Value : 0x"); + if (ctx.accxL2>=UINT32_MAX) { + print_string(itoa( (int32_t) ((ctx.accxL2 >> 32U) & ((uint64_t)UINT32_MAX)) , &str[0], 16)); + print_string(itoa( (int32_t) (ctx.accxL2 & ((uint64_t)UINT32_MAX)) , &str[0], 16)); + } + else { + print_string(itoa((int32_t)ctx.accxL2 , &str[0], 16)); + } + print_string("\n"); + + +#ifdef GR740_ESA_BOARD + print_string("L1 Instr Cache misses (read) CPU_0 : "); + print_string(itoa(soc_stats.l1_inst_cache_miss[0], &str[0], 10)); + print_string("\n"); + print_string("L1 Instr Cache misses (read) CPU_1 : "); + print_string(itoa(soc_stats.l1_inst_cache_miss[1], &str[0], 10)); + print_string("\n"); + print_string("L1 Instr Cache misses (read) CPU_2 : "); + print_string(itoa(soc_stats.l1_inst_cache_miss[2], &str[0], 10)); + print_string("\n"); + print_string("L1 Instr Cache misses (read) CPU_3 : "); + print_string(itoa(soc_stats.l1_inst_cache_miss[3], &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses (read) CPU_0 : "); + print_string(itoa(soc_stats.l1_data_cache_miss[0], &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses (read) CPU_1 : "); + print_string(itoa(soc_stats.l1_data_cache_miss[1], &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses (read) CPU_2 : "); + print_string(itoa(soc_stats.l1_data_cache_miss[2], &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses (read) CPU_3 : "); + print_string(itoa(soc_stats.l1_data_cache_miss[3], &str[0], 10)); + print_string("\n"); + print_string("L2 Cache hits (read + writes) : "); + print_string(itoa(soc_stats.l2_cache_hits, &str[0], 10)); + print_string("\n"); + print_string("L2 Cache misses (read + writes) : "); + print_string(itoa(soc_stats.l2_cache_miss, &str[0], 10)); + print_string("\n"); + print_string("AHB Splits : "); + print_string(itoa(soc_stats.ahb_split_delay, &str[0], 10)); + print_string("\n"); + print_string("\n"); +#endif + +// -------------------------------------------------------------------------- +// Delete Objects and Finalize testcase +// -------------------------------------------------------------------------- + for (uint32_t i = 0; i < TASK_COUNT; i++){ + DeleteTask(ctx.task_id[i]); + DeleteMessageQueue(ctx.message_queue[i]); + } + DeleteMessageQueue(ctx.tile_queue); + + DeleteMutex(ctx.mutex_id); + + rtems_fatal(RTEMS_FATAL_SOURCE_EXIT, 0); +} + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER + +#define CONFIGURE_MAXIMUM_PROCESSORS TEST_PROCESSORS + +#define CONFIGURE_MAXIMUM_MESSAGE_QUEUES MAX_MESSAGE_QUEUES + +#define CONFIGURE_MAXIMUM_SEMAPHORES 1 + +#define CONFIGURE_MAXIMUM_TASKS ( TEST_PROCESSORS + 1 ) + +#define CONFIGURE_SCHEDULER_EDF_SMP + +#define CONFIGURE_MINIMUM_TASK_STACK_SIZE \ + RTEMS_MINIMUM_STACK_SIZE + CPU_STACK_ALIGNMENT + +#define CONFIGURE_EXTRA_TASK_STACKS RTEMS_MINIMUM_STACK_SIZE + +#define CONFIGURE_INIT_TASK_CONSTRUCT_STORAGE_SIZE 2 * TASK_STORAGE_SIZE + +#define CONFIGURE_MINIMUM_TASKS_WITH_USER_PROVIDED_STORAGE \ + CONFIGURE_MAXIMUM_TASKS + +#define CONFIGURE_MICROSECONDS_PER_TICK 1000 + +#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 0 + +#define CONFIGURE_DISABLE_NEWLIB_REENTRANCY + +#define CONFIGURE_APPLICATION_DISABLE_FILESYSTEM + +#define CONFIGURE_MAXIMUM_THREAD_LOCAL_STORAGE_SIZE MAX_TLS_SIZE + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT_TASK_ATTRIBUTES (RTEMS_SYSTEM_TASK | TASK_ATTRIBUTES) + +#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES + +#define CONFIGURE_INIT + +#include <rtems/confdefs.h> diff --git a/testsuites/isvv/23.6_multi_cache_split_transactions_enabled/multi_cache_split_transactions_enabled.c b/testsuites/isvv/23.6_multi_cache_split_transactions_enabled/multi_cache_split_transactions_enabled.c new file mode 100644 index 0000000000..dcaa534c6c --- /dev/null +++ b/testsuites/isvv/23.6_multi_cache_split_transactions_enabled/multi_cache_split_transactions_enabled.c @@ -0,0 +1,495 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 2022 Critical Software SA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stddef.h> +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <rtems/bspIo.h> +#include <string.h> +#include "../shared/utils.h" +#include "../shared/isvv_rtems_aux.h" +#include "../shared/low_level_utils.h" + + +/** + * + * @brief Tests impact performing of L2 cache split transactions + * + * Step 2: Multiprocessor with L2 cache split transactions enabled + * + * There is one set of math equations processed: + * - named "filter_simulation" + * + * The equations for "filter_simulation" are used by TEST_PROCESSORS tasks that + * processes small sections of a "data array" in parallel. + * + * The locations in memory for acessing the small sections of the "data arrays" do + * overlap in terms of cache memory positions, and when acessing one section of the + * "data array", or even a smaller part of one, other sections of that "data array" + * should be kicked out of the cache. Sometimes that may happen within the same task. + * + * With the "L2 cache split transactions" enabled, everytime a data word is required + * by the CPU from L2 and it may happen that the L2 cache is busy retrieving other other data + * from the main memory, and the data word would need to wait for the other transaction to + * finish if L2 cache split transactions enabled. + * + * With L2 cache split transactions enabled, L2 cache can issue a split transactation to + * the other data transaction, and becomes free to attend the data word that was required by CPU. + * For the other data transaction, the master of the bus that requested it must issue a Retry + * transaction. + * + * Expected Results: + * - The Tiles must be processed only once. + * - "Ouput Data Result Value" must match in the Uniprocessor version with the + * Multiprocessor version with L2 cache split transactions disabled. + * - Elapsed Time should be lower than the Uniprocessor version, and slightly lower + * than Multiprocessor version with L2 cache split transactions disabled. + * - The number of AHB Splits transactions reported must be significant + * + */ + +/** + * + * For standalone tests in the actual hardware boards the following options can be used: + * + * 1) use make XFLAGS="-Dgr740 -DGR740_ESA_BOARD" + * 2) declare #define GR740_ESA_BOARD at the beginning of this file + * + */ + +#define MAX_TLS_SIZE RTEMS_ALIGN_UP(64, RTEMS_TASK_STORAGE_ALIGNMENT) + +#define TASK_ATTRIBUTES RTEMS_FLOATING_POINT + +#define TASK_STORAGE_SIZE \ + RTEMS_TASK_STORAGE_SIZE( \ + MAX_TLS_SIZE + RTEMS_MINIMUM_STACK_SIZE, \ + TASK_ATTRIBUTES) + +// test specific global vars +#define TASK_COUNT TEST_PROCESSORS +#define TOTAL_TILES 64 + +#define MAX_MESSAGE_QUEUES 5 +#define MAX_MESSAGE_SIZE sizeof(uint8_t) +#define MAX_PENDING_MESSAGES 10 + +rtems_event_set event_send[4] = {RTEMS_EVENT_1, + RTEMS_EVENT_2, + RTEMS_EVENT_3, + RTEMS_EVENT_4}; + +uint8_t count_process[TOTAL_TILES]; + +typedef struct +{ + rtems_id main_task; + uint8_t ntiles; + uint8_t next_tile; + rtems_id task_id[TASK_COUNT]; + rtems_id tile_queue; + rtems_id message_queue[TASK_COUNT]; + rtems_id mutex_id; + uint64_t accxL2; +} test_context; + +RTEMS_ALIGNED(RTEMS_TASK_STORAGE_ALIGNMENT) +static char calc_task_storage[TASK_COUNT][TASK_STORAGE_SIZE]; + +RTEMS_MESSAGE_QUEUE_BUFFER(MAX_MESSAGE_SIZE) +msg_tile_queue_storage[MAX_PENDING_MESSAGES]; + +RTEMS_MESSAGE_QUEUE_BUFFER(MAX_MESSAGE_SIZE) +msg_task_queue_storage[TASK_COUNT][MAX_PENDING_MESSAGES]; + + +#define ITOA_STR_SIZE (8*sizeof(int)+1) + +//----------------------------------------------------------------------------------------- +#define L2_CACHE_SIZE (4U*512U*1024U) // 2Mbytes +#define L2_CACHE_WAY_SIZE (512U*1024U) // 512kbytes +#define xL2_ELEM (8*L2_CACHE_SIZE/sizeof(uint32_t)) // 4M elements + +#ifdef GR740_ESA_BOARD +RTEMS_ALIGNED(L2_CACHE_SIZE) +#endif +static uint32_t xL2[xL2_ELEM]; + +//----------------------------------------------------------------------------------------- +#define FILTER_TAPS (16U) +#define COEFS_SIZE (128U) +const uint32_t coefs[COEFS_SIZE] = + { 29, 31, 37, 41, 43, 47, 53, 59, + 61, 67, 71, 73, 79, 83, 89, 97, + 101, 103, 107, 109, 113, 127, 131, 137, + 139, 149, 151, 157, 163, 167, 173, 179, + 181, 191, 193, 197, 199, 211, 223, 227, + 229, 233, 239, 241, 251, 257, 263, 269, + 271, 277, 281, 283, 293, 307, 311, 313, + 317, 331, 337, 347, 349, 353, 359, 367, + 373, 379, 383, 389, 397, 401, 409, 419, + 421, 431, 433, 439, 443, 449, 457, 461, + 463, 467, 479, 487, 491, 499, 503, 509, + 521, 523, 541, 547, 557, 563, 569, 571, + 577, 587, 593, 599, 601, 607, 613, 617, + 619, 631, 641, 643, 647, 653, 659, 661, + 673, 677, 683, 691, 701, 709, 719, 727, + 733, 739, 743, 751, 757, 761, 769, 773}; + +static void fill_main_memory_with_data(void){ + // Store to memory + for ( uint32_t j = 0 ; j < xL2_ELEM; j ++) + xL2[j] = j; +} + +static uint64_t warmup_caches(void){ + uint64_t acc = 0; + for ( uint32_t j = 0 ; j < xL2_ELEM; j++) + acc += xL2[j]; + return acc; +} + +static uint64_t calc_filter_simulation_equation(uint8_t tile, uint32_t total_elems){ + uint64_t acc = 0; + const uint32_t begin_idx = tile*xL2_ELEM/total_elems; + const uint32_t end_idx = begin_idx + (xL2_ELEM/total_elems) - 1; + + for ( uint32_t j = begin_idx ; j <= end_idx; j ++) { + uint32_t i; + + // Simulating filtering/convolution + uint32_t t1 = 0, t2 = 0, t3 = 0, t4 = 0; + for (i = 0 ; i < FILTER_TAPS; i++) + t1 += xL2[(j+i) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < FILTER_TAPS; i++) + t1 += xL2[(j+i+xL2_ELEM*1/8/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < FILTER_TAPS; i++) + t1 += xL2[(j+i+xL2_ELEM*2/8/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < FILTER_TAPS; i++) + t1 += xL2[(j+i+xL2_ELEM*3/8/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < FILTER_TAPS; i++) + t2 += xL2[(j+i+xL2_ELEM*4/8/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < FILTER_TAPS; i++) + t2 += xL2[(j+i+xL2_ELEM*5/8/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < FILTER_TAPS; i++) + t2 += xL2[(j+i+xL2_ELEM*6/8/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < FILTER_TAPS; i++) + t2 += xL2[(j+i+xL2_ELEM*7/8/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + // Simulating normalization + t3 = ((t1*1000)/(42*137)) + 1; + t4 = ((t2*10)/(96*137)) + 1; + uint64_t t5 = (uint64_t)t3 * (uint64_t)t3; + uint64_t t6 = (uint64_t)t4 * (uint64_t)t4; + acc += (t5+t6)/((uint64_t)isqrt(t4+t3)); + } + return acc; +} + + +static void calc_task_function(rtems_task_argument arg) +{ + test_context *ctx; + uint64_t acc; + + ctx = (test_context *)arg; + + uint8_t tile; + rtems_id local_id = TaskSelfId(); + uint8_t task_idx = 255; + + for (int i = 0; i < TASK_COUNT; i++){ + if (ctx->task_id[i] == local_id){ + task_idx = i; + break; + } + } + + char ch = '0' + task_idx; + + rtems_message_queue_config msg_config = { + .name = rtems_build_name('M', 'S', 'G', ch), + .maximum_pending_messages = MAX_PENDING_MESSAGES, + .maximum_message_size = MAX_MESSAGE_SIZE, + .storage_size = sizeof(msg_task_queue_storage[task_idx]), + .storage_area = &msg_task_queue_storage[task_idx], + .attributes = RTEMS_FIFO | RTEMS_GLOBAL}; + + ctx->message_queue[task_idx] = CreateMessageQueue(msg_config); + + SendMessage(ctx->tile_queue, &task_idx, sizeof(task_idx)); + ReceiveMessage(ctx->message_queue[task_idx], &tile); + + while (tile <= ctx->ntiles) { + acc = 0; + count_process[tile - 1]++; + acc = calc_filter_simulation_equation(tile-1, ctx->ntiles); + + ObtainMutex(ctx->mutex_id); + ctx->accxL2 += acc; + ReleaseMutex(ctx->mutex_id); + + SendMessage(ctx->tile_queue, &task_idx, sizeof(task_idx)); + ReceiveMessage(ctx->message_queue[task_idx], &tile); + } + + SendMessage(ctx->tile_queue, &task_idx, sizeof(task_idx)); + SendEvents(ctx->main_task, event_send[task_idx]); + SuspendSelf(); +} + +static void Init(rtems_task_argument arg){ + (void)arg; + test_context ctx; + uint32_t start_time, end_time, elapsed_time; + char ch, str[ITOA_STR_SIZE]; + uint32_t total_events = 0; + uint8_t task = 255; + bool correctly_processed = true; + (void) memset(&ctx, 0, sizeof(test_context)); + (void) memset(&count_process[0], 0, TOTAL_TILES); + (void) memset(&xL2[0], 0, xL2_ELEM); + +#ifdef GR740_ESA_BOARD + soc_stats_regs soc_stats; +#endif + + +//----------------------------------------------------------------------------- +// Create/Initialize Objects +//----------------------------------------------------------------------------- + rtems_message_queue_config msg_config = { + .name = rtems_build_name('M', 'S', 'G', 'T'), + .maximum_pending_messages = RTEMS_ARRAY_SIZE(msg_tile_queue_storage), + .maximum_message_size = MAX_MESSAGE_SIZE, + .storage_size = sizeof(msg_tile_queue_storage), + .storage_area = &msg_tile_queue_storage, + .attributes = RTEMS_FIFO | RTEMS_GLOBAL}; + + ctx.main_task = rtems_task_self(); + ctx.tile_queue = CreateMessageQueue(msg_config); + ctx.ntiles = TOTAL_TILES; + ctx.next_tile = 1; + + rtems_task_config calc_task_config = { + .initial_priority = PRIO_NORMAL, + .storage_size = TASK_STORAGE_SIZE, + .maximum_thread_local_storage_size = MAX_TLS_SIZE, + .initial_modes = RTEMS_DEFAULT_MODES, + .attributes = TASK_ATTRIBUTES}; + + ctx.mutex_id = CreateMutex(rtems_build_name('M', 'U', 'T', 'X')); + + for (uint32_t i = 0; i < TASK_COUNT; i++){ + ch = '0' + i; + calc_task_config.name = rtems_build_name('R', 'U', 'N', ch); + calc_task_config.storage_area = &calc_task_storage[i][0]; + + ctx.task_id[i] = DoCreateTask(calc_task_config); + StartTask(ctx.task_id[i], calc_task_function, &ctx); + total_events += event_send[i]; + } + SetSelfPriority( PRIO_NORMAL ); + + +//----------------------------------------------------------------------------- +// Setup the testcase +//----------------------------------------------------------------------------- + fill_main_memory_with_data(); + l1_dcache_flush(); + l1_dcache_disable(); + +#ifdef GR740_ESA_BOARD + l2_cache_disable(); + l2_cache_flush(); + l2_cache_enable(); +#endif + + l1_dcache_enable(); + uint32_t control_data_word = warmup_caches(); + +#ifdef GR740_ESA_BOARD + l2_cache_enable_split_responses(); + clockgating_enable_l4stat(); + soc_stats_configure_regs(); + soc_stats_init(&soc_stats); +#endif + +//----------------------------------------------------------------------------- +// Do the work: distribute the work through the tasks +//----------------------------------------------------------------------------- + start_time = rtems_clock_get_ticks_since_boot(); + while (ReceiveAvailableEvents() != total_events) { + ReceiveMessage(ctx.tile_queue, &task); + SendMessage(ctx.message_queue[task], &ctx.next_tile, sizeof(ctx.next_tile)); + ctx.next_tile++; + } + end_time = rtems_clock_get_ticks_since_boot(); + elapsed_time = end_time - start_time; + +#ifdef GR740_ESA_BOARD + soc_stats_update(&soc_stats); +#endif + +//----------------------------------------------------------------------------- +// Show Results +//----------------------------------------------------------------------------- + print_string("\n"); + print_string("Multicore Elapsed Time -"); + print_string(itoa(elapsed_time, &str[0], 10)); + print_string("\n"); + + for (uint8_t i = 0; i < ctx.ntiles; i++){ + if (count_process[i] != 1){ + correctly_processed = false; + break; + } + } + if (correctly_processed){ + print_string("Each tile only processed once : true\n"); + } + else{ + print_string("Each tile only processed once : false\n"); + } + + print_string("Input Data Result Value : 0x"); + print_string(itoa(control_data_word , &str[0], 16)); + print_string("\n"); + + print_string("Ouput Data Result Value : 0x"); + if (ctx.accxL2>=UINT32_MAX) { + print_string(itoa( (int32_t) ((ctx.accxL2 >> 32U) & ((uint64_t)UINT32_MAX)) , &str[0], 16)); + print_string(itoa( (int32_t) (ctx.accxL2 & ((uint64_t)UINT32_MAX)) , &str[0], 16)); + } + else { + print_string(itoa((int32_t)ctx.accxL2 , &str[0], 16)); + } + print_string("\n"); + + +#ifdef GR740_ESA_BOARD + print_string("L1 Instr Cache misses (read) CPU_0 : "); + print_string(itoa(soc_stats.l1_inst_cache_miss[0], &str[0], 10)); + print_string("\n"); + print_string("L1 Instr Cache misses (read) CPU_1 : "); + print_string(itoa(soc_stats.l1_inst_cache_miss[1], &str[0], 10)); + print_string("\n"); + print_string("L1 Instr Cache misses (read) CPU_2 : "); + print_string(itoa(soc_stats.l1_inst_cache_miss[2], &str[0], 10)); + print_string("\n"); + print_string("L1 Instr Cache misses (read) CPU_3 : "); + print_string(itoa(soc_stats.l1_inst_cache_miss[3], &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses (read) CPU_0 : "); + print_string(itoa(soc_stats.l1_data_cache_miss[0], &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses (read) CPU_1 : "); + print_string(itoa(soc_stats.l1_data_cache_miss[1], &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses (read) CPU_2 : "); + print_string(itoa(soc_stats.l1_data_cache_miss[2], &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses (read) CPU_3 : "); + print_string(itoa(soc_stats.l1_data_cache_miss[3], &str[0], 10)); + print_string("\n"); + print_string("L2 Cache hits (read + writes) : "); + print_string(itoa(soc_stats.l2_cache_hits, &str[0], 10)); + print_string("\n"); + print_string("L2 Cache misses (read + writes) : "); + print_string(itoa(soc_stats.l2_cache_miss, &str[0], 10)); + print_string("\n"); + print_string("AHB Splits : "); + print_string(itoa(soc_stats.ahb_split_delay, &str[0], 10)); + print_string("\n"); + print_string("\n"); +#endif + +// -------------------------------------------------------------------------- +// Delete Objects and Finalize testcase +// -------------------------------------------------------------------------- + for (uint32_t i = 0; i < TASK_COUNT; i++){ + DeleteTask(ctx.task_id[i]); + DeleteMessageQueue(ctx.message_queue[i]); + } + DeleteMessageQueue(ctx.tile_queue); + + DeleteMutex(ctx.mutex_id); + + rtems_fatal(RTEMS_FATAL_SOURCE_EXIT, 0); +} + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER + +#define CONFIGURE_MAXIMUM_PROCESSORS TEST_PROCESSORS + +#define CONFIGURE_MAXIMUM_MESSAGE_QUEUES MAX_MESSAGE_QUEUES + +#define CONFIGURE_MAXIMUM_SEMAPHORES 1 + +#define CONFIGURE_MAXIMUM_TASKS ( TEST_PROCESSORS + 1 ) + +#define CONFIGURE_SCHEDULER_EDF_SMP + +#define CONFIGURE_MINIMUM_TASK_STACK_SIZE \ + RTEMS_MINIMUM_STACK_SIZE + CPU_STACK_ALIGNMENT + +#define CONFIGURE_EXTRA_TASK_STACKS RTEMS_MINIMUM_STACK_SIZE + +#define CONFIGURE_INIT_TASK_CONSTRUCT_STORAGE_SIZE 2 * TASK_STORAGE_SIZE + +#define CONFIGURE_MINIMUM_TASKS_WITH_USER_PROVIDED_STORAGE \ + CONFIGURE_MAXIMUM_TASKS + +#define CONFIGURE_MICROSECONDS_PER_TICK 1000 + +#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 0 + +#define CONFIGURE_DISABLE_NEWLIB_REENTRANCY + +#define CONFIGURE_APPLICATION_DISABLE_FILESYSTEM + +#define CONFIGURE_MAXIMUM_THREAD_LOCAL_STORAGE_SIZE MAX_TLS_SIZE + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT_TASK_ATTRIBUTES (RTEMS_SYSTEM_TASK | TASK_ATTRIBUTES) + +#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES + +#define CONFIGURE_INIT + +#include <rtems/confdefs.h> diff --git a/testsuites/isvv/23.7_uni_cache_repl_policy_l2_lru/uni_cache_repl_policy_l2_lru.c b/testsuites/isvv/23.7_uni_cache_repl_policy_l2_lru/uni_cache_repl_policy_l2_lru.c new file mode 100644 index 0000000000..0315036a28 --- /dev/null +++ b/testsuites/isvv/23.7_uni_cache_repl_policy_l2_lru/uni_cache_repl_policy_l2_lru.c @@ -0,0 +1,535 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 2022 Critical Software SA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stddef.h> +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <rtems/bspIo.h> +#include <string.h> +#include "../shared/utils.h" +#include "../shared/isvv_rtems_aux.h" +#include "../shared/low_level_utils.h" + + +/** + * + * @brief Tests impact performing of L2 cache replacement policy + * + * Step 1: Uniprocessor case + * + * In this step the same set of math equations used by several tasks in the + * Multiprocessor version are run in an Uniprocessor and ONE task only environment + * in order to achieve a reference output result for comparison. + * + * There are two main sets of math equations processed here: + * - one named "filter_simulation" + * - and other named "snr_processing" + * + * For each one, result values are obtained for later comparison with multiprocessor + * versions. Also some internal cache statistics are shown. Most relevant one is the number of + * L2 cache misses, which when increased significantly, may delay the data processing. + * + */ + +/** + * + * For standalone tests in the actual hardware boards the following options can be used: + * + * 1) use make XFLAGS="-Dgr740 -DGR740_ESA_BOARD" + * 2) declare #define GR740_ESA_BOARD at the beginning of this file + * + */ + +#define MAX_TLS_SIZE RTEMS_ALIGN_UP(64, RTEMS_TASK_STORAGE_ALIGNMENT) + +#define TASK_ATTRIBUTES RTEMS_FLOATING_POINT + +#define TASK_STORAGE_SIZE \ + RTEMS_TASK_STORAGE_SIZE( \ + MAX_TLS_SIZE + RTEMS_MINIMUM_STACK_SIZE, \ + TASK_ATTRIBUTES) + + +// test specific global vars +#undef TEST_PROCESSORS +#define TEST_PROCESSORS 1 + +#define TASK_COUNT TEST_PROCESSORS +#define TOTAL_TILES 128 + +#define MAX_MESSAGE_SIZE sizeof(uint8_t) +#define MAX_PENDING_MESSAGES 10 + +const rtems_event_set event_send[6] = {RTEMS_EVENT_1, + RTEMS_EVENT_2, + RTEMS_EVENT_3, + RTEMS_EVENT_4, + RTEMS_EVENT_5, + RTEMS_EVENT_6 + }; + +uint8_t count_process[TOTAL_TILES]; + +typedef struct{ + uint8_t ntiles; + uint8_t next_tile; + float filter_sim_process_time; + uint64_t accxL2; + float snr_process_time; + float scaling_fft_factor; +} test_context; + +#define ITOA_STR_SIZE (8*sizeof(int)+1) + +//------------------------------------------------------------------------------- +#define L2_CACHE_SIZE (4U*512U*1024U) // 2M bytes +#define L2_CACHE_WAY_SIZE (512U*1024U) // 512k bytes +#define xL2_ELEM (4*L2_CACHE_SIZE/sizeof(uint32_t)) // 2M elements + +#ifdef GR740_ESA_BOARD +RTEMS_ALIGNED(L2_CACHE_SIZE) +#endif +static uint32_t xL2[xL2_ELEM]; + +#define COEFS_SIZE (128U) +const uint32_t coefs[COEFS_SIZE] = + { 29, 31, 37, 41, 43, 47, 53, 59, + 61, 67, 71, 73, 79, 83, 89, 97, + 101, 103, 107, 109, 113, 127, 131, 137, + 139, 149, 151, 157, 163, 167, 173, 179, + 181, 191, 193, 197, 199, 211, 223, 227, + 229, 233, 239, 241, 251, 257, 263, 269, + 271, 277, 281, 283, 293, 307, 311, 313, + 317, 331, 337, 347, 349, 353, 359, 367, + 373, 379, 383, 389, 397, 401, 409, 419, + 421, 431, 433, 439, 443, 449, 457, 461, + 463, 467, 479, 487, 491, 499, 503, 509, + 521, 523, 541, 547, 557, 563, 569, 571, + 577, 587, 593, 599, 601, 607, 613, 617, + 619, 631, 641, 643, 647, 653, 659, 661, + 673, 677, 683, 691, 701, 709, 719, 727, + 733, 739, 743, 751, 757, 761, 769, 773}; + +//------------------------------------------------------------------------------- +#define SENSOR_DATA_ELEM (6*L2_CACHE_WAY_SIZE/sizeof(uint32_t)) +#define MAX_ITER (SENSOR_DATA_ELEM / FFT_SIZE) +#define FFT_SIZE (8192U) +#define FFT_SIZE_LOG2 (13U) +#define TC_MAX (16U) +#define FILTER_TAPS (64U) +#define SNR_THRESHOLD (1000000.0f) +const uint16_t FS = 48000U; +const uint16_t FREQ[TC_MAX] = { 2500U, 1500U, 15000U, 500U, + 1000U, 800U, 440U, 8000U, + 100U, 3500U, 12345U, 1200U, + 20000U, 715U, 5000U, 4500U }; +const float NOISE_FACTOR[TC_MAX] = { 0.0001f, 0.2250f, 0.00068f, 0.30f, + 0.004f, 0.0123f, 0.0054f, 0.00054f, + 0.01f, 0.0325f, 0.012f, 0.00032f, + 0.075f, 0.0423f, 0.0354f, 0.00002f }; +#ifdef GR740_ESA_BOARD +RTEMS_ALIGNED(L2_CACHE_WAY_SIZE) +#endif +static float inSensorDataRe[SENSOR_DATA_ELEM]; + +#ifdef GR740_ESA_BOARD +RTEMS_ALIGNED(L2_CACHE_WAY_SIZE) +#endif +static float inSensorDataIm[SENSOR_DATA_ELEM]; +static uint8_t dsp_result[MAX_ITER]; + + +//======================================================================================= +// Auxiliary Functions +//======================================================================================= +static void fill_main_memory_with_data(void){ + // Store to memory + for ( uint32_t j = 0 ; j < xL2_ELEM; j ++) + xL2[j] = j; +} + +static uint64_t warmup_caches(void){ + uint64_t acc = 0; + for ( uint32_t j = 0 ; j < xL2_ELEM; j++) + acc += xL2[j]; + return acc; +} + + +//======================================================================================= +// "filter_simulation" Tasks/Functions +//======================================================================================= +static uint64_t calc_filter_simulation_equation(uint8_t tile, uint32_t total_elems) { + uint64_t acc = 0; + const uint32_t begin_idx = tile*xL2_ELEM/total_elems; + const uint32_t end_idx = begin_idx + (xL2_ELEM/total_elems) - 1; + + for ( uint32_t j = begin_idx ; j <= end_idx; j++ ) { + uint32_t i; + + // Simulating filtering/convolution + uint32_t t1 = 0, t2 = 0, t3 = 0, t4 = 0; + for (i = 0 ; i < FILTER_TAPS; i++) + t1 += xL2[(j+i) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < FILTER_TAPS; i++) + t1 += xL2[(j+i+L2_CACHE_WAY_SIZE*1/2/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < FILTER_TAPS; i++) + t1 += xL2[(j+i+L2_CACHE_WAY_SIZE*2/2/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < FILTER_TAPS; i++) + t1 += xL2[(j+i+L2_CACHE_WAY_SIZE*3/2/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < FILTER_TAPS; i++) + t1 += xL2[(j+i+L2_CACHE_WAY_SIZE*4/2/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < FILTER_TAPS; i++) + t1 += xL2[(j+i+L2_CACHE_WAY_SIZE*5/2/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < FILTER_TAPS; i++) + t1 += xL2[(j+i+L2_CACHE_WAY_SIZE*6/2/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < FILTER_TAPS; i++) + t1 += xL2[(j+i+L2_CACHE_WAY_SIZE*7/2/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + // Simulating normalization + t3 = ((t1*1000)/(42*137)) + 1; + t4 = ((t2*10)/(96*137)) + 1; + uint64_t t5 = (uint64_t)t3 * (uint64_t)t3; + uint64_t t6 = (uint64_t)t4 * (uint64_t)t4; + acc += (t5+t6)/((uint64_t)isqrt(t4+t3)); + } + return acc; +} + +static uint64_t function_calc_filter_simulation(test_context *ctx, uint8_t tile, uint32_t total_elems) { + struct timespec begin_time; + struct timespec end_time; + static uint64_t acc; + + rtems_clock_get_uptime(&begin_time); + + acc = calc_filter_simulation_equation(tile, total_elems); + + rtems_clock_get_uptime(&end_time); + ctx->filter_sim_process_time += + (float)(end_time.tv_sec - begin_time.tv_sec) + + ( (float)((end_time.tv_nsec/1000) - (begin_time.tv_nsec/1000))/1000000.0); + + return acc; +} + + +//======================================================================================= +// "snr_processing" Tasks/Functions +//======================================================================================= +static void function_snr_read_sensor_data( uint32_t start_idx, uint32_t iter) { + for (uint32_t i = 0; i < FFT_SIZE; i++) { + inSensorDataRe[start_idx + i] = 0.4995f * cos_aprox(i*2.0f*PI*FREQ[iter%TC_MAX]/FS) + + (noise_generator(0) * NOISE_FACTOR[iter%TC_MAX]); + inSensorDataIm[start_idx + i] = 0.4995f * sin_aprox(i*2.0f*PI*FREQ[iter%TC_MAX]/FS) + + (noise_generator(0) * NOISE_FACTOR[iter % TC_MAX]); + } +} + +static void function_snr_process_data(test_context *ctx, uint32_t start_idx, uint32_t iter) { + struct timespec begin_time; + struct timespec end_time; + + rtems_clock_get_uptime(&begin_time); + + //Apply Blackman-Harris Window + for (uint32_t i = 0; i < FFT_SIZE; i++) { + inSensorDataRe[i] = inSensorDataRe[start_idx+i]*blackman_harris(i, FFT_SIZE)/ctx->scaling_fft_factor; + inSensorDataIm[i] = inSensorDataIm[start_idx+i]*blackman_harris(i, FFT_SIZE)/ctx->scaling_fft_factor; + } + + //Calculates FFT + fft(&inSensorDataRe[0], &inSensorDataIm[0], FFT_SIZE_LOG2); + + //Calculates the magnitude values + for (uint32_t i = 0; i < FFT_SIZE; i++) { + inSensorDataRe[i] = (inSensorDataRe[i] * inSensorDataRe[i] + + inSensorDataIm[i] * inSensorDataIm[i]) / ((float)FFT_SIZE); + } + + //Look for the peak Value and its index (no DC) + float maxValue = 0.0; + float maxValueIndex = -1; + for (uint32_t i = 3; i < (FFT_SIZE / 2); i++) { + if (inSensorDataRe[i] > maxValue) { + maxValue = inSensorDataRe[i]; + maxValueIndex = i; + } + } + + //Calculates the signal and noise power (no DC) + float sig = 0.0f; + float noise = 0.0f; + for (uint32_t i = 3; i < (FFT_SIZE / 2); i++) { + if ((i > maxValueIndex - 4) && (i < maxValueIndex + 4)) { + sig += (2 * inSensorDataRe[i]); + } + else { + noise += (2 * inSensorDataRe[i]); + } + } + + if (!(sig > 0.0f)) { sig = 0.0000000001f; } + if (!(noise > 0.0f)) { noise = 0.0000000001f; } + + //Calculates SNR + float snr_float = sig/noise; + + if (snr_float > SNR_THRESHOLD) { + dsp_result[iter] = 1; + } + else { + dsp_result[iter] = 0; + } + rtems_clock_get_uptime(&end_time); + + ctx->snr_process_time += + (float)(end_time.tv_sec - begin_time.tv_sec) + + ( (float)((end_time.tv_nsec/1000) - (begin_time.tv_nsec/1000))/1000000.0); +} + + +//======================================================================================= +// INIT/MAIN Task +//======================================================================================= +static void Init(rtems_task_argument arg){ + (void)arg; + test_context ctx; + uint32_t start_time, end_time, elapsed_time; + char str[ITOA_STR_SIZE]; + bool correctly_processed = true; + (void) memset(&ctx, 0, sizeof(test_context)); + (void) memset(&count_process[0], 0, TOTAL_TILES); + (void) memset(&xL2[0], 0, xL2_ELEM); + (void) memset(&inSensorDataRe[0], 0, SENSOR_DATA_ELEM); + (void) memset(&inSensorDataIm[0], 0, SENSOR_DATA_ELEM); + +#ifdef GR740_ESA_BOARD + soc_stats_regs soc_stats; +#endif + +//----------------------------------------------------------------------------- +// Create/Initialize Objects +//----------------------------------------------------------------------------- + ctx.ntiles = TOTAL_TILES; + ctx.next_tile = 1; + SetSelfPriority( PRIO_NORMAL ); + + +//----------------------------------------------------------------------------- +// Setup the testcase +//----------------------------------------------------------------------------- + fill_main_memory_with_data(); + l1_dcache_flush(); + l1_dcache_disable(); + +#ifdef GR740_ESA_BOARD + l2_cache_disable(); + l2_cache_flush(); + l2_cache_set_replacement_policy(L2_CACHE_REPL_LRU, 0); + l2_cache_enable(); +#endif + + l1_dcache_enable(); + uint32_t control_data_word = warmup_caches(); + +#ifdef GR740_ESA_BOARD + clockgating_enable_l4stat(); + soc_stats_configure_regs(); + soc_stats_init(&soc_stats); +#endif + + //Calculates mean of Blackman-Harris terms + ctx.scaling_fft_factor = 0.0; + for (uint32_t i = 0; i<FFT_SIZE; i++){ + ctx.scaling_fft_factor += blackman_harris( i, FFT_SIZE); + } + ctx.scaling_fft_factor = ctx.scaling_fft_factor/ ((float) FFT_SIZE); + +//----------------------------------------------------------------------------- +// Do the work: distribute the work through the tasks +//----------------------------------------------------------------------------- + start_time = rtems_clock_get_ticks_since_boot(); + ctx.accxL2 = function_calc_filter_simulation(&ctx, 0, 1); + + uint32_t start_idx = 0; + for (uint32_t iter=0; iter<MAX_ITER; iter++, start_idx += FFT_SIZE) { + function_snr_read_sensor_data(start_idx, iter); + function_snr_process_data(&ctx, start_idx, iter) ; + } + + end_time = rtems_clock_get_ticks_since_boot(); + elapsed_time = end_time - start_time; + +#ifdef GR740_ESA_BOARD + soc_stats_update(&soc_stats); +#endif + +//----------------------------------------------------------------------------- +// Show Results +//----------------------------------------------------------------------------- + print_string("\n"); + print_string("Single Core Elapsed Time -"); + print_string(itoa(elapsed_time, &str[0], 10)); + print_string("\n"); + + for (uint8_t i = 0; i < ctx.ntiles; i++){ + if (count_process[i] != 1){ + correctly_processed = false; + break; + } + } + + if (correctly_processed){ + print_string("Each tile only processed once : true\n"); + } + else{ + print_string("Each tile only processed once : false\n"); + } + + print_string("Input Data Result Value : 0x"); + print_string(itoa(control_data_word , &str[0], 16)); + print_string("\n"); + + print_string("Ouput Data Result Value : 0x"); + if (ctx.accxL2>=UINT32_MAX) { + print_string(itoa( (int32_t) ((ctx.accxL2 >> 32U) & ((uint64_t)UINT32_MAX)) , &str[0], 16)); + print_string(itoa( (int32_t) (ctx.accxL2 & ((uint64_t)UINT32_MAX)) , &str[0], 16)); + } + else { + print_string(itoa((int32_t)ctx.accxL2 , &str[0], 16)); + } + print_string("\n"); + print_string("Time used in filter sim processing : "); + print_string(itoa( (int32_t) (ctx.filter_sim_process_time *1000) , &str[0], 10)); + print_string(" ms\n"); + + print_string("Time used in SNR processing : "); + print_string(itoa( (int32_t) (ctx.snr_process_time *1000) , &str[0], 10)); + print_string(" ms\n"); + + print_string("SNR triggers found at : "); + for (uint32_t j = 0; j < MAX_ITER; j++) + if (dsp_result[j] > 0.0){ + print_string(itoa(j, &str[0], 10)); + print_string(" "); + } + print_string("\n"); + + +#ifdef GR740_ESA_BOARD + print_string("L1 Instr Cache misses (read) CPU_0 : "); + print_string(itoa(soc_stats.l1_inst_cache_miss[0], &str[0], 10)); + print_string("\n"); + print_string("L1 Instr Cache misses (read) CPU_1 : "); + print_string(itoa(soc_stats.l1_inst_cache_miss[1], &str[0], 10)); + print_string("\n"); + print_string("L1 Instr Cache misses (read) CPU_2 : "); + print_string(itoa(soc_stats.l1_inst_cache_miss[2], &str[0], 10)); + print_string("\n"); + print_string("L1 Instr Cache misses (read) CPU_3 : "); + print_string(itoa(soc_stats.l1_inst_cache_miss[3], &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses (read) CPU_0 : "); + print_string(itoa(soc_stats.l1_data_cache_miss[0], &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses (read) CPU_1 : "); + print_string(itoa(soc_stats.l1_data_cache_miss[1], &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses (read) CPU_2 : "); + print_string(itoa(soc_stats.l1_data_cache_miss[2], &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses (read) CPU_3 : "); + print_string(itoa(soc_stats.l1_data_cache_miss[3], &str[0], 10)); + print_string("\n"); + print_string("L2 Cache hits (read + writes) : "); + print_string(itoa(soc_stats.l2_cache_hits, &str[0], 10)); + print_string("\n"); + print_string("L2 Cache misses (read + writes) : "); + print_string(itoa(soc_stats.l2_cache_miss, &str[0], 10)); + print_string("\n"); + print_string("AHB Splits : "); + print_string(itoa(soc_stats.ahb_split_delay, &str[0], 10)); + print_string("\n"); + print_string("\n"); +#endif + + +// -------------------------------------------------------------------------- +// Delete Objects and Finalize testcase +// -------------------------------------------------------------------------- + + rtems_fatal(RTEMS_FATAL_SOURCE_EXIT, 0); +} + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER + +#define CONFIGURE_MAXIMUM_PROCESSORS TEST_PROCESSORS + +#define CONFIGURE_MAXIMUM_TASKS TEST_PROCESSORS + +#define CONFIGURE_SCHEDULER_EDF_SMP + +#define CONFIGURE_MINIMUM_TASK_STACK_SIZE \ + RTEMS_MINIMUM_STACK_SIZE + CPU_STACK_ALIGNMENT + +#define CONFIGURE_EXTRA_TASK_STACKS RTEMS_MINIMUM_STACK_SIZE + +#define CONFIGURE_INIT_TASK_CONSTRUCT_STORAGE_SIZE 2 * TASK_STORAGE_SIZE + +#define CONFIGURE_MINIMUM_TASKS_WITH_USER_PROVIDED_STORAGE \ + CONFIGURE_MAXIMUM_TASKS + +#define CONFIGURE_MICROSECONDS_PER_TICK 1000 + +#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 0 + +#define CONFIGURE_DISABLE_NEWLIB_REENTRANCY + +#define CONFIGURE_APPLICATION_DISABLE_FILESYSTEM + +#define CONFIGURE_MAXIMUM_THREAD_LOCAL_STORAGE_SIZE MAX_TLS_SIZE + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT_TASK_ATTRIBUTES (RTEMS_SYSTEM_TASK | TASK_ATTRIBUTES) + +#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES + +#define CONFIGURE_INIT + +#include <rtems/confdefs.h> diff --git a/testsuites/isvv/23.8_multi_cache_repl_policy_l2_lru/multi_cache_repl_policy_l2_lru.c b/testsuites/isvv/23.8_multi_cache_repl_policy_l2_lru/multi_cache_repl_policy_l2_lru.c new file mode 100644 index 0000000000..c755516f63 --- /dev/null +++ b/testsuites/isvv/23.8_multi_cache_repl_policy_l2_lru/multi_cache_repl_policy_l2_lru.c @@ -0,0 +1,722 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 2022 Critical Software SA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stddef.h> +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <rtems/bspIo.h> +#include <string.h> +#include "../shared/utils.h" +#include "../shared/isvv_rtems_aux.h" +#include "../shared/low_level_utils.h" + +/** + * + * @brief Tests impact performing of L2 cache replacement policy + * + * Step 2: Multiprocessor with L2 cache replacement policy LRU + * + * There are two main set of math equations used here: + * - one named "filter_simulation" + * - and other named "snr_processing" + * + * The equations for "filter_simulation" are used by TWO tasks that processes small + * sections of a "data array" in parallel. + * The equations for "snr_processing" are used by TWO tasks that processes small + * sections of other "data array" in sequential order, but in parallel with the other + * tasks. + * + * The locations in memory for both "data arrays" do overlap in terms of cache memory + * positions, and when acessing one "data array", or part of one, other sections of + * the other "data array" should be kicked out of the cache. Sometimes that may + * also happen within the same "data array". + * + * Expected Results: + * - The Tiles must be processed only once. + * - "Ouput Data Result Value" must match with the Uniprocessor version. + * - SNR triggers index positions must match with the ones of the Uniprocessor + * version. + * - L2 cache misses should be significantly higher than the Uniprocessor version. + * + */ + +/** + * + * For standalone tests in the actual hardware boards the following options can be used: + * + * 1) use make XFLAGS="-Dgr740 -DGR740_ESA_BOARD" + * 2) declare #define GR740_ESA_BOARD at the beginning of this file + * + */ + +#define MAX_TLS_SIZE RTEMS_ALIGN_UP(64, RTEMS_TASK_STORAGE_ALIGNMENT) + +#define TASK_ATTRIBUTES RTEMS_FLOATING_POINT + +#define TASK_STORAGE_SIZE \ + RTEMS_TASK_STORAGE_SIZE( \ + MAX_TLS_SIZE + RTEMS_MINIMUM_STACK_SIZE, \ + TASK_ATTRIBUTES) + + +// test specific global vars +#define TASK_COUNT_FILTER (2U ) //2 parallel tasks for "filter simulation" +#define TASK_COUNT_SNR (2U) //2 sequential tasks for "snr processing" +#define TASK_COUNT (TASK_COUNT_FILTER+TASK_COUNT_SNR) + +#define TOTAL_TILES 128 +#define PERIOD_IN_TICKS 100 + +#define MAX_MESSAGE_QUEUES 6 +#define MAX_MESSAGE_SIZE sizeof(uint8_t) +#define MAX_PENDING_MESSAGES 10 + +const rtems_event_set event_send[6] = {RTEMS_EVENT_1, + RTEMS_EVENT_2, + RTEMS_EVENT_3, + RTEMS_EVENT_4, + RTEMS_EVENT_5, + RTEMS_EVENT_6 + }; + +#define EVENT_DATA_READY RTEMS_EVENT_10 +#define GO_READ_SENSOR RTEMS_EVENT_11 + +uint8_t count_process[TOTAL_TILES]; + +typedef struct{ + rtems_id main_task; + uint8_t ntiles; + uint8_t next_tile; + rtems_id task_filter_simulation_id[TASK_COUNT_FILTER]; + rtems_id task_snr_process_data_id; + rtems_id task_snr_read_sensor_data_id; + rtems_id tile_queue; + rtems_id message_queue[TASK_COUNT_FILTER]; + rtems_id filter_mutex_id; + float filter_sim_process_time; + uint64_t accxL2; + rtems_id snr_mutex_id; + float snr_process_time; + float scaling_fft_factor; +} test_context; + +RTEMS_ALIGNED(RTEMS_TASK_STORAGE_ALIGNMENT) +static char calc_task_storage[TASK_COUNT][TASK_STORAGE_SIZE]; + +RTEMS_MESSAGE_QUEUE_BUFFER(MAX_MESSAGE_SIZE) +msg_tile_queue_storage[MAX_PENDING_MESSAGES]; + +RTEMS_MESSAGE_QUEUE_BUFFER(MAX_MESSAGE_SIZE) +msg_task_queue_storage[TASK_COUNT_FILTER][MAX_PENDING_MESSAGES]; + +#define ITOA_STR_SIZE (8*sizeof(int)+1) + +//------------------------------------------------------------------------------- +#define L2_CACHE_SIZE (4U*512U*1024U) // 2M bytes +#define L2_CACHE_WAY_SIZE (512U*1024U) // 512k bytes +#define xL2_ELEM (4*L2_CACHE_SIZE/sizeof(uint32_t)) // 2M elements + +#ifdef GR740_ESA_BOARD +RTEMS_ALIGNED(L2_CACHE_SIZE) +#endif +static uint32_t xL2[xL2_ELEM]; + +#define COEFS_SIZE (128U) +const uint32_t coefs[COEFS_SIZE] = + { 29, 31, 37, 41, 43, 47, 53, 59, + 61, 67, 71, 73, 79, 83, 89, 97, + 101, 103, 107, 109, 113, 127, 131, 137, + 139, 149, 151, 157, 163, 167, 173, 179, + 181, 191, 193, 197, 199, 211, 223, 227, + 229, 233, 239, 241, 251, 257, 263, 269, + 271, 277, 281, 283, 293, 307, 311, 313, + 317, 331, 337, 347, 349, 353, 359, 367, + 373, 379, 383, 389, 397, 401, 409, 419, + 421, 431, 433, 439, 443, 449, 457, 461, + 463, 467, 479, 487, 491, 499, 503, 509, + 521, 523, 541, 547, 557, 563, 569, 571, + 577, 587, 593, 599, 601, 607, 613, 617, + 619, 631, 641, 643, 647, 653, 659, 661, + 673, 677, 683, 691, 701, 709, 719, 727, + 733, 739, 743, 751, 757, 761, 769, 773}; + +//------------------------------------------------------------------------------- +#define SENSOR_DATA_ELEM (6*L2_CACHE_WAY_SIZE/sizeof(uint32_t)) +#define MAX_ITER (SENSOR_DATA_ELEM / FFT_SIZE) +#define FFT_SIZE (8192U) +#define FFT_SIZE_LOG2 (13U) +#define TC_MAX (16U) +#define FILTER_TAPS (64U) +#define SNR_THRESHOLD (1000000.0f) +const uint16_t FS = 48000U; +const uint16_t FREQ[TC_MAX] = { 2500U, 1500U, 15000U, 500U, + 1000U, 800U, 440U, 8000U, + 100U, 3500U, 12345U, 1200U, + 20000U, 715U, 5000U, 4500U }; +const float NOISE_FACTOR[TC_MAX] = { 0.0001f, 0.2250f, 0.00068f, 0.30f, + 0.004f, 0.0123f, 0.0054f, 0.00054f, + 0.01f, 0.0325f, 0.012f, 0.00032f, + 0.075f, 0.0423f, 0.0354f, 0.00002f }; +#ifdef GR740_ESA_BOARD +RTEMS_ALIGNED(L2_CACHE_WAY_SIZE) +#endif +static float inSensorDataRe[SENSOR_DATA_ELEM]; + +#ifdef GR740_ESA_BOARD +RTEMS_ALIGNED(L2_CACHE_WAY_SIZE) +#endif +static float inSensorDataIm[SENSOR_DATA_ELEM]; +static uint8_t dsp_result[MAX_ITER]; + + +//======================================================================================= +// Auxiliary Functions +//======================================================================================= +static void fill_main_memory_with_data(void){ + // Store to memory + for ( uint32_t j = 0 ; j < xL2_ELEM; j ++) + xL2[j] = j; +} + +static uint64_t warmup_caches(void){ + uint64_t acc = 0; + for ( uint32_t j = 0 ; j < xL2_ELEM; j++) + acc += xL2[j]; + return acc; +} + + +//======================================================================================= +// "filter_simulation" Tasks/Functions +//======================================================================================= +static uint64_t calc_filter_simulation_equation(uint8_t tile, uint32_t total_elems) { + uint64_t acc = 0; + const uint32_t begin_idx = tile*xL2_ELEM/total_elems; + const uint32_t end_idx = begin_idx + (xL2_ELEM/total_elems) - 1; + + for ( uint32_t j = begin_idx ; j <= end_idx; j++ ) { + uint32_t i; + + // Simulating filtering/convolution + uint32_t t1 = 0, t2 = 0, t3 = 0, t4 = 0; + for (i = 0 ; i < FILTER_TAPS; i++) + t1 += xL2[(j+i) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < FILTER_TAPS; i++) + t1 += xL2[(j+i+L2_CACHE_WAY_SIZE*1/2/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < FILTER_TAPS; i++) + t1 += xL2[(j+i+L2_CACHE_WAY_SIZE*2/2/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < FILTER_TAPS; i++) + t1 += xL2[(j+i+L2_CACHE_WAY_SIZE*3/2/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < FILTER_TAPS; i++) + t1 += xL2[(j+i+L2_CACHE_WAY_SIZE*4/2/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < FILTER_TAPS; i++) + t1 += xL2[(j+i+L2_CACHE_WAY_SIZE*5/2/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < FILTER_TAPS; i++) + t1 += xL2[(j+i+L2_CACHE_WAY_SIZE*6/2/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < FILTER_TAPS; i++) + t1 += xL2[(j+i+L2_CACHE_WAY_SIZE*7/2/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + // Simulating normalization + t3 = ((t1*1000)/(42*137)) + 1; + t4 = ((t2*10)/(96*137)) + 1; + uint64_t t5 = (uint64_t)t3 * (uint64_t)t3; + uint64_t t6 = (uint64_t)t4 * (uint64_t)t4; + acc += (t5+t6)/((uint64_t)isqrt(t4+t3)); + } + return acc; +} + + +static void calc_task_function(rtems_task_argument arg){ + test_context *ctx; + uint64_t acc; + rtems_id calc_task_period; + struct timespec begin_time; + struct timespec end_time; + uint8_t tile = 0; + uint8_t task_idx = 255; + + ctx = (test_context *)arg; + rtems_id local_id = TaskSelfId(); + + for (uint32_t i = 0; i < TASK_COUNT; i++){ + if (ctx->task_filter_simulation_id[i] == local_id){ + task_idx = i; + break; + } + } + + char ch = '0' + task_idx; + + rtems_message_queue_config msg_config = { + .name = rtems_build_name('M', 'S', 'G', ch), + .maximum_pending_messages = MAX_PENDING_MESSAGES, + .maximum_message_size = MAX_MESSAGE_SIZE, + .storage_size = sizeof(msg_task_queue_storage[task_idx]), + .storage_area = &msg_task_queue_storage[task_idx], + .attributes = RTEMS_FIFO | RTEMS_GLOBAL}; + + ctx->message_queue[task_idx] = CreateMessageQueue(msg_config); + calc_task_period = CreateRateMonotonic(); + + SendMessage(ctx->tile_queue, &task_idx, sizeof(task_idx)); + ReceiveMessage(ctx->message_queue[task_idx], &tile); + + while (tile <= ctx->ntiles) { + +#ifdef GR740_ESA_BOARD + WaitPeriod(calc_task_period, 8*PERIOD_IN_TICKS); +#endif + + count_process[tile - 1]++; + rtems_clock_get_uptime(&begin_time); + acc = calc_filter_simulation_equation(tile-1, ctx->ntiles); + rtems_clock_get_uptime(&end_time); + + ObtainMutex(ctx->filter_mutex_id); + ctx->filter_sim_process_time += (float)(end_time.tv_sec - begin_time.tv_sec) + + ( (float)(end_time.tv_nsec/1000 - begin_time.tv_nsec/1000)/1000000.0); + ctx->accxL2 += acc; + ReleaseMutex(ctx->filter_mutex_id); + + SendMessage(ctx->tile_queue, &task_idx, sizeof(task_idx)); + ReceiveMessage(ctx->message_queue[task_idx], &tile); + } + + SendMessage(ctx->tile_queue, &task_idx, sizeof(task_idx)); + SendEvents(ctx->main_task, event_send[task_idx]); + DeleteRateMonotonic(calc_task_period); + SuspendSelf(); +} + +//======================================================================================= +// "snr_processing" Tasks/Functions +//======================================================================================= +static void task_snr_read_sensor_data(rtems_task_argument arg){ + test_context *ctx; + rtems_id read_sensor_data_period; + uint32_t start_idx = 0; + uint32_t iter = 0; + + ctx = (test_context *)arg; + + ReceiveAllEvents(GO_READ_SENSOR); + read_sensor_data_period = CreateRateMonotonic(); + + while ( start_idx < SENSOR_DATA_ELEM) { + +#ifdef GR740_ESA_BOARD + WaitPeriod(read_sensor_data_period, 5*PERIOD_IN_TICKS); +#endif + + ObtainMutex(ctx->snr_mutex_id); + + for (uint32_t i = 0; i < FFT_SIZE; i++) { + inSensorDataRe[start_idx + i] = 0.4995f * cos_aprox(i*2.0f*PI*FREQ[iter%TC_MAX]/FS) + + (noise_generator(0) * NOISE_FACTOR[iter%TC_MAX]); + inSensorDataIm[start_idx + i] = 0.4995f * sin_aprox(i*2.0f*PI*FREQ[iter%TC_MAX]/FS) + + (noise_generator(0) * NOISE_FACTOR[iter % TC_MAX]); + } + + ReleaseMutex(ctx->snr_mutex_id); + SendEvents(ctx->task_snr_process_data_id, EVENT_DATA_READY); + + start_idx += FFT_SIZE; + iter++; + + } + + rtems_event_send(ctx->main_task, event_send[(TASK_COUNT-2)]); + DeleteRateMonotonic(read_sensor_data_period); + SuspendSelf(); +} + +static void task_snr_process_data(rtems_task_argument arg) { + test_context *ctx; + ctx = (test_context *)arg; + uint32_t start_idx = 0; + uint32_t iter = 0; + struct timespec begin_time; + struct timespec end_time; + + while ( start_idx < SENSOR_DATA_ELEM ) { + ReceiveAllEvents(EVENT_DATA_READY); + ObtainMutex(ctx->snr_mutex_id); + rtems_clock_get_uptime(&begin_time); + + //Apply Blackman-Harris Window + for (uint32_t i = 0; i < FFT_SIZE; i++) { + inSensorDataRe[i] = inSensorDataRe[start_idx+i]*blackman_harris(i, FFT_SIZE)/ctx->scaling_fft_factor; + inSensorDataIm[i] = inSensorDataIm[start_idx+i]*blackman_harris(i, FFT_SIZE)/ctx->scaling_fft_factor; + } + + //Calculates FFT + fft(&inSensorDataRe[0], &inSensorDataIm[0], FFT_SIZE_LOG2); + + //Calculates the magnitude values + for (uint32_t i = 0; i < FFT_SIZE; i++) { + inSensorDataRe[i] = (inSensorDataRe[i] * inSensorDataRe[i] + + inSensorDataIm[i] * inSensorDataIm[i]) / ((float)FFT_SIZE); + } + + //Look for the peak Value and its index (no DC) + float maxValue = 0.0; + float maxValueIndex = -1; + for (uint32_t i = 3; i < (FFT_SIZE / 2); i++) { + if (inSensorDataRe[i] > maxValue) { + maxValue = inSensorDataRe[i]; + maxValueIndex = i; + } + } + + //Calculates the signal and noise power (no DC) + float sig = 0.0f; + float noise = 0.0f; + for (uint32_t i = 3; i < (FFT_SIZE / 2); i++) { + if ((i > maxValueIndex - 4) && (i < maxValueIndex + 4)) { + sig += (2 * inSensorDataRe[i]); + } + else { + noise += (2 * inSensorDataRe[i]); + } + } + + if (!(sig > 0.0f)) { sig = 0.0000000001f; } + if (!(noise > 0.0f)) { noise = 0.0000000001f; } + + //Calculates SNR + float snr_float = sig/noise; + + if (snr_float > SNR_THRESHOLD) { + dsp_result[iter] = 1; + } + else { + dsp_result[iter] = 0; + } + rtems_clock_get_uptime(&end_time); + + ctx->snr_process_time += + (float)(end_time.tv_sec - begin_time.tv_sec) + + ( (float)((end_time.tv_nsec/1000) - (begin_time.tv_nsec/1000))/1000000.0); + + ReleaseMutex(ctx->snr_mutex_id); + start_idx += FFT_SIZE; + iter++; + } + + rtems_event_send(ctx->main_task, event_send[(TASK_COUNT-1)]); + SuspendSelf(); +} + + +//======================================================================================= +// INIT/MAIN Task +//======================================================================================= +static void Init(rtems_task_argument arg){ + (void)arg; + test_context ctx; + uint32_t start_time, end_time, elapsed_time; + char ch, str[ITOA_STR_SIZE]; + uint32_t total_events = 0; + uint8_t task = 255; + bool correctly_processed = true; + (void) memset(&ctx, 0, sizeof(test_context)); + (void) memset(&count_process[0], 0, TOTAL_TILES); + (void) memset(&xL2[0], 0, xL2_ELEM); + (void) memset(&inSensorDataRe[0], 0, SENSOR_DATA_ELEM); + (void) memset(&inSensorDataIm[0], 0, SENSOR_DATA_ELEM); + +#ifdef GR740_ESA_BOARD + soc_stats_regs soc_stats; +#endif + +//----------------------------------------------------------------------------- +// Create/Initialize Objects +//----------------------------------------------------------------------------- + rtems_message_queue_config msg_config = { + .name = rtems_build_name('M', 'S', 'G', 'T'), + .maximum_pending_messages = RTEMS_ARRAY_SIZE(msg_tile_queue_storage), + .maximum_message_size = MAX_MESSAGE_SIZE, + .storage_size = sizeof(msg_tile_queue_storage), + .storage_area = &msg_tile_queue_storage, + .attributes = RTEMS_FIFO | RTEMS_GLOBAL}; + + ctx.main_task = rtems_task_self(); + ctx.tile_queue = CreateMessageQueue(msg_config); + ctx.ntiles = TOTAL_TILES; + ctx.next_tile = 1; + + rtems_task_config calc_task_config = { + .initial_priority = PRIO_NORMAL, + .storage_size = TASK_STORAGE_SIZE, + .maximum_thread_local_storage_size = MAX_TLS_SIZE, + .initial_modes = RTEMS_DEFAULT_MODES, + .attributes = TASK_ATTRIBUTES}; + + ctx.filter_mutex_id = CreateMutex(rtems_build_name('M', 'U', 'T', '0')); + ctx.snr_mutex_id = CreateMutex(rtems_build_name('M', 'U', 'T', '1')); + SetSelfPriority( PRIO_NORMAL ); + + for (uint32_t i = 0; i < TASK_COUNT-2; i++){ + ch = '0' + i; + calc_task_config.name = rtems_build_name('R', 'U', 'N', ch); + calc_task_config.storage_area = &calc_task_storage[i][0]; + + ctx.task_filter_simulation_id[i] = DoCreateTask(calc_task_config); + StartTask(ctx.task_filter_simulation_id[i], calc_task_function, &ctx); + total_events += event_send[i]; + } + + ch = '0' + (TASK_COUNT-2); + calc_task_config.name = rtems_build_name('R', 'U', 'N', ch); + calc_task_config.storage_area = &calc_task_storage[(TASK_COUNT-2)][0]; + ctx.task_snr_read_sensor_data_id = DoCreateTask(calc_task_config); + StartTask(ctx.task_snr_read_sensor_data_id, task_snr_read_sensor_data, &ctx); + + ch = '0' + (TASK_COUNT-1); + calc_task_config.name = rtems_build_name('R', 'U', 'N', ch); + calc_task_config.storage_area = &calc_task_storage[(TASK_COUNT-1)][0]; + ctx.task_snr_process_data_id = DoCreateTask(calc_task_config); + StartTask(ctx.task_snr_process_data_id, task_snr_process_data, &ctx); + +//----------------------------------------------------------------------------- +// Setup the testcase +//----------------------------------------------------------------------------- + fill_main_memory_with_data(); + l1_dcache_flush(); + l1_dcache_disable(); + +#ifdef GR740_ESA_BOARD + l2_cache_disable(); + l2_cache_flush(); + l2_cache_set_replacement_policy(L2_CACHE_REPL_LRU, 0); + l2_cache_enable(); +#endif + + l1_dcache_enable(); + uint32_t control_data_word = warmup_caches(); + +#ifdef GR740_ESA_BOARD + clockgating_enable_l4stat(); + soc_stats_configure_regs(); + soc_stats_init(&soc_stats); +#endif + + //Calculates mean of Blackman-Harris terms + ctx.scaling_fft_factor = 0.0; + for (uint32_t i = 0; i<FFT_SIZE; i++){ + ctx.scaling_fft_factor += blackman_harris( i, FFT_SIZE); + } + ctx.scaling_fft_factor = ctx.scaling_fft_factor/ ((float) FFT_SIZE); + +//----------------------------------------------------------------------------- +// Do the work: distribute the work through the tasks +//----------------------------------------------------------------------------- + SendEvents(ctx.task_snr_read_sensor_data_id, GO_READ_SENSOR); + start_time = rtems_clock_get_ticks_since_boot(); + + rtems_event_set revents = ReceiveAvailableEvents(); + while ( (revents & total_events) != total_events ) { + ReceiveMessage(ctx.tile_queue, &task); + SendMessage(ctx.message_queue[task], &ctx.next_tile, sizeof(ctx.next_tile)); + ctx.next_tile++; + revents = ReceiveAvailableEvents(); + + } + // Wait for the SNR processing tasks to finish + ReceiveAllEvents(event_send[(TASK_COUNT-2)]); + ReceiveAllEvents(event_send[(TASK_COUNT-1)]); + + end_time = rtems_clock_get_ticks_since_boot(); + elapsed_time = end_time - start_time; + +#ifdef GR740_ESA_BOARD + soc_stats_update(&soc_stats); +#endif + +//----------------------------------------------------------------------------- +// Show Results +//----------------------------------------------------------------------------- + print_string("\n"); + print_string("Multicore Elapsed Time -"); + print_string(itoa(elapsed_time, &str[0], 10)); + print_string("\n"); + + for (uint8_t i = 0; i < ctx.ntiles; i++){ + if (count_process[i] != 1){ + correctly_processed = false; + break; + } + } + + if (correctly_processed){ + print_string("Each tile only processed once : true\n"); + } + else{ + print_string("Each tile only processed once : false\n"); + } + + print_string("Input Data Result Value : 0x"); + print_string(itoa(control_data_word , &str[0], 16)); + print_string("\n"); + + print_string("Ouput Data Result Value : 0x"); + if (ctx.accxL2>=UINT32_MAX) { + print_string(itoa( (int32_t) ((ctx.accxL2 >> 32U) & ((uint64_t)UINT32_MAX)) , &str[0], 16)); + print_string(itoa( (int32_t) (ctx.accxL2 & ((uint64_t)UINT32_MAX)) , &str[0], 16)); + } + else { + print_string(itoa((int32_t)ctx.accxL2 , &str[0], 16)); + } + print_string("\n"); + print_string("Time used in filter sim processing : "); + print_string(itoa( (int32_t) (ctx.filter_sim_process_time *1000) , &str[0], 10)); + print_string(" ms\n"); + + print_string("Time used in SNR processing : "); + print_string(itoa( (int32_t) (ctx.snr_process_time *1000) , &str[0], 10)); + print_string(" ms\n"); + + print_string("SNR triggers found at : "); + for (uint32_t j = 0; j < MAX_ITER; j++) + if (dsp_result[j] > 0.0){ + print_string(itoa(j, &str[0], 10)); + print_string(" "); + } + print_string("\n"); + + +#ifdef GR740_ESA_BOARD + print_string("L1 Instr Cache misses (read) CPU_0 : "); + print_string(itoa(soc_stats.l1_inst_cache_miss[0], &str[0], 10)); + print_string("\n"); + print_string("L1 Instr Cache misses (read) CPU_1 : "); + print_string(itoa(soc_stats.l1_inst_cache_miss[1], &str[0], 10)); + print_string("\n"); + print_string("L1 Instr Cache misses (read) CPU_2 : "); + print_string(itoa(soc_stats.l1_inst_cache_miss[2], &str[0], 10)); + print_string("\n"); + print_string("L1 Instr Cache misses (read) CPU_3 : "); + print_string(itoa(soc_stats.l1_inst_cache_miss[3], &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses (read) CPU_0 : "); + print_string(itoa(soc_stats.l1_data_cache_miss[0], &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses (read) CPU_1 : "); + print_string(itoa(soc_stats.l1_data_cache_miss[1], &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses (read) CPU_2 : "); + print_string(itoa(soc_stats.l1_data_cache_miss[2], &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses (read) CPU_3 : "); + print_string(itoa(soc_stats.l1_data_cache_miss[3], &str[0], 10)); + print_string("\n"); + print_string("L2 Cache hits (read + writes) : "); + print_string(itoa(soc_stats.l2_cache_hits, &str[0], 10)); + print_string("\n"); + print_string("L2 Cache misses (read + writes) : "); + print_string(itoa(soc_stats.l2_cache_miss, &str[0], 10)); + print_string("\n"); + print_string("AHB Splits : "); + print_string(itoa(soc_stats.ahb_split_delay, &str[0], 10)); + print_string("\n"); + print_string("\n"); +#endif + + +// -------------------------------------------------------------------------- +// Delete Objects and Finalize testcase +// -------------------------------------------------------------------------- + for (uint32_t i = 0; i < (TASK_COUNT-2); i++){ + DeleteTask(ctx.task_filter_simulation_id[i]); + DeleteMessageQueue(ctx.message_queue[i]); + } + + DeleteTask(ctx.task_snr_process_data_id); + DeleteTask(ctx.task_snr_read_sensor_data_id); + + DeleteMutex(ctx.filter_mutex_id); + DeleteMutex(ctx.snr_mutex_id); + + DeleteMessageQueue(ctx.tile_queue); + rtems_fatal(RTEMS_FATAL_SOURCE_EXIT, 0); +} + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER + +#define CONFIGURE_MAXIMUM_PROCESSORS TEST_PROCESSORS + +#define CONFIGURE_MAXIMUM_MESSAGE_QUEUES MAX_MESSAGE_QUEUES + +#define CONFIGURE_MAXIMUM_SEMAPHORES 2 + +#define CONFIGURE_MAXIMUM_PERIODS 3 + +#define CONFIGURE_MAXIMUM_TASKS ( TASK_COUNT + 1 ) + +#define CONFIGURE_SCHEDULER_EDF_SMP + +#define CONFIGURE_MINIMUM_TASK_STACK_SIZE \ + RTEMS_MINIMUM_STACK_SIZE + CPU_STACK_ALIGNMENT + +#define CONFIGURE_EXTRA_TASK_STACKS RTEMS_MINIMUM_STACK_SIZE + +#define CONFIGURE_INIT_TASK_CONSTRUCT_STORAGE_SIZE 2 * TASK_STORAGE_SIZE + +#define CONFIGURE_MINIMUM_TASKS_WITH_USER_PROVIDED_STORAGE \ + CONFIGURE_MAXIMUM_TASKS + +#define CONFIGURE_MICROSECONDS_PER_TICK 1000 + +#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 0 + +#define CONFIGURE_DISABLE_NEWLIB_REENTRANCY + +#define CONFIGURE_APPLICATION_DISABLE_FILESYSTEM + +#define CONFIGURE_MAXIMUM_THREAD_LOCAL_STORAGE_SIZE MAX_TLS_SIZE + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT_TASK_ATTRIBUTES (RTEMS_SYSTEM_TASK | TASK_ATTRIBUTES) + +#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES + +#define CONFIGURE_INIT + +#include <rtems/confdefs.h> diff --git a/testsuites/isvv/23.9_multi_cache_repl_policy_l2_random/multi_cache_repl_policy_l2_random.c b/testsuites/isvv/23.9_multi_cache_repl_policy_l2_random/multi_cache_repl_policy_l2_random.c new file mode 100644 index 0000000000..62a8f1e822 --- /dev/null +++ b/testsuites/isvv/23.9_multi_cache_repl_policy_l2_random/multi_cache_repl_policy_l2_random.c @@ -0,0 +1,725 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 2022 Critical Software SA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stddef.h> +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <rtems/bspIo.h> +#include <string.h> +#include "../shared/utils.h" +#include "../shared/isvv_rtems_aux.h" +#include "../shared/low_level_utils.h" + +/** + * + * @brief Tests impact performing of L2 cache replacement policy + * + * Step 2: Multiprocessor with L2 cache replacement policy Pseudo-Random + * + * There are two main set of math equations used here: + * - one named "filter_simulation" + * - and other named "snr_processing" + * + * The equations for "filter_simulation" are used by TWO tasks that processes small + * sections of a "data array" in parallel. + * The equations for "snr_processing" are used by TWO tasks that processes small + * sections of other "data array" in sequential order, but in parallel with the other + * tasks. + * + * The locations in memory for both "data arrays" do overlap in terms of cache memory + * positions, and when acessing one "data array", or part of one, other sections of + * the other "data array" should be kicked out of the cache. Sometimes that may + * also happen within the same "data array". + * + * Expected Results: + * - The Tiles must be processed only once. + * - "Ouput Data Result Value" must match with the Multiprocessor with + * L2 cache replacement policy LRU version and Uniprocessor version. + * - SNR triggers index positions must match with the ones from the Multiprocessor with + * L2 cache replacement policy LRU version and with the ones from the Uniprocessor + * version. + * - L2 cache misses should be significantly higher than the Multiprocessor with L2 + * cache replacement policy LRU version. + * + */ + +/** + * + * For standalone tests in the actual hardware boards the following options can be used: + * + * 1) use make XFLAGS="-Dgr740 -DGR740_ESA_BOARD" + * 2) declare #define GR740_ESA_BOARD at the beginning of this file + * + */ + +#define MAX_TLS_SIZE RTEMS_ALIGN_UP(64, RTEMS_TASK_STORAGE_ALIGNMENT) + +#define TASK_ATTRIBUTES RTEMS_FLOATING_POINT + +#define TASK_STORAGE_SIZE \ + RTEMS_TASK_STORAGE_SIZE( \ + MAX_TLS_SIZE + RTEMS_MINIMUM_STACK_SIZE, \ + TASK_ATTRIBUTES) + + +// test specific global vars +#define TASK_COUNT_FILTER (2U ) //2 parallel tasks for "filter simulation" +#define TASK_COUNT_SNR (2U) //2 sequential tasks for "snr processing" +#define TASK_COUNT (TASK_COUNT_FILTER+TASK_COUNT_SNR) + +#define TOTAL_TILES 128 +#define PERIOD_IN_TICKS 100 + +#define MAX_MESSAGE_QUEUES 6 +#define MAX_MESSAGE_SIZE sizeof(uint8_t) +#define MAX_PENDING_MESSAGES 10 + +const rtems_event_set event_send[6] = {RTEMS_EVENT_1, + RTEMS_EVENT_2, + RTEMS_EVENT_3, + RTEMS_EVENT_4, + RTEMS_EVENT_5, + RTEMS_EVENT_6 + }; + +#define EVENT_DATA_READY RTEMS_EVENT_10 +#define GO_READ_SENSOR RTEMS_EVENT_11 + +uint8_t count_process[TOTAL_TILES]; + +typedef struct{ + rtems_id main_task; + uint8_t ntiles; + uint8_t next_tile; + rtems_id task_filter_simulation_id[TASK_COUNT_FILTER]; + rtems_id task_snr_process_data_id; + rtems_id task_snr_read_sensor_data_id; + rtems_id tile_queue; + rtems_id message_queue[TASK_COUNT_FILTER]; + rtems_id filter_mutex_id; + float filter_sim_process_time; + uint64_t accxL2; + rtems_id snr_mutex_id; + float snr_process_time; + float scaling_fft_factor; +} test_context; + +RTEMS_ALIGNED(RTEMS_TASK_STORAGE_ALIGNMENT) +static char calc_task_storage[TASK_COUNT][TASK_STORAGE_SIZE]; + +RTEMS_MESSAGE_QUEUE_BUFFER(MAX_MESSAGE_SIZE) +msg_tile_queue_storage[MAX_PENDING_MESSAGES]; + +RTEMS_MESSAGE_QUEUE_BUFFER(MAX_MESSAGE_SIZE) +msg_task_queue_storage[TASK_COUNT_FILTER][MAX_PENDING_MESSAGES]; + +#define ITOA_STR_SIZE (8*sizeof(int)+1) + +//------------------------------------------------------------------------------- +#define L2_CACHE_SIZE (4U*512U*1024U) // 2M bytes +#define L2_CACHE_WAY_SIZE (512U*1024U) // 512k bytes +#define xL2_ELEM (4*L2_CACHE_SIZE/sizeof(uint32_t)) // 2M elements + +#ifdef GR740_ESA_BOARD +RTEMS_ALIGNED(L2_CACHE_SIZE) +#endif +static uint32_t xL2[xL2_ELEM]; + +#define COEFS_SIZE (128U) +const uint32_t coefs[COEFS_SIZE] = + { 29, 31, 37, 41, 43, 47, 53, 59, + 61, 67, 71, 73, 79, 83, 89, 97, + 101, 103, 107, 109, 113, 127, 131, 137, + 139, 149, 151, 157, 163, 167, 173, 179, + 181, 191, 193, 197, 199, 211, 223, 227, + 229, 233, 239, 241, 251, 257, 263, 269, + 271, 277, 281, 283, 293, 307, 311, 313, + 317, 331, 337, 347, 349, 353, 359, 367, + 373, 379, 383, 389, 397, 401, 409, 419, + 421, 431, 433, 439, 443, 449, 457, 461, + 463, 467, 479, 487, 491, 499, 503, 509, + 521, 523, 541, 547, 557, 563, 569, 571, + 577, 587, 593, 599, 601, 607, 613, 617, + 619, 631, 641, 643, 647, 653, 659, 661, + 673, 677, 683, 691, 701, 709, 719, 727, + 733, 739, 743, 751, 757, 761, 769, 773}; + +//------------------------------------------------------------------------------- +#define SENSOR_DATA_ELEM (6*L2_CACHE_WAY_SIZE/sizeof(uint32_t)) +#define MAX_ITER (SENSOR_DATA_ELEM / FFT_SIZE) +#define FFT_SIZE (8192U) +#define FFT_SIZE_LOG2 (13U) +#define TC_MAX (16U) +#define FILTER_TAPS (64U) +#define SNR_THRESHOLD (1000000.0f) +const uint16_t FS = 48000U; +const uint16_t FREQ[TC_MAX] = { 2500U, 1500U, 15000U, 500U, + 1000U, 800U, 440U, 8000U, + 100U, 3500U, 12345U, 1200U, + 20000U, 715U, 5000U, 4500U }; +const float NOISE_FACTOR[TC_MAX] = { 0.0001f, 0.2250f, 0.00068f, 0.30f, + 0.004f, 0.0123f, 0.0054f, 0.00054f, + 0.01f, 0.0325f, 0.012f, 0.00032f, + 0.075f, 0.0423f, 0.0354f, 0.00002f }; +#ifdef GR740_ESA_BOARD +RTEMS_ALIGNED(L2_CACHE_WAY_SIZE) +#endif +static float inSensorDataRe[SENSOR_DATA_ELEM]; + +#ifdef GR740_ESA_BOARD +RTEMS_ALIGNED(L2_CACHE_WAY_SIZE) +#endif +static float inSensorDataIm[SENSOR_DATA_ELEM]; +static uint8_t dsp_result[MAX_ITER]; + + +//======================================================================================= +// Auxiliary Functions +//======================================================================================= +static void fill_main_memory_with_data(void){ + // Store to memory + for ( uint32_t j = 0 ; j < xL2_ELEM; j ++) + xL2[j] = j; +} + +static uint64_t warmup_caches(void){ + uint64_t acc = 0; + for ( uint32_t j = 0 ; j < xL2_ELEM; j++) + acc += xL2[j]; + return acc; +} + + +//======================================================================================= +// "filter_simulation" Tasks/Functions +//======================================================================================= +static uint64_t calc_filter_simulation_equation(uint8_t tile, uint32_t total_elems) { + uint64_t acc = 0; + const uint32_t begin_idx = tile*xL2_ELEM/total_elems; + const uint32_t end_idx = begin_idx + (xL2_ELEM/total_elems) - 1; + + for ( uint32_t j = begin_idx ; j <= end_idx; j++ ) { + uint32_t i; + + // Simulating filtering/convolution + uint32_t t1 = 0, t2 = 0, t3 = 0, t4 = 0; + for (i = 0 ; i < FILTER_TAPS; i++) + t1 += xL2[(j+i) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < FILTER_TAPS; i++) + t1 += xL2[(j+i+L2_CACHE_WAY_SIZE*1/2/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < FILTER_TAPS; i++) + t1 += xL2[(j+i+L2_CACHE_WAY_SIZE*2/2/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < FILTER_TAPS; i++) + t1 += xL2[(j+i+L2_CACHE_WAY_SIZE*3/2/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < FILTER_TAPS; i++) + t1 += xL2[(j+i+L2_CACHE_WAY_SIZE*4/2/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < FILTER_TAPS; i++) + t1 += xL2[(j+i+L2_CACHE_WAY_SIZE*5/2/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < FILTER_TAPS; i++) + t1 += xL2[(j+i+L2_CACHE_WAY_SIZE*6/2/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + for (i = 0 ; i < FILTER_TAPS; i++) + t1 += xL2[(j+i+L2_CACHE_WAY_SIZE*7/2/sizeof(uint32_t)) % xL2_ELEM]*coefs[i]; + + // Simulating normalization + t3 = ((t1*1000)/(42*137)) + 1; + t4 = ((t2*10)/(96*137)) + 1; + uint64_t t5 = (uint64_t)t3 * (uint64_t)t3; + uint64_t t6 = (uint64_t)t4 * (uint64_t)t4; + acc += (t5+t6)/((uint64_t)isqrt(t4+t3)); + } + return acc; +} + + +static void calc_task_function(rtems_task_argument arg){ + test_context *ctx; + uint64_t acc; + rtems_id calc_task_period; + struct timespec begin_time; + struct timespec end_time; + uint8_t tile = 0; + uint8_t task_idx = 255; + + ctx = (test_context *)arg; + rtems_id local_id = TaskSelfId(); + + for (uint32_t i = 0; i < TASK_COUNT; i++){ + if (ctx->task_filter_simulation_id[i] == local_id){ + task_idx = i; + break; + } + } + + char ch = '0' + task_idx; + + rtems_message_queue_config msg_config = { + .name = rtems_build_name('M', 'S', 'G', ch), + .maximum_pending_messages = MAX_PENDING_MESSAGES, + .maximum_message_size = MAX_MESSAGE_SIZE, + .storage_size = sizeof(msg_task_queue_storage[task_idx]), + .storage_area = &msg_task_queue_storage[task_idx], + .attributes = RTEMS_FIFO | RTEMS_GLOBAL}; + + ctx->message_queue[task_idx] = CreateMessageQueue(msg_config); + calc_task_period = CreateRateMonotonic(); + + SendMessage(ctx->tile_queue, &task_idx, sizeof(task_idx)); + ReceiveMessage(ctx->message_queue[task_idx], &tile); + + while (tile <= ctx->ntiles) { + +#ifdef GR740_ESA_BOARD + WaitPeriod(calc_task_period, 8*PERIOD_IN_TICKS); +#endif + + count_process[tile - 1]++; + rtems_clock_get_uptime(&begin_time); + acc = calc_filter_simulation_equation(tile-1, ctx->ntiles); + rtems_clock_get_uptime(&end_time); + + ObtainMutex(ctx->filter_mutex_id); + ctx->filter_sim_process_time += (float)(end_time.tv_sec - begin_time.tv_sec) + + ( (float)(end_time.tv_nsec/1000 - begin_time.tv_nsec/1000)/1000000.0); + ctx->accxL2 += acc; + ReleaseMutex(ctx->filter_mutex_id); + + SendMessage(ctx->tile_queue, &task_idx, sizeof(task_idx)); + ReceiveMessage(ctx->message_queue[task_idx], &tile); + } + + SendMessage(ctx->tile_queue, &task_idx, sizeof(task_idx)); + SendEvents(ctx->main_task, event_send[task_idx]); + DeleteRateMonotonic(calc_task_period); + SuspendSelf(); +} + +//======================================================================================= +// "snr_processing" Tasks/Functions +//======================================================================================= +static void task_snr_read_sensor_data(rtems_task_argument arg){ + test_context *ctx; + rtems_id read_sensor_data_period; + uint32_t start_idx = 0; + uint32_t iter = 0; + + ctx = (test_context *)arg; + + ReceiveAllEvents(GO_READ_SENSOR); + read_sensor_data_period = CreateRateMonotonic(); + + while ( start_idx < SENSOR_DATA_ELEM) { + +#ifdef GR740_ESA_BOARD + WaitPeriod(read_sensor_data_period, 5*PERIOD_IN_TICKS); +#endif + + ObtainMutex(ctx->snr_mutex_id); + + for (uint32_t i = 0; i < FFT_SIZE; i++) { + inSensorDataRe[start_idx + i] = 0.4995f * cos_aprox(i*2.0f*PI*FREQ[iter%TC_MAX]/FS) + + (noise_generator(0) * NOISE_FACTOR[iter%TC_MAX]); + inSensorDataIm[start_idx + i] = 0.4995f * sin_aprox(i*2.0f*PI*FREQ[iter%TC_MAX]/FS) + + (noise_generator(0) * NOISE_FACTOR[iter % TC_MAX]); + } + + ReleaseMutex(ctx->snr_mutex_id); + SendEvents(ctx->task_snr_process_data_id, EVENT_DATA_READY); + + start_idx += FFT_SIZE; + iter++; + + } + + rtems_event_send(ctx->main_task, event_send[(TASK_COUNT-2)]); + DeleteRateMonotonic(read_sensor_data_period); + SuspendSelf(); +} + +static void task_snr_process_data(rtems_task_argument arg) { + test_context *ctx; + ctx = (test_context *)arg; + uint32_t start_idx = 0; + uint32_t iter = 0; + struct timespec begin_time; + struct timespec end_time; + + while ( start_idx < SENSOR_DATA_ELEM ) { + ReceiveAllEvents(EVENT_DATA_READY); + ObtainMutex(ctx->snr_mutex_id); + rtems_clock_get_uptime(&begin_time); + + //Apply Blackman-Harris Window + for (uint32_t i = 0; i < FFT_SIZE; i++) { + inSensorDataRe[i] = inSensorDataRe[start_idx+i]*blackman_harris(i, FFT_SIZE)/ctx->scaling_fft_factor; + inSensorDataIm[i] = inSensorDataIm[start_idx+i]*blackman_harris(i, FFT_SIZE)/ctx->scaling_fft_factor; + } + + //Calculates FFT + fft(&inSensorDataRe[0], &inSensorDataIm[0], FFT_SIZE_LOG2); + + //Calculates the magnitude values + for (uint32_t i = 0; i < FFT_SIZE; i++) { + inSensorDataRe[i] = (inSensorDataRe[i] * inSensorDataRe[i] + + inSensorDataIm[i] * inSensorDataIm[i]) / ((float)FFT_SIZE); + } + + //Look for the peak Value and its index (no DC) + float maxValue = 0.0; + float maxValueIndex = -1; + for (uint32_t i = 3; i < (FFT_SIZE / 2); i++) { + if (inSensorDataRe[i] > maxValue) { + maxValue = inSensorDataRe[i]; + maxValueIndex = i; + } + } + + //Calculates the signal and noise power (no DC) + float sig = 0.0f; + float noise = 0.0f; + for (uint32_t i = 3; i < (FFT_SIZE / 2); i++) { + if ((i > maxValueIndex - 4) && (i < maxValueIndex + 4)) { + sig += (2 * inSensorDataRe[i]); + } + else { + noise += (2 * inSensorDataRe[i]); + } + } + + if (!(sig > 0.0f)) { sig = 0.0000000001f; } + if (!(noise > 0.0f)) { noise = 0.0000000001f; } + + //Calculates SNR + float snr_float = sig/noise; + + if (snr_float > SNR_THRESHOLD) { + dsp_result[iter] = 1; + } + else { + dsp_result[iter] = 0; + } + rtems_clock_get_uptime(&end_time); + + ctx->snr_process_time += + (float)(end_time.tv_sec - begin_time.tv_sec) + + ( (float)((end_time.tv_nsec/1000) - (begin_time.tv_nsec/1000))/1000000.0); + + ReleaseMutex(ctx->snr_mutex_id); + start_idx += FFT_SIZE; + iter++; + } + + rtems_event_send(ctx->main_task, event_send[(TASK_COUNT-1)]); + SuspendSelf(); +} + + +//======================================================================================= +// INIT/MAIN Task +//======================================================================================= +static void Init(rtems_task_argument arg){ + (void)arg; + test_context ctx; + uint32_t start_time, end_time, elapsed_time; + char ch, str[ITOA_STR_SIZE]; + uint32_t total_events = 0; + uint8_t task = 255; + bool correctly_processed = true; + (void) memset(&ctx, 0, sizeof(test_context)); + (void) memset(&count_process[0], 0, TOTAL_TILES); + (void) memset(&xL2[0], 0, xL2_ELEM); + (void) memset(&inSensorDataRe[0], 0, SENSOR_DATA_ELEM); + (void) memset(&inSensorDataIm[0], 0, SENSOR_DATA_ELEM); + +#ifdef GR740_ESA_BOARD + soc_stats_regs soc_stats; +#endif + +//----------------------------------------------------------------------------- +// Create/Initialize Objects +//----------------------------------------------------------------------------- + rtems_message_queue_config msg_config = { + .name = rtems_build_name('M', 'S', 'G', 'T'), + .maximum_pending_messages = RTEMS_ARRAY_SIZE(msg_tile_queue_storage), + .maximum_message_size = MAX_MESSAGE_SIZE, + .storage_size = sizeof(msg_tile_queue_storage), + .storage_area = &msg_tile_queue_storage, + .attributes = RTEMS_FIFO | RTEMS_GLOBAL}; + + ctx.main_task = rtems_task_self(); + ctx.tile_queue = CreateMessageQueue(msg_config); + ctx.ntiles = TOTAL_TILES; + ctx.next_tile = 1; + + rtems_task_config calc_task_config = { + .initial_priority = PRIO_NORMAL, + .storage_size = TASK_STORAGE_SIZE, + .maximum_thread_local_storage_size = MAX_TLS_SIZE, + .initial_modes = RTEMS_DEFAULT_MODES, + .attributes = TASK_ATTRIBUTES}; + + ctx.filter_mutex_id = CreateMutex(rtems_build_name('M', 'U', 'T', '0')); + ctx.snr_mutex_id = CreateMutex(rtems_build_name('M', 'U', 'T', '1')); + SetSelfPriority( PRIO_NORMAL ); + + for (uint32_t i = 0; i < TASK_COUNT-2; i++){ + ch = '0' + i; + calc_task_config.name = rtems_build_name('R', 'U', 'N', ch); + calc_task_config.storage_area = &calc_task_storage[i][0]; + + ctx.task_filter_simulation_id[i] = DoCreateTask(calc_task_config); + StartTask(ctx.task_filter_simulation_id[i], calc_task_function, &ctx); + total_events += event_send[i]; + } + + ch = '0' + (TASK_COUNT-2); + calc_task_config.name = rtems_build_name('R', 'U', 'N', ch); + calc_task_config.storage_area = &calc_task_storage[(TASK_COUNT-2)][0]; + ctx.task_snr_read_sensor_data_id = DoCreateTask(calc_task_config); + StartTask(ctx.task_snr_read_sensor_data_id, task_snr_read_sensor_data, &ctx); + + ch = '0' + (TASK_COUNT-1); + calc_task_config.name = rtems_build_name('R', 'U', 'N', ch); + calc_task_config.storage_area = &calc_task_storage[(TASK_COUNT-1)][0]; + ctx.task_snr_process_data_id = DoCreateTask(calc_task_config); + StartTask(ctx.task_snr_process_data_id, task_snr_process_data, &ctx); + +//----------------------------------------------------------------------------- +// Setup the testcase +//----------------------------------------------------------------------------- + fill_main_memory_with_data(); + l1_dcache_flush(); + l1_dcache_disable(); + +#ifdef GR740_ESA_BOARD + l2_cache_disable(); + l2_cache_flush(); + l2_cache_set_replacement_policy(L2_CACHE_REPL_PSEUDORANDOM, 0); + l2_cache_enable(); +#endif + + l1_dcache_enable(); + uint32_t control_data_word = warmup_caches(); + +#ifdef GR740_ESA_BOARD + clockgating_enable_l4stat(); + soc_stats_configure_regs(); + soc_stats_init(&soc_stats); +#endif + + //Calculates mean of Blackman-Harris terms + ctx.scaling_fft_factor = 0.0; + for (uint32_t i = 0; i<FFT_SIZE; i++){ + ctx.scaling_fft_factor += blackman_harris( i, FFT_SIZE); + } + ctx.scaling_fft_factor = ctx.scaling_fft_factor/ ((float) FFT_SIZE); + +//----------------------------------------------------------------------------- +// Do the work: distribute the work through the tasks +//----------------------------------------------------------------------------- + SendEvents(ctx.task_snr_read_sensor_data_id, GO_READ_SENSOR); + start_time = rtems_clock_get_ticks_since_boot(); + + rtems_event_set revents = ReceiveAvailableEvents(); + while ( (revents & total_events) != total_events ) { + ReceiveMessage(ctx.tile_queue, &task); + SendMessage(ctx.message_queue[task], &ctx.next_tile, sizeof(ctx.next_tile)); + ctx.next_tile++; + revents = ReceiveAvailableEvents(); + + } + // Wait for the SNR processing tasks to finish + ReceiveAllEvents(event_send[(TASK_COUNT-2)]); + ReceiveAllEvents(event_send[(TASK_COUNT-1)]); + + end_time = rtems_clock_get_ticks_since_boot(); + elapsed_time = end_time - start_time; + +#ifdef GR740_ESA_BOARD + soc_stats_update(&soc_stats); +#endif + +//----------------------------------------------------------------------------- +// Show Results +//----------------------------------------------------------------------------- + print_string("\n"); + print_string("Multicore Elapsed Time -"); + print_string(itoa(elapsed_time, &str[0], 10)); + print_string("\n"); + + for (uint8_t i = 0; i < ctx.ntiles; i++){ + if (count_process[i] != 1){ + correctly_processed = false; + break; + } + } + + if (correctly_processed){ + print_string("Each tile only processed once : true\n"); + } + else{ + print_string("Each tile only processed once : false\n"); + } + + print_string("Input Data Result Value : 0x"); + print_string(itoa(control_data_word , &str[0], 16)); + print_string("\n"); + + print_string("Ouput Data Result Value : 0x"); + if (ctx.accxL2>=UINT32_MAX) { + print_string(itoa( (int32_t) ((ctx.accxL2 >> 32U) & ((uint64_t)UINT32_MAX)) , &str[0], 16)); + print_string(itoa( (int32_t) (ctx.accxL2 & ((uint64_t)UINT32_MAX)) , &str[0], 16)); + } + else { + print_string(itoa((int32_t)ctx.accxL2 , &str[0], 16)); + } + print_string("\n"); + print_string("Time used in filter sim processing : "); + print_string(itoa( (int32_t) (ctx.filter_sim_process_time *1000) , &str[0], 10)); + print_string(" ms\n"); + + print_string("Time used in SNR processing : "); + print_string(itoa( (int32_t) (ctx.snr_process_time *1000) , &str[0], 10)); + print_string(" ms\n"); + + print_string("SNR triggers found at : "); + for (uint32_t j = 0; j < MAX_ITER; j++) + if (dsp_result[j] > 0.0){ + print_string(itoa(j, &str[0], 10)); + print_string(" "); + } + print_string("\n"); + + +#ifdef GR740_ESA_BOARD + print_string("L1 Instr Cache misses (read) CPU_0 : "); + print_string(itoa(soc_stats.l1_inst_cache_miss[0], &str[0], 10)); + print_string("\n"); + print_string("L1 Instr Cache misses (read) CPU_1 : "); + print_string(itoa(soc_stats.l1_inst_cache_miss[1], &str[0], 10)); + print_string("\n"); + print_string("L1 Instr Cache misses (read) CPU_2 : "); + print_string(itoa(soc_stats.l1_inst_cache_miss[2], &str[0], 10)); + print_string("\n"); + print_string("L1 Instr Cache misses (read) CPU_3 : "); + print_string(itoa(soc_stats.l1_inst_cache_miss[3], &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses (read) CPU_0 : "); + print_string(itoa(soc_stats.l1_data_cache_miss[0], &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses (read) CPU_1 : "); + print_string(itoa(soc_stats.l1_data_cache_miss[1], &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses (read) CPU_2 : "); + print_string(itoa(soc_stats.l1_data_cache_miss[2], &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses (read) CPU_3 : "); + print_string(itoa(soc_stats.l1_data_cache_miss[3], &str[0], 10)); + print_string("\n"); + print_string("L2 Cache hits (read + writes) : "); + print_string(itoa(soc_stats.l2_cache_hits, &str[0], 10)); + print_string("\n"); + print_string("L2 Cache misses (read + writes) : "); + print_string(itoa(soc_stats.l2_cache_miss, &str[0], 10)); + print_string("\n"); + print_string("AHB Splits : "); + print_string(itoa(soc_stats.ahb_split_delay, &str[0], 10)); + print_string("\n"); + print_string("\n"); +#endif + + +// -------------------------------------------------------------------------- +// Delete Objects and Finalize testcase +// -------------------------------------------------------------------------- + for (uint32_t i = 0; i < (TASK_COUNT-2); i++){ + DeleteTask(ctx.task_filter_simulation_id[i]); + DeleteMessageQueue(ctx.message_queue[i]); + } + + DeleteTask(ctx.task_snr_process_data_id); + DeleteTask(ctx.task_snr_read_sensor_data_id); + + DeleteMutex(ctx.filter_mutex_id); + DeleteMutex(ctx.snr_mutex_id); + + DeleteMessageQueue(ctx.tile_queue); + rtems_fatal(RTEMS_FATAL_SOURCE_EXIT, 0); +} + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER + +#define CONFIGURE_MAXIMUM_PROCESSORS TEST_PROCESSORS + +#define CONFIGURE_MAXIMUM_MESSAGE_QUEUES MAX_MESSAGE_QUEUES + +#define CONFIGURE_MAXIMUM_SEMAPHORES 2 + +#define CONFIGURE_MAXIMUM_PERIODS 3 + +#define CONFIGURE_MAXIMUM_TASKS ( TASK_COUNT + 1 ) + +#define CONFIGURE_SCHEDULER_EDF_SMP + +#define CONFIGURE_MINIMUM_TASK_STACK_SIZE \ + RTEMS_MINIMUM_STACK_SIZE + CPU_STACK_ALIGNMENT + +#define CONFIGURE_EXTRA_TASK_STACKS RTEMS_MINIMUM_STACK_SIZE + +#define CONFIGURE_INIT_TASK_CONSTRUCT_STORAGE_SIZE 2 * TASK_STORAGE_SIZE + +#define CONFIGURE_MINIMUM_TASKS_WITH_USER_PROVIDED_STORAGE \ + CONFIGURE_MAXIMUM_TASKS + +#define CONFIGURE_MICROSECONDS_PER_TICK 1000 + +#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 0 + +#define CONFIGURE_DISABLE_NEWLIB_REENTRANCY + +#define CONFIGURE_APPLICATION_DISABLE_FILESYSTEM + +#define CONFIGURE_MAXIMUM_THREAD_LOCAL_STORAGE_SIZE MAX_TLS_SIZE + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT_TASK_ATTRIBUTES (RTEMS_SYSTEM_TASK | TASK_ATTRIBUTES) + +#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES + +#define CONFIGURE_INIT + +#include <rtems/confdefs.h> diff --git a/testsuites/isvv/shared/isvv_rtems_aux.c b/testsuites/isvv/shared/isvv_rtems_aux.c new file mode 100644 index 0000000000..b67bcc982e --- /dev/null +++ b/testsuites/isvv/shared/isvv_rtems_aux.c @@ -0,0 +1,622 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 2022 Critical Software SA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "isvv_rtems_aux.h" + +# define ITOA_STR_SIZE (8 * sizeof(int) + 1) + +/* ############################################### */ +/* Scheduler */ +/* ############################################### */ +rtems_id IdentifyScheduler( rtems_name name ) +{ + rtems_id id; + rtems_status_code sc; + + sc = rtems_scheduler_ident( name, &id ); + ASSERT_SUCCESS(sc); + return id; +} + +void SetScheduler(rtems_id task_id, rtems_id scheduler_id, rtems_task_priority priority) { + rtems_status_code sc; + + sc = rtems_task_set_scheduler( task_id, scheduler_id, priority ); + ASSERT_SUCCESS( sc ); +} + +/* ############################################### */ +/* Tasks */ +/* ############################################### */ +rtems_id DoCreateTask( rtems_task_config task_config ) +{ + rtems_id id; + rtems_status_code sc; + + sc = rtems_task_construct(&task_config, &id); + ASSERT_SUCCESS(sc); + return id; +} + +void StartTask( rtems_id id, rtems_task_entry entry, void *arg ) +{ + rtems_status_code sc; + + sc = rtems_task_start( id, entry, (rtems_task_argument) arg); + ASSERT_SUCCESS( sc ); +} + +void DeleteTask( rtems_id id ) +{ + if ( id != 0 ) { + rtems_status_code sc; + + sc = rtems_task_delete( id ); + ASSERT_SUCCESS( sc ); + } +} + +void SuspendTask( rtems_id id ) +{ + rtems_status_code sc; + + sc = rtems_task_suspend( id ); + ASSERT_SUCCESS( sc ); +} + +void SuspendSelf( void ) +{ + SuspendTask( RTEMS_SELF ); +} + +void ResumeTask( rtems_id id ) +{ + rtems_status_code sc; + + sc = rtems_task_resume( id ); + ASSERT_SUCCESS( sc ); +} + +bool IsTaskSuspended( rtems_id id ) +{ + rtems_status_code sc; + + sc = rtems_task_is_suspended( id ); + return sc == RTEMS_ALREADY_SUSPENDED; +} + +rtems_id TaskSelfId(void) +{ + rtems_id id; + rtems_status_code sc; + + sc = rtems_task_ident(RTEMS_WHO_AM_I, RTEMS_SEARCH_ALL_NODES, &id); + ASSERT_SUCCESS( sc ); + return id; +} + +rtems_task_priority SetTaskPriority(rtems_id id, rtems_task_priority prio) { + rtems_status_code sc; + rtems_task_priority old_prio; + + sc = rtems_task_set_priority(id, prio, &old_prio); + ASSERT_SUCCESS(sc); + return old_prio; +} + +rtems_task_priority SetSelfPriority( rtems_task_priority priority ) +{ + return SetTaskPriority( RTEMS_SELF, priority ); +} + +rtems_task_priority GetTaskPriority(rtems_id id) { + return SetTaskPriority(id, RTEMS_CURRENT_PRIORITY); +} + +void SetTaskMode(rtems_mode mode_set, rtems_mode mask, rtems_mode previous_mode_set) { + rtems_status_code sc; + + sc = rtems_task_mode(mode_set, mask, &previous_mode_set); + ASSERT_SUCCESS(sc); +} + +rtems_mode GetTaskMode( void ) { + rtems_status_code sc; + rtems_mode mode_set; + + // First parameter is ignored when second parameter is set to RTEMS_CURRENT_MODE + sc = rtems_task_mode(RTEMS_CURRENT_MODE, RTEMS_CURRENT_MODE, &mode_set); + ASSERT_SUCCESS(sc); + + return mode_set; +} + +// If task modes aren't equal to what we expect, print them out in hex +bool ASSERT_TASK_MODES_EQ(rtems_mode RESULT_MODE, rtems_mode EXPECTED_MODE) +{ + char str[ITOA_STR_SIZE]; + if (EXPECTED_MODE != RESULT_MODE) + { + print_string("TASK MODES NOT EXPECTED.\nRECEIVED-"); + print_string(itoa(RESULT_MODE, &str[0], 16)); + print_string(" EXPECTED-"); + print_string(itoa(EXPECTED_MODE, &str[0], 16)); + print_string("\n"); + } + + return (EXPECTED_MODE == RESULT_MODE); +} + +/* ############################################### */ +/* Semaphores */ +/* ############################################### */ +rtems_id CreateMutex( rtems_name name ) +{ + rtems_status_code sc; + rtems_id id; + + id = INVALID_ID; + sc = rtems_semaphore_create(name, 1, + RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | + RTEMS_INHERIT_PRIORITY, + 0, &id); + ASSERT_SUCCESS( sc ); + + return id; +} + +rtems_id CreateMutexNoProtocol( void ) +{ + rtems_status_code sc; + rtems_id id; + + id = INVALID_ID; + sc = rtems_semaphore_create(rtems_build_name('M', 'U', 'T', 'X'), 1, + RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY, 0, &id); + ASSERT_SUCCESS( sc ); + + return id; +} + +rtems_id CreateMutexNoLocking( rtems_name name ) +{ + rtems_status_code sc; + rtems_id id; + + id = INVALID_ID; + sc = rtems_semaphore_create(name, 3, RTEMS_NO_INHERIT_PRIORITY, 0, &id); + ASSERT_SUCCESS( sc ); + + return id; +} + +rtems_id CreateMutexFIFO( void ) +{ + rtems_status_code sc; + rtems_id id; + + id = INVALID_ID; + sc = rtems_semaphore_create(rtems_build_name('M', 'U', 'T', 'X'), 1, + RTEMS_BINARY_SEMAPHORE | RTEMS_FIFO, 0, &id); + ASSERT_SUCCESS(sc); + + return id; +} + +rtems_id CreateMutexMrsP( rtems_name name ) +{ + rtems_status_code sc; + rtems_id id; + + id = INVALID_ID; + sc = rtems_semaphore_create(name, 1, + RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | + RTEMS_MULTIPROCESSOR_RESOURCE_SHARING, + PRIO_ULTRA_HIGH, &id); + ASSERT_SUCCESS(sc); + + return id; +} + +void ObtainMutex( rtems_id id ) +{ + rtems_status_code sc; + + sc = rtems_semaphore_obtain(id, RTEMS_WAIT, RTEMS_NO_TIMEOUT); + ASSERT_SUCCESS(sc); +} + +void ReleaseMutex( rtems_id id ) +{ + rtems_status_code sc; + + sc = rtems_semaphore_release( id ); + ASSERT_SUCCESS( sc ); +} + +void DeleteMutex( rtems_id id ) +{ + if ( id != INVALID_ID ) { + rtems_status_code sc; + + sc = rtems_semaphore_delete( id ); + ASSERT_SUCCESS(sc); + } +} + +rtems_id CreateCounterSemaphore( rtems_name name, uint32_t count ) +{ + rtems_status_code sc; + rtems_id id; + + id = INVALID_ID; + sc = rtems_semaphore_create(name, count, RTEMS_DEFAULT_ATTRIBUTES, 0, &id); + ASSERT_SUCCESS( sc ); + + return id; +} + +void ObtainCounterSemaphore( rtems_id id ) +{ + ObtainMutex(id); +} + +void ReleaseCounterSemaphore( rtems_id id) +{ + ReleaseMutex(id); +} + + +/* ############################################### */ +/* Messages */ +/* ############################################### */ +rtems_id CreateMessageQueue(rtems_message_queue_config config) { + rtems_id id; + rtems_status_code sc; + + sc = rtems_message_queue_construct(&config, &id); + ASSERT_SUCCESS(sc); + return id; +} + +void SendMessage(rtems_id id, void *buffer, size_t size) { + rtems_status_code sc; + + sc = rtems_message_queue_send(id, buffer, size); + ASSERT_SUCCESS(sc); +} + +void ReceiveMessage(rtems_id id, void *buffer) { + rtems_status_code sc; + size_t size; + + sc = rtems_message_queue_receive(id, buffer, &size, RTEMS_DEFAULT_OPTIONS, + RTEMS_NO_TIMEOUT); + ASSERT_SUCCESS(sc); +} + +void DeleteMessageQueue( rtems_id id ) +{ + if ( id != INVALID_ID ) { + rtems_status_code sc; + + sc = rtems_message_queue_delete( id ); + ASSERT_SUCCESS(sc); + } +} + + +/* ############################################### */ +/* Events */ +/* ############################################### */ +rtems_event_set ReceiveAllEvents( rtems_event_set events ) +{ + rtems_status_code sc; + rtems_event_set received; + + received = 0; + sc = rtems_event_receive(events, RTEMS_EVENT_ALL | RTEMS_WAIT, + RTEMS_NO_TIMEOUT, &received); + ASSERT_SUCCESS(sc); + return received; +} + +rtems_event_set ReceiveAvailableEvents( void ) +{ + rtems_status_code sc; + rtems_event_set events; + + events = 0; + sc = rtems_event_receive(RTEMS_PENDING_EVENTS, + RTEMS_EVENT_ALL | RTEMS_WAIT, 0, &events); + if (sc != RTEMS_TIMEOUT) ASSERT_SUCCESS(sc); + + return events; +} + +rtems_event_set QueryPendingEvents( void ) +{ + rtems_status_code sc; + rtems_event_set events; + + events = 0; + sc = rtems_event_receive(RTEMS_PENDING_EVENTS, + RTEMS_EVENT_ALL | RTEMS_NO_WAIT, 0, &events); + ASSERT_SUCCESS(sc); + + return events; +} + +rtems_event_set ReceiveAnyEvents( void ) +{ + return ReceiveAnyEventsTimed( RTEMS_NO_TIMEOUT ); +} + +rtems_event_set ReceiveAnyEventsTimed(rtems_interval ticks) +{ + rtems_status_code sc; + rtems_event_set events; + + events = 0; + sc = rtems_event_receive(RTEMS_ALL_EVENTS, RTEMS_EVENT_ANY | RTEMS_WAIT, + ticks, &events); + ASSERT_SUCCESS(sc); + + return events; +} + +void SendEvents( rtems_id id, rtems_event_set events ) +{ + rtems_status_code sc; + + sc = rtems_event_send( id, events ); + ASSERT_SUCCESS(sc); +} + +/* ############################################### */ +/* Rate Monotonic */ +/* ############################################### */ +rtems_id CreateRateMonotonic( void ) +{ + rtems_status_code sc; + rtems_id id; + + id = INVALID_ID; + sc = rtems_rate_monotonic_create(rtems_build_name( 'R', 'M', 'O', 'N' ), &id); + ASSERT_SUCCESS( sc ); + + return id; +} + +bool DoesPeriodTimeOut( rtems_id id, rtems_interval period ) +{ + rtems_status_code sc; + bool timeout = false; + + sc = rtems_rate_monotonic_period(id, period); + if (sc == RTEMS_TIMEOUT) { + timeout = true; + } else { + ASSERT_SUCCESS(sc); + } + + return timeout; +} + +void WaitPeriod( rtems_id id, rtems_interval period ) +{ + rtems_status_code sc; + + sc = rtems_rate_monotonic_period(id, period); + ASSERT_SUCCESS(sc); +} + +void DeleteRateMonotonic( rtems_id id ) +{ + if ( id != INVALID_ID ) { + rtems_status_code sc; + + sc = rtems_rate_monotonic_delete( id ); + ASSERT_SUCCESS(sc); + } +} + + +/* ############################################### */ +/* Timer */ +/* ############################################### */ +rtems_id CreateTimer( rtems_name name ) +{ + rtems_status_code sc; + rtems_id id; + + id = INVALID_ID; + sc = rtems_timer_create(name, &id); + ASSERT_SUCCESS( sc ); + + return id; +} + +void LaunchFunctionAfter(rtems_id id, rtems_interval ticks, + rtems_timer_service_routine_entry routine, + void *user_data) { + rtems_status_code sc; + sc = rtems_timer_fire_after(id, ticks, routine, user_data); + ASSERT_SUCCESS(sc); +} + +void ResetTimer( rtems_id id ) { + rtems_status_code sc; + sc = rtems_timer_reset( id ); + ASSERT_SUCCESS(sc); +} + +void DeleteTimer( rtems_id id ) +{ + if ( id != INVALID_ID ) { + rtems_status_code sc; + + sc = rtems_timer_delete( id ); + ASSERT_SUCCESS(sc); + } +} + +/* ############################################### */ +/* Barrier */ +/* ############################################### */ +rtems_id CreateAutomaticBarrier( uint8_t nbarriers ) +{ + rtems_status_code sc; + rtems_id id; + + id = INVALID_ID; + sc = rtems_barrier_create(rtems_build_name('B', 'A', 'R', 'A'), + RTEMS_BARRIER_AUTOMATIC_RELEASE, nbarriers, &id); + ASSERT_SUCCESS( sc ); + + return id; +} + +rtems_id CreateManualBarrier(void) +{ + rtems_status_code sc; + rtems_id id; + + id = INVALID_ID; + sc = rtems_barrier_create(rtems_build_name('B', 'A', 'R', 'M'), + RTEMS_BARRIER_MANUAL_RELEASE, 0, &id); + ASSERT_SUCCESS( sc ); + + return id; +} + +void WaitAtBarrier( rtems_id id ) +{ + rtems_status_code sc; + + sc = rtems_barrier_wait(id, BARRIER_TIMEOUT); + ASSERT_SUCCESS( sc ); +} + +void ReleaseManualBarrier( rtems_id id, uint32_t n_barriers_to_release ) +{ + rtems_status_code sc; + uint32_t released; + uint32_t total_released = 0; + + while (total_released < n_barriers_to_release) { + sc = rtems_barrier_release(id, &released); + ASSERT_SUCCESS(sc); + total_released += released; + } +} + +void DeleteBarrier( rtems_id id ) +{ + if ( id != INVALID_ID ) { + rtems_status_code sc; + + sc = rtems_barrier_delete( id ); + ASSERT_SUCCESS(sc); + } +} + +/* ############################################### */ +/* Other */ +/* ############################################### */ +/* char GetRandomChar(void) { */ +/* return "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" */ +/* [rand() % 62]; */ +/* } */ + +/* rtems_name BuildRandomName( void ) { */ +/* return rtems_build_name(GetRandomChar(),GetRandomChar(),GetRandomChar(),GetRandomChar()); */ +/* } */ + +Thread_Control *GetThread( rtems_id id ) +{ + Thread_Control *the_thread; + ISR_lock_Context lock_context; + + the_thread = _Thread_Get( id, &lock_context ); + + if ( the_thread == NULL ) { + return NULL; + } + + _ISR_lock_ISR_enable( &lock_context); + return the_thread; +} + +void WaitForExecutionStop( rtems_id task_id ) +{ +#if defined( RTEMS_SMP ) + Thread_Control *the_thread; + + the_thread = GetThread( task_id ); + + while ( _Thread_Is_executing_on_a_processor( the_thread ) ) { + /* Wait */ + } +#else + (void) task_id; +#endif +} + +void WaitForIntendToBlock( rtems_id task_id ) +{ +#if defined( RTEMS_SMP ) + Thread_Control *the_thread; + Thread_Wait_flags intend_to_block; + + the_thread = GetThread( task_id ); + + intend_to_block = THREAD_WAIT_CLASS_OBJECT | + THREAD_WAIT_STATE_INTEND_TO_BLOCK; + + while ( _Thread_Wait_flags_get_acquire( the_thread ) != intend_to_block ) { + /* Wait */ + } +#else + (void) task_id; +#endif +} + +rtems_task_priority GetPriorityByScheduler(rtems_id task_id, + rtems_id scheduler_id) { + rtems_status_code sc; + rtems_task_priority priority; + + priority = PRIO_INVALID; + sc = rtems_task_get_priority( task_id, scheduler_id, &priority ); + + if ( sc != RTEMS_SUCCESSFUL ) { + return PRIO_INVALID; + } + + return priority; +} diff --git a/testsuites/isvv/shared/isvv_rtems_aux.h b/testsuites/isvv/shared/isvv_rtems_aux.h new file mode 100644 index 0000000000..8b4988756f --- /dev/null +++ b/testsuites/isvv/shared/isvv_rtems_aux.h @@ -0,0 +1,176 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 2022 Critical Software SA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <rtems.h> +#include <rtems/score/percpu.h> +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#include <rtems/score/threadimpl.h> +#pragma GCC diagnostic pop +#include "utils.h" + +typedef enum { + PRIO_PSEUDO_ISR, + PRIO_VERY_ULTRA_HIGH, + PRIO_ULTRA_HIGH, + PRIO_VERY_HIGH, + PRIO_HIGH, + PRIO_NORMAL, + PRIO_LOW, + PRIO_VERY_LOW, + PRIO_ULTRA_LOW +} Priority; + +#define INVALID_ID 0xfffffffd +#define PRIO_INVALID 0xfffffffe + +#define BARRIER_TIMEOUT 10000 + +#define SCHEDULER_A_NAME rtems_build_name( 'A', ' ', ' ', ' ' ) +#define SCHEDULER_B_NAME rtems_build_name( 'B', ' ', ' ', ' ' ) +#define SCHEDULER_C_NAME rtems_build_name( 'C', ' ', ' ', ' ' ) +#define SCHEDULER_D_NAME rtems_build_name( 'D', ' ', ' ', ' ' ) + +typedef struct { + rtems_name name; + uint32_t count; + size_t max_message_size; +} message_config; + +rtems_id IdentifyScheduler(rtems_name name); + +void SetScheduler(rtems_id task_id, rtems_id scheduler_id, rtems_task_priority priority); + +rtems_id DoCreateTask( rtems_task_config task_config ); + +void StartTask( rtems_id id, rtems_task_entry entry, void *arg ); + +void DeleteTask(rtems_id id); + +void SuspendTask( rtems_id id ); + +void SuspendSelf( void ); + +void ResumeTask( rtems_id id ); + +bool IsTaskSuspended(rtems_id id); + +rtems_id TaskSelfId(void); + +rtems_task_priority SetTaskPriority( rtems_id id, rtems_task_priority prio ); + +rtems_task_priority SetSelfPriority( rtems_task_priority priority ); + +rtems_task_priority GetTaskPriority(rtems_id id); + +void SetTaskMode(rtems_mode mode_set, rtems_mode mask, rtems_mode previous_mode_set); + +rtems_mode GetTaskMode( void ); + +bool ASSERT_TASK_MODES_EQ(rtems_mode RESULT_MODE, rtems_mode EXPECTED_MODE); + +rtems_id CreateMutex( rtems_name name ); + +rtems_id CreateMutexNoProtocol( void ); + +rtems_id CreateMutexNoLocking( rtems_name name ); + +rtems_id CreateMutexFIFO( void ); + +rtems_id CreateMutexMrsP( rtems_name name ); + +void ObtainMutex( rtems_id id ); + +void ReleaseMutex( rtems_id id ); + +void DeleteMutex( rtems_id id ); + +rtems_id CreateCounterSemaphore( rtems_name name, uint32_t count ); + +void ObtainCounterSemaphore( rtems_id id ); + +void ReleaseCounterSemaphore( rtems_id id); + +rtems_id CreateMessageQueue(rtems_message_queue_config config); + +void SendMessage(rtems_id id, void *buffer, size_t size); + +void ReceiveMessage(rtems_id id, void *buffer); + +void DeleteMessageQueue(rtems_id id); + +rtems_event_set ReceiveAllEvents( rtems_event_set events ); + +rtems_event_set ReceiveAnyEvents(void); + +rtems_event_set ReceiveAnyEventsTimed(rtems_interval ticks); + +rtems_event_set ReceiveAvailableEvents( void ); + +rtems_event_set QueryPendingEvents( void ); + +void SendEvents( rtems_id id, rtems_event_set events ); + +rtems_id CreateRateMonotonic( void ); + +bool DoesPeriodTimeOut( rtems_id id, rtems_interval period ); + +void WaitPeriod( rtems_id id, rtems_interval period ); + +void DeleteRateMonotonic( rtems_id id ); + +rtems_id CreateTimer( rtems_name name ); + +void LaunchFunctionAfter(rtems_id id, rtems_interval ticks, + rtems_timer_service_routine_entry routine, + void *user_data); + +void ResetTimer( rtems_id id ); + +void DeleteTimer( rtems_id id ); + +rtems_id CreateAutomaticBarrier( uint8_t nbarriers ); + +rtems_id CreateManualBarrier(void); + +void WaitAtBarrier( rtems_id id ); + +void ReleaseManualBarrier( rtems_id id, uint32_t n_barriers_to_release); + +void DeleteBarrier( rtems_id id ); + +char GetRandomChar( void ); + +rtems_name BuildRandomName( void ); + +Thread_Control *GetThread( rtems_id id ); + +void WaitForExecutionStop( rtems_id task_id ); + +void WaitForIntendToBlock( rtems_id task_id ); + +rtems_task_priority GetPriorityByScheduler( rtems_id task_id, rtems_id scheduler_id ); diff --git a/testsuites/isvv/shared/low_level_utils.c b/testsuites/isvv/shared/low_level_utils.c new file mode 100644 index 0000000000..5c46f239bb --- /dev/null +++ b/testsuites/isvv/shared/low_level_utils.c @@ -0,0 +1,464 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 2022 Critical Software SA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <string.h> +#include "low_level_utils.h" +#include "utils.h" + +// ------------------------------------------------------------------------------------------------ +// Pricate Declarations +// ------------------------------------------------------------------------------------------------ + +// Processor numeration +#define CPU_0 (0U) +#define CPU_1 (1U) +#define CPU_2 (2U) +#define CPU_3 (3U) + +// L1 Cache Bit registers bit definitions +#define L1_CACHE_CTRL_FD (0x00400000U) +#define L1_CACHE_CTRL_DP (0x00004000U) +#define L1_CACHE_CTRL_DCS (0x0000000CU) + +// L1 Cache Replacement policies +#define L1_CACHE_REPL_MAX (3U) +#define L1_CACHE_REPL_MASK (0xCFFFFFFF) +#define L1_CACHE_REPL_SHIFT (28U) + +// L2 Cache Bit registers bit definitions +#define L2_CACHE_L2CC_EN (0x80000000U) +#define L2_CACHE_L2CFMA_FMODE_FLUSH_ALL (0x00000007U) + +// L2 Cache Replacement policies +#define L2_CACHE_REPL_MAX (3U) +#define L2_CACHE_ENABLE_SPLIT_RESPONSES (0x00000002U) + +#define L2_CACHE_REPL_MASK (0xCFFFFFFF) +#define L2_CACHE_REPL_SHIFT (28U) +#define L2_CACHE_WAYS_MAX (4U) +#define L2_CACHE_WAYS_MASK (0xFFFFF0FF) +#define L2_CACHE_WAYS_LOCK_SHIFT (8U) +#define L2_CACHE_INDEX_WAYS_MASK (0xFFFF0FFF) +#define L2_CACHE_INDEX_WAYS_SHIFT (12U) + +// L4 Stats definitions +#define L4_STAT_CLEAR_COUNTER_ON_READ (0x00002000U) +#define L4_STAT_ENABLE_COUNTER (0x00001000U) +#define L4_STAT_L1_INST_CACHE_MISS_EVENT (0x00000000U) +#define L4_STAT_L1_DATA_CACHE_MISS_EVENT (0x00000008U) +#define L4_STAT_L2_CACHE_HIT_EVENT (0x00000060U) +#define L4_STAT_L2_CACHE_MISS_EVENT (0x00000061U) +#define L4_STAT_AHB_SPLIT_DELAY_EVENT (0x0000004EU) +#define L4_STAT_EVENT_ID_SHIFT (0x00000004U) +#define L4_STAT_EVENT_ID_MASK (0x00000FF0U) +#define L4_STAT_CPU_SHIFT (0x00000000U) +#define L4_STAT_CPU_MASK (0x0000000FU) + + +typedef struct l4stat_regs { + uint32_t cval[32]; /* 0x000 */ + uint32_t cctrl[32]; /* 0x080 */ + uint32_t cmax[32]; /* 0x100 */ + uint32_t timestamp; /* 0x180 */ +} l4stat_regs; + + +// ------------------------------------------------------------------------------------------------ +// Leon3/4 internal registers access - Public functions implementation +// ------------------------------------------------------------------------------------------------ + +uint32_t leon3_get_configuration_register(void) { + uint32_t asr17; + __asm__ volatile ("mov %%asr17, %0" : "=&r" (asr17) ); + return asr17; +} + +uint32_t leon3_get_psr_register(void) { + uint32_t psr; + __asm__ volatile ("mov %%psr, %0" : "=&r" (psr) ); + return psr; +} + +uint32_t leon3_get_wim_register(void) { + uint32_t wim; + __asm__ volatile ("mov %%wim, %0" : "=&r" (wim) ); + return wim; +} + +uint32_t leon3_get_tbr_register(void) { + uint32_t tbr; + __asm__ volatile ("mov %%tbr, %0" : "=&r" (tbr) ); + return tbr; +} + + +// ------------------------------------------------------------------------------------------------ +// L1 Cache peripheral/module - Public functions implementation +// ------------------------------------------------------------------------------------------------ + +void l1_dcache_disable(void) { + // Set the Data Cache state bits (DCS bits 3:2) to '00' in the Cache control register + uint32_t cache_reg = leon3_get_cache_control_register(); + cache_reg &= ~L1_CACHE_CTRL_DCS; + leon3_set_cache_control_register(cache_reg); +} + +void l1_dcache_enable(void) { + // Set the Data Cache state bits (DCS bits 3:2) to '11' in the Cache control register + uint32_t cache_reg = leon3_get_cache_control_register(); + cache_reg |= L1_CACHE_CTRL_DCS; + leon3_set_cache_control_register(cache_reg); +} + +void l1_dcache_flush(void) { + // Set the Flush data cache bit (FD - bit 22) to '1' in the Cache control register + uint32_t cache_reg = leon3_get_cache_control_register(); + cache_reg |= L1_CACHE_CTRL_FD; + leon3_set_cache_control_register(cache_reg); + + // Loop while the Data cache flush pending bit (DP - 14) in the Cache control register is set to '1' + do { + cache_reg = leon3_get_cache_control_register(); + } + while ( (cache_reg & L1_CACHE_CTRL_DP) == L1_CACHE_CTRL_DP); +} + +void l1_dcache_set_replacement_policy(uint32_t policy) { + if (policy <= L1_CACHE_REPL_MAX){ + uint32_t cache_reg = leon3_get_data_cache_config_register(); + cache_reg = (cache_reg & L1_CACHE_REPL_MASK) | (policy << L1_CACHE_REPL_SHIFT); + // There is no leon3_set_data_cache_config_register() in leon3.h, so a lower level function is used + leon3_set_system_register( 0xC, cache_reg ); + } +} + + +// ------------------------------------------------------------------------------------------------ +// L2 Cache peripheral/module - Public functions implementation +// ------------------------------------------------------------------------------------------------ + +void l2_cache_disable(void) { + // Set the L2 Controller Cache enable bit register (EN bit 31) to '0' in the L2C Control register (L2CS) + volatile l2cache *regs; + regs = (l2cache *) LEON3_L2CACHE_BASE; + uint32_t status = regs->l2cc; + status &= ~L2_CACHE_L2CC_EN; + regs->l2cc = status; +} + +void l2_cache_enable(void) { + // Set the L2 Controller Cache enable bit register (EN bit 31) to '1' in the L2C Control register (L2CS) + volatile l2cache *regs; + regs = (l2cache *) LEON3_L2CACHE_BASE; + uint32_t status = regs->l2cc; + status |= L2_CACHE_L2CC_EN; + regs->l2cc = status; +} + +void l2_cache_flush(void) { + // Set the L2 Flush mode bit registers ( FMODE bits 2:0) to '111' in the "L2C Flush + // (Memory address) register" (L2CFMA) + volatile l2cache *regs; + regs = (l2cache *) LEON3_L2CACHE_BASE; + uint32_t status = L2_CACHE_L2CFMA_FMODE_FLUSH_ALL; + regs->l2cfma = status; + + // There is no active way to wait for the L2 flush to finish, so a loop is added + Loop(1000); +} + +void l2_cache_set_replacement_policy(uint32_t policy, uint32_t index_way) { + // The index_way is only used if the Policy is L2_CACHE_REPL_MASTERINDEX_REPLACE + // (10: Master-index using index-replace field) + if ((policy <= L2_CACHE_REPL_MAX) && (index_way <= L2_CACHE_REPL_MAX)) { + volatile l2cache *regs; + regs = (l2cache *) LEON3_L2CACHE_BASE; + uint32_t status = regs->l2cc; + status = (status & L2_CACHE_REPL_MASK) | (policy << L2_CACHE_REPL_SHIFT) ; + if ( policy == L2_CACHE_REPL_MASTERINDEX_REPLACE) + status = (status & L2_CACHE_INDEX_WAYS_MASK)| (index_way << L2_CACHE_INDEX_WAYS_SHIFT); + regs->l2cc = status; + } +} + +void l2_cache_set_way_lock(uint32_t ways) { + // We can only control the number of cache ways to be locked: + // if 1 way is to be locked then way#4 is locked, + // if 2 ways are to be locked then way#3 and way#4 are locked, + // if 3 ways are to be locked then way#2, way#3 and way#4 are locked, + // otherwise all cache ways are locked. + + if (ways <= L2_CACHE_WAYS_MAX) { + volatile l2cache *regs; + regs = (l2cache *) LEON3_L2CACHE_BASE; + uint32_t status = regs->l2cc; + status = (status & L2_CACHE_WAYS_MASK) | (ways << L2_CACHE_WAYS_LOCK_SHIFT); + regs->l2cc = status; + } +} + +void l2_cache_enable_split_responses(void) { + volatile l2cache *regs; + regs = (l2cache *) LEON3_L2CACHE_BASE; + uint32_t status = regs->l2caccc; + status |= L2_CACHE_ENABLE_SPLIT_RESPONSES; + regs->l2caccc = status; +} + +void l2_cache_disable_split_responses(void) { + volatile l2cache *regs; + regs = (l2cache *) LEON3_L2CACHE_BASE; + uint32_t status = regs->l2caccc; + status &= ~L2_CACHE_ENABLE_SPLIT_RESPONSES; + regs->l2caccc = status; +} + +size_t l2_cache_get_size(void) { + volatile l2cache *regs; + unsigned status; + unsigned ways; + unsigned set_size; + + regs = (l2cache *) LEON3_L2CACHE_BASE; + status = regs->l2cs; + ways = L2CACHE_L2CS_WAY_GET(status) + 1; + set_size = L2CACHE_L2CS_WAY_SIZE_GET(status) * 1024; + + return ways * set_size; +} + + +void l2_cache_print_tags(uint32_t n) { + const uint32_t LEON3_L2CACHE_TAGS_OFFSET_ADDR = 0x80000U; + char str[8*sizeof(int)+1]; + + for ( uint32_t i=0; i<32*n; i+=4) { + volatile uint32_t addr = LEON3_L2CACHE_BASE + LEON3_L2CACHE_TAGS_OFFSET_ADDR + i; + if (addr%32 < 16) { + print_string("L2 cache Tag @addr[0x"); + print_string(itoa( addr, &str[0], 16)); + print_string("] : 0x"); + print_string(itoa(grlib_load_32((void*)(addr)), &str[0], 16)); + print_string("\n"); + } + } +} + + +// ------------------------------------------------------------------------------------------------ +// Leon4 Statistics peripheral/module - Public functions implementation +// ------------------------------------------------------------------------------------------------ + +void soc_stats_configure_regs(void) { + volatile l4stat_regs *regs; + uint32_t status; + + regs = (l4stat_regs *) L4_STAT_BASE; + + // "Counter 0 value register": Event "0x00 Instruction Data cache (read) miss" on processor #0 + status = L4_STAT_CLEAR_COUNTER_ON_READ | L4_STAT_ENABLE_COUNTER; + status |= L4_STAT_L1_INST_CACHE_MISS_EVENT << L4_STAT_EVENT_ID_SHIFT; + status |= CPU_0 << L4_STAT_CPU_SHIFT; + regs->cctrl[0] = status; + + // "Counter 1 value register": Event "0x00 Instruction cache (read) miss" on processor #1 + status = L4_STAT_CLEAR_COUNTER_ON_READ | L4_STAT_ENABLE_COUNTER; + status |= L4_STAT_L1_INST_CACHE_MISS_EVENT << L4_STAT_EVENT_ID_SHIFT; + status |= CPU_1 << L4_STAT_CPU_SHIFT; + regs->cctrl[1] = status; + + // "Counter 2 value register": Event "0x00 Instruction cache (read) miss" on processor #2 + status = L4_STAT_CLEAR_COUNTER_ON_READ | L4_STAT_ENABLE_COUNTER; + status |= L4_STAT_L1_INST_CACHE_MISS_EVENT << L4_STAT_EVENT_ID_SHIFT; + status |= CPU_2 << L4_STAT_CPU_SHIFT; + regs->cctrl[2] = status; + + // "Counter 3 value register": Event 0x00 Instruction cache (read) miss" on processor #3 + status = L4_STAT_CLEAR_COUNTER_ON_READ | L4_STAT_ENABLE_COUNTER; + status |= L4_STAT_L1_INST_CACHE_MISS_EVENT << L4_STAT_EVENT_ID_SHIFT; + status |= CPU_3 << L4_STAT_CPU_SHIFT; + regs->cctrl[3] = status; + + // "Counter 4 value register": Event "0x08 Data cache (read) miss" on processor #0 + status = L4_STAT_CLEAR_COUNTER_ON_READ | L4_STAT_ENABLE_COUNTER; + status |= L4_STAT_L1_DATA_CACHE_MISS_EVENT << L4_STAT_EVENT_ID_SHIFT; + status |= CPU_0 << L4_STAT_CPU_SHIFT; + regs->cctrl[4] = status; + + // "Counter 5 value register": Event "0x08 Data cache (read) miss" on processor #1 + status = L4_STAT_CLEAR_COUNTER_ON_READ | L4_STAT_ENABLE_COUNTER; + status |= L4_STAT_L1_DATA_CACHE_MISS_EVENT << L4_STAT_EVENT_ID_SHIFT; + status |= CPU_1 << L4_STAT_CPU_SHIFT; + regs->cctrl[5] = status; + + // "Counter 6 value register": Event "0x08 Data cache (read) miss" on processor #2 + status = L4_STAT_CLEAR_COUNTER_ON_READ | L4_STAT_ENABLE_COUNTER; + status |= L4_STAT_L1_DATA_CACHE_MISS_EVENT << L4_STAT_EVENT_ID_SHIFT; + status |= CPU_2 << L4_STAT_CPU_SHIFT; + regs->cctrl[6] = status; + + // "Counter 7 value register": Event "0x08 Data cache (read) miss" on processor #3 + status = L4_STAT_CLEAR_COUNTER_ON_READ | L4_STAT_ENABLE_COUNTER; + status |= L4_STAT_L1_DATA_CACHE_MISS_EVENT << L4_STAT_EVENT_ID_SHIFT; + status |= CPU_3 << L4_STAT_CPU_SHIFT; + regs->cctrl[7] = status; + + // "Counter 8 value register": Event "0x60 L2 cache hits (external event 0, CPU/AHBM + // field can select AHB master)" + status = L4_STAT_CLEAR_COUNTER_ON_READ | L4_STAT_ENABLE_COUNTER; + status |= L4_STAT_L2_CACHE_HIT_EVENT << L4_STAT_EVENT_ID_SHIFT; + regs->cctrl[8] = status; + + // "Counter 9 value register": Event "0x61 L2 cache miss (external event 1, CPU/AHBM + // field can select AHB master)" + status = L4_STAT_CLEAR_COUNTER_ON_READ | L4_STAT_ENABLE_COUNTER; + status |= L4_STAT_L2_CACHE_MISS_EVENT << L4_STAT_EVENT_ID_SHIFT; + regs->cctrl[9] = status; + + // "Counter 10 value register": Event "0x4E AHB SPLIT delay. Filtered on CPU/AHBM + // if SU(1) = ‘1‘" + status = L4_STAT_CLEAR_COUNTER_ON_READ | L4_STAT_ENABLE_COUNTER; + status |= L4_STAT_AHB_SPLIT_DELAY_EVENT << L4_STAT_EVENT_ID_SHIFT; + status |= CPU_1 << L4_STAT_CPU_SHIFT; + regs->cctrl[10] = status; +} + +void soc_stats_init(soc_stats_regs *stats) { + volatile l4stat_regs *regs; + regs = (l4stat_regs *) L4_STAT_BASE; + + memset(stats, 0, sizeof(soc_stats_regs)); + + // The following dummy read operations purpose is to clean the statistcs counters + (void) regs->cval[0]; + (void) regs->cval[1]; + (void) regs->cval[2]; + (void) regs->cval[3]; + (void) regs->cval[4]; + (void) regs->cval[5]; + (void) regs->cval[6]; + (void) regs->cval[7]; + (void) regs->cval[8]; + (void) regs->cval[9]; + (void) regs->cval[10]; +} + +void soc_stats_update(soc_stats_regs *stats){ + volatile l4stat_regs *regs; + + regs = (l4stat_regs *) L4_STAT_BASE; + stats->l1_inst_cache_miss[0] += regs->cval[0]; + stats->l1_inst_cache_miss[1] += regs->cval[1]; + stats->l1_inst_cache_miss[2] += regs->cval[2]; + stats->l1_inst_cache_miss[3] += regs->cval[3]; + stats->l1_data_cache_miss[0] += regs->cval[4]; + stats->l1_data_cache_miss[1] += regs->cval[5]; + stats->l1_data_cache_miss[2] += regs->cval[6]; + stats->l1_data_cache_miss[3] += regs->cval[7]; + stats->l2_cache_hits += regs->cval[8]; + stats->l2_cache_miss += regs->cval[9]; + stats->ahb_split_delay += regs->cval[10]; +} + +void l4_stats_print(void) { + char str[8*sizeof(int)+1]; + print_string("------------------------------------------------------------\n"); + print_string("Printing L4 STAT REGS current value\n"); + print_string("L1 Instructions Cache misses CPU_0 : "); + print_string(itoa(grlib_load_32((uint32_t*)( L4_STAT_BASE +0x00U)), &str[0], 10)); + print_string("\n"); + print_string("L1 Instructions Cache misses CPU_1 : "); + print_string(itoa(grlib_load_32((uint32_t*)( L4_STAT_BASE +0x04U)), &str[0], 10)); + print_string("\n"); + print_string("L1 Instructions Cache misses CPU_2 : "); + print_string(itoa(grlib_load_32((uint32_t*)( L4_STAT_BASE +0x08U)), &str[0], 10)); + print_string("\n"); + print_string("L1 Instructions Cache misses CPU_3 : "); + print_string(itoa(grlib_load_32((uint32_t*)( L4_STAT_BASE +0x0CU)), &str[0], 10)); + print_string("L1 Data Cache misses CPU_0 : "); + print_string(itoa(grlib_load_32((uint32_t*)( L4_STAT_BASE +0x10U)), &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses CPU_1 : "); + print_string(itoa(grlib_load_32((uint32_t*)( L4_STAT_BASE +0x14U)), &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses CPU_2 : "); + print_string(itoa(grlib_load_32((uint32_t*)( L4_STAT_BASE +0x18U)), &str[0], 10)); + print_string("\n"); + print_string("L1 Data Cache misses CPU_3 : "); + print_string(itoa(grlib_load_32((uint32_t*)( L4_STAT_BASE +0x1CU)), &str[0], 10)); + print_string("\n"); + print_string("L2 Cache hits : "); + print_string(itoa(grlib_load_32((uint32_t*)( L4_STAT_BASE +0x20U)), &str[0], 10)); + print_string("\n"); + print_string("L2 Cache misses : "); + print_string(itoa(grlib_load_32((uint32_t*)( L4_STAT_BASE +0x24U)), &str[0], 10)); + print_string("\n"); + print_string("AHB Splits : "); + print_string(itoa(grlib_load_32((uint32_t*)( L4_STAT_BASE +0x30U)), &str[0], 10)); + print_string("\n"); +} + +// ------------------------------------------------------------------------------------------------ +// Clock Gating peripheral/module - Public functions implementation +// ------------------------------------------------------------------------------------------------ + +void clockgating_enable_l4stat(void) { + // 1. Write a 1 to the corresponding bit in the unlock register + volatile uint32_t reg = grlib_load_32((uint32_t*)(GRCLKGATE_BASE + 0x00U)); + reg |= 0x40LU; + grlib_store_32((uint32_t*)(GRCLKGATE_BASE + 0x00U), reg); + + // 2. Write a 1 to the corresponding bit in the core reset register + reg = grlib_load_32((uint32_t*)(GRCLKGATE_BASE + 0x08U)); + reg |= 0x40LU; + grlib_store_32((uint32_t*)(GRCLKGATE_BASE + 0x08U), reg); + + // 3. Write a 1 to the corresponding bit in the clock enable register + reg = grlib_load_32((uint32_t*)(GRCLKGATE_BASE + 0x04U)); + reg |= 0x40LU; + grlib_store_32((uint32_t*)(GRCLKGATE_BASE + 0x04U), reg); + + // 4. Write a 0 to the corresponding bit in the clock enable register + reg = grlib_load_32((uint32_t*)(GRCLKGATE_BASE + 0x04U)); + reg &= ~0x40LU; + grlib_store_32((uint32_t*)(GRCLKGATE_BASE + 0x04U), reg); + + // 5. Write a 0 to the corresponding bit in the core reset register + reg = grlib_load_32((uint32_t*)(GRCLKGATE_BASE + 0x08U)); + reg &= ~0x40LU; + grlib_store_32((uint32_t*)(GRCLKGATE_BASE + 0x08U), reg); + + // 6. Write a 1 to the corresponding bit in the clock enable register + reg = grlib_load_32((uint32_t*)(GRCLKGATE_BASE + 0x04U)); + reg |= 0x40LU; + grlib_store_32((uint32_t*)(GRCLKGATE_BASE + 0x04U), reg); + + // 7. Write a 0 to the corresponding bit in the unlock register + reg = grlib_load_32((uint32_t*)(GRCLKGATE_BASE + 0x00U)); + reg &= ~0x40LU; + grlib_store_32((uint32_t*)(GRCLKGATE_BASE + 0x00U), reg); +} diff --git a/testsuites/isvv/shared/low_level_utils.h b/testsuites/isvv/shared/low_level_utils.h new file mode 100644 index 0000000000..22f0de4369 --- /dev/null +++ b/testsuites/isvv/shared/low_level_utils.h @@ -0,0 +1,126 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 2022 Critical Software SA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _LOW_LEVEL_UTILS_H +#define _LOW_LEVEL_UTILS_H + +#include <bsp/leon3.h> +#include <grlib/l2cache-regs.h> +#include <grlib/io.h> + + +// ------------------------------------------------------------------------------------------------ +// Leon3/4 Configuration Registers +// ------------------------------------------------------------------------------------------------ + +uint32_t leon3_get_configuration_register( void ); + +uint32_t leon3_get_psr_register( void ); + +uint32_t leon3_get_wim_register( void ); + +uint32_t leon3_get_tbr_register( void ); + + +// ------------------------------------------------------------------------------------------------ +// L1 Cache definitions +// ------------------------------------------------------------------------------------------------ +// L1 Cache Replacement policies +#define L1_CACHE_REPL_DIRECT_MAPPED (0x00000000U) // 00: no replacement policy (direct-mapped cache) +#define L1_CACHE_REPL_LRU (0x00000001U) // 01: least recently used (LRU) +#define L1_CACHE_REPL_LRR (0x00000002U) // 10: least recently replaced (LRR) +#define L1_CACHE_REPL_RANDOM (0x00000003U) // 11: random + +void l1_dcache_flush(void); + +void l1_dcache_disable(void); + +void l1_dcache_enable(void); + +void l1_dcache_set_replacement_policy(uint32_t policy); + + +// ------------------------------------------------------------------------------------------------ +// L2 Cache definitions +// ------------------------------------------------------------------------------------------------ +// L2 Cache Replacement policies +#define L2_CACHE_REPL_LRU (0x00000000U) // 00: LRU +#define L2_CACHE_REPL_PSEUDORANDOM (0x00000001U) // 01: (pseudo-) random +#define L2_CACHE_REPL_MASTERINDEX_REPLACE (0x00000002U) // 10: Master-index using index-replace field +#define L2_CACHE_REPL_MASTERINDEX_MODULUS (0x00000003U) // 11: Master-index using the modulus function + +void l2_cache_disable(void); + +void l2_cache_enable(void); + +void l2_cache_flush(void); + +void l2_cache_set_replacement_policy(uint32_t policy, uint32_t index_way); + +void l2_cache_set_way_lock(uint32_t ways); + +void l2_cache_enable_split_responses(void); + +void l2_cache_disable_split_responses(void); + +size_t l2_cache_get_size(void); + +void l2_cache_print_tags(uint32_t n); + + +// ------------------------------------------------------------------------------------------------ +// SOC Statistics definitions +// ------------------------------------------------------------------------------------------------ +#define L4_STAT_BASE (0xFFA0D000U) + +typedef struct soc_stats_regs { + uint32_t l1_inst_cache_miss[4]; + uint32_t l1_data_cache_miss[4]; + uint32_t l2_cache_hits; + uint32_t l2_cache_miss; + uint32_t ahb_split_delay; + +} soc_stats_regs; + +void soc_stats_init(soc_stats_regs *stats); + +void soc_stats_configure_regs(void); + +void soc_stats_update(soc_stats_regs *stats); + +void l4_stats_print(void); + + +// ------------------------------------------------------------------------------------------------ +// Clock Gating Definitions +// ------------------------------------------------------------------------------------------------ +#define GRCLKGATE_BASE (0xFFA04000U) + +void clockgating_enable_l4stat(void); + +#endif /* !_LOW_LEVEL_UTILS_H */ +/* end of include file */ diff --git a/testsuites/isvv/shared/trig_tables.h b/testsuites/isvv/shared/trig_tables.h new file mode 100644 index 0000000000..0a9dfe609c --- /dev/null +++ b/testsuites/isvv/shared/trig_tables.h @@ -0,0 +1,2091 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 2022 Critical Software SA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _TRIG_TABLES_H +#define _TRIG_TABLES_H + +#ifndef PI +#define PI (3.14159265358979323846f) +#endif + +#define FFT_TABLE_SIZE (8192U) + +static const float cosTable[FFT_TABLE_SIZE]={ + 1.00000000, 0.99999970, 0.99999881, 0.99999738, 0.99999529, 0.99999267, 0.99998939, 0.99998558, + 0.99998116, 0.99997616, 0.99997061, 0.99996442, 0.99995762, 0.99995029, 0.99994236, 0.99993384, + 0.99992472, 0.99991500, 0.99990469, 0.99989384, 0.99988234, 0.99987030, 0.99985766, 0.99984443, + 0.99983060, 0.99981618, 0.99980116, 0.99978560, 0.99976939, 0.99975264, 0.99973530, 0.99971735, + 0.99969882, 0.99967968, 0.99966002, 0.99963969, 0.99961883, 0.99959737, 0.99957532, 0.99955267, + 0.99952942, 0.99950558, 0.99948120, 0.99945617, 0.99943060, 0.99940443, 0.99937767, 0.99935031, + 0.99932235, 0.99929386, 0.99926478, 0.99923503, 0.99920475, 0.99917388, 0.99914241, 0.99911034, + 0.99907774, 0.99904448, 0.99901068, 0.99897629, 0.99894130, 0.99890572, 0.99886954, 0.99883282, + 0.99879545, 0.99875754, 0.99871904, 0.99867994, 0.99864024, 0.99859995, 0.99855906, 0.99851763, + 0.99847555, 0.99843293, 0.99838972, 0.99834591, 0.99830157, 0.99825656, 0.99821103, 0.99816483, + 0.99811810, 0.99807078, 0.99802285, 0.99797440, 0.99792528, 0.99787563, 0.99782532, 0.99777448, + 0.99772304, 0.99767107, 0.99761844, 0.99756521, 0.99751145, 0.99745709, 0.99740213, 0.99734658, + 0.99729043, 0.99723375, 0.99717641, 0.99711853, 0.99706006, 0.99700099, 0.99694133, 0.99688113, + 0.99682027, 0.99675888, 0.99669689, 0.99663430, 0.99657112, 0.99650741, 0.99644303, 0.99637812, + 0.99631262, 0.99624652, 0.99617982, 0.99611259, 0.99604470, 0.99597627, 0.99590725, 0.99583763, + 0.99576741, 0.99569660, 0.99562526, 0.99555331, 0.99548078, 0.99540764, 0.99533391, 0.99525958, + 0.99518472, 0.99510926, 0.99503320, 0.99495655, 0.99487931, 0.99480152, 0.99472314, 0.99464417, + 0.99456459, 0.99448442, 0.99440366, 0.99432236, 0.99424046, 0.99415797, 0.99407488, 0.99399120, + 0.99390697, 0.99382216, 0.99373674, 0.99365073, 0.99356413, 0.99347699, 0.99338919, 0.99330086, + 0.99321193, 0.99312246, 0.99303234, 0.99294168, 0.99285042, 0.99275857, 0.99266613, 0.99257314, + 0.99247956, 0.99238533, 0.99229062, 0.99219525, 0.99209929, 0.99200279, 0.99190569, 0.99180800, + 0.99170977, 0.99161088, 0.99151146, 0.99141145, 0.99131083, 0.99120969, 0.99110794, 0.99100554, + 0.99090266, 0.99079913, 0.99069500, 0.99059033, 0.99048507, 0.99037921, 0.99027282, 0.99016583, + 0.99005818, 0.98995006, 0.98984128, 0.98973197, 0.98962200, 0.98951149, 0.98940045, 0.98928875, + 0.98917651, 0.98906368, 0.98895025, 0.98883629, 0.98872167, 0.98860651, 0.98849082, 0.98837447, + 0.98825759, 0.98814011, 0.98802203, 0.98790336, 0.98778415, 0.98766434, 0.98754394, 0.98742294, + 0.98730141, 0.98717928, 0.98705655, 0.98693329, 0.98680937, 0.98668492, 0.98655993, 0.98643428, + 0.98630810, 0.98618132, 0.98605394, 0.98592603, 0.98579752, 0.98566842, 0.98553872, 0.98540848, + 0.98527765, 0.98514622, 0.98501426, 0.98488164, 0.98474848, 0.98461479, 0.98448044, 0.98434556, + 0.98421007, 0.98407406, 0.98393744, 0.98380023, 0.98366243, 0.98352402, 0.98338509, 0.98324561, + 0.98310548, 0.98296481, 0.98282355, 0.98268169, 0.98253930, 0.98239630, 0.98225272, 0.98210859, + 0.98196387, 0.98181856, 0.98167270, 0.98152626, 0.98137921, 0.98123157, 0.98108339, 0.98093462, + 0.98078525, 0.98063534, 0.98048484, 0.98033381, 0.98018211, 0.98002988, 0.97987711, 0.97972375, + 0.97956979, 0.97941524, 0.97926015, 0.97910446, 0.97894818, 0.97879136, 0.97863394, 0.97847593, + 0.97831738, 0.97815824, 0.97799850, 0.97783822, 0.97767735, 0.97751594, 0.97735387, 0.97719133, + 0.97702813, 0.97686440, 0.97670007, 0.97653520, 0.97636974, 0.97620368, 0.97603709, 0.97586989, + 0.97570211, 0.97553378, 0.97536486, 0.97519541, 0.97502536, 0.97485471, 0.97468352, 0.97451174, + 0.97433937, 0.97416645, 0.97399294, 0.97381890, 0.97364426, 0.97346902, 0.97329324, 0.97311687, + 0.97293997, 0.97276247, 0.97258437, 0.97240573, 0.97222650, 0.97204673, 0.97186631, 0.97168541, + 0.97150391, 0.97132182, 0.97113913, 0.97095591, 0.97077215, 0.97058779, 0.97040284, 0.97021735, + 0.97003126, 0.96984458, 0.96965736, 0.96946961, 0.96928126, 0.96909231, 0.96890283, 0.96871275, + 0.96852207, 0.96833086, 0.96813911, 0.96794677, 0.96775383, 0.96756035, 0.96736628, 0.96717167, + 0.96697646, 0.96678072, 0.96658438, 0.96638745, 0.96618998, 0.96599197, 0.96579337, 0.96559417, + 0.96539444, 0.96519411, 0.96499324, 0.96479183, 0.96458977, 0.96438724, 0.96418405, 0.96398038, + 0.96377605, 0.96357119, 0.96336579, 0.96315980, 0.96295327, 0.96274614, 0.96253848, 0.96233022, + 0.96212143, 0.96191204, 0.96170205, 0.96149158, 0.96128047, 0.96106887, 0.96085662, 0.96064389, + 0.96043050, 0.96021664, 0.96000212, 0.95978713, 0.95957154, 0.95935535, 0.95913863, 0.95892131, + 0.95870346, 0.95848507, 0.95826608, 0.95804650, 0.95782644, 0.95760572, 0.95738453, 0.95716268, + 0.95694035, 0.95671743, 0.95649391, 0.95626986, 0.95604527, 0.95582008, 0.95559436, 0.95536804, + 0.95514119, 0.95491374, 0.95468575, 0.95445722, 0.95422810, 0.95399845, 0.95376819, 0.95353740, + 0.95330602, 0.95307410, 0.95284164, 0.95260859, 0.95237499, 0.95214087, 0.95190614, 0.95167089, + 0.95143503, 0.95119864, 0.95096165, 0.95072412, 0.95048606, 0.95024747, 0.95000827, 0.94976848, + 0.94952816, 0.94928730, 0.94904590, 0.94880390, 0.94856137, 0.94831824, 0.94807458, 0.94783038, + 0.94758558, 0.94734025, 0.94709438, 0.94684792, 0.94660091, 0.94635338, 0.94610524, 0.94585657, + 0.94560730, 0.94535756, 0.94510722, 0.94485629, 0.94460481, 0.94435281, 0.94410026, 0.94384712, + 0.94359344, 0.94333923, 0.94308442, 0.94282907, 0.94257319, 0.94231677, 0.94205976, 0.94180220, + 0.94154406, 0.94128537, 0.94102615, 0.94076639, 0.94050604, 0.94024521, 0.93998373, 0.93972176, + 0.93945920, 0.93919611, 0.93893248, 0.93866831, 0.93840355, 0.93813825, 0.93787235, 0.93760598, + 0.93733901, 0.93707150, 0.93680346, 0.93653482, 0.93626565, 0.93599594, 0.93572569, 0.93545485, + 0.93518353, 0.93491161, 0.93463916, 0.93436611, 0.93409252, 0.93381846, 0.93354380, 0.93326855, + 0.93299282, 0.93271649, 0.93243963, 0.93216223, 0.93188429, 0.93160576, 0.93132669, 0.93104708, + 0.93076694, 0.93048626, 0.93020505, 0.92992324, 0.92964089, 0.92935801, 0.92907459, 0.92879063, + 0.92850608, 0.92822099, 0.92793542, 0.92764926, 0.92736250, 0.92707527, 0.92678750, 0.92649913, + 0.92621022, 0.92592078, 0.92563081, 0.92534029, 0.92504925, 0.92475760, 0.92446548, 0.92417276, + 0.92387950, 0.92358577, 0.92329144, 0.92299652, 0.92270112, 0.92240518, 0.92210865, 0.92181164, + 0.92151403, 0.92121589, 0.92091721, 0.92061806, 0.92031831, 0.92001796, 0.91971713, 0.91941577, + 0.91911387, 0.91881138, 0.91850841, 0.91820484, 0.91790080, 0.91759616, 0.91729099, 0.91698527, + 0.91667908, 0.91637230, 0.91606498, 0.91575712, 0.91544873, 0.91513979, 0.91483033, 0.91452032, + 0.91420978, 0.91389865, 0.91358703, 0.91327488, 0.91296220, 0.91264898, 0.91233516, 0.91202086, + 0.91170603, 0.91139066, 0.91107476, 0.91075826, 0.91044128, 0.91012377, 0.90980572, 0.90948713, + 0.90916800, 0.90884835, 0.90852809, 0.90820736, 0.90788609, 0.90756434, 0.90724200, 0.90691912, + 0.90659571, 0.90627176, 0.90594727, 0.90562230, 0.90529674, 0.90497071, 0.90464407, 0.90431696, + 0.90398932, 0.90366107, 0.90333235, 0.90300310, 0.90267330, 0.90234298, 0.90201217, 0.90168077, + 0.90134883, 0.90101641, 0.90068340, 0.90034992, 0.90001589, 0.89968133, 0.89934623, 0.89901060, + 0.89867449, 0.89833778, 0.89800060, 0.89766282, 0.89732456, 0.89698577, 0.89664650, 0.89630663, + 0.89596623, 0.89562535, 0.89528394, 0.89494199, 0.89459950, 0.89425647, 0.89391297, 0.89356887, + 0.89322430, 0.89287919, 0.89253354, 0.89218742, 0.89184070, 0.89149350, 0.89114577, 0.89079750, + 0.89044875, 0.89009941, 0.88974959, 0.88939923, 0.88904834, 0.88869697, 0.88834506, 0.88799256, + 0.88763964, 0.88728613, 0.88693213, 0.88657761, 0.88622254, 0.88586694, 0.88551086, 0.88515425, + 0.88479710, 0.88443947, 0.88408124, 0.88372254, 0.88336337, 0.88300359, 0.88264334, 0.88228256, + 0.88192129, 0.88155943, 0.88119709, 0.88083428, 0.88047087, 0.88010699, 0.87974262, 0.87937766, + 0.87901223, 0.87864625, 0.87827981, 0.87791282, 0.87754530, 0.87717724, 0.87680870, 0.87643969, + 0.87607008, 0.87570000, 0.87532938, 0.87495828, 0.87458664, 0.87421453, 0.87384182, 0.87346870, + 0.87309498, 0.87272078, 0.87234604, 0.87197083, 0.87159508, 0.87121886, 0.87084204, 0.87046480, + 0.87008697, 0.86970866, 0.86932987, 0.86895055, 0.86857069, 0.86819035, 0.86780947, 0.86742812, + 0.86704624, 0.86666387, 0.86628097, 0.86589754, 0.86551362, 0.86512917, 0.86474425, 0.86435878, + 0.86397284, 0.86358637, 0.86319941, 0.86281192, 0.86242396, 0.86203545, 0.86164647, 0.86125696, + 0.86086696, 0.86047643, 0.86008537, 0.85969388, 0.85930181, 0.85890925, 0.85851622, 0.85812265, + 0.85772860, 0.85733402, 0.85693896, 0.85654342, 0.85614735, 0.85575074, 0.85535365, 0.85495609, + 0.85455799, 0.85415941, 0.85376030, 0.85336071, 0.85296059, 0.85255998, 0.85215890, 0.85175729, + 0.85135520, 0.85095257, 0.85054946, 0.85014588, 0.84974176, 0.84933716, 0.84893203, 0.84852648, + 0.84812033, 0.84771377, 0.84730661, 0.84689903, 0.84649092, 0.84608233, 0.84567326, 0.84526366, + 0.84485358, 0.84444296, 0.84403187, 0.84362030, 0.84320825, 0.84279567, 0.84238261, 0.84196901, + 0.84155500, 0.84114045, 0.84072536, 0.84030986, 0.83989382, 0.83947724, 0.83906025, 0.83864272, + 0.83822471, 0.83780622, 0.83738720, 0.83696771, 0.83654773, 0.83612728, 0.83570629, 0.83528483, + 0.83486289, 0.83444041, 0.83401752, 0.83359408, 0.83317018, 0.83274579, 0.83232087, 0.83189547, + 0.83146960, 0.83104324, 0.83061641, 0.83018905, 0.82976121, 0.82933295, 0.82890409, 0.82847482, + 0.82804507, 0.82761478, 0.82718402, 0.82675278, 0.82632107, 0.82588887, 0.82545614, 0.82502300, + 0.82458931, 0.82415515, 0.82372051, 0.82328540, 0.82284981, 0.82241368, 0.82197714, 0.82154006, + 0.82110250, 0.82066447, 0.82022595, 0.81978697, 0.81934750, 0.81890756, 0.81846714, 0.81802619, + 0.81758481, 0.81714290, 0.81670058, 0.81625772, 0.81581444, 0.81537062, 0.81492633, 0.81448156, + 0.81403631, 0.81359059, 0.81314439, 0.81269777, 0.81225061, 0.81180298, 0.81135488, 0.81090623, + 0.81045717, 0.81000763, 0.80955762, 0.80910712, 0.80865616, 0.80820471, 0.80775285, 0.80730045, + 0.80684757, 0.80639422, 0.80594039, 0.80548608, 0.80503136, 0.80457610, 0.80412036, 0.80366421, + 0.80320752, 0.80275041, 0.80229282, 0.80183470, 0.80137616, 0.80091715, 0.80045766, 0.79999769, + 0.79953724, 0.79907638, 0.79861498, 0.79815316, 0.79769087, 0.79722804, 0.79676479, 0.79630107, + 0.79583693, 0.79537225, 0.79490715, 0.79444152, 0.79397547, 0.79350895, 0.79304194, 0.79257452, + 0.79210657, 0.79163820, 0.79116935, 0.79070002, 0.79023021, 0.78975999, 0.78928924, 0.78881806, + 0.78834641, 0.78787434, 0.78740174, 0.78692871, 0.78645521, 0.78598124, 0.78550684, 0.78503191, + 0.78455657, 0.78408080, 0.78360450, 0.78312778, 0.78265059, 0.78217292, 0.78169483, 0.78121626, + 0.78073722, 0.78025776, 0.77977777, 0.77929735, 0.77881652, 0.77833521, 0.77785343, 0.77737117, + 0.77688849, 0.77640533, 0.77592170, 0.77543765, 0.77495313, 0.77446812, 0.77398270, 0.77349681, + 0.77301043, 0.77252364, 0.77203637, 0.77154869, 0.77106053, 0.77057189, 0.77008283, 0.76959330, + 0.76910335, 0.76861292, 0.76812202, 0.76763070, 0.76713890, 0.76664668, 0.76615399, 0.76566088, + 0.76516724, 0.76467323, 0.76417875, 0.76368380, 0.76318842, 0.76269257, 0.76219630, 0.76169956, + 0.76120239, 0.76070476, 0.76020670, 0.75970817, 0.75920922, 0.75870979, 0.75820988, 0.75770962, + 0.75720882, 0.75670767, 0.75620598, 0.75570393, 0.75520140, 0.75469840, 0.75419497, 0.75369114, + 0.75318682, 0.75268203, 0.75217682, 0.75167120, 0.75116515, 0.75065863, 0.75015163, 0.74964422, + 0.74913639, 0.74862808, 0.74811935, 0.74761021, 0.74710059, 0.74659055, 0.74608010, 0.74556917, + 0.74505776, 0.74454600, 0.74403375, 0.74352109, 0.74300796, 0.74249440, 0.74198043, 0.74146599, + 0.74095112, 0.74043584, 0.73992008, 0.73940390, 0.73888731, 0.73837030, 0.73785281, 0.73733491, + 0.73681659, 0.73629779, 0.73577857, 0.73525894, 0.73473889, 0.73421836, 0.73369741, 0.73317605, + 0.73265427, 0.73213202, 0.73160940, 0.73108631, 0.73056275, 0.73003882, 0.72951442, 0.72898960, + 0.72846437, 0.72793871, 0.72741264, 0.72688609, 0.72635913, 0.72583181, 0.72530395, 0.72477573, + 0.72424710, 0.72371799, 0.72318846, 0.72265857, 0.72212821, 0.72159743, 0.72106618, 0.72053456, + 0.72000253, 0.71947002, 0.71893710, 0.71840382, 0.71787006, 0.71733588, 0.71680129, 0.71626627, + 0.71573085, 0.71519494, 0.71465868, 0.71412200, 0.71358484, 0.71304733, 0.71250939, 0.71197098, + 0.71143222, 0.71089298, 0.71035337, 0.70981330, 0.70927280, 0.70873195, 0.70819062, 0.70764893, + 0.70710677, 0.70656425, 0.70602125, 0.70547789, 0.70493406, 0.70438987, 0.70384526, 0.70330018, + 0.70275474, 0.70220888, 0.70166260, 0.70111591, 0.70056880, 0.70002127, 0.69947332, 0.69892502, + 0.69837624, 0.69782710, 0.69727749, 0.69672751, 0.69617712, 0.69562632, 0.69507509, 0.69452351, + 0.69397146, 0.69341904, 0.69286615, 0.69231290, 0.69175923, 0.69120520, 0.69065070, 0.69009584, + 0.68954057, 0.68898487, 0.68842876, 0.68787223, 0.68731534, 0.68675804, 0.68620032, 0.68564218, + 0.68508369, 0.68452471, 0.68396538, 0.68340570, 0.68284553, 0.68228501, 0.68172407, 0.68116271, + 0.68060100, 0.68003887, 0.67947632, 0.67891335, 0.67835003, 0.67778629, 0.67722219, 0.67665762, + 0.67609268, 0.67552739, 0.67496163, 0.67439550, 0.67382902, 0.67326206, 0.67269474, 0.67212707, + 0.67155898, 0.67099047, 0.67042154, 0.66985226, 0.66928262, 0.66871250, 0.66814202, 0.66757119, + 0.66699994, 0.66642827, 0.66585624, 0.66528380, 0.66471100, 0.66413778, 0.66356415, 0.66299015, + 0.66241580, 0.66184098, 0.66126585, 0.66069031, 0.66011435, 0.65953803, 0.65896130, 0.65838420, + 0.65780669, 0.65722883, 0.65665054, 0.65607190, 0.65549284, 0.65491343, 0.65433359, 0.65375340, + 0.65317285, 0.65259188, 0.65201056, 0.65142882, 0.65084666, 0.65026420, 0.64968133, 0.64909804, + 0.64851439, 0.64793038, 0.64734596, 0.64676118, 0.64617604, 0.64559048, 0.64500451, 0.64441824, + 0.64383155, 0.64324450, 0.64265704, 0.64206922, 0.64148104, 0.64089245, 0.64030349, 0.63971418, + 0.63912445, 0.63853437, 0.63794392, 0.63735306, 0.63676184, 0.63617027, 0.63557833, 0.63498598, + 0.63439327, 0.63380021, 0.63320678, 0.63261294, 0.63201874, 0.63142419, 0.63082922, 0.63023394, + 0.62963825, 0.62904221, 0.62844574, 0.62784898, 0.62725180, 0.62665427, 0.62605637, 0.62545812, + 0.62485951, 0.62426049, 0.62366110, 0.62306136, 0.62246126, 0.62186080, 0.62125999, 0.62065876, + 0.62005723, 0.61945528, 0.61885297, 0.61825031, 0.61764729, 0.61704391, 0.61644018, 0.61583608, + 0.61523157, 0.61462677, 0.61402154, 0.61341602, 0.61281008, 0.61220378, 0.61159718, 0.61099017, + 0.61038280, 0.60977507, 0.60916704, 0.60855860, 0.60794979, 0.60734063, 0.60673112, 0.60612124, + 0.60551107, 0.60490048, 0.60428953, 0.60367823, 0.60306662, 0.60245460, 0.60184222, 0.60122955, + 0.60061646, 0.60000306, 0.59938931, 0.59877521, 0.59816068, 0.59754586, 0.59693068, 0.59631521, + 0.59569931, 0.59508306, 0.59446651, 0.59384960, 0.59323227, 0.59261465, 0.59199667, 0.59137839, + 0.59075969, 0.59014070, 0.58952129, 0.58890158, 0.58828157, 0.58766115, 0.58704036, 0.58641928, + 0.58579785, 0.58517605, 0.58455396, 0.58393145, 0.58330864, 0.58268547, 0.58206201, 0.58143812, + 0.58081394, 0.58018941, 0.57956457, 0.57893932, 0.57831377, 0.57768792, 0.57706165, 0.57643509, + 0.57580817, 0.57518095, 0.57455337, 0.57392544, 0.57329714, 0.57266855, 0.57203960, 0.57141036, + 0.57078075, 0.57015079, 0.56952053, 0.56888992, 0.56825894, 0.56762767, 0.56699604, 0.56636411, + 0.56573182, 0.56509918, 0.56446624, 0.56383294, 0.56319934, 0.56256539, 0.56193113, 0.56129652, + 0.56066155, 0.56002629, 0.55939072, 0.55875480, 0.55811852, 0.55748194, 0.55684501, 0.55620778, + 0.55557024, 0.55493236, 0.55429411, 0.55365556, 0.55301672, 0.55237752, 0.55173796, 0.55109817, + 0.55045795, 0.54981750, 0.54917663, 0.54853553, 0.54789406, 0.54725230, 0.54661018, 0.54596776, + 0.54532498, 0.54468191, 0.54403853, 0.54339480, 0.54275078, 0.54210645, 0.54146177, 0.54081678, + 0.54017144, 0.53952587, 0.53887993, 0.53823364, 0.53758705, 0.53694016, 0.53629297, 0.53564548, + 0.53499764, 0.53434944, 0.53370100, 0.53305221, 0.53240311, 0.53175372, 0.53110403, 0.53045398, + 0.52980363, 0.52915299, 0.52850199, 0.52785075, 0.52719915, 0.52654725, 0.52589500, 0.52524251, + 0.52458966, 0.52393657, 0.52328312, 0.52262938, 0.52197528, 0.52132094, 0.52066624, 0.52001125, + 0.51935601, 0.51870042, 0.51804453, 0.51738828, 0.51673180, 0.51607502, 0.51541787, 0.51476043, + 0.51410276, 0.51344472, 0.51278639, 0.51212776, 0.51146883, 0.51080960, 0.51015007, 0.50949025, + 0.50883013, 0.50816971, 0.50750899, 0.50684798, 0.50618666, 0.50552505, 0.50486308, 0.50420088, + 0.50353837, 0.50287557, 0.50221246, 0.50154907, 0.50088537, 0.50022137, 0.49955711, 0.49889255, + 0.49822766, 0.49756250, 0.49689704, 0.49623129, 0.49556527, 0.49489895, 0.49423230, 0.49356541, + 0.49289820, 0.49223071, 0.49156290, 0.49089485, 0.49022648, 0.48955783, 0.48888889, 0.48821968, + 0.48755017, 0.48688036, 0.48621029, 0.48553991, 0.48486924, 0.48419830, 0.48352706, 0.48285556, + 0.48218378, 0.48151168, 0.48083934, 0.48016667, 0.47949377, 0.47882056, 0.47814706, 0.47747329, + 0.47679922, 0.47612488, 0.47545028, 0.47477537, 0.47410020, 0.47342476, 0.47274902, 0.47207302, + 0.47139674, 0.47072017, 0.47004333, 0.46936622, 0.46868882, 0.46801114, 0.46733320, 0.46665499, + 0.46597651, 0.46529773, 0.46461868, 0.46393937, 0.46325979, 0.46257994, 0.46189979, 0.46121940, + 0.46053872, 0.45985776, 0.45917654, 0.45849505, 0.45781329, 0.45713127, 0.45644897, 0.45576641, + 0.45508358, 0.45440048, 0.45371711, 0.45303348, 0.45234957, 0.45166543, 0.45098099, 0.45029628, + 0.44961134, 0.44892609, 0.44824061, 0.44755486, 0.44686884, 0.44618255, 0.44549602, 0.44480920, + 0.44412214, 0.44343480, 0.44274724, 0.44205937, 0.44137126, 0.44068289, 0.43999428, 0.43930539, + 0.43861625, 0.43792683, 0.43723717, 0.43654725, 0.43585709, 0.43516666, 0.43447596, 0.43378502, + 0.43309382, 0.43240237, 0.43171066, 0.43101871, 0.43032649, 0.42963400, 0.42894128, 0.42824832, + 0.42755508, 0.42686161, 0.42616788, 0.42547390, 0.42477968, 0.42408520, 0.42339048, 0.42269549, + 0.42200026, 0.42130479, 0.42060909, 0.41991311, 0.41921690, 0.41852042, 0.41782370, 0.41712677, + 0.41642955, 0.41573212, 0.41503441, 0.41433650, 0.41363832, 0.41293988, 0.41224122, 0.41154233, + 0.41084316, 0.41014379, 0.40944415, 0.40874428, 0.40804416, 0.40734380, 0.40664321, 0.40594238, + 0.40524131, 0.40454000, 0.40383846, 0.40313667, 0.40243465, 0.40173239, 0.40102988, 0.40032718, + 0.39962420, 0.39892101, 0.39821756, 0.39751390, 0.39681000, 0.39610586, 0.39540148, 0.39469686, + 0.39399204, 0.39328697, 0.39258167, 0.39187613, 0.39117038, 0.39046440, 0.38975817, 0.38905174, + 0.38834503, 0.38763815, 0.38693100, 0.38622364, 0.38551605, 0.38480824, 0.38410020, 0.38339192, + 0.38268343, 0.38197473, 0.38126576, 0.38055661, 0.37984720, 0.37913761, 0.37842774, 0.37771770, + 0.37700742, 0.37629691, 0.37558618, 0.37487522, 0.37416407, 0.37345266, 0.37274107, 0.37202924, + 0.37131721, 0.37060493, 0.36989245, 0.36917976, 0.36846682, 0.36775368, 0.36704034, 0.36632678, + 0.36561298, 0.36489901, 0.36418480, 0.36347038, 0.36275572, 0.36204088, 0.36132580, 0.36061051, + 0.35989505, 0.35917935, 0.35846341, 0.35774729, 0.35703096, 0.35631442, 0.35559767, 0.35488069, + 0.35416353, 0.35344616, 0.35272855, 0.35201076, 0.35129276, 0.35057455, 0.34985614, 0.34913751, + 0.34841868, 0.34769964, 0.34698042, 0.34626096, 0.34554133, 0.34482148, 0.34410143, 0.34338117, + 0.34266073, 0.34194008, 0.34121922, 0.34049815, 0.33977687, 0.33905542, 0.33833376, 0.33761191, + 0.33688986, 0.33616760, 0.33544514, 0.33472249, 0.33399966, 0.33327660, 0.33255336, 0.33182994, + 0.33110631, 0.33038250, 0.32965845, 0.32893425, 0.32820985, 0.32748523, 0.32676044, 0.32603547, + 0.32531029, 0.32458493, 0.32385936, 0.32313362, 0.32240769, 0.32168156, 0.32095525, 0.32022873, + 0.31950203, 0.31877515, 0.31804809, 0.31732082, 0.31659338, 0.31586576, 0.31513792, 0.31440994, + 0.31368175, 0.31295338, 0.31222481, 0.31149608, 0.31076714, 0.31003806, 0.30930877, 0.30857930, + 0.30784965, 0.30711982, 0.30638981, 0.30565959, 0.30492923, 0.30419868, 0.30346796, 0.30273703, + 0.30200595, 0.30127469, 0.30054325, 0.29981163, 0.29907984, 0.29834786, 0.29761571, 0.29688337, + 0.29615089, 0.29541820, 0.29468536, 0.29395235, 0.29321915, 0.29248580, 0.29175225, 0.29101855, + 0.29028466, 0.28955063, 0.28881642, 0.28808203, 0.28734747, 0.28661272, 0.28587782, 0.28514278, + 0.28440753, 0.28367212, 0.28293657, 0.28220084, 0.28146493, 0.28072888, 0.27999264, 0.27925625, + 0.27851969, 0.27778298, 0.27704608, 0.27630904, 0.27557182, 0.27483445, 0.27409691, 0.27335921, + 0.27262136, 0.27188334, 0.27114516, 0.27040681, 0.26966831, 0.26892966, 0.26819086, 0.26745188, + 0.26671275, 0.26597348, 0.26523402, 0.26449442, 0.26375467, 0.26301476, 0.26227471, 0.26153448, + 0.26079410, 0.26005360, 0.25931293, 0.25857207, 0.25783110, 0.25708997, 0.25634867, 0.25560725, + 0.25486565, 0.25412393, 0.25338203, 0.25264001, 0.25189781, 0.25115550, 0.25041300, 0.24967039, + 0.24892761, 0.24818468, 0.24744162, 0.24669841, 0.24595505, 0.24521154, 0.24446790, 0.24372411, + 0.24298018, 0.24223611, 0.24149188, 0.24074753, 0.24000302, 0.23925838, 0.23851359, 0.23776866, + 0.23702361, 0.23627840, 0.23553306, 0.23478758, 0.23404196, 0.23329620, 0.23255031, 0.23180428, + 0.23105811, 0.23031181, 0.22956537, 0.22881879, 0.22807208, 0.22732525, 0.22657827, 0.22583115, + 0.22508392, 0.22433653, 0.22358903, 0.22284140, 0.22209363, 0.22134572, 0.22059768, 0.21984953, + 0.21910124, 0.21835282, 0.21760428, 0.21685560, 0.21610680, 0.21535787, 0.21460882, 0.21385963, + 0.21311031, 0.21236089, 0.21161133, 0.21086164, 0.21011184, 0.20936191, 0.20861185, 0.20786168, + 0.20711137, 0.20636095, 0.20561041, 0.20485975, 0.20410897, 0.20335807, 0.20260704, 0.20185590, + 0.20110464, 0.20035325, 0.19960175, 0.19885014, 0.19809841, 0.19734657, 0.19659460, 0.19584252, + 0.19509032, 0.19433801, 0.19358559, 0.19283305, 0.19208039, 0.19132763, 0.19057475, 0.18982176, + 0.18906866, 0.18831545, 0.18756212, 0.18680869, 0.18605515, 0.18530150, 0.18454774, 0.18379387, + 0.18303989, 0.18228580, 0.18153161, 0.18077731, 0.18002290, 0.17926839, 0.17851377, 0.17775905, + 0.17700422, 0.17624930, 0.17549425, 0.17473911, 0.17398387, 0.17322853, 0.17247309, 0.17171754, + 0.17096189, 0.17020614, 0.16945030, 0.16869435, 0.16793829, 0.16718215, 0.16642590, 0.16566956, + 0.16491312, 0.16415659, 0.16339995, 0.16264322, 0.16188639, 0.16112947, 0.16037245, 0.15961535, + 0.15885815, 0.15810084, 0.15734346, 0.15658598, 0.15582840, 0.15507074, 0.15431297, 0.15355512, + 0.15279719, 0.15203916, 0.15128104, 0.15052283, 0.14976454, 0.14900614, 0.14824767, 0.14748912, + 0.14673047, 0.14597175, 0.14521292, 0.14445402, 0.14369503, 0.14293596, 0.14217681, 0.14141756, + 0.14065824, 0.13989884, 0.13913934, 0.13837977, 0.13762012, 0.13686039, 0.13610058, 0.13534068, + 0.13458070, 0.13382065, 0.13306053, 0.13230032, 0.13154003, 0.13077967, 0.13001922, 0.12925871, + 0.12849811, 0.12773745, 0.12697670, 0.12621588, 0.12545498, 0.12469402, 0.12393297, 0.12317186, + 0.12241068, 0.12164941, 0.12088808, 0.12012669, 0.11936522, 0.11860368, 0.11784206, 0.11708038, + 0.11631863, 0.11555681, 0.11479492, 0.11403298, 0.11327095, 0.11250886, 0.11174671, 0.11098449, + 0.11022221, 0.10945985, 0.10869744, 0.10793497, 0.10717242, 0.10640982, 0.10564715, 0.10488442, + 0.10412163, 0.10335878, 0.10259587, 0.10183290, 0.10106986, 0.10030677, 0.09954362, 0.09878041, + 0.09801714, 0.09725381, 0.09649043, 0.09572699, 0.09496350, 0.09419994, 0.09343634, 0.09267268, + 0.09190895, 0.09114519, 0.09038136, 0.08961748, 0.08885355, 0.08808957, 0.08732554, 0.08656145, + 0.08579731, 0.08503313, 0.08426889, 0.08350460, 0.08274026, 0.08197588, 0.08121145, 0.08044697, + 0.07968244, 0.07891786, 0.07815325, 0.07738858, 0.07662386, 0.07585911, 0.07509430, 0.07432945, + 0.07356457, 0.07279963, 0.07203465, 0.07126963, 0.07050458, 0.06973947, 0.06897433, 0.06820914, + 0.06744392, 0.06667866, 0.06591335, 0.06514801, 0.06438263, 0.06361721, 0.06285176, 0.06208627, + 0.06132074, 0.06055517, 0.05978957, 0.05902394, 0.05825827, 0.05749256, 0.05672682, 0.05596105, + 0.05519525, 0.05442941, 0.05366354, 0.05289764, 0.05213170, 0.05136574, 0.05059975, 0.04983373, + 0.04906768, 0.04830159, 0.04753548, 0.04676935, 0.04600318, 0.04523699, 0.04447077, 0.04370453, + 0.04293826, 0.04217196, 0.04140564, 0.04063930, 0.03987293, 0.03910654, 0.03834012, 0.03757368, + 0.03680722, 0.03604074, 0.03527424, 0.03450771, 0.03374117, 0.03297461, 0.03220803, 0.03144142, + 0.03067480, 0.02990817, 0.02914151, 0.02837484, 0.02760815, 0.02684144, 0.02607472, 0.02530798, + 0.02454123, 0.02377446, 0.02300768, 0.02224089, 0.02147408, 0.02070726, 0.01994043, 0.01917358, + 0.01840673, 0.01763986, 0.01687299, 0.01610610, 0.01533921, 0.01457230, 0.01380539, 0.01303847, + 0.01227154, 0.01150460, 0.01073766, 0.00997071, 0.00920375, 0.00843679, 0.00766983, 0.00690286, + 0.00613588, 0.00536891, 0.00460193, 0.00383494, 0.00306796, 0.00230097, 0.00153398, 0.00076699, + 0.00000000, -0.00076699, -0.00153398, -0.00230097, -0.00306796, -0.00383494, -0.00460193, -0.00536891, + -0.00613588, -0.00690286, -0.00766983, -0.00843679, -0.00920375, -0.00997071, -0.01073766, -0.01150460, + -0.01227154, -0.01303847, -0.01380539, -0.01457230, -0.01533921, -0.01610610, -0.01687299, -0.01763986, + -0.01840673, -0.01917358, -0.01994043, -0.02070726, -0.02147408, -0.02224089, -0.02300768, -0.02377446, + -0.02454123, -0.02530798, -0.02607472, -0.02684144, -0.02760815, -0.02837484, -0.02914151, -0.02990817, + -0.03067480, -0.03144142, -0.03220803, -0.03297461, -0.03374117, -0.03450771, -0.03527424, -0.03604074, + -0.03680722, -0.03757368, -0.03834012, -0.03910654, -0.03987293, -0.04063930, -0.04140564, -0.04217196, + -0.04293826, -0.04370453, -0.04447077, -0.04523699, -0.04600318, -0.04676935, -0.04753548, -0.04830159, + -0.04906768, -0.04983373, -0.05059975, -0.05136574, -0.05213170, -0.05289764, -0.05366354, -0.05442941, + -0.05519525, -0.05596105, -0.05672682, -0.05749256, -0.05825827, -0.05902394, -0.05978957, -0.06055517, + -0.06132074, -0.06208627, -0.06285176, -0.06361721, -0.06438263, -0.06514801, -0.06591335, -0.06667866, + -0.06744392, -0.06820914, -0.06897433, -0.06973947, -0.07050458, -0.07126963, -0.07203465, -0.07279963, + -0.07356457, -0.07432945, -0.07509430, -0.07585911, -0.07662386, -0.07738858, -0.07815325, -0.07891786, + -0.07968244, -0.08044697, -0.08121145, -0.08197588, -0.08274026, -0.08350460, -0.08426889, -0.08503313, + -0.08579731, -0.08656145, -0.08732554, -0.08808957, -0.08885355, -0.08961748, -0.09038136, -0.09114519, + -0.09190895, -0.09267268, -0.09343634, -0.09419994, -0.09496350, -0.09572699, -0.09649043, -0.09725381, + -0.09801714, -0.09878041, -0.09954362, -0.10030677, -0.10106986, -0.10183290, -0.10259587, -0.10335878, + -0.10412163, -0.10488442, -0.10564715, -0.10640982, -0.10717242, -0.10793497, -0.10869744, -0.10945985, + -0.11022221, -0.11098449, -0.11174671, -0.11250886, -0.11327095, -0.11403298, -0.11479492, -0.11555681, + -0.11631863, -0.11708038, -0.11784206, -0.11860368, -0.11936522, -0.12012669, -0.12088808, -0.12164941, + -0.12241068, -0.12317186, -0.12393297, -0.12469402, -0.12545498, -0.12621588, -0.12697670, -0.12773745, + -0.12849811, -0.12925871, -0.13001922, -0.13077967, -0.13154003, -0.13230032, -0.13306053, -0.13382065, + -0.13458070, -0.13534068, -0.13610058, -0.13686039, -0.13762012, -0.13837977, -0.13913934, -0.13989884, + -0.14065824, -0.14141756, -0.14217681, -0.14293596, -0.14369503, -0.14445402, -0.14521292, -0.14597175, + -0.14673047, -0.14748912, -0.14824767, -0.14900614, -0.14976454, -0.15052283, -0.15128104, -0.15203916, + -0.15279719, -0.15355512, -0.15431297, -0.15507074, -0.15582840, -0.15658598, -0.15734346, -0.15810084, + -0.15885815, -0.15961535, -0.16037245, -0.16112947, -0.16188639, -0.16264322, -0.16339995, -0.16415659, + -0.16491312, -0.16566956, -0.16642590, -0.16718215, -0.16793829, -0.16869435, -0.16945030, -0.17020614, + -0.17096189, -0.17171754, -0.17247309, -0.17322853, -0.17398387, -0.17473911, -0.17549425, -0.17624930, + -0.17700422, -0.17775905, -0.17851377, -0.17926839, -0.18002290, -0.18077731, -0.18153161, -0.18228580, + -0.18303989, -0.18379387, -0.18454774, -0.18530150, -0.18605515, -0.18680869, -0.18756212, -0.18831545, + -0.18906866, -0.18982176, -0.19057475, -0.19132763, -0.19208039, -0.19283305, -0.19358559, -0.19433801, + -0.19509032, -0.19584252, -0.19659460, -0.19734657, -0.19809841, -0.19885014, -0.19960175, -0.20035325, + -0.20110464, -0.20185590, -0.20260704, -0.20335807, -0.20410897, -0.20485975, -0.20561041, -0.20636095, + -0.20711137, -0.20786168, -0.20861185, -0.20936191, -0.21011184, -0.21086164, -0.21161133, -0.21236089, + -0.21311031, -0.21385963, -0.21460882, -0.21535787, -0.21610680, -0.21685560, -0.21760428, -0.21835282, + -0.21910124, -0.21984953, -0.22059768, -0.22134572, -0.22209363, -0.22284140, -0.22358903, -0.22433653, + -0.22508392, -0.22583115, -0.22657827, -0.22732525, -0.22807208, -0.22881879, -0.22956537, -0.23031181, + -0.23105811, -0.23180428, -0.23255031, -0.23329620, -0.23404196, -0.23478758, -0.23553306, -0.23627840, + -0.23702361, -0.23776866, -0.23851359, -0.23925838, -0.24000302, -0.24074753, -0.24149188, -0.24223611, + -0.24298018, -0.24372411, -0.24446790, -0.24521154, -0.24595505, -0.24669841, -0.24744162, -0.24818468, + -0.24892761, -0.24967039, -0.25041300, -0.25115550, -0.25189781, -0.25264001, -0.25338203, -0.25412393, + -0.25486565, -0.25560725, -0.25634867, -0.25708997, -0.25783110, -0.25857207, -0.25931293, -0.26005360, + -0.26079410, -0.26153448, -0.26227471, -0.26301476, -0.26375467, -0.26449442, -0.26523402, -0.26597348, + -0.26671275, -0.26745188, -0.26819086, -0.26892966, -0.26966831, -0.27040681, -0.27114516, -0.27188334, + -0.27262136, -0.27335921, -0.27409691, -0.27483445, -0.27557182, -0.27630904, -0.27704608, -0.27778298, + -0.27851969, -0.27925625, -0.27999264, -0.28072888, -0.28146493, -0.28220084, -0.28293657, -0.28367212, + -0.28440753, -0.28514278, -0.28587782, -0.28661272, -0.28734747, -0.28808203, -0.28881642, -0.28955063, + -0.29028466, -0.29101855, -0.29175225, -0.29248580, -0.29321915, -0.29395235, -0.29468536, -0.29541820, + -0.29615089, -0.29688337, -0.29761571, -0.29834786, -0.29907984, -0.29981163, -0.30054325, -0.30127469, + -0.30200595, -0.30273703, -0.30346796, -0.30419868, -0.30492923, -0.30565959, -0.30638981, -0.30711982, + -0.30784965, -0.30857930, -0.30930877, -0.31003806, -0.31076714, -0.31149608, -0.31222481, -0.31295338, + -0.31368175, -0.31440994, -0.31513792, -0.31586576, -0.31659338, -0.31732082, -0.31804809, -0.31877515, + -0.31950203, -0.32022873, -0.32095525, -0.32168156, -0.32240769, -0.32313362, -0.32385936, -0.32458493, + -0.32531029, -0.32603547, -0.32676044, -0.32748523, -0.32820985, -0.32893425, -0.32965845, -0.33038250, + -0.33110631, -0.33182994, -0.33255336, -0.33327660, -0.33399966, -0.33472249, -0.33544514, -0.33616760, + -0.33688986, -0.33761191, -0.33833376, -0.33905542, -0.33977687, -0.34049815, -0.34121922, -0.34194008, + -0.34266073, -0.34338117, -0.34410143, -0.34482148, -0.34554133, -0.34626096, -0.34698042, -0.34769964, + -0.34841868, -0.34913751, -0.34985614, -0.35057455, -0.35129276, -0.35201076, -0.35272855, -0.35344616, + -0.35416353, -0.35488069, -0.35559767, -0.35631442, -0.35703096, -0.35774729, -0.35846341, -0.35917935, + -0.35989505, -0.36061051, -0.36132580, -0.36204088, -0.36275572, -0.36347038, -0.36418480, -0.36489901, + -0.36561298, -0.36632678, -0.36704034, -0.36775368, -0.36846682, -0.36917976, -0.36989245, -0.37060493, + -0.37131721, -0.37202924, -0.37274107, -0.37345266, -0.37416407, -0.37487522, -0.37558618, -0.37629691, + -0.37700742, -0.37771770, -0.37842774, -0.37913761, -0.37984720, -0.38055661, -0.38126576, -0.38197473, + -0.38268343, -0.38339192, -0.38410020, -0.38480824, -0.38551605, -0.38622364, -0.38693100, -0.38763815, + -0.38834503, -0.38905174, -0.38975817, -0.39046440, -0.39117038, -0.39187613, -0.39258167, -0.39328697, + -0.39399204, -0.39469686, -0.39540148, -0.39610586, -0.39681000, -0.39751390, -0.39821756, -0.39892101, + -0.39962420, -0.40032718, -0.40102988, -0.40173239, -0.40243465, -0.40313667, -0.40383846, -0.40454000, + -0.40524131, -0.40594238, -0.40664321, -0.40734380, -0.40804416, -0.40874428, -0.40944415, -0.41014379, + -0.41084316, -0.41154233, -0.41224122, -0.41293988, -0.41363832, -0.41433650, -0.41503441, -0.41573212, + -0.41642955, -0.41712677, -0.41782370, -0.41852042, -0.41921690, -0.41991311, -0.42060909, -0.42130479, + -0.42200026, -0.42269549, -0.42339048, -0.42408520, -0.42477968, -0.42547390, -0.42616788, -0.42686161, + -0.42755508, -0.42824832, -0.42894128, -0.42963400, -0.43032649, -0.43101871, -0.43171066, -0.43240237, + -0.43309382, -0.43378502, -0.43447596, -0.43516666, -0.43585709, -0.43654725, -0.43723717, -0.43792683, + -0.43861625, -0.43930539, -0.43999428, -0.44068289, -0.44137126, -0.44205937, -0.44274724, -0.44343480, + -0.44412214, -0.44480920, -0.44549602, -0.44618255, -0.44686884, -0.44755486, -0.44824061, -0.44892609, + -0.44961134, -0.45029628, -0.45098099, -0.45166543, -0.45234957, -0.45303348, -0.45371711, -0.45440048, + -0.45508358, -0.45576641, -0.45644897, -0.45713127, -0.45781329, -0.45849505, -0.45917654, -0.45985776, + -0.46053872, -0.46121940, -0.46189979, -0.46257994, -0.46325979, -0.46393937, -0.46461868, -0.46529773, + -0.46597651, -0.46665499, -0.46733320, -0.46801114, -0.46868882, -0.46936622, -0.47004333, -0.47072017, + -0.47139674, -0.47207302, -0.47274902, -0.47342476, -0.47410020, -0.47477537, -0.47545028, -0.47612488, + -0.47679922, -0.47747329, -0.47814706, -0.47882056, -0.47949377, -0.48016667, -0.48083934, -0.48151168, + -0.48218378, -0.48285556, -0.48352706, -0.48419830, -0.48486924, -0.48553991, -0.48621029, -0.48688036, + -0.48755017, -0.48821968, -0.48888889, -0.48955783, -0.49022648, -0.49089485, -0.49156290, -0.49223071, + -0.49289820, -0.49356541, -0.49423230, -0.49489895, -0.49556527, -0.49623129, -0.49689704, -0.49756250, + -0.49822766, -0.49889255, -0.49955711, -0.50022137, -0.50088537, -0.50154907, -0.50221246, -0.50287557, + -0.50353837, -0.50420088, -0.50486308, -0.50552505, -0.50618666, -0.50684798, -0.50750899, -0.50816971, + -0.50883013, -0.50949025, -0.51015007, -0.51080960, -0.51146883, -0.51212776, -0.51278639, -0.51344472, + -0.51410276, -0.51476043, -0.51541787, -0.51607502, -0.51673180, -0.51738828, -0.51804453, -0.51870042, + -0.51935601, -0.52001125, -0.52066624, -0.52132094, -0.52197528, -0.52262938, -0.52328312, -0.52393657, + -0.52458966, -0.52524251, -0.52589500, -0.52654725, -0.52719915, -0.52785075, -0.52850199, -0.52915299, + -0.52980363, -0.53045398, -0.53110403, -0.53175372, -0.53240311, -0.53305221, -0.53370100, -0.53434944, + -0.53499764, -0.53564548, -0.53629297, -0.53694016, -0.53758705, -0.53823364, -0.53887993, -0.53952587, + -0.54017144, -0.54081678, -0.54146177, -0.54210645, -0.54275078, -0.54339480, -0.54403853, -0.54468191, + -0.54532498, -0.54596776, -0.54661018, -0.54725230, -0.54789406, -0.54853553, -0.54917663, -0.54981750, + -0.55045795, -0.55109817, -0.55173796, -0.55237752, -0.55301672, -0.55365556, -0.55429411, -0.55493236, + -0.55557024, -0.55620778, -0.55684501, -0.55748194, -0.55811852, -0.55875480, -0.55939072, -0.56002629, + -0.56066155, -0.56129652, -0.56193113, -0.56256539, -0.56319934, -0.56383294, -0.56446624, -0.56509918, + -0.56573182, -0.56636411, -0.56699604, -0.56762767, -0.56825894, -0.56888992, -0.56952053, -0.57015079, + -0.57078075, -0.57141036, -0.57203960, -0.57266855, -0.57329714, -0.57392544, -0.57455337, -0.57518095, + -0.57580817, -0.57643509, -0.57706165, -0.57768792, -0.57831377, -0.57893932, -0.57956457, -0.58018941, + -0.58081394, -0.58143812, -0.58206201, -0.58268547, -0.58330864, -0.58393145, -0.58455396, -0.58517605, + -0.58579785, -0.58641928, -0.58704036, -0.58766115, -0.58828157, -0.58890158, -0.58952129, -0.59014070, + -0.59075969, -0.59137839, -0.59199667, -0.59261465, -0.59323227, -0.59384960, -0.59446651, -0.59508306, + -0.59569931, -0.59631521, -0.59693068, -0.59754586, -0.59816068, -0.59877521, -0.59938931, -0.60000306, + -0.60061646, -0.60122955, -0.60184222, -0.60245460, -0.60306662, -0.60367823, -0.60428953, -0.60490048, + -0.60551107, -0.60612124, -0.60673112, -0.60734063, -0.60794979, -0.60855860, -0.60916704, -0.60977507, + -0.61038280, -0.61099017, -0.61159718, -0.61220378, -0.61281008, -0.61341602, -0.61402154, -0.61462677, + -0.61523157, -0.61583608, -0.61644018, -0.61704391, -0.61764729, -0.61825031, -0.61885297, -0.61945528, + -0.62005723, -0.62065876, -0.62125999, -0.62186080, -0.62246126, -0.62306136, -0.62366110, -0.62426049, + -0.62485951, -0.62545812, -0.62605637, -0.62665427, -0.62725180, -0.62784898, -0.62844574, -0.62904221, + -0.62963825, -0.63023394, -0.63082922, -0.63142419, -0.63201874, -0.63261294, -0.63320678, -0.63380021, + -0.63439327, -0.63498598, -0.63557833, -0.63617027, -0.63676184, -0.63735306, -0.63794392, -0.63853437, + -0.63912445, -0.63971418, -0.64030349, -0.64089245, -0.64148104, -0.64206922, -0.64265704, -0.64324450, + -0.64383155, -0.64441824, -0.64500451, -0.64559048, -0.64617604, -0.64676118, -0.64734596, -0.64793038, + -0.64851439, -0.64909804, -0.64968133, -0.65026420, -0.65084666, -0.65142882, -0.65201056, -0.65259188, + -0.65317285, -0.65375340, -0.65433359, -0.65491343, -0.65549284, -0.65607190, -0.65665054, -0.65722883, + -0.65780669, -0.65838420, -0.65896130, -0.65953803, -0.66011435, -0.66069031, -0.66126585, -0.66184098, + -0.66241580, -0.66299015, -0.66356415, -0.66413778, -0.66471100, -0.66528380, -0.66585624, -0.66642827, + -0.66699994, -0.66757119, -0.66814202, -0.66871250, -0.66928262, -0.66985226, -0.67042154, -0.67099047, + -0.67155898, -0.67212707, -0.67269474, -0.67326206, -0.67382902, -0.67439550, -0.67496163, -0.67552739, + -0.67609268, -0.67665762, -0.67722219, -0.67778629, -0.67835003, -0.67891335, -0.67947632, -0.68003887, + -0.68060100, -0.68116271, -0.68172407, -0.68228501, -0.68284553, -0.68340570, -0.68396538, -0.68452471, + -0.68508369, -0.68564218, -0.68620032, -0.68675804, -0.68731534, -0.68787223, -0.68842876, -0.68898487, + -0.68954057, -0.69009584, -0.69065070, -0.69120520, -0.69175923, -0.69231290, -0.69286615, -0.69341904, + -0.69397146, -0.69452351, -0.69507509, -0.69562632, -0.69617712, -0.69672751, -0.69727749, -0.69782710, + -0.69837624, -0.69892502, -0.69947332, -0.70002127, -0.70056880, -0.70111591, -0.70166260, -0.70220888, + -0.70275474, -0.70330018, -0.70384526, -0.70438987, -0.70493406, -0.70547789, -0.70602125, -0.70656425, + -0.70710677, -0.70764893, -0.70819062, -0.70873195, -0.70927280, -0.70981330, -0.71035337, -0.71089298, + -0.71143222, -0.71197098, -0.71250939, -0.71304733, -0.71358484, -0.71412200, -0.71465868, -0.71519494, + -0.71573085, -0.71626627, -0.71680129, -0.71733588, -0.71787006, -0.71840382, -0.71893710, -0.71947002, + -0.72000253, -0.72053456, -0.72106618, -0.72159743, -0.72212821, -0.72265857, -0.72318846, -0.72371799, + -0.72424710, -0.72477573, -0.72530395, -0.72583181, -0.72635913, -0.72688609, -0.72741264, -0.72793871, + -0.72846437, -0.72898960, -0.72951442, -0.73003882, -0.73056275, -0.73108631, -0.73160940, -0.73213202, + -0.73265427, -0.73317605, -0.73369741, -0.73421836, -0.73473889, -0.73525894, -0.73577857, -0.73629779, + -0.73681659, -0.73733491, -0.73785281, -0.73837030, -0.73888731, -0.73940390, -0.73992008, -0.74043584, + -0.74095112, -0.74146599, -0.74198043, -0.74249440, -0.74300796, -0.74352109, -0.74403375, -0.74454600, + -0.74505776, -0.74556917, -0.74608010, -0.74659055, -0.74710059, -0.74761021, -0.74811935, -0.74862808, + -0.74913639, -0.74964422, -0.75015163, -0.75065863, -0.75116515, -0.75167120, -0.75217682, -0.75268203, + -0.75318682, -0.75369114, -0.75419497, -0.75469840, -0.75520140, -0.75570393, -0.75620598, -0.75670767, + -0.75720882, -0.75770962, -0.75820988, -0.75870979, -0.75920922, -0.75970817, -0.76020670, -0.76070476, + -0.76120239, -0.76169956, -0.76219630, -0.76269257, -0.76318842, -0.76368380, -0.76417875, -0.76467323, + -0.76516724, -0.76566088, -0.76615399, -0.76664668, -0.76713890, -0.76763070, -0.76812202, -0.76861292, + -0.76910335, -0.76959330, -0.77008283, -0.77057189, -0.77106053, -0.77154869, -0.77203637, -0.77252364, + -0.77301043, -0.77349681, -0.77398270, -0.77446812, -0.77495313, -0.77543765, -0.77592170, -0.77640533, + -0.77688849, -0.77737117, -0.77785343, -0.77833521, -0.77881652, -0.77929735, -0.77977777, -0.78025776, + -0.78073722, -0.78121626, -0.78169483, -0.78217292, -0.78265059, -0.78312778, -0.78360450, -0.78408080, + -0.78455657, -0.78503191, -0.78550684, -0.78598124, -0.78645521, -0.78692871, -0.78740174, -0.78787434, + -0.78834641, -0.78881806, -0.78928924, -0.78975999, -0.79023021, -0.79070002, -0.79116935, -0.79163820, + -0.79210657, -0.79257452, -0.79304194, -0.79350895, -0.79397547, -0.79444152, -0.79490715, -0.79537225, + -0.79583693, -0.79630107, -0.79676479, -0.79722804, -0.79769087, -0.79815316, -0.79861498, -0.79907638, + -0.79953724, -0.79999769, -0.80045766, -0.80091715, -0.80137616, -0.80183470, -0.80229282, -0.80275041, + -0.80320752, -0.80366421, -0.80412036, -0.80457610, -0.80503136, -0.80548608, -0.80594039, -0.80639422, + -0.80684757, -0.80730045, -0.80775285, -0.80820471, -0.80865616, -0.80910712, -0.80955762, -0.81000763, + -0.81045717, -0.81090623, -0.81135488, -0.81180298, -0.81225061, -0.81269777, -0.81314439, -0.81359059, + -0.81403631, -0.81448156, -0.81492633, -0.81537062, -0.81581444, -0.81625772, -0.81670058, -0.81714290, + -0.81758481, -0.81802619, -0.81846714, -0.81890756, -0.81934750, -0.81978697, -0.82022595, -0.82066447, + -0.82110250, -0.82154006, -0.82197714, -0.82241368, -0.82284981, -0.82328540, -0.82372051, -0.82415515, + -0.82458931, -0.82502300, -0.82545614, -0.82588887, -0.82632107, -0.82675278, -0.82718402, -0.82761478, + -0.82804507, -0.82847482, -0.82890409, -0.82933295, -0.82976121, -0.83018905, -0.83061641, -0.83104324, + -0.83146960, -0.83189547, -0.83232087, -0.83274579, -0.83317018, -0.83359408, -0.83401752, -0.83444041, + -0.83486289, -0.83528483, -0.83570629, -0.83612728, -0.83654773, -0.83696771, -0.83738720, -0.83780622, + -0.83822471, -0.83864272, -0.83906025, -0.83947724, -0.83989382, -0.84030986, -0.84072536, -0.84114045, + -0.84155500, -0.84196901, -0.84238261, -0.84279567, -0.84320825, -0.84362030, -0.84403187, -0.84444296, + -0.84485358, -0.84526366, -0.84567326, -0.84608233, -0.84649092, -0.84689903, -0.84730661, -0.84771377, + -0.84812033, -0.84852648, -0.84893203, -0.84933716, -0.84974176, -0.85014588, -0.85054946, -0.85095257, + -0.85135520, -0.85175729, -0.85215890, -0.85255998, -0.85296059, -0.85336071, -0.85376030, -0.85415941, + -0.85455799, -0.85495609, -0.85535365, -0.85575074, -0.85614735, -0.85654342, -0.85693896, -0.85733402, + -0.85772860, -0.85812265, -0.85851622, -0.85890925, -0.85930181, -0.85969388, -0.86008537, -0.86047643, + -0.86086696, -0.86125696, -0.86164647, -0.86203545, -0.86242396, -0.86281192, -0.86319941, -0.86358637, + -0.86397284, -0.86435878, -0.86474425, -0.86512917, -0.86551362, -0.86589754, -0.86628097, -0.86666387, + -0.86704624, -0.86742812, -0.86780947, -0.86819035, -0.86857069, -0.86895055, -0.86932987, -0.86970866, + -0.87008697, -0.87046480, -0.87084204, -0.87121886, -0.87159508, -0.87197083, -0.87234604, -0.87272078, + -0.87309498, -0.87346870, -0.87384182, -0.87421453, -0.87458664, -0.87495828, -0.87532938, -0.87570000, + -0.87607008, -0.87643969, -0.87680870, -0.87717724, -0.87754530, -0.87791282, -0.87827981, -0.87864625, + -0.87901223, -0.87937766, -0.87974262, -0.88010699, -0.88047087, -0.88083428, -0.88119709, -0.88155943, + -0.88192129, -0.88228256, -0.88264334, -0.88300359, -0.88336337, -0.88372254, -0.88408124, -0.88443947, + -0.88479710, -0.88515425, -0.88551086, -0.88586694, -0.88622254, -0.88657761, -0.88693213, -0.88728613, + -0.88763964, -0.88799256, -0.88834506, -0.88869697, -0.88904834, -0.88939923, -0.88974959, -0.89009941, + -0.89044875, -0.89079750, -0.89114577, -0.89149350, -0.89184070, -0.89218742, -0.89253354, -0.89287919, + -0.89322430, -0.89356887, -0.89391297, -0.89425647, -0.89459950, -0.89494199, -0.89528394, -0.89562535, + -0.89596623, -0.89630663, -0.89664650, -0.89698577, -0.89732456, -0.89766282, -0.89800060, -0.89833778, + -0.89867449, -0.89901060, -0.89934623, -0.89968133, -0.90001589, -0.90034992, -0.90068340, -0.90101641, + -0.90134883, -0.90168077, -0.90201217, -0.90234298, -0.90267330, -0.90300310, -0.90333235, -0.90366107, + -0.90398932, -0.90431696, -0.90464407, -0.90497071, -0.90529674, -0.90562230, -0.90594727, -0.90627176, + -0.90659571, -0.90691912, -0.90724200, -0.90756434, -0.90788609, -0.90820736, -0.90852809, -0.90884835, + -0.90916800, -0.90948713, -0.90980572, -0.91012377, -0.91044128, -0.91075826, -0.91107476, -0.91139066, + -0.91170603, -0.91202086, -0.91233516, -0.91264898, -0.91296220, -0.91327488, -0.91358703, -0.91389865, + -0.91420978, -0.91452032, -0.91483033, -0.91513979, -0.91544873, -0.91575712, -0.91606498, -0.91637230, + -0.91667908, -0.91698527, -0.91729099, -0.91759616, -0.91790080, -0.91820484, -0.91850841, -0.91881138, + -0.91911387, -0.91941577, -0.91971713, -0.92001796, -0.92031831, -0.92061806, -0.92091721, -0.92121589, + -0.92151403, -0.92181164, -0.92210865, -0.92240518, -0.92270112, -0.92299652, -0.92329144, -0.92358577, + -0.92387950, -0.92417276, -0.92446548, -0.92475760, -0.92504925, -0.92534029, -0.92563081, -0.92592078, + -0.92621022, -0.92649913, -0.92678750, -0.92707527, -0.92736250, -0.92764926, -0.92793542, -0.92822099, + -0.92850608, -0.92879063, -0.92907459, -0.92935801, -0.92964089, -0.92992324, -0.93020505, -0.93048626, + -0.93076694, -0.93104708, -0.93132669, -0.93160576, -0.93188429, -0.93216223, -0.93243963, -0.93271649, + -0.93299282, -0.93326855, -0.93354380, -0.93381846, -0.93409252, -0.93436611, -0.93463916, -0.93491161, + -0.93518353, -0.93545485, -0.93572569, -0.93599594, -0.93626565, -0.93653482, -0.93680346, -0.93707150, + -0.93733901, -0.93760598, -0.93787235, -0.93813825, -0.93840355, -0.93866831, -0.93893248, -0.93919611, + -0.93945920, -0.93972176, -0.93998373, -0.94024521, -0.94050604, -0.94076639, -0.94102615, -0.94128537, + -0.94154406, -0.94180220, -0.94205976, -0.94231677, -0.94257319, -0.94282907, -0.94308442, -0.94333923, + -0.94359344, -0.94384712, -0.94410026, -0.94435281, -0.94460481, -0.94485629, -0.94510722, -0.94535756, + -0.94560730, -0.94585657, -0.94610524, -0.94635338, -0.94660091, -0.94684792, -0.94709438, -0.94734025, + -0.94758558, -0.94783038, -0.94807458, -0.94831824, -0.94856137, -0.94880390, -0.94904590, -0.94928730, + -0.94952816, -0.94976848, -0.95000827, -0.95024747, -0.95048606, -0.95072412, -0.95096165, -0.95119864, + -0.95143503, -0.95167089, -0.95190614, -0.95214087, -0.95237499, -0.95260859, -0.95284164, -0.95307410, + -0.95330602, -0.95353740, -0.95376819, -0.95399845, -0.95422810, -0.95445722, -0.95468575, -0.95491374, + -0.95514119, -0.95536804, -0.95559436, -0.95582008, -0.95604527, -0.95626986, -0.95649391, -0.95671743, + -0.95694035, -0.95716268, -0.95738453, -0.95760572, -0.95782644, -0.95804650, -0.95826608, -0.95848507, + -0.95870346, -0.95892131, -0.95913863, -0.95935535, -0.95957154, -0.95978713, -0.96000212, -0.96021664, + -0.96043050, -0.96064389, -0.96085662, -0.96106887, -0.96128047, -0.96149158, -0.96170205, -0.96191204, + -0.96212143, -0.96233022, -0.96253848, -0.96274614, -0.96295327, -0.96315980, -0.96336579, -0.96357119, + -0.96377605, -0.96398038, -0.96418405, -0.96438724, -0.96458977, -0.96479183, -0.96499324, -0.96519411, + -0.96539444, -0.96559417, -0.96579337, -0.96599197, -0.96618998, -0.96638745, -0.96658438, -0.96678072, + -0.96697646, -0.96717167, -0.96736628, -0.96756035, -0.96775383, -0.96794677, -0.96813911, -0.96833086, + -0.96852207, -0.96871275, -0.96890283, -0.96909231, -0.96928126, -0.96946961, -0.96965736, -0.96984458, + -0.97003126, -0.97021735, -0.97040284, -0.97058779, -0.97077215, -0.97095591, -0.97113913, -0.97132182, + -0.97150391, -0.97168541, -0.97186631, -0.97204673, -0.97222650, -0.97240573, -0.97258437, -0.97276247, + -0.97293997, -0.97311687, -0.97329324, -0.97346902, -0.97364426, -0.97381890, -0.97399294, -0.97416645, + -0.97433937, -0.97451174, -0.97468352, -0.97485471, -0.97502536, -0.97519541, -0.97536486, -0.97553378, + -0.97570211, -0.97586989, -0.97603709, -0.97620368, -0.97636974, -0.97653520, -0.97670007, -0.97686440, + -0.97702813, -0.97719133, -0.97735387, -0.97751594, -0.97767735, -0.97783822, -0.97799850, -0.97815824, + -0.97831738, -0.97847593, -0.97863394, -0.97879136, -0.97894818, -0.97910446, -0.97926015, -0.97941524, + -0.97956979, -0.97972375, -0.97987711, -0.98002988, -0.98018211, -0.98033381, -0.98048484, -0.98063534, + -0.98078525, -0.98093462, -0.98108339, -0.98123157, -0.98137921, -0.98152626, -0.98167270, -0.98181856, + -0.98196387, -0.98210859, -0.98225272, -0.98239630, -0.98253930, -0.98268169, -0.98282355, -0.98296481, + -0.98310548, -0.98324561, -0.98338509, -0.98352402, -0.98366243, -0.98380023, -0.98393744, -0.98407406, + -0.98421007, -0.98434556, -0.98448044, -0.98461479, -0.98474848, -0.98488164, -0.98501426, -0.98514622, + -0.98527765, -0.98540848, -0.98553872, -0.98566842, -0.98579752, -0.98592603, -0.98605394, -0.98618132, + -0.98630810, -0.98643428, -0.98655993, -0.98668492, -0.98680937, -0.98693329, -0.98705655, -0.98717928, + -0.98730141, -0.98742294, -0.98754394, -0.98766434, -0.98778415, -0.98790336, -0.98802203, -0.98814011, + -0.98825759, -0.98837447, -0.98849082, -0.98860651, -0.98872167, -0.98883629, -0.98895025, -0.98906368, + -0.98917651, -0.98928875, -0.98940045, -0.98951149, -0.98962200, -0.98973197, -0.98984128, -0.98995006, + -0.99005818, -0.99016583, -0.99027282, -0.99037921, -0.99048507, -0.99059033, -0.99069500, -0.99079913, + -0.99090266, -0.99100554, -0.99110794, -0.99120969, -0.99131083, -0.99141145, -0.99151146, -0.99161088, + -0.99170977, -0.99180800, -0.99190569, -0.99200279, -0.99209929, -0.99219525, -0.99229062, -0.99238533, + -0.99247956, -0.99257314, -0.99266613, -0.99275857, -0.99285042, -0.99294168, -0.99303234, -0.99312246, + -0.99321193, -0.99330086, -0.99338919, -0.99347699, -0.99356413, -0.99365073, -0.99373674, -0.99382216, + -0.99390697, -0.99399120, -0.99407488, -0.99415797, -0.99424046, -0.99432236, -0.99440366, -0.99448442, + -0.99456459, -0.99464417, -0.99472314, -0.99480152, -0.99487931, -0.99495655, -0.99503320, -0.99510926, + -0.99518472, -0.99525958, -0.99533391, -0.99540764, -0.99548078, -0.99555331, -0.99562526, -0.99569660, + -0.99576741, -0.99583763, -0.99590725, -0.99597627, -0.99604470, -0.99611259, -0.99617982, -0.99624652, + -0.99631262, -0.99637812, -0.99644303, -0.99650741, -0.99657112, -0.99663430, -0.99669689, -0.99675888, + -0.99682027, -0.99688113, -0.99694133, -0.99700099, -0.99706006, -0.99711853, -0.99717641, -0.99723375, + -0.99729043, -0.99734658, -0.99740213, -0.99745709, -0.99751145, -0.99756521, -0.99761844, -0.99767107, + -0.99772304, -0.99777448, -0.99782532, -0.99787563, -0.99792528, -0.99797440, -0.99802285, -0.99807078, + -0.99811810, -0.99816483, -0.99821103, -0.99825656, -0.99830157, -0.99834591, -0.99838972, -0.99843293, + -0.99847555, -0.99851763, -0.99855906, -0.99859995, -0.99864024, -0.99867994, -0.99871904, -0.99875754, + -0.99879545, -0.99883282, -0.99886954, -0.99890572, -0.99894130, -0.99897629, -0.99901068, -0.99904448, + -0.99907774, -0.99911034, -0.99914241, -0.99917388, -0.99920475, -0.99923503, -0.99926478, -0.99929386, + -0.99932235, -0.99935031, -0.99937767, -0.99940443, -0.99943060, -0.99945617, -0.99948120, -0.99950558, + -0.99952942, -0.99955267, -0.99957532, -0.99959737, -0.99961883, -0.99963969, -0.99966002, -0.99967968, + -0.99969882, -0.99971735, -0.99973530, -0.99975264, -0.99976939, -0.99978560, -0.99980116, -0.99981618, + -0.99983060, -0.99984443, -0.99985766, -0.99987030, -0.99988234, -0.99989384, -0.99990469, -0.99991500, + -0.99992472, -0.99993384, -0.99994236, -0.99995029, -0.99995762, -0.99996442, -0.99997061, -0.99997616, + -0.99998116, -0.99998558, -0.99998939, -0.99999267, -0.99999529, -0.99999738, -0.99999881, -0.99999970, + -1.00000000, -0.99999970, -0.99999881, -0.99999738, -0.99999529, -0.99999267, -0.99998939, -0.99998558, + -0.99998116, -0.99997616, -0.99997061, -0.99996442, -0.99995762, -0.99995029, -0.99994236, -0.99993384, + -0.99992472, -0.99991500, -0.99990469, -0.99989384, -0.99988234, -0.99987030, -0.99985766, -0.99984443, + -0.99983060, -0.99981618, -0.99980116, -0.99978560, -0.99976939, -0.99975264, -0.99973530, -0.99971735, + -0.99969882, -0.99967968, -0.99966002, -0.99963969, -0.99961883, -0.99959737, -0.99957532, -0.99955267, + -0.99952942, -0.99950558, -0.99948120, -0.99945617, -0.99943060, -0.99940443, -0.99937767, -0.99935031, + -0.99932235, -0.99929386, -0.99926478, -0.99923503, -0.99920475, -0.99917388, -0.99914241, -0.99911034, + -0.99907774, -0.99904448, -0.99901068, -0.99897629, -0.99894130, -0.99890572, -0.99886954, -0.99883282, + -0.99879545, -0.99875754, -0.99871904, -0.99867994, -0.99864024, -0.99859995, -0.99855906, -0.99851763, + -0.99847555, -0.99843293, -0.99838972, -0.99834591, -0.99830157, -0.99825656, -0.99821103, -0.99816483, + -0.99811810, -0.99807078, -0.99802285, -0.99797440, -0.99792528, -0.99787563, -0.99782532, -0.99777448, + -0.99772304, -0.99767107, -0.99761844, -0.99756521, -0.99751145, -0.99745709, -0.99740213, -0.99734658, + -0.99729043, -0.99723375, -0.99717641, -0.99711853, -0.99706006, -0.99700099, -0.99694133, -0.99688113, + -0.99682027, -0.99675888, -0.99669689, -0.99663430, -0.99657112, -0.99650741, -0.99644303, -0.99637812, + -0.99631262, -0.99624652, -0.99617982, -0.99611259, -0.99604470, -0.99597627, -0.99590725, -0.99583763, + -0.99576741, -0.99569660, -0.99562526, -0.99555331, -0.99548078, -0.99540764, -0.99533391, -0.99525958, + -0.99518472, -0.99510926, -0.99503320, -0.99495655, -0.99487931, -0.99480152, -0.99472314, -0.99464417, + -0.99456459, -0.99448442, -0.99440366, -0.99432236, -0.99424046, -0.99415797, -0.99407488, -0.99399120, + -0.99390697, -0.99382216, -0.99373674, -0.99365073, -0.99356413, -0.99347699, -0.99338919, -0.99330086, + -0.99321193, -0.99312246, -0.99303234, -0.99294168, -0.99285042, -0.99275857, -0.99266613, -0.99257314, + -0.99247956, -0.99238533, -0.99229062, -0.99219525, -0.99209929, -0.99200279, -0.99190569, -0.99180800, + -0.99170977, -0.99161088, -0.99151146, -0.99141145, -0.99131083, -0.99120969, -0.99110794, -0.99100554, + -0.99090266, -0.99079913, -0.99069500, -0.99059033, -0.99048507, -0.99037921, -0.99027282, -0.99016583, + -0.99005818, -0.98995006, -0.98984128, -0.98973197, -0.98962200, -0.98951149, -0.98940045, -0.98928875, + -0.98917651, -0.98906368, -0.98895025, -0.98883629, -0.98872167, -0.98860651, -0.98849082, -0.98837447, + -0.98825759, -0.98814011, -0.98802203, -0.98790336, -0.98778415, -0.98766434, -0.98754394, -0.98742294, + -0.98730141, -0.98717928, -0.98705655, -0.98693329, -0.98680937, -0.98668492, -0.98655993, -0.98643428, + -0.98630810, -0.98618132, -0.98605394, -0.98592603, -0.98579752, -0.98566842, -0.98553872, -0.98540848, + -0.98527765, -0.98514622, -0.98501426, -0.98488164, -0.98474848, -0.98461479, -0.98448044, -0.98434556, + -0.98421007, -0.98407406, -0.98393744, -0.98380023, -0.98366243, -0.98352402, -0.98338509, -0.98324561, + -0.98310548, -0.98296481, -0.98282355, -0.98268169, -0.98253930, -0.98239630, -0.98225272, -0.98210859, + -0.98196387, -0.98181856, -0.98167270, -0.98152626, -0.98137921, -0.98123157, -0.98108339, -0.98093462, + -0.98078525, -0.98063534, -0.98048484, -0.98033381, -0.98018211, -0.98002988, -0.97987711, -0.97972375, + -0.97956979, -0.97941524, -0.97926015, -0.97910446, -0.97894818, -0.97879136, -0.97863394, -0.97847593, + -0.97831738, -0.97815824, -0.97799850, -0.97783822, -0.97767735, -0.97751594, -0.97735387, -0.97719133, + -0.97702813, -0.97686440, -0.97670007, -0.97653520, -0.97636974, -0.97620368, -0.97603709, -0.97586989, + -0.97570211, -0.97553378, -0.97536486, -0.97519541, -0.97502536, -0.97485471, -0.97468352, -0.97451174, + -0.97433937, -0.97416645, -0.97399294, -0.97381890, -0.97364426, -0.97346902, -0.97329324, -0.97311687, + -0.97293997, -0.97276247, -0.97258437, -0.97240573, -0.97222650, -0.97204673, -0.97186631, -0.97168541, + -0.97150391, -0.97132182, -0.97113913, -0.97095591, -0.97077215, -0.97058779, -0.97040284, -0.97021735, + -0.97003126, -0.96984458, -0.96965736, -0.96946961, -0.96928126, -0.96909231, -0.96890283, -0.96871275, + -0.96852207, -0.96833086, -0.96813911, -0.96794677, -0.96775383, -0.96756035, -0.96736628, -0.96717167, + -0.96697646, -0.96678072, -0.96658438, -0.96638745, -0.96618998, -0.96599197, -0.96579337, -0.96559417, + -0.96539444, -0.96519411, -0.96499324, -0.96479183, -0.96458977, -0.96438724, -0.96418405, -0.96398038, + -0.96377605, -0.96357119, -0.96336579, -0.96315980, -0.96295327, -0.96274614, -0.96253848, -0.96233022, + -0.96212143, -0.96191204, -0.96170205, -0.96149158, -0.96128047, -0.96106887, -0.96085662, -0.96064389, + -0.96043050, -0.96021664, -0.96000212, -0.95978713, -0.95957154, -0.95935535, -0.95913863, -0.95892131, + -0.95870346, -0.95848507, -0.95826608, -0.95804650, -0.95782644, -0.95760572, -0.95738453, -0.95716268, + -0.95694035, -0.95671743, -0.95649391, -0.95626986, -0.95604527, -0.95582008, -0.95559436, -0.95536804, + -0.95514119, -0.95491374, -0.95468575, -0.95445722, -0.95422810, -0.95399845, -0.95376819, -0.95353740, + -0.95330602, -0.95307410, -0.95284164, -0.95260859, -0.95237499, -0.95214087, -0.95190614, -0.95167089, + -0.95143503, -0.95119864, -0.95096165, -0.95072412, -0.95048606, -0.95024747, -0.95000827, -0.94976848, + -0.94952816, -0.94928730, -0.94904590, -0.94880390, -0.94856137, -0.94831824, -0.94807458, -0.94783038, + -0.94758558, -0.94734025, -0.94709438, -0.94684792, -0.94660091, -0.94635338, -0.94610524, -0.94585657, + -0.94560730, -0.94535756, -0.94510722, -0.94485629, -0.94460481, -0.94435281, -0.94410026, -0.94384712, + -0.94359344, -0.94333923, -0.94308442, -0.94282907, -0.94257319, -0.94231677, -0.94205976, -0.94180220, + -0.94154406, -0.94128537, -0.94102615, -0.94076639, -0.94050604, -0.94024521, -0.93998373, -0.93972176, + -0.93945920, -0.93919611, -0.93893248, -0.93866831, -0.93840355, -0.93813825, -0.93787235, -0.93760598, + -0.93733901, -0.93707150, -0.93680346, -0.93653482, -0.93626565, -0.93599594, -0.93572569, -0.93545485, + -0.93518353, -0.93491161, -0.93463916, -0.93436611, -0.93409252, -0.93381846, -0.93354380, -0.93326855, + -0.93299282, -0.93271649, -0.93243963, -0.93216223, -0.93188429, -0.93160576, -0.93132669, -0.93104708, + -0.93076694, -0.93048626, -0.93020505, -0.92992324, -0.92964089, -0.92935801, -0.92907459, -0.92879063, + -0.92850608, -0.92822099, -0.92793542, -0.92764926, -0.92736250, -0.92707527, -0.92678750, -0.92649913, + -0.92621022, -0.92592078, -0.92563081, -0.92534029, -0.92504925, -0.92475760, -0.92446548, -0.92417276, + -0.92387950, -0.92358577, -0.92329144, -0.92299652, -0.92270112, -0.92240518, -0.92210865, -0.92181164, + -0.92151403, -0.92121589, -0.92091721, -0.92061806, -0.92031831, -0.92001796, -0.91971713, -0.91941577, + -0.91911387, -0.91881138, -0.91850841, -0.91820484, -0.91790080, -0.91759616, -0.91729099, -0.91698527, + -0.91667908, -0.91637230, -0.91606498, -0.91575712, -0.91544873, -0.91513979, -0.91483033, -0.91452032, + -0.91420978, -0.91389865, -0.91358703, -0.91327488, -0.91296220, -0.91264898, -0.91233516, -0.91202086, + -0.91170603, -0.91139066, -0.91107476, -0.91075826, -0.91044128, -0.91012377, -0.90980572, -0.90948713, + -0.90916800, -0.90884835, -0.90852809, -0.90820736, -0.90788609, -0.90756434, -0.90724200, -0.90691912, + -0.90659571, -0.90627176, -0.90594727, -0.90562230, -0.90529674, -0.90497071, -0.90464407, -0.90431696, + -0.90398932, -0.90366107, -0.90333235, -0.90300310, -0.90267330, -0.90234298, -0.90201217, -0.90168077, + -0.90134883, -0.90101641, -0.90068340, -0.90034992, -0.90001589, -0.89968133, -0.89934623, -0.89901060, + -0.89867449, -0.89833778, -0.89800060, -0.89766282, -0.89732456, -0.89698577, -0.89664650, -0.89630663, + -0.89596623, -0.89562535, -0.89528394, -0.89494199, -0.89459950, -0.89425647, -0.89391297, -0.89356887, + -0.89322430, -0.89287919, -0.89253354, -0.89218742, -0.89184070, -0.89149350, -0.89114577, -0.89079750, + -0.89044875, -0.89009941, -0.88974959, -0.88939923, -0.88904834, -0.88869697, -0.88834506, -0.88799256, + -0.88763964, -0.88728613, -0.88693213, -0.88657761, -0.88622254, -0.88586694, -0.88551086, -0.88515425, + -0.88479710, -0.88443947, -0.88408124, -0.88372254, -0.88336337, -0.88300359, -0.88264334, -0.88228256, + -0.88192129, -0.88155943, -0.88119709, -0.88083428, -0.88047087, -0.88010699, -0.87974262, -0.87937766, + -0.87901223, -0.87864625, -0.87827981, -0.87791282, -0.87754530, -0.87717724, -0.87680870, -0.87643969, + -0.87607008, -0.87570000, -0.87532938, -0.87495828, -0.87458664, -0.87421453, -0.87384182, -0.87346870, + -0.87309498, -0.87272078, -0.87234604, -0.87197083, -0.87159508, -0.87121886, -0.87084204, -0.87046480, + -0.87008697, -0.86970866, -0.86932987, -0.86895055, -0.86857069, -0.86819035, -0.86780947, -0.86742812, + -0.86704624, -0.86666387, -0.86628097, -0.86589754, -0.86551362, -0.86512917, -0.86474425, -0.86435878, + -0.86397284, -0.86358637, -0.86319941, -0.86281192, -0.86242396, -0.86203545, -0.86164647, -0.86125696, + -0.86086696, -0.86047643, -0.86008537, -0.85969388, -0.85930181, -0.85890925, -0.85851622, -0.85812265, + -0.85772860, -0.85733402, -0.85693896, -0.85654342, -0.85614735, -0.85575074, -0.85535365, -0.85495609, + -0.85455799, -0.85415941, -0.85376030, -0.85336071, -0.85296059, -0.85255998, -0.85215890, -0.85175729, + -0.85135520, -0.85095257, -0.85054946, -0.85014588, -0.84974176, -0.84933716, -0.84893203, -0.84852648, + -0.84812033, -0.84771377, -0.84730661, -0.84689903, -0.84649092, -0.84608233, -0.84567326, -0.84526366, + -0.84485358, -0.84444296, -0.84403187, -0.84362030, -0.84320825, -0.84279567, -0.84238261, -0.84196901, + -0.84155500, -0.84114045, -0.84072536, -0.84030986, -0.83989382, -0.83947724, -0.83906025, -0.83864272, + -0.83822471, -0.83780622, -0.83738720, -0.83696771, -0.83654773, -0.83612728, -0.83570629, -0.83528483, + -0.83486289, -0.83444041, -0.83401752, -0.83359408, -0.83317018, -0.83274579, -0.83232087, -0.83189547, + -0.83146960, -0.83104324, -0.83061641, -0.83018905, -0.82976121, -0.82933295, -0.82890409, -0.82847482, + -0.82804507, -0.82761478, -0.82718402, -0.82675278, -0.82632107, -0.82588887, -0.82545614, -0.82502300, + -0.82458931, -0.82415515, -0.82372051, -0.82328540, -0.82284981, -0.82241368, -0.82197714, -0.82154006, + -0.82110250, -0.82066447, -0.82022595, -0.81978697, -0.81934750, -0.81890756, -0.81846714, -0.81802619, + -0.81758481, -0.81714290, -0.81670058, -0.81625772, -0.81581444, -0.81537062, -0.81492633, -0.81448156, + -0.81403631, -0.81359059, -0.81314439, -0.81269777, -0.81225061, -0.81180298, -0.81135488, -0.81090623, + -0.81045717, -0.81000763, -0.80955762, -0.80910712, -0.80865616, -0.80820471, -0.80775285, -0.80730045, + -0.80684757, -0.80639422, -0.80594039, -0.80548608, -0.80503136, -0.80457610, -0.80412036, -0.80366421, + -0.80320752, -0.80275041, -0.80229282, -0.80183470, -0.80137616, -0.80091715, -0.80045766, -0.79999769, + -0.79953724, -0.79907638, -0.79861498, -0.79815316, -0.79769087, -0.79722804, -0.79676479, -0.79630107, + -0.79583693, -0.79537225, -0.79490715, -0.79444152, -0.79397547, -0.79350895, -0.79304194, -0.79257452, + -0.79210657, -0.79163820, -0.79116935, -0.79070002, -0.79023021, -0.78975999, -0.78928924, -0.78881806, + -0.78834641, -0.78787434, -0.78740174, -0.78692871, -0.78645521, -0.78598124, -0.78550684, -0.78503191, + -0.78455657, -0.78408080, -0.78360450, -0.78312778, -0.78265059, -0.78217292, -0.78169483, -0.78121626, + -0.78073722, -0.78025776, -0.77977777, -0.77929735, -0.77881652, -0.77833521, -0.77785343, -0.77737117, + -0.77688849, -0.77640533, -0.77592170, -0.77543765, -0.77495313, -0.77446812, -0.77398270, -0.77349681, + -0.77301043, -0.77252364, -0.77203637, -0.77154869, -0.77106053, -0.77057189, -0.77008283, -0.76959330, + -0.76910335, -0.76861292, -0.76812202, -0.76763070, -0.76713890, -0.76664668, -0.76615399, -0.76566088, + -0.76516724, -0.76467323, -0.76417875, -0.76368380, -0.76318842, -0.76269257, -0.76219630, -0.76169956, + -0.76120239, -0.76070476, -0.76020670, -0.75970817, -0.75920922, -0.75870979, -0.75820988, -0.75770962, + -0.75720882, -0.75670767, -0.75620598, -0.75570393, -0.75520140, -0.75469840, -0.75419497, -0.75369114, + -0.75318682, -0.75268203, -0.75217682, -0.75167120, -0.75116515, -0.75065863, -0.75015163, -0.74964422, + -0.74913639, -0.74862808, -0.74811935, -0.74761021, -0.74710059, -0.74659055, -0.74608010, -0.74556917, + -0.74505776, -0.74454600, -0.74403375, -0.74352109, -0.74300796, -0.74249440, -0.74198043, -0.74146599, + -0.74095112, -0.74043584, -0.73992008, -0.73940390, -0.73888731, -0.73837030, -0.73785281, -0.73733491, + -0.73681659, -0.73629779, -0.73577857, -0.73525894, -0.73473889, -0.73421836, -0.73369741, -0.73317605, + -0.73265427, -0.73213202, -0.73160940, -0.73108631, -0.73056275, -0.73003882, -0.72951442, -0.72898960, + -0.72846437, -0.72793871, -0.72741264, -0.72688609, -0.72635913, -0.72583181, -0.72530395, -0.72477573, + -0.72424710, -0.72371799, -0.72318846, -0.72265857, -0.72212821, -0.72159743, -0.72106618, -0.72053456, + -0.72000253, -0.71947002, -0.71893710, -0.71840382, -0.71787006, -0.71733588, -0.71680129, -0.71626627, + -0.71573085, -0.71519494, -0.71465868, -0.71412200, -0.71358484, -0.71304733, -0.71250939, -0.71197098, + -0.71143222, -0.71089298, -0.71035337, -0.70981330, -0.70927280, -0.70873195, -0.70819062, -0.70764893, + -0.70710677, -0.70656425, -0.70602125, -0.70547789, -0.70493406, -0.70438987, -0.70384526, -0.70330018, + -0.70275474, -0.70220888, -0.70166260, -0.70111591, -0.70056880, -0.70002127, -0.69947332, -0.69892502, + -0.69837624, -0.69782710, -0.69727749, -0.69672751, -0.69617712, -0.69562632, -0.69507509, -0.69452351, + -0.69397146, -0.69341904, -0.69286615, -0.69231290, -0.69175923, -0.69120520, -0.69065070, -0.69009584, + -0.68954057, -0.68898487, -0.68842876, -0.68787223, -0.68731534, -0.68675804, -0.68620032, -0.68564218, + -0.68508369, -0.68452471, -0.68396538, -0.68340570, -0.68284553, -0.68228501, -0.68172407, -0.68116271, + -0.68060100, -0.68003887, -0.67947632, -0.67891335, -0.67835003, -0.67778629, -0.67722219, -0.67665762, + -0.67609268, -0.67552739, -0.67496163, -0.67439550, -0.67382902, -0.67326206, -0.67269474, -0.67212707, + -0.67155898, -0.67099047, -0.67042154, -0.66985226, -0.66928262, -0.66871250, -0.66814202, -0.66757119, + -0.66699994, -0.66642827, -0.66585624, -0.66528380, -0.66471100, -0.66413778, -0.66356415, -0.66299015, + -0.66241580, -0.66184098, -0.66126585, -0.66069031, -0.66011435, -0.65953803, -0.65896130, -0.65838420, + -0.65780669, -0.65722883, -0.65665054, -0.65607190, -0.65549284, -0.65491343, -0.65433359, -0.65375340, + -0.65317285, -0.65259188, -0.65201056, -0.65142882, -0.65084666, -0.65026420, -0.64968133, -0.64909804, + -0.64851439, -0.64793038, -0.64734596, -0.64676118, -0.64617604, -0.64559048, -0.64500451, -0.64441824, + -0.64383155, -0.64324450, -0.64265704, -0.64206922, -0.64148104, -0.64089245, -0.64030349, -0.63971418, + -0.63912445, -0.63853437, -0.63794392, -0.63735306, -0.63676184, -0.63617027, -0.63557833, -0.63498598, + -0.63439327, -0.63380021, -0.63320678, -0.63261294, -0.63201874, -0.63142419, -0.63082922, -0.63023394, + -0.62963825, -0.62904221, -0.62844574, -0.62784898, -0.62725180, -0.62665427, -0.62605637, -0.62545812, + -0.62485951, -0.62426049, -0.62366110, -0.62306136, -0.62246126, -0.62186080, -0.62125999, -0.62065876, + -0.62005723, -0.61945528, -0.61885297, -0.61825031, -0.61764729, -0.61704391, -0.61644018, -0.61583608, + -0.61523157, -0.61462677, -0.61402154, -0.61341602, -0.61281008, -0.61220378, -0.61159718, -0.61099017, + -0.61038280, -0.60977507, -0.60916704, -0.60855860, -0.60794979, -0.60734063, -0.60673112, -0.60612124, + -0.60551107, -0.60490048, -0.60428953, -0.60367823, -0.60306662, -0.60245460, -0.60184222, -0.60122955, + -0.60061646, -0.60000306, -0.59938931, -0.59877521, -0.59816068, -0.59754586, -0.59693068, -0.59631521, + -0.59569931, -0.59508306, -0.59446651, -0.59384960, -0.59323227, -0.59261465, -0.59199667, -0.59137839, + -0.59075969, -0.59014070, -0.58952129, -0.58890158, -0.58828157, -0.58766115, -0.58704036, -0.58641928, + -0.58579785, -0.58517605, -0.58455396, -0.58393145, -0.58330864, -0.58268547, -0.58206201, -0.58143812, + -0.58081394, -0.58018941, -0.57956457, -0.57893932, -0.57831377, -0.57768792, -0.57706165, -0.57643509, + -0.57580817, -0.57518095, -0.57455337, -0.57392544, -0.57329714, -0.57266855, -0.57203960, -0.57141036, + -0.57078075, -0.57015079, -0.56952053, -0.56888992, -0.56825894, -0.56762767, -0.56699604, -0.56636411, + -0.56573182, -0.56509918, -0.56446624, -0.56383294, -0.56319934, -0.56256539, -0.56193113, -0.56129652, + -0.56066155, -0.56002629, -0.55939072, -0.55875480, -0.55811852, -0.55748194, -0.55684501, -0.55620778, + -0.55557024, -0.55493236, -0.55429411, -0.55365556, -0.55301672, -0.55237752, -0.55173796, -0.55109817, + -0.55045795, -0.54981750, -0.54917663, -0.54853553, -0.54789406, -0.54725230, -0.54661018, -0.54596776, + -0.54532498, -0.54468191, -0.54403853, -0.54339480, -0.54275078, -0.54210645, -0.54146177, -0.54081678, + -0.54017144, -0.53952587, -0.53887993, -0.53823364, -0.53758705, -0.53694016, -0.53629297, -0.53564548, + -0.53499764, -0.53434944, -0.53370100, -0.53305221, -0.53240311, -0.53175372, -0.53110403, -0.53045398, + -0.52980363, -0.52915299, -0.52850199, -0.52785075, -0.52719915, -0.52654725, -0.52589500, -0.52524251, + -0.52458966, -0.52393657, -0.52328312, -0.52262938, -0.52197528, -0.52132094, -0.52066624, -0.52001125, + -0.51935601, -0.51870042, -0.51804453, -0.51738828, -0.51673180, -0.51607502, -0.51541787, -0.51476043, + -0.51410276, -0.51344472, -0.51278639, -0.51212776, -0.51146883, -0.51080960, -0.51015007, -0.50949025, + -0.50883013, -0.50816971, -0.50750899, -0.50684798, -0.50618666, -0.50552505, -0.50486308, -0.50420088, + -0.50353837, -0.50287557, -0.50221246, -0.50154907, -0.50088537, -0.50022137, -0.49955711, -0.49889255, + -0.49822766, -0.49756250, -0.49689704, -0.49623129, -0.49556527, -0.49489895, -0.49423230, -0.49356541, + -0.49289820, -0.49223071, -0.49156290, -0.49089485, -0.49022648, -0.48955783, -0.48888889, -0.48821968, + -0.48755017, -0.48688036, -0.48621029, -0.48553991, -0.48486924, -0.48419830, -0.48352706, -0.48285556, + -0.48218378, -0.48151168, -0.48083934, -0.48016667, -0.47949377, -0.47882056, -0.47814706, -0.47747329, + -0.47679922, -0.47612488, -0.47545028, -0.47477537, -0.47410020, -0.47342476, -0.47274902, -0.47207302, + -0.47139674, -0.47072017, -0.47004333, -0.46936622, -0.46868882, -0.46801114, -0.46733320, -0.46665499, + -0.46597651, -0.46529773, -0.46461868, -0.46393937, -0.46325979, -0.46257994, -0.46189979, -0.46121940, + -0.46053872, -0.45985776, -0.45917654, -0.45849505, -0.45781329, -0.45713127, -0.45644897, -0.45576641, + -0.45508358, -0.45440048, -0.45371711, -0.45303348, -0.45234957, -0.45166543, -0.45098099, -0.45029628, + -0.44961134, -0.44892609, -0.44824061, -0.44755486, -0.44686884, -0.44618255, -0.44549602, -0.44480920, + -0.44412214, -0.44343480, -0.44274724, -0.44205937, -0.44137126, -0.44068289, -0.43999428, -0.43930539, + -0.43861625, -0.43792683, -0.43723717, -0.43654725, -0.43585709, -0.43516666, -0.43447596, -0.43378502, + -0.43309382, -0.43240237, -0.43171066, -0.43101871, -0.43032649, -0.42963400, -0.42894128, -0.42824832, + -0.42755508, -0.42686161, -0.42616788, -0.42547390, -0.42477968, -0.42408520, -0.42339048, -0.42269549, + -0.42200026, -0.42130479, -0.42060909, -0.41991311, -0.41921690, -0.41852042, -0.41782370, -0.41712677, + -0.41642955, -0.41573212, -0.41503441, -0.41433650, -0.41363832, -0.41293988, -0.41224122, -0.41154233, + -0.41084316, -0.41014379, -0.40944415, -0.40874428, -0.40804416, -0.40734380, -0.40664321, -0.40594238, + -0.40524131, -0.40454000, -0.40383846, -0.40313667, -0.40243465, -0.40173239, -0.40102988, -0.40032718, + -0.39962420, -0.39892101, -0.39821756, -0.39751390, -0.39681000, -0.39610586, -0.39540148, -0.39469686, + -0.39399204, -0.39328697, -0.39258167, -0.39187613, -0.39117038, -0.39046440, -0.38975817, -0.38905174, + -0.38834503, -0.38763815, -0.38693100, -0.38622364, -0.38551605, -0.38480824, -0.38410020, -0.38339192, + -0.38268343, -0.38197473, -0.38126576, -0.38055661, -0.37984720, -0.37913761, -0.37842774, -0.37771770, + -0.37700742, -0.37629691, -0.37558618, -0.37487522, -0.37416407, -0.37345266, -0.37274107, -0.37202924, + -0.37131721, -0.37060493, -0.36989245, -0.36917976, -0.36846682, -0.36775368, -0.36704034, -0.36632678, + -0.36561298, -0.36489901, -0.36418480, -0.36347038, -0.36275572, -0.36204088, -0.36132580, -0.36061051, + -0.35989505, -0.35917935, -0.35846341, -0.35774729, -0.35703096, -0.35631442, -0.35559767, -0.35488069, + -0.35416353, -0.35344616, -0.35272855, -0.35201076, -0.35129276, -0.35057455, -0.34985614, -0.34913751, + -0.34841868, -0.34769964, -0.34698042, -0.34626096, -0.34554133, -0.34482148, -0.34410143, -0.34338117, + -0.34266073, -0.34194008, -0.34121922, -0.34049815, -0.33977687, -0.33905542, -0.33833376, -0.33761191, + -0.33688986, -0.33616760, -0.33544514, -0.33472249, -0.33399966, -0.33327660, -0.33255336, -0.33182994, + -0.33110631, -0.33038250, -0.32965845, -0.32893425, -0.32820985, -0.32748523, -0.32676044, -0.32603547, + -0.32531029, -0.32458493, -0.32385936, -0.32313362, -0.32240769, -0.32168156, -0.32095525, -0.32022873, + -0.31950203, -0.31877515, -0.31804809, -0.31732082, -0.31659338, -0.31586576, -0.31513792, -0.31440994, + -0.31368175, -0.31295338, -0.31222481, -0.31149608, -0.31076714, -0.31003806, -0.30930877, -0.30857930, + -0.30784965, -0.30711982, -0.30638981, -0.30565959, -0.30492923, -0.30419868, -0.30346796, -0.30273703, + -0.30200595, -0.30127469, -0.30054325, -0.29981163, -0.29907984, -0.29834786, -0.29761571, -0.29688337, + -0.29615089, -0.29541820, -0.29468536, -0.29395235, -0.29321915, -0.29248580, -0.29175225, -0.29101855, + -0.29028466, -0.28955063, -0.28881642, -0.28808203, -0.28734747, -0.28661272, -0.28587782, -0.28514278, + -0.28440753, -0.28367212, -0.28293657, -0.28220084, -0.28146493, -0.28072888, -0.27999264, -0.27925625, + -0.27851969, -0.27778298, -0.27704608, -0.27630904, -0.27557182, -0.27483445, -0.27409691, -0.27335921, + -0.27262136, -0.27188334, -0.27114516, -0.27040681, -0.26966831, -0.26892966, -0.26819086, -0.26745188, + -0.26671275, -0.26597348, -0.26523402, -0.26449442, -0.26375467, -0.26301476, -0.26227471, -0.26153448, + -0.26079410, -0.26005360, -0.25931293, -0.25857207, -0.25783110, -0.25708997, -0.25634867, -0.25560725, + -0.25486565, -0.25412393, -0.25338203, -0.25264001, -0.25189781, -0.25115550, -0.25041300, -0.24967039, + -0.24892761, -0.24818468, -0.24744162, -0.24669841, -0.24595505, -0.24521154, -0.24446790, -0.24372411, + -0.24298018, -0.24223611, -0.24149188, -0.24074753, -0.24000302, -0.23925838, -0.23851359, -0.23776866, + -0.23702361, -0.23627840, -0.23553306, -0.23478758, -0.23404196, -0.23329620, -0.23255031, -0.23180428, + -0.23105811, -0.23031181, -0.22956537, -0.22881879, -0.22807208, -0.22732525, -0.22657827, -0.22583115, + -0.22508392, -0.22433653, -0.22358903, -0.22284140, -0.22209363, -0.22134572, -0.22059768, -0.21984953, + -0.21910124, -0.21835282, -0.21760428, -0.21685560, -0.21610680, -0.21535787, -0.21460882, -0.21385963, + -0.21311031, -0.21236089, -0.21161133, -0.21086164, -0.21011184, -0.20936191, -0.20861185, -0.20786168, + -0.20711137, -0.20636095, -0.20561041, -0.20485975, -0.20410897, -0.20335807, -0.20260704, -0.20185590, + -0.20110464, -0.20035325, -0.19960175, -0.19885014, -0.19809841, -0.19734657, -0.19659460, -0.19584252, + -0.19509032, -0.19433801, -0.19358559, -0.19283305, -0.19208039, -0.19132763, -0.19057475, -0.18982176, + -0.18906866, -0.18831545, -0.18756212, -0.18680869, -0.18605515, -0.18530150, -0.18454774, -0.18379387, + -0.18303989, -0.18228580, -0.18153161, -0.18077731, -0.18002290, -0.17926839, -0.17851377, -0.17775905, + -0.17700422, -0.17624930, -0.17549425, -0.17473911, -0.17398387, -0.17322853, -0.17247309, -0.17171754, + -0.17096189, -0.17020614, -0.16945030, -0.16869435, -0.16793829, -0.16718215, -0.16642590, -0.16566956, + -0.16491312, -0.16415659, -0.16339995, -0.16264322, -0.16188639, -0.16112947, -0.16037245, -0.15961535, + -0.15885815, -0.15810084, -0.15734346, -0.15658598, -0.15582840, -0.15507074, -0.15431297, -0.15355512, + -0.15279719, -0.15203916, -0.15128104, -0.15052283, -0.14976454, -0.14900614, -0.14824767, -0.14748912, + -0.14673047, -0.14597175, -0.14521292, -0.14445402, -0.14369503, -0.14293596, -0.14217681, -0.14141756, + -0.14065824, -0.13989884, -0.13913934, -0.13837977, -0.13762012, -0.13686039, -0.13610058, -0.13534068, + -0.13458070, -0.13382065, -0.13306053, -0.13230032, -0.13154003, -0.13077967, -0.13001922, -0.12925871, + -0.12849811, -0.12773745, -0.12697670, -0.12621588, -0.12545498, -0.12469402, -0.12393297, -0.12317186, + -0.12241068, -0.12164941, -0.12088808, -0.12012669, -0.11936522, -0.11860368, -0.11784206, -0.11708038, + -0.11631863, -0.11555681, -0.11479492, -0.11403298, -0.11327095, -0.11250886, -0.11174671, -0.11098449, + -0.11022221, -0.10945985, -0.10869744, -0.10793497, -0.10717242, -0.10640982, -0.10564715, -0.10488442, + -0.10412163, -0.10335878, -0.10259587, -0.10183290, -0.10106986, -0.10030677, -0.09954362, -0.09878041, + -0.09801714, -0.09725381, -0.09649043, -0.09572699, -0.09496350, -0.09419994, -0.09343634, -0.09267268, + -0.09190895, -0.09114519, -0.09038136, -0.08961748, -0.08885355, -0.08808957, -0.08732554, -0.08656145, + -0.08579731, -0.08503313, -0.08426889, -0.08350460, -0.08274026, -0.08197588, -0.08121145, -0.08044697, + -0.07968244, -0.07891786, -0.07815325, -0.07738858, -0.07662386, -0.07585911, -0.07509430, -0.07432945, + -0.07356457, -0.07279963, -0.07203465, -0.07126963, -0.07050458, -0.06973947, -0.06897433, -0.06820914, + -0.06744392, -0.06667866, -0.06591335, -0.06514801, -0.06438263, -0.06361721, -0.06285176, -0.06208627, + -0.06132074, -0.06055517, -0.05978957, -0.05902394, -0.05825827, -0.05749256, -0.05672682, -0.05596105, + -0.05519525, -0.05442941, -0.05366354, -0.05289764, -0.05213170, -0.05136574, -0.05059975, -0.04983373, + -0.04906768, -0.04830159, -0.04753548, -0.04676935, -0.04600318, -0.04523699, -0.04447077, -0.04370453, + -0.04293826, -0.04217196, -0.04140564, -0.04063930, -0.03987293, -0.03910654, -0.03834012, -0.03757368, + -0.03680722, -0.03604074, -0.03527424, -0.03450771, -0.03374117, -0.03297461, -0.03220803, -0.03144142, + -0.03067480, -0.02990817, -0.02914151, -0.02837484, -0.02760815, -0.02684144, -0.02607472, -0.02530798, + -0.02454123, -0.02377446, -0.02300768, -0.02224089, -0.02147408, -0.02070726, -0.01994043, -0.01917358, + -0.01840673, -0.01763986, -0.01687299, -0.01610610, -0.01533921, -0.01457230, -0.01380539, -0.01303847, + -0.01227154, -0.01150460, -0.01073766, -0.00997071, -0.00920375, -0.00843679, -0.00766983, -0.00690286, + -0.00613588, -0.00536891, -0.00460193, -0.00383494, -0.00306796, -0.00230097, -0.00153398, -0.00076699, + -0.00000000, 0.00076699, 0.00153398, 0.00230097, 0.00306796, 0.00383494, 0.00460193, 0.00536891, + 0.00613588, 0.00690286, 0.00766983, 0.00843679, 0.00920375, 0.00997071, 0.01073766, 0.01150460, + 0.01227154, 0.01303847, 0.01380539, 0.01457230, 0.01533921, 0.01610610, 0.01687299, 0.01763986, + 0.01840673, 0.01917358, 0.01994043, 0.02070726, 0.02147408, 0.02224089, 0.02300768, 0.02377446, + 0.02454123, 0.02530798, 0.02607472, 0.02684144, 0.02760815, 0.02837484, 0.02914151, 0.02990817, + 0.03067480, 0.03144142, 0.03220803, 0.03297461, 0.03374117, 0.03450771, 0.03527424, 0.03604074, + 0.03680722, 0.03757368, 0.03834012, 0.03910654, 0.03987293, 0.04063930, 0.04140564, 0.04217196, + 0.04293826, 0.04370453, 0.04447077, 0.04523699, 0.04600318, 0.04676935, 0.04753548, 0.04830159, + 0.04906768, 0.04983373, 0.05059975, 0.05136574, 0.05213170, 0.05289764, 0.05366354, 0.05442941, + 0.05519525, 0.05596105, 0.05672682, 0.05749256, 0.05825827, 0.05902394, 0.05978957, 0.06055517, + 0.06132074, 0.06208627, 0.06285176, 0.06361721, 0.06438263, 0.06514801, 0.06591335, 0.06667866, + 0.06744392, 0.06820914, 0.06897433, 0.06973947, 0.07050458, 0.07126963, 0.07203465, 0.07279963, + 0.07356457, 0.07432945, 0.07509430, 0.07585911, 0.07662386, 0.07738858, 0.07815325, 0.07891786, + 0.07968244, 0.08044697, 0.08121145, 0.08197588, 0.08274026, 0.08350460, 0.08426889, 0.08503313, + 0.08579731, 0.08656145, 0.08732554, 0.08808957, 0.08885355, 0.08961748, 0.09038136, 0.09114519, + 0.09190895, 0.09267268, 0.09343634, 0.09419994, 0.09496350, 0.09572699, 0.09649043, 0.09725381, + 0.09801714, 0.09878041, 0.09954362, 0.10030677, 0.10106986, 0.10183290, 0.10259587, 0.10335878, + 0.10412163, 0.10488442, 0.10564715, 0.10640982, 0.10717242, 0.10793497, 0.10869744, 0.10945985, + 0.11022221, 0.11098449, 0.11174671, 0.11250886, 0.11327095, 0.11403298, 0.11479492, 0.11555681, + 0.11631863, 0.11708038, 0.11784206, 0.11860368, 0.11936522, 0.12012669, 0.12088808, 0.12164941, + 0.12241068, 0.12317186, 0.12393297, 0.12469402, 0.12545498, 0.12621588, 0.12697670, 0.12773745, + 0.12849811, 0.12925871, 0.13001922, 0.13077967, 0.13154003, 0.13230032, 0.13306053, 0.13382065, + 0.13458070, 0.13534068, 0.13610058, 0.13686039, 0.13762012, 0.13837977, 0.13913934, 0.13989884, + 0.14065824, 0.14141756, 0.14217681, 0.14293596, 0.14369503, 0.14445402, 0.14521292, 0.14597175, + 0.14673047, 0.14748912, 0.14824767, 0.14900614, 0.14976454, 0.15052283, 0.15128104, 0.15203916, + 0.15279719, 0.15355512, 0.15431297, 0.15507074, 0.15582840, 0.15658598, 0.15734346, 0.15810084, + 0.15885815, 0.15961535, 0.16037245, 0.16112947, 0.16188639, 0.16264322, 0.16339995, 0.16415659, + 0.16491312, 0.16566956, 0.16642590, 0.16718215, 0.16793829, 0.16869435, 0.16945030, 0.17020614, + 0.17096189, 0.17171754, 0.17247309, 0.17322853, 0.17398387, 0.17473911, 0.17549425, 0.17624930, + 0.17700422, 0.17775905, 0.17851377, 0.17926839, 0.18002290, 0.18077731, 0.18153161, 0.18228580, + 0.18303989, 0.18379387, 0.18454774, 0.18530150, 0.18605515, 0.18680869, 0.18756212, 0.18831545, + 0.18906866, 0.18982176, 0.19057475, 0.19132763, 0.19208039, 0.19283305, 0.19358559, 0.19433801, + 0.19509032, 0.19584252, 0.19659460, 0.19734657, 0.19809841, 0.19885014, 0.19960175, 0.20035325, + 0.20110464, 0.20185590, 0.20260704, 0.20335807, 0.20410897, 0.20485975, 0.20561041, 0.20636095, + 0.20711137, 0.20786168, 0.20861185, 0.20936191, 0.21011184, 0.21086164, 0.21161133, 0.21236089, + 0.21311031, 0.21385963, 0.21460882, 0.21535787, 0.21610680, 0.21685560, 0.21760428, 0.21835282, + 0.21910124, 0.21984953, 0.22059768, 0.22134572, 0.22209363, 0.22284140, 0.22358903, 0.22433653, + 0.22508392, 0.22583115, 0.22657827, 0.22732525, 0.22807208, 0.22881879, 0.22956537, 0.23031181, + 0.23105811, 0.23180428, 0.23255031, 0.23329620, 0.23404196, 0.23478758, 0.23553306, 0.23627840, + 0.23702361, 0.23776866, 0.23851359, 0.23925838, 0.24000302, 0.24074753, 0.24149188, 0.24223611, + 0.24298018, 0.24372411, 0.24446790, 0.24521154, 0.24595505, 0.24669841, 0.24744162, 0.24818468, + 0.24892761, 0.24967039, 0.25041300, 0.25115550, 0.25189781, 0.25264001, 0.25338203, 0.25412393, + 0.25486565, 0.25560725, 0.25634867, 0.25708997, 0.25783110, 0.25857207, 0.25931293, 0.26005360, + 0.26079410, 0.26153448, 0.26227471, 0.26301476, 0.26375467, 0.26449442, 0.26523402, 0.26597348, + 0.26671275, 0.26745188, 0.26819086, 0.26892966, 0.26966831, 0.27040681, 0.27114516, 0.27188334, + 0.27262136, 0.27335921, 0.27409691, 0.27483445, 0.27557182, 0.27630904, 0.27704608, 0.27778298, + 0.27851969, 0.27925625, 0.27999264, 0.28072888, 0.28146493, 0.28220084, 0.28293657, 0.28367212, + 0.28440753, 0.28514278, 0.28587782, 0.28661272, 0.28734747, 0.28808203, 0.28881642, 0.28955063, + 0.29028466, 0.29101855, 0.29175225, 0.29248580, 0.29321915, 0.29395235, 0.29468536, 0.29541820, + 0.29615089, 0.29688337, 0.29761571, 0.29834786, 0.29907984, 0.29981163, 0.30054325, 0.30127469, + 0.30200595, 0.30273703, 0.30346796, 0.30419868, 0.30492923, 0.30565959, 0.30638981, 0.30711982, + 0.30784965, 0.30857930, 0.30930877, 0.31003806, 0.31076714, 0.31149608, 0.31222481, 0.31295338, + 0.31368175, 0.31440994, 0.31513792, 0.31586576, 0.31659338, 0.31732082, 0.31804809, 0.31877515, + 0.31950203, 0.32022873, 0.32095525, 0.32168156, 0.32240769, 0.32313362, 0.32385936, 0.32458493, + 0.32531029, 0.32603547, 0.32676044, 0.32748523, 0.32820985, 0.32893425, 0.32965845, 0.33038250, + 0.33110631, 0.33182994, 0.33255336, 0.33327660, 0.33399966, 0.33472249, 0.33544514, 0.33616760, + 0.33688986, 0.33761191, 0.33833376, 0.33905542, 0.33977687, 0.34049815, 0.34121922, 0.34194008, + 0.34266073, 0.34338117, 0.34410143, 0.34482148, 0.34554133, 0.34626096, 0.34698042, 0.34769964, + 0.34841868, 0.34913751, 0.34985614, 0.35057455, 0.35129276, 0.35201076, 0.35272855, 0.35344616, + 0.35416353, 0.35488069, 0.35559767, 0.35631442, 0.35703096, 0.35774729, 0.35846341, 0.35917935, + 0.35989505, 0.36061051, 0.36132580, 0.36204088, 0.36275572, 0.36347038, 0.36418480, 0.36489901, + 0.36561298, 0.36632678, 0.36704034, 0.36775368, 0.36846682, 0.36917976, 0.36989245, 0.37060493, + 0.37131721, 0.37202924, 0.37274107, 0.37345266, 0.37416407, 0.37487522, 0.37558618, 0.37629691, + 0.37700742, 0.37771770, 0.37842774, 0.37913761, 0.37984720, 0.38055661, 0.38126576, 0.38197473, + 0.38268343, 0.38339192, 0.38410020, 0.38480824, 0.38551605, 0.38622364, 0.38693100, 0.38763815, + 0.38834503, 0.38905174, 0.38975817, 0.39046440, 0.39117038, 0.39187613, 0.39258167, 0.39328697, + 0.39399204, 0.39469686, 0.39540148, 0.39610586, 0.39681000, 0.39751390, 0.39821756, 0.39892101, + 0.39962420, 0.40032718, 0.40102988, 0.40173239, 0.40243465, 0.40313667, 0.40383846, 0.40454000, + 0.40524131, 0.40594238, 0.40664321, 0.40734380, 0.40804416, 0.40874428, 0.40944415, 0.41014379, + 0.41084316, 0.41154233, 0.41224122, 0.41293988, 0.41363832, 0.41433650, 0.41503441, 0.41573212, + 0.41642955, 0.41712677, 0.41782370, 0.41852042, 0.41921690, 0.41991311, 0.42060909, 0.42130479, + 0.42200026, 0.42269549, 0.42339048, 0.42408520, 0.42477968, 0.42547390, 0.42616788, 0.42686161, + 0.42755508, 0.42824832, 0.42894128, 0.42963400, 0.43032649, 0.43101871, 0.43171066, 0.43240237, + 0.43309382, 0.43378502, 0.43447596, 0.43516666, 0.43585709, 0.43654725, 0.43723717, 0.43792683, + 0.43861625, 0.43930539, 0.43999428, 0.44068289, 0.44137126, 0.44205937, 0.44274724, 0.44343480, + 0.44412214, 0.44480920, 0.44549602, 0.44618255, 0.44686884, 0.44755486, 0.44824061, 0.44892609, + 0.44961134, 0.45029628, 0.45098099, 0.45166543, 0.45234957, 0.45303348, 0.45371711, 0.45440048, + 0.45508358, 0.45576641, 0.45644897, 0.45713127, 0.45781329, 0.45849505, 0.45917654, 0.45985776, + 0.46053872, 0.46121940, 0.46189979, 0.46257994, 0.46325979, 0.46393937, 0.46461868, 0.46529773, + 0.46597651, 0.46665499, 0.46733320, 0.46801114, 0.46868882, 0.46936622, 0.47004333, 0.47072017, + 0.47139674, 0.47207302, 0.47274902, 0.47342476, 0.47410020, 0.47477537, 0.47545028, 0.47612488, + 0.47679922, 0.47747329, 0.47814706, 0.47882056, 0.47949377, 0.48016667, 0.48083934, 0.48151168, + 0.48218378, 0.48285556, 0.48352706, 0.48419830, 0.48486924, 0.48553991, 0.48621029, 0.48688036, + 0.48755017, 0.48821968, 0.48888889, 0.48955783, 0.49022648, 0.49089485, 0.49156290, 0.49223071, + 0.49289820, 0.49356541, 0.49423230, 0.49489895, 0.49556527, 0.49623129, 0.49689704, 0.49756250, + 0.49822766, 0.49889255, 0.49955711, 0.50022137, 0.50088537, 0.50154907, 0.50221246, 0.50287557, + 0.50353837, 0.50420088, 0.50486308, 0.50552505, 0.50618666, 0.50684798, 0.50750899, 0.50816971, + 0.50883013, 0.50949025, 0.51015007, 0.51080960, 0.51146883, 0.51212776, 0.51278639, 0.51344472, + 0.51410276, 0.51476043, 0.51541787, 0.51607502, 0.51673180, 0.51738828, 0.51804453, 0.51870042, + 0.51935601, 0.52001125, 0.52066624, 0.52132094, 0.52197528, 0.52262938, 0.52328312, 0.52393657, + 0.52458966, 0.52524251, 0.52589500, 0.52654725, 0.52719915, 0.52785075, 0.52850199, 0.52915299, + 0.52980363, 0.53045398, 0.53110403, 0.53175372, 0.53240311, 0.53305221, 0.53370100, 0.53434944, + 0.53499764, 0.53564548, 0.53629297, 0.53694016, 0.53758705, 0.53823364, 0.53887993, 0.53952587, + 0.54017144, 0.54081678, 0.54146177, 0.54210645, 0.54275078, 0.54339480, 0.54403853, 0.54468191, + 0.54532498, 0.54596776, 0.54661018, 0.54725230, 0.54789406, 0.54853553, 0.54917663, 0.54981750, + 0.55045795, 0.55109817, 0.55173796, 0.55237752, 0.55301672, 0.55365556, 0.55429411, 0.55493236, + 0.55557024, 0.55620778, 0.55684501, 0.55748194, 0.55811852, 0.55875480, 0.55939072, 0.56002629, + 0.56066155, 0.56129652, 0.56193113, 0.56256539, 0.56319934, 0.56383294, 0.56446624, 0.56509918, + 0.56573182, 0.56636411, 0.56699604, 0.56762767, 0.56825894, 0.56888992, 0.56952053, 0.57015079, + 0.57078075, 0.57141036, 0.57203960, 0.57266855, 0.57329714, 0.57392544, 0.57455337, 0.57518095, + 0.57580817, 0.57643509, 0.57706165, 0.57768792, 0.57831377, 0.57893932, 0.57956457, 0.58018941, + 0.58081394, 0.58143812, 0.58206201, 0.58268547, 0.58330864, 0.58393145, 0.58455396, 0.58517605, + 0.58579785, 0.58641928, 0.58704036, 0.58766115, 0.58828157, 0.58890158, 0.58952129, 0.59014070, + 0.59075969, 0.59137839, 0.59199667, 0.59261465, 0.59323227, 0.59384960, 0.59446651, 0.59508306, + 0.59569931, 0.59631521, 0.59693068, 0.59754586, 0.59816068, 0.59877521, 0.59938931, 0.60000306, + 0.60061646, 0.60122955, 0.60184222, 0.60245460, 0.60306662, 0.60367823, 0.60428953, 0.60490048, + 0.60551107, 0.60612124, 0.60673112, 0.60734063, 0.60794979, 0.60855860, 0.60916704, 0.60977507, + 0.61038280, 0.61099017, 0.61159718, 0.61220378, 0.61281008, 0.61341602, 0.61402154, 0.61462677, + 0.61523157, 0.61583608, 0.61644018, 0.61704391, 0.61764729, 0.61825031, 0.61885297, 0.61945528, + 0.62005723, 0.62065876, 0.62125999, 0.62186080, 0.62246126, 0.62306136, 0.62366110, 0.62426049, + 0.62485951, 0.62545812, 0.62605637, 0.62665427, 0.62725180, 0.62784898, 0.62844574, 0.62904221, + 0.62963825, 0.63023394, 0.63082922, 0.63142419, 0.63201874, 0.63261294, 0.63320678, 0.63380021, + 0.63439327, 0.63498598, 0.63557833, 0.63617027, 0.63676184, 0.63735306, 0.63794392, 0.63853437, + 0.63912445, 0.63971418, 0.64030349, 0.64089245, 0.64148104, 0.64206922, 0.64265704, 0.64324450, + 0.64383155, 0.64441824, 0.64500451, 0.64559048, 0.64617604, 0.64676118, 0.64734596, 0.64793038, + 0.64851439, 0.64909804, 0.64968133, 0.65026420, 0.65084666, 0.65142882, 0.65201056, 0.65259188, + 0.65317285, 0.65375340, 0.65433359, 0.65491343, 0.65549284, 0.65607190, 0.65665054, 0.65722883, + 0.65780669, 0.65838420, 0.65896130, 0.65953803, 0.66011435, 0.66069031, 0.66126585, 0.66184098, + 0.66241580, 0.66299015, 0.66356415, 0.66413778, 0.66471100, 0.66528380, 0.66585624, 0.66642827, + 0.66699994, 0.66757119, 0.66814202, 0.66871250, 0.66928262, 0.66985226, 0.67042154, 0.67099047, + 0.67155898, 0.67212707, 0.67269474, 0.67326206, 0.67382902, 0.67439550, 0.67496163, 0.67552739, + 0.67609268, 0.67665762, 0.67722219, 0.67778629, 0.67835003, 0.67891335, 0.67947632, 0.68003887, + 0.68060100, 0.68116271, 0.68172407, 0.68228501, 0.68284553, 0.68340570, 0.68396538, 0.68452471, + 0.68508369, 0.68564218, 0.68620032, 0.68675804, 0.68731534, 0.68787223, 0.68842876, 0.68898487, + 0.68954057, 0.69009584, 0.69065070, 0.69120520, 0.69175923, 0.69231290, 0.69286615, 0.69341904, + 0.69397146, 0.69452351, 0.69507509, 0.69562632, 0.69617712, 0.69672751, 0.69727749, 0.69782710, + 0.69837624, 0.69892502, 0.69947332, 0.70002127, 0.70056880, 0.70111591, 0.70166260, 0.70220888, + 0.70275474, 0.70330018, 0.70384526, 0.70438987, 0.70493406, 0.70547789, 0.70602125, 0.70656425, + 0.70710677, 0.70764893, 0.70819062, 0.70873195, 0.70927280, 0.70981330, 0.71035337, 0.71089298, + 0.71143222, 0.71197098, 0.71250939, 0.71304733, 0.71358484, 0.71412200, 0.71465868, 0.71519494, + 0.71573085, 0.71626627, 0.71680129, 0.71733588, 0.71787006, 0.71840382, 0.71893710, 0.71947002, + 0.72000253, 0.72053456, 0.72106618, 0.72159743, 0.72212821, 0.72265857, 0.72318846, 0.72371799, + 0.72424710, 0.72477573, 0.72530395, 0.72583181, 0.72635913, 0.72688609, 0.72741264, 0.72793871, + 0.72846437, 0.72898960, 0.72951442, 0.73003882, 0.73056275, 0.73108631, 0.73160940, 0.73213202, + 0.73265427, 0.73317605, 0.73369741, 0.73421836, 0.73473889, 0.73525894, 0.73577857, 0.73629779, + 0.73681659, 0.73733491, 0.73785281, 0.73837030, 0.73888731, 0.73940390, 0.73992008, 0.74043584, + 0.74095112, 0.74146599, 0.74198043, 0.74249440, 0.74300796, 0.74352109, 0.74403375, 0.74454600, + 0.74505776, 0.74556917, 0.74608010, 0.74659055, 0.74710059, 0.74761021, 0.74811935, 0.74862808, + 0.74913639, 0.74964422, 0.75015163, 0.75065863, 0.75116515, 0.75167120, 0.75217682, 0.75268203, + 0.75318682, 0.75369114, 0.75419497, 0.75469840, 0.75520140, 0.75570393, 0.75620598, 0.75670767, + 0.75720882, 0.75770962, 0.75820988, 0.75870979, 0.75920922, 0.75970817, 0.76020670, 0.76070476, + 0.76120239, 0.76169956, 0.76219630, 0.76269257, 0.76318842, 0.76368380, 0.76417875, 0.76467323, + 0.76516724, 0.76566088, 0.76615399, 0.76664668, 0.76713890, 0.76763070, 0.76812202, 0.76861292, + 0.76910335, 0.76959330, 0.77008283, 0.77057189, 0.77106053, 0.77154869, 0.77203637, 0.77252364, + 0.77301043, 0.77349681, 0.77398270, 0.77446812, 0.77495313, 0.77543765, 0.77592170, 0.77640533, + 0.77688849, 0.77737117, 0.77785343, 0.77833521, 0.77881652, 0.77929735, 0.77977777, 0.78025776, + 0.78073722, 0.78121626, 0.78169483, 0.78217292, 0.78265059, 0.78312778, 0.78360450, 0.78408080, + 0.78455657, 0.78503191, 0.78550684, 0.78598124, 0.78645521, 0.78692871, 0.78740174, 0.78787434, + 0.78834641, 0.78881806, 0.78928924, 0.78975999, 0.79023021, 0.79070002, 0.79116935, 0.79163820, + 0.79210657, 0.79257452, 0.79304194, 0.79350895, 0.79397547, 0.79444152, 0.79490715, 0.79537225, + 0.79583693, 0.79630107, 0.79676479, 0.79722804, 0.79769087, 0.79815316, 0.79861498, 0.79907638, + 0.79953724, 0.79999769, 0.80045766, 0.80091715, 0.80137616, 0.80183470, 0.80229282, 0.80275041, + 0.80320752, 0.80366421, 0.80412036, 0.80457610, 0.80503136, 0.80548608, 0.80594039, 0.80639422, + 0.80684757, 0.80730045, 0.80775285, 0.80820471, 0.80865616, 0.80910712, 0.80955762, 0.81000763, + 0.81045717, 0.81090623, 0.81135488, 0.81180298, 0.81225061, 0.81269777, 0.81314439, 0.81359059, + 0.81403631, 0.81448156, 0.81492633, 0.81537062, 0.81581444, 0.81625772, 0.81670058, 0.81714290, + 0.81758481, 0.81802619, 0.81846714, 0.81890756, 0.81934750, 0.81978697, 0.82022595, 0.82066447, + 0.82110250, 0.82154006, 0.82197714, 0.82241368, 0.82284981, 0.82328540, 0.82372051, 0.82415515, + 0.82458931, 0.82502300, 0.82545614, 0.82588887, 0.82632107, 0.82675278, 0.82718402, 0.82761478, + 0.82804507, 0.82847482, 0.82890409, 0.82933295, 0.82976121, 0.83018905, 0.83061641, 0.83104324, + 0.83146960, 0.83189547, 0.83232087, 0.83274579, 0.83317018, 0.83359408, 0.83401752, 0.83444041, + 0.83486289, 0.83528483, 0.83570629, 0.83612728, 0.83654773, 0.83696771, 0.83738720, 0.83780622, + 0.83822471, 0.83864272, 0.83906025, 0.83947724, 0.83989382, 0.84030986, 0.84072536, 0.84114045, + 0.84155500, 0.84196901, 0.84238261, 0.84279567, 0.84320825, 0.84362030, 0.84403187, 0.84444296, + 0.84485358, 0.84526366, 0.84567326, 0.84608233, 0.84649092, 0.84689903, 0.84730661, 0.84771377, + 0.84812033, 0.84852648, 0.84893203, 0.84933716, 0.84974176, 0.85014588, 0.85054946, 0.85095257, + 0.85135520, 0.85175729, 0.85215890, 0.85255998, 0.85296059, 0.85336071, 0.85376030, 0.85415941, + 0.85455799, 0.85495609, 0.85535365, 0.85575074, 0.85614735, 0.85654342, 0.85693896, 0.85733402, + 0.85772860, 0.85812265, 0.85851622, 0.85890925, 0.85930181, 0.85969388, 0.86008537, 0.86047643, + 0.86086696, 0.86125696, 0.86164647, 0.86203545, 0.86242396, 0.86281192, 0.86319941, 0.86358637, + 0.86397284, 0.86435878, 0.86474425, 0.86512917, 0.86551362, 0.86589754, 0.86628097, 0.86666387, + 0.86704624, 0.86742812, 0.86780947, 0.86819035, 0.86857069, 0.86895055, 0.86932987, 0.86970866, + 0.87008697, 0.87046480, 0.87084204, 0.87121886, 0.87159508, 0.87197083, 0.87234604, 0.87272078, + 0.87309498, 0.87346870, 0.87384182, 0.87421453, 0.87458664, 0.87495828, 0.87532938, 0.87570000, + 0.87607008, 0.87643969, 0.87680870, 0.87717724, 0.87754530, 0.87791282, 0.87827981, 0.87864625, + 0.87901223, 0.87937766, 0.87974262, 0.88010699, 0.88047087, 0.88083428, 0.88119709, 0.88155943, + 0.88192129, 0.88228256, 0.88264334, 0.88300359, 0.88336337, 0.88372254, 0.88408124, 0.88443947, + 0.88479710, 0.88515425, 0.88551086, 0.88586694, 0.88622254, 0.88657761, 0.88693213, 0.88728613, + 0.88763964, 0.88799256, 0.88834506, 0.88869697, 0.88904834, 0.88939923, 0.88974959, 0.89009941, + 0.89044875, 0.89079750, 0.89114577, 0.89149350, 0.89184070, 0.89218742, 0.89253354, 0.89287919, + 0.89322430, 0.89356887, 0.89391297, 0.89425647, 0.89459950, 0.89494199, 0.89528394, 0.89562535, + 0.89596623, 0.89630663, 0.89664650, 0.89698577, 0.89732456, 0.89766282, 0.89800060, 0.89833778, + 0.89867449, 0.89901060, 0.89934623, 0.89968133, 0.90001589, 0.90034992, 0.90068340, 0.90101641, + 0.90134883, 0.90168077, 0.90201217, 0.90234298, 0.90267330, 0.90300310, 0.90333235, 0.90366107, + 0.90398932, 0.90431696, 0.90464407, 0.90497071, 0.90529674, 0.90562230, 0.90594727, 0.90627176, + 0.90659571, 0.90691912, 0.90724200, 0.90756434, 0.90788609, 0.90820736, 0.90852809, 0.90884835, + 0.90916800, 0.90948713, 0.90980572, 0.91012377, 0.91044128, 0.91075826, 0.91107476, 0.91139066, + 0.91170603, 0.91202086, 0.91233516, 0.91264898, 0.91296220, 0.91327488, 0.91358703, 0.91389865, + 0.91420978, 0.91452032, 0.91483033, 0.91513979, 0.91544873, 0.91575712, 0.91606498, 0.91637230, + 0.91667908, 0.91698527, 0.91729099, 0.91759616, 0.91790080, 0.91820484, 0.91850841, 0.91881138, + 0.91911387, 0.91941577, 0.91971713, 0.92001796, 0.92031831, 0.92061806, 0.92091721, 0.92121589, + 0.92151403, 0.92181164, 0.92210865, 0.92240518, 0.92270112, 0.92299652, 0.92329144, 0.92358577, + 0.92387950, 0.92417276, 0.92446548, 0.92475760, 0.92504925, 0.92534029, 0.92563081, 0.92592078, + 0.92621022, 0.92649913, 0.92678750, 0.92707527, 0.92736250, 0.92764926, 0.92793542, 0.92822099, + 0.92850608, 0.92879063, 0.92907459, 0.92935801, 0.92964089, 0.92992324, 0.93020505, 0.93048626, + 0.93076694, 0.93104708, 0.93132669, 0.93160576, 0.93188429, 0.93216223, 0.93243963, 0.93271649, + 0.93299282, 0.93326855, 0.93354380, 0.93381846, 0.93409252, 0.93436611, 0.93463916, 0.93491161, + 0.93518353, 0.93545485, 0.93572569, 0.93599594, 0.93626565, 0.93653482, 0.93680346, 0.93707150, + 0.93733901, 0.93760598, 0.93787235, 0.93813825, 0.93840355, 0.93866831, 0.93893248, 0.93919611, + 0.93945920, 0.93972176, 0.93998373, 0.94024521, 0.94050604, 0.94076639, 0.94102615, 0.94128537, + 0.94154406, 0.94180220, 0.94205976, 0.94231677, 0.94257319, 0.94282907, 0.94308442, 0.94333923, + 0.94359344, 0.94384712, 0.94410026, 0.94435281, 0.94460481, 0.94485629, 0.94510722, 0.94535756, + 0.94560730, 0.94585657, 0.94610524, 0.94635338, 0.94660091, 0.94684792, 0.94709438, 0.94734025, + 0.94758558, 0.94783038, 0.94807458, 0.94831824, 0.94856137, 0.94880390, 0.94904590, 0.94928730, + 0.94952816, 0.94976848, 0.95000827, 0.95024747, 0.95048606, 0.95072412, 0.95096165, 0.95119864, + 0.95143503, 0.95167089, 0.95190614, 0.95214087, 0.95237499, 0.95260859, 0.95284164, 0.95307410, + 0.95330602, 0.95353740, 0.95376819, 0.95399845, 0.95422810, 0.95445722, 0.95468575, 0.95491374, + 0.95514119, 0.95536804, 0.95559436, 0.95582008, 0.95604527, 0.95626986, 0.95649391, 0.95671743, + 0.95694035, 0.95716268, 0.95738453, 0.95760572, 0.95782644, 0.95804650, 0.95826608, 0.95848507, + 0.95870346, 0.95892131, 0.95913863, 0.95935535, 0.95957154, 0.95978713, 0.96000212, 0.96021664, + 0.96043050, 0.96064389, 0.96085662, 0.96106887, 0.96128047, 0.96149158, 0.96170205, 0.96191204, + 0.96212143, 0.96233022, 0.96253848, 0.96274614, 0.96295327, 0.96315980, 0.96336579, 0.96357119, + 0.96377605, 0.96398038, 0.96418405, 0.96438724, 0.96458977, 0.96479183, 0.96499324, 0.96519411, + 0.96539444, 0.96559417, 0.96579337, 0.96599197, 0.96618998, 0.96638745, 0.96658438, 0.96678072, + 0.96697646, 0.96717167, 0.96736628, 0.96756035, 0.96775383, 0.96794677, 0.96813911, 0.96833086, + 0.96852207, 0.96871275, 0.96890283, 0.96909231, 0.96928126, 0.96946961, 0.96965736, 0.96984458, + 0.97003126, 0.97021735, 0.97040284, 0.97058779, 0.97077215, 0.97095591, 0.97113913, 0.97132182, + 0.97150391, 0.97168541, 0.97186631, 0.97204673, 0.97222650, 0.97240573, 0.97258437, 0.97276247, + 0.97293997, 0.97311687, 0.97329324, 0.97346902, 0.97364426, 0.97381890, 0.97399294, 0.97416645, + 0.97433937, 0.97451174, 0.97468352, 0.97485471, 0.97502536, 0.97519541, 0.97536486, 0.97553378, + 0.97570211, 0.97586989, 0.97603709, 0.97620368, 0.97636974, 0.97653520, 0.97670007, 0.97686440, + 0.97702813, 0.97719133, 0.97735387, 0.97751594, 0.97767735, 0.97783822, 0.97799850, 0.97815824, + 0.97831738, 0.97847593, 0.97863394, 0.97879136, 0.97894818, 0.97910446, 0.97926015, 0.97941524, + 0.97956979, 0.97972375, 0.97987711, 0.98002988, 0.98018211, 0.98033381, 0.98048484, 0.98063534, + 0.98078525, 0.98093462, 0.98108339, 0.98123157, 0.98137921, 0.98152626, 0.98167270, 0.98181856, + 0.98196387, 0.98210859, 0.98225272, 0.98239630, 0.98253930, 0.98268169, 0.98282355, 0.98296481, + 0.98310548, 0.98324561, 0.98338509, 0.98352402, 0.98366243, 0.98380023, 0.98393744, 0.98407406, + 0.98421007, 0.98434556, 0.98448044, 0.98461479, 0.98474848, 0.98488164, 0.98501426, 0.98514622, + 0.98527765, 0.98540848, 0.98553872, 0.98566842, 0.98579752, 0.98592603, 0.98605394, 0.98618132, + 0.98630810, 0.98643428, 0.98655993, 0.98668492, 0.98680937, 0.98693329, 0.98705655, 0.98717928, + 0.98730141, 0.98742294, 0.98754394, 0.98766434, 0.98778415, 0.98790336, 0.98802203, 0.98814011, + 0.98825759, 0.98837447, 0.98849082, 0.98860651, 0.98872167, 0.98883629, 0.98895025, 0.98906368, + 0.98917651, 0.98928875, 0.98940045, 0.98951149, 0.98962200, 0.98973197, 0.98984128, 0.98995006, + 0.99005818, 0.99016583, 0.99027282, 0.99037921, 0.99048507, 0.99059033, 0.99069500, 0.99079913, + 0.99090266, 0.99100554, 0.99110794, 0.99120969, 0.99131083, 0.99141145, 0.99151146, 0.99161088, + 0.99170977, 0.99180800, 0.99190569, 0.99200279, 0.99209929, 0.99219525, 0.99229062, 0.99238533, + 0.99247956, 0.99257314, 0.99266613, 0.99275857, 0.99285042, 0.99294168, 0.99303234, 0.99312246, + 0.99321193, 0.99330086, 0.99338919, 0.99347699, 0.99356413, 0.99365073, 0.99373674, 0.99382216, + 0.99390697, 0.99399120, 0.99407488, 0.99415797, 0.99424046, 0.99432236, 0.99440366, 0.99448442, + 0.99456459, 0.99464417, 0.99472314, 0.99480152, 0.99487931, 0.99495655, 0.99503320, 0.99510926, + 0.99518472, 0.99525958, 0.99533391, 0.99540764, 0.99548078, 0.99555331, 0.99562526, 0.99569660, + 0.99576741, 0.99583763, 0.99590725, 0.99597627, 0.99604470, 0.99611259, 0.99617982, 0.99624652, + 0.99631262, 0.99637812, 0.99644303, 0.99650741, 0.99657112, 0.99663430, 0.99669689, 0.99675888, + 0.99682027, 0.99688113, 0.99694133, 0.99700099, 0.99706006, 0.99711853, 0.99717641, 0.99723375, + 0.99729043, 0.99734658, 0.99740213, 0.99745709, 0.99751145, 0.99756521, 0.99761844, 0.99767107, + 0.99772304, 0.99777448, 0.99782532, 0.99787563, 0.99792528, 0.99797440, 0.99802285, 0.99807078, + 0.99811810, 0.99816483, 0.99821103, 0.99825656, 0.99830157, 0.99834591, 0.99838972, 0.99843293, + 0.99847555, 0.99851763, 0.99855906, 0.99859995, 0.99864024, 0.99867994, 0.99871904, 0.99875754, + 0.99879545, 0.99883282, 0.99886954, 0.99890572, 0.99894130, 0.99897629, 0.99901068, 0.99904448, + 0.99907774, 0.99911034, 0.99914241, 0.99917388, 0.99920475, 0.99923503, 0.99926478, 0.99929386, + 0.99932235, 0.99935031, 0.99937767, 0.99940443, 0.99943060, 0.99945617, 0.99948120, 0.99950558, + 0.99952942, 0.99955267, 0.99957532, 0.99959737, 0.99961883, 0.99963969, 0.99966002, 0.99967968, + 0.99969882, 0.99971735, 0.99973530, 0.99975264, 0.99976939, 0.99978560, 0.99980116, 0.99981618, + 0.99983060, 0.99984443, 0.99985766, 0.99987030, 0.99988234, 0.99989384, 0.99990469, 0.99991500, + 0.99992472, 0.99993384, 0.99994236, 0.99995029, 0.99995762, 0.99996442, 0.99997061, 0.99997616, + 0.99998116, 0.99998558, 0.99998939, 0.99999267, 0.99999529, 0.99999738, 0.99999881, 0.99999970 + }; + +static const float sinTable[FFT_TABLE_SIZE]={ + 0.00000000, 0.00076699, 0.00153398, 0.00230097, 0.00306796, 0.00383494, 0.00460193, 0.00536891, + 0.00613588, 0.00690286, 0.00766983, 0.00843679, 0.00920375, 0.00997071, 0.01073766, 0.01150460, + 0.01227154, 0.01303847, 0.01380539, 0.01457230, 0.01533921, 0.01610610, 0.01687299, 0.01763986, + 0.01840673, 0.01917358, 0.01994043, 0.02070726, 0.02147408, 0.02224089, 0.02300768, 0.02377446, + 0.02454123, 0.02530798, 0.02607472, 0.02684144, 0.02760815, 0.02837484, 0.02914151, 0.02990817, + 0.03067480, 0.03144142, 0.03220803, 0.03297461, 0.03374117, 0.03450771, 0.03527424, 0.03604074, + 0.03680722, 0.03757368, 0.03834012, 0.03910654, 0.03987293, 0.04063930, 0.04140564, 0.04217196, + 0.04293826, 0.04370453, 0.04447077, 0.04523699, 0.04600318, 0.04676935, 0.04753548, 0.04830159, + 0.04906768, 0.04983373, 0.05059975, 0.05136574, 0.05213170, 0.05289764, 0.05366354, 0.05442941, + 0.05519525, 0.05596105, 0.05672682, 0.05749256, 0.05825827, 0.05902394, 0.05978957, 0.06055517, + 0.06132074, 0.06208627, 0.06285176, 0.06361721, 0.06438263, 0.06514801, 0.06591335, 0.06667866, + 0.06744392, 0.06820914, 0.06897433, 0.06973947, 0.07050458, 0.07126963, 0.07203465, 0.07279963, + 0.07356457, 0.07432945, 0.07509430, 0.07585911, 0.07662386, 0.07738858, 0.07815325, 0.07891786, + 0.07968244, 0.08044697, 0.08121145, 0.08197588, 0.08274026, 0.08350460, 0.08426889, 0.08503313, + 0.08579731, 0.08656145, 0.08732554, 0.08808957, 0.08885355, 0.08961748, 0.09038136, 0.09114519, + 0.09190895, 0.09267268, 0.09343634, 0.09419994, 0.09496350, 0.09572699, 0.09649043, 0.09725381, + 0.09801714, 0.09878041, 0.09954362, 0.10030677, 0.10106986, 0.10183290, 0.10259587, 0.10335878, + 0.10412163, 0.10488442, 0.10564715, 0.10640982, 0.10717242, 0.10793497, 0.10869744, 0.10945985, + 0.11022221, 0.11098449, 0.11174671, 0.11250886, 0.11327095, 0.11403298, 0.11479492, 0.11555681, + 0.11631863, 0.11708038, 0.11784206, 0.11860368, 0.11936522, 0.12012669, 0.12088808, 0.12164941, + 0.12241068, 0.12317186, 0.12393297, 0.12469402, 0.12545498, 0.12621588, 0.12697670, 0.12773745, + 0.12849811, 0.12925871, 0.13001922, 0.13077967, 0.13154003, 0.13230032, 0.13306053, 0.13382065, + 0.13458070, 0.13534068, 0.13610058, 0.13686039, 0.13762012, 0.13837977, 0.13913934, 0.13989884, + 0.14065824, 0.14141756, 0.14217681, 0.14293596, 0.14369503, 0.14445402, 0.14521292, 0.14597175, + 0.14673047, 0.14748912, 0.14824767, 0.14900614, 0.14976454, 0.15052283, 0.15128104, 0.15203916, + 0.15279719, 0.15355512, 0.15431297, 0.15507074, 0.15582840, 0.15658598, 0.15734346, 0.15810084, + 0.15885815, 0.15961535, 0.16037245, 0.16112947, 0.16188639, 0.16264322, 0.16339995, 0.16415659, + 0.16491312, 0.16566956, 0.16642590, 0.16718215, 0.16793829, 0.16869435, 0.16945030, 0.17020614, + 0.17096189, 0.17171754, 0.17247309, 0.17322853, 0.17398387, 0.17473911, 0.17549425, 0.17624930, + 0.17700422, 0.17775905, 0.17851377, 0.17926839, 0.18002290, 0.18077731, 0.18153161, 0.18228580, + 0.18303989, 0.18379387, 0.18454774, 0.18530150, 0.18605515, 0.18680869, 0.18756212, 0.18831545, + 0.18906866, 0.18982176, 0.19057475, 0.19132763, 0.19208039, 0.19283305, 0.19358559, 0.19433801, + 0.19509032, 0.19584252, 0.19659460, 0.19734657, 0.19809841, 0.19885014, 0.19960175, 0.20035325, + 0.20110464, 0.20185590, 0.20260704, 0.20335807, 0.20410897, 0.20485975, 0.20561041, 0.20636095, + 0.20711137, 0.20786168, 0.20861185, 0.20936191, 0.21011184, 0.21086164, 0.21161133, 0.21236089, + 0.21311031, 0.21385963, 0.21460882, 0.21535787, 0.21610680, 0.21685560, 0.21760428, 0.21835282, + 0.21910124, 0.21984953, 0.22059768, 0.22134572, 0.22209363, 0.22284140, 0.22358903, 0.22433653, + 0.22508392, 0.22583115, 0.22657827, 0.22732525, 0.22807208, 0.22881879, 0.22956537, 0.23031181, + 0.23105811, 0.23180428, 0.23255031, 0.23329620, 0.23404196, 0.23478758, 0.23553306, 0.23627840, + 0.23702361, 0.23776866, 0.23851359, 0.23925838, 0.24000302, 0.24074753, 0.24149188, 0.24223611, + 0.24298018, 0.24372411, 0.24446790, 0.24521154, 0.24595505, 0.24669841, 0.24744162, 0.24818468, + 0.24892761, 0.24967039, 0.25041300, 0.25115550, 0.25189781, 0.25264001, 0.25338203, 0.25412393, + 0.25486565, 0.25560725, 0.25634867, 0.25708997, 0.25783110, 0.25857207, 0.25931293, 0.26005360, + 0.26079410, 0.26153448, 0.26227471, 0.26301476, 0.26375467, 0.26449442, 0.26523402, 0.26597348, + 0.26671275, 0.26745188, 0.26819086, 0.26892966, 0.26966831, 0.27040681, 0.27114516, 0.27188334, + 0.27262136, 0.27335921, 0.27409691, 0.27483445, 0.27557182, 0.27630904, 0.27704608, 0.27778298, + 0.27851969, 0.27925625, 0.27999264, 0.28072888, 0.28146493, 0.28220084, 0.28293657, 0.28367212, + 0.28440753, 0.28514278, 0.28587782, 0.28661272, 0.28734747, 0.28808203, 0.28881642, 0.28955063, + 0.29028466, 0.29101855, 0.29175225, 0.29248580, 0.29321915, 0.29395235, 0.29468536, 0.29541820, + 0.29615089, 0.29688337, 0.29761571, 0.29834786, 0.29907984, 0.29981163, 0.30054325, 0.30127469, + 0.30200595, 0.30273703, 0.30346796, 0.30419868, 0.30492923, 0.30565959, 0.30638981, 0.30711982, + 0.30784965, 0.30857930, 0.30930877, 0.31003806, 0.31076714, 0.31149608, 0.31222481, 0.31295338, + 0.31368175, 0.31440994, 0.31513792, 0.31586576, 0.31659338, 0.31732082, 0.31804809, 0.31877515, + 0.31950203, 0.32022873, 0.32095525, 0.32168156, 0.32240769, 0.32313362, 0.32385936, 0.32458493, + 0.32531029, 0.32603547, 0.32676044, 0.32748523, 0.32820985, 0.32893425, 0.32965845, 0.33038250, + 0.33110631, 0.33182994, 0.33255336, 0.33327660, 0.33399966, 0.33472249, 0.33544514, 0.33616760, + 0.33688986, 0.33761191, 0.33833376, 0.33905542, 0.33977687, 0.34049815, 0.34121922, 0.34194008, + 0.34266073, 0.34338117, 0.34410143, 0.34482148, 0.34554133, 0.34626096, 0.34698042, 0.34769964, + 0.34841868, 0.34913751, 0.34985614, 0.35057455, 0.35129276, 0.35201076, 0.35272855, 0.35344616, + 0.35416353, 0.35488069, 0.35559767, 0.35631442, 0.35703096, 0.35774729, 0.35846341, 0.35917935, + 0.35989505, 0.36061051, 0.36132580, 0.36204088, 0.36275572, 0.36347038, 0.36418480, 0.36489901, + 0.36561298, 0.36632678, 0.36704034, 0.36775368, 0.36846682, 0.36917976, 0.36989245, 0.37060493, + 0.37131721, 0.37202924, 0.37274107, 0.37345266, 0.37416407, 0.37487522, 0.37558618, 0.37629691, + 0.37700742, 0.37771770, 0.37842774, 0.37913761, 0.37984720, 0.38055661, 0.38126576, 0.38197473, + 0.38268343, 0.38339192, 0.38410020, 0.38480824, 0.38551605, 0.38622364, 0.38693100, 0.38763815, + 0.38834503, 0.38905174, 0.38975817, 0.39046440, 0.39117038, 0.39187613, 0.39258167, 0.39328697, + 0.39399204, 0.39469686, 0.39540148, 0.39610586, 0.39681000, 0.39751390, 0.39821756, 0.39892101, + 0.39962420, 0.40032718, 0.40102988, 0.40173239, 0.40243465, 0.40313667, 0.40383846, 0.40454000, + 0.40524131, 0.40594238, 0.40664321, 0.40734380, 0.40804416, 0.40874428, 0.40944415, 0.41014379, + 0.41084316, 0.41154233, 0.41224122, 0.41293988, 0.41363832, 0.41433650, 0.41503441, 0.41573212, + 0.41642955, 0.41712677, 0.41782370, 0.41852042, 0.41921690, 0.41991311, 0.42060909, 0.42130479, + 0.42200026, 0.42269549, 0.42339048, 0.42408520, 0.42477968, 0.42547390, 0.42616788, 0.42686161, + 0.42755508, 0.42824832, 0.42894128, 0.42963400, 0.43032649, 0.43101871, 0.43171066, 0.43240237, + 0.43309382, 0.43378502, 0.43447596, 0.43516666, 0.43585709, 0.43654725, 0.43723717, 0.43792683, + 0.43861625, 0.43930539, 0.43999428, 0.44068289, 0.44137126, 0.44205937, 0.44274724, 0.44343480, + 0.44412214, 0.44480920, 0.44549602, 0.44618255, 0.44686884, 0.44755486, 0.44824061, 0.44892609, + 0.44961134, 0.45029628, 0.45098099, 0.45166543, 0.45234957, 0.45303348, 0.45371711, 0.45440048, + 0.45508358, 0.45576641, 0.45644897, 0.45713127, 0.45781329, 0.45849505, 0.45917654, 0.45985776, + 0.46053872, 0.46121940, 0.46189979, 0.46257994, 0.46325979, 0.46393937, 0.46461868, 0.46529773, + 0.46597651, 0.46665499, 0.46733320, 0.46801114, 0.46868882, 0.46936622, 0.47004333, 0.47072017, + 0.47139674, 0.47207302, 0.47274902, 0.47342476, 0.47410020, 0.47477537, 0.47545028, 0.47612488, + 0.47679922, 0.47747329, 0.47814706, 0.47882056, 0.47949377, 0.48016667, 0.48083934, 0.48151168, + 0.48218378, 0.48285556, 0.48352706, 0.48419830, 0.48486924, 0.48553991, 0.48621029, 0.48688036, + 0.48755017, 0.48821968, 0.48888889, 0.48955783, 0.49022648, 0.49089485, 0.49156290, 0.49223071, + 0.49289820, 0.49356541, 0.49423230, 0.49489895, 0.49556527, 0.49623129, 0.49689704, 0.49756250, + 0.49822766, 0.49889255, 0.49955711, 0.50022137, 0.50088537, 0.50154907, 0.50221246, 0.50287557, + 0.50353837, 0.50420088, 0.50486308, 0.50552505, 0.50618666, 0.50684798, 0.50750899, 0.50816971, + 0.50883013, 0.50949025, 0.51015007, 0.51080960, 0.51146883, 0.51212776, 0.51278639, 0.51344472, + 0.51410276, 0.51476043, 0.51541787, 0.51607502, 0.51673180, 0.51738828, 0.51804453, 0.51870042, + 0.51935601, 0.52001125, 0.52066624, 0.52132094, 0.52197528, 0.52262938, 0.52328312, 0.52393657, + 0.52458966, 0.52524251, 0.52589500, 0.52654725, 0.52719915, 0.52785075, 0.52850199, 0.52915299, + 0.52980363, 0.53045398, 0.53110403, 0.53175372, 0.53240311, 0.53305221, 0.53370100, 0.53434944, + 0.53499764, 0.53564548, 0.53629297, 0.53694016, 0.53758705, 0.53823364, 0.53887993, 0.53952587, + 0.54017144, 0.54081678, 0.54146177, 0.54210645, 0.54275078, 0.54339480, 0.54403853, 0.54468191, + 0.54532498, 0.54596776, 0.54661018, 0.54725230, 0.54789406, 0.54853553, 0.54917663, 0.54981750, + 0.55045795, 0.55109817, 0.55173796, 0.55237752, 0.55301672, 0.55365556, 0.55429411, 0.55493236, + 0.55557024, 0.55620778, 0.55684501, 0.55748194, 0.55811852, 0.55875480, 0.55939072, 0.56002629, + 0.56066155, 0.56129652, 0.56193113, 0.56256539, 0.56319934, 0.56383294, 0.56446624, 0.56509918, + 0.56573182, 0.56636411, 0.56699604, 0.56762767, 0.56825894, 0.56888992, 0.56952053, 0.57015079, + 0.57078075, 0.57141036, 0.57203960, 0.57266855, 0.57329714, 0.57392544, 0.57455337, 0.57518095, + 0.57580817, 0.57643509, 0.57706165, 0.57768792, 0.57831377, 0.57893932, 0.57956457, 0.58018941, + 0.58081394, 0.58143812, 0.58206201, 0.58268547, 0.58330864, 0.58393145, 0.58455396, 0.58517605, + 0.58579785, 0.58641928, 0.58704036, 0.58766115, 0.58828157, 0.58890158, 0.58952129, 0.59014070, + 0.59075969, 0.59137839, 0.59199667, 0.59261465, 0.59323227, 0.59384960, 0.59446651, 0.59508306, + 0.59569931, 0.59631521, 0.59693068, 0.59754586, 0.59816068, 0.59877521, 0.59938931, 0.60000306, + 0.60061646, 0.60122955, 0.60184222, 0.60245460, 0.60306662, 0.60367823, 0.60428953, 0.60490048, + 0.60551107, 0.60612124, 0.60673112, 0.60734063, 0.60794979, 0.60855860, 0.60916704, 0.60977507, + 0.61038280, 0.61099017, 0.61159718, 0.61220378, 0.61281008, 0.61341602, 0.61402154, 0.61462677, + 0.61523157, 0.61583608, 0.61644018, 0.61704391, 0.61764729, 0.61825031, 0.61885297, 0.61945528, + 0.62005723, 0.62065876, 0.62125999, 0.62186080, 0.62246126, 0.62306136, 0.62366110, 0.62426049, + 0.62485951, 0.62545812, 0.62605637, 0.62665427, 0.62725180, 0.62784898, 0.62844574, 0.62904221, + 0.62963825, 0.63023394, 0.63082922, 0.63142419, 0.63201874, 0.63261294, 0.63320678, 0.63380021, + 0.63439327, 0.63498598, 0.63557833, 0.63617027, 0.63676184, 0.63735306, 0.63794392, 0.63853437, + 0.63912445, 0.63971418, 0.64030349, 0.64089245, 0.64148104, 0.64206922, 0.64265704, 0.64324450, + 0.64383155, 0.64441824, 0.64500451, 0.64559048, 0.64617604, 0.64676118, 0.64734596, 0.64793038, + 0.64851439, 0.64909804, 0.64968133, 0.65026420, 0.65084666, 0.65142882, 0.65201056, 0.65259188, + 0.65317285, 0.65375340, 0.65433359, 0.65491343, 0.65549284, 0.65607190, 0.65665054, 0.65722883, + 0.65780669, 0.65838420, 0.65896130, 0.65953803, 0.66011435, 0.66069031, 0.66126585, 0.66184098, + 0.66241580, 0.66299015, 0.66356415, 0.66413778, 0.66471100, 0.66528380, 0.66585624, 0.66642827, + 0.66699994, 0.66757119, 0.66814202, 0.66871250, 0.66928262, 0.66985226, 0.67042154, 0.67099047, + 0.67155898, 0.67212707, 0.67269474, 0.67326206, 0.67382902, 0.67439550, 0.67496163, 0.67552739, + 0.67609268, 0.67665762, 0.67722219, 0.67778629, 0.67835003, 0.67891335, 0.67947632, 0.68003887, + 0.68060100, 0.68116271, 0.68172407, 0.68228501, 0.68284553, 0.68340570, 0.68396538, 0.68452471, + 0.68508369, 0.68564218, 0.68620032, 0.68675804, 0.68731534, 0.68787223, 0.68842876, 0.68898487, + 0.68954057, 0.69009584, 0.69065070, 0.69120520, 0.69175923, 0.69231290, 0.69286615, 0.69341904, + 0.69397146, 0.69452351, 0.69507509, 0.69562632, 0.69617712, 0.69672751, 0.69727749, 0.69782710, + 0.69837624, 0.69892502, 0.69947332, 0.70002127, 0.70056880, 0.70111591, 0.70166260, 0.70220888, + 0.70275474, 0.70330018, 0.70384526, 0.70438987, 0.70493406, 0.70547789, 0.70602125, 0.70656425, + 0.70710677, 0.70764893, 0.70819062, 0.70873195, 0.70927280, 0.70981330, 0.71035337, 0.71089298, + 0.71143222, 0.71197098, 0.71250939, 0.71304733, 0.71358484, 0.71412200, 0.71465868, 0.71519494, + 0.71573085, 0.71626627, 0.71680129, 0.71733588, 0.71787006, 0.71840382, 0.71893710, 0.71947002, + 0.72000253, 0.72053456, 0.72106618, 0.72159743, 0.72212821, 0.72265857, 0.72318846, 0.72371799, + 0.72424710, 0.72477573, 0.72530395, 0.72583181, 0.72635913, 0.72688609, 0.72741264, 0.72793871, + 0.72846437, 0.72898960, 0.72951442, 0.73003882, 0.73056275, 0.73108631, 0.73160940, 0.73213202, + 0.73265427, 0.73317605, 0.73369741, 0.73421836, 0.73473889, 0.73525894, 0.73577857, 0.73629779, + 0.73681659, 0.73733491, 0.73785281, 0.73837030, 0.73888731, 0.73940390, 0.73992008, 0.74043584, + 0.74095112, 0.74146599, 0.74198043, 0.74249440, 0.74300796, 0.74352109, 0.74403375, 0.74454600, + 0.74505776, 0.74556917, 0.74608010, 0.74659055, 0.74710059, 0.74761021, 0.74811935, 0.74862808, + 0.74913639, 0.74964422, 0.75015163, 0.75065863, 0.75116515, 0.75167120, 0.75217682, 0.75268203, + 0.75318682, 0.75369114, 0.75419497, 0.75469840, 0.75520140, 0.75570393, 0.75620598, 0.75670767, + 0.75720882, 0.75770962, 0.75820988, 0.75870979, 0.75920922, 0.75970817, 0.76020670, 0.76070476, + 0.76120239, 0.76169956, 0.76219630, 0.76269257, 0.76318842, 0.76368380, 0.76417875, 0.76467323, + 0.76516724, 0.76566088, 0.76615399, 0.76664668, 0.76713890, 0.76763070, 0.76812202, 0.76861292, + 0.76910335, 0.76959330, 0.77008283, 0.77057189, 0.77106053, 0.77154869, 0.77203637, 0.77252364, + 0.77301043, 0.77349681, 0.77398270, 0.77446812, 0.77495313, 0.77543765, 0.77592170, 0.77640533, + 0.77688849, 0.77737117, 0.77785343, 0.77833521, 0.77881652, 0.77929735, 0.77977777, 0.78025776, + 0.78073722, 0.78121626, 0.78169483, 0.78217292, 0.78265059, 0.78312778, 0.78360450, 0.78408080, + 0.78455657, 0.78503191, 0.78550684, 0.78598124, 0.78645521, 0.78692871, 0.78740174, 0.78787434, + 0.78834641, 0.78881806, 0.78928924, 0.78975999, 0.79023021, 0.79070002, 0.79116935, 0.79163820, + 0.79210657, 0.79257452, 0.79304194, 0.79350895, 0.79397547, 0.79444152, 0.79490715, 0.79537225, + 0.79583693, 0.79630107, 0.79676479, 0.79722804, 0.79769087, 0.79815316, 0.79861498, 0.79907638, + 0.79953724, 0.79999769, 0.80045766, 0.80091715, 0.80137616, 0.80183470, 0.80229282, 0.80275041, + 0.80320752, 0.80366421, 0.80412036, 0.80457610, 0.80503136, 0.80548608, 0.80594039, 0.80639422, + 0.80684757, 0.80730045, 0.80775285, 0.80820471, 0.80865616, 0.80910712, 0.80955762, 0.81000763, + 0.81045717, 0.81090623, 0.81135488, 0.81180298, 0.81225061, 0.81269777, 0.81314439, 0.81359059, + 0.81403631, 0.81448156, 0.81492633, 0.81537062, 0.81581444, 0.81625772, 0.81670058, 0.81714290, + 0.81758481, 0.81802619, 0.81846714, 0.81890756, 0.81934750, 0.81978697, 0.82022595, 0.82066447, + 0.82110250, 0.82154006, 0.82197714, 0.82241368, 0.82284981, 0.82328540, 0.82372051, 0.82415515, + 0.82458931, 0.82502300, 0.82545614, 0.82588887, 0.82632107, 0.82675278, 0.82718402, 0.82761478, + 0.82804507, 0.82847482, 0.82890409, 0.82933295, 0.82976121, 0.83018905, 0.83061641, 0.83104324, + 0.83146960, 0.83189547, 0.83232087, 0.83274579, 0.83317018, 0.83359408, 0.83401752, 0.83444041, + 0.83486289, 0.83528483, 0.83570629, 0.83612728, 0.83654773, 0.83696771, 0.83738720, 0.83780622, + 0.83822471, 0.83864272, 0.83906025, 0.83947724, 0.83989382, 0.84030986, 0.84072536, 0.84114045, + 0.84155500, 0.84196901, 0.84238261, 0.84279567, 0.84320825, 0.84362030, 0.84403187, 0.84444296, + 0.84485358, 0.84526366, 0.84567326, 0.84608233, 0.84649092, 0.84689903, 0.84730661, 0.84771377, + 0.84812033, 0.84852648, 0.84893203, 0.84933716, 0.84974176, 0.85014588, 0.85054946, 0.85095257, + 0.85135520, 0.85175729, 0.85215890, 0.85255998, 0.85296059, 0.85336071, 0.85376030, 0.85415941, + 0.85455799, 0.85495609, 0.85535365, 0.85575074, 0.85614735, 0.85654342, 0.85693896, 0.85733402, + 0.85772860, 0.85812265, 0.85851622, 0.85890925, 0.85930181, 0.85969388, 0.86008537, 0.86047643, + 0.86086696, 0.86125696, 0.86164647, 0.86203545, 0.86242396, 0.86281192, 0.86319941, 0.86358637, + 0.86397284, 0.86435878, 0.86474425, 0.86512917, 0.86551362, 0.86589754, 0.86628097, 0.86666387, + 0.86704624, 0.86742812, 0.86780947, 0.86819035, 0.86857069, 0.86895055, 0.86932987, 0.86970866, + 0.87008697, 0.87046480, 0.87084204, 0.87121886, 0.87159508, 0.87197083, 0.87234604, 0.87272078, + 0.87309498, 0.87346870, 0.87384182, 0.87421453, 0.87458664, 0.87495828, 0.87532938, 0.87570000, + 0.87607008, 0.87643969, 0.87680870, 0.87717724, 0.87754530, 0.87791282, 0.87827981, 0.87864625, + 0.87901223, 0.87937766, 0.87974262, 0.88010699, 0.88047087, 0.88083428, 0.88119709, 0.88155943, + 0.88192129, 0.88228256, 0.88264334, 0.88300359, 0.88336337, 0.88372254, 0.88408124, 0.88443947, + 0.88479710, 0.88515425, 0.88551086, 0.88586694, 0.88622254, 0.88657761, 0.88693213, 0.88728613, + 0.88763964, 0.88799256, 0.88834506, 0.88869697, 0.88904834, 0.88939923, 0.88974959, 0.89009941, + 0.89044875, 0.89079750, 0.89114577, 0.89149350, 0.89184070, 0.89218742, 0.89253354, 0.89287919, + 0.89322430, 0.89356887, 0.89391297, 0.89425647, 0.89459950, 0.89494199, 0.89528394, 0.89562535, + 0.89596623, 0.89630663, 0.89664650, 0.89698577, 0.89732456, 0.89766282, 0.89800060, 0.89833778, + 0.89867449, 0.89901060, 0.89934623, 0.89968133, 0.90001589, 0.90034992, 0.90068340, 0.90101641, + 0.90134883, 0.90168077, 0.90201217, 0.90234298, 0.90267330, 0.90300310, 0.90333235, 0.90366107, + 0.90398932, 0.90431696, 0.90464407, 0.90497071, 0.90529674, 0.90562230, 0.90594727, 0.90627176, + 0.90659571, 0.90691912, 0.90724200, 0.90756434, 0.90788609, 0.90820736, 0.90852809, 0.90884835, + 0.90916800, 0.90948713, 0.90980572, 0.91012377, 0.91044128, 0.91075826, 0.91107476, 0.91139066, + 0.91170603, 0.91202086, 0.91233516, 0.91264898, 0.91296220, 0.91327488, 0.91358703, 0.91389865, + 0.91420978, 0.91452032, 0.91483033, 0.91513979, 0.91544873, 0.91575712, 0.91606498, 0.91637230, + 0.91667908, 0.91698527, 0.91729099, 0.91759616, 0.91790080, 0.91820484, 0.91850841, 0.91881138, + 0.91911387, 0.91941577, 0.91971713, 0.92001796, 0.92031831, 0.92061806, 0.92091721, 0.92121589, + 0.92151403, 0.92181164, 0.92210865, 0.92240518, 0.92270112, 0.92299652, 0.92329144, 0.92358577, + 0.92387950, 0.92417276, 0.92446548, 0.92475760, 0.92504925, 0.92534029, 0.92563081, 0.92592078, + 0.92621022, 0.92649913, 0.92678750, 0.92707527, 0.92736250, 0.92764926, 0.92793542, 0.92822099, + 0.92850608, 0.92879063, 0.92907459, 0.92935801, 0.92964089, 0.92992324, 0.93020505, 0.93048626, + 0.93076694, 0.93104708, 0.93132669, 0.93160576, 0.93188429, 0.93216223, 0.93243963, 0.93271649, + 0.93299282, 0.93326855, 0.93354380, 0.93381846, 0.93409252, 0.93436611, 0.93463916, 0.93491161, + 0.93518353, 0.93545485, 0.93572569, 0.93599594, 0.93626565, 0.93653482, 0.93680346, 0.93707150, + 0.93733901, 0.93760598, 0.93787235, 0.93813825, 0.93840355, 0.93866831, 0.93893248, 0.93919611, + 0.93945920, 0.93972176, 0.93998373, 0.94024521, 0.94050604, 0.94076639, 0.94102615, 0.94128537, + 0.94154406, 0.94180220, 0.94205976, 0.94231677, 0.94257319, 0.94282907, 0.94308442, 0.94333923, + 0.94359344, 0.94384712, 0.94410026, 0.94435281, 0.94460481, 0.94485629, 0.94510722, 0.94535756, + 0.94560730, 0.94585657, 0.94610524, 0.94635338, 0.94660091, 0.94684792, 0.94709438, 0.94734025, + 0.94758558, 0.94783038, 0.94807458, 0.94831824, 0.94856137, 0.94880390, 0.94904590, 0.94928730, + 0.94952816, 0.94976848, 0.95000827, 0.95024747, 0.95048606, 0.95072412, 0.95096165, 0.95119864, + 0.95143503, 0.95167089, 0.95190614, 0.95214087, 0.95237499, 0.95260859, 0.95284164, 0.95307410, + 0.95330602, 0.95353740, 0.95376819, 0.95399845, 0.95422810, 0.95445722, 0.95468575, 0.95491374, + 0.95514119, 0.95536804, 0.95559436, 0.95582008, 0.95604527, 0.95626986, 0.95649391, 0.95671743, + 0.95694035, 0.95716268, 0.95738453, 0.95760572, 0.95782644, 0.95804650, 0.95826608, 0.95848507, + 0.95870346, 0.95892131, 0.95913863, 0.95935535, 0.95957154, 0.95978713, 0.96000212, 0.96021664, + 0.96043050, 0.96064389, 0.96085662, 0.96106887, 0.96128047, 0.96149158, 0.96170205, 0.96191204, + 0.96212143, 0.96233022, 0.96253848, 0.96274614, 0.96295327, 0.96315980, 0.96336579, 0.96357119, + 0.96377605, 0.96398038, 0.96418405, 0.96438724, 0.96458977, 0.96479183, 0.96499324, 0.96519411, + 0.96539444, 0.96559417, 0.96579337, 0.96599197, 0.96618998, 0.96638745, 0.96658438, 0.96678072, + 0.96697646, 0.96717167, 0.96736628, 0.96756035, 0.96775383, 0.96794677, 0.96813911, 0.96833086, + 0.96852207, 0.96871275, 0.96890283, 0.96909231, 0.96928126, 0.96946961, 0.96965736, 0.96984458, + 0.97003126, 0.97021735, 0.97040284, 0.97058779, 0.97077215, 0.97095591, 0.97113913, 0.97132182, + 0.97150391, 0.97168541, 0.97186631, 0.97204673, 0.97222650, 0.97240573, 0.97258437, 0.97276247, + 0.97293997, 0.97311687, 0.97329324, 0.97346902, 0.97364426, 0.97381890, 0.97399294, 0.97416645, + 0.97433937, 0.97451174, 0.97468352, 0.97485471, 0.97502536, 0.97519541, 0.97536486, 0.97553378, + 0.97570211, 0.97586989, 0.97603709, 0.97620368, 0.97636974, 0.97653520, 0.97670007, 0.97686440, + 0.97702813, 0.97719133, 0.97735387, 0.97751594, 0.97767735, 0.97783822, 0.97799850, 0.97815824, + 0.97831738, 0.97847593, 0.97863394, 0.97879136, 0.97894818, 0.97910446, 0.97926015, 0.97941524, + 0.97956979, 0.97972375, 0.97987711, 0.98002988, 0.98018211, 0.98033381, 0.98048484, 0.98063534, + 0.98078525, 0.98093462, 0.98108339, 0.98123157, 0.98137921, 0.98152626, 0.98167270, 0.98181856, + 0.98196387, 0.98210859, 0.98225272, 0.98239630, 0.98253930, 0.98268169, 0.98282355, 0.98296481, + 0.98310548, 0.98324561, 0.98338509, 0.98352402, 0.98366243, 0.98380023, 0.98393744, 0.98407406, + 0.98421007, 0.98434556, 0.98448044, 0.98461479, 0.98474848, 0.98488164, 0.98501426, 0.98514622, + 0.98527765, 0.98540848, 0.98553872, 0.98566842, 0.98579752, 0.98592603, 0.98605394, 0.98618132, + 0.98630810, 0.98643428, 0.98655993, 0.98668492, 0.98680937, 0.98693329, 0.98705655, 0.98717928, + 0.98730141, 0.98742294, 0.98754394, 0.98766434, 0.98778415, 0.98790336, 0.98802203, 0.98814011, + 0.98825759, 0.98837447, 0.98849082, 0.98860651, 0.98872167, 0.98883629, 0.98895025, 0.98906368, + 0.98917651, 0.98928875, 0.98940045, 0.98951149, 0.98962200, 0.98973197, 0.98984128, 0.98995006, + 0.99005818, 0.99016583, 0.99027282, 0.99037921, 0.99048507, 0.99059033, 0.99069500, 0.99079913, + 0.99090266, 0.99100554, 0.99110794, 0.99120969, 0.99131083, 0.99141145, 0.99151146, 0.99161088, + 0.99170977, 0.99180800, 0.99190569, 0.99200279, 0.99209929, 0.99219525, 0.99229062, 0.99238533, + 0.99247956, 0.99257314, 0.99266613, 0.99275857, 0.99285042, 0.99294168, 0.99303234, 0.99312246, + 0.99321193, 0.99330086, 0.99338919, 0.99347699, 0.99356413, 0.99365073, 0.99373674, 0.99382216, + 0.99390697, 0.99399120, 0.99407488, 0.99415797, 0.99424046, 0.99432236, 0.99440366, 0.99448442, + 0.99456459, 0.99464417, 0.99472314, 0.99480152, 0.99487931, 0.99495655, 0.99503320, 0.99510926, + 0.99518472, 0.99525958, 0.99533391, 0.99540764, 0.99548078, 0.99555331, 0.99562526, 0.99569660, + 0.99576741, 0.99583763, 0.99590725, 0.99597627, 0.99604470, 0.99611259, 0.99617982, 0.99624652, + 0.99631262, 0.99637812, 0.99644303, 0.99650741, 0.99657112, 0.99663430, 0.99669689, 0.99675888, + 0.99682027, 0.99688113, 0.99694133, 0.99700099, 0.99706006, 0.99711853, 0.99717641, 0.99723375, + 0.99729043, 0.99734658, 0.99740213, 0.99745709, 0.99751145, 0.99756521, 0.99761844, 0.99767107, + 0.99772304, 0.99777448, 0.99782532, 0.99787563, 0.99792528, 0.99797440, 0.99802285, 0.99807078, + 0.99811810, 0.99816483, 0.99821103, 0.99825656, 0.99830157, 0.99834591, 0.99838972, 0.99843293, + 0.99847555, 0.99851763, 0.99855906, 0.99859995, 0.99864024, 0.99867994, 0.99871904, 0.99875754, + 0.99879545, 0.99883282, 0.99886954, 0.99890572, 0.99894130, 0.99897629, 0.99901068, 0.99904448, + 0.99907774, 0.99911034, 0.99914241, 0.99917388, 0.99920475, 0.99923503, 0.99926478, 0.99929386, + 0.99932235, 0.99935031, 0.99937767, 0.99940443, 0.99943060, 0.99945617, 0.99948120, 0.99950558, + 0.99952942, 0.99955267, 0.99957532, 0.99959737, 0.99961883, 0.99963969, 0.99966002, 0.99967968, + 0.99969882, 0.99971735, 0.99973530, 0.99975264, 0.99976939, 0.99978560, 0.99980116, 0.99981618, + 0.99983060, 0.99984443, 0.99985766, 0.99987030, 0.99988234, 0.99989384, 0.99990469, 0.99991500, + 0.99992472, 0.99993384, 0.99994236, 0.99995029, 0.99995762, 0.99996442, 0.99997061, 0.99997616, + 0.99998116, 0.99998558, 0.99998939, 0.99999267, 0.99999529, 0.99999738, 0.99999881, 0.99999970, + 1.00000000, 0.99999970, 0.99999881, 0.99999738, 0.99999529, 0.99999267, 0.99998939, 0.99998558, + 0.99998116, 0.99997616, 0.99997061, 0.99996442, 0.99995762, 0.99995029, 0.99994236, 0.99993384, + 0.99992472, 0.99991500, 0.99990469, 0.99989384, 0.99988234, 0.99987030, 0.99985766, 0.99984443, + 0.99983060, 0.99981618, 0.99980116, 0.99978560, 0.99976939, 0.99975264, 0.99973530, 0.99971735, + 0.99969882, 0.99967968, 0.99966002, 0.99963969, 0.99961883, 0.99959737, 0.99957532, 0.99955267, + 0.99952942, 0.99950558, 0.99948120, 0.99945617, 0.99943060, 0.99940443, 0.99937767, 0.99935031, + 0.99932235, 0.99929386, 0.99926478, 0.99923503, 0.99920475, 0.99917388, 0.99914241, 0.99911034, + 0.99907774, 0.99904448, 0.99901068, 0.99897629, 0.99894130, 0.99890572, 0.99886954, 0.99883282, + 0.99879545, 0.99875754, 0.99871904, 0.99867994, 0.99864024, 0.99859995, 0.99855906, 0.99851763, + 0.99847555, 0.99843293, 0.99838972, 0.99834591, 0.99830157, 0.99825656, 0.99821103, 0.99816483, + 0.99811810, 0.99807078, 0.99802285, 0.99797440, 0.99792528, 0.99787563, 0.99782532, 0.99777448, + 0.99772304, 0.99767107, 0.99761844, 0.99756521, 0.99751145, 0.99745709, 0.99740213, 0.99734658, + 0.99729043, 0.99723375, 0.99717641, 0.99711853, 0.99706006, 0.99700099, 0.99694133, 0.99688113, + 0.99682027, 0.99675888, 0.99669689, 0.99663430, 0.99657112, 0.99650741, 0.99644303, 0.99637812, + 0.99631262, 0.99624652, 0.99617982, 0.99611259, 0.99604470, 0.99597627, 0.99590725, 0.99583763, + 0.99576741, 0.99569660, 0.99562526, 0.99555331, 0.99548078, 0.99540764, 0.99533391, 0.99525958, + 0.99518472, 0.99510926, 0.99503320, 0.99495655, 0.99487931, 0.99480152, 0.99472314, 0.99464417, + 0.99456459, 0.99448442, 0.99440366, 0.99432236, 0.99424046, 0.99415797, 0.99407488, 0.99399120, + 0.99390697, 0.99382216, 0.99373674, 0.99365073, 0.99356413, 0.99347699, 0.99338919, 0.99330086, + 0.99321193, 0.99312246, 0.99303234, 0.99294168, 0.99285042, 0.99275857, 0.99266613, 0.99257314, + 0.99247956, 0.99238533, 0.99229062, 0.99219525, 0.99209929, 0.99200279, 0.99190569, 0.99180800, + 0.99170977, 0.99161088, 0.99151146, 0.99141145, 0.99131083, 0.99120969, 0.99110794, 0.99100554, + 0.99090266, 0.99079913, 0.99069500, 0.99059033, 0.99048507, 0.99037921, 0.99027282, 0.99016583, + 0.99005818, 0.98995006, 0.98984128, 0.98973197, 0.98962200, 0.98951149, 0.98940045, 0.98928875, + 0.98917651, 0.98906368, 0.98895025, 0.98883629, 0.98872167, 0.98860651, 0.98849082, 0.98837447, + 0.98825759, 0.98814011, 0.98802203, 0.98790336, 0.98778415, 0.98766434, 0.98754394, 0.98742294, + 0.98730141, 0.98717928, 0.98705655, 0.98693329, 0.98680937, 0.98668492, 0.98655993, 0.98643428, + 0.98630810, 0.98618132, 0.98605394, 0.98592603, 0.98579752, 0.98566842, 0.98553872, 0.98540848, + 0.98527765, 0.98514622, 0.98501426, 0.98488164, 0.98474848, 0.98461479, 0.98448044, 0.98434556, + 0.98421007, 0.98407406, 0.98393744, 0.98380023, 0.98366243, 0.98352402, 0.98338509, 0.98324561, + 0.98310548, 0.98296481, 0.98282355, 0.98268169, 0.98253930, 0.98239630, 0.98225272, 0.98210859, + 0.98196387, 0.98181856, 0.98167270, 0.98152626, 0.98137921, 0.98123157, 0.98108339, 0.98093462, + 0.98078525, 0.98063534, 0.98048484, 0.98033381, 0.98018211, 0.98002988, 0.97987711, 0.97972375, + 0.97956979, 0.97941524, 0.97926015, 0.97910446, 0.97894818, 0.97879136, 0.97863394, 0.97847593, + 0.97831738, 0.97815824, 0.97799850, 0.97783822, 0.97767735, 0.97751594, 0.97735387, 0.97719133, + 0.97702813, 0.97686440, 0.97670007, 0.97653520, 0.97636974, 0.97620368, 0.97603709, 0.97586989, + 0.97570211, 0.97553378, 0.97536486, 0.97519541, 0.97502536, 0.97485471, 0.97468352, 0.97451174, + 0.97433937, 0.97416645, 0.97399294, 0.97381890, 0.97364426, 0.97346902, 0.97329324, 0.97311687, + 0.97293997, 0.97276247, 0.97258437, 0.97240573, 0.97222650, 0.97204673, 0.97186631, 0.97168541, + 0.97150391, 0.97132182, 0.97113913, 0.97095591, 0.97077215, 0.97058779, 0.97040284, 0.97021735, + 0.97003126, 0.96984458, 0.96965736, 0.96946961, 0.96928126, 0.96909231, 0.96890283, 0.96871275, + 0.96852207, 0.96833086, 0.96813911, 0.96794677, 0.96775383, 0.96756035, 0.96736628, 0.96717167, + 0.96697646, 0.96678072, 0.96658438, 0.96638745, 0.96618998, 0.96599197, 0.96579337, 0.96559417, + 0.96539444, 0.96519411, 0.96499324, 0.96479183, 0.96458977, 0.96438724, 0.96418405, 0.96398038, + 0.96377605, 0.96357119, 0.96336579, 0.96315980, 0.96295327, 0.96274614, 0.96253848, 0.96233022, + 0.96212143, 0.96191204, 0.96170205, 0.96149158, 0.96128047, 0.96106887, 0.96085662, 0.96064389, + 0.96043050, 0.96021664, 0.96000212, 0.95978713, 0.95957154, 0.95935535, 0.95913863, 0.95892131, + 0.95870346, 0.95848507, 0.95826608, 0.95804650, 0.95782644, 0.95760572, 0.95738453, 0.95716268, + 0.95694035, 0.95671743, 0.95649391, 0.95626986, 0.95604527, 0.95582008, 0.95559436, 0.95536804, + 0.95514119, 0.95491374, 0.95468575, 0.95445722, 0.95422810, 0.95399845, 0.95376819, 0.95353740, + 0.95330602, 0.95307410, 0.95284164, 0.95260859, 0.95237499, 0.95214087, 0.95190614, 0.95167089, + 0.95143503, 0.95119864, 0.95096165, 0.95072412, 0.95048606, 0.95024747, 0.95000827, 0.94976848, + 0.94952816, 0.94928730, 0.94904590, 0.94880390, 0.94856137, 0.94831824, 0.94807458, 0.94783038, + 0.94758558, 0.94734025, 0.94709438, 0.94684792, 0.94660091, 0.94635338, 0.94610524, 0.94585657, + 0.94560730, 0.94535756, 0.94510722, 0.94485629, 0.94460481, 0.94435281, 0.94410026, 0.94384712, + 0.94359344, 0.94333923, 0.94308442, 0.94282907, 0.94257319, 0.94231677, 0.94205976, 0.94180220, + 0.94154406, 0.94128537, 0.94102615, 0.94076639, 0.94050604, 0.94024521, 0.93998373, 0.93972176, + 0.93945920, 0.93919611, 0.93893248, 0.93866831, 0.93840355, 0.93813825, 0.93787235, 0.93760598, + 0.93733901, 0.93707150, 0.93680346, 0.93653482, 0.93626565, 0.93599594, 0.93572569, 0.93545485, + 0.93518353, 0.93491161, 0.93463916, 0.93436611, 0.93409252, 0.93381846, 0.93354380, 0.93326855, + 0.93299282, 0.93271649, 0.93243963, 0.93216223, 0.93188429, 0.93160576, 0.93132669, 0.93104708, + 0.93076694, 0.93048626, 0.93020505, 0.92992324, 0.92964089, 0.92935801, 0.92907459, 0.92879063, + 0.92850608, 0.92822099, 0.92793542, 0.92764926, 0.92736250, 0.92707527, 0.92678750, 0.92649913, + 0.92621022, 0.92592078, 0.92563081, 0.92534029, 0.92504925, 0.92475760, 0.92446548, 0.92417276, + 0.92387950, 0.92358577, 0.92329144, 0.92299652, 0.92270112, 0.92240518, 0.92210865, 0.92181164, + 0.92151403, 0.92121589, 0.92091721, 0.92061806, 0.92031831, 0.92001796, 0.91971713, 0.91941577, + 0.91911387, 0.91881138, 0.91850841, 0.91820484, 0.91790080, 0.91759616, 0.91729099, 0.91698527, + 0.91667908, 0.91637230, 0.91606498, 0.91575712, 0.91544873, 0.91513979, 0.91483033, 0.91452032, + 0.91420978, 0.91389865, 0.91358703, 0.91327488, 0.91296220, 0.91264898, 0.91233516, 0.91202086, + 0.91170603, 0.91139066, 0.91107476, 0.91075826, 0.91044128, 0.91012377, 0.90980572, 0.90948713, + 0.90916800, 0.90884835, 0.90852809, 0.90820736, 0.90788609, 0.90756434, 0.90724200, 0.90691912, + 0.90659571, 0.90627176, 0.90594727, 0.90562230, 0.90529674, 0.90497071, 0.90464407, 0.90431696, + 0.90398932, 0.90366107, 0.90333235, 0.90300310, 0.90267330, 0.90234298, 0.90201217, 0.90168077, + 0.90134883, 0.90101641, 0.90068340, 0.90034992, 0.90001589, 0.89968133, 0.89934623, 0.89901060, + 0.89867449, 0.89833778, 0.89800060, 0.89766282, 0.89732456, 0.89698577, 0.89664650, 0.89630663, + 0.89596623, 0.89562535, 0.89528394, 0.89494199, 0.89459950, 0.89425647, 0.89391297, 0.89356887, + 0.89322430, 0.89287919, 0.89253354, 0.89218742, 0.89184070, 0.89149350, 0.89114577, 0.89079750, + 0.89044875, 0.89009941, 0.88974959, 0.88939923, 0.88904834, 0.88869697, 0.88834506, 0.88799256, + 0.88763964, 0.88728613, 0.88693213, 0.88657761, 0.88622254, 0.88586694, 0.88551086, 0.88515425, + 0.88479710, 0.88443947, 0.88408124, 0.88372254, 0.88336337, 0.88300359, 0.88264334, 0.88228256, + 0.88192129, 0.88155943, 0.88119709, 0.88083428, 0.88047087, 0.88010699, 0.87974262, 0.87937766, + 0.87901223, 0.87864625, 0.87827981, 0.87791282, 0.87754530, 0.87717724, 0.87680870, 0.87643969, + 0.87607008, 0.87570000, 0.87532938, 0.87495828, 0.87458664, 0.87421453, 0.87384182, 0.87346870, + 0.87309498, 0.87272078, 0.87234604, 0.87197083, 0.87159508, 0.87121886, 0.87084204, 0.87046480, + 0.87008697, 0.86970866, 0.86932987, 0.86895055, 0.86857069, 0.86819035, 0.86780947, 0.86742812, + 0.86704624, 0.86666387, 0.86628097, 0.86589754, 0.86551362, 0.86512917, 0.86474425, 0.86435878, + 0.86397284, 0.86358637, 0.86319941, 0.86281192, 0.86242396, 0.86203545, 0.86164647, 0.86125696, + 0.86086696, 0.86047643, 0.86008537, 0.85969388, 0.85930181, 0.85890925, 0.85851622, 0.85812265, + 0.85772860, 0.85733402, 0.85693896, 0.85654342, 0.85614735, 0.85575074, 0.85535365, 0.85495609, + 0.85455799, 0.85415941, 0.85376030, 0.85336071, 0.85296059, 0.85255998, 0.85215890, 0.85175729, + 0.85135520, 0.85095257, 0.85054946, 0.85014588, 0.84974176, 0.84933716, 0.84893203, 0.84852648, + 0.84812033, 0.84771377, 0.84730661, 0.84689903, 0.84649092, 0.84608233, 0.84567326, 0.84526366, + 0.84485358, 0.84444296, 0.84403187, 0.84362030, 0.84320825, 0.84279567, 0.84238261, 0.84196901, + 0.84155500, 0.84114045, 0.84072536, 0.84030986, 0.83989382, 0.83947724, 0.83906025, 0.83864272, + 0.83822471, 0.83780622, 0.83738720, 0.83696771, 0.83654773, 0.83612728, 0.83570629, 0.83528483, + 0.83486289, 0.83444041, 0.83401752, 0.83359408, 0.83317018, 0.83274579, 0.83232087, 0.83189547, + 0.83146960, 0.83104324, 0.83061641, 0.83018905, 0.82976121, 0.82933295, 0.82890409, 0.82847482, + 0.82804507, 0.82761478, 0.82718402, 0.82675278, 0.82632107, 0.82588887, 0.82545614, 0.82502300, + 0.82458931, 0.82415515, 0.82372051, 0.82328540, 0.82284981, 0.82241368, 0.82197714, 0.82154006, + 0.82110250, 0.82066447, 0.82022595, 0.81978697, 0.81934750, 0.81890756, 0.81846714, 0.81802619, + 0.81758481, 0.81714290, 0.81670058, 0.81625772, 0.81581444, 0.81537062, 0.81492633, 0.81448156, + 0.81403631, 0.81359059, 0.81314439, 0.81269777, 0.81225061, 0.81180298, 0.81135488, 0.81090623, + 0.81045717, 0.81000763, 0.80955762, 0.80910712, 0.80865616, 0.80820471, 0.80775285, 0.80730045, + 0.80684757, 0.80639422, 0.80594039, 0.80548608, 0.80503136, 0.80457610, 0.80412036, 0.80366421, + 0.80320752, 0.80275041, 0.80229282, 0.80183470, 0.80137616, 0.80091715, 0.80045766, 0.79999769, + 0.79953724, 0.79907638, 0.79861498, 0.79815316, 0.79769087, 0.79722804, 0.79676479, 0.79630107, + 0.79583693, 0.79537225, 0.79490715, 0.79444152, 0.79397547, 0.79350895, 0.79304194, 0.79257452, + 0.79210657, 0.79163820, 0.79116935, 0.79070002, 0.79023021, 0.78975999, 0.78928924, 0.78881806, + 0.78834641, 0.78787434, 0.78740174, 0.78692871, 0.78645521, 0.78598124, 0.78550684, 0.78503191, + 0.78455657, 0.78408080, 0.78360450, 0.78312778, 0.78265059, 0.78217292, 0.78169483, 0.78121626, + 0.78073722, 0.78025776, 0.77977777, 0.77929735, 0.77881652, 0.77833521, 0.77785343, 0.77737117, + 0.77688849, 0.77640533, 0.77592170, 0.77543765, 0.77495313, 0.77446812, 0.77398270, 0.77349681, + 0.77301043, 0.77252364, 0.77203637, 0.77154869, 0.77106053, 0.77057189, 0.77008283, 0.76959330, + 0.76910335, 0.76861292, 0.76812202, 0.76763070, 0.76713890, 0.76664668, 0.76615399, 0.76566088, + 0.76516724, 0.76467323, 0.76417875, 0.76368380, 0.76318842, 0.76269257, 0.76219630, 0.76169956, + 0.76120239, 0.76070476, 0.76020670, 0.75970817, 0.75920922, 0.75870979, 0.75820988, 0.75770962, + 0.75720882, 0.75670767, 0.75620598, 0.75570393, 0.75520140, 0.75469840, 0.75419497, 0.75369114, + 0.75318682, 0.75268203, 0.75217682, 0.75167120, 0.75116515, 0.75065863, 0.75015163, 0.74964422, + 0.74913639, 0.74862808, 0.74811935, 0.74761021, 0.74710059, 0.74659055, 0.74608010, 0.74556917, + 0.74505776, 0.74454600, 0.74403375, 0.74352109, 0.74300796, 0.74249440, 0.74198043, 0.74146599, + 0.74095112, 0.74043584, 0.73992008, 0.73940390, 0.73888731, 0.73837030, 0.73785281, 0.73733491, + 0.73681659, 0.73629779, 0.73577857, 0.73525894, 0.73473889, 0.73421836, 0.73369741, 0.73317605, + 0.73265427, 0.73213202, 0.73160940, 0.73108631, 0.73056275, 0.73003882, 0.72951442, 0.72898960, + 0.72846437, 0.72793871, 0.72741264, 0.72688609, 0.72635913, 0.72583181, 0.72530395, 0.72477573, + 0.72424710, 0.72371799, 0.72318846, 0.72265857, 0.72212821, 0.72159743, 0.72106618, 0.72053456, + 0.72000253, 0.71947002, 0.71893710, 0.71840382, 0.71787006, 0.71733588, 0.71680129, 0.71626627, + 0.71573085, 0.71519494, 0.71465868, 0.71412200, 0.71358484, 0.71304733, 0.71250939, 0.71197098, + 0.71143222, 0.71089298, 0.71035337, 0.70981330, 0.70927280, 0.70873195, 0.70819062, 0.70764893, + 0.70710677, 0.70656425, 0.70602125, 0.70547789, 0.70493406, 0.70438987, 0.70384526, 0.70330018, + 0.70275474, 0.70220888, 0.70166260, 0.70111591, 0.70056880, 0.70002127, 0.69947332, 0.69892502, + 0.69837624, 0.69782710, 0.69727749, 0.69672751, 0.69617712, 0.69562632, 0.69507509, 0.69452351, + 0.69397146, 0.69341904, 0.69286615, 0.69231290, 0.69175923, 0.69120520, 0.69065070, 0.69009584, + 0.68954057, 0.68898487, 0.68842876, 0.68787223, 0.68731534, 0.68675804, 0.68620032, 0.68564218, + 0.68508369, 0.68452471, 0.68396538, 0.68340570, 0.68284553, 0.68228501, 0.68172407, 0.68116271, + 0.68060100, 0.68003887, 0.67947632, 0.67891335, 0.67835003, 0.67778629, 0.67722219, 0.67665762, + 0.67609268, 0.67552739, 0.67496163, 0.67439550, 0.67382902, 0.67326206, 0.67269474, 0.67212707, + 0.67155898, 0.67099047, 0.67042154, 0.66985226, 0.66928262, 0.66871250, 0.66814202, 0.66757119, + 0.66699994, 0.66642827, 0.66585624, 0.66528380, 0.66471100, 0.66413778, 0.66356415, 0.66299015, + 0.66241580, 0.66184098, 0.66126585, 0.66069031, 0.66011435, 0.65953803, 0.65896130, 0.65838420, + 0.65780669, 0.65722883, 0.65665054, 0.65607190, 0.65549284, 0.65491343, 0.65433359, 0.65375340, + 0.65317285, 0.65259188, 0.65201056, 0.65142882, 0.65084666, 0.65026420, 0.64968133, 0.64909804, + 0.64851439, 0.64793038, 0.64734596, 0.64676118, 0.64617604, 0.64559048, 0.64500451, 0.64441824, + 0.64383155, 0.64324450, 0.64265704, 0.64206922, 0.64148104, 0.64089245, 0.64030349, 0.63971418, + 0.63912445, 0.63853437, 0.63794392, 0.63735306, 0.63676184, 0.63617027, 0.63557833, 0.63498598, + 0.63439327, 0.63380021, 0.63320678, 0.63261294, 0.63201874, 0.63142419, 0.63082922, 0.63023394, + 0.62963825, 0.62904221, 0.62844574, 0.62784898, 0.62725180, 0.62665427, 0.62605637, 0.62545812, + 0.62485951, 0.62426049, 0.62366110, 0.62306136, 0.62246126, 0.62186080, 0.62125999, 0.62065876, + 0.62005723, 0.61945528, 0.61885297, 0.61825031, 0.61764729, 0.61704391, 0.61644018, 0.61583608, + 0.61523157, 0.61462677, 0.61402154, 0.61341602, 0.61281008, 0.61220378, 0.61159718, 0.61099017, + 0.61038280, 0.60977507, 0.60916704, 0.60855860, 0.60794979, 0.60734063, 0.60673112, 0.60612124, + 0.60551107, 0.60490048, 0.60428953, 0.60367823, 0.60306662, 0.60245460, 0.60184222, 0.60122955, + 0.60061646, 0.60000306, 0.59938931, 0.59877521, 0.59816068, 0.59754586, 0.59693068, 0.59631521, + 0.59569931, 0.59508306, 0.59446651, 0.59384960, 0.59323227, 0.59261465, 0.59199667, 0.59137839, + 0.59075969, 0.59014070, 0.58952129, 0.58890158, 0.58828157, 0.58766115, 0.58704036, 0.58641928, + 0.58579785, 0.58517605, 0.58455396, 0.58393145, 0.58330864, 0.58268547, 0.58206201, 0.58143812, + 0.58081394, 0.58018941, 0.57956457, 0.57893932, 0.57831377, 0.57768792, 0.57706165, 0.57643509, + 0.57580817, 0.57518095, 0.57455337, 0.57392544, 0.57329714, 0.57266855, 0.57203960, 0.57141036, + 0.57078075, 0.57015079, 0.56952053, 0.56888992, 0.56825894, 0.56762767, 0.56699604, 0.56636411, + 0.56573182, 0.56509918, 0.56446624, 0.56383294, 0.56319934, 0.56256539, 0.56193113, 0.56129652, + 0.56066155, 0.56002629, 0.55939072, 0.55875480, 0.55811852, 0.55748194, 0.55684501, 0.55620778, + 0.55557024, 0.55493236, 0.55429411, 0.55365556, 0.55301672, 0.55237752, 0.55173796, 0.55109817, + 0.55045795, 0.54981750, 0.54917663, 0.54853553, 0.54789406, 0.54725230, 0.54661018, 0.54596776, + 0.54532498, 0.54468191, 0.54403853, 0.54339480, 0.54275078, 0.54210645, 0.54146177, 0.54081678, + 0.54017144, 0.53952587, 0.53887993, 0.53823364, 0.53758705, 0.53694016, 0.53629297, 0.53564548, + 0.53499764, 0.53434944, 0.53370100, 0.53305221, 0.53240311, 0.53175372, 0.53110403, 0.53045398, + 0.52980363, 0.52915299, 0.52850199, 0.52785075, 0.52719915, 0.52654725, 0.52589500, 0.52524251, + 0.52458966, 0.52393657, 0.52328312, 0.52262938, 0.52197528, 0.52132094, 0.52066624, 0.52001125, + 0.51935601, 0.51870042, 0.51804453, 0.51738828, 0.51673180, 0.51607502, 0.51541787, 0.51476043, + 0.51410276, 0.51344472, 0.51278639, 0.51212776, 0.51146883, 0.51080960, 0.51015007, 0.50949025, + 0.50883013, 0.50816971, 0.50750899, 0.50684798, 0.50618666, 0.50552505, 0.50486308, 0.50420088, + 0.50353837, 0.50287557, 0.50221246, 0.50154907, 0.50088537, 0.50022137, 0.49955711, 0.49889255, + 0.49822766, 0.49756250, 0.49689704, 0.49623129, 0.49556527, 0.49489895, 0.49423230, 0.49356541, + 0.49289820, 0.49223071, 0.49156290, 0.49089485, 0.49022648, 0.48955783, 0.48888889, 0.48821968, + 0.48755017, 0.48688036, 0.48621029, 0.48553991, 0.48486924, 0.48419830, 0.48352706, 0.48285556, + 0.48218378, 0.48151168, 0.48083934, 0.48016667, 0.47949377, 0.47882056, 0.47814706, 0.47747329, + 0.47679922, 0.47612488, 0.47545028, 0.47477537, 0.47410020, 0.47342476, 0.47274902, 0.47207302, + 0.47139674, 0.47072017, 0.47004333, 0.46936622, 0.46868882, 0.46801114, 0.46733320, 0.46665499, + 0.46597651, 0.46529773, 0.46461868, 0.46393937, 0.46325979, 0.46257994, 0.46189979, 0.46121940, + 0.46053872, 0.45985776, 0.45917654, 0.45849505, 0.45781329, 0.45713127, 0.45644897, 0.45576641, + 0.45508358, 0.45440048, 0.45371711, 0.45303348, 0.45234957, 0.45166543, 0.45098099, 0.45029628, + 0.44961134, 0.44892609, 0.44824061, 0.44755486, 0.44686884, 0.44618255, 0.44549602, 0.44480920, + 0.44412214, 0.44343480, 0.44274724, 0.44205937, 0.44137126, 0.44068289, 0.43999428, 0.43930539, + 0.43861625, 0.43792683, 0.43723717, 0.43654725, 0.43585709, 0.43516666, 0.43447596, 0.43378502, + 0.43309382, 0.43240237, 0.43171066, 0.43101871, 0.43032649, 0.42963400, 0.42894128, 0.42824832, + 0.42755508, 0.42686161, 0.42616788, 0.42547390, 0.42477968, 0.42408520, 0.42339048, 0.42269549, + 0.42200026, 0.42130479, 0.42060909, 0.41991311, 0.41921690, 0.41852042, 0.41782370, 0.41712677, + 0.41642955, 0.41573212, 0.41503441, 0.41433650, 0.41363832, 0.41293988, 0.41224122, 0.41154233, + 0.41084316, 0.41014379, 0.40944415, 0.40874428, 0.40804416, 0.40734380, 0.40664321, 0.40594238, + 0.40524131, 0.40454000, 0.40383846, 0.40313667, 0.40243465, 0.40173239, 0.40102988, 0.40032718, + 0.39962420, 0.39892101, 0.39821756, 0.39751390, 0.39681000, 0.39610586, 0.39540148, 0.39469686, + 0.39399204, 0.39328697, 0.39258167, 0.39187613, 0.39117038, 0.39046440, 0.38975817, 0.38905174, + 0.38834503, 0.38763815, 0.38693100, 0.38622364, 0.38551605, 0.38480824, 0.38410020, 0.38339192, + 0.38268343, 0.38197473, 0.38126576, 0.38055661, 0.37984720, 0.37913761, 0.37842774, 0.37771770, + 0.37700742, 0.37629691, 0.37558618, 0.37487522, 0.37416407, 0.37345266, 0.37274107, 0.37202924, + 0.37131721, 0.37060493, 0.36989245, 0.36917976, 0.36846682, 0.36775368, 0.36704034, 0.36632678, + 0.36561298, 0.36489901, 0.36418480, 0.36347038, 0.36275572, 0.36204088, 0.36132580, 0.36061051, + 0.35989505, 0.35917935, 0.35846341, 0.35774729, 0.35703096, 0.35631442, 0.35559767, 0.35488069, + 0.35416353, 0.35344616, 0.35272855, 0.35201076, 0.35129276, 0.35057455, 0.34985614, 0.34913751, + 0.34841868, 0.34769964, 0.34698042, 0.34626096, 0.34554133, 0.34482148, 0.34410143, 0.34338117, + 0.34266073, 0.34194008, 0.34121922, 0.34049815, 0.33977687, 0.33905542, 0.33833376, 0.33761191, + 0.33688986, 0.33616760, 0.33544514, 0.33472249, 0.33399966, 0.33327660, 0.33255336, 0.33182994, + 0.33110631, 0.33038250, 0.32965845, 0.32893425, 0.32820985, 0.32748523, 0.32676044, 0.32603547, + 0.32531029, 0.32458493, 0.32385936, 0.32313362, 0.32240769, 0.32168156, 0.32095525, 0.32022873, + 0.31950203, 0.31877515, 0.31804809, 0.31732082, 0.31659338, 0.31586576, 0.31513792, 0.31440994, + 0.31368175, 0.31295338, 0.31222481, 0.31149608, 0.31076714, 0.31003806, 0.30930877, 0.30857930, + 0.30784965, 0.30711982, 0.30638981, 0.30565959, 0.30492923, 0.30419868, 0.30346796, 0.30273703, + 0.30200595, 0.30127469, 0.30054325, 0.29981163, 0.29907984, 0.29834786, 0.29761571, 0.29688337, + 0.29615089, 0.29541820, 0.29468536, 0.29395235, 0.29321915, 0.29248580, 0.29175225, 0.29101855, + 0.29028466, 0.28955063, 0.28881642, 0.28808203, 0.28734747, 0.28661272, 0.28587782, 0.28514278, + 0.28440753, 0.28367212, 0.28293657, 0.28220084, 0.28146493, 0.28072888, 0.27999264, 0.27925625, + 0.27851969, 0.27778298, 0.27704608, 0.27630904, 0.27557182, 0.27483445, 0.27409691, 0.27335921, + 0.27262136, 0.27188334, 0.27114516, 0.27040681, 0.26966831, 0.26892966, 0.26819086, 0.26745188, + 0.26671275, 0.26597348, 0.26523402, 0.26449442, 0.26375467, 0.26301476, 0.26227471, 0.26153448, + 0.26079410, 0.26005360, 0.25931293, 0.25857207, 0.25783110, 0.25708997, 0.25634867, 0.25560725, + 0.25486565, 0.25412393, 0.25338203, 0.25264001, 0.25189781, 0.25115550, 0.25041300, 0.24967039, + 0.24892761, 0.24818468, 0.24744162, 0.24669841, 0.24595505, 0.24521154, 0.24446790, 0.24372411, + 0.24298018, 0.24223611, 0.24149188, 0.24074753, 0.24000302, 0.23925838, 0.23851359, 0.23776866, + 0.23702361, 0.23627840, 0.23553306, 0.23478758, 0.23404196, 0.23329620, 0.23255031, 0.23180428, + 0.23105811, 0.23031181, 0.22956537, 0.22881879, 0.22807208, 0.22732525, 0.22657827, 0.22583115, + 0.22508392, 0.22433653, 0.22358903, 0.22284140, 0.22209363, 0.22134572, 0.22059768, 0.21984953, + 0.21910124, 0.21835282, 0.21760428, 0.21685560, 0.21610680, 0.21535787, 0.21460882, 0.21385963, + 0.21311031, 0.21236089, 0.21161133, 0.21086164, 0.21011184, 0.20936191, 0.20861185, 0.20786168, + 0.20711137, 0.20636095, 0.20561041, 0.20485975, 0.20410897, 0.20335807, 0.20260704, 0.20185590, + 0.20110464, 0.20035325, 0.19960175, 0.19885014, 0.19809841, 0.19734657, 0.19659460, 0.19584252, + 0.19509032, 0.19433801, 0.19358559, 0.19283305, 0.19208039, 0.19132763, 0.19057475, 0.18982176, + 0.18906866, 0.18831545, 0.18756212, 0.18680869, 0.18605515, 0.18530150, 0.18454774, 0.18379387, + 0.18303989, 0.18228580, 0.18153161, 0.18077731, 0.18002290, 0.17926839, 0.17851377, 0.17775905, + 0.17700422, 0.17624930, 0.17549425, 0.17473911, 0.17398387, 0.17322853, 0.17247309, 0.17171754, + 0.17096189, 0.17020614, 0.16945030, 0.16869435, 0.16793829, 0.16718215, 0.16642590, 0.16566956, + 0.16491312, 0.16415659, 0.16339995, 0.16264322, 0.16188639, 0.16112947, 0.16037245, 0.15961535, + 0.15885815, 0.15810084, 0.15734346, 0.15658598, 0.15582840, 0.15507074, 0.15431297, 0.15355512, + 0.15279719, 0.15203916, 0.15128104, 0.15052283, 0.14976454, 0.14900614, 0.14824767, 0.14748912, + 0.14673047, 0.14597175, 0.14521292, 0.14445402, 0.14369503, 0.14293596, 0.14217681, 0.14141756, + 0.14065824, 0.13989884, 0.13913934, 0.13837977, 0.13762012, 0.13686039, 0.13610058, 0.13534068, + 0.13458070, 0.13382065, 0.13306053, 0.13230032, 0.13154003, 0.13077967, 0.13001922, 0.12925871, + 0.12849811, 0.12773745, 0.12697670, 0.12621588, 0.12545498, 0.12469402, 0.12393297, 0.12317186, + 0.12241068, 0.12164941, 0.12088808, 0.12012669, 0.11936522, 0.11860368, 0.11784206, 0.11708038, + 0.11631863, 0.11555681, 0.11479492, 0.11403298, 0.11327095, 0.11250886, 0.11174671, 0.11098449, + 0.11022221, 0.10945985, 0.10869744, 0.10793497, 0.10717242, 0.10640982, 0.10564715, 0.10488442, + 0.10412163, 0.10335878, 0.10259587, 0.10183290, 0.10106986, 0.10030677, 0.09954362, 0.09878041, + 0.09801714, 0.09725381, 0.09649043, 0.09572699, 0.09496350, 0.09419994, 0.09343634, 0.09267268, + 0.09190895, 0.09114519, 0.09038136, 0.08961748, 0.08885355, 0.08808957, 0.08732554, 0.08656145, + 0.08579731, 0.08503313, 0.08426889, 0.08350460, 0.08274026, 0.08197588, 0.08121145, 0.08044697, + 0.07968244, 0.07891786, 0.07815325, 0.07738858, 0.07662386, 0.07585911, 0.07509430, 0.07432945, + 0.07356457, 0.07279963, 0.07203465, 0.07126963, 0.07050458, 0.06973947, 0.06897433, 0.06820914, + 0.06744392, 0.06667866, 0.06591335, 0.06514801, 0.06438263, 0.06361721, 0.06285176, 0.06208627, + 0.06132074, 0.06055517, 0.05978957, 0.05902394, 0.05825827, 0.05749256, 0.05672682, 0.05596105, + 0.05519525, 0.05442941, 0.05366354, 0.05289764, 0.05213170, 0.05136574, 0.05059975, 0.04983373, + 0.04906768, 0.04830159, 0.04753548, 0.04676935, 0.04600318, 0.04523699, 0.04447077, 0.04370453, + 0.04293826, 0.04217196, 0.04140564, 0.04063930, 0.03987293, 0.03910654, 0.03834012, 0.03757368, + 0.03680722, 0.03604074, 0.03527424, 0.03450771, 0.03374117, 0.03297461, 0.03220803, 0.03144142, + 0.03067480, 0.02990817, 0.02914151, 0.02837484, 0.02760815, 0.02684144, 0.02607472, 0.02530798, + 0.02454123, 0.02377446, 0.02300768, 0.02224089, 0.02147408, 0.02070726, 0.01994043, 0.01917358, + 0.01840673, 0.01763986, 0.01687299, 0.01610610, 0.01533921, 0.01457230, 0.01380539, 0.01303847, + 0.01227154, 0.01150460, 0.01073766, 0.00997071, 0.00920375, 0.00843679, 0.00766983, 0.00690286, + 0.00613588, 0.00536891, 0.00460193, 0.00383494, 0.00306796, 0.00230097, 0.00153398, 0.00076699, + 0.00000000, -0.00076699, -0.00153398, -0.00230097, -0.00306796, -0.00383494, -0.00460193, -0.00536891, + -0.00613588, -0.00690286, -0.00766983, -0.00843679, -0.00920375, -0.00997071, -0.01073766, -0.01150460, + -0.01227154, -0.01303847, -0.01380539, -0.01457230, -0.01533921, -0.01610610, -0.01687299, -0.01763986, + -0.01840673, -0.01917358, -0.01994043, -0.02070726, -0.02147408, -0.02224089, -0.02300768, -0.02377446, + -0.02454123, -0.02530798, -0.02607472, -0.02684144, -0.02760815, -0.02837484, -0.02914151, -0.02990817, + -0.03067480, -0.03144142, -0.03220803, -0.03297461, -0.03374117, -0.03450771, -0.03527424, -0.03604074, + -0.03680722, -0.03757368, -0.03834012, -0.03910654, -0.03987293, -0.04063930, -0.04140564, -0.04217196, + -0.04293826, -0.04370453, -0.04447077, -0.04523699, -0.04600318, -0.04676935, -0.04753548, -0.04830159, + -0.04906768, -0.04983373, -0.05059975, -0.05136574, -0.05213170, -0.05289764, -0.05366354, -0.05442941, + -0.05519525, -0.05596105, -0.05672682, -0.05749256, -0.05825827, -0.05902394, -0.05978957, -0.06055517, + -0.06132074, -0.06208627, -0.06285176, -0.06361721, -0.06438263, -0.06514801, -0.06591335, -0.06667866, + -0.06744392, -0.06820914, -0.06897433, -0.06973947, -0.07050458, -0.07126963, -0.07203465, -0.07279963, + -0.07356457, -0.07432945, -0.07509430, -0.07585911, -0.07662386, -0.07738858, -0.07815325, -0.07891786, + -0.07968244, -0.08044697, -0.08121145, -0.08197588, -0.08274026, -0.08350460, -0.08426889, -0.08503313, + -0.08579731, -0.08656145, -0.08732554, -0.08808957, -0.08885355, -0.08961748, -0.09038136, -0.09114519, + -0.09190895, -0.09267268, -0.09343634, -0.09419994, -0.09496350, -0.09572699, -0.09649043, -0.09725381, + -0.09801714, -0.09878041, -0.09954362, -0.10030677, -0.10106986, -0.10183290, -0.10259587, -0.10335878, + -0.10412163, -0.10488442, -0.10564715, -0.10640982, -0.10717242, -0.10793497, -0.10869744, -0.10945985, + -0.11022221, -0.11098449, -0.11174671, -0.11250886, -0.11327095, -0.11403298, -0.11479492, -0.11555681, + -0.11631863, -0.11708038, -0.11784206, -0.11860368, -0.11936522, -0.12012669, -0.12088808, -0.12164941, + -0.12241068, -0.12317186, -0.12393297, -0.12469402, -0.12545498, -0.12621588, -0.12697670, -0.12773745, + -0.12849811, -0.12925871, -0.13001922, -0.13077967, -0.13154003, -0.13230032, -0.13306053, -0.13382065, + -0.13458070, -0.13534068, -0.13610058, -0.13686039, -0.13762012, -0.13837977, -0.13913934, -0.13989884, + -0.14065824, -0.14141756, -0.14217681, -0.14293596, -0.14369503, -0.14445402, -0.14521292, -0.14597175, + -0.14673047, -0.14748912, -0.14824767, -0.14900614, -0.14976454, -0.15052283, -0.15128104, -0.15203916, + -0.15279719, -0.15355512, -0.15431297, -0.15507074, -0.15582840, -0.15658598, -0.15734346, -0.15810084, + -0.15885815, -0.15961535, -0.16037245, -0.16112947, -0.16188639, -0.16264322, -0.16339995, -0.16415659, + -0.16491312, -0.16566956, -0.16642590, -0.16718215, -0.16793829, -0.16869435, -0.16945030, -0.17020614, + -0.17096189, -0.17171754, -0.17247309, -0.17322853, -0.17398387, -0.17473911, -0.17549425, -0.17624930, + -0.17700422, -0.17775905, -0.17851377, -0.17926839, -0.18002290, -0.18077731, -0.18153161, -0.18228580, + -0.18303989, -0.18379387, -0.18454774, -0.18530150, -0.18605515, -0.18680869, -0.18756212, -0.18831545, + -0.18906866, -0.18982176, -0.19057475, -0.19132763, -0.19208039, -0.19283305, -0.19358559, -0.19433801, + -0.19509032, -0.19584252, -0.19659460, -0.19734657, -0.19809841, -0.19885014, -0.19960175, -0.20035325, + -0.20110464, -0.20185590, -0.20260704, -0.20335807, -0.20410897, -0.20485975, -0.20561041, -0.20636095, + -0.20711137, -0.20786168, -0.20861185, -0.20936191, -0.21011184, -0.21086164, -0.21161133, -0.21236089, + -0.21311031, -0.21385963, -0.21460882, -0.21535787, -0.21610680, -0.21685560, -0.21760428, -0.21835282, + -0.21910124, -0.21984953, -0.22059768, -0.22134572, -0.22209363, -0.22284140, -0.22358903, -0.22433653, + -0.22508392, -0.22583115, -0.22657827, -0.22732525, -0.22807208, -0.22881879, -0.22956537, -0.23031181, + -0.23105811, -0.23180428, -0.23255031, -0.23329620, -0.23404196, -0.23478758, -0.23553306, -0.23627840, + -0.23702361, -0.23776866, -0.23851359, -0.23925838, -0.24000302, -0.24074753, -0.24149188, -0.24223611, + -0.24298018, -0.24372411, -0.24446790, -0.24521154, -0.24595505, -0.24669841, -0.24744162, -0.24818468, + -0.24892761, -0.24967039, -0.25041300, -0.25115550, -0.25189781, -0.25264001, -0.25338203, -0.25412393, + -0.25486565, -0.25560725, -0.25634867, -0.25708997, -0.25783110, -0.25857207, -0.25931293, -0.26005360, + -0.26079410, -0.26153448, -0.26227471, -0.26301476, -0.26375467, -0.26449442, -0.26523402, -0.26597348, + -0.26671275, -0.26745188, -0.26819086, -0.26892966, -0.26966831, -0.27040681, -0.27114516, -0.27188334, + -0.27262136, -0.27335921, -0.27409691, -0.27483445, -0.27557182, -0.27630904, -0.27704608, -0.27778298, + -0.27851969, -0.27925625, -0.27999264, -0.28072888, -0.28146493, -0.28220084, -0.28293657, -0.28367212, + -0.28440753, -0.28514278, -0.28587782, -0.28661272, -0.28734747, -0.28808203, -0.28881642, -0.28955063, + -0.29028466, -0.29101855, -0.29175225, -0.29248580, -0.29321915, -0.29395235, -0.29468536, -0.29541820, + -0.29615089, -0.29688337, -0.29761571, -0.29834786, -0.29907984, -0.29981163, -0.30054325, -0.30127469, + -0.30200595, -0.30273703, -0.30346796, -0.30419868, -0.30492923, -0.30565959, -0.30638981, -0.30711982, + -0.30784965, -0.30857930, -0.30930877, -0.31003806, -0.31076714, -0.31149608, -0.31222481, -0.31295338, + -0.31368175, -0.31440994, -0.31513792, -0.31586576, -0.31659338, -0.31732082, -0.31804809, -0.31877515, + -0.31950203, -0.32022873, -0.32095525, -0.32168156, -0.32240769, -0.32313362, -0.32385936, -0.32458493, + -0.32531029, -0.32603547, -0.32676044, -0.32748523, -0.32820985, -0.32893425, -0.32965845, -0.33038250, + -0.33110631, -0.33182994, -0.33255336, -0.33327660, -0.33399966, -0.33472249, -0.33544514, -0.33616760, + -0.33688986, -0.33761191, -0.33833376, -0.33905542, -0.33977687, -0.34049815, -0.34121922, -0.34194008, + -0.34266073, -0.34338117, -0.34410143, -0.34482148, -0.34554133, -0.34626096, -0.34698042, -0.34769964, + -0.34841868, -0.34913751, -0.34985614, -0.35057455, -0.35129276, -0.35201076, -0.35272855, -0.35344616, + -0.35416353, -0.35488069, -0.35559767, -0.35631442, -0.35703096, -0.35774729, -0.35846341, -0.35917935, + -0.35989505, -0.36061051, -0.36132580, -0.36204088, -0.36275572, -0.36347038, -0.36418480, -0.36489901, + -0.36561298, -0.36632678, -0.36704034, -0.36775368, -0.36846682, -0.36917976, -0.36989245, -0.37060493, + -0.37131721, -0.37202924, -0.37274107, -0.37345266, -0.37416407, -0.37487522, -0.37558618, -0.37629691, + -0.37700742, -0.37771770, -0.37842774, -0.37913761, -0.37984720, -0.38055661, -0.38126576, -0.38197473, + -0.38268343, -0.38339192, -0.38410020, -0.38480824, -0.38551605, -0.38622364, -0.38693100, -0.38763815, + -0.38834503, -0.38905174, -0.38975817, -0.39046440, -0.39117038, -0.39187613, -0.39258167, -0.39328697, + -0.39399204, -0.39469686, -0.39540148, -0.39610586, -0.39681000, -0.39751390, -0.39821756, -0.39892101, + -0.39962420, -0.40032718, -0.40102988, -0.40173239, -0.40243465, -0.40313667, -0.40383846, -0.40454000, + -0.40524131, -0.40594238, -0.40664321, -0.40734380, -0.40804416, -0.40874428, -0.40944415, -0.41014379, + -0.41084316, -0.41154233, -0.41224122, -0.41293988, -0.41363832, -0.41433650, -0.41503441, -0.41573212, + -0.41642955, -0.41712677, -0.41782370, -0.41852042, -0.41921690, -0.41991311, -0.42060909, -0.42130479, + -0.42200026, -0.42269549, -0.42339048, -0.42408520, -0.42477968, -0.42547390, -0.42616788, -0.42686161, + -0.42755508, -0.42824832, -0.42894128, -0.42963400, -0.43032649, -0.43101871, -0.43171066, -0.43240237, + -0.43309382, -0.43378502, -0.43447596, -0.43516666, -0.43585709, -0.43654725, -0.43723717, -0.43792683, + -0.43861625, -0.43930539, -0.43999428, -0.44068289, -0.44137126, -0.44205937, -0.44274724, -0.44343480, + -0.44412214, -0.44480920, -0.44549602, -0.44618255, -0.44686884, -0.44755486, -0.44824061, -0.44892609, + -0.44961134, -0.45029628, -0.45098099, -0.45166543, -0.45234957, -0.45303348, -0.45371711, -0.45440048, + -0.45508358, -0.45576641, -0.45644897, -0.45713127, -0.45781329, -0.45849505, -0.45917654, -0.45985776, + -0.46053872, -0.46121940, -0.46189979, -0.46257994, -0.46325979, -0.46393937, -0.46461868, -0.46529773, + -0.46597651, -0.46665499, -0.46733320, -0.46801114, -0.46868882, -0.46936622, -0.47004333, -0.47072017, + -0.47139674, -0.47207302, -0.47274902, -0.47342476, -0.47410020, -0.47477537, -0.47545028, -0.47612488, + -0.47679922, -0.47747329, -0.47814706, -0.47882056, -0.47949377, -0.48016667, -0.48083934, -0.48151168, + -0.48218378, -0.48285556, -0.48352706, -0.48419830, -0.48486924, -0.48553991, -0.48621029, -0.48688036, + -0.48755017, -0.48821968, -0.48888889, -0.48955783, -0.49022648, -0.49089485, -0.49156290, -0.49223071, + -0.49289820, -0.49356541, -0.49423230, -0.49489895, -0.49556527, -0.49623129, -0.49689704, -0.49756250, + -0.49822766, -0.49889255, -0.49955711, -0.50022137, -0.50088537, -0.50154907, -0.50221246, -0.50287557, + -0.50353837, -0.50420088, -0.50486308, -0.50552505, -0.50618666, -0.50684798, -0.50750899, -0.50816971, + -0.50883013, -0.50949025, -0.51015007, -0.51080960, -0.51146883, -0.51212776, -0.51278639, -0.51344472, + -0.51410276, -0.51476043, -0.51541787, -0.51607502, -0.51673180, -0.51738828, -0.51804453, -0.51870042, + -0.51935601, -0.52001125, -0.52066624, -0.52132094, -0.52197528, -0.52262938, -0.52328312, -0.52393657, + -0.52458966, -0.52524251, -0.52589500, -0.52654725, -0.52719915, -0.52785075, -0.52850199, -0.52915299, + -0.52980363, -0.53045398, -0.53110403, -0.53175372, -0.53240311, -0.53305221, -0.53370100, -0.53434944, + -0.53499764, -0.53564548, -0.53629297, -0.53694016, -0.53758705, -0.53823364, -0.53887993, -0.53952587, + -0.54017144, -0.54081678, -0.54146177, -0.54210645, -0.54275078, -0.54339480, -0.54403853, -0.54468191, + -0.54532498, -0.54596776, -0.54661018, -0.54725230, -0.54789406, -0.54853553, -0.54917663, -0.54981750, + -0.55045795, -0.55109817, -0.55173796, -0.55237752, -0.55301672, -0.55365556, -0.55429411, -0.55493236, + -0.55557024, -0.55620778, -0.55684501, -0.55748194, -0.55811852, -0.55875480, -0.55939072, -0.56002629, + -0.56066155, -0.56129652, -0.56193113, -0.56256539, -0.56319934, -0.56383294, -0.56446624, -0.56509918, + -0.56573182, -0.56636411, -0.56699604, -0.56762767, -0.56825894, -0.56888992, -0.56952053, -0.57015079, + -0.57078075, -0.57141036, -0.57203960, -0.57266855, -0.57329714, -0.57392544, -0.57455337, -0.57518095, + -0.57580817, -0.57643509, -0.57706165, -0.57768792, -0.57831377, -0.57893932, -0.57956457, -0.58018941, + -0.58081394, -0.58143812, -0.58206201, -0.58268547, -0.58330864, -0.58393145, -0.58455396, -0.58517605, + -0.58579785, -0.58641928, -0.58704036, -0.58766115, -0.58828157, -0.58890158, -0.58952129, -0.59014070, + -0.59075969, -0.59137839, -0.59199667, -0.59261465, -0.59323227, -0.59384960, -0.59446651, -0.59508306, + -0.59569931, -0.59631521, -0.59693068, -0.59754586, -0.59816068, -0.59877521, -0.59938931, -0.60000306, + -0.60061646, -0.60122955, -0.60184222, -0.60245460, -0.60306662, -0.60367823, -0.60428953, -0.60490048, + -0.60551107, -0.60612124, -0.60673112, -0.60734063, -0.60794979, -0.60855860, -0.60916704, -0.60977507, + -0.61038280, -0.61099017, -0.61159718, -0.61220378, -0.61281008, -0.61341602, -0.61402154, -0.61462677, + -0.61523157, -0.61583608, -0.61644018, -0.61704391, -0.61764729, -0.61825031, -0.61885297, -0.61945528, + -0.62005723, -0.62065876, -0.62125999, -0.62186080, -0.62246126, -0.62306136, -0.62366110, -0.62426049, + -0.62485951, -0.62545812, -0.62605637, -0.62665427, -0.62725180, -0.62784898, -0.62844574, -0.62904221, + -0.62963825, -0.63023394, -0.63082922, -0.63142419, -0.63201874, -0.63261294, -0.63320678, -0.63380021, + -0.63439327, -0.63498598, -0.63557833, -0.63617027, -0.63676184, -0.63735306, -0.63794392, -0.63853437, + -0.63912445, -0.63971418, -0.64030349, -0.64089245, -0.64148104, -0.64206922, -0.64265704, -0.64324450, + -0.64383155, -0.64441824, -0.64500451, -0.64559048, -0.64617604, -0.64676118, -0.64734596, -0.64793038, + -0.64851439, -0.64909804, -0.64968133, -0.65026420, -0.65084666, -0.65142882, -0.65201056, -0.65259188, + -0.65317285, -0.65375340, -0.65433359, -0.65491343, -0.65549284, -0.65607190, -0.65665054, -0.65722883, + -0.65780669, -0.65838420, -0.65896130, -0.65953803, -0.66011435, -0.66069031, -0.66126585, -0.66184098, + -0.66241580, -0.66299015, -0.66356415, -0.66413778, -0.66471100, -0.66528380, -0.66585624, -0.66642827, + -0.66699994, -0.66757119, -0.66814202, -0.66871250, -0.66928262, -0.66985226, -0.67042154, -0.67099047, + -0.67155898, -0.67212707, -0.67269474, -0.67326206, -0.67382902, -0.67439550, -0.67496163, -0.67552739, + -0.67609268, -0.67665762, -0.67722219, -0.67778629, -0.67835003, -0.67891335, -0.67947632, -0.68003887, + -0.68060100, -0.68116271, -0.68172407, -0.68228501, -0.68284553, -0.68340570, -0.68396538, -0.68452471, + -0.68508369, -0.68564218, -0.68620032, -0.68675804, -0.68731534, -0.68787223, -0.68842876, -0.68898487, + -0.68954057, -0.69009584, -0.69065070, -0.69120520, -0.69175923, -0.69231290, -0.69286615, -0.69341904, + -0.69397146, -0.69452351, -0.69507509, -0.69562632, -0.69617712, -0.69672751, -0.69727749, -0.69782710, + -0.69837624, -0.69892502, -0.69947332, -0.70002127, -0.70056880, -0.70111591, -0.70166260, -0.70220888, + -0.70275474, -0.70330018, -0.70384526, -0.70438987, -0.70493406, -0.70547789, -0.70602125, -0.70656425, + -0.70710677, -0.70764893, -0.70819062, -0.70873195, -0.70927280, -0.70981330, -0.71035337, -0.71089298, + -0.71143222, -0.71197098, -0.71250939, -0.71304733, -0.71358484, -0.71412200, -0.71465868, -0.71519494, + -0.71573085, -0.71626627, -0.71680129, -0.71733588, -0.71787006, -0.71840382, -0.71893710, -0.71947002, + -0.72000253, -0.72053456, -0.72106618, -0.72159743, -0.72212821, -0.72265857, -0.72318846, -0.72371799, + -0.72424710, -0.72477573, -0.72530395, -0.72583181, -0.72635913, -0.72688609, -0.72741264, -0.72793871, + -0.72846437, -0.72898960, -0.72951442, -0.73003882, -0.73056275, -0.73108631, -0.73160940, -0.73213202, + -0.73265427, -0.73317605, -0.73369741, -0.73421836, -0.73473889, -0.73525894, -0.73577857, -0.73629779, + -0.73681659, -0.73733491, -0.73785281, -0.73837030, -0.73888731, -0.73940390, -0.73992008, -0.74043584, + -0.74095112, -0.74146599, -0.74198043, -0.74249440, -0.74300796, -0.74352109, -0.74403375, -0.74454600, + -0.74505776, -0.74556917, -0.74608010, -0.74659055, -0.74710059, -0.74761021, -0.74811935, -0.74862808, + -0.74913639, -0.74964422, -0.75015163, -0.75065863, -0.75116515, -0.75167120, -0.75217682, -0.75268203, + -0.75318682, -0.75369114, -0.75419497, -0.75469840, -0.75520140, -0.75570393, -0.75620598, -0.75670767, + -0.75720882, -0.75770962, -0.75820988, -0.75870979, -0.75920922, -0.75970817, -0.76020670, -0.76070476, + -0.76120239, -0.76169956, -0.76219630, -0.76269257, -0.76318842, -0.76368380, -0.76417875, -0.76467323, + -0.76516724, -0.76566088, -0.76615399, -0.76664668, -0.76713890, -0.76763070, -0.76812202, -0.76861292, + -0.76910335, -0.76959330, -0.77008283, -0.77057189, -0.77106053, -0.77154869, -0.77203637, -0.77252364, + -0.77301043, -0.77349681, -0.77398270, -0.77446812, -0.77495313, -0.77543765, -0.77592170, -0.77640533, + -0.77688849, -0.77737117, -0.77785343, -0.77833521, -0.77881652, -0.77929735, -0.77977777, -0.78025776, + -0.78073722, -0.78121626, -0.78169483, -0.78217292, -0.78265059, -0.78312778, -0.78360450, -0.78408080, + -0.78455657, -0.78503191, -0.78550684, -0.78598124, -0.78645521, -0.78692871, -0.78740174, -0.78787434, + -0.78834641, -0.78881806, -0.78928924, -0.78975999, -0.79023021, -0.79070002, -0.79116935, -0.79163820, + -0.79210657, -0.79257452, -0.79304194, -0.79350895, -0.79397547, -0.79444152, -0.79490715, -0.79537225, + -0.79583693, -0.79630107, -0.79676479, -0.79722804, -0.79769087, -0.79815316, -0.79861498, -0.79907638, + -0.79953724, -0.79999769, -0.80045766, -0.80091715, -0.80137616, -0.80183470, -0.80229282, -0.80275041, + -0.80320752, -0.80366421, -0.80412036, -0.80457610, -0.80503136, -0.80548608, -0.80594039, -0.80639422, + -0.80684757, -0.80730045, -0.80775285, -0.80820471, -0.80865616, -0.80910712, -0.80955762, -0.81000763, + -0.81045717, -0.81090623, -0.81135488, -0.81180298, -0.81225061, -0.81269777, -0.81314439, -0.81359059, + -0.81403631, -0.81448156, -0.81492633, -0.81537062, -0.81581444, -0.81625772, -0.81670058, -0.81714290, + -0.81758481, -0.81802619, -0.81846714, -0.81890756, -0.81934750, -0.81978697, -0.82022595, -0.82066447, + -0.82110250, -0.82154006, -0.82197714, -0.82241368, -0.82284981, -0.82328540, -0.82372051, -0.82415515, + -0.82458931, -0.82502300, -0.82545614, -0.82588887, -0.82632107, -0.82675278, -0.82718402, -0.82761478, + -0.82804507, -0.82847482, -0.82890409, -0.82933295, -0.82976121, -0.83018905, -0.83061641, -0.83104324, + -0.83146960, -0.83189547, -0.83232087, -0.83274579, -0.83317018, -0.83359408, -0.83401752, -0.83444041, + -0.83486289, -0.83528483, -0.83570629, -0.83612728, -0.83654773, -0.83696771, -0.83738720, -0.83780622, + -0.83822471, -0.83864272, -0.83906025, -0.83947724, -0.83989382, -0.84030986, -0.84072536, -0.84114045, + -0.84155500, -0.84196901, -0.84238261, -0.84279567, -0.84320825, -0.84362030, -0.84403187, -0.84444296, + -0.84485358, -0.84526366, -0.84567326, -0.84608233, -0.84649092, -0.84689903, -0.84730661, -0.84771377, + -0.84812033, -0.84852648, -0.84893203, -0.84933716, -0.84974176, -0.85014588, -0.85054946, -0.85095257, + -0.85135520, -0.85175729, -0.85215890, -0.85255998, -0.85296059, -0.85336071, -0.85376030, -0.85415941, + -0.85455799, -0.85495609, -0.85535365, -0.85575074, -0.85614735, -0.85654342, -0.85693896, -0.85733402, + -0.85772860, -0.85812265, -0.85851622, -0.85890925, -0.85930181, -0.85969388, -0.86008537, -0.86047643, + -0.86086696, -0.86125696, -0.86164647, -0.86203545, -0.86242396, -0.86281192, -0.86319941, -0.86358637, + -0.86397284, -0.86435878, -0.86474425, -0.86512917, -0.86551362, -0.86589754, -0.86628097, -0.86666387, + -0.86704624, -0.86742812, -0.86780947, -0.86819035, -0.86857069, -0.86895055, -0.86932987, -0.86970866, + -0.87008697, -0.87046480, -0.87084204, -0.87121886, -0.87159508, -0.87197083, -0.87234604, -0.87272078, + -0.87309498, -0.87346870, -0.87384182, -0.87421453, -0.87458664, -0.87495828, -0.87532938, -0.87570000, + -0.87607008, -0.87643969, -0.87680870, -0.87717724, -0.87754530, -0.87791282, -0.87827981, -0.87864625, + -0.87901223, -0.87937766, -0.87974262, -0.88010699, -0.88047087, -0.88083428, -0.88119709, -0.88155943, + -0.88192129, -0.88228256, -0.88264334, -0.88300359, -0.88336337, -0.88372254, -0.88408124, -0.88443947, + -0.88479710, -0.88515425, -0.88551086, -0.88586694, -0.88622254, -0.88657761, -0.88693213, -0.88728613, + -0.88763964, -0.88799256, -0.88834506, -0.88869697, -0.88904834, -0.88939923, -0.88974959, -0.89009941, + -0.89044875, -0.89079750, -0.89114577, -0.89149350, -0.89184070, -0.89218742, -0.89253354, -0.89287919, + -0.89322430, -0.89356887, -0.89391297, -0.89425647, -0.89459950, -0.89494199, -0.89528394, -0.89562535, + -0.89596623, -0.89630663, -0.89664650, -0.89698577, -0.89732456, -0.89766282, -0.89800060, -0.89833778, + -0.89867449, -0.89901060, -0.89934623, -0.89968133, -0.90001589, -0.90034992, -0.90068340, -0.90101641, + -0.90134883, -0.90168077, -0.90201217, -0.90234298, -0.90267330, -0.90300310, -0.90333235, -0.90366107, + -0.90398932, -0.90431696, -0.90464407, -0.90497071, -0.90529674, -0.90562230, -0.90594727, -0.90627176, + -0.90659571, -0.90691912, -0.90724200, -0.90756434, -0.90788609, -0.90820736, -0.90852809, -0.90884835, + -0.90916800, -0.90948713, -0.90980572, -0.91012377, -0.91044128, -0.91075826, -0.91107476, -0.91139066, + -0.91170603, -0.91202086, -0.91233516, -0.91264898, -0.91296220, -0.91327488, -0.91358703, -0.91389865, + -0.91420978, -0.91452032, -0.91483033, -0.91513979, -0.91544873, -0.91575712, -0.91606498, -0.91637230, + -0.91667908, -0.91698527, -0.91729099, -0.91759616, -0.91790080, -0.91820484, -0.91850841, -0.91881138, + -0.91911387, -0.91941577, -0.91971713, -0.92001796, -0.92031831, -0.92061806, -0.92091721, -0.92121589, + -0.92151403, -0.92181164, -0.92210865, -0.92240518, -0.92270112, -0.92299652, -0.92329144, -0.92358577, + -0.92387950, -0.92417276, -0.92446548, -0.92475760, -0.92504925, -0.92534029, -0.92563081, -0.92592078, + -0.92621022, -0.92649913, -0.92678750, -0.92707527, -0.92736250, -0.92764926, -0.92793542, -0.92822099, + -0.92850608, -0.92879063, -0.92907459, -0.92935801, -0.92964089, -0.92992324, -0.93020505, -0.93048626, + -0.93076694, -0.93104708, -0.93132669, -0.93160576, -0.93188429, -0.93216223, -0.93243963, -0.93271649, + -0.93299282, -0.93326855, -0.93354380, -0.93381846, -0.93409252, -0.93436611, -0.93463916, -0.93491161, + -0.93518353, -0.93545485, -0.93572569, -0.93599594, -0.93626565, -0.93653482, -0.93680346, -0.93707150, + -0.93733901, -0.93760598, -0.93787235, -0.93813825, -0.93840355, -0.93866831, -0.93893248, -0.93919611, + -0.93945920, -0.93972176, -0.93998373, -0.94024521, -0.94050604, -0.94076639, -0.94102615, -0.94128537, + -0.94154406, -0.94180220, -0.94205976, -0.94231677, -0.94257319, -0.94282907, -0.94308442, -0.94333923, + -0.94359344, -0.94384712, -0.94410026, -0.94435281, -0.94460481, -0.94485629, -0.94510722, -0.94535756, + -0.94560730, -0.94585657, -0.94610524, -0.94635338, -0.94660091, -0.94684792, -0.94709438, -0.94734025, + -0.94758558, -0.94783038, -0.94807458, -0.94831824, -0.94856137, -0.94880390, -0.94904590, -0.94928730, + -0.94952816, -0.94976848, -0.95000827, -0.95024747, -0.95048606, -0.95072412, -0.95096165, -0.95119864, + -0.95143503, -0.95167089, -0.95190614, -0.95214087, -0.95237499, -0.95260859, -0.95284164, -0.95307410, + -0.95330602, -0.95353740, -0.95376819, -0.95399845, -0.95422810, -0.95445722, -0.95468575, -0.95491374, + -0.95514119, -0.95536804, -0.95559436, -0.95582008, -0.95604527, -0.95626986, -0.95649391, -0.95671743, + -0.95694035, -0.95716268, -0.95738453, -0.95760572, -0.95782644, -0.95804650, -0.95826608, -0.95848507, + -0.95870346, -0.95892131, -0.95913863, -0.95935535, -0.95957154, -0.95978713, -0.96000212, -0.96021664, + -0.96043050, -0.96064389, -0.96085662, -0.96106887, -0.96128047, -0.96149158, -0.96170205, -0.96191204, + -0.96212143, -0.96233022, -0.96253848, -0.96274614, -0.96295327, -0.96315980, -0.96336579, -0.96357119, + -0.96377605, -0.96398038, -0.96418405, -0.96438724, -0.96458977, -0.96479183, -0.96499324, -0.96519411, + -0.96539444, -0.96559417, -0.96579337, -0.96599197, -0.96618998, -0.96638745, -0.96658438, -0.96678072, + -0.96697646, -0.96717167, -0.96736628, -0.96756035, -0.96775383, -0.96794677, -0.96813911, -0.96833086, + -0.96852207, -0.96871275, -0.96890283, -0.96909231, -0.96928126, -0.96946961, -0.96965736, -0.96984458, + -0.97003126, -0.97021735, -0.97040284, -0.97058779, -0.97077215, -0.97095591, -0.97113913, -0.97132182, + -0.97150391, -0.97168541, -0.97186631, -0.97204673, -0.97222650, -0.97240573, -0.97258437, -0.97276247, + -0.97293997, -0.97311687, -0.97329324, -0.97346902, -0.97364426, -0.97381890, -0.97399294, -0.97416645, + -0.97433937, -0.97451174, -0.97468352, -0.97485471, -0.97502536, -0.97519541, -0.97536486, -0.97553378, + -0.97570211, -0.97586989, -0.97603709, -0.97620368, -0.97636974, -0.97653520, -0.97670007, -0.97686440, + -0.97702813, -0.97719133, -0.97735387, -0.97751594, -0.97767735, -0.97783822, -0.97799850, -0.97815824, + -0.97831738, -0.97847593, -0.97863394, -0.97879136, -0.97894818, -0.97910446, -0.97926015, -0.97941524, + -0.97956979, -0.97972375, -0.97987711, -0.98002988, -0.98018211, -0.98033381, -0.98048484, -0.98063534, + -0.98078525, -0.98093462, -0.98108339, -0.98123157, -0.98137921, -0.98152626, -0.98167270, -0.98181856, + -0.98196387, -0.98210859, -0.98225272, -0.98239630, -0.98253930, -0.98268169, -0.98282355, -0.98296481, + -0.98310548, -0.98324561, -0.98338509, -0.98352402, -0.98366243, -0.98380023, -0.98393744, -0.98407406, + -0.98421007, -0.98434556, -0.98448044, -0.98461479, -0.98474848, -0.98488164, -0.98501426, -0.98514622, + -0.98527765, -0.98540848, -0.98553872, -0.98566842, -0.98579752, -0.98592603, -0.98605394, -0.98618132, + -0.98630810, -0.98643428, -0.98655993, -0.98668492, -0.98680937, -0.98693329, -0.98705655, -0.98717928, + -0.98730141, -0.98742294, -0.98754394, -0.98766434, -0.98778415, -0.98790336, -0.98802203, -0.98814011, + -0.98825759, -0.98837447, -0.98849082, -0.98860651, -0.98872167, -0.98883629, -0.98895025, -0.98906368, + -0.98917651, -0.98928875, -0.98940045, -0.98951149, -0.98962200, -0.98973197, -0.98984128, -0.98995006, + -0.99005818, -0.99016583, -0.99027282, -0.99037921, -0.99048507, -0.99059033, -0.99069500, -0.99079913, + -0.99090266, -0.99100554, -0.99110794, -0.99120969, -0.99131083, -0.99141145, -0.99151146, -0.99161088, + -0.99170977, -0.99180800, -0.99190569, -0.99200279, -0.99209929, -0.99219525, -0.99229062, -0.99238533, + -0.99247956, -0.99257314, -0.99266613, -0.99275857, -0.99285042, -0.99294168, -0.99303234, -0.99312246, + -0.99321193, -0.99330086, -0.99338919, -0.99347699, -0.99356413, -0.99365073, -0.99373674, -0.99382216, + -0.99390697, -0.99399120, -0.99407488, -0.99415797, -0.99424046, -0.99432236, -0.99440366, -0.99448442, + -0.99456459, -0.99464417, -0.99472314, -0.99480152, -0.99487931, -0.99495655, -0.99503320, -0.99510926, + -0.99518472, -0.99525958, -0.99533391, -0.99540764, -0.99548078, -0.99555331, -0.99562526, -0.99569660, + -0.99576741, -0.99583763, -0.99590725, -0.99597627, -0.99604470, -0.99611259, -0.99617982, -0.99624652, + -0.99631262, -0.99637812, -0.99644303, -0.99650741, -0.99657112, -0.99663430, -0.99669689, -0.99675888, + -0.99682027, -0.99688113, -0.99694133, -0.99700099, -0.99706006, -0.99711853, -0.99717641, -0.99723375, + -0.99729043, -0.99734658, -0.99740213, -0.99745709, -0.99751145, -0.99756521, -0.99761844, -0.99767107, + -0.99772304, -0.99777448, -0.99782532, -0.99787563, -0.99792528, -0.99797440, -0.99802285, -0.99807078, + -0.99811810, -0.99816483, -0.99821103, -0.99825656, -0.99830157, -0.99834591, -0.99838972, -0.99843293, + -0.99847555, -0.99851763, -0.99855906, -0.99859995, -0.99864024, -0.99867994, -0.99871904, -0.99875754, + -0.99879545, -0.99883282, -0.99886954, -0.99890572, -0.99894130, -0.99897629, -0.99901068, -0.99904448, + -0.99907774, -0.99911034, -0.99914241, -0.99917388, -0.99920475, -0.99923503, -0.99926478, -0.99929386, + -0.99932235, -0.99935031, -0.99937767, -0.99940443, -0.99943060, -0.99945617, -0.99948120, -0.99950558, + -0.99952942, -0.99955267, -0.99957532, -0.99959737, -0.99961883, -0.99963969, -0.99966002, -0.99967968, + -0.99969882, -0.99971735, -0.99973530, -0.99975264, -0.99976939, -0.99978560, -0.99980116, -0.99981618, + -0.99983060, -0.99984443, -0.99985766, -0.99987030, -0.99988234, -0.99989384, -0.99990469, -0.99991500, + -0.99992472, -0.99993384, -0.99994236, -0.99995029, -0.99995762, -0.99996442, -0.99997061, -0.99997616, + -0.99998116, -0.99998558, -0.99998939, -0.99999267, -0.99999529, -0.99999738, -0.99999881, -0.99999970, + -1.00000000, -0.99999970, -0.99999881, -0.99999738, -0.99999529, -0.99999267, -0.99998939, -0.99998558, + -0.99998116, -0.99997616, -0.99997061, -0.99996442, -0.99995762, -0.99995029, -0.99994236, -0.99993384, + -0.99992472, -0.99991500, -0.99990469, -0.99989384, -0.99988234, -0.99987030, -0.99985766, -0.99984443, + -0.99983060, -0.99981618, -0.99980116, -0.99978560, -0.99976939, -0.99975264, -0.99973530, -0.99971735, + -0.99969882, -0.99967968, -0.99966002, -0.99963969, -0.99961883, -0.99959737, -0.99957532, -0.99955267, + -0.99952942, -0.99950558, -0.99948120, -0.99945617, -0.99943060, -0.99940443, -0.99937767, -0.99935031, + -0.99932235, -0.99929386, -0.99926478, -0.99923503, -0.99920475, -0.99917388, -0.99914241, -0.99911034, + -0.99907774, -0.99904448, -0.99901068, -0.99897629, -0.99894130, -0.99890572, -0.99886954, -0.99883282, + -0.99879545, -0.99875754, -0.99871904, -0.99867994, -0.99864024, -0.99859995, -0.99855906, -0.99851763, + -0.99847555, -0.99843293, -0.99838972, -0.99834591, -0.99830157, -0.99825656, -0.99821103, -0.99816483, + -0.99811810, -0.99807078, -0.99802285, -0.99797440, -0.99792528, -0.99787563, -0.99782532, -0.99777448, + -0.99772304, -0.99767107, -0.99761844, -0.99756521, -0.99751145, -0.99745709, -0.99740213, -0.99734658, + -0.99729043, -0.99723375, -0.99717641, -0.99711853, -0.99706006, -0.99700099, -0.99694133, -0.99688113, + -0.99682027, -0.99675888, -0.99669689, -0.99663430, -0.99657112, -0.99650741, -0.99644303, -0.99637812, + -0.99631262, -0.99624652, -0.99617982, -0.99611259, -0.99604470, -0.99597627, -0.99590725, -0.99583763, + -0.99576741, -0.99569660, -0.99562526, -0.99555331, -0.99548078, -0.99540764, -0.99533391, -0.99525958, + -0.99518472, -0.99510926, -0.99503320, -0.99495655, -0.99487931, -0.99480152, -0.99472314, -0.99464417, + -0.99456459, -0.99448442, -0.99440366, -0.99432236, -0.99424046, -0.99415797, -0.99407488, -0.99399120, + -0.99390697, -0.99382216, -0.99373674, -0.99365073, -0.99356413, -0.99347699, -0.99338919, -0.99330086, + -0.99321193, -0.99312246, -0.99303234, -0.99294168, -0.99285042, -0.99275857, -0.99266613, -0.99257314, + -0.99247956, -0.99238533, -0.99229062, -0.99219525, -0.99209929, -0.99200279, -0.99190569, -0.99180800, + -0.99170977, -0.99161088, -0.99151146, -0.99141145, -0.99131083, -0.99120969, -0.99110794, -0.99100554, + -0.99090266, -0.99079913, -0.99069500, -0.99059033, -0.99048507, -0.99037921, -0.99027282, -0.99016583, + -0.99005818, -0.98995006, -0.98984128, -0.98973197, -0.98962200, -0.98951149, -0.98940045, -0.98928875, + -0.98917651, -0.98906368, -0.98895025, -0.98883629, -0.98872167, -0.98860651, -0.98849082, -0.98837447, + -0.98825759, -0.98814011, -0.98802203, -0.98790336, -0.98778415, -0.98766434, -0.98754394, -0.98742294, + -0.98730141, -0.98717928, -0.98705655, -0.98693329, -0.98680937, -0.98668492, -0.98655993, -0.98643428, + -0.98630810, -0.98618132, -0.98605394, -0.98592603, -0.98579752, -0.98566842, -0.98553872, -0.98540848, + -0.98527765, -0.98514622, -0.98501426, -0.98488164, -0.98474848, -0.98461479, -0.98448044, -0.98434556, + -0.98421007, -0.98407406, -0.98393744, -0.98380023, -0.98366243, -0.98352402, -0.98338509, -0.98324561, + -0.98310548, -0.98296481, -0.98282355, -0.98268169, -0.98253930, -0.98239630, -0.98225272, -0.98210859, + -0.98196387, -0.98181856, -0.98167270, -0.98152626, -0.98137921, -0.98123157, -0.98108339, -0.98093462, + -0.98078525, -0.98063534, -0.98048484, -0.98033381, -0.98018211, -0.98002988, -0.97987711, -0.97972375, + -0.97956979, -0.97941524, -0.97926015, -0.97910446, -0.97894818, -0.97879136, -0.97863394, -0.97847593, + -0.97831738, -0.97815824, -0.97799850, -0.97783822, -0.97767735, -0.97751594, -0.97735387, -0.97719133, + -0.97702813, -0.97686440, -0.97670007, -0.97653520, -0.97636974, -0.97620368, -0.97603709, -0.97586989, + -0.97570211, -0.97553378, -0.97536486, -0.97519541, -0.97502536, -0.97485471, -0.97468352, -0.97451174, + -0.97433937, -0.97416645, -0.97399294, -0.97381890, -0.97364426, -0.97346902, -0.97329324, -0.97311687, + -0.97293997, -0.97276247, -0.97258437, -0.97240573, -0.97222650, -0.97204673, -0.97186631, -0.97168541, + -0.97150391, -0.97132182, -0.97113913, -0.97095591, -0.97077215, -0.97058779, -0.97040284, -0.97021735, + -0.97003126, -0.96984458, -0.96965736, -0.96946961, -0.96928126, -0.96909231, -0.96890283, -0.96871275, + -0.96852207, -0.96833086, -0.96813911, -0.96794677, -0.96775383, -0.96756035, -0.96736628, -0.96717167, + -0.96697646, -0.96678072, -0.96658438, -0.96638745, -0.96618998, -0.96599197, -0.96579337, -0.96559417, + -0.96539444, -0.96519411, -0.96499324, -0.96479183, -0.96458977, -0.96438724, -0.96418405, -0.96398038, + -0.96377605, -0.96357119, -0.96336579, -0.96315980, -0.96295327, -0.96274614, -0.96253848, -0.96233022, + -0.96212143, -0.96191204, -0.96170205, -0.96149158, -0.96128047, -0.96106887, -0.96085662, -0.96064389, + -0.96043050, -0.96021664, -0.96000212, -0.95978713, -0.95957154, -0.95935535, -0.95913863, -0.95892131, + -0.95870346, -0.95848507, -0.95826608, -0.95804650, -0.95782644, -0.95760572, -0.95738453, -0.95716268, + -0.95694035, -0.95671743, -0.95649391, -0.95626986, -0.95604527, -0.95582008, -0.95559436, -0.95536804, + -0.95514119, -0.95491374, -0.95468575, -0.95445722, -0.95422810, -0.95399845, -0.95376819, -0.95353740, + -0.95330602, -0.95307410, -0.95284164, -0.95260859, -0.95237499, -0.95214087, -0.95190614, -0.95167089, + -0.95143503, -0.95119864, -0.95096165, -0.95072412, -0.95048606, -0.95024747, -0.95000827, -0.94976848, + -0.94952816, -0.94928730, -0.94904590, -0.94880390, -0.94856137, -0.94831824, -0.94807458, -0.94783038, + -0.94758558, -0.94734025, -0.94709438, -0.94684792, -0.94660091, -0.94635338, -0.94610524, -0.94585657, + -0.94560730, -0.94535756, -0.94510722, -0.94485629, -0.94460481, -0.94435281, -0.94410026, -0.94384712, + -0.94359344, -0.94333923, -0.94308442, -0.94282907, -0.94257319, -0.94231677, -0.94205976, -0.94180220, + -0.94154406, -0.94128537, -0.94102615, -0.94076639, -0.94050604, -0.94024521, -0.93998373, -0.93972176, + -0.93945920, -0.93919611, -0.93893248, -0.93866831, -0.93840355, -0.93813825, -0.93787235, -0.93760598, + -0.93733901, -0.93707150, -0.93680346, -0.93653482, -0.93626565, -0.93599594, -0.93572569, -0.93545485, + -0.93518353, -0.93491161, -0.93463916, -0.93436611, -0.93409252, -0.93381846, -0.93354380, -0.93326855, + -0.93299282, -0.93271649, -0.93243963, -0.93216223, -0.93188429, -0.93160576, -0.93132669, -0.93104708, + -0.93076694, -0.93048626, -0.93020505, -0.92992324, -0.92964089, -0.92935801, -0.92907459, -0.92879063, + -0.92850608, -0.92822099, -0.92793542, -0.92764926, -0.92736250, -0.92707527, -0.92678750, -0.92649913, + -0.92621022, -0.92592078, -0.92563081, -0.92534029, -0.92504925, -0.92475760, -0.92446548, -0.92417276, + -0.92387950, -0.92358577, -0.92329144, -0.92299652, -0.92270112, -0.92240518, -0.92210865, -0.92181164, + -0.92151403, -0.92121589, -0.92091721, -0.92061806, -0.92031831, -0.92001796, -0.91971713, -0.91941577, + -0.91911387, -0.91881138, -0.91850841, -0.91820484, -0.91790080, -0.91759616, -0.91729099, -0.91698527, + -0.91667908, -0.91637230, -0.91606498, -0.91575712, -0.91544873, -0.91513979, -0.91483033, -0.91452032, + -0.91420978, -0.91389865, -0.91358703, -0.91327488, -0.91296220, -0.91264898, -0.91233516, -0.91202086, + -0.91170603, -0.91139066, -0.91107476, -0.91075826, -0.91044128, -0.91012377, -0.90980572, -0.90948713, + -0.90916800, -0.90884835, -0.90852809, -0.90820736, -0.90788609, -0.90756434, -0.90724200, -0.90691912, + -0.90659571, -0.90627176, -0.90594727, -0.90562230, -0.90529674, -0.90497071, -0.90464407, -0.90431696, + -0.90398932, -0.90366107, -0.90333235, -0.90300310, -0.90267330, -0.90234298, -0.90201217, -0.90168077, + -0.90134883, -0.90101641, -0.90068340, -0.90034992, -0.90001589, -0.89968133, -0.89934623, -0.89901060, + -0.89867449, -0.89833778, -0.89800060, -0.89766282, -0.89732456, -0.89698577, -0.89664650, -0.89630663, + -0.89596623, -0.89562535, -0.89528394, -0.89494199, -0.89459950, -0.89425647, -0.89391297, -0.89356887, + -0.89322430, -0.89287919, -0.89253354, -0.89218742, -0.89184070, -0.89149350, -0.89114577, -0.89079750, + -0.89044875, -0.89009941, -0.88974959, -0.88939923, -0.88904834, -0.88869697, -0.88834506, -0.88799256, + -0.88763964, -0.88728613, -0.88693213, -0.88657761, -0.88622254, -0.88586694, -0.88551086, -0.88515425, + -0.88479710, -0.88443947, -0.88408124, -0.88372254, -0.88336337, -0.88300359, -0.88264334, -0.88228256, + -0.88192129, -0.88155943, -0.88119709, -0.88083428, -0.88047087, -0.88010699, -0.87974262, -0.87937766, + -0.87901223, -0.87864625, -0.87827981, -0.87791282, -0.87754530, -0.87717724, -0.87680870, -0.87643969, + -0.87607008, -0.87570000, -0.87532938, -0.87495828, -0.87458664, -0.87421453, -0.87384182, -0.87346870, + -0.87309498, -0.87272078, -0.87234604, -0.87197083, -0.87159508, -0.87121886, -0.87084204, -0.87046480, + -0.87008697, -0.86970866, -0.86932987, -0.86895055, -0.86857069, -0.86819035, -0.86780947, -0.86742812, + -0.86704624, -0.86666387, -0.86628097, -0.86589754, -0.86551362, -0.86512917, -0.86474425, -0.86435878, + -0.86397284, -0.86358637, -0.86319941, -0.86281192, -0.86242396, -0.86203545, -0.86164647, -0.86125696, + -0.86086696, -0.86047643, -0.86008537, -0.85969388, -0.85930181, -0.85890925, -0.85851622, -0.85812265, + -0.85772860, -0.85733402, -0.85693896, -0.85654342, -0.85614735, -0.85575074, -0.85535365, -0.85495609, + -0.85455799, -0.85415941, -0.85376030, -0.85336071, -0.85296059, -0.85255998, -0.85215890, -0.85175729, + -0.85135520, -0.85095257, -0.85054946, -0.85014588, -0.84974176, -0.84933716, -0.84893203, -0.84852648, + -0.84812033, -0.84771377, -0.84730661, -0.84689903, -0.84649092, -0.84608233, -0.84567326, -0.84526366, + -0.84485358, -0.84444296, -0.84403187, -0.84362030, -0.84320825, -0.84279567, -0.84238261, -0.84196901, + -0.84155500, -0.84114045, -0.84072536, -0.84030986, -0.83989382, -0.83947724, -0.83906025, -0.83864272, + -0.83822471, -0.83780622, -0.83738720, -0.83696771, -0.83654773, -0.83612728, -0.83570629, -0.83528483, + -0.83486289, -0.83444041, -0.83401752, -0.83359408, -0.83317018, -0.83274579, -0.83232087, -0.83189547, + -0.83146960, -0.83104324, -0.83061641, -0.83018905, -0.82976121, -0.82933295, -0.82890409, -0.82847482, + -0.82804507, -0.82761478, -0.82718402, -0.82675278, -0.82632107, -0.82588887, -0.82545614, -0.82502300, + -0.82458931, -0.82415515, -0.82372051, -0.82328540, -0.82284981, -0.82241368, -0.82197714, -0.82154006, + -0.82110250, -0.82066447, -0.82022595, -0.81978697, -0.81934750, -0.81890756, -0.81846714, -0.81802619, + -0.81758481, -0.81714290, -0.81670058, -0.81625772, -0.81581444, -0.81537062, -0.81492633, -0.81448156, + -0.81403631, -0.81359059, -0.81314439, -0.81269777, -0.81225061, -0.81180298, -0.81135488, -0.81090623, + -0.81045717, -0.81000763, -0.80955762, -0.80910712, -0.80865616, -0.80820471, -0.80775285, -0.80730045, + -0.80684757, -0.80639422, -0.80594039, -0.80548608, -0.80503136, -0.80457610, -0.80412036, -0.80366421, + -0.80320752, -0.80275041, -0.80229282, -0.80183470, -0.80137616, -0.80091715, -0.80045766, -0.79999769, + -0.79953724, -0.79907638, -0.79861498, -0.79815316, -0.79769087, -0.79722804, -0.79676479, -0.79630107, + -0.79583693, -0.79537225, -0.79490715, -0.79444152, -0.79397547, -0.79350895, -0.79304194, -0.79257452, + -0.79210657, -0.79163820, -0.79116935, -0.79070002, -0.79023021, -0.78975999, -0.78928924, -0.78881806, + -0.78834641, -0.78787434, -0.78740174, -0.78692871, -0.78645521, -0.78598124, -0.78550684, -0.78503191, + -0.78455657, -0.78408080, -0.78360450, -0.78312778, -0.78265059, -0.78217292, -0.78169483, -0.78121626, + -0.78073722, -0.78025776, -0.77977777, -0.77929735, -0.77881652, -0.77833521, -0.77785343, -0.77737117, + -0.77688849, -0.77640533, -0.77592170, -0.77543765, -0.77495313, -0.77446812, -0.77398270, -0.77349681, + -0.77301043, -0.77252364, -0.77203637, -0.77154869, -0.77106053, -0.77057189, -0.77008283, -0.76959330, + -0.76910335, -0.76861292, -0.76812202, -0.76763070, -0.76713890, -0.76664668, -0.76615399, -0.76566088, + -0.76516724, -0.76467323, -0.76417875, -0.76368380, -0.76318842, -0.76269257, -0.76219630, -0.76169956, + -0.76120239, -0.76070476, -0.76020670, -0.75970817, -0.75920922, -0.75870979, -0.75820988, -0.75770962, + -0.75720882, -0.75670767, -0.75620598, -0.75570393, -0.75520140, -0.75469840, -0.75419497, -0.75369114, + -0.75318682, -0.75268203, -0.75217682, -0.75167120, -0.75116515, -0.75065863, -0.75015163, -0.74964422, + -0.74913639, -0.74862808, -0.74811935, -0.74761021, -0.74710059, -0.74659055, -0.74608010, -0.74556917, + -0.74505776, -0.74454600, -0.74403375, -0.74352109, -0.74300796, -0.74249440, -0.74198043, -0.74146599, + -0.74095112, -0.74043584, -0.73992008, -0.73940390, -0.73888731, -0.73837030, -0.73785281, -0.73733491, + -0.73681659, -0.73629779, -0.73577857, -0.73525894, -0.73473889, -0.73421836, -0.73369741, -0.73317605, + -0.73265427, -0.73213202, -0.73160940, -0.73108631, -0.73056275, -0.73003882, -0.72951442, -0.72898960, + -0.72846437, -0.72793871, -0.72741264, -0.72688609, -0.72635913, -0.72583181, -0.72530395, -0.72477573, + -0.72424710, -0.72371799, -0.72318846, -0.72265857, -0.72212821, -0.72159743, -0.72106618, -0.72053456, + -0.72000253, -0.71947002, -0.71893710, -0.71840382, -0.71787006, -0.71733588, -0.71680129, -0.71626627, + -0.71573085, -0.71519494, -0.71465868, -0.71412200, -0.71358484, -0.71304733, -0.71250939, -0.71197098, + -0.71143222, -0.71089298, -0.71035337, -0.70981330, -0.70927280, -0.70873195, -0.70819062, -0.70764893, + -0.70710677, -0.70656425, -0.70602125, -0.70547789, -0.70493406, -0.70438987, -0.70384526, -0.70330018, + -0.70275474, -0.70220888, -0.70166260, -0.70111591, -0.70056880, -0.70002127, -0.69947332, -0.69892502, + -0.69837624, -0.69782710, -0.69727749, -0.69672751, -0.69617712, -0.69562632, -0.69507509, -0.69452351, + -0.69397146, -0.69341904, -0.69286615, -0.69231290, -0.69175923, -0.69120520, -0.69065070, -0.69009584, + -0.68954057, -0.68898487, -0.68842876, -0.68787223, -0.68731534, -0.68675804, -0.68620032, -0.68564218, + -0.68508369, -0.68452471, -0.68396538, -0.68340570, -0.68284553, -0.68228501, -0.68172407, -0.68116271, + -0.68060100, -0.68003887, -0.67947632, -0.67891335, -0.67835003, -0.67778629, -0.67722219, -0.67665762, + -0.67609268, -0.67552739, -0.67496163, -0.67439550, -0.67382902, -0.67326206, -0.67269474, -0.67212707, + -0.67155898, -0.67099047, -0.67042154, -0.66985226, -0.66928262, -0.66871250, -0.66814202, -0.66757119, + -0.66699994, -0.66642827, -0.66585624, -0.66528380, -0.66471100, -0.66413778, -0.66356415, -0.66299015, + -0.66241580, -0.66184098, -0.66126585, -0.66069031, -0.66011435, -0.65953803, -0.65896130, -0.65838420, + -0.65780669, -0.65722883, -0.65665054, -0.65607190, -0.65549284, -0.65491343, -0.65433359, -0.65375340, + -0.65317285, -0.65259188, -0.65201056, -0.65142882, -0.65084666, -0.65026420, -0.64968133, -0.64909804, + -0.64851439, -0.64793038, -0.64734596, -0.64676118, -0.64617604, -0.64559048, -0.64500451, -0.64441824, + -0.64383155, -0.64324450, -0.64265704, -0.64206922, -0.64148104, -0.64089245, -0.64030349, -0.63971418, + -0.63912445, -0.63853437, -0.63794392, -0.63735306, -0.63676184, -0.63617027, -0.63557833, -0.63498598, + -0.63439327, -0.63380021, -0.63320678, -0.63261294, -0.63201874, -0.63142419, -0.63082922, -0.63023394, + -0.62963825, -0.62904221, -0.62844574, -0.62784898, -0.62725180, -0.62665427, -0.62605637, -0.62545812, + -0.62485951, -0.62426049, -0.62366110, -0.62306136, -0.62246126, -0.62186080, -0.62125999, -0.62065876, + -0.62005723, -0.61945528, -0.61885297, -0.61825031, -0.61764729, -0.61704391, -0.61644018, -0.61583608, + -0.61523157, -0.61462677, -0.61402154, -0.61341602, -0.61281008, -0.61220378, -0.61159718, -0.61099017, + -0.61038280, -0.60977507, -0.60916704, -0.60855860, -0.60794979, -0.60734063, -0.60673112, -0.60612124, + -0.60551107, -0.60490048, -0.60428953, -0.60367823, -0.60306662, -0.60245460, -0.60184222, -0.60122955, + -0.60061646, -0.60000306, -0.59938931, -0.59877521, -0.59816068, -0.59754586, -0.59693068, -0.59631521, + -0.59569931, -0.59508306, -0.59446651, -0.59384960, -0.59323227, -0.59261465, -0.59199667, -0.59137839, + -0.59075969, -0.59014070, -0.58952129, -0.58890158, -0.58828157, -0.58766115, -0.58704036, -0.58641928, + -0.58579785, -0.58517605, -0.58455396, -0.58393145, -0.58330864, -0.58268547, -0.58206201, -0.58143812, + -0.58081394, -0.58018941, -0.57956457, -0.57893932, -0.57831377, -0.57768792, -0.57706165, -0.57643509, + -0.57580817, -0.57518095, -0.57455337, -0.57392544, -0.57329714, -0.57266855, -0.57203960, -0.57141036, + -0.57078075, -0.57015079, -0.56952053, -0.56888992, -0.56825894, -0.56762767, -0.56699604, -0.56636411, + -0.56573182, -0.56509918, -0.56446624, -0.56383294, -0.56319934, -0.56256539, -0.56193113, -0.56129652, + -0.56066155, -0.56002629, -0.55939072, -0.55875480, -0.55811852, -0.55748194, -0.55684501, -0.55620778, + -0.55557024, -0.55493236, -0.55429411, -0.55365556, -0.55301672, -0.55237752, -0.55173796, -0.55109817, + -0.55045795, -0.54981750, -0.54917663, -0.54853553, -0.54789406, -0.54725230, -0.54661018, -0.54596776, + -0.54532498, -0.54468191, -0.54403853, -0.54339480, -0.54275078, -0.54210645, -0.54146177, -0.54081678, + -0.54017144, -0.53952587, -0.53887993, -0.53823364, -0.53758705, -0.53694016, -0.53629297, -0.53564548, + -0.53499764, -0.53434944, -0.53370100, -0.53305221, -0.53240311, -0.53175372, -0.53110403, -0.53045398, + -0.52980363, -0.52915299, -0.52850199, -0.52785075, -0.52719915, -0.52654725, -0.52589500, -0.52524251, + -0.52458966, -0.52393657, -0.52328312, -0.52262938, -0.52197528, -0.52132094, -0.52066624, -0.52001125, + -0.51935601, -0.51870042, -0.51804453, -0.51738828, -0.51673180, -0.51607502, -0.51541787, -0.51476043, + -0.51410276, -0.51344472, -0.51278639, -0.51212776, -0.51146883, -0.51080960, -0.51015007, -0.50949025, + -0.50883013, -0.50816971, -0.50750899, -0.50684798, -0.50618666, -0.50552505, -0.50486308, -0.50420088, + -0.50353837, -0.50287557, -0.50221246, -0.50154907, -0.50088537, -0.50022137, -0.49955711, -0.49889255, + -0.49822766, -0.49756250, -0.49689704, -0.49623129, -0.49556527, -0.49489895, -0.49423230, -0.49356541, + -0.49289820, -0.49223071, -0.49156290, -0.49089485, -0.49022648, -0.48955783, -0.48888889, -0.48821968, + -0.48755017, -0.48688036, -0.48621029, -0.48553991, -0.48486924, -0.48419830, -0.48352706, -0.48285556, + -0.48218378, -0.48151168, -0.48083934, -0.48016667, -0.47949377, -0.47882056, -0.47814706, -0.47747329, + -0.47679922, -0.47612488, -0.47545028, -0.47477537, -0.47410020, -0.47342476, -0.47274902, -0.47207302, + -0.47139674, -0.47072017, -0.47004333, -0.46936622, -0.46868882, -0.46801114, -0.46733320, -0.46665499, + -0.46597651, -0.46529773, -0.46461868, -0.46393937, -0.46325979, -0.46257994, -0.46189979, -0.46121940, + -0.46053872, -0.45985776, -0.45917654, -0.45849505, -0.45781329, -0.45713127, -0.45644897, -0.45576641, + -0.45508358, -0.45440048, -0.45371711, -0.45303348, -0.45234957, -0.45166543, -0.45098099, -0.45029628, + -0.44961134, -0.44892609, -0.44824061, -0.44755486, -0.44686884, -0.44618255, -0.44549602, -0.44480920, + -0.44412214, -0.44343480, -0.44274724, -0.44205937, -0.44137126, -0.44068289, -0.43999428, -0.43930539, + -0.43861625, -0.43792683, -0.43723717, -0.43654725, -0.43585709, -0.43516666, -0.43447596, -0.43378502, + -0.43309382, -0.43240237, -0.43171066, -0.43101871, -0.43032649, -0.42963400, -0.42894128, -0.42824832, + -0.42755508, -0.42686161, -0.42616788, -0.42547390, -0.42477968, -0.42408520, -0.42339048, -0.42269549, + -0.42200026, -0.42130479, -0.42060909, -0.41991311, -0.41921690, -0.41852042, -0.41782370, -0.41712677, + -0.41642955, -0.41573212, -0.41503441, -0.41433650, -0.41363832, -0.41293988, -0.41224122, -0.41154233, + -0.41084316, -0.41014379, -0.40944415, -0.40874428, -0.40804416, -0.40734380, -0.40664321, -0.40594238, + -0.40524131, -0.40454000, -0.40383846, -0.40313667, -0.40243465, -0.40173239, -0.40102988, -0.40032718, + -0.39962420, -0.39892101, -0.39821756, -0.39751390, -0.39681000, -0.39610586, -0.39540148, -0.39469686, + -0.39399204, -0.39328697, -0.39258167, -0.39187613, -0.39117038, -0.39046440, -0.38975817, -0.38905174, + -0.38834503, -0.38763815, -0.38693100, -0.38622364, -0.38551605, -0.38480824, -0.38410020, -0.38339192, + -0.38268343, -0.38197473, -0.38126576, -0.38055661, -0.37984720, -0.37913761, -0.37842774, -0.37771770, + -0.37700742, -0.37629691, -0.37558618, -0.37487522, -0.37416407, -0.37345266, -0.37274107, -0.37202924, + -0.37131721, -0.37060493, -0.36989245, -0.36917976, -0.36846682, -0.36775368, -0.36704034, -0.36632678, + -0.36561298, -0.36489901, -0.36418480, -0.36347038, -0.36275572, -0.36204088, -0.36132580, -0.36061051, + -0.35989505, -0.35917935, -0.35846341, -0.35774729, -0.35703096, -0.35631442, -0.35559767, -0.35488069, + -0.35416353, -0.35344616, -0.35272855, -0.35201076, -0.35129276, -0.35057455, -0.34985614, -0.34913751, + -0.34841868, -0.34769964, -0.34698042, -0.34626096, -0.34554133, -0.34482148, -0.34410143, -0.34338117, + -0.34266073, -0.34194008, -0.34121922, -0.34049815, -0.33977687, -0.33905542, -0.33833376, -0.33761191, + -0.33688986, -0.33616760, -0.33544514, -0.33472249, -0.33399966, -0.33327660, -0.33255336, -0.33182994, + -0.33110631, -0.33038250, -0.32965845, -0.32893425, -0.32820985, -0.32748523, -0.32676044, -0.32603547, + -0.32531029, -0.32458493, -0.32385936, -0.32313362, -0.32240769, -0.32168156, -0.32095525, -0.32022873, + -0.31950203, -0.31877515, -0.31804809, -0.31732082, -0.31659338, -0.31586576, -0.31513792, -0.31440994, + -0.31368175, -0.31295338, -0.31222481, -0.31149608, -0.31076714, -0.31003806, -0.30930877, -0.30857930, + -0.30784965, -0.30711982, -0.30638981, -0.30565959, -0.30492923, -0.30419868, -0.30346796, -0.30273703, + -0.30200595, -0.30127469, -0.30054325, -0.29981163, -0.29907984, -0.29834786, -0.29761571, -0.29688337, + -0.29615089, -0.29541820, -0.29468536, -0.29395235, -0.29321915, -0.29248580, -0.29175225, -0.29101855, + -0.29028466, -0.28955063, -0.28881642, -0.28808203, -0.28734747, -0.28661272, -0.28587782, -0.28514278, + -0.28440753, -0.28367212, -0.28293657, -0.28220084, -0.28146493, -0.28072888, -0.27999264, -0.27925625, + -0.27851969, -0.27778298, -0.27704608, -0.27630904, -0.27557182, -0.27483445, -0.27409691, -0.27335921, + -0.27262136, -0.27188334, -0.27114516, -0.27040681, -0.26966831, -0.26892966, -0.26819086, -0.26745188, + -0.26671275, -0.26597348, -0.26523402, -0.26449442, -0.26375467, -0.26301476, -0.26227471, -0.26153448, + -0.26079410, -0.26005360, -0.25931293, -0.25857207, -0.25783110, -0.25708997, -0.25634867, -0.25560725, + -0.25486565, -0.25412393, -0.25338203, -0.25264001, -0.25189781, -0.25115550, -0.25041300, -0.24967039, + -0.24892761, -0.24818468, -0.24744162, -0.24669841, -0.24595505, -0.24521154, -0.24446790, -0.24372411, + -0.24298018, -0.24223611, -0.24149188, -0.24074753, -0.24000302, -0.23925838, -0.23851359, -0.23776866, + -0.23702361, -0.23627840, -0.23553306, -0.23478758, -0.23404196, -0.23329620, -0.23255031, -0.23180428, + -0.23105811, -0.23031181, -0.22956537, -0.22881879, -0.22807208, -0.22732525, -0.22657827, -0.22583115, + -0.22508392, -0.22433653, -0.22358903, -0.22284140, -0.22209363, -0.22134572, -0.22059768, -0.21984953, + -0.21910124, -0.21835282, -0.21760428, -0.21685560, -0.21610680, -0.21535787, -0.21460882, -0.21385963, + -0.21311031, -0.21236089, -0.21161133, -0.21086164, -0.21011184, -0.20936191, -0.20861185, -0.20786168, + -0.20711137, -0.20636095, -0.20561041, -0.20485975, -0.20410897, -0.20335807, -0.20260704, -0.20185590, + -0.20110464, -0.20035325, -0.19960175, -0.19885014, -0.19809841, -0.19734657, -0.19659460, -0.19584252, + -0.19509032, -0.19433801, -0.19358559, -0.19283305, -0.19208039, -0.19132763, -0.19057475, -0.18982176, + -0.18906866, -0.18831545, -0.18756212, -0.18680869, -0.18605515, -0.18530150, -0.18454774, -0.18379387, + -0.18303989, -0.18228580, -0.18153161, -0.18077731, -0.18002290, -0.17926839, -0.17851377, -0.17775905, + -0.17700422, -0.17624930, -0.17549425, -0.17473911, -0.17398387, -0.17322853, -0.17247309, -0.17171754, + -0.17096189, -0.17020614, -0.16945030, -0.16869435, -0.16793829, -0.16718215, -0.16642590, -0.16566956, + -0.16491312, -0.16415659, -0.16339995, -0.16264322, -0.16188639, -0.16112947, -0.16037245, -0.15961535, + -0.15885815, -0.15810084, -0.15734346, -0.15658598, -0.15582840, -0.15507074, -0.15431297, -0.15355512, + -0.15279719, -0.15203916, -0.15128104, -0.15052283, -0.14976454, -0.14900614, -0.14824767, -0.14748912, + -0.14673047, -0.14597175, -0.14521292, -0.14445402, -0.14369503, -0.14293596, -0.14217681, -0.14141756, + -0.14065824, -0.13989884, -0.13913934, -0.13837977, -0.13762012, -0.13686039, -0.13610058, -0.13534068, + -0.13458070, -0.13382065, -0.13306053, -0.13230032, -0.13154003, -0.13077967, -0.13001922, -0.12925871, + -0.12849811, -0.12773745, -0.12697670, -0.12621588, -0.12545498, -0.12469402, -0.12393297, -0.12317186, + -0.12241068, -0.12164941, -0.12088808, -0.12012669, -0.11936522, -0.11860368, -0.11784206, -0.11708038, + -0.11631863, -0.11555681, -0.11479492, -0.11403298, -0.11327095, -0.11250886, -0.11174671, -0.11098449, + -0.11022221, -0.10945985, -0.10869744, -0.10793497, -0.10717242, -0.10640982, -0.10564715, -0.10488442, + -0.10412163, -0.10335878, -0.10259587, -0.10183290, -0.10106986, -0.10030677, -0.09954362, -0.09878041, + -0.09801714, -0.09725381, -0.09649043, -0.09572699, -0.09496350, -0.09419994, -0.09343634, -0.09267268, + -0.09190895, -0.09114519, -0.09038136, -0.08961748, -0.08885355, -0.08808957, -0.08732554, -0.08656145, + -0.08579731, -0.08503313, -0.08426889, -0.08350460, -0.08274026, -0.08197588, -0.08121145, -0.08044697, + -0.07968244, -0.07891786, -0.07815325, -0.07738858, -0.07662386, -0.07585911, -0.07509430, -0.07432945, + -0.07356457, -0.07279963, -0.07203465, -0.07126963, -0.07050458, -0.06973947, -0.06897433, -0.06820914, + -0.06744392, -0.06667866, -0.06591335, -0.06514801, -0.06438263, -0.06361721, -0.06285176, -0.06208627, + -0.06132074, -0.06055517, -0.05978957, -0.05902394, -0.05825827, -0.05749256, -0.05672682, -0.05596105, + -0.05519525, -0.05442941, -0.05366354, -0.05289764, -0.05213170, -0.05136574, -0.05059975, -0.04983373, + -0.04906768, -0.04830159, -0.04753548, -0.04676935, -0.04600318, -0.04523699, -0.04447077, -0.04370453, + -0.04293826, -0.04217196, -0.04140564, -0.04063930, -0.03987293, -0.03910654, -0.03834012, -0.03757368, + -0.03680722, -0.03604074, -0.03527424, -0.03450771, -0.03374117, -0.03297461, -0.03220803, -0.03144142, + -0.03067480, -0.02990817, -0.02914151, -0.02837484, -0.02760815, -0.02684144, -0.02607472, -0.02530798, + -0.02454123, -0.02377446, -0.02300768, -0.02224089, -0.02147408, -0.02070726, -0.01994043, -0.01917358, + -0.01840673, -0.01763986, -0.01687299, -0.01610610, -0.01533921, -0.01457230, -0.01380539, -0.01303847, + -0.01227154, -0.01150460, -0.01073766, -0.00997071, -0.00920375, -0.00843679, -0.00766983, -0.00690286, + -0.00613588, -0.00536891, -0.00460193, -0.00383494, -0.00306796, -0.00230097, -0.00153398, -0.00076699 + }; +#endif +
\ No newline at end of file diff --git a/testsuites/isvv/shared/utils.c b/testsuites/isvv/shared/utils.c new file mode 100644 index 0000000000..46b2321458 --- /dev/null +++ b/testsuites/isvv/shared/utils.c @@ -0,0 +1,397 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 2022 Critical Software SA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <rtems/bspIo.h> +#include <string.h> +#include "utils.h" +#include "isvv_rtems_aux.h" + +uint8_t TEST_SET[IMAGE_WIDTH][IMAGE_HEIGHT]; + +void Loop(int16_t x) { + volatile int i; + for (i=0; i<100000* x; i++); +} + +uint32_t crc32(const uint8_t *s,size_t n) +{ + uint32_t crc=0xFFFFFFFF; + for(size_t i=0;i<n;i++) { + char ch=s[i]; + for(size_t j=0;j<8;j++) { + uint32_t b=(ch^crc)&1; + crc>>=1; + if(b) crc=crc^0xEDB88320; + ch>>=1; + } + } + + return ~crc; +} + +/* to print results */ +void print_test_results(void) +{ + char str[8*sizeof(uint32_t)+1]; + uint32_t crc = crc32((uint8_t *)&TEST_SET[0][0], sizeof(TEST_SET)); + print_string("Begin set {\n"); + print_string("0x"); + print_string(itoa(crc, &str[0], 16)); + // print_string("P6 \n"); + // print_string(itoa(IMAGE_WIDTH, &str[0], 10)); + // print_string(" "); + // print_string(itoa(IMAGE_HEIGHT, &str[0], 10)); + // print_string("\n255\n"); + // for(int j= 0; j<IMAGE_HEIGHT; j++ ) + // { + // for(int i = 0; i<IMAGE_WIDTH; i++ ) + // { + // if (TEST_SET[i][j] < 16) + // { + // print_string("0"); + // print_string(itoa(TEST_SET[i][j], &str[0], 16)); + // } + // else + // print_string(itoa(TEST_SET[i][j], &str[0], 16)); + // // print_string((char)TEST_SET[i][j]); + // //block of code to generate output to a .ppm file + // // if (TEST_SET[i][j]<50) color(0,0,0); + // // else if( TEST_SET[i][j]<100) color(5,5,5); + // // else if (TEST_SET[i][j]<150) color(0,0,255); + // // else if (TEST_SET[i][j]<255) color(255,255,255); + // // else color(180,0,0); + // } + // } + print_string("\n} End set\n"); +} + +//function to print on unsigned char rgb format to generate the +//output to a .ppm file +void color(uint8_t red, uint8_t green, uint8_t blue) +{ + BSP_output_char((unsigned char)red); + BSP_output_char((unsigned char)green); + BSP_output_char((unsigned char)blue); +} + +// return the lentgh of a string +size_t str_len (const char *str) +{ + const char *s = str; + while (*s) s++; + return s - str; +} + +//print a string +void print_string(const char *string) +{ + char *s; + size_t i=0; + s = (char *) string; + + while (i<str_len(s)) + { + BSP_output_char(s[i]); + ++i; + } +} + +// swap two chars +void swap (char *x, char *y) +{ + char temp = *x; + *x = *y; + *y = temp; +} + + +// function to reverse the order of an array/a string +void reverse(char str[], int length) +{ + int start = 0; + int end = length - 1; + while (start < end) + { + swap(&str[start], &str[end]); + start++; + end--; + } +} + +// Implementation of itoa() +char* itoa(int num, char* str, int base) +{ + uint32_t i = 0; + bool isNegative = false; + uint32_t u32num = (uint32_t) num; + uint32_t u32base = (uint32_t) base; + + /* Handle 0 explicitly, otherwise empty string is printed for 0 */ + if (num == 0) + { + str[i++] = '0'; + str[i] = '\0'; + return str; + } + + // In standard itoa(), negative numbers are handled only with + // base 10. Otherwise numbers are considered unsigned. + if (num < 0 && base == 10) + { + // -2^31 is a special case, and needs to be treated diferently + if (num == -2147483648) + { + memcpy(str,"-2147483648", str_len("-2147483648")); + return str; + } + isNegative = true; + u32num = (uint32_t) (-num); + } + + // Process individual digits + while (u32num != 0) + { + uint32_t u32rem = u32num % u32base; + str[i++] = (u32rem > 9)? (u32rem-10) + 'a' : u32rem + '0'; + u32num = u32num/u32base; + } + + // If number is negative, append '-' + if (isNegative) + str[i++] = '-'; + + str[i] = '\0'; // Append string terminator + + // Reverse the string + reverse(str, str_len(str)); + + return str; +} + +// Function to calc mandelbrot set +void mandelbrot_tile(uint8_t tile, uint8_t tiles) +{ + float zx, zy, x_zero, tempx, y_zero; + uint16_t iteration, y_min_tile, y_max_tile; + + // setting first and last point of the tile + y_min_tile = ( IMAGE_HEIGHT/tiles ) * (tile - 1); + y_max_tile = tile < tiles ? (IMAGE_HEIGHT / tiles) * tile : IMAGE_HEIGHT; + + // scanning every point in the tile + for (uint16_t x = 0; x < IMAGE_WIDTH; x++) + { + x_zero = (x * SCALE_X)+ LEFT; + for (uint16_t y = y_min_tile; y < y_max_tile; y++) + { + //scaling to lie in the mandelbrot scale + y_zero = (y * SCALE_Y) + TOP; + + //iterations need to be reset before calculations for each point + zx = 0; + zy = 0; + iteration = 0; + + // Calculate whether belongs to the Mandelbrot set or not + while ((zx * zx + zy * zy < 4) && (iteration < MAXITERATION)) + { + // Calculate Mandelbrot function + // z = z*z + c where z is a complex number + tempx = zx * zx - zy * zy + x_zero; + zy = 2 * zx * zy + y_zero; + zx = tempx; + + iteration = iteration + 1; + } + TEST_SET[x][y]=iteration; + } + } +} + +// Dumb implementation of primality test +bool is_prime(uint64_t p) +{ + if (2 == p) + return TRUE; + else if ((1 >= p) || (0 == (p % 2))) + return FALSE; + else + { + bool prime = TRUE; + const uint32_t to = p / 2; + for (uint32_t i = 3; i <= to; i += 2) + { + if (0 == (p % i)) { + prime = false; + break; + } + } + return prime; + } +} + +bool is_mersenne_prime(uint64_t p) +{ + if (2 == p) + return TRUE; + else if (p >= 64) + { + // Using this to make sure we don't run into any undefined behaviour + // When left-shifting bits by greater than the set amount + // The object of this function isn't necessarily to get the correct value for any given integer + // Just to stress the the CPU while utilising lots of execution time to assert robustness + return false; + } + else + { + const uint64_t m_p = (1LLU << p) - 1; + uint64_t s = 4; + uint64_t i; + for (i = 3; i <= p; i++) + { + s = (s * s - 2) % m_p; + } + return 0 == s; + } +} + +// Dumb implementation of power function for small numbers +uint64_t power (uint16_t num, uint16_t exp) { + uint64_t total = 1; + for (uint16_t i = 0; i < exp; i++) { + total *= num; + } + return total; +} + +uint32_t isqrt(uint32_t val) { + uint32_t temp, g = 0U, b = 0x8000U, bshft = 15U; + do { + if (val >= (temp = (((g << 1) + b)<<bshft--))) { + g += b; + val -= temp; + } + } while (b >>= 1); + return g; +} + + +//----------------------------------------------------------------------------- +// Functions related with signal processing +//----------------------------------------------------------------------------- + +static void swapf(float *x, float *y){ + float temp = *x; + *x = *y; + *y = temp; +} + +static uint32_t bits_reverse(uint32_t val, int width) { + uint32_t result = 0; + for (int i = 0; i < width; i++, val >>= 1) + result = (result << 1) | (val & 1U); + return result; +} + +float cos_aprox(float arg) { + // arg must be between 0 and 2*PI + uint32_t idx = (uint32_t)(arg/(2*PI)*FFT_TABLE_SIZE); + float ro = (arg/(2*PI)*FFT_TABLE_SIZE)-(float)idx; + // using liner interpolation in the case that the given arg does not match exactly with a direct table entry + return cosTable[idx%FFT_TABLE_SIZE] + ro*(cosTable[(idx+1)%FFT_TABLE_SIZE]-cosTable[idx%FFT_TABLE_SIZE]); +} + +float sin_aprox(float arg) { + // arg must be between 0 and 2*PI + uint32_t idx = (uint32_t)(arg/(2*PI)*FFT_TABLE_SIZE); + float ro = (arg/(2*PI)*FFT_TABLE_SIZE)-(float)idx; + // using liner interpolation in the case that the given arg does not match exactly with a direct table entry + return sinTable[idx%FFT_TABLE_SIZE] + ro*(sinTable[(idx+1)%FFT_TABLE_SIZE]-sinTable[idx%FFT_TABLE_SIZE]); +} + +float blackman_harris(int n, int N){ + float a0, a1, a2, a3, seg1, seg2, seg3, w_n; + a0 = 0.35875f; + a1 = 0.48829f; + a2 = 0.14128f; + a3 = 0.01168f; + + seg1 = a1 * (float) cos_aprox((float)(2*PI*n)/(float) (N - 1)); + seg2 = a2 * (float) cos_aprox((float)(4*PI*n)/(float) (N - 1)); + seg3 = a3 * (float) cos_aprox((float)(6*PI*n)/(float) (N - 1)); + + w_n = a0 - seg1 + seg2 - seg3; + + return w_n; +} + +void fft( float *inReal, float *inImag, uint32_t log2_N ){ + const uint32_t N = 1 << log2_N; + + // Bits-reversed + for (uint32_t i = 0; i < N; i++) { + uint32_t j = bits_reverse(i, log2_N); + if (j > i) { + swapf(&inReal[i], &inReal[j]); + swapf(&inImag[i], &inImag[j]); + } + } + + // Cooley-Tukey radix-2 FFT + for (uint32_t size = 2; size <= N; size *= 2) { + for (uint32_t i = 0; i < N; i += size) { + uint32_t k=0; + for (uint32_t j = i; j < i + size/2; j++) { + float a_real = inReal[j]; + float a_imag = inImag[j]; + float b_real = inReal[j+size/2]; + float b_imag = inImag[j+size/2]; + float twiddle_real = cos_aprox(2.0*PI*(float)k/(float)N); + float twiddle_imag = sin_aprox(2.0*PI*(float)k/(float)N); + + float bias_real = b_real * twiddle_real + b_imag * twiddle_imag; + float bias_imag = -b_real * twiddle_imag + b_imag * twiddle_real; + inReal[j+size/2] = a_real - bias_real; + inImag[j+size/2] = a_imag - bias_imag; + inReal[j] = a_real + bias_real; + inImag[j] = a_imag + bias_imag; + k += N/size; + } + } + } +} + + +float noise_generator(uint32_t seed) { + static uint32_t lfsr = 0xE3F5828U; + if (seed != 0) { lfsr = seed; } + /* taps: 32,22,2,1; feedback polynomial : x^32 + x^22 + x^2 + x^1 + 1 */ + uint32_t bit = ((lfsr >> 0) ^ (lfsr >> 10) ^ (lfsr >> 30) ^ (lfsr >> 31)) & 1u; + lfsr = (lfsr >> 1) | (bit << 31); + return (((float)lfsr / (float)UINT32_MAX) - 0.5f); +} + diff --git a/testsuites/isvv/shared/utils.h b/testsuites/isvv/shared/utils.h new file mode 100644 index 0000000000..3de91eb3a9 --- /dev/null +++ b/testsuites/isvv/shared/utils.h @@ -0,0 +1,111 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 2022 Critical Software SA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Calculates the mandebroot set +*/ +#include <rtems.h> +#include "trig_tables.h" + +#ifdef gr740 + #define TEST_PROCESSORS 4 +#endif +#ifdef gr712rc + #define TEST_PROCESSORS 2 +#endif + +#define MAXITERATION 255 +#define IMAGE_WIDTH 2250 +#define IMAGE_HEIGHT 2250 + +#define LEFT -2.00 //x max value +#define SIDE_X 2.47 //x range (xmax-xmin) +#define TOP 1.12 //y max value +#define SIDE_Y -2.24 //y range (ymax-ymin) +#define SCALE_X (SIDE_X / IMAGE_WIDTH) +#define SCALE_Y (SIDE_Y / IMAGE_HEIGHT) + +#define ASSERT_SUCCESS(sc) \ + do { \ + if ((sc) != RTEMS_SUCCESSFUL) \ + { \ + print_string(rtems_status_text(sc)); \ + print_string("\n"); \ + rtems_fatal(RTEMS_FATAL_SOURCE_EXIT, __LINE__); \ + } \ + } while (0) + +#define ASSERT_SUCCESS_WITHOUT_FAILING(sc) \ + do { \ + if ((sc) != RTEMS_SUCCESSFUL) \ + { \ + print_string(rtems_status_text(sc)); \ + print_string("\n"); \ + } \ + } while (0) + +#define MAX(x, y) (((x) > (y)) ? (x) : (y)) + +#define MIN(x, y) (((x) < (y)) ? (x) : (y)) + +void Loop(int16_t x); + +uint32_t crc32(const uint8_t *s,size_t n); + +void print_test_results(void); + +void color(uint8_t red, uint8_t green, uint8_t blue); + +size_t str_len (const char *str); + +void print_string(const char *string); + +void swap (char *x, char *y); + +void reverse(char str[], int length); + +char* itoa(int num, char* str, int base); + +void mandelbrot_tile(uint8_t tile, uint8_t tiles); + +bool is_prime(uint64_t p); + +bool is_mersenne_prime(uint64_t p); + +uint64_t power(uint16_t num, uint16_t exp); + +uint32_t isqrt(uint32_t val); + +float sin_aprox(float arg); + +float cos_aprox(float arg); + +float blackman_harris(int n, int N); + +void fft(float *inReal, float *inImag, uint32_t log2_N); + +float noise_generator(uint32_t seed); |