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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
|
// Copyright (C) 2005, 2006 IBM Corp.
//
// This file is part of systemtap, and is free software. You can
// redistribute it and/or modify it under the terms of the GNU General
// Public License (GPL); either version 2, or (at your option) any
// later version.
%{
#include <linux/cpufreq.h>
#if defined(ASCII_TRACE)
#ifndef _FMT_
#define _FMT_ unsigned int
#endif
#else
#ifndef _FMT_
#define _FMT_ int64_t
#endif
#endif
#ifndef TIMING_GETCYCLES
#define TIMING_GETCYCLES 0x01
#endif
#ifndef TIMING_GETTIMEOFDAY
#define TIMING_GETTIMEOFDAY 0x02
#endif
#ifndef TIMING_SCHEDCLOCK
#define TIMING_SCHEDCLOCK 0x03
#endif
extern int _GROUP_CPUFREQ;
extern int _HOOKID_SWITCH_CPUFREQ;
extern long timing_method;
#ifndef _PFN_SCHEDCLOCK_TYPE
#define _PFN_SCHEDCLOCK_TYPE
typedef unsigned long long (* pfn_schedclock_type)(void);
#endif
extern pfn_schedclock_type pfn_schedclock;
%}
function lket_trace_header_init()
%{
/* header info for binary format*/
#if !defined(ASCII_TRACE)
#define MAGIC_NUMBER 0xAEFCDB6B
#define LKET_TRACE_VER_MAJOR 0x01
#define LKET_TRACE_VER_MINOR 0x01 /* used for user customization */
#define LITTLE_ENDIAN 0x01
#define BIG_ENDIAN 0x02
#define BITS_WIDTH 64 /* 32-bit or 64-bit environment*/
_stp_printf("%4b%2n%1b%1b%1b%1b%1b%4b", (_FMT_)MAGIC_NUMBER,
(_FMT_)LKET_TRACE_VER_MAJOR, (_FMT_)LKET_TRACE_VER_MINOR,
(_FMT_)BIG_ENDIAN, (_FMT_)timing_method,
(_FMT_)BITS_WIDTH, (_FMT_)__stp_estimate_cpufreq());
_stp_print_flush();
#endif
%}
function lket_trace_init()
{
lket_trace_header_init()
}
%{
#ifndef __LKET_TRACE__
#define __LKET_TRACE__
#define LKET_PKT_BT 2
#define MAX_FMT_LEN 128
char new_sysfmt[MAX_FMT_LEN] = "\n%d|%d|%d|%d|%d|%d|%d|%d";
#define NEW_SYSFMT_START 24
void fmt_change(char *oldfmt, char *newfmt, int newfmt_start)
{
char *old_ptr, *new_ptr;
old_ptr = oldfmt;
new_ptr = newfmt + newfmt_start;
while(*old_ptr != 0 && (new_ptr - newfmt) < MAX_FMT_LEN) {
if(*old_ptr != '%') {
*new_ptr++ = *old_ptr++;
continue;
} else {
*new_ptr++ = '|'; /* delimier to make it readable */
*new_ptr++ = *old_ptr++;
while( *old_ptr == 'L' || *old_ptr == 'l'
|| isdigit(*old_ptr) ) {
*new_ptr++ = *old_ptr++;
}
if( *old_ptr == 'b') {
if(isdigit(*(old_ptr-1))) {
if(*(old_ptr-1) == '1' ||
*(old_ptr-1) == '2' ||
*(old_ptr-1) == '3' ||
*(old_ptr-1) == '4') {
new_ptr--;
} else if(*(old_ptr-1) == '8') {
*--new_ptr='l';
*++new_ptr='l';
new_ptr++;
}
}
*new_ptr++ = 'd';
old_ptr++;
}
else if ( *old_ptr == 's') {
if(isdigit(*(old_ptr-1)) && *(old_ptr-1)=='0')
new_ptr--;
*new_ptr++ = 's';
old_ptr++;
} else
*new_ptr++ = *old_ptr++;
}
}
*new_ptr=0;
}
/* trace data in ASCII format
Format of the common prefix of the trace data:
groupid|subhookid|sec|usec|tgid|ppid|pid|cpuid|
*/
#if defined(ASCII_TRACE)
#define _lket_trace(GroupID, hookID, fmt, args...) do { \
struct timeval tv; \
do_gettimeofday (&tv); \
fmt_change(fmt, new_sysfmt, NEW_SYSFMT_START); \
_stp_printf(new_sysfmt, \
(_FMT_)GroupID, (_FMT_)hookID, (_FMT_)tv.tv_sec, (_FMT_)tv.tv_usec,\
(_FMT_)current->tgid, (_FMT_)current->parent->tgid,\
(_FMT_)current->pid, (_FMT_)current->thread_info->cpu, args);\
} while(0)
#else //binary trace
static inline int this_event_len(void)
{
return 0;
}
/* we use 2 bytes to store the length. */
#define _lket_trace(GroupID, hookID, fmt, args...) do { \
if(timing_method == TIMING_GETCYCLES) { \
_stp_printf("%2b%2n%8b%8b%8b"fmt, (_FMT_)0, \
(_FMT_)get_cycles(), \
(_FMT_)((int64_t)current->pid << 32 | (int32_t)current->tgid),\
(_FMT_)((int64_t)current->parent->tgid << 32 | \
(int32_t)GroupID << 24 | (int32_t)hookID << 16 | \
(int16_t)current->thread_info->cpu << 8), \
args); \
} \
else if(timing_method == TIMING_GETTIMEOFDAY) { \
struct timeval tv; \
do_gettimeofday (&tv); \
_stp_printf("%2b%2n%8b%8b%8b"fmt, (_FMT_)0, \
(_FMT_)(tv.tv_sec*1000000LL + tv.tv_usec), \
(_FMT_)((int64_t)current->pid << 32 | (int32_t)current->tgid),\
(_FMT_)((int64_t)current->parent->tgid << 32 | \
(int32_t)GroupID << 24 | (int32_t)hookID << 16 | \
(int16_t)current->thread_info->cpu << 8), \
args); \
} \
else { \
_stp_printf("%2b%2n%8b%8b%8b"fmt, (_FMT_)0, \
(_FMT_)pfn_schedclock(), \
(_FMT_)((int64_t)current->pid << 32 | (int32_t)current->tgid),\
(_FMT_)((int64_t)current->parent->tgid << 32 | \
(int32_t)GroupID << 24 | (int32_t)hookID << 16 | \
(int16_t)current->thread_info->cpu << 8), \
args); \
} \
} while(0)
#endif
#endif
%}
function update_record()
%{
#if !defined(ASCII_TRACE)
_stp_pbuf *pb = per_cpu_ptr(Stp_pbuf, smp_processor_id());
char *total_length = &(pb->buf[0]);
*(int16_t *)total_length = pb->len - 4;
#endif
%}
%{
#ifdef CONFIG_CPU_FREQ
static int __lket_time_cpufreq_callback(struct notifier_block *self,
unsigned long state, void *vfreqs)
{
int cpu;
unsigned long flags;
struct cpufreq_freqs *freqs;
unsigned int freq_mhz;
stp_time_t *time;
switch (state) {
case CPUFREQ_POSTCHANGE:
case CPUFREQ_RESUMECHANGE:
_lket_trace(_GROUP_CPUFREQ, _HOOKID_SWITCH_CPUFREQ,
"%8b", __stp_estimate_cpufreq());
break;
}
return NOTIFY_OK;
}
#endif
%}
|