#obj-m += ltt-facility-loader-tests.o
# #obj-m += test-time-probe.o
#obj-m += test-time-probe2.o
- #obj-m += test-compact.o
+ obj-m += test-compact.o
# obj-m += ltt-facility-loader-compact.o
# obj-m += test-instrument-size-small.o
# obj-m += test-instrument-size-med.o
# obj-m += test-instrument-size-big.o
# obj-m += test-printk-effect.o
+ obj-m += ltt-probe-tests.o
+ obj-m += test-time-probe3.o
endif
+ obj-m += probe-example.o
+ obj-m += marker-example.o
# obj-m += test-async-tsc.o
obj-m += test-tsc-sync.o
obj-m += test-tsc.o
--- /dev/null
+/* marker-example.c
+ *
+ * Executes a marker when /proc/marker-example is opened.
+ *
+ * (C) Copyright 2007 Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/marker.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+
+struct proc_dir_entry *pentry_example = NULL;
+
+static int my_open(struct inode *inode, struct file *file)
+{
+ int i;
+
+ MARK(subsystem_event, "%d %s %*.*r", 123, "example string",
+ sizeof(current), __alignof__(current), current);
+ for (i=0; i<10; i++) {
+ MARK(subsystem_eventb, MARK_NOARGS);
+ }
+ return -EPERM;
+}
+
+static struct file_operations mark_ops = {
+ .open = my_open,
+};
+
+static int example_init(void)
+{
+ printk(KERN_ALERT "example init\n");
+ pentry_example = create_proc_entry("marker-example", 0444, NULL);
+ if (pentry_example)
+ pentry_example->proc_fops = &mark_ops;
+ else
+ return -EPERM;
+ return 0;
+}
+
+static void example_exit(void)
+{
+ printk(KERN_ALERT "example exit\n");
+ remove_proc_entry("marker-example", NULL);
+}
+
+module_init(example_init)
+module_exit(example_exit)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mathieu Desnoyers");
+MODULE_DESCRIPTION("Linux Trace Toolkit example");
--- /dev/null
+/* probe-example.c
+ *
+ * Connects a two functions to marker call sites.
+ *
+ * (C) Copyright 2007 Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/marker.h>
+#include <asm/atomic.h>
+
+#define NUM_PROBES (sizeof(probe_array) / sizeof(struct probe_data))
+
+struct probe_data {
+ const char *name;
+ const char *format;
+ marker_probe_func *probe_func;
+};
+
+void probe_subsystem_event(const struct __mark_marker_c *mdata,
+ const char *format, ...)
+{
+ va_list ap;
+ /* Declare args */
+ unsigned int value;
+ const char *mystr;
+ int task_size, task_alignment;
+ struct task_struct *task;
+
+ /* Assign args */
+ va_start(ap, format);
+ value = va_arg(ap, typeof(value));
+ mystr = va_arg(ap, typeof(mystr));
+ task_size = va_arg(ap, typeof(task_size));
+ task_alignment = va_arg(ap, typeof(task_alignment));
+ task = va_arg(ap, typeof(task));
+
+ /* Call printk */
+ printk("Value %u, string %s, current ptr %p\n", value, mystr, current);
+
+ /* or count, check rights, serialize data in a buffer */
+
+ va_end(ap);
+}
+
+atomic_t eventb_count = ATOMIC_INIT(0);
+
+void probe_subsystem_eventb(const struct __mark_marker_c *mdata,
+ const char *format, ...)
+{
+ /* Increment counter */
+ atomic_inc(&eventb_count);
+}
+
+static struct probe_data probe_array[] =
+{
+ { .name = "subsystem_event",
+ .format = "%d %s %*.*r",
+ .probe_func = probe_subsystem_event },
+ { .name = "subsystem_eventb",
+ .format = MARK_NOARGS,
+ .probe_func = probe_subsystem_eventb },
+};
+
+static int __init probe_init(void)
+{
+ int result;
+ uint8_t eID;
+
+ for (eID = 0; eID < NUM_PROBES; eID++) {
+ result = marker_set_probe(probe_array[eID].name,
+ probe_array[eID].format,
+ probe_array[eID].probe_func, &probe_array[eID]);
+ if (!result)
+ printk(KERN_INFO "Unable to register probe %s\n",
+ probe_array[eID].name);
+ }
+ return 0;
+}
+
+static void __exit probe_fini(void)
+{
+ uint8_t eID;
+
+ for (eID = 0; eID < NUM_PROBES; eID++) {
+ marker_remove_probe(probe_array[eID].name);
+ }
+ synchronize_sched(); /* Wait for probes to finish */
+ printk("Number of event b : %u\n", atomic_read(&eventb_count));
+}
+
+module_init(probe_init);
+module_exit(probe_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mathieu Desnoyers");
+MODULE_DESCRIPTION("SUBSYSTEM Probe");
*/
-#include <ltt/ltt-facility-select-compact.h>
-#include <ltt/ltt-facility-compact.h>
-
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/ltt-core.h>
+#include <ltt/ltt-tracer.h>
#include <linux/timex.h>
+#include <linux/marker.h>
+#include <linux/proc_fs.h>
+struct proc_dir_entry *pentry_test = NULL;
/* Event logged : 4 bytes. Let's use 1MB of
* buffers. 1MB / 4bytes = 262144 (plus heartbeats). So, if we write 20000
#define NR_LOOPS 20000
-static int ltt_test_init(void)
+static int my_open(struct inode *inode, struct file *file)
{
unsigned int i;
cycles_t time1, time2, time;
cycles_t tot_time = 0;
unsigned long flags;
- printk(KERN_ALERT "test init\n");
+ printk(KERN_ALERT "test begin\n");
local_irq_save(flags);
time1 = get_cycles();
for(i=0; i<NR_LOOPS; i++) {
- trace_compact_event_a();
- trace_compact_event_c(get_cycles());
- trace_compact_event_d(0xFF);
- trace_compact_event_e(0xFF, 0xFAFAFA);
+ _MARK(_MF_DEFAULT | ltt_flag_mask(LTT_FLAG_COMPACT),
+ compact_event_a, MARK_NOARGS);
+ _MARK(_MF_DEFAULT | ltt_flag_mask(LTT_FLAG_COMPACT),
+ compact_event_b, "%4b", 0xFFFF);
+ _MARK(_MF_DEFAULT | ltt_flag_mask(LTT_FLAG_COMPACT),
+ compact_event_c, "%8b", 0xFFFFFFFFULL);
+ _MARK(_MF_DEFAULT | ltt_flag_mask(LTT_FLAG_COMPACT)
+ | ltt_flag_mask(LTT_FLAG_COMPACT_DATA),
+ compact_event_d, MARK_NOARGS, 0xFFFF);
+ _MARK(_MF_DEFAULT | ltt_flag_mask(LTT_FLAG_COMPACT)
+ | ltt_flag_mask(LTT_FLAG_COMPACT_DATA),
+ compact_event_e, "%8b", 0xFFFF, 0xFFFFFFFFULL);
}
time2 = get_cycles();
time = time2 - time1;
printk(KERN_ALERT "total time : %llu\n", tot_time);
printk(KERN_ALERT "test end\n");
-
- return -EAGAIN; /* Fail will directly unload the module */
+ return -EPERM;
+}
+
+static struct file_operations mark_ops = {
+ .open = my_open,
+};
+
+static int ltt_test_init(void)
+{
+ printk(KERN_ALERT "test init\n");
+ pentry_test = create_proc_entry("test-compact", 0444, NULL);
+ if (pentry_test)
+ pentry_test->proc_fops = &mark_ops;
+ else
+ return -EPERM;
+ return 0;
}
static void ltt_test_exit(void)
{
printk(KERN_ALERT "test exit\n");
+ remove_proc_entry("test-compact", NULL);
}
module_init(ltt_test_init)
#include <stdarg.h>
+/* Maximum number of callbacks per marker */
+#define LTT_NR_CALLBACKS 10
+
/* LTT flags
*
* LTT_FLAG_TRACE : first arg contains trace to write into.
#define LTT_FLAG_FORCE (1 << _LTT_FLAG_FORCE)
-char *(*ltt_serialize_cb)(char *buffer, const char *fmt, va_list args);
+char *(*ltt_serialize_cb)(char *buffer, int *cb_args,
+ const char *fmt, va_list args);
static int skip_atoi(const char **s)
/* Inspired from vsnprintf */
/* New types :
- * %r : serialized pointer.
+ * %r : serialized fixed length struct, union, array.
+ * %v : serialized sequence
+ * %k : callback
*/
static inline __attribute__((no_instrument_function))
-char *ltt_serialize_data(char *buffer, const char *fmt, va_list args)
+char *ltt_serialize_data(char *buffer, int *cb_args,
+ const char *fmt, va_list args)
{
int len;
const char *s;
/* 't' added for ptrdiff_t */
char *str; /* Pointer to write to */
ltt_serialize_cb cb;
+ int cb_arg_nr = 0;
str = buf;
if (buffer)
strcpy(str, s);
str += strlen(s);
+ /* Following alignment for genevent
+ * compatibility */
+ str += ltt_align(str, sizeof(void*));
continue;
case 'p':
memcpy(str, src, elem_size);
str += elem_size;
}
+ /* Following alignment for genevent
+ * compatibility */
+ str += ltt_align(str, sizeof(void*));
continue;
case 'k':
/* The callback will take as many arguments
* as it needs from args. They won't be
* type verified. */
- str = cb(str, fmt, args);
+ if (cb_arg_nr < LTT_NR_CALLBACKS)
+ str = cb(str, &cb_args[cb_arg_nr++],
+ fmt, args);
continue;
case 'n':
/* FIXME:
- * What does C99 say about the overflow case here? */
+ * What does C99 say about the overflow case
+ * here? */
if (qualifier == 'l') {
long * ip = va_arg(args, long *);
*ip = (str - buf);
- } else if (qualifier == 'Z' || qualifier == 'z') {
+ } else if (qualifier == 'Z'
+ || qualifier == 'z') {
size_t * ip = va_arg(args, size_t *);
*ip = (str - buf);
} else {
if (buffer)
switch (elem_size) {
case 1:
- *(int8_t*)str = (int8_t)va_arg(args, int);
+ *(int8_t*)str =
+ (int8_t)va_arg(args, int);
break;
case 2:
- *(int16_t*)str = (int16_t)va_arg(args, int);
+ *(int16_t*)str =
+ (int16_t)va_arg(args, int);
break;
case 4:
*(int32_t*)str = va_arg(args, int32_t);
* sizeof(void *) address. */
static inline __attribute__((no_instrument_function))
size_t ltt_get_data_size(ltt_facility_t fID, uint8_t eID,
+ int *cb_args,
const char *fmt, va_list args)
{
return (size_t)ltt_serialize_data(NULL, fmt, args);
static inline __attribute__((no_instrument_function))
void ltt_write_event_data(char *buffer,
ltt_facility_t fID, uint8_t eID,
+ int *cb_args,
const char *fmt, va_list args)
{
ltt_serialize_data(buffer, fmt, args);
uint64_t tsc;
char *buffer;
va_list args_copy;
+ int cb_args[LTT_NR_CALLBACKS];
/* This test is useful for quickly exiting static tracing when no
* trace is active. */
- if (likely(ltt_traces.num_active_traces == 0 && !(flags & LTT_FLAG_FORCE)))
+ if (likely(ltt_traces.num_active_traces == 0
+ && !(flags & LTT_FLAG_FORCE)))
return;
preempt_disable();
channel_index = ltt_get_channel_index(fID, eID);
va_copy(args_copy, args); /* Check : skip 2 st args if trace/ch */
- data_size = ltt_get_data_size(fID, eID, fmt, args_copy);
+ data_size = ltt_get_data_size(fID, eID, cb_args, fmt, args_copy);
va_end(args_copy);
/* Iterate on each traces */
buffer = ltt_write_event_header(trace, channel, buffer,
fID, eID, data_size, tsc);
va_copy(args_copy, args);
- ltt_write_event_data(buffer, fID, eID, fmt, args_copy);
+ ltt_write_event_data(buffer, fID, eID, cb_args, fmt, args_copy);
va_end(args_copy);
/* Out-of-order commit */
ltt_commit_slot(channel, &transport_data, buffer, slot_size);