Skip to content

Commit

Permalink
Implement selective attribute writeback using shadow memory.
Browse files Browse the repository at this point in the history
whitequark committed Jan 2, 2016
1 parent 2e33084 commit 38a99fd
Showing 7 changed files with 174 additions and 49 deletions.
16 changes: 11 additions & 5 deletions artiq/compiler/builtins.py
Original file line number Diff line number Diff line change
@@ -89,13 +89,13 @@ class TException(types.TMono):
attributes = OrderedDict([
("__name__", TStr()),
("__file__", TStr()),
("__line__", TInt(types.TValue(32))),
("__col__", TInt(types.TValue(32))),
("__line__", TInt32()),
("__col__", TInt32()),
("__func__", TStr()),
("__message__", TStr()),
("__param0__", TInt(types.TValue(64))),
("__param1__", TInt(types.TValue(64))),
("__param2__", TInt(types.TValue(64))),
("__param0__", TInt64()),
("__param1__", TInt64()),
("__param2__", TInt64()),
])

def __init__(self, name="Exception", id=0):
@@ -191,6 +191,12 @@ def is_int(typ, width=None):
else:
return types.is_mono(typ, "int")

def is_int32(typ):
return is_int(typ, types.TValue(32))

def is_int64(typ):
return is_int(typ, types.TValue(64))

def get_int_width(typ):
if is_int(typ):
return types.get_value(typ.find()["width"])
10 changes: 8 additions & 2 deletions artiq/compiler/targets.py
Original file line number Diff line number Diff line change
@@ -81,8 +81,14 @@ def compile(self, module):
print(function.as_entity(type_printer), file=sys.stderr)

llmod = module.build_llvm_ir(self)
llparsedmod = llvm.parse_assembly(str(llmod))
llparsedmod.verify()

try:
llparsedmod = llvm.parse_assembly(str(llmod))
llparsedmod.verify()
except RuntimeError:
print("====== LLVM IR DUMP (PARSE FAILED) ======", file=sys.stderr)
print(str(llmod), file=sys.stderr)
raise

