// 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 #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"fmt, (_FMT_)0, \ (_FMT_)get_cycles(), \ (_FMT_)((int64_t)current->pid << 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"fmt, (_FMT_)0, \ (_FMT_)(tv.tv_sec*1000000LL + tv.tv_usec), \ (_FMT_)((int64_t)current->pid << 32 | \ (int32_t)GroupID << 24 | (int32_t)hookID << 16 | \ (int16_t)current->thread_info->cpu << 8), \ args); \ } \ else { \ _stp_printf("%2b%2n%8b%8b"fmt, (_FMT_)0, \ (_FMT_)pfn_schedclock(), \ (_FMT_)((int64_t)current->pid << 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 %}