Skip to content

Commit 148e6f7

Browse files
committed
Make log the log level configurable per module
This overloads the meaning of RUST_LOG to also allow 'module.submodule' or 'module.somethingelse=2' forms. The first turn on all logging for a module (loglevel 3), the second sets its loglevel to 2. Log levels are: 0: Show only errors 1: Errors and warnings 2: Errors, warnings, and notes 3: Everything, including debug logging Right now, since we only have one 'log' operation, everything happens at level 1 (warning), so the only meaningful thing that can be done with the new RUST_LOG support is disable logging (=0) for some modules. TODOS: * Language support for logging at a specific level * Also add a log level field to tasks, query the current task as well as the current module before logging (log if one of them allows it) * Revise the C logging API to conform to this set-up (globals for per-module log level, query the task level before logging, stop using a global mask) Implementation notes: Crates now contain two extra data structures. A 'module map' that contains names and pointers to the module-log-level globals for each module in the crate that logs, and a 'crate map' that points at the crate's module map, as well as at the crate maps of all external crates it depends on. These are walked by the runtime (in rust_crate.cpp) to set the currect log levels based on RUST_LOG. These module log globals are allocated as-needed whenever a log expression is encountered, and their location is hard-coded into the logging code, which compares the current level to the log statement's level, and skips over all logging code when it is lower.
1 parent 0bf75a2 commit 148e6f7

File tree

5 files changed

+206
-29
lines changed

5 files changed

+206
-29
lines changed

src/comp/middle/trans.rs

Lines changed: 111 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -108,12 +108,14 @@ state type crate_ctxt = rec(session.session sess,
108108
hashmap[ast.def_id, ValueRef] consts,
109109
hashmap[ast.def_id,()] obj_methods,
110110
hashmap[@ty.t, @tydesc_info] tydescs,
111+
hashmap[str, ValueRef] module_data,
111112
@glue_fns glues,
112113
namegen names,
113114
vec[str] path,
114115
std.sha1.sha1 sha);
115116

116117
type local_ctxt = rec(vec[str] path,
118+
vec[str] module_path,
117119
vec[ast.ty_param] obj_typarams,
118120
vec[ast.obj_field] obj_fields,
119121
@crate_ctxt ccx);
@@ -426,7 +428,8 @@ fn T_crate(type_names tn) -> TypeRef {
426428
T_int(), // int n_rust_syms
427429
T_int(), // int n_c_syms
428430
T_int(), // int n_libs
429-
T_int() // uintptr_t abi_tag
431+
T_int(), // uintptr_t abi_tag
432+
T_int() // void* crate_map
430433
));
431434
tn.associate(s, t);
432435
ret t;
@@ -909,6 +912,11 @@ fn C_struct(vec[ValueRef] elts) -> ValueRef {
909912
False);
910913
}
911914