if os.getenv("ARTIQ_DUMP_LLVM"):
print("====== LLVM IR DUMP ======", file=sys.stderr)
106 changes: 74 additions & 32 deletions artiq/compiler/transforms/llvm_ir_generator.py
Original file line number Diff line number Diff line change
@@ -3,10 +3,10 @@
into LLVM intermediate representation.
"""

import os, re
import os, re, types as pytypes
from collections import defaultdict
from pythonparser import ast, diagnostic
from llvmlite_artiq import ir as ll
from llvmlite_artiq import ir as ll, binding as llvm
from ...language import core as language_core
from .. import types, builtins, ir

@@ -418,26 +418,40 @@ def process(self, functions, attribute_writeback):
return self.llmodule

def emit_attribute_writeback(self):
llobjects = []
shadow_memory_dim = defaultdict(lambda: 0)

for obj_id in self.object_map:
while len(llobjects) <= obj_id:
llobjects.append(ll.Constant(llptr, None))

llobject = self.llmodule.get_global("object.{}".format(obj_id))
if llobject is not None:
llobjects[obj_id] = llobject.bitcast(llptr)

obj_ref = self.object_map.retrieve(obj_id)
if isinstance(obj_ref, type):
if isinstance(obj_ref, (pytypes.FunctionType, pytypes.MethodType)):
continue
elif isinstance(obj_ref, type):
_, typ = self.type_map[obj_ref]
else:
typ, _ = self.type_map[type(obj_ref)]

if shadow_memory_dim[typ] <= obj_id:
shadow_memory_dim[typ] = obj_id + 1

lldatalayout = llvm.create_target_data(self.llmodule.data_layout)

llrpcattrty = self.llcontext.get_identified_type("shadow.attr")
llrpcattrty.elements = [lli32, llptr, llptr]

lldescty = self.llcontext.get_identified_type("shadow.desc")
lldescty.elements = [llptr.as_pointer(), llptr, lli32, llptr]
lldescty.elements = [llrpcattrty.as_pointer().as_pointer(), lli32, llptr]

lldescs = []
for typ in shadow_memory_dim:
if "__objectid__" not in typ.attributes:
continue
assert list(typ.attributes.keys())[0] == "__objectid__"

if types.is_constructor(typ):
type_name = "class.{}".format(typ.name)
@@ -455,44 +469,72 @@ def emit_attribute_writeback(self):
llshadow.type = llshadowty.as_pointer()
llshadow.initializer = ll.Constant(llshadowty, None)

def rpc_tag_error(typ):
print(typ)
assert False

rpcattrary = list(typ.attributes.keys())[1:]
llrpcattraryty = ll.ArrayType(llptr, len(rpcattrary) + 1)
llrpcattrary = list(map(lambda attr: self.llstr_of_str(attr), rpcattrary))
def llrpcattr_of_attr(name, typ):
llty = self.llty_of_type(typ)
if isinstance(llty, ll.PointerType):
# Work around llvmlite bug where it is unable to get a C++
# object for a type if it includes an identified type in a context
# other than the default.
size = llptr.get_abi_size(lldatalayout)
else:
size = llty.get_abi_size(lldatalayout)

llrpcattrs = ll.GlobalVariable(self.llmodule, llrpcattraryty,
name="shadow.attrs.{}".format(type_name))
llrpcattrs.initializer = ll.Constant(llrpcattraryty,
llrpcattrary + [ll.Constant(llptr, None)])
llrpcattrs.linkage = 'internal'
def rpc_tag_error(typ):
print(typ)
assert False

rpctag = b""
for attr_type in list(typ.attributes.values())[1:]:
if types.is_function(attr_type) or types.is_method(attr_type):
continue
rpctag += self._rpc_tag(attr_type, error_handler=rpc_tag_error)
rpctag += b"\x00"
llrpctag = self.llstr_of_str(rpctag)
rpctag = b"Os"
if not (types.is_function(typ) or types.is_method(typ)):
rpctag += self._rpc_tag(typ, error_handler=rpc_tag_error)
else:
rpctag += b""
rpctag += b":n\x00"
llrpctag = self.llstr_of_str(rpctag)

llrpcattr = ll.GlobalVariable(self.llmodule, llrpcattrty,
name="shadow.attr.{}.{}".format(type_name, name))
llrpcattr.initializer = ll.Constant(llrpcattrty, [
ll.Constant(lli32, size),
self.llstr_of_str(rpctag),
self.llstr_of_str(name)
])
llrpcattr.global_constant = True
llrpcattr.unnamed_addr = True
llrpcattr.linkage = 'internal'

return llrpcattr

llrpcattrs = [llrpcattr_of_attr(attr, typ.attributes[attr])
for attr in typ.attributes]

llrpcattraryty = ll.ArrayType(llrpcattrty.as_pointer(), len(llrpcattrs) + 1)
llrpcattrary = ll.GlobalVariable(self.llmodule, llrpcattraryty,
name="shadow.attrs.{}".format(type_name))
llrpcattrary.initializer = ll.Constant(llrpcattraryty,
llrpcattrs + [ll.Constant(llrpcattrty.as_pointer(), None)])
llrpcattrary.global_constant = True
llrpcattrary.unnamed_addr = True
llrpcattrary.linkage = 'internal'

lldesc = ll.GlobalVariable(self.llmodule, lldescty,
name="shadow.desc.{}".format(type_name))
lldesc.initializer = ll.Constant(lldescty, [
llrpcattrs.bitcast(llptr.as_pointer()),
llrpctag,
llrpcattrary.bitcast(llrpcattrty.as_pointer().as_pointer()),
ll.Constant(lli32, shadow_memory_dim[typ]),
llshadow.bitcast(llptr)])
llshadow.bitcast(llptr)
])
lldesc.global_constant = True
lldesc.linkage = 'internal'
lldescs.append(lldesc)

llglobaldescty = ll.ArrayType(lldescty.as_pointer(), len(lldescs) + 1)
llglobaldesc = ll.GlobalVariable(self.llmodule, llglobaldescty,
name="shadow.descs")
llglobaldesc = ll.GlobalVariable(self.llmodule, llglobaldescty, name="shadow")
llglobaldesc.initializer = ll.Constant(llglobaldescty,
lldescs + [ll.Constant(lldescty.as_pointer(), None)])
# llglobaldesc.linkage = 'internal'

llobjectaryty = ll.ArrayType(llptr, len(llobjects))
llobjectary = ll.GlobalVariable(self.llmodule, llobjectaryty, name="objects")
llobjectary.initializer = ll.Constant(llobjectaryty, llobjects)

def process_function(self, func):
try:
@@ -661,10 +703,10 @@ def process_SetAttr(self, insn):
llidptr = self.llbuilder.gep(self.map(insn.object()),
[self.llindex(0), self.llindex(0)])
llid = self.llbuilder.load(llidptr, name="shadow.id")
llattrcount = ll.Constant(lli32, len(object_type.attributes) - 1)
llattrcount = ll.Constant(lli32, len(object_type.attributes))
llshadowpos = self.llbuilder.add(
self.llbuilder.mul(llid, llattrcount),
ll.Constant(lli32, self.attr_index(insn) - 1))
ll.Constant(lli32, self.attr_index(insn)))

if types.is_constructor(object_type):
shadowname = "shadow.class.{}".format(object_type.name)
15 changes: 10 additions & 5 deletions artiq/coredevice/comm_generic.py
Original file line number Diff line number Diff line change
@@ -435,7 +435,11 @@ def check(cond, expected):

def _serve_rpc(self, object_map):
service_id = self._read_int32()
service = object_map.retrieve(service_id)
if service_id == 0:
service = lambda obj, attr, value: setattr(obj, attr, value)
else:
service = object_map.retrieve(service_id)

arguments = self._receive_rpc_args(object_map, service.__defaults__)
return_tags = self._read_bytes()
logger.debug("rpc service: [%d]%r %r -> %s", service_id, service, arguments, return_tags)
@@ -444,10 +448,11 @@ def _serve_rpc(self, object_map):
result = service(*arguments)
logger.debug("rpc service: %d %r == %r", service_id, arguments, result)

self._write_header(_H2DMsgType.RPC_REPLY)
self._write_bytes(return_tags)
self._send_rpc_value(bytearray(return_tags), result, result, service)
self._write_flush()
if service_id != 0:
self._write_header(_H2DMsgType.RPC_REPLY)
self._write_bytes(return_tags)
self._send_rpc_value(bytearray(return_tags), result, result, service)
self._write_flush()
except Exception as exn:
logger.debug("rpc service: %d %r ! %r", service_id, arguments, exn)

62 changes: 59 additions & 3 deletions artiq/runtime/ksupport.c
Original file line number Diff line number Diff line change
@@ -20,6 +20,7 @@
double round(double x);

void ksupport_abort(void);
static void attribute_writeback(void *, void *);

int64_t now;

@@ -249,14 +250,22 @@ int main(void)
}

if(request->run_kernel) {
void (*kernel_init)() = request->library_info->init;
void (*kernel_run)() = request->library_info->init;
void *__bss_start = dyld_lookup("__bss_start", request->library_info);
void *_end = dyld_lookup("_end", request->library_info);
void *shadow = dyld_lookup("shadow", request->library_info);
void *objects = dyld_lookup("objects", request->library_info);

memset(__bss_start, 0, _end - __bss_start);

mailbox_send_and_wait(&load_reply);

now = now_init();
kernel_init();
kernel_run();
now_save(now);

attribute_writeback(shadow, objects);

struct msg_base finished_reply;
finished_reply.type = MESSAGE_TYPE_FINISHED;
mailbox_send_and_wait(&finished_reply);
@@ -357,7 +366,10 @@ void send_rpc(int service, const char *tag, ...)
{
struct msg_rpc_send request;

request.type = MESSAGE_TYPE_RPC_SEND;
if(service != 0)
request.type = MESSAGE_TYPE_RPC_SEND;
else
request.type = MESSAGE_TYPE_RPC_BATCH;
request.service = service;
request.tag = tag;
va_start(request.args, tag);
@@ -393,6 +405,50 @@ int recv_rpc(void *slot) {
}
}

struct shadow_attr {
uint32_t size;
const char *tag;
const char *name;
};

struct shadow_desc {
struct shadow_attr **attributes;
uint32_t object_count;
uint8_t *shadow;
};

void attribute_writeback(void *udescs, void *uobjects) {
struct shadow_desc **descs = (struct shadow_desc **)udescs;
void **objects = (void **)uobjects;

while(*descs) {
struct shadow_desc *desc = *descs++;

size_t attr_count = 0;
for(struct shadow_attr **attr = desc->attributes; *attr; attr++)
attr_count++;

for(int object_id = 0; object_id < desc->object_count; object_id++) {
uint8_t *shadow = &desc->shadow[object_id * attr_count];
void *object = objects[object_id];

if(object == NULL) continue;

size_t offset = 0;
for(int attr_index = 0; attr_index < attr_count; attr_index++) {
struct shadow_attr *attr = desc->attributes[attr_index];

if(shadow[attr_index]) {
uintptr_t value = (uintptr_t)object + offset;
send_rpc(0, attr->tag, &object, &attr->name, value);
}

offset += attr->size;
}
}
}
}

void lognonl(const char *fmt, ...)
{
struct msg_log request;
8 changes: 8 additions & 0 deletions artiq/runtime/messages.h
Original file line number Diff line number Diff line change
@@ -17,6 +17,7 @@ enum {
MESSAGE_TYPE_RPC_SEND,
MESSAGE_TYPE_RPC_RECV_REQUEST,
MESSAGE_TYPE_RPC_RECV_REPLY,
MESSAGE_TYPE_RPC_BATCH,
MESSAGE_TYPE_LOG,

MESSAGE_TYPE_BRG_READY,
@@ -97,6 +98,13 @@ struct msg_rpc_recv_reply {
struct artiq_exception *exception;
};

struct msg_rpc_batch {
int type;
int service;
const char *tag;
void *ptr;
};

struct msg_log {
int type;
const char *fmt;
6 changes: 4 additions & 2 deletions artiq/runtime/session.c
Original file line number Diff line number Diff line change
@@ -962,7 +962,8 @@ static int process_kmsg(struct msg_base *umsg)
break;
}

case MESSAGE_TYPE_RPC_SEND: {
case MESSAGE_TYPE_RPC_SEND:
case MESSAGE_TYPE_RPC_BATCH: {
struct msg_rpc_send *msg = (struct msg_rpc_send *)umsg;

if(!send_rpc_request(msg->service, msg->tag, msg->args)) {
@@ -971,7 +972,8 @@ static int process_kmsg(struct msg_base *umsg)
return 0; // restart session
}

user_kernel_state = USER_KERNEL_WAIT_RPC;
if(msg->type == MESSAGE_TYPE_RPC_SEND)
user_kernel_state = USER_KERNEL_WAIT_RPC;
mailbox_acknowledge();
break;
}

0 comments on commit 38a99fd

Please sign in to comment.