Skip to content

Commit

Permalink
thread_aware now internal & experimental; many fixes; test PoC
Browse files Browse the repository at this point in the history
Gonna keep the documentation for now
  • Loading branch information
lwaern-intel committed Apr 5, 2024
1 parent 6837b15 commit 7ce8717
Show file tree
Hide file tree
Showing 8 changed files with 325 additions and 156 deletions.
169 changes: 94 additions & 75 deletions lib/1.4/dml-builtins.dml

Large diffs are not rendered by default.

22 changes: 11 additions & 11 deletions lib/1.4/utility.dml
Original file line number Diff line number Diff line change
Expand Up @@ -1128,15 +1128,15 @@ template function_io_memory {
foreach b in (each function_mapped_bank in (dev)) {
if (b.function == map_info.function) {
local domain_lock_t *lock;
#if (dev.thread_aware) SIM_ACQUIRE_CELL(dev.obj, &lock);
#if (dev._thread_aware) SIM_ACQUIRE_CELL(dev.obj, &lock);
if (!b.use_io_memory) {
local map_target_t *mt = SIM_new_map_target(b._bank_obj(),
NULL, NULL);
if (!mt) {
local exception_type_t _exc = SIM_clear_exception();
log error: "failed to create map target for %s: %s",
SIM_object_name(b._bank_obj()), SIM_last_error();
#if (dev.thread_aware) SIM_RELEASE_CELL(dev.obj, &lock);
#if (dev._thread_aware) SIM_RELEASE_CELL(dev.obj, &lock);
return Sim_PE_IO_Not_Taken;
}
// hack: VT_map_target_access doesn't accept a map_info
Expand All @@ -1149,17 +1149,17 @@ template function_io_memory {
= VT_map_target_access(mt, mem_op);
SIM_set_mem_op_physical_address(mem_op, before);
SIM_free_map_target(mt);
#if (dev.thread_aware) SIM_RELEASE_CELL(dev.obj, &lock);
#if (dev._thread_aware) SIM_RELEASE_CELL(dev.obj, &lock);
return ret;
}
if (b.io_memory_access(
mem_op,
SIM_get_mem_op_physical_address(mem_op) + offset,
NULL)) {
#if (dev.thread_aware) SIM_RELEASE_CELL(dev.obj, &lock);
#if (dev._thread_aware) SIM_RELEASE_CELL(dev.obj, &lock);
return Sim_PE_No_Exception;
} else {
#if (dev.thread_aware) SIM_RELEASE_CELL(dev.obj, &lock);
#if (dev._thread_aware) SIM_RELEASE_CELL(dev.obj, &lock);
return Sim_PE_IO_Not_Taken;
}
}
Expand Down Expand Up @@ -1380,14 +1380,14 @@ template map_target is (connect, _qname) {
}
}
local domain_lock_t *lock;
#if (dev.thread_aware) SIM_ACQUIRE_TARGET(obj, &lock);
#if (dev._thread_aware) SIM_ACQUIRE_CELL(obj, &lock);
local exception_type_t exc = SIM_issue_transaction(map_target, t, addr);
local bool fail = exc != Sim_PE_No_Exception;
log info, (fail ? 2 : 4) : "%s%s %d bytes @ 0x%x in %s",
fail ? "failed to " : "",
SIM_transaction_is_read(t) ? "read" : fail ? "write" : "wrote",
SIM_transaction_size(t), addr, SIM_object_name(obj);
#if (dev.thread_aware) SIM_RELEASE_TARGET(obj, &lock);
#if (dev._thread_aware) SIM_RELEASE_CELL(obj, &lock);
return exc;
}
}
Expand Down Expand Up @@ -1451,10 +1451,10 @@ template signal_connect is (connect, post_init) {

method post_init() default {
local domain_lock_t *lock;
#if (dev.thread_aware) SIM_ACQUIRE_CELL(dev.obj, &lock);
#if (dev._thread_aware) SIM_ACQUIRE_CELL(dev.obj, &lock);
if (!SIM_is_restoring_state(dev.obj) && signal.val && signal.high)
signal.signal_raise();
#if (dev.thread_aware) SIM_RELEASE_CELL(dev.obj, &lock);
#if (dev._thread_aware) SIM_RELEASE_CELL(dev.obj, &lock);
}

method set(conf_object_t *obj) default {
Expand All @@ -1469,10 +1469,10 @@ template signal_connect is (connect, post_init) {
// currently high but the effects of the hotplug has already taken
// place so we should NOT treat it as a hotplug.
local domain_lock_t *lock;
#if (dev.thread_aware) SIM_ACQUIRE_CELL(dev.obj, &lock);
#if (dev._thread_aware) SIM_ACQUIRE_CELL(dev.obj, &lock);
local bool hotplug = SIM_object_is_configured(dev.obj)
&& !SIM_is_restoring_state(dev.obj);
#if (dev.thread_aware) SIM_RELEASE_CELL(dev.obj, &lock);
#if (dev._thread_aware) SIM_RELEASE_CELL(dev.obj, &lock);
if (hotplug && signal.val && signal.high)
signal.signal_lower();
default(obj);
Expand Down
33 changes: 18 additions & 15 deletions py/dml/c_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -1269,13 +1269,14 @@ def generate_simple_events_control_methods(device):
out('{\n', postindent = 1)
out(crep.structtype(device) + ' *_dev UNUSED = ('
+ crep.structtype(device) + '*)_obj;\n')
output_domain_lock_decl('_lock')
output_acquire_cell('_obj', '_lock')
for key in dml.globals.after_delay_infos:
out('SIM_event_cancel_time('
+ f'SIM_object_clock(_obj), {crep.get_evclass(key)}, _obj, '
+ '_simple_event_predicate, (lang_void *) &domain);\n')
output_release_cell('_obj', '_lock')
if dml.globals.after_delay_infos:
output_domain_lock_decl('_lock')
output_acquire_cell('_obj', '_lock')
for key in dml.globals.after_delay_infos:
out('SIM_event_cancel_time('
+ f'SIM_object_clock(_obj), {crep.get_evclass(key)}, _obj, '
+ '_simple_event_predicate, (lang_void *) &domain);\n')
output_release_cell('_obj', '_lock')

site = logging.SimpleSite('<_cancel_simple_events>')
by_dims = {}
Expand Down Expand Up @@ -1336,25 +1337,27 @@ def generate_register_events(device):
if not events and not dml.globals.after_delay_infos:
out('return;\n')
else:
flags = 'Sim_EC_No_Serialize' if dml.globals.thread_aware else '0'
for event in events:
if (dml.globals.dml_version == (1, 2)
and param_str(event, 'timebase') == 'stacked'
and event.dimensions > 0):
raise ICE(event, "stacked event array not supported")
for indices in event.all_indices():
out('%s%s = SIM_register_event("%s", class, 0, %s);\n'
out('%s%s = SIM_register_event("%s", class, %s, %s);\n'
% (crep.get_evclass(event),
''.join('[' + str(i) + ']' for i in indices),
event.logname_anonymized(indices),
', '.join(
cname
for (_, cname) in event_callbacks(event,
''.join('[' + str(i) + ']' for i in indices),
event.logname_anonymized(indices),
flags,
', '.join(
cname
for (_, cname) in event_callbacks(event,
indices))))
for (key, info) in dml.globals.after_delay_infos.items():
out(('%s = SIM_register_event(%s, class, 0, %s, %s, %s, %s, '
out(('%s = SIM_register_event(%s, class, %s, %s, %s, %s, %s, '
+ 'NULL);\n')
% (crep.get_evclass(key), string_literal(info.string_key),
info.cident_callback, '_destroy_simple_event_data',
flags, info.cident_callback, '_destroy_simple_event_data',
info.cident_get_value, info.cident_set_value))
out('}\n\n', preindent = -1)
splitting_point()
Expand Down
10 changes: 8 additions & 2 deletions py/dml/structure.py
Original file line number Diff line number Diff line change
Expand Up @@ -1491,6 +1491,13 @@ def mkobj2(obj, obj_specs, params, each_stmts):
for (issite, tpl) in obj_spec.templates:
if tpl.trait:
obj_traits.append((issite, tpl.trait))
# TODO remove once thread-awareness support is public.
# Determining thread-awareness via the _thread_aware param is
# cleaner, but doesn't provide is-site info.
if (obj.objtype == 'device'
and tpl.name == '_thread_aware'
and dml.globals.dml_version != (1, 2)):
report(WEXPERIMENTAL(issite, 'thread-aware device model'))

for obj_spec in obj_specs:
for (templates, spec) in obj_spec.in_eachs:
Expand Down Expand Up @@ -1956,8 +1963,7 @@ def mkobj2(obj, obj_specs, params, each_stmts):
mark_method_exported(func, name, export.site)

if dml.globals.dml_version != (1, 2):
dml.globals.thread_aware = param_bool_fixup(
obj, 'thread_aware', False)
dml.globals.thread_aware = param_bool(obj, '_thread_aware')

elif obj.objtype == 'bank':
set_confidential_object(obj)
Expand Down
49 changes: 0 additions & 49 deletions test/1.4/misc/T_thread_aware.py

This file was deleted.

115 changes: 113 additions & 2 deletions test/1.4/misc/T_thread_aware.dml → test/1.4/misc/thread_aware.dml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,112 @@ dml 1.4;
device test;

import "utility.dml";
import "simics/util/os.dml";

saved int s;

is thread_aware;
// This test should accomplish two things:
// 1. Only pass if the device is actually considered thread-aware, and is
// entered without the cell domain being taken.
// 2. Only pass if the device acquires and releases locks correctly
//
// Accomplished by two cooperative devices that have a piece of shared state:
// 1. is accomplished by manipulating the shared state without locking,
// relying on sleeps for one thread to observe the changes made by the
// other, and performing tests on that state that can only succeed if
// the two devices are entered concurrently.
// 2. is accomplished by manipulations on the shared state while holding
// an object lock; then having a device entry to inspect the
// state be blocked by an existing entry that modifies it. This blocking is
// ensured by also leveraging sleeps. The test is practically guaranteed to
// succeed only if object locking is done correctly.

/// WARNING WEXPERIMENTAL
is _thread_aware;

param init_concurrency_mode = Sim_Concurrency_Mode_Serialized;
header %{
static volatile int32 shared_state = 0;
%}

extern int32 shared_state;

connect buddy {
session int32 *state;
param configuration = "optional";
interface pulse;
}

attribute setup_main is write_only_attr {
param type = "n";
method set(attr_value_t val) throws default {
after 1 cycles: event();
}

method event() {
os_millisleep(50);
// Second resolved (due to the sleep in setup_buddy.event() being
// longer)

// This essentially serves as a check that setup_buddy.event() is
// ongoing; and thus the buddy is holding its own lock
assert shared_state == 1;
// Modify shared state without acquiring lock.
shared_state = 2;
// Then try to enter the buddy, and become blocked
buddy.pulse.pulse();
}
}

attribute setup_buddy is write_only_attr {
param type = "n";
method set(attr_value_t val) throws default {
after 1 cycles: event();
}

method event() {
// First resolved (due to the sleep in setup_main.event())
shared_state = 1;
os_millisleep(100);
// Third resolved.
assert shared_state == 2;
shared_state = 3;
// Once this is left, the object lock of the buddy will be released
}
}

implement pulse {
method pulse() {
// Last resolved, when setup_main.event() becomes unblocked and may
// enter the buddy
assert shared_state == 3;
}
}

attribute shared_state_attr {
param type = "i";
method get() -> (attr_value_t) {
return SIM_make_attr_int64(shared_state);
}
method set(attr_value_t val) throws {
shared_state = SIM_attr_integer(val);
}
}

bank b;
port p;
subdevice sd {
subdevice sd {
bank b;
port p;
}
bank b;
port p;
}

// Remainder is skeleton code stolen from 1.4/misc/notify_state.
// We have to do similar tests that object locking is done for the various ways
// the device may be entered.
// ... That, or write those tests via ctree_tests.py

header %{
#include <assert.h>
Expand Down Expand Up @@ -127,4 +227,15 @@ implement signal {
}


// port insig is signal_port;
// connect outsig is signal_connect;

// attribute test_outsig is (pseudo_attr, bool_attr) {
// method set(attr_value_t value) throws {
// default(value);
// if (this.val)
// outsig.set_level(1);
// else
// outsig.set_level(0);
// }
// }
Loading

0 comments on commit 7ce8717

Please sign in to comment.