915+
fn C_array(TypeRef ty, vec[ValueRef] elts) -> ValueRef {
916+
ret llvm.LLVMConstArray(ty, _vec.buf[ValueRef](elts),
917+
_vec.len[ValueRef](elts));
918+
}
919+
912920
fn decl_fn(ModuleRef llmod, str name, uint cc, TypeRef llty) -> ValueRef {
913921
let ValueRef llfn =
914922
llvm.LLVMAddFunction(llmod, _str.buf(name), llty);
@@ -4925,8 +4933,28 @@ fn load_if_immediate(@block_ctxt cx, ValueRef v, @ty.t t) -> ValueRef {
49254933
}
49264934

49274935
fn trans_log(@block_ctxt cx, @ast.expr e) -> result {
4928-
4929-
auto sub = trans_expr(cx, e);
4936+
auto lcx = cx.fcx.lcx;
4937+
auto modname = _str.connect(lcx.module_path, ".");
4938+
auto global;
4939+
if (lcx.ccx.module_data.contains_key(modname)) {
4940+
global = lcx.ccx.module_data.get(modname);
4941+
} else {
4942+
global = llvm.LLVMAddGlobal(lcx.ccx.llmod, T_int(),
4943+
_str.buf("_rust_mod_log_" + modname));
4944+
llvm.LLVMSetGlobalConstant(global, False);
4945+
llvm.LLVMSetInitializer(global, C_null(T_int()));
4946+
llvm.LLVMSetLinkage(global, lib.llvm.LLVMInternalLinkage
4947+
as llvm.Linkage);
4948+
lcx.ccx.module_data.insert(modname, global);
4949+
}
4950+
4951+
auto log_cx = new_sub_block_ctxt(cx, "log");
4952+
auto after_cx = new_sub_block_ctxt(cx, "after");
4953+
auto load = cx.build.Load(global);
4954+
auto test = cx.build.ICmp(lib.llvm.LLVMIntSGE, load, C_int(1));
4955+
cx.build.CondBr(test, log_cx.llbb, after_cx.llbb);
4956+
4957+
auto sub = trans_expr(log_cx, e);
49304958
auto e_ty = ty.expr_ty(e);
49314959

49324960
if (ty.type_is_fp(e_ty)) {
@@ -4945,33 +4973,34 @@ fn trans_log(@block_ctxt cx, @ast.expr e) -> result {
49454973
}
49464974
}
49474975
if (is32bit) {
4948-
ret trans_upcall(sub.bcx,
4949-
"upcall_log_float",
4950-
vec(sub.val));
4976+
trans_upcall(sub.bcx,
4977+
"upcall_log_float",
4978+
vec(sub.val)).bcx.build.Br(after_cx.llbb);
49514979
} else {
49524980
auto tmp = alloca(sub.bcx, tr);
49534981
sub.bcx.build.Store(sub.val, tmp);
49544982
auto v = vp2i(sub.bcx, tmp);
4955-
ret trans_upcall(sub.bcx,
4956-
"upcall_log_double",
4957-
vec(v));
4983+
trans_upcall(sub.bcx,
4984+
"upcall_log_double",
4985+
vec(v)).bcx.build.Br(after_cx.llbb);
49584986
}
4959-
}
4960-
4961-
alt (e_ty.struct) {
4962-
case (ty.ty_str) {
4963-
auto v = vp2i(sub.bcx, sub.val);
4964-
ret trans_upcall(sub.bcx,
4987+
} else {
4988+
alt (e_ty.struct) {
4989+
case (ty.ty_str) {
4990+
auto v = vp2i(sub.bcx, sub.val);
4991+
trans_upcall(sub.bcx,
49654992
"upcall_log_str",
4966-
vec(v));
4967-
}
4968-
case (_) {
4969-
ret trans_upcall(sub.bcx,
4993+
vec(v)).bcx.build.Br(after_cx.llbb);
4994+
}
4995+
case (_) {
4996+
trans_upcall(sub.bcx,
49704997
"upcall_log_int",
4971-
vec(sub.val));
4998+
vec(sub.val)).bcx.build.Br(after_cx.llbb);
4999+
}
49725000
}
49735001
}
4974-
fail;
5002+
5003+
ret res(after_cx, C_nil());
49755004
}
49765005

49775006
fn trans_check_expr(@block_ctxt cx, @ast.expr e) -> result {
@@ -6114,7 +6143,9 @@ fn trans_item(@local_ctxt cx, &ast.item item) {
61146143
trans_obj(sub_cx, ob, oid.ctor, tps, ann);
61156144
}
61166145
case (ast.item_mod(?name, ?m, _)) {
6117-
auto sub_cx = extend_path(cx, name);
6146+
auto sub_cx = @rec(path = cx.path + vec(name),
6147+
module_path = cx.module_path + vec(name)
6148+
with *cx);
61186149
trans_mod(sub_cx, m);
61196150
}
61206151
case (ast.item_tag(?name, ?variants, ?tps, ?tag_id, _)) {
@@ -6593,7 +6624,8 @@ fn create_typedefs(@crate_ctxt cx) {
65936624
llvm.LLVMAddTypeName(cx.llmod, _str.buf("tydesc"), T_tydesc(cx.tn));
65946625
}
65956626

6596-
fn create_crate_constant(ValueRef crate_ptr, @glue_fns glues) {
6627+
fn create_crate_constant(ValueRef crate_ptr, @glue_fns glues,
6628+
ValueRef crate_map) {
65976629

65986630
let ValueRef crate_addr = p2i(crate_ptr);
65996631

@@ -6608,7 +6640,7 @@ fn create_crate_constant(ValueRef crate_ptr, @glue_fns glues) {
66086640

66096641
let ValueRef crate_val =
66106642
C_struct(vec(C_null(T_int()), // ptrdiff_t image_base_off
6611-
p2i(crate_ptr), // uintptr_t self_addr
6643+
p2i(crate_ptr), // uintptr_t self_addr
66126644
C_null(T_int()), // ptrdiff_t debug_abbrev_off
66136645
C_null(T_int()), // size_t debug_abbrev_sz
66146646
C_null(T_int()), // ptrdiff_t debug_info_off
@@ -6621,7 +6653,8 @@ fn create_crate_constant(ValueRef crate_ptr, @glue_fns glues) {
66216653
C_null(T_int()), // int n_rust_syms
66226654
C_null(T_int()), // int n_c_syms
66236655
C_null(T_int()), // int n_libs
6624-
C_int(abi.abi_x86_rustc_fastcall) // uintptr_t abi_tag
6656+
C_int(abi.abi_x86_rustc_fastcall), // uintptr_t abi_tag
6657+
p2i(crate_map) // void* crate_map
66256658
));
66266659

66276660
llvm.LLVMSetInitializer(crate_ptr, crate_val);
@@ -7159,6 +7192,54 @@ fn make_common_glue(str output, bool optimize,
71597192
run_passes(llmod, optimize, output, ot);
71607193
}
71617194

7195+
fn create_module_map(@crate_ctxt ccx) -> ValueRef {
7196+
auto elttype = T_struct(vec(T_int(), T_int()));
7197+
auto maptype = T_array(elttype, ccx.module_data.size() + 1u);
7198+
auto map = llvm.LLVMAddGlobal(ccx.llmod, maptype,
7199+
_str.buf("_rust_mod_map"));
7200+
llvm.LLVMSetLinkage(map, lib.llvm.LLVMInternalLinkage as llvm.Linkage);
7201+
let vec[ValueRef] elts = vec();
7202+
for each (@tup(str, ValueRef) item in ccx.module_data.items()) {
7203+
auto elt = C_struct(vec(p2i(C_cstr(ccx, item._0)), p2i(item._1)));
7204+
_vec.push[ValueRef](elts, elt);
7205+
}
7206+
auto term = C_struct(vec(C_int(0), C_int(0)));
7207+
_vec.push[ValueRef](elts, term);
7208+
llvm.LLVMSetInitializer(map, C_array(elttype, elts));
7209+
ret map;
7210+
}
7211+
7212+
fn crate_name(@crate_ctxt ccx, str deflt) -> str {
7213+
for (@ast.meta_item item in ccx.sess.get_metadata()) {
7214+
if (_str.eq(item.node.name, "name")) {
7215+
ret item.node.value;
7216+
}
7217+
}
7218+
ret deflt;
7219+
}
7220+
7221+
// FIXME use hashed metadata instead of crate names once we have that
7222+
fn create_crate_map(@crate_ctxt ccx) -> ValueRef {
7223+
let vec[ValueRef] subcrates = vec();
7224+
auto i = 1;
7225+
while (ccx.sess.has_external_crate(i)) {
7226+
auto name = ccx.sess.get_external_crate(i).name;
7227+
auto cr = llvm.LLVMAddGlobal(ccx.llmod, T_int(),
7228+
_str.buf("_rust_crate_map_" + name));
7229+
_vec.push[ValueRef](subcrates, p2i(cr));
7230+
i += 1;
7231+
}
7232+
_vec.push[ValueRef](subcrates, C_int(0));
7233+
auto sym_name = "_rust_crate_map_" + crate_name(ccx, "__none__");
7234+
auto arrtype = T_array(T_int(), _vec.len[ValueRef](subcrates));
7235+
auto maptype = T_struct(vec(T_int(), arrtype));
7236+
auto map = llvm.LLVMAddGlobal(ccx.llmod, maptype, _str.buf(sym_name));
7237+
llvm.LLVMSetLinkage(map, lib.llvm.LLVMExternalLinkage as llvm.Linkage);
7238+
llvm.LLVMSetInitializer(map, C_struct(vec(p2i(create_module_map(ccx)),
7239+
C_array(T_int(), subcrates))));
7240+
ret map;
7241+
}
7242+
71627243
fn trans_crate(session.session sess, @ast.crate crate,
71637244
&ty.type_cache type_cache, str output, bool shared,
71647245
bool optimize, output_type ot) {
@@ -7203,25 +7284,28 @@ fn trans_crate(session.session sess, @ast.crate crate,
72037284
consts = new_def_hash[ValueRef](),
72047285
obj_methods = new_def_hash[()](),
72057286
tydescs = tydescs,
7287+
module_data = new_str_hash[ValueRef](),
72067288
glues = glues,
72077289
names = namegen(0),
72087290
path = pth,
72097291
sha = std.sha1.mk_sha1());
72107292
auto cx = @rec(path=pth,
7293+
module_path=vec(crate_name(ccx, "main")),
72117294
obj_typarams = obj_typarams,
72127295
obj_fields = obj_fields,
72137296
ccx = ccx);
72147297

7215-
create_typedefs(cx.ccx);
7298+
create_typedefs(ccx);
72167299

72177300
collect_items(cx, crate);
72187301
collect_tag_ctors(cx, crate);
72197302
trans_constants(cx, crate);
72207303
trans_mod(cx, crate.node.module);
72217304
trans_vec_append_glue(cx);
7305+
auto crate_map = create_crate_map(ccx);
72227306
if (!shared) {
72237307
trans_main_fn(cx, crate_ptr);
7224-
create_crate_constant(crate_ptr, ccx.glues);
7308+
create_crate_constant(crate_ptr, ccx.glues, crate_map);
72257309
}
72267310

72277311
// Translate the metadata.

src/rt/rust.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ extern "C" CDECL int
8080
rust_start(uintptr_t main_fn, rust_crate const *crate, int argc,
8181
char **argv) {
8282

83+
crate->update_log_settings(getenv("RUST_LOG"));
8384
rust_srv *srv = new rust_srv();
8485
rust_kernel *kernel = new rust_kernel(srv);
8586
kernel->start();
@@ -102,6 +103,7 @@ rust_start(uintptr_t main_fn, rust_crate const *crate, int argc,
102103
dom->root_task->start(crate->get_exit_task_glue(),
103104
crate->abi_tag, main_fn,
104105
(uintptr_t)&main_args, sizeof(main_args));
106+
105107
int ret = dom->start_main_loop();
106108
delete args;
107109
kernel->destroy_domain(dom);

src/rt/rust_crate.cpp

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,92 @@ rust_crate::get_debug_abbrev(rust_dom *dom) const {
6565
return mem_area(dom, 0, 0);
6666
}
6767

68+
struct mod_entry {
69+
const char* name;
70+
int* state;
71+
};
72+
73+
struct cratemap {
74+
mod_entry* entries;
75+
cratemap* children[1];
76+
};
77+
78+
struct log_directive {
79+
char* name;
80+
size_t level;
81+
};
82+
83+
const size_t max_log_directives = 255;
84+
85+
size_t parse_logging_spec(char* spec, log_directive* dirs) {
86+
size_t dir = 0;
87+
while (dir < max_log_directives && *spec) {
88+
char* start = spec;
89+
char cur;
90+
while (true) {
91+
cur = *spec;
92+
if (cur == ',' || cur == '=' || cur == '\0') {
93+
if (start == spec) {spec++; break;}
94+
*spec = '\0';
95+
spec++;
96+
size_t level = 3;
97+
if (cur == '=') {
98+
level = *spec - '0';
99+
if (level > 3) level = 1;
100+
if (*spec) ++spec;
101+
}
102+
dirs[dir].name = start;
103+
dirs[dir++].level = level;
104+
break;
105+
}
106+
spec++;
107+
}
108+
}
109+
return dir;
110+
}
111+
112+
void update_crate_map(cratemap* map, log_directive* dirs, size_t n_dirs) {
113+
// First update log levels for this crate
114+
for (mod_entry* cur = map->entries; cur->name; cur++) {
115+
size_t level = 1, longest_match = 0;
116+
for (size_t d = 0; d < n_dirs; d++) {
117+
if (strstr(cur->name, dirs[d].name) == cur->name &&
118+
strlen(dirs[d].name) > longest_match) {
119+
longest_match = strlen(dirs[d].name);
120+
level = dirs[d].level;
121+
}
122+
}
123+
*cur->state = level;
124+
}
125+
126+
// Then recurse on linked crates
127+
for (size_t i = 0; map->children[i]; i++) {
128+
update_crate_map(map->children[i], dirs, n_dirs);
129+
}
130+
}
131+
132+
void rust_crate::update_log_settings(char* settings) const {
133+
// Only try this if the crate was generated by Rustc, not rustboot
134+
if (image_base_off) return;
135+
136+
// This is a rather ugly parser for strings in the form
137+
// "crate1,crate2.mod3,crate3.x=2". Log levels range 0=err, 1=warn,
138+
// 2=info, 3=debug. Default is 1. Words without an '=X' part set the log
139+
// level for that module (and submodules) to 3.
140+
char* buffer = NULL;
141+
log_directive dirs[256];
142+
size_t dir = 0;
143+
if (settings) {
144+
buffer = (char*)malloc(strlen(settings));
145+
strcpy(buffer, settings);
146+
dir = parse_logging_spec(buffer, &dirs[0]);
147+
}
148+
149+
update_crate_map((cratemap*)crate_map, &dirs[0], dir);
150+
151+
free(buffer);
152+
}
153+
68154
//
69155
// Local Variables:
70156
// mode: C++

src/rt/rust_internal.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,9 @@ class rust_crate {
248248
size_t n_libs;
249249

250250
uintptr_t abi_tag;
251+
// FIXME: not generated by rustboot, should only be accessed in crates
252+
// generated by rustc.
253+
void* crate_map;
251254

252255
// Crates are immutable, constructed by the compiler.
253256

@@ -259,6 +262,8 @@ class rust_crate {
259262
uintptr_t get_gc_glue() const;
260263
uintptr_t get_exit_task_glue() const;
261264

265+
void update_log_settings(char* settings) const;
266+
262267
struct mem_area
263268
{
264269
rust_dom *dom;

src/rt/rust_log.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <stdlib.h>
1010
#include <string.h>
1111

12+
// FIXME somehow unify this with the parsing happening in rust_crate.cpp
1213
static uint32_t
1314
read_type_bit_mask() {
1415
uint32_t bits = rust_log::ULOG | rust_log::ERR;
@@ -18,14 +19,13 @@ read_type_bit_mask() {
1819
str[0] = ',';
1920
strcpy(str + 1, env_str);
2021

21-
bits = 0;
22+
bits = rust_log::ULOG;
2223
bits |= strstr(str, ",err") ? rust_log::ERR : 0;
2324
bits |= strstr(str, ",mem") ? rust_log::MEM : 0;
2425
bits |= strstr(str, ",comm") ? rust_log::COMM : 0;
2526
bits |= strstr(str, ",task") ? rust_log::TASK : 0;
2627
bits |= strstr(str, ",up") ? rust_log::UPCALL : 0;
2728
bits |= strstr(str, ",dom") ? rust_log::DOM : 0;
28-
bits |= strstr(str, ",ulog") ? rust_log::ULOG : 0;
2929
bits |= strstr(str, ",trace") ? rust_log::TRACE : 0;
3030
bits |= strstr(str, ",dwarf") ? rust_log::DWARF : 0;
3131
bits |= strstr(str, ",cache") ? rust_log::CACHE : 0;

0 commit comments

Comments
 (0)