summaryrefslogtreecommitdiffstats
path: root/runtime/probes/os_timer/os_timer.c
blob: 4a80d02be247e1ed4b04b91d1bb9ba593e7dd705 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
/* Use the os timer as a poor-man's time based profiler for a UP system */

/* Demonstrates the beginnings of a generic framework for */
/* asynchronous probes using the runtime */

/* @todo NOTE: the statement: regs = task_pt_regs(current); */
/* isn't working in the way I would expect. The timer callback */
/* happens, but I don't get a reasonable value in regs->eip */
/* Can this routine be called during the timer callback? */

/* os includes */
#include "linux/timer.h"

/* How many strings to allocate. see strings.c. Default is 0. */
#define STP_NUM_STRINGS 1

/* maximum size for a string. default is 2048 */
#define STP_STRING_SIZE 2048

/* size of strings saved in maps */
#define MAP_STRING_LENGTH 256

/* width of histograms. Default 50 */
#define HIST_WIDTH 50

/* always include this.  Put all non-map defines above it. */
#include "runtime.h"

/* @todo since we don't have aggregation maps yet, try regular maps */
#define VALUE_TYPE INT64
#define KEY1_TYPE STRING
#define KEY2_TYPE INT64
#include "map-gen.c"

#include "map.c"

#include "stat.c"
#include "stack.c"

MODULE_DESCRIPTION("SystemTap probe: os_timer");
MODULE_AUTHOR("Charles Spirakis <charles.spirakis@intel.com>");

Stat timing;
MAP cur_addr;

/* A generic asynchorous probe entry point */
void inst_async(struct pt_regs *regs)
{
    u64 start;
    u64 end;
    unsigned long ip;
    
    rdtscll(start);
    ip = REG_IP(regs);

    /* Create a map of interrupted addresses seen */
    /* really want a map of image name / address */
    _stp_map_add_sii(cur_addr, current->comm, ip, 1);

    /* Need _stp_stack() and _stp_ustack()? */
    /* _stp_image() and aggregation maps */

    rdtscll(end);
    _stp_stat_add(timing, end - start);
}

static struct timer_list timer;

/* Helper function to convert from os timer callback into */
/* generic asynchronous entry point form */
static void os_timer_callback(unsigned long val)
{
    struct pt_regs *regs;

    /* setup the next timeout now so it doesn't drift */
    /* due to processing the async probe code */
    mod_timer(&timer, jiffies + val);

    /* determine pt_regs from the kernel stack */
    /* @todo This doesn't seem to get a reasonable pt_regs pointer */
    /* based on the value of regs->eip. However, KSTK_EIP() in */
    /* include/asm/processor.h implies regs->eip is valid... */
    regs = task_pt_regs(current);

    /* Call the asynchronous probe with a ptregs struct */
    inst_async(regs);
}

/* called when the module loads. */
int probe_start(void)
{
    timing = _stp_stat_init(HIST_LINEAR, 0, 5000, 250);

    cur_addr = _stp_map_new_sii(1000);

    /* register the os_timer */
    init_timer(&timer);

    timer.expires = jiffies + 50;
    timer.function = os_timer_callback;

    /* data is usd for defining when the next timeout shoud occur */
    timer.data = 50;

    add_timer(&timer);
    return 0;
}

void probe_exit (void)
{
    /* unregister the os_timer */
    del_timer_sync(&timer);

    /* print out any colledted data, etc */
    _stp_printf ("os timer done.\n");
    _stp_printf ("WARNING: Currently using task_pt_regs() to get the pt_regs struct\n");
    _stp_printf ("during the timer interrupt, but there seems to be issues with that...\n\n");
    _stp_stat_print (timing, "timing (cpu cycles): # calls:%C  avg:%A  min:%m  max:%M\n%H", 0);

    _stp_print("Process\tIp\tCount\n");
    _stp_map_print (cur_addr, "%1s\t%2P\t%d");
    _stp_map_del(cur_addr);

    _stp_print_flush();
}