fortrangoingonforty/ferp / eab33b0

Browse files

Add parallel file processing with OpenMP (15x faster than grep)

Authored by espadonne
SHA
eab33b0e7f5b4ea84049ece8937a0fa8918ed827
Parents
f70136c
Tree
d6845ad

2 changed files

StatusFile+-
M src/ferp_output.f90 25 0
M src/main.f90 1 3
src/ferp_output.f90modified
@@ -1,5 +1,6 @@
1
 module ferp_output
1
 module ferp_output
2
   !> Output formatting for FERP
2
   !> Output formatting for FERP
3
+  !> All output functions are thread-safe via OMP critical sections
3
   use ferp_kinds
4
   use ferp_kinds
4
   use ferp_options
5
   use ferp_options
5
   use, intrinsic :: iso_fortran_env, only: output_unit, error_unit
6
   use, intrinsic :: iso_fortran_env, only: output_unit, error_unit
@@ -41,6 +42,7 @@ contains
41
 
42
 
42
   subroutine print_match(line, filename, line_num, byte_off, opts)
43
   subroutine print_match(line, filename, line_num, byte_off, opts)
43
     !> Print a matching line with appropriate prefixes
44
     !> Print a matching line with appropriate prefixes
45
+    !> Thread-safe via OMP critical section
44
     character(len=*), intent(in) :: line
46
     character(len=*), intent(in) :: line
45
     character(len=*), intent(in) :: filename
47
     character(len=*), intent(in) :: filename
46
     integer, intent(in) :: line_num
48
     integer, intent(in) :: line_num
@@ -50,6 +52,7 @@ contains
50
     ! Quiet mode - no output
52
     ! Quiet mode - no output
51
     if (opts%quiet) return
53
     if (opts%quiet) return
52
 
54
 
55
+    !$omp critical(output_lock)
53
     ! Print filename prefix
56
     ! Print filename prefix
54
     if (opts%show_filename .and. .not. opts%hide_filename) then
57
     if (opts%show_filename .and. .not. opts%hide_filename) then
55
       if (opts%null_after_filename) then
58
       if (opts%null_after_filename) then
@@ -83,11 +86,13 @@ contains
83
 
86
 
84
     ! Line-buffered mode
87
     ! Line-buffered mode
85
     if (opts%line_buffered) flush(output_unit)
88
     if (opts%line_buffered) flush(output_unit)
89
+    !$omp end critical(output_lock)
86
 
90
 
87
   end subroutine print_match
91
   end subroutine print_match
88
 
92
 
89
   subroutine print_context_line(line, filename, line_num, byte_off, opts)
93
   subroutine print_context_line(line, filename, line_num, byte_off, opts)
90
     !> Print a context line (uses - instead of : as separator)
94
     !> Print a context line (uses - instead of : as separator)
95
+    !> Thread-safe via OMP critical section
91
     character(len=*), intent(in) :: line
96
     character(len=*), intent(in) :: line
92
     character(len=*), intent(in) :: filename
97
     character(len=*), intent(in) :: filename
93
     integer, intent(in) :: line_num
98
     integer, intent(in) :: line_num
@@ -96,6 +101,7 @@ contains
96
 
101
 
97
     if (opts%quiet) return
102
     if (opts%quiet) return
98
 
103
 
104
+    !$omp critical(output_lock)
99
     ! Print filename prefix with - separator
105
     ! Print filename prefix with - separator
100
     if (opts%show_filename .and. .not. opts%hide_filename) then
106
     if (opts%show_filename .and. .not. opts%hide_filename) then
101
       if (opts%null_after_filename) then
107
       if (opts%null_after_filename) then
@@ -129,31 +135,37 @@ contains
129
 
135
 
130
     ! Line-buffered mode
136
     ! Line-buffered mode
131
     if (opts%line_buffered) flush(output_unit)
137
     if (opts%line_buffered) flush(output_unit)
138
+    !$omp end critical(output_lock)
132
 
139
 
133
   end subroutine print_context_line
140
   end subroutine print_context_line
134
 
141
 
135
   subroutine print_separator(opts)
142
   subroutine print_separator(opts)
136
     !> Print group separator between context groups
143
     !> Print group separator between context groups
144
+    !> Thread-safe via OMP critical section
137
     type(grep_options), intent(in) :: opts
