| 1 | ! ============================================================================== |
| 2 | ! Simplified test program for Phase 6 - Executor module with memory pooling |
| 3 | ! ============================================================================== |
| 4 | program test_executor_simple |
| 5 | use string_pool |
| 6 | use memory_dashboard |
| 7 | use shell_types |
| 8 | use iso_fortran_env, only: output_unit |
| 9 | implicit none |
| 10 | |
| 11 | type(string_ref) :: buffer_ref, output_ref, cmd_ref |
| 12 | type(string_ref) :: pipe_buffer_ref, heredoc_ref |
| 13 | type(string_ref), allocatable :: token_refs(:) |
| 14 | integer :: i, j |
| 15 | logical :: test_passed |
| 16 | integer :: total_allocs, total_deallocs, current_strings, peak_strings |
| 17 | real :: hit_rate |
| 18 | character(:), pointer :: str_ptr |
| 19 | |
| 20 | test_passed = .true. |
| 21 | |
| 22 | print *, "=== Phase 6 Executor Memory Pooling Test (Simplified) ===" |
| 23 | print *, "Testing pooled memory for command execution" |
| 24 | print * |
| 25 | |
| 26 | ! Initialize the pool and dashboard |
| 27 | call pool_init() |
| 28 | call dashboard_init(verbose=.false.) |
| 29 | |
| 30 | ! Test 1: Large output buffer allocation (typical for command output) |
| 31 | print *, "Test 1: Testing large output buffer allocation (16KB)..." |
| 32 | |
| 33 | ! Allocate a large buffer for command output capture |
| 34 | output_ref = pool_get_string(16384) ! 16KB buffer |
| 35 | call dashboard_track_allocation(MOD_EXECUTOR, 16384, 5) ! bucket 5 for 16KB |
| 36 | |
| 37 | ! Simulate capturing command output |
| 38 | call pool_copy_to_ref(output_ref, "Command output line 1" // new_line('a') // & |
| 39 | "Command output line 2" // new_line('a') // & |
| 40 | "Command output line 3") |
| 41 | |
| 42 | str_ptr => output_ref%data |
| 43 | if (associated(str_ptr)) then |
| 44 | print *, " Output buffer allocated (16KB)" |
| 45 | print *, " First line:", str_ptr(1:21) |
| 46 | if (str_ptr(1:21) == "Command output line 1") then |
| 47 | print *, " PASSED: Large buffer working" |
| 48 | else |
| 49 | print *, " FAILED: Buffer content incorrect" |
| 50 | test_passed = .false. |
| 51 | end if |
| 52 | end if |
| 53 | |
| 54 | ! Release the buffer |
| 55 | call pool_release_string(output_ref) |
| 56 | call dashboard_track_deallocation(MOD_EXECUTOR, 16384, 5) |
| 57 | |
| 58 | ! Test 2: Command reconstruction buffer (4KB) |
| 59 | print *, "" |
| 60 | print *, "Test 2: Testing command reconstruction buffer (4KB)..." |
| 61 | |
| 62 | cmd_ref = pool_get_string(4096) ! 4KB for reconstructed commands |
| 63 | call dashboard_track_allocation(MOD_EXECUTOR, 4096, 4) |
| 64 | |
| 65 | ! Simulate reconstructing a command from tokens |
| 66 | call pool_copy_to_ref(cmd_ref, "echo 'This is a reconstructed command' | grep command | wc -l") |
| 67 | |
| 68 | str_ptr => cmd_ref%data |
| 69 | if (associated(str_ptr)) then |
| 70 | print *, " Reconstructed command:", trim(str_ptr) |
| 71 | if (index(str_ptr, "reconstructed command") > 0) then |
| 72 | print *, " PASSED: Command reconstruction buffer working" |
| 73 | else |
| 74 | print *, " FAILED: Reconstruction failed" |
| 75 | test_passed = .false. |
| 76 | end if |
| 77 | end if |
| 78 | |
| 79 | call pool_release_string(cmd_ref) |
| 80 | call dashboard_track_deallocation(MOD_EXECUTOR, 4096, 4) |
| 81 | |
| 82 | ! Test 3: Pipeline data transfer buffers |
| 83 | print *, "" |
| 84 | print *, "Test 3: Testing pipeline data transfer buffers..." |
| 85 | |
| 86 | ! Allocate buffer for pipe data transfer |
| 87 | pipe_buffer_ref = pool_get_string(8192) ! 8KB for pipe data |
| 88 | call dashboard_track_allocation(MOD_EXECUTOR, 8192, 5) ! maps to bucket 5 |
| 89 | |
| 90 | ! Simulate data transfer through pipe |
| 91 | call pool_copy_to_ref(pipe_buffer_ref, & |
| 92 | "Data from process 1 flowing through pipe to process 2...") |
| 93 | |
| 94 | str_ptr => pipe_buffer_ref%data |
| 95 | if (associated(str_ptr)) then |
| 96 | print *, " Pipe buffer (8KB) allocated" |
| 97 | print *, " Data sample:", trim(str_ptr) |
| 98 | print *, " PASSED: Pipeline buffer working" |
| 99 | end if |
| 100 | |
| 101 | call pool_release_string(pipe_buffer_ref) |
| 102 | call dashboard_track_deallocation(MOD_EXECUTOR, 8192, 5) |
| 103 | |
| 104 | ! Test 4: Token expansion buffers (multiple 1KB buffers) |
| 105 | print *, "" |
| 106 | print *, "Test 4: Testing token expansion buffers..." |
| 107 | |
| 108 | ! Allocate multiple token buffers as executor would |
| 109 | allocate(token_refs(5)) |
| 110 | do i = 1, 5 |
| 111 | token_refs(i) = pool_get_string(1024) ! 1KB per token |
| 112 | call dashboard_track_allocation(MOD_EXECUTOR, 1024, 3) |
| 113 | end do |
| 114 | |
| 115 | ! Simulate token expansion |
| 116 | call pool_copy_to_ref(token_refs(1), "ls") |
| 117 | call pool_copy_to_ref(token_refs(2), "-la") |
| 118 | call pool_copy_to_ref(token_refs(3), "/home/user") |
| 119 | call pool_copy_to_ref(token_refs(4), "|") |
| 120 | call pool_copy_to_ref(token_refs(5), "grep") |
| 121 | |
| 122 | print *, " Allocated 5 token buffers (1KB each)" |
| 123 | print *, " Token 1:", trim(token_refs(1)%data) |
| 124 | print *, " Token 2:", trim(token_refs(2)%data) |
| 125 | print *, " Token 5:", trim(token_refs(5)%data) |
| 126 | |
| 127 | ! Release token buffers |
| 128 | do i = 1, 5 |
| 129 | call pool_release_string(token_refs(i)) |
| 130 | call dashboard_track_deallocation(MOD_EXECUTOR, 1024, 3) |
| 131 | end do |
| 132 | deallocate(token_refs) |
| 133 | print *, " Released all token buffers" |
| 134 | |
| 135 | ! Test 5: Heredoc content buffer |
| 136 | print *, "" |
| 137 | print *, "Test 5: Testing heredoc content buffer..." |
| 138 | |
| 139 | heredoc_ref = pool_get_string(4096) ! 4KB for heredoc content |
| 140 | call dashboard_track_allocation(MOD_EXECUTOR, 4096, 4) |
| 141 | |
| 142 | ! Simulate heredoc content |
| 143 | call pool_copy_to_ref(heredoc_ref, & |
| 144 | "Line 1 of heredoc" // new_line('a') // & |
| 145 | "Line 2 of heredoc" // new_line('a') // & |
| 146 | "Line 3 of heredoc" // new_line('a') // & |
| 147 | "EOF") |
| 148 | |
| 149 | str_ptr => heredoc_ref%data |
| 150 | if (associated(str_ptr)) then |
| 151 | print *, " Heredoc buffer (4KB) allocated" |
| 152 | print *, " First line:", str_ptr(1:17) |
| 153 | print *, " PASSED: Heredoc buffer working" |
| 154 | end if |
| 155 | |
| 156 | call pool_release_string(heredoc_ref) |
| 157 | call dashboard_track_deallocation(MOD_EXECUTOR, 4096, 4) |
| 158 | |
| 159 | ! Test 6: Stress test - rapid command executions |
| 160 | print *, "" |
| 161 | print *, "Test 6: Stress testing with 1000 command execution cycles..." |
| 162 | do i = 1, 1000 |
| 163 | ! Simulate typical executor allocation pattern |
| 164 | buffer_ref = pool_get_string(4096) ! Command buffer |
| 165 | output_ref = pool_get_string(8192) ! Output buffer |
| 166 | |
| 167 | call dashboard_track_allocation(MOD_EXECUTOR, 4096, 4) |
| 168 | call dashboard_track_allocation(MOD_EXECUTOR, 8192, 5) |
| 169 | |
| 170 | ! Simulate some work |
| 171 | call pool_copy_to_ref(buffer_ref, "command") |
| 172 | call pool_copy_to_ref(output_ref, "output") |
| 173 | |
| 174 | ! Release |
| 175 | call pool_release_string(buffer_ref) |
| 176 | call pool_release_string(output_ref) |
| 177 | |
| 178 | call dashboard_track_deallocation(MOD_EXECUTOR, 4096, 4) |
| 179 | call dashboard_track_deallocation(MOD_EXECUTOR, 8192, 5) |
| 180 | end do |
| 181 | print *, " Completed 1000 execution cycles" |
| 182 | |
| 183 | ! Test 7: Check for memory leaks |
| 184 | print *, "" |
| 185 | print *, "Test 7: Checking for memory leaks..." |
| 186 | call pool_statistics(total_allocs, total_deallocs, current_strings, peak_strings, hit_rate) |
| 187 | |
| 188 | print *, " Total allocations:", total_allocs |
| 189 | print *, " Total deallocations:", total_deallocs |
| 190 | print *, " Current strings:", current_strings |
| 191 | print *, " Peak strings:", peak_strings |
| 192 | print *, " Cache hit rate:", int(hit_rate * 100), "%" |
| 193 | |
| 194 | if (current_strings == 0) then |
| 195 | print *, " PASSED: No memory leaks" |
| 196 | else |
| 197 | print *, " FAILED: Memory leak -", current_strings, "strings still allocated" |
| 198 | test_passed = .false. |
| 199 | end if |
| 200 | |
| 201 | ! Display dashboard |
| 202 | print *, "" |
| 203 | print *, "=== Executor Module Statistics ===" |
| 204 | call dashboard_display(detailed=.false.) |
| 205 | |
| 206 | ! Export statistics |
| 207 | call dashboard_export_csv("executor_pooling_test.csv") |
| 208 | print *, "" |
| 209 | print *, "Statistics exported to executor_pooling_test.csv" |
| 210 | |
| 211 | ! Clean up |
| 212 | call dashboard_cleanup() |
| 213 | call pool_cleanup() |
| 214 | |
| 215 | ! Summary |
| 216 | print *, "" |
| 217 | print *, "=== Test Summary ===" |
| 218 | if (test_passed .and. current_strings == 0) then |
| 219 | print *, "ALL TESTS PASSED" |
| 220 | print *, "" |
| 221 | print *, "Executor pooling integration verified:" |
| 222 | print *, " - Large output buffers (16KB) working" |
| 223 | print *, " - Command reconstruction buffers (4KB) working" |
| 224 | print *, " - Pipeline data buffers (8KB) working" |
| 225 | print *, " - Token expansion buffers (1KB) working" |
| 226 | print *, " - Heredoc buffers (4KB) working" |
| 227 | print *, " - No memory leaks detected" |
| 228 | print *, " - Dashboard tracking successful" |
| 229 | print *, " - Cache hit rate:", int(hit_rate * 100), "%" |
| 230 | print *, "" |
| 231 | print *, "Ready to integrate into production executor module!" |
| 232 | else |
| 233 | print *, "SOME TESTS FAILED" |
| 234 | if (current_strings > 0) then |
| 235 | print *, " Memory leak:", current_strings, "strings not released" |
| 236 | end if |
| 237 | end if |
| 238 | |
| 239 | end program test_executor_simple |