2011-06-14 Antoniu Pop <antoniu.pop@gmail.com>
libgomp/ gcc/ Revert and correct some of the changes from last commit. git-svn-id: svn://gcc.gnu.org/svn/gcc/branches/omp-stream@175027 138bc75d-0d04-0410-961f-82ee72b054a4
This commit is contained in:
parent
48de164d08
commit
2a002cb87f
|
@ -219,6 +219,7 @@ DEF_FUNCTION_TYPE_1 (BT_FN_ULONGLONG_ULONGLONG, BT_ULONGLONG, BT_ULONGLONG)
|
|||
DEF_FUNCTION_TYPE_1 (BT_FN_UINT32_UINT32, BT_UINT32, BT_UINT32)
|
||||
DEF_FUNCTION_TYPE_1 (BT_FN_UINT64_UINT64, BT_UINT64, BT_UINT64)
|
||||
DEF_FUNCTION_TYPE_1 (BT_FN_PTR_INT, BT_PTR, BT_INT)
|
||||
DEF_FUNCTION_TYPE_1 (BT_FN_BOOL_PTR, BT_BOOL, BT_PTR)
|
||||
|
||||
DEF_POINTER_TYPE (BT_PTR_FN_VOID_PTR, BT_FN_VOID_PTR)
|
||||
|
||||
|
@ -318,6 +319,9 @@ DEF_FUNCTION_TYPE_2 (BT_FN_ULL_PTR_ULL,
|
|||
BT_ULONGLONG, BT_PTR, BT_ULONGLONG)
|
||||
DEF_FUNCTION_TYPE_2 (BT_FN_VOID_PTR_ULL,
|
||||
BT_VOID, BT_PTR, BT_ULONGLONG)
|
||||
DEF_FUNCTION_TYPE_2 (BT_FN_PTR_PTR_PTR,
|
||||
BT_PTR, BT_PTR, BT_PTR)
|
||||
DEF_FUNCTION_TYPE_2 (BT_FN_PTR_PTR_ULL, BT_PTR, BT_PTR, BT_ULONGLONG)
|
||||
|
||||
DEF_POINTER_TYPE (BT_PTR_FN_VOID_PTR_PTR, BT_FN_VOID_PTR_PTR)
|
||||
|
||||
|
@ -388,6 +392,10 @@ DEF_FUNCTION_TYPE_3 (BT_FN_PTR_CONST_PTR_INT_SIZE, BT_PTR,
|
|||
BT_CONST_PTR, BT_INT, BT_SIZE)
|
||||
DEF_FUNCTION_TYPE_3 (BT_FN_PTR_SIZE_ULL_PTR,
|
||||
BT_PTR, BT_SIZE, BT_ULONGLONG, BT_PTR)
|
||||
DEF_FUNCTION_TYPE_3 (BT_FN_ULL_PTR_ULL_ULL,
|
||||
BT_ULONGLONG, BT_PTR, BT_ULONGLONG, BT_ULONGLONG)
|
||||
DEF_FUNCTION_TYPE_3 (BT_FN_PTR_PTR_ULL_ULL,
|
||||
BT_PTR, BT_PTR, BT_ULONGLONG, BT_ULONGLONG)
|
||||
|
||||
DEF_FUNCTION_TYPE_4 (BT_FN_SIZE_CONST_PTR_SIZE_SIZE_FILEPTR,
|
||||
BT_SIZE, BT_CONST_PTR, BT_SIZE, BT_SIZE, BT_FILEPTR)
|
||||
|
@ -441,6 +449,9 @@ DEF_FUNCTION_TYPE_7 (BT_FN_BOOL_BOOL_ULL_ULL_ULL_ULL_ULLPTR_ULLPTR,
|
|||
BT_BOOL, BT_BOOL, BT_ULONGLONG, BT_ULONGLONG,
|
||||
BT_ULONGLONG, BT_ULONGLONG,
|
||||
BT_PTR_ULONGLONG, BT_PTR_ULONGLONG)
|
||||
DEF_FUNCTION_TYPE_7 (BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_LONG_BOOL,
|
||||
BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR,
|
||||
BT_PTR_FN_VOID_PTR_PTR, BT_LONG, BT_LONG, BT_LONG, BT_BOOL)
|
||||
|
||||
DEF_FUNCTION_TYPE_VAR_0 (BT_FN_VOID_VAR, BT_VOID)
|
||||
DEF_FUNCTION_TYPE_VAR_0 (BT_FN_INT_VAR, BT_INT)
|
||||
|
|
|
@ -7364,7 +7364,6 @@ c_parser_omp_stream_clause (c_parser *parser,
|
|||
OMP_CLAUSE_STREAM_ID (omp_clause) = stream_id;
|
||||
OMP_CLAUSE_STREAM_SUB (omp_clause) = stream_idx;
|
||||
|
||||
|
||||
if (c_parser_next_token_is (parser, CPP_LSHIFT)
|
||||
|| c_parser_next_token_is (parser, CPP_RSHIFT))
|
||||
{
|
||||
|
@ -8768,7 +8767,8 @@ c_parser_omp_single (location_t loc, c_parser *parser)
|
|||
| (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
|
||||
| (1u << PRAGMA_OMP_CLAUSE_SHARED)) \
|
||||
| (1u << PRAGMA_OMP_CLAUSE_INPUT) \
|
||||
| (1u << PRAGMA_OMP_CLAUSE_OUTPUT)
|
||||
| (1u << PRAGMA_OMP_CLAUSE_OUTPUT) \
|
||||
| (1u << PRAGMA_OMP_CLAUSE_NUM_THREADS)
|
||||
|
||||
static tree
|
||||
c_parser_omp_task (location_t loc, c_parser *parser)
|
||||
|
|
|
@ -10231,6 +10231,7 @@ c_finish_omp_clauses (tree clauses)
|
|||
case OMP_CLAUSE_FIRSTPRIVATE:
|
||||
name = "firstprivate";
|
||||
t = OMP_CLAUSE_DECL (c);
|
||||
OMP_CLAUSE_VIEW_VAR_KIND (c) = OMP_CLAUSE_VIEW_VAR_UNSPECIFIED;
|
||||
need_complete = true;
|
||||
need_implicitly_determined = true;
|
||||
if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL)
|
||||
|
|
137
gcc/gimplify.c
137
gcc/gimplify.c
|
@ -5724,6 +5724,9 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p,
|
|||
goto do_add;
|
||||
case OMP_CLAUSE_FIRSTPRIVATE:
|
||||
flags = GOVD_FIRSTPRIVATE | GOVD_EXPLICIT;
|
||||
if (OMP_CLAUSE_VIEW_VAR_KIND (c) != OMP_CLAUSE_VIEW_VAR_UNSPECIFIED)
|
||||
flags |= GOVD_SEEN;
|
||||
|
||||
check_non_private = "firstprivate";
|
||||
goto do_add;
|
||||
case OMP_CLAUSE_LASTPRIVATE:
|
||||
|
@ -5737,9 +5740,38 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p,
|
|||
case OMP_CLAUSE_INPUT:
|
||||
case OMP_CLAUSE_OUTPUT:
|
||||
{
|
||||
#if 0
|
||||
tree view = OMP_CLAUSE_VIEW_ID (c);
|
||||
if(view != NULL_TREE)
|
||||
omp_add_variable (ctx, view, GOVD_LOCAL | GOVD_SEEN);
|
||||
{
|
||||
//omp_add_variable (ctx, view, GOVD_LOCAL | GOVD_SEEN);
|
||||
if (DECL_HAS_VALUE_EXPR_P (view))
|
||||
{
|
||||
tree new_decl = DECL_VALUE_EXPR (view);
|
||||
gcc_assert (TREE_CODE (new_decl) == INDIRECT_REF);
|
||||
/* if (TREE_CODE (new_decl) == INDIRECT_REF)*/
|
||||
new_decl = TREE_OPERAND (new_decl, 0);
|
||||
OMP_CLAUSE_VIEW_ID (c) = new_decl;
|
||||
}
|
||||
}
|
||||
tree burst = OMP_CLAUSE_BURST_SIZE (c);
|
||||
if (burst != NULL_TREE && DECL_P (burst))
|
||||
{
|
||||
omp_add_variable (ctx, burst, GOVD_FIRSTPRIVATE | GOVD_EXPLICIT | GOVD_SEEN);
|
||||
if (outer_ctx)
|
||||
omp_notice_variable (outer_ctx, decl, true);
|
||||
|
||||
gcc_assert (!DECL_HAS_VALUE_EXPR_P (burst));
|
||||
if (0)
|
||||
{
|
||||
tree new_decl = DECL_VALUE_EXPR (burst);
|
||||
gcc_assert (TREE_CODE (new_decl) == INDIRECT_REF);
|
||||
/* if (TREE_CODE (new_decl) == INDIRECT_REF)*/
|
||||
new_decl = TREE_OPERAND (new_decl, 0);
|
||||
OMP_CLAUSE_BURST_SIZE (c) = new_decl;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
flags = GOVD_PRIVATE | GOVD_EXPLICIT;
|
||||
goto do_add;
|
||||
|
@ -6046,9 +6078,112 @@ static void
|
|||
gimplify_omp_task (tree *expr_p, gimple_seq *pre_p)
|
||||
{
|
||||
tree expr = *expr_p;
|
||||
tree clauses = OMP_TASK_CLAUSES (expr);
|
||||
gimple g;
|
||||
gimple_seq body = NULL;
|
||||
struct gimplify_ctx gctx;
|
||||
bool is_streaming = false;
|
||||
|
||||
for (; clauses ; clauses = OMP_CLAUSE_CHAIN (clauses))
|
||||
if (OMP_CLAUSE_CODE (clauses) == OMP_CLAUSE_INPUT ||
|
||||
OMP_CLAUSE_CODE (clauses) == OMP_CLAUSE_OUTPUT)
|
||||
{
|
||||
is_streaming = true;
|
||||
break;
|
||||
}
|
||||
|
||||
/* We promote firstprivate clauses on streaming tasks to streams
|
||||
from the enclosing context. */
|
||||
if (is_streaming)
|
||||
{
|
||||
tree *clauses_p = &OMP_TASK_CLAUSES (expr);
|
||||
for (; *clauses_p ; clauses_p = &OMP_CLAUSE_CHAIN (*clauses_p))
|
||||
if (OMP_CLAUSE_CODE (*clauses_p) == OMP_CLAUSE_FIRSTPRIVATE)
|
||||
{
|
||||
tree c = build_omp_clause (input_location, OMP_CLAUSE_INPUT);
|
||||
OMP_CLAUSE_DECL (c) = OMP_CLAUSE_DECL (*clauses_p);
|
||||
/* Store the original decl, but this will be replaced by
|
||||
the firstprivate view's decl. */
|
||||
OMP_CLAUSE_FIRSTPRIVATE_INPUT (c) = OMP_CLAUSE_DECL (*clauses_p);
|
||||
OMP_CLAUSE_CHAIN (c) = OMP_CLAUSE_CHAIN (*clauses_p);
|
||||
*clauses_p = c;
|
||||
lang_hooks.decls.omp_finish_clause (c);
|
||||
}
|
||||
else if (OMP_CLAUSE_CODE (*clauses_p) == OMP_CLAUSE_INPUT
|
||||
|| OMP_CLAUSE_CODE (*clauses_p) == OMP_CLAUSE_OUTPUT)
|
||||
{
|
||||
tree view = OMP_CLAUSE_VIEW_ID (*clauses_p);
|
||||
tree burst = OMP_CLAUSE_BURST_SIZE (*clauses_p);
|
||||
tree *size = &OMP_CLAUSE_VIEW_SIZE (*clauses_p);
|
||||
|
||||
/* We need to add firstprivate clauses for the burst
|
||||
variables used in these clauses to ensure we don't
|
||||
loose track of them. */
|
||||
if (view != NULL_TREE)
|
||||
{
|
||||
tree c = build_omp_clause (input_location, OMP_CLAUSE_FIRSTPRIVATE);
|
||||
|
||||
OMP_CLAUSE_DECL (c) = view;
|
||||
OMP_CLAUSE_CHAIN (c) = OMP_CLAUSE_CHAIN (*clauses_p);
|
||||
OMP_CLAUSE_CHAIN (*clauses_p) = c;
|
||||
|
||||
/* Store the replacement pointer's decl, if there is
|
||||
one, instead of the original view id. */
|
||||
if (DECL_HAS_VALUE_EXPR_P (view))
|
||||
{
|
||||
tree new_decl = DECL_VALUE_EXPR (view);
|
||||
gcc_assert (TREE_CODE (new_decl) == INDIRECT_REF);
|
||||
new_decl = TREE_OPERAND (new_decl, 0);
|
||||
OMP_CLAUSE_VIEW_ID (*clauses_p) = new_decl;
|
||||
}
|
||||
|
||||
clauses_p = &OMP_CLAUSE_CHAIN (*clauses_p);
|
||||
OMP_CLAUSE_VIEW_VAR_KIND (c) = OMP_CLAUSE_VIEW_VAR_DISCARD;
|
||||
lang_hooks.decls.omp_finish_clause (c);
|
||||
|
||||
*size = TYPE_SIZE_UNIT (TREE_TYPE (view));
|
||||
}
|
||||
else
|
||||
continue;
|
||||
|
||||
if (burst != NULL_TREE && DECL_P (burst))
|
||||
{
|
||||
/* Check if there already is a clause for this burst. */
|
||||
tree c_iter = OMP_TASK_CLAUSES (expr);
|
||||
bool add_firstprivate = true;
|
||||
|
||||
for (; c_iter; c_iter = OMP_CLAUSE_CHAIN (c_iter))
|
||||
if (OMP_CLAUSE_DECL (c_iter) == burst)
|
||||
{
|
||||
/* FIXME: check clause type, upgrade private to firstprivate. */
|
||||
add_firstprivate = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (add_firstprivate)
|
||||
{
|
||||
tree c = build_omp_clause (input_location, OMP_CLAUSE_FIRSTPRIVATE);
|
||||
OMP_CLAUSE_DECL (c) = burst;
|
||||
OMP_CLAUSE_CHAIN (c) = OMP_CLAUSE_CHAIN (*clauses_p);
|
||||
OMP_CLAUSE_CHAIN (*clauses_p) = c;
|
||||
clauses_p = &OMP_CLAUSE_CHAIN (*clauses_p);
|
||||
OMP_CLAUSE_VIEW_VAR_KIND (c) = OMP_CLAUSE_VIEW_VAR_KEEP;
|
||||
lang_hooks.decls.omp_finish_clause (c);
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
if (*size && DECL_P (*size))
|
||||
{
|
||||
tree c = build_omp_clause (input_location, OMP_CLAUSE_FIRSTPRIVATE);
|
||||
OMP_CLAUSE_DECL (c) = *size;
|
||||
OMP_CLAUSE_CHAIN (c) = OMP_CLAUSE_CHAIN (*clauses_p);
|
||||
OMP_CLAUSE_CHAIN (*clauses_p) = c;
|
||||
clauses_p = &OMP_CLAUSE_CHAIN (*clauses_p);
|
||||
lang_hooks.decls.omp_finish_clause (c);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
gimplify_scan_omp_clauses (&OMP_TASK_CLAUSES (expr), pre_p, ORT_TASK);
|
||||
|
||||
|
|
|
@ -209,16 +209,25 @@ DEF_GOMP_BUILTIN (BUILT_IN_GOMP_SINGLE_COPY_END, "GOMP_single_copy_end",
|
|||
|
||||
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_STREAM_CREATE_STREAM,
|
||||
"GOMP_stream_create_stream",
|
||||
BT_FN_PTR_SIZE_ULL_PTR, ATTR_NOTHROW_LIST)
|
||||
BT_FN_PTR_SIZE_SIZE, ATTR_NOTHROW_LIST)
|
||||
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_STREAM_CREATE_READ_VIEW,
|
||||
"GOMP_stream_create_read_view",
|
||||
BT_FN_PTR, ATTR_NOTHROW_LIST)
|
||||
BT_FN_PTR_SIZE_SIZE, ATTR_NOTHROW_LIST)
|
||||
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_STREAM_CREATE_WRITE_VIEW,
|
||||
"GOMP_stream_create_write_view",
|
||||
BT_FN_PTR, ATTR_NOTHROW_LIST)
|
||||
BT_FN_PTR_SIZE_SIZE, ATTR_NOTHROW_LIST)
|
||||
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_STREAM_CREATE_TASK,
|
||||
"GOMP_stream_create_task",
|
||||
BT_FN_PTR, ATTR_NOTHROW_LIST)
|
||||
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_STREAM_GET_TASK_ACTIVATION_COUNTER,
|
||||
"GOMP_stream_get_task_activation_counter",
|
||||
BT_FN_PTR_PTR, ATTR_NOTHROW_LIST)
|
||||
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_STREAM_SET_TASK_TERMINATION_FLAG,
|
||||
"GOMP_stream_set_task_termination_flag",
|
||||
BT_FN_VOID_PTR, ATTR_NOTHROW_LIST)
|
||||
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_STREAM_TASK_ADD_INSTANCE,
|
||||
"GOMP_stream_task_add_instance",
|
||||
BT_FN_VOID_PTR, ATTR_NOTHROW_LIST)
|
||||
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_STREAM_ADD_EXPECTED_VIEWS,
|
||||
"GOMP_stream_add_expected_views",
|
||||
BT_FN_VOID_PTR_INT_INT_INT, ATTR_NOTHROW_LIST)
|
||||
|
@ -228,10 +237,13 @@ DEF_GOMP_BUILTIN (BUILT_IN_GOMP_STREAM_CONNECT_VIEW,
|
|||
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_STREAM_WAIT_UNTIL_CONNECTED,
|
||||
"GOMP_stream_wait_until_connected",
|
||||
BT_FN_VOID_PTR, ATTR_NOTHROW_LIST)
|
||||
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_STREAM_UPDATE, "GOMP_stream_update",
|
||||
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_STREAM_GET_AVAILABLE_WORK,
|
||||
"GOMP_stream_get_available_work",
|
||||
BT_FN_ULL_PTR_ULL, ATTR_NOTHROW_LIST)
|
||||
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_STREAM_UPDATE, "GOMP_stream_update",
|
||||
BT_FN_PTR_PTR_ULL_ULL, ATTR_NOTHROW_LIST)
|
||||
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_STREAM_STALL, "GOMP_stream_stall",
|
||||
BT_FN_VOID_PTR_ULL, ATTR_NOTHROW_LIST)
|
||||
BT_FN_PTR_PTR_ULL_ULL, ATTR_NOTHROW_LIST)
|
||||
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_STREAM_RELEASE, "GOMP_stream_release",
|
||||
BT_FN_VOID_PTR_ULL, ATTR_NOTHROW_LIST)
|
||||
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_STREAM_COMMIT, "GOMP_stream_commit",
|
||||
|
@ -239,6 +251,32 @@ DEF_GOMP_BUILTIN (BUILT_IN_GOMP_STREAM_COMMIT, "GOMP_stream_commit",
|
|||
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_STREAM_TASK_EXIT, "GOMP_stream_task_exit",
|
||||
BT_FN_VOID_PTR, ATTR_NOTHROW_LIST)
|
||||
|
||||
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_STREAM_CREATE_CONTROL_STREAM,
|
||||
"GOMP_stream_create_control_stream",
|
||||
BT_FN_PTR, ATTR_NOTHROW_LIST)
|
||||
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_STREAM_CONTROL_STREAM_ENABLE_ACTIVATION,
|
||||
"GOMP_stream_control_stream_enable_activation",
|
||||
BT_FN_VOID_PTR, ATTR_NOTHROW_LIST)
|
||||
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_STREAM_CONTROL_STREAM_SET_EOS,
|
||||
"GOMP_stream_control_stream_set_eos",
|
||||
BT_FN_VOID_PTR, ATTR_NOTHROW_LIST)
|
||||
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_STREAM_CONTROL_STREAM_EOS,
|
||||
"GOMP_stream_control_stream_eos",
|
||||
BT_FN_BOOL_PTR, ATTR_NOTHROW_LIST)
|
||||
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_STREAM_DESTROY_CONTROL_STREAM,
|
||||
"GOMP_stream_destroy_control_stream",
|
||||
BT_FN_VOID_PTR, ATTR_NOTHROW_LIST)
|
||||
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_STREAM_TASK, "GOMP_stream_task",
|
||||
BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_LONG_BOOL,
|
||||
ATTR_NOTHROW_LIST)
|
||||
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_STREAM_INIT, "GOMP_stream_init",
|
||||
BT_FN_VOID, ATTR_NOTHROW_LIST)
|
||||
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_STREAM_EXIT, "GOMP_stream_exit",
|
||||
BT_FN_VOID, ATTR_NOTHROW_LIST)
|
||||
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_STREAM_PRE, "GOMP_stream_pre",
|
||||
BT_FN_PTR_PTR_ULL, ATTR_NOTHROW_LIST)
|
||||
|
||||
|
||||
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_STREAM_PUSH_STUB, "GOMP_stream_push_stub",
|
||||
BT_FN_VOID_PTR_PTR, ATTR_NOTHROW_LIST)
|
||||
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_STREAM_POP_STUB, "GOMP_stream_pop_stub",
|
||||
|
|
4162
gcc/omp-low.c
4162
gcc/omp-low.c
File diff suppressed because it is too large
Load Diff
|
@ -233,8 +233,8 @@ unsigned const char omp_clause_num_ops[] =
|
|||
1, /* OMP_CLAUSE_SHARED */
|
||||
1, /* OMP_CLAUSE_FIRSTPRIVATE */
|
||||
2, /* OMP_CLAUSE_LASTPRIVATE */
|
||||
4, /* OMP_CLAUSE_INPUT */
|
||||
4, /* OMP_CLAUSE_OUTPUT */
|
||||
6, /* OMP_CLAUSE_INPUT */
|
||||
5, /* OMP_CLAUSE_OUTPUT */
|
||||
4, /* OMP_CLAUSE_REDUCTION */
|
||||
1, /* OMP_CLAUSE_COPYIN */
|
||||
1, /* OMP_CLAUSE_COPYPRIVATE */
|
||||
|
|
18
gcc/tree.h
18
gcc/tree.h
|
@ -1783,6 +1783,13 @@ extern void protected_set_expr_location (tree, location_t);
|
|||
OMP_CLAUSE_OPERAND (OMP_CLAUSE_RANGE_CHECK (OMP_CLAUSE_CHECK (NODE), \
|
||||
OMP_CLAUSE_INPUT, \
|
||||
OMP_CLAUSE_OUTPUT), 3)
|
||||
#define OMP_CLAUSE_VIEW_SIZE(NODE) \
|
||||
OMP_CLAUSE_OPERAND (OMP_CLAUSE_RANGE_CHECK (OMP_CLAUSE_CHECK (NODE), \
|
||||
OMP_CLAUSE_INPUT, \
|
||||
OMP_CLAUSE_OUTPUT), 4)
|
||||
#define OMP_CLAUSE_FIRSTPRIVATE_INPUT(NODE) \
|
||||
OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, \
|
||||
OMP_CLAUSE_INPUT), 5)
|
||||
|
||||
#define OMP_CLAUSE_HAS_LOCATION(NODE) \
|
||||
((OMP_CLAUSE_CHECK (NODE))->omp_clause.locus != UNKNOWN_LOCATION)
|
||||
|
@ -1871,6 +1878,16 @@ enum omp_clause_default_kind
|
|||
#define OMP_CLAUSE_DEFAULT_KIND(NODE) \
|
||||
(OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_DEFAULT)->omp_clause.subcode.default_kind)
|
||||
|
||||
enum omp_clause_view_var_kind
|
||||
{
|
||||
OMP_CLAUSE_VIEW_VAR_UNSPECIFIED,
|
||||
OMP_CLAUSE_VIEW_VAR_DISCARD,
|
||||
OMP_CLAUSE_VIEW_VAR_KEEP
|
||||
};
|
||||
|
||||
#define OMP_CLAUSE_VIEW_VAR_KIND(NODE) \
|
||||
(OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_FIRSTPRIVATE)->omp_clause.subcode.view_var_kind)
|
||||
|
||||
struct GTY(()) tree_exp {
|
||||
struct tree_common common;
|
||||
location_t locus;
|
||||
|
@ -1987,6 +2004,7 @@ struct GTY(()) tree_omp_clause {
|
|||
union omp_clause_subcode {
|
||||
enum omp_clause_default_kind default_kind;
|
||||
enum omp_clause_schedule_kind schedule_kind;
|
||||
enum omp_clause_view_var_kind view_var_kind;
|
||||
enum tree_code reduction_code;
|
||||
} GTY ((skip)) subcode;
|
||||
|
||||
|
|
|
@ -171,13 +171,25 @@ GOMP_2.0 {
|
|||
GOMP_stream_create_read_view;
|
||||
GOMP_stream_create_write_view;
|
||||
GOMP_stream_create_task;
|
||||
GOMP_stream_get_task_activation_counter;
|
||||
GOMP_stream_set_task_termination_flag;
|
||||
GOMP_stream_task_add_instance;
|
||||
GOMP_stream_add_expected_views;
|
||||
GOMP_stream_connect_view;
|
||||
GOMP_stream_wait_until_connected;
|
||||
GOMP_stream_get_available_work;
|
||||
GOMP_stream_update;
|
||||
GOMP_stream_stall;
|
||||
GOMP_stream_release;
|
||||
GOMP_stream_commit;
|
||||
GOMP_stream_task_exit;
|
||||
GOMP_stream_create_control_stream;
|
||||
GOMP_stream_control_stream_set_eos;
|
||||
GOMP_stream_control_stream_eos;
|
||||
GOMP_stream_destroy_control_stream;
|
||||
GOMP_stream_task;
|
||||
GOMP_stream_init;
|
||||
GOMP_stream_exit;
|
||||
GOMP_stream_pre;
|
||||
} GOMP_1.0;
|
||||
|
||||
|
|
|
@ -180,20 +180,36 @@ extern void *GOMP_single_copy_start (void);
|
|||
extern void GOMP_single_copy_end (void *);
|
||||
|
||||
/* stream.c */
|
||||
extern void *GOMP_stream_create_stream (size_t, unsigned long long, char *);
|
||||
extern void *GOMP_stream_create_read_view (void);
|
||||
extern void *GOMP_stream_create_write_view (void);
|
||||
extern void *GOMP_stream_create_stream (size_t, size_t);
|
||||
extern void *GOMP_stream_create_read_view (size_t, size_t);
|
||||
extern void *GOMP_stream_create_write_view (size_t, size_t);
|
||||
extern void *GOMP_stream_create_task (void);
|
||||
extern volatile void *GOMP_stream_get_task_activation_counter (void *);
|
||||
extern void GOMP_stream_set_task_termination_flag (void *);
|
||||
extern void GOMP_stream_task_add_instance (void *);
|
||||
extern void GOMP_stream_add_expected_views (void *, int, int, int);
|
||||
extern void GOMP_stream_connect_view (void *, void *, void *);
|
||||
extern void GOMP_stream_wait_until_connected (void *);
|
||||
extern unsigned long long GOMP_stream_update (void *,
|
||||
extern unsigned long long GOMP_stream_get_available_work (void *,
|
||||
unsigned long long *);
|
||||
extern void *GOMP_stream_update (void *,
|
||||
const unsigned long long,
|
||||
const unsigned long long);
|
||||
extern void *GOMP_stream_stall (void *, const unsigned long long,
|
||||
const unsigned long long);
|
||||
extern void GOMP_stream_stall (void *, const unsigned long long);
|
||||
extern void GOMP_stream_release (void *, const unsigned long long);
|
||||
extern void GOMP_stream_commit (void *, const unsigned long long);
|
||||
extern void GOMP_stream_task_exit (void *);
|
||||
|
||||
|
||||
extern void *GOMP_stream_create_control_stream (void);
|
||||
extern void GOMP_stream_control_stream_set_eos (void *);
|
||||
extern bool GOMP_stream_control_stream_eos (void *);
|
||||
extern void GOMP_stream_destroy_control_stream (void *);
|
||||
extern void GOMP_stream_task (void (*) (void *), void *,
|
||||
void (*) (void *, void *),
|
||||
long, long, long, bool);
|
||||
extern void GOMP_stream_init (void);
|
||||
extern void GOMP_stream_exit (void);
|
||||
extern void *GOMP_stream_pre (void *, const unsigned long long);
|
||||
|
||||
#endif /* LIBGOMP_G_H */
|
||||
|
|
|
@ -107,19 +107,24 @@ int omp_get_active_level (void) __GOMP_NOTHROW;
|
|||
[(unsigned long long)(INDEX) & \
|
||||
(*((unsigned long long *)((*((char ***) (VIEW))) + 1)))]
|
||||
|
||||
extern void *GOMP_stream_create_stream (size_t, unsigned long long, char *)
|
||||
extern void *GOMP_stream_create_stream (size_t, size_t)
|
||||
__GOMP_NOTHROW;
|
||||
extern void *GOMP_stream_create_read_view (void) __GOMP_NOTHROW;
|
||||
extern void *GOMP_stream_create_write_view (void) __GOMP_NOTHROW;
|
||||
extern void *GOMP_stream_create_read_view (size_t, size_t) __GOMP_NOTHROW;
|
||||
extern void *GOMP_stream_create_write_view (size_t, size_t) __GOMP_NOTHROW;
|
||||
extern void *GOMP_stream_create_task (void) __GOMP_NOTHROW;
|
||||
extern void GOMP_stream_add_expected_views (void *, int, int, int)
|
||||
__GOMP_NOTHROW;
|
||||
extern void GOMP_stream_connect_view (void *, void *, void *) __GOMP_NOTHROW;
|
||||
extern void GOMP_stream_wait_until_connected (void *) __GOMP_NOTHROW;
|
||||
extern unsigned long long GOMP_stream_update (void *,
|
||||
extern unsigned long long GOMP_stream_get_available_work (void *,
|
||||
unsigned long long *)
|
||||
__GOMP_NOTHROW;
|
||||
extern void *GOMP_stream_update (void *,
|
||||
const unsigned long long,
|
||||
const unsigned long long)
|
||||
__GOMP_NOTHROW;
|
||||
extern void GOMP_stream_stall (void *, const unsigned long long)
|
||||
extern void *GOMP_stream_stall (void *, const unsigned long long,
|
||||
const unsigned long long)
|
||||
__GOMP_NOTHROW;
|
||||
extern void GOMP_stream_release (void *, const unsigned long long)
|
||||
__GOMP_NOTHROW;
|
||||
|
|
438
libgomp/stream.c
438
libgomp/stream.c
|
@ -36,6 +36,30 @@
|
|||
#include "mutex.h"
|
||||
#include "libgomp.h"
|
||||
|
||||
#define AGGREGATION_FACTOR 32
|
||||
|
||||
//#define debug_log_init(S, V1, V2) printf (S, V1, V2); fflush (stdout)
|
||||
#define debug_log_init(S, V1, V2)
|
||||
|
||||
//#define debug_log_init3(S, V1, V2, V3) printf (S, V1, V2, V3); fflush (stdout)
|
||||
#define debug_log_init3(S, V1, V2, V3)
|
||||
|
||||
//#define debug_log(S, V1, V2) printf (S, V1, V2); fflush (stdout)
|
||||
#define debug_log(S, V1, V2)
|
||||
|
||||
gomp_barrier_t gomp_stream_tasks_wait_until_connected_barrier;
|
||||
gomp_barrier_t gomp_stream_tasks_exit_barrier;
|
||||
unsigned gomp_stream_tasks_count;
|
||||
|
||||
/* This structure is used to communicate across pthread_create. */
|
||||
|
||||
struct gomp_stream_thread_start_data
|
||||
{
|
||||
void (*fn) (void *);
|
||||
void *fn_data;
|
||||
|
||||
int id;
|
||||
};
|
||||
|
||||
/* Data structures creation and pipeline initialization. */
|
||||
|
||||
|
@ -46,39 +70,32 @@
|
|||
BUFFER for the stream. */
|
||||
|
||||
void *
|
||||
GOMP_stream_create_stream (size_t element_size,
|
||||
unsigned long long stream_buffer_size,
|
||||
char *buffer)
|
||||
GOMP_stream_create_stream (size_t element_size, size_t buffer_size)
|
||||
{
|
||||
gomp_stream_p stream = (gomp_stream_p) gomp_malloc (sizeof (gomp_stream_t));
|
||||
debug_log_init ("GOMP_stream_create_stream %zu %zu\n", element_size, buffer_size);
|
||||
|
||||
if (buffer_size < 2)
|
||||
gomp_fatal ("GOMP_stream: insufficient stream buffer size.");
|
||||
|
||||
/* Initialize and allocate the data buffer. We force the
|
||||
buffer_size to be a power of 2 for efficient modulo computation
|
||||
of the indices in the circular buffer. */
|
||||
stream->element_size = element_size;
|
||||
|
||||
/* To avoid excessive multiplication operations, we convert the
|
||||
accounting from elements to bytes. */
|
||||
buffer_size *= element_size;
|
||||
stream->buffer_size = 1;
|
||||
while(stream->buffer_size < stream_buffer_size)
|
||||
while(stream->buffer_size < buffer_size)
|
||||
stream->buffer_size <<= 1;
|
||||
stream->buffer_mask = stream->buffer_size - 1;
|
||||
|
||||
/* In case the user provided a pre-allocated buffer, we need to
|
||||
ensure it is properly sized. */
|
||||
if (buffer != NULL)
|
||||
{
|
||||
if (stream->buffer_size != stream_buffer_size)
|
||||
gomp_fatal ("GOMP_stream: provided buffer size is not power of 2.");
|
||||
|
||||
stream->buffer = buffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
stream->buffer =
|
||||
(void *) gomp_malloc (stream->element_size * stream->buffer_size);
|
||||
}
|
||||
(void *) gomp_malloc (stream->buffer_size * 2);
|
||||
|
||||
stream->expected_ready_p = false;
|
||||
stream->connected_p = false;
|
||||
stream->eos_p = false;
|
||||
stream->pre_shift = 0;
|
||||
|
||||
/* Initialize the view_handles. */
|
||||
stream->read_views.current_min = stream->buffer_size;
|
||||
|
@ -89,7 +106,7 @@ GOMP_stream_create_stream (size_t element_size,
|
|||
stream->read_views.nr_expected_views = 0;
|
||||
stream->read_views.nr_registered_views = 0;
|
||||
stream->read_views.nr_unregistered_views = 0;
|
||||
gomp_mutex_init (&stream->read_views.connect_view_mutex);
|
||||
gomp_mutex_init (&stream->read_views.view_list.connect_view_mutex);
|
||||
|
||||
stream->write_views.current_min = 0;
|
||||
stream->write_views.current_max = stream->buffer_size;
|
||||
|
@ -99,7 +116,7 @@ GOMP_stream_create_stream (size_t element_size,
|
|||
stream->write_views.nr_expected_views = 0;
|
||||
stream->write_views.nr_registered_views = 0;
|
||||
stream->write_views.nr_unregistered_views = 0;
|
||||
gomp_mutex_init (&stream->write_views.connect_view_mutex);
|
||||
gomp_mutex_init (&stream->write_views.view_list.connect_view_mutex);
|
||||
|
||||
#ifndef HAVE_SYNC_BUILTINS
|
||||
gomp_mutex_init (&stream->stream_mutex);
|
||||
|
@ -111,10 +128,11 @@ GOMP_stream_create_stream (size_t element_size,
|
|||
/* Allocate and initialize a generic GOMP_STREAM_VIEW that can be
|
||||
connected to any stream to give either read or write access
|
||||
depending on its TYPE. Returns a pointer to the newly allocated
|
||||
view. */
|
||||
view. This view accesses VIEW_SIZE bytes in the stream and
|
||||
commits/releases BURST_SIZE bytes per activation. */
|
||||
|
||||
static inline void *
|
||||
gomp_stream_create_view (int type)
|
||||
gomp_stream_create_view (int type, size_t view_size, size_t burst_size)
|
||||
{
|
||||
gomp_stream_view_p view =
|
||||
(gomp_stream_view_p) gomp_malloc (sizeof(gomp_stream_view_t));
|
||||
|
@ -125,6 +143,9 @@ gomp_stream_create_view (int type)
|
|||
view->end_p = false;
|
||||
view->type = type;
|
||||
view->local_min_value = 0;
|
||||
view->view_size = view_size;
|
||||
view->burst_size = burst_size;
|
||||
view->pxxk_size = view_size - burst_size;
|
||||
|
||||
return view;
|
||||
}
|
||||
|
@ -132,38 +153,76 @@ gomp_stream_create_view (int type)
|
|||
/* Wrapper for creating a READ view . */
|
||||
|
||||
void *
|
||||
GOMP_stream_create_read_view (void)
|
||||
GOMP_stream_create_read_view (size_t view_size, size_t burst_size)
|
||||
{
|
||||
return gomp_stream_create_view (READ_VIEW);
|
||||
debug_log_init ("GOMP_stream_create_read_view %zu %zu\n", view_size, burst_size);
|
||||
return gomp_stream_create_view (READ_VIEW, view_size, burst_size);
|
||||
}
|
||||
|
||||
/* Wrapper for creating a WRITE view. */
|
||||
|
||||
void *
|
||||
GOMP_stream_create_write_view (void)
|
||||
GOMP_stream_create_write_view (size_t view_size, size_t burst_size)
|
||||
{
|
||||
return gomp_stream_create_view (WRITE_VIEW);
|
||||
debug_log_init ("GOMP_stream_create_write_view %zu %zu\n", view_size, burst_size);
|
||||
return gomp_stream_create_view (WRITE_VIEW, view_size, burst_size);
|
||||
}
|
||||
|
||||
/* Allocate and initialize a GOMP_STREAM_TASK data structure. */
|
||||
|
||||
void *
|
||||
GOMP_stream_create_task (void)
|
||||
GOMP_stream_create_task ()
|
||||
{
|
||||
gomp_stream_task_p task =
|
||||
(gomp_stream_task_p) gomp_malloc (sizeof(gomp_stream_task_t));
|
||||
debug_log_init3 ("GOMP_stream_create_task %d %d \t %15zu\n", 0, 0, (size_t) task);
|
||||
|
||||
task->read_view_list.views = NULL;
|
||||
task->read_view_list.nr_views = 0;
|
||||
task->read_view_list.size = 0;
|
||||
gomp_mutex_init (&task->read_view_list.connect_view_mutex);
|
||||
|
||||
task->write_view_list.views = NULL;
|
||||
task->write_view_list.nr_views = 0;
|
||||
task->write_view_list.size = 0;
|
||||
gomp_mutex_init (&task->write_view_list.connect_view_mutex);
|
||||
|
||||
task->activation_counter = 0;
|
||||
task->termination_flag = false;
|
||||
|
||||
task->first_unassigned_activation_counter = 0;
|
||||
task->num_instances = 0;
|
||||
|
||||
__sync_synchronize ();
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
volatile void *
|
||||
GOMP_stream_get_task_activation_counter (void *t)
|
||||
{
|
||||
gomp_stream_task_p task = (gomp_stream_task_p) t;
|
||||
|
||||
return &(task->activation_counter);
|
||||
}
|
||||
|
||||
void
|
||||
GOMP_stream_set_task_termination_flag (void *t)
|
||||
{
|
||||
gomp_stream_task_p task = (gomp_stream_task_p) t;
|
||||
|
||||
task->termination_flag = true;
|
||||
}
|
||||
|
||||
void
|
||||
GOMP_stream_task_add_instance (void *t)
|
||||
{
|
||||
gomp_stream_task_p task = (gomp_stream_task_p) t;
|
||||
|
||||
__sync_fetch_and_add (&task->num_instances, 1);
|
||||
__sync_synchronize ();
|
||||
}
|
||||
|
||||
/* Declare additional READ_VIEWS and WRITE_VIEWS expected views on
|
||||
stream S. When possible, the thread that creates the streaming
|
||||
tasks should declare, for each stream, the number of read/write
|
||||
|
@ -177,6 +236,7 @@ GOMP_stream_add_expected_views (void *s, int read_views, int write_views,
|
|||
int final)
|
||||
{
|
||||
gomp_stream_p stream = (gomp_stream_p) s;
|
||||
debug_log_init ("GOMP_stream_add_expected_views %d %d\n", read_views, write_views);
|
||||
|
||||
if (stream->expected_ready_p)
|
||||
gomp_fatal
|
||||
|
@ -249,14 +309,16 @@ GOMP_stream_connect_view (void *t, void *s, void *v)
|
|||
/* Register the view with the TASK to which it belongs. This
|
||||
operation is local to the task, so there is no need to
|
||||
synchronize. */
|
||||
gomp_mutex_lock (&task_list->connect_view_mutex);
|
||||
gomp_stream_add_view_to_list (view, task_list);
|
||||
gomp_mutex_unlock (&task_list->connect_view_mutex);
|
||||
|
||||
/* Connect the view to the stream. This must be done atomically as
|
||||
this data structure is shared with the other producer/consumer
|
||||
tasks. */
|
||||
gomp_mutex_lock (&vh->connect_view_mutex);
|
||||
gomp_mutex_lock (&vh->view_list.connect_view_mutex);
|
||||
gomp_stream_add_view_to_list (view, stream_list);
|
||||
gomp_mutex_unlock (&vh->connect_view_mutex);
|
||||
gomp_mutex_unlock (&vh->view_list.connect_view_mutex);
|
||||
__sync_fetch_and_add (&vh->nr_registered_views, 1);
|
||||
}
|
||||
|
||||
|
@ -290,24 +352,27 @@ void
|
|||
GOMP_stream_wait_until_connected (void *t)
|
||||
{
|
||||
gomp_stream_task_p task = (gomp_stream_task_p) t;
|
||||
int num_read_views = task->read_view_list.nr_views;
|
||||
int num_write_views = task->write_view_list.nr_views;
|
||||
int i;
|
||||
bool done;
|
||||
int i;
|
||||
|
||||
do
|
||||
{
|
||||
done = true;
|
||||
|
||||
for (i = 0; i < num_read_views; ++i)
|
||||
gomp_mutex_lock (&task->read_view_list.connect_view_mutex);
|
||||
for (i = 0; i < task->read_view_list.nr_views; ++i)
|
||||
if (!gomp_stream_check_connected (task->read_view_list.views[i]->stream))
|
||||
done = false;
|
||||
gomp_mutex_unlock (&task->read_view_list.connect_view_mutex);
|
||||
|
||||
for (i = 0; i < num_write_views; ++i)
|
||||
gomp_mutex_lock (&task->write_view_list.connect_view_mutex);
|
||||
for (i = 0; i < task->write_view_list.nr_views; ++i)
|
||||
if (!gomp_stream_check_connected (task->write_view_list.views[i]->stream))
|
||||
done = false;
|
||||
gomp_mutex_unlock (&task->write_view_list.connect_view_mutex);
|
||||
}
|
||||
while (!done);
|
||||
debug_log_init ("GOMP_stream_wait_until_connected %zu %zu\n", (size_t) task, (size_t) task);
|
||||
}
|
||||
|
||||
/* Stream communication/synchronization. */
|
||||
|
@ -409,76 +474,151 @@ gomp_stream_wait_release (gomp_stream_view_p view,
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/* Request read access for the view V to the stream up to INDEX. In
|
||||
case the producers have finished and there is not enough data, the
|
||||
returned value is the highest index to which the view is allowed to
|
||||
access the stream. */
|
||||
|
||||
unsigned long long
|
||||
GOMP_stream_update (void *v, const unsigned long long index)
|
||||
void *
|
||||
GOMP_stream_update (void *v, const unsigned long long act_start,
|
||||
const unsigned long long act_end)
|
||||
{
|
||||
unsigned long long low_idx, up_idx;
|
||||
size_t low_idx_loc, up_idx_loc;
|
||||
gomp_stream_view_p view = (gomp_stream_view_p) v;
|
||||
view->upper_index = index;
|
||||
gomp_stream_p stream = view->stream;
|
||||
void *buffer_pointer;
|
||||
|
||||
debug_log ("GOMP_stream_update [in] %llu %llu\n", act_start, act_end);
|
||||
|
||||
/* This update requests access to the buffer in [low_idx,up_idx[.
|
||||
We will release up to low_idx-1 and acquire up to up_idx-1. */
|
||||
low_idx = act_start * view->burst_size;
|
||||
up_idx = act_end * view->burst_size + view->pxxk_size - 1;
|
||||
|
||||
if (up_idx - low_idx > stream->buffer_size)
|
||||
gomp_fatal ("GOMP_stream: update requested access to more than buffer_size data.");
|
||||
|
||||
|
||||
view->lower_index = low_idx + view->stream->buffer_size;
|
||||
view->upper_index = up_idx;
|
||||
|
||||
/* In case another consumer has received permission to read up to a
|
||||
yet higher index, then there is no need to check for this one. */
|
||||
if (index > view->stream->read_views.current_max)
|
||||
if (up_idx > view->stream->read_views.current_max)
|
||||
{
|
||||
gomp_stream_wait_release (view, &view->stream->write_views, index);
|
||||
gomp_stream_wait_release (view, &view->stream->write_views, up_idx);
|
||||
view->stream->read_views.current_max = up_idx;
|
||||
}
|
||||
|
||||
/* If the producers have finished producing for this stream, we
|
||||
need to ensure we do not give read permission to the view
|
||||
past the highest fully committed index (committed by all
|
||||
producers). */
|
||||
if (view->stream->eos_p)
|
||||
{
|
||||
view->stream->write_views.current_min =
|
||||
gomp_stream_compute_lower_min (&view->stream->write_views.view_list);
|
||||
low_idx_loc = low_idx & stream->buffer_mask;
|
||||
up_idx_loc = up_idx & stream->buffer_mask;
|
||||
|
||||
if (index > view->stream->write_views.current_min)
|
||||
/* Once we know enough data is available for reading, we need to
|
||||
check whether the data between the lower and upper buonds is
|
||||
contiguous or if the buffer wrap-around occurs in the middle. */
|
||||
if (low_idx_loc > up_idx_loc)
|
||||
{
|
||||
return view->stream->write_views.current_min;
|
||||
/* FIXME: does this require synchronization or is concurrent
|
||||
overwriting acceptable as long as enough data has been copied
|
||||
at the end? */
|
||||
memcpy (stream->buffer + stream->buffer_size, stream->buffer,
|
||||
up_idx_loc + 1);
|
||||
//printf ("Update copy: (%llu,%llu) %llu - %llu | %zu - %zu (size: %zu)\n ", act_start, act_end, low_idx, up_idx, low_idx_loc, up_idx_loc, up_idx_loc + 1);
|
||||
}
|
||||
}
|
||||
view->stream->read_views.current_max = index;
|
||||
}
|
||||
return index;
|
||||
|
||||
/* We return a pointer to a contiguous array where this view is
|
||||
guaranteed access to all the requested data. */
|
||||
buffer_pointer = stream->buffer + low_idx_loc;
|
||||
|
||||
debug_log ("GOMP_stream_update [out] %llu %llu\n", act_start, act_end);
|
||||
|
||||
return buffer_pointer;
|
||||
}
|
||||
|
||||
/* Request write access for the view V to the stream up to INDEX. */
|
||||
|
||||
void
|
||||
GOMP_stream_stall (void *v, const unsigned long long index)
|
||||
void *
|
||||
GOMP_stream_stall (void *v, const unsigned long long act_start,
|
||||
const unsigned long long act_end)
|
||||
{
|
||||
unsigned long long low_idx, up_idx;
|
||||
gomp_stream_view_p view = (gomp_stream_view_p) v;
|
||||
view->upper_index = index;
|
||||
gomp_stream_p stream = view->stream;
|
||||
void *buffer_pointer;
|
||||
|
||||
if (index > view->stream->write_views.current_max)
|
||||
debug_log ("GOMP_stream_stall [in] %llu %llu\n", act_start, act_end);
|
||||
|
||||
/* This update requests access to the buffer in [low_idx,up_idx[.
|
||||
We will release up to low_idx-1 and acquire up to up_idx-1. */
|
||||
low_idx = act_start * view->burst_size + stream->pre_shift;
|
||||
up_idx = act_end * view->burst_size + view->pxxk_size + stream->pre_shift - 1;
|
||||
|
||||
if (up_idx - low_idx > stream->buffer_size)
|
||||
{
|
||||
gomp_stream_wait_release (view, &view->stream->read_views, index);
|
||||
view->stream->write_views.current_max = index;
|
||||
fprintf (stderr, "Requesting data from low: %llu to up: %llu act [%llu,%llu] for burst:%zu size: %zu\n", low_idx, up_idx, act_start, act_end, view->burst_size, view->view_size);
|
||||
gomp_fatal ("GOMP_stream: stall requested access to more than buffer_size data.");
|
||||
}
|
||||
/* We do not need to worry about wrap-around copying as this
|
||||
"commit" only means that we do not want to write to those
|
||||
indices below low_idx. */
|
||||
view->lower_index = low_idx;
|
||||
view->upper_index = up_idx;
|
||||
|
||||
if (up_idx > stream->write_views.current_max)
|
||||
{
|
||||
gomp_stream_wait_release (view, &stream->read_views, up_idx);
|
||||
stream->write_views.current_max = up_idx;
|
||||
}
|
||||
|
||||
buffer_pointer = stream->buffer + (low_idx & stream->buffer_mask);
|
||||
|
||||
debug_log ("GOMP_stream_stall [out] %llu %llu\n", act_start, act_end);
|
||||
|
||||
return buffer_pointer;
|
||||
}
|
||||
|
||||
/* Relinquish read access for the view V to the stream up to
|
||||
INDEX. */
|
||||
|
||||
void
|
||||
GOMP_stream_release (void *v, const unsigned long long index)
|
||||
GOMP_stream_release (void *v, const unsigned long long act_idx)
|
||||
{
|
||||
gomp_stream_view_p view = (gomp_stream_view_p) v;
|
||||
view->lower_index = index + view->stream->buffer_size;
|
||||
view->lower_index = act_idx * view->burst_size + view->stream->buffer_size - 1;
|
||||
debug_log ("GOMP_stream_release %llu %llu\n", act_idx, act_idx);
|
||||
}
|
||||
|
||||
/* Relinquish write access for the view V to the stream up to
|
||||
INDEX. */
|
||||
|
||||
void
|
||||
GOMP_stream_commit (void *v, const unsigned long long index)
|
||||
GOMP_stream_commit (void *v, const unsigned long long act_idx)
|
||||
{
|
||||
gomp_stream_view_p view = (gomp_stream_view_p) v;
|
||||
view->lower_index = index;
|
||||
gomp_stream_p stream = view->stream;
|
||||
unsigned long long up_idx = act_idx * view->burst_size + stream->pre_shift - 1;
|
||||
size_t low_idx_loc, up_idx_loc;
|
||||
|
||||
low_idx_loc = view->lower_index & stream->buffer_mask;
|
||||
up_idx_loc = up_idx & stream->buffer_mask;
|
||||
|
||||
/* Once we know enough data is available for reading, we need to
|
||||
check whether the data between the lower and upper buonds is
|
||||
contiguous or if the buffer wrap-around occurs in the middle. */
|
||||
if (low_idx_loc > up_idx_loc)
|
||||
{
|
||||
/* FIXME: does this require synchronization or is concurrent
|
||||
overwriting acceptable as long as enough data has been copied
|
||||
at the end? */
|
||||
memcpy (stream->buffer, stream->buffer + stream->buffer_size,
|
||||
up_idx_loc + 1);
|
||||
|
||||
//printf ("Commit copy: (%llu) %llu - %llu | %zu - %zu (size: %zu)\n ", act_idx, view->lower_index, up_idx, low_idx_loc, up_idx_loc, up_idx_loc + 1);
|
||||
}
|
||||
|
||||
view->lower_index = up_idx;
|
||||
debug_log ("GOMP_stream_commit %llu %llu\n", act_idx, act_idx);
|
||||
}
|
||||
|
||||
/* Finalization and destruction of the streaming data structures. */
|
||||
|
@ -543,8 +683,13 @@ GOMP_stream_task_exit (void *t)
|
|||
gomp_stream_task_p task = (gomp_stream_task_p) t;
|
||||
int num_read_views = task->read_view_list.nr_views;
|
||||
int num_write_views = task->write_view_list.nr_views;
|
||||
int i;
|
||||
int i, res;
|
||||
debug_log_init ("GOMP_stream_task_exit %zu %zu\n", (size_t) t, (size_t) t);
|
||||
|
||||
res = __sync_sub_and_fetch (&task->num_instances, 1);
|
||||
|
||||
if (res == 0)
|
||||
{
|
||||
for (i = 0; i < num_read_views; ++i)
|
||||
gomp_stream_unregister_view (task->read_view_list.views[i]);
|
||||
|
||||
|
@ -555,8 +700,169 @@ GOMP_stream_task_exit (void *t)
|
|||
free (task->write_view_list.views);
|
||||
free (task);
|
||||
}
|
||||
}
|
||||
|
||||
/* Get info on the amount of work/data available in the stream
|
||||
starting from INDEX and considering a constant burst of size BURST.
|
||||
This function does not wait, except in case there is no work yet,
|
||||
but the EOS flag has not yet been set. The function only returns 0
|
||||
on termination. */
|
||||
unsigned long long
|
||||
GOMP_stream_get_available_work (void *t, unsigned long long *start_idx)
|
||||
{
|
||||
gomp_stream_task_p task = (gomp_stream_task_p) t;
|
||||
long result = 0;
|
||||
unsigned long long start;
|
||||
|
||||
/* Atomically acquire a range, then wait until the range is either
|
||||
fully available or termination occurs. */
|
||||
start = __sync_fetch_and_add (&task->first_unassigned_activation_counter,
|
||||
AGGREGATION_FACTOR);
|
||||
result = task->activation_counter - start;
|
||||
debug_log_init3 ("GOMP_stream_get_available_work [entry] %llu %llu \t %15zu\n", start, task->activation_counter, (size_t) task);
|
||||
|
||||
if (result >= AGGREGATION_FACTOR)
|
||||
{
|
||||
*start_idx = start;
|
||||
return AGGREGATION_FACTOR;
|
||||
}
|
||||
|
||||
while (result < AGGREGATION_FACTOR)
|
||||
{
|
||||
if (task->termination_flag)
|
||||
{
|
||||
__sync_synchronize ();
|
||||
result = task->activation_counter - start;
|
||||
debug_log ("GOMP_stream_get_available_work [final] %llu %ld\n", start, result);
|
||||
*start_idx = start;
|
||||
if (result > AGGREGATION_FACTOR)
|
||||
return AGGREGATION_FACTOR;
|
||||
return (result > 0) ? result : 0;
|
||||
}
|
||||
result = task->activation_counter - start;
|
||||
}
|
||||
debug_log ("GOMP_stream_get_available_work %llu %ld\n", start, result);
|
||||
|
||||
*start_idx = start;
|
||||
return AGGREGATION_FACTOR;
|
||||
}
|
||||
|
||||
|
||||
/* Initialize streaming in this region. */
|
||||
|
||||
void
|
||||
GOMP_stream_init ()
|
||||
{
|
||||
/* Add self to ensure at least one member of the team barrier will
|
||||
be waiting for the streaming tasks. */
|
||||
gomp_stream_tasks_count = 1;
|
||||
gomp_barrier_init (&gomp_stream_tasks_exit_barrier, gomp_stream_tasks_count);
|
||||
}
|
||||
|
||||
/* Wait until all streaming threads complete. */
|
||||
|
||||
void
|
||||
GOMP_stream_exit ()
|
||||
{
|
||||
gomp_barrier_wait (&gomp_stream_tasks_exit_barrier);
|
||||
}
|
||||
|
||||
/* Request SIZE bytes for a PRE operator on stream S. Return a
|
||||
pointer where data should be stored. */
|
||||
void *
|
||||
GOMP_stream_pre (void *s, const unsigned long long size)
|
||||
{
|
||||
gomp_stream_p stream = (gomp_stream_p) s;
|
||||
|
||||
debug_log_init ("GOMP_stream_pre %zu \t %llu\n", (size_t) s, size);
|
||||
|
||||
stream->pre_shift = size;
|
||||
stream->write_views.current_min = size;
|
||||
|
||||
return stream->buffer;
|
||||
}
|
||||
|
||||
|
||||
/* This function is a pthread_create entry point for streaming
|
||||
tasks. */
|
||||
|
||||
static void *
|
||||
gomp_stream_thread_start (void *xdata)
|
||||
{
|
||||
struct gomp_stream_thread_start_data *data = xdata;
|
||||
void (*local_fn) (void *);
|
||||
void *local_data;
|
||||
|
||||
local_fn = data->fn;
|
||||
local_data = data->fn_data;
|
||||
|
||||
local_fn (local_data);
|
||||
|
||||
gomp_barrier_wait_last (&gomp_stream_tasks_exit_barrier);
|
||||
debug_log_init ("** exiting task: %d (%u)\n", data->id, gomp_stream_tasks_count);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Called for starting a streaming task. These tasks do not partake
|
||||
in existing thread teams and are not subject to scheduling
|
||||
points. */
|
||||
|
||||
void
|
||||
GOMP_stream_task (void (*fn) (void *), void *data,
|
||||
void (*cpyfn) (void *, void *),
|
||||
long arg_size, long arg_align,
|
||||
long num_instances, bool auto_replicable)
|
||||
{
|
||||
pthread_attr_t thread_attr, *attr;
|
||||
pthread_t pt;
|
||||
int err, i, base_id;
|
||||
char *arg, *buf;
|
||||
|
||||
base_id = __sync_fetch_and_add (&gomp_stream_tasks_count, num_instances);
|
||||
gomp_barrier_reinit (&gomp_stream_tasks_exit_barrier,
|
||||
gomp_stream_tasks_count);
|
||||
|
||||
debug_log_init ("** adding tasks: %ld (%u)\n", num_instances, gomp_stream_tasks_count);
|
||||
|
||||
attr = &gomp_thread_attr;
|
||||
if (__builtin_expect (gomp_cpu_affinity != NULL, 0))
|
||||
{
|
||||
size_t stacksize;
|
||||
pthread_attr_init (&thread_attr);
|
||||
pthread_attr_setdetachstate (&thread_attr, PTHREAD_CREATE_DETACHED);
|
||||
if (! pthread_attr_getstacksize (&gomp_thread_attr, &stacksize))
|
||||
pthread_attr_setstacksize (&thread_attr, stacksize);
|
||||
attr = &thread_attr;
|
||||
#if 0 /* This should be handled separately ... we will have to build a
|
||||
stream mapping and prevent other OMP threads from touching
|
||||
the cores running streaming tasks. */
|
||||
gomp_init_thread_affinity (attr);
|
||||
#endif
|
||||
}
|
||||
|
||||
for (i = 0; i < num_instances; ++i)
|
||||
{
|
||||
struct gomp_stream_thread_start_data *start_data;
|
||||
|
||||
buf = (char *) gomp_malloc (arg_size + arg_align - 1);
|
||||
arg = (char *) (((uintptr_t) (buf) + arg_align - 1)
|
||||
& ~(uintptr_t) (arg_align - 1));
|
||||
if (cpyfn)
|
||||
cpyfn (arg, data);
|
||||
else
|
||||
memcpy (arg, data, arg_size);
|
||||
|
||||
start_data = gomp_malloc (sizeof (struct gomp_stream_thread_start_data));
|
||||
start_data->fn = fn;
|
||||
start_data->fn_data = arg;
|
||||
start_data->id = base_id + i;
|
||||
|
||||
err = pthread_create (&pt, attr, gomp_stream_thread_start, start_data);
|
||||
if (err != 0)
|
||||
gomp_fatal ("Thread creation failed: %s", strerror (err));
|
||||
}
|
||||
|
||||
if (__builtin_expect (gomp_cpu_affinity != NULL, 0))
|
||||
pthread_attr_destroy (&thread_attr);
|
||||
}
|
||||
|
|
|
@ -73,6 +73,12 @@ typedef struct gomp_stream_view
|
|||
to be first. */
|
||||
struct gomp_stream *stream;
|
||||
|
||||
/* Size in bytes of the burst associated to this view. Later this
|
||||
may become a stream. */
|
||||
size_t view_size;
|
||||
size_t burst_size;
|
||||
size_t pxxk_size;
|
||||
|
||||
/* The alignment directives are needed to ensure these
|
||||
high-potential false-sharing fields are on their own cache
|
||||
lines. */
|
||||
|
@ -109,6 +115,10 @@ typedef struct gomp_stream_view_list
|
|||
gomp_stream_view_p *views;
|
||||
int nr_views;
|
||||
int size;
|
||||
|
||||
/* Enforce atomic connection of the views in this list. */
|
||||
gomp_mutex_t connect_view_mutex;
|
||||
|
||||
} gomp_stream_view_list_t, *gomp_stream_view_list_p;
|
||||
|
||||
|
||||
|
@ -133,9 +143,6 @@ typedef struct gomp_stream_view_handle
|
|||
int nr_registered_views;
|
||||
int nr_unregistered_views;
|
||||
|
||||
/* Enforce atomic connection of the views to the stream. */
|
||||
gomp_mutex_t connect_view_mutex;
|
||||
|
||||
} gomp_stream_view_handle_t, *gomp_stream_view_handle_p;
|
||||
|
||||
|
||||
|
@ -158,9 +165,9 @@ typedef struct gomp_stream
|
|||
for the wrap-around. The size is expressed in basic elements for
|
||||
this stream. The size in bytes of the buffer is
|
||||
BUFFER_SIZE * ELEMENT_SIZE. */
|
||||
unsigned long long buffer_mask;
|
||||
unsigned long long buffer_size;
|
||||
unsigned long long element_size;
|
||||
unsigned long long buffer_mask;
|
||||
unsigned long long pre_shift;
|
||||
|
||||
/* True once all the tasks that should be expected to connect to
|
||||
this stream been declared. */
|
||||
|
@ -205,6 +212,58 @@ typedef struct gomp_stream_task
|
|||
gomp_stream_view_list_t read_view_list;
|
||||
gomp_stream_view_list_t write_view_list;
|
||||
|
||||
/* The following are used directly in the generated code and should
|
||||
only be read here. A memory fence is guaranteed before the
|
||||
termination flag is set to true. */
|
||||
|
||||
/* Number of activations allowed for the task. */
|
||||
volatile unsigned long long activation_counter;
|
||||
volatile unsigned long long first_unassigned_activation_counter;
|
||||
|
||||
int num_instances;
|
||||
|
||||
/* True only when the activation counter has reached the maximum
|
||||
number of activations allowed for this task. */
|
||||
volatile bool termination_flag;
|
||||
|
||||
} gomp_stream_task_t, *gomp_stream_task_p;
|
||||
|
||||
|
||||
#if 0
|
||||
/* GOMP_STREAM_CONTROL_STREAM data structure. Implements a simple
|
||||
if-conversion analog that allows a non data-driven task to conform
|
||||
to its original control dependences. */
|
||||
|
||||
typedef struct gomp_stream_control_stream
|
||||
{
|
||||
/* In all cases where the streams bypass control (i.e., for
|
||||
sequential control flow only), an activation counter is
|
||||
sufficient to carry the control flow. */
|
||||
|
||||
/* Local counter of the number of times a task has been activated. */
|
||||
unsigned long long activation_counter __attribute__((aligned (64)));
|
||||
unsigned long long local_enabled_activations;
|
||||
|
||||
/* Number of times this task is allowed to activate. */
|
||||
unsigned long long enabled_activations __attribute__((aligned (64)));
|
||||
|
||||
/* When a task's inputs or outputs cross a parallel control flow
|
||||
boundary (i.e., worksharing construct), their activation pattern
|
||||
can be sparse wrt. the actual stream of data that they share with
|
||||
their sibling tasks. We use activation ranges as an optimization
|
||||
to streaming the activation indexes themselves, but the two
|
||||
options are equivalent. These streams are inherently 1-to-1, so
|
||||
a simpler implementation of the synchronization should be used in
|
||||
this case.*/
|
||||
/* gomp_stream_p activation_range_stream; */
|
||||
|
||||
/* End of stream: true when all producers have finished committing
|
||||
all the data and are terminating. */
|
||||
bool eos_p;
|
||||
|
||||
} gomp_stream_control_stream_t, *gomp_stream_control_stream_p;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* GOMP_STREAM_H */
|
||||
|
|
Loading…
Reference in New Issue