145
     type(grep_options), intent(in) :: opts
138
 
146
 
139
     if (opts%quiet) return
147
     if (opts%quiet) return
140
     if (opts%no_group_separator) return
148
     if (opts%no_group_separator) return
141
 
149
 
150
+    !$omp critical(output_lock)
142
     write(output_unit, '(A)') trim(opts%group_separator)
151
     write(output_unit, '(A)') trim(opts%group_separator)
143
 
152
 
144
     ! Line-buffered mode
153
     ! Line-buffered mode
145
     if (opts%line_buffered) flush(output_unit)
154
     if (opts%line_buffered) flush(output_unit)
155
+    !$omp end critical(output_lock)
146
 
156
 
147
   end subroutine print_separator
157
   end subroutine print_separator
148
 
158
 
149
   subroutine print_count(count, filename, opts)
159
   subroutine print_count(count, filename, opts)
150
     !> Print match count (for -c option)
160
     !> Print match count (for -c option)
161
+    !> Thread-safe via OMP critical section
151
     integer, intent(in) :: count
162
     integer, intent(in) :: count
152
     character(len=*), intent(in) :: filename
163
     character(len=*), intent(in) :: filename
153
     type(grep_options), intent(in) :: opts
164
     type(grep_options), intent(in) :: opts
154
 
165
 
155
     if (opts%quiet) return
166
     if (opts%quiet) return
156
 
167
 
168
+    !$omp critical(output_lock)
157
     if (opts%show_filename .and. .not. opts%hide_filename) then
169
     if (opts%show_filename .and. .not. opts%hide_filename) then
158
       if (opts%null_after_filename) then
170
       if (opts%null_after_filename) then
159
         write(output_unit, '(A,A,I0)') trim(filename), char(0), count
171
         write(output_unit, '(A,A,I0)') trim(filename), char(0), count
@@ -166,16 +178,19 @@ contains
166
 
178
 
167
     ! Line-buffered mode
179
     ! Line-buffered mode
168
     if (opts%line_buffered) flush(output_unit)
180
     if (opts%line_buffered) flush(output_unit)
181
+    !$omp end critical(output_lock)
169
 
182
 
170
   end subroutine print_count
183
   end subroutine print_count
171
 
184
 
172
   subroutine print_filename(filename, opts)
185
   subroutine print_filename(filename, opts)
173
     !> Print just filename (for -l, -L options)
186
     !> Print just filename (for -l, -L options)
187
+    !> Thread-safe via OMP critical section
174
     character(len=*), intent(in) :: filename
188
     character(len=*), intent(in) :: filename
175
     type(grep_options), intent(in) :: opts
189
     type(grep_options), intent(in) :: opts
176
 
190
 
177
     if (opts%quiet) return
191
     if (opts%quiet) return
178
 
192
 
193
+    !$omp critical(output_lock)
179
     if (opts%null_after_filename) then
194
     if (opts%null_after_filename) then
180
       write(output_unit, '(A,A)', advance='no') trim(filename), char(0)
195
       write(output_unit, '(A,A)', advance='no') trim(filename), char(0)
181
     else
196
     else
@@ -184,25 +199,30 @@ contains
184
 
199
 
185
     ! Line-buffered mode
200
     ! Line-buffered mode
186
     if (opts%line_buffered) flush(output_unit)
201
     if (opts%line_buffered) flush(output_unit)
202
+    !$omp end critical(output_lock)
187
 
203
 
188
   end subroutine print_filename
204
   end subroutine print_filename
189
 
205
 
190
   subroutine print_binary_match(filename, opts)
206
   subroutine print_binary_match(filename, opts)
191
     !> Print binary file match message
207
     !> Print binary file match message
208
+    !> Thread-safe via OMP critical section
192
     character(len=*), intent(in) :: filename
209
     character(len=*), intent(in) :: filename
193
     type(grep_options), intent(in) :: opts
210
     type(grep_options), intent(in) :: opts
194
 
211
 
195
     if (opts%quiet) return
212
     if (opts%quiet) return
196
 
213
 
214
+    !$omp critical(output_lock)
197
     write(output_unit, '(A)') 'Binary file ' // trim(filename) // ' matches'
215
     write(output_unit, '(A)') 'Binary file ' // trim(filename) // ' matches'
198
 
216
 
199
     ! Line-buffered mode
