summaryrefslogtreecommitdiff
path: root/src/util/perf/u_trace.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/perf/u_trace.py')
-rw-r--r--src/util/perf/u_trace.py526
1 files changed, 426 insertions, 100 deletions
diff --git a/src/util/perf/u_trace.py b/src/util/perf/u_trace.py
index d0d99c828ee..34796a4b1a1 100644
--- a/src/util/perf/u_trace.py
+++ b/src/util/perf/u_trace.py
@@ -22,16 +22,20 @@
#
from mako.template import Template
+from mako import exceptions
from collections import namedtuple
-from enum import Flag, auto
+from enum import IntEnum
import os
TRACEPOINTS = {}
+TRACEPOINTS_TOGGLES = {}
class Tracepoint(object):
"""Class that represents all the information about a tracepoint
"""
- def __init__(self, name, args=[], tp_struct=None, tp_print=None, tp_perfetto=None):
+ def __init__(self, name, args=[], toggle_name=None,
+ tp_struct=None, tp_print=None, tp_perfetto=None,
+ tp_markers=None, tp_flags=[], need_cs_param=True):
"""Parameters:
- name: the tracepoint name, a tracepoint function with the given
@@ -42,25 +46,76 @@ class Tracepoint(object):
- tp_print: (optional) array of format string followed by expressions
- tp_perfetto: (optional) driver provided callback which can generate
perfetto events
+ - tp_markers: (optional) driver provided printf-style callback which can
+ generate CS markers, this requires 'need_cs_param' as the first param
+ is the CS that the label should be emitted into
+ - need_cs_param: whether tracepoint functions need an additional cs
+ parameter.
"""
assert isinstance(name, str)
assert isinstance(args, list)
assert name not in TRACEPOINTS
+ def needs_storage(a):
+ if a.c_format is None:
+ return False
+ if a.is_indirect:
+ return False
+ return True
+
self.name = name
self.args = args
- if tp_struct is None:
- tp_struct = args
- self.tp_struct = tp_struct
- self.tp_print = tp_print
+ # For storage data, include all the specified tp_struct by the caller
+ # as well as arguments needing storage
+ self.tp_struct = []
+ if tp_struct is not None:
+ self.tp_struct += tp_struct
+ self.tp_struct += [x for x in args if needs_storage(x)]
+ # For printing, include all the arguments & tp_struct elements that
+ # have a format printer
+ self.tp_print = [x for x in args if x.c_format is not None]
+ if tp_struct is not None:
+ self.tp_print += [x for x in tp_struct if x.c_format is not None]
+
+ self.has_variable_arg = False
+ for arg in self.tp_struct:
+ if arg.length_arg != None and not arg.length_arg.isdigit():
+ self.has_variable_arg = True
+ break
+ self.tp_print_custom = tp_print
+
+ # Compute the offset of each indirect argument
+ self.indirect_args = [x for x in args if x.is_indirect]
+ indirect_sizes = []
+ for indirect in self.indirect_args:
+ indirect.indirect_offset = ' + '.join(indirect_sizes) if len(indirect_sizes) > 0 else 0
+ indirect_sizes.append(f"sizeof({indirect.type}")
+
self.tp_perfetto = tp_perfetto
+ self.tp_markers = tp_markers
+ self.tp_flags = tp_flags
+ self.toggle_name = toggle_name
+ self.need_cs_param = need_cs_param
TRACEPOINTS[name] = self
+ if toggle_name is not None and toggle_name not in TRACEPOINTS_TOGGLES:
+ TRACEPOINTS_TOGGLES[toggle_name] = len(TRACEPOINTS_TOGGLES)
+
+ def can_generate_print(self):
+ return self.args is not None and len(self.args) > 0
+
+ def enabled_expr(self, trace_toggle_name):
+ if trace_toggle_name is None:
+ return "true"
+ assert self.toggle_name is not None
+ return "({0} & {1}_{2})".format(trace_toggle_name,
+ trace_toggle_name.upper(),
+ self.toggle_name.upper())
class TracepointArgStruct():
"""Represents struct that is being passed as an argument
"""
- def __init__(self, type, var):
+ def __init__(self, type, var, c_format=None, fields=[], is_indirect=False):
"""Parameters:
- type: argument's C type.
@@ -71,11 +126,36 @@ class TracepointArgStruct():
self.type = type
self.var = var
+ self.name = var
+ self.is_indirect = is_indirect
+ self.indirect_offset = 0
+ self.is_struct = True
+ self.c_format = c_format
+ self.fields = fields
+ self.to_prim_type = None
+ self.perfetto_field = None
+
+ if self.is_indirect:
+ self.func_param = f"struct u_trace_address {self.var}"
+ else:
+ self.func_param = f"{self.type} {self.var}"
+
+ def value_expr(self, entry_name):
+ ret = None
+ if self.is_struct:
+ if self.is_indirect:
+ ret = ", ".join([f"__{self.name}->{f}" for f in self.fields])
+ else:
+ ret = ", ".join([f"{entry_name}->{self.name}.{f}" for f in self.fields])
+ else:
+ ret = f"{entry_name}->{self.name}"
+ return ret
class TracepointArg(object):
"""Class that represents either an argument being passed or a field in a struct
"""
- def __init__(self, type, var, c_format, name=None, to_prim_type=None):
+ def __init__(self, type, var, c_format=None, name=None, to_prim_type=None,
+ length_arg=None, copy_func=None, is_indirect=False, perfetto_field=None):
"""Parameters:
- type: argument's C type.
@@ -85,10 +165,12 @@ class TracepointArg(object):
be displayed in output or perfetto, otherwise var will be used.
- to_prim_type: (optional) C function to convert from arg's type to a type
compatible with c_format.
+ - length_arg: whether this argument is a variable length array
+ - perfetto_field: Whether the argument should be set to a perfetto field
+ with the given name, as opposed to attached with add_extra_data().
"""
assert isinstance(type, str)
assert isinstance(var, str)
- assert isinstance(c_format, str)
self.type = type
self.var = var
@@ -97,18 +179,52 @@ class TracepointArg(object):
name = var
self.name = name
self.to_prim_type = to_prim_type
+ self.length_arg = length_arg
+ self.copy_func = copy_func
+ self.perfetto_field = perfetto_field
+
+ self.is_struct = False
+ self.is_indirect = is_indirect
+ self.indirect_offset = 0
+
+ if self.is_indirect:
+ pass
+ elif self.type == "str":
+ if self.length_arg and self.length_arg.isdigit():
+ self.struct_member = f"char {self.name}[{length_arg} + 1]"
+ else:
+ self.struct_member = f"char {self.name}[0]"
+ else:
+ self.struct_member = f"{self.type} {self.name}"
+
+ if self.is_indirect:
+ self.func_param = f"struct u_trace_address {self.var}"
+ elif self.type == "str":
+ self.func_param = f"const char *{self.var}"
+ else:
+ self.func_param = f"{self.type} {self.var}"
+
+ def value_expr(self, entry_name):
+ if self.is_indirect:
+ ret = f"*__{self.name}"
+ else:
+ ret = f"{entry_name}->{self.name}"
+ if not self.is_struct and self.to_prim_type:
+ ret = self.to_prim_type.format(ret)
+ return ret
HEADERS = []
-class HeaderScope(Flag):
- HEADER = auto()
- SOURCE = auto()
+class HeaderScope(IntEnum):
+ HEADER = (1 << 0)
+ SOURCE = (1 << 1)
+ PERFETTO = (1 << 2)
class Header(object):
"""Class that represents a header file dependency of generated tracepoints
"""
- def __init__(self, hdr, scope=HeaderScope.HEADER|HeaderScope.SOURCE):
+ def __init__(self, hdr, scope=HeaderScope.HEADER):
"""Parameters:
- hdr: the required header path
@@ -173,50 +289,81 @@ extern "C" {
${declaration.decl};
% endfor
+% if trace_toggle_name is not None:
+enum ${trace_toggle_name.lower()} {
+% for toggle_name, config_id in TRACEPOINTS_TOGGLES.items():
+ ${trace_toggle_name.upper()}_${toggle_name.upper()} = 1ull << ${config_id},
+% endfor
+};
+
+extern uint64_t ${trace_toggle_name};
+
+void ${trace_toggle_name}_config_variable(void);
+% endif
+
% for trace_name, trace in TRACEPOINTS.items():
+
/*
* ${trace_name}
*/
struct trace_${trace_name} {
% for arg in trace.tp_struct:
- ${arg.type} ${arg.name};
+ ${arg.struct_member};
% endfor
-% if len(trace.args) == 0:
-#ifdef __cplusplus
- /* avoid warnings about empty struct size mis-match in C vs C++..
- * the size mis-match is harmless because (a) nothing will deref
- * the empty struct, and (b) the code that cares about allocating
- * sizeof(struct trace_${trace_name}) (and wants this to be zero
- * if there is no payload) is C
- */
- uint8_t dummy;
+% if len(trace.tp_struct) == 0:
+#ifdef __cplusplus
+ /* avoid warnings about empty struct size mis-match in C vs C++..
+ * the size mis-match is harmless because (a) nothing will deref
+ * the empty struct, and (b) the code that cares about allocating
+ * sizeof(struct trace_${trace_name}) (and wants this to be zero
+ * if there is no payload) is C
+ */
+ uint8_t dummy;
#endif
% endif
};
% if trace.tp_perfetto is not None:
#ifdef HAVE_PERFETTO
-void ${trace.tp_perfetto}(${ctx_param}, uint64_t ts_ns, const void *flush_data, const struct trace_${trace_name} *payload);
+void ${trace.tp_perfetto}(
+ ${ctx_param},
+ uint64_t ts_ns,
+ uint16_t tp_idx,
+ const void *flush_data,
+ const struct trace_${trace_name} *payload,
+ const void *indirect_data);
#endif
% endif
-void __trace_${trace_name}(struct u_trace *ut, void *cs
+void __trace_${trace_name}(
+ struct u_trace *ut
+ , enum u_trace_type enabled_traces
+% if trace.need_cs_param:
+ , void *cs
+% endif
% for arg in trace.args:
- , ${arg.type} ${arg.var}
+ , ${arg.func_param}
% endfor
);
-static inline void trace_${trace_name}(struct u_trace *ut, void *cs
+static ALWAYS_INLINE void trace_${trace_name}(
+ struct u_trace *ut
+% if trace.need_cs_param:
+ , void *cs
+% endif
% for arg in trace.args:
- , ${arg.type} ${arg.var}
+ , ${arg.func_param}
% endfor
) {
-% if trace.tp_perfetto is not None:
- if (!unlikely(ut->enabled || ut_perfetto_enabled))
-% else:
- if (!unlikely(ut->enabled))
-% endif
+ enum u_trace_type enabled_traces = p_atomic_read_relaxed(&ut->utctx->enabled_traces);
+ if (!unlikely(enabled_traces != 0 &&
+ ${trace.enabled_expr(trace_toggle_name)}))
return;
- __trace_${trace_name}(ut, cs
+ __trace_${trace_name}(
+ ut
+ , enabled_traces
+% if trace.need_cs_param:
+ , cs
+% endif
% for arg in trace.args:
- , ${arg.var}
+ , ${arg.var}
% endfor
);
}
@@ -252,92 +399,248 @@ src_template = """\
* IN THE SOFTWARE.
*/
+#include "${hdr}"
+
% for header in HEADERS:
#include "${header.hdr}"
% endfor
-#include "${hdr}"
-
#define __NEEDS_TRACE_PRIV
+#include "util/u_debug.h"
#include "util/perf/u_trace_priv.h"
-% for trace_name, trace in TRACEPOINTS.items():
+% if trace_toggle_name is not None:
+static const struct debug_control config_control[] = {
+% for toggle_name in TRACEPOINTS_TOGGLES.keys():
+ { "${toggle_name}", ${trace_toggle_name.upper()}_${toggle_name.upper()}, },
+% endfor
+ { NULL, 0, },
+};
+uint64_t ${trace_toggle_name} = 0;
+
+static void
+${trace_toggle_name}_variable_once(void)
+{
+ uint64_t default_value = 0
+% for name in trace_toggle_defaults:
+ | ${trace_toggle_name.upper()}_${name.upper()}
+% endfor
+ ;
+
+ ${trace_toggle_name} =
+ parse_enable_string(getenv("${trace_toggle_name.upper()}"),
+ default_value,
+ config_control);
+}
+
+void
+${trace_toggle_name}_config_variable(void)
+{
+ static once_flag process_${trace_toggle_name}_variable_flag = ONCE_FLAG_INIT;
+
+ call_once(&process_${trace_toggle_name}_variable_flag,
+ ${trace_toggle_name}_variable_once);
+}
+% endif
+
+% for index, (trace_name, trace) in enumerate(TRACEPOINTS.items()):
/*
* ${trace_name}
*/
-% if trace.args is not None and len(trace.args) > 0:
-static void __print_${trace_name}(FILE *out, const void *arg) {
+ % if trace.can_generate_print():
+static void __print_${trace_name}(FILE *out, const void *arg, const void *indirect) {
+ % if len(trace.tp_struct) > 0:
const struct trace_${trace_name} *__entry =
(const struct trace_${trace_name} *)arg;
-% if trace.tp_print is not None:
- fprintf(out, "${trace.tp_print[0]}\\n"
-% for arg in trace.tp_print[1:]:
+ % endif
+ % for arg in trace.indirect_args:
+ const ${arg.type} *__${arg.name} = (const ${arg.type} *) ((char *)indirect + ${arg.indirect_offset});
+ % endfor
+ % if trace.tp_print_custom is not None:
+ fprintf(out, "${trace.tp_print_custom[0]}\\n"
+ % for arg in trace.tp_print_custom[1:]:
, ${arg}
-% endfor
-% else:
+ % endfor
+ % else:
fprintf(out, ""
-% for arg in trace.tp_struct:
+ % for arg in trace.tp_print:
"${arg.name}=${arg.c_format}, "
-% endfor
+ % endfor
"\\n"
-% for arg in trace.tp_struct:
- % if arg.to_prim_type:
- ,${arg.to_prim_type.format('__entry->' + arg.name)}
- % else:
- ,__entry->${arg.name}
- % endif
-% endfor
-%endif
+ % for arg in trace.tp_print:
+ ,${arg.value_expr("__entry")}
+ % endfor
+ % endif
+ );
+}
+
+static void __print_json_${trace_name}(FILE *out, const void *arg, const void *indirect) {
+ % if len(trace.tp_struct) > 0:
+ const struct trace_${trace_name} *__entry =
+ (const struct trace_${trace_name} *)arg;
+ % endif
+ % for arg in trace.indirect_args:
+ const ${arg.type} *__${arg.var} = (const ${arg.type} *) ((char *)indirect + ${arg.indirect_offset});
+ % endfor
+ % if trace.tp_print_custom is not None:
+ fprintf(out, "\\"unstructured\\": \\"${trace.tp_print_custom[0]}\\""
+ % for arg in trace.tp_print_custom[1:]:
+ , ${arg}
+ % endfor
+ % else:
+ fprintf(out, ""
+ % for arg in trace.tp_print:
+ "\\"${arg.name}\\": \\"${arg.c_format}\\""
+ % if arg != trace.tp_print[-1]:
+ ", "
+ % endif
+ % endfor
+ % for arg in trace.tp_print:
+ ,${arg.value_expr("__entry")}
+ % endfor
+ % endif
);
}
-% else:
+
+ % else:
#define __print_${trace_name} NULL
-% endif
+#define __print_json_${trace_name} NULL
+ % endif
+ % if trace.tp_markers is not None:
+
+__attribute__((format(printf, 3, 4))) void ${trace.tp_markers}(struct u_trace_context *utctx, void *, const char *, ...);
+
+static void __emit_label_${trace_name}(struct u_trace_context *utctx, void *cs, struct trace_${trace_name} *entry) {
+ ${trace.tp_markers}(utctx, cs, "${trace_name}("
+ % for idx,arg in enumerate(trace.tp_print):
+ % if not arg.is_indirect:
+ "${"," if idx != 0 else ""}${arg.name}=${arg.c_format}"
+ % endif
+ % endfor
+ ")"
+ % for arg in trace.tp_print:
+ % if not arg.is_indirect:
+ ,${arg.value_expr('entry')}
+ % endif
+ % endfor
+ );
+}
+
+ % endif
static const struct u_tracepoint __tp_${trace_name} = {
- ALIGN_POT(sizeof(struct trace_${trace_name}), 8), /* keep size 64b aligned */
"${trace_name}",
+ ALIGN_POT(sizeof(struct trace_${trace_name}), 8), /* keep size 64b aligned */
+ 0
+ % for arg in trace.indirect_args:
+ + sizeof(${arg.type})
+ % endfor
+ ,
+ ${0 if len(trace.tp_flags) == 0 else " | ".join(trace.tp_flags)},
+ ${index},
__print_${trace_name},
-% if trace.tp_perfetto is not None:
+ __print_json_${trace_name},
+ % if trace.tp_perfetto is not None:
#ifdef HAVE_PERFETTO
- (void (*)(void *pctx, uint64_t, const void *, const void *))${trace.tp_perfetto},
+ (void (*)(void *pctx, uint64_t, uint16_t, const void *, const void *, const void *))${trace.tp_perfetto},
#endif
-% endif
+ % endif
};
-void __trace_${trace_name}(struct u_trace *ut, void *cs
-% for arg in trace.args:
- , ${arg.type} ${arg.var}
-% endfor
+void __trace_${trace_name}(
+ struct u_trace *ut
+ , enum u_trace_type enabled_traces
+ % if trace.need_cs_param:
+ , void *cs
+ % endif
+ % for arg in trace.args:
+ , ${arg.func_param}
+ % endfor
) {
- struct trace_${trace_name} *__entry =
- (struct trace_${trace_name} *)u_trace_append(ut, cs, &__tp_${trace_name});
- (void)__entry;
-% for arg in trace.tp_struct:
- __entry->${arg.name} = ${arg.var};
-% endfor
+ struct trace_${trace_name} entry;
+ % if len(trace.indirect_args) > 0:
+ struct u_trace_address indirects[] = {
+ % for arg in trace.indirect_args:
+ ${arg.var},
+ % endfor
+ };
+ uint8_t indirect_sizes[] = {
+ % for arg in trace.indirect_args:
+ sizeof(${arg.type}),
+ % endfor
+ };
+ % endif
+ UNUSED struct trace_${trace_name} *__entry =
+ enabled_traces & U_TRACE_TYPE_REQUIRE_QUEUING ?
+ (struct trace_${trace_name} *)u_trace_appendv(ut, ${"cs," if trace.need_cs_param else "NULL,"} &__tp_${trace_name},
+ 0
+ % for arg in trace.tp_struct:
+ % if arg.length_arg is not None and not arg.length_arg.isdigit():
+ + ${arg.length_arg}
+ % endif
+ % endfor
+ ,
+ % if len(trace.indirect_args) > 0:
+ ARRAY_SIZE(indirects), indirects, indirect_sizes
+ % else:
+ 0, NULL, NULL
+ % endif
+ ) :
+ &entry;
+ % for arg in trace.tp_struct:
+ % if arg.copy_func is None:
+ __entry->${arg.name} = ${arg.var};
+ % else:
+ ${arg.copy_func}(__entry->${arg.name}, ${arg.var}, ${arg.length_arg});
+ % endif
+ % endfor
+ % if trace.tp_markers is not None:
+ if (enabled_traces & U_TRACE_TYPE_MARKERS)
+ __emit_label_${trace_name}(ut->utctx, cs, __entry);
+ % endif
}
% endfor
"""
-def utrace_generate(cpath, hpath, ctx_param):
+def utrace_generate(cpath, hpath, ctx_param, trace_toggle_name=None,
+ trace_toggle_defaults=[]):
+ """Parameters:
+
+ - cpath: c file to generate.
+ - hpath: h file to generate.
+ - ctx_param: type of the first parameter to the perfetto vfuncs.
+ - trace_toggle_name: (optional) name of the environment variable
+ enabling/disabling tracepoints.
+ - trace_toggle_defaults: (optional) list of tracepoints enabled by default.
+ """
if cpath is not None:
hdr = os.path.basename(cpath).rsplit('.', 1)[0] + '.h'
- with open(cpath, 'w') as f:
- f.write(Template(src_template).render(
- hdr=hdr,
- ctx_param=ctx_param,
- HEADERS=[h for h in HEADERS if h.scope & HeaderScope.SOURCE],
- TRACEPOINTS=TRACEPOINTS))
+ with open(cpath, 'w', encoding='utf-8') as f:
+ try:
+ f.write(Template(src_template).render(
+ hdr=hdr,
+ ctx_param=ctx_param,
+ trace_toggle_name=trace_toggle_name,
+ trace_toggle_defaults=trace_toggle_defaults,
+ HEADERS=[h for h in HEADERS if h.scope & HeaderScope.SOURCE],
+ TRACEPOINTS=TRACEPOINTS,
+ TRACEPOINTS_TOGGLES=TRACEPOINTS_TOGGLES))
+ except:
+ print(exceptions.text_error_template().render())
if hpath is not None:
hdr = os.path.basename(hpath)
- with open(hpath, 'w') as f:
- f.write(Template(hdr_template).render(
- hdrname=hdr.rstrip('.h').upper(),
- ctx_param=ctx_param,
- HEADERS=[h for h in HEADERS if h.scope & HeaderScope.HEADER],
- FORWARD_DECLS=FORWARD_DECLS,
- TRACEPOINTS=TRACEPOINTS))
+ with open(hpath, 'w', encoding='utf-8') as f:
+ try:
+ f.write(Template(hdr_template).render(
+ hdrname=hdr.rstrip('.h').upper(),
+ ctx_param=ctx_param,
+ trace_toggle_name=trace_toggle_name,
+ HEADERS=[h for h in HEADERS if h.scope & HeaderScope.HEADER],
+ FORWARD_DECLS=FORWARD_DECLS,
+ TRACEPOINTS=TRACEPOINTS,
+ TRACEPOINTS_TOGGLES=TRACEPOINTS_TOGGLES))
+ except:
+ print(exceptions.text_error_template().render())
perfetto_utils_hdr_template = """\
@@ -370,40 +673,63 @@ perfetto_utils_hdr_template = """\
#include <perfetto.h>
+% for header in HEADERS:
+#include "${header.hdr}"
+% endfor
+
+UNUSED static const char *${basename}_names[] = {
+% for trace_name, trace in TRACEPOINTS.items():
+ "${trace_name}",
+% endfor
+};
+
+typedef void (*trace_payload_as_extra_func)(perfetto::protos::pbzero::GpuRenderStageEvent *, const void*, const void*);
+
% for trace_name, trace in TRACEPOINTS.items():
static void UNUSED
trace_payload_as_extra_${trace_name}(perfetto::protos::pbzero::GpuRenderStageEvent *event,
- const struct trace_${trace_name} *payload)
+ const struct trace_${trace_name} *payload,
+ const void *indirect_data)
{
-% if all([trace.tp_perfetto, trace.tp_struct]) and len(trace.tp_struct) > 0:
+ % if trace.tp_perfetto is not None and len(trace.tp_print) > 0:
+ % if any(not arg.perfetto_field for arg in trace.tp_print):
char buf[128];
+ % endif
-% for arg in trace.tp_struct:
+ % for arg in trace.tp_print:
+ % if arg.perfetto_field:
+ event->set_${arg.name}(${arg.value_expr("payload")});
+ % else:
{
auto data = event->add_extra_data();
data->set_name("${arg.name}");
-% if arg.to_prim_type:
- sprintf(buf, "${arg.c_format}", ${arg.to_prim_type.format('payload->' + arg.name)});
-% else:
- sprintf(buf, "${arg.c_format}", payload->${arg.name});
-% endif
+ % if arg.is_indirect:
+ const ${arg.type}* __${arg.var} = (const ${arg.type}*)((uint8_t *)indirect_data + ${arg.indirect_offset});
+ % endif
+ sprintf(buf, "${arg.c_format}", ${arg.value_expr("payload")});
data->set_value(buf);
}
-% endfor
+ % endif
+ % endfor
-% endif
+ % endif
}
% endfor
#endif /* ${guard_name} */
"""
-def utrace_generate_perfetto_utils(hpath):
+def utrace_generate_perfetto_utils(hpath,basename="tracepoint"):
if hpath is not None:
hdr = os.path.basename(hpath)
- with open(hpath, 'wb') as f:
- f.write(Template(perfetto_utils_hdr_template, output_encoding='utf-8').render(
- hdrname=hdr.rstrip('.h').upper(),
- TRACEPOINTS=TRACEPOINTS))
+ with open(hpath, 'w', encoding='utf-8') as f:
+ try:
+ f.write(Template(perfetto_utils_hdr_template).render(
+ basename=basename,
+ hdrname=hdr.rstrip('.h').upper(),
+ HEADERS=[h for h in HEADERS if h.scope & HeaderScope.PERFETTO],
+ TRACEPOINTS=TRACEPOINTS))
+ except:
+ print(exceptions.text_error_template().render())