Files
mercury/tests/hard_coded/thread_barrier_test.m
Zoltan Somogyi 2bd7c5ee3e Rename X's aux modules as X_helper_N in hard_coded.
tests/hard_coded/*.m:
    Rename modules as mentioned above.

    In a few cases, where the main module's name itself had a suffix,
    such as "_mod_a" or "_main", remove that suffix. This entails
    renaming the .exp file as well. (In some cases, this meant that
    the name of a helper module was "taken over" by the main module
    of the test case.)

    Update all references to the moved modules.

    General updates to programming style, such as

    - replacing DCG notation with state var notation
    - replacing (C->T;E) with (if C then T else E)
    - moving pred/func declarations to just before their code
    - replacing io.write/io.nl sequences with io.write_line
    - replacing io.print/io.nl sequences with io.print_line
    - fixing too-long lines
    - fixing grammar errors in comments

tests/hard_coded/Mmakefile:
tests/hard_coded/Mercury.options:
    Update all references to the moved modules.

    Enable the constant_prop_int test case. The fact that it wasn't enabled
    before is probably an accident. (When constant_prop_int.m was created,
    the test case was added to a list in the Mmakefile, but that list
    was later removed due to never being referenced.)

tests/hard_coded/constant_prop_int.{m,exp}:
    Delete the calls to shift operations with negative shift amounts,
    since we have added a compile-time error for these since the test
    was originally created.
2023-06-16 08:33:22 +02:00

166 lines
6.3 KiB
Mathematica

%---------------------------------------------------------------------------%
% vim: ts=4 sw=4 et ft=mercury
%---------------------------------------------------------------------------%
% File: thread_barrier_test.m
% Main author: Sebastian Godelet <sebastian.godelet+github@gmail.com>
% Created on: Tue Apr 8 15:54:57 CEST 2014
%---------------------------------------------------------------------------%
:- module thread_barrier_test.
:- interface.
:- import_module io.
:- pred main(io::di, io::uo) is cc_multi.
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
:- implementation.
:- import_module int.
:- import_module integer.
:- import_module list.
:- import_module require.
:- import_module string.
:- import_module thread.
:- import_module thread.barrier.
:- import_module thread.mvar.
:- import_module thread_barrier_test_helper_1.
%---------------------------------------------------------------------------%
:- func fib(integer) = integer.
fib(N) = Fib :-
( if N < integer(2) then
Fib = integer(1)
else
Fib = fib(N - integer(1)) + fib(N - integer(2))
).
:- pred test_spawn_and_wait(int::in, io::di, io::uo) is cc_multi.
test_spawn_and_wait(ThreadCount, !IO) :-
init_all_thread_output(AllThreadOutput, !IO),
init_thread_output(AllThreadOutput, 0, Output, !IO),
t_write_string(Output, format("-- testing spawning with %d threads",
[i(ThreadCount)]), !IO),
barrier.init(ThreadCount + 1, Barrier, !IO),
list.foldl((pred(Thread::in, !.IO::di, !:IO::uo) is cc_multi :-
t_write_string(Output, format("spawning thread #%d", [i(Thread)]),
!IO),
spawn(test_spawn_and_wait_thread(Thread, AllThreadOutput, Barrier),
!IO)
), 1 .. ThreadCount, !IO),
barrier.wait(Barrier, !IO),
t_write_string(Output, "-- test finished", !IO),
close_thread_output(Output, !IO),
write_all_thread_output(AllThreadOutput, !IO).
:- pragma no_determinism_warning(test_spawn_and_wait_thread/5).
:- pred test_spawn_and_wait_thread(int::in, all_threads_output::in,
barrier::in, io::di, io::uo) is cc_multi.
test_spawn_and_wait_thread(Thread, AllThreadOutput, Barrier, !IO) :-
init_thread_output(AllThreadOutput, Thread, Output, !IO),
t_write_string(Output, format("thread %d starting", [i(Thread)]), !IO),
N = 5 + Thread * 5,
t_write_string(Output, format("fib(%d) = %s",
[i(N), s(integer.to_string(fib(integer(N))))]), !IO),
barrier.wait(Barrier, !IO),
t_write_string(Output, format("thread %d exiting", [i(Thread)]), !IO),
close_thread_output(Output, !IO).
% This state allows us to determine if certain actions have already
% taken place. This lets us show that some things happen before/after
% release is called on the barrier.
%
:- type state
---> state_before_release
; state_after_release.
:- pred test_release(int::in, int::in, io::di, io::uo) is cc_multi.
test_release(AbortAt, ThreadCount, !IO) :-
init_all_thread_output(AllThreadOutput, !IO),
init_thread_output(AllThreadOutput, 0, Output, !IO),
t_write_string(Output, format("-- testing barrier release at %d of %d",
[i(AbortAt), i(ThreadCount)]), !IO),
barrier.init(ThreadCount + 1, Barrier, !IO),
mvar.init(StateMvar, !IO),
mvar.put(StateMvar, state_before_release, !IO),
list.foldl(
( pred(Thread::in, !.IO::di, !:IO::uo) is cc_multi :-
t_write_string(Output, format("spawning thread #%d", [i(Thread)]),
!IO),
spawn(
release_thread(AllThreadOutput, Thread, AbortAt, Barrier,
StateMvar),
!IO)
), 1 .. ThreadCount, !IO),
% There is no guarantee that we will reach this point before the AbortAt
% thread releases the barrier, so don't log the state as expected.
t_write_string(Output, "waiting", !IO),
barrier.wait(Barrier, !IO),
log_with_state(Output, StateMvar, "done waiting, test finished", !IO),
close_thread_output(Output, !IO),
write_all_thread_output(AllThreadOutput, !IO).
:- pragma no_determinism_warning(release_thread/7).
:- pred release_thread(all_threads_output::in, int::in, int::in, barrier::in,
mvar(thread_barrier_test.state)::in, io::di, io::uo) is cc_multi.
release_thread(AllOutput, Thread, AbortAt, Barrier, StateMvar, !IO) :-
init_thread_output(AllOutput, Thread, Output, !IO),
t_write_string(Output, "thread starting", !IO),
N = 5 + Thread * 5,
t_write_string(Output, format("fib(%d) = %s",
[i(N), s(integer.to_string(fib(integer(N))))]), !IO),
( if Thread = AbortAt then
t_write_string(Output, "releasing barrier", !IO),
mvar.take(StateMvar, _, !IO),
barrier.release(Barrier, !IO),
mvar.put(StateMvar, state_after_release, !IO),
t_write_string(Output, "released.", !IO)
else
% There is no guarantee that we will reach this point before the
% AbortAt thread releases the barrier, so don't log the state as
% expected.
t_write_string(Output, "waiting", !IO),
barrier.wait(Barrier, !IO),
log_with_state(Output, StateMvar, "done waiting", !IO)
),
close_thread_output(Output, !IO).
:- pred log_with_state(thread_output::in,
mvar(thread_barrier_test.state)::in, string::in, io::di, io::uo) is det.
log_with_state(Output, StateMvar, String, !IO) :-
mvar.take(StateMvar, State, !IO),
(
State = state_before_release,
StateStr = "before release"
;
State = state_after_release,
StateStr = "after release"
),
Message = format("%s:\t%s", [s(String), s(StateStr)]),
t_write_string(Output, Message, !IO),
mvar.put(StateMvar, State, !IO).
main(!IO) :-
( if thread.can_spawn then
io.write_string("Test spawn and wait\n", !IO),
test_spawn_and_wait(5, !IO),
io.write_string("\nTest release\n", !IO),
test_release(3, 5, !IO)
else
unexpected($file, $pred, $grade ++ " does not support thread spawning")
).
%---------------------------------------------------------------------------%
% -*- Mode: Mercury; column: 80; indent-tabs-mode: nil; tabs-width: 4 -*-
%---------------------------------------------------------------------------%