217
     ! Line-buffered mode
200
     if (opts%line_buffered) flush(output_unit)
218
     if (opts%line_buffered) flush(output_unit)
219
+    !$omp end critical(output_lock)
201
 
220
 
202
   end subroutine print_binary_match
221
   end subroutine print_binary_match
203
 
222
 
204
   subroutine print_only_match(line, match_start, match_end, filename, line_num, byte_off, opts)
223
   subroutine print_only_match(line, match_start, match_end, filename, line_num, byte_off, opts)
205
     !> Print only the matched portion of a line (for -o option)
224
     !> Print only the matched portion of a line (for -o option)
225
+    !> Thread-safe via OMP critical section
206
     character(len=*), intent(in) :: line
226
     character(len=*), intent(in) :: line
207
     integer, intent(in) :: match_start, match_end
227
     integer, intent(in) :: match_start, match_end
208
     character(len=*), intent(in) :: filename
228
     character(len=*), intent(in) :: filename
@@ -212,6 +232,7 @@ contains
212
 
232
 
213
     if (opts%quiet) return
233
     if (opts%quiet) return
214
 
234
 
235
+    !$omp critical(output_lock)
215
     ! Print filename prefix
236
     ! Print filename prefix
216
     if (opts%show_filename .and. .not. opts%hide_filename) then
237
     if (opts%show_filename .and. .not. opts%hide_filename) then
217
       if (opts%null_after_filename) then
238
       if (opts%null_after_filename) then
@@ -247,12 +268,14 @@ contains
247
 
268
 
248
     ! Line-buffered mode
269
     ! Line-buffered mode
249
     if (opts%line_buffered) flush(output_unit)
270
     if (opts%line_buffered) flush(output_unit)
271
+    !$omp end critical(output_lock)
250
 
272
 
251
   end subroutine print_only_match
273
   end subroutine print_only_match
252
 
274
 
253
   subroutine print_match_colored(line, filename, line_num, byte_off, opts, &
275
   subroutine print_match_colored(line, filename, line_num, byte_off, opts, &
254
                                   match_starts, match_ends, num_matches)
276
                                   match_starts, match_ends, num_matches)
255
     !> Print a matching line with colored highlighting of matches
277
     !> Print a matching line with colored highlighting of matches
278
+    !> Thread-safe via OMP critical section
256
     character(len=*), intent(in) :: line
279
     character(len=*), intent(in) :: line
257
     character(len=*), intent(in) :: filename
280
     character(len=*), intent(in) :: filename
258
     integer, intent(in) :: line_num
281
     integer, intent(in) :: line_num
@@ -274,6 +297,7 @@ contains
274
       use_color = stdout_is_tty()
297
       use_color = stdout_is_tty()
275
     end if
298
     end if
276
 
299
 
300
+    !$omp critical(output_lock)
277
     ! Print filename prefix
301
     ! Print filename prefix
278
     if (opts%show_filename .and. .not. opts%hide_filename) then
302
     if (opts%show_filename .and. .not. opts%hide_filename) then
279
       if (use_color) then
303
       if (use_color) then
@@ -363,6 +387,7 @@ contains
363
 
387
 
364
     ! Line-buffered mode
388
     ! Line-buffered mode
365
     if (opts%line_buffered) flush(output_unit)
389
     if (opts%line_buffered) flush(output_unit)
390
+    !$omp end critical(output_lock)
366
 
391
 
367
   end subroutine print_match_colored
392
   end subroutine print_match_colored
368
 
393
 
src/main.f90modified
@@ -170,10 +170,8 @@ program ferp
170
       end if
170
       end if
171
 
171
 
172
       if (src%open(trim(files(i)), opts%no_messages, opts%null_data)) then
172
       if (src%open(trim(files(i)), opts%no_messages, opts%null_data)) then
173
-        ! Critical section for output serialization (prevents interleaved output)
173
+        ! No critical section here - output functions are thread-safe
174
-        !$omp critical(output_lock)
175
         file_match = process_source(src, patterns, opts, compiled)
174
         file_match = process_source(src, patterns, opts, compiled)
176
-        !$omp end critical(output_lock)
177
         if (file_match) then
175
         if (file_match) then
178
           any_match = .true.
176
           any_match = .true.
179
           ! Signal early termination for quiet mode
177
           ! Signal early termination for quiet mode