How can I use ftrace filtering to see the call stack above a function? - linux

It's well-documented how to use ftrace to find the function graph starting from a certain function, e.g.
# echo nop > current_tracer
# echo 100 > max_graph_depth
# echo ksys_dup3 > set_graph_function
# echo function_graph > current_tracer
# cat trace
# tracer: function_graph
#
# CPU DURATION FUNCTION CALLS
# | | | | | | |
7) | ksys_dup3() {
7) 0.533 us | expand_files();
7) | do_dup2() {
7) | filp_close() {
7) 0.405 us | dnotify_flush();
7) 0.459 us | locks_remove_posix();
7) | fput() {
7) | fput_many() {
7) | task_work_add() {
7) 0.533 us | kick_process();
7) 1.558 us | }
7) 2.475 us | }
7) 3.382 us | }
7) 6.122 us | }
7) 7.104 us | }
7) + 10.763 us | }
But this only returns the function graph starting at ksys_dup3. It omits the full function graph that leads to ksys_dup3:
7) | el0_svc_handler() {
7) | el0_svc_common() {
7) | __arm64_sys_dup3() {
7) | ksys_dup3() {
7) 0.416 us | expand_files();
7) | do_dup2() {
7) | filp_close() {
7) 0.405 us | dnotify_flush();
7) 0.406 us | locks_remove_posix();
7) | fput() {
7) 0.416 us | fput_many();
7) 1.269 us | }
7) 3.819 us | }
7) 4.746 us | }
7) 6.475 us | }
7) 7.381 us | }
7) 8.362 us | }
7) 9.205 us | }
Is there a way to use ftrace to filter a full function graph?

I'd say all of ftrace is well documented (here). There is no way to do what you want though, because the filtering ability of ftrace is implemented through triggers that can start/stop tracing exactly when an event happens. Setting set_graph_function will trigger a trace start when the function is entered and a trace stop when it's exited. Since when you enter el0_svc_handler you cannot know beforehand if ksys_dup3 is going to be called, there is no way to write a trigger to start the trace on such a condition (that would require being able to "predict the future").
You can however do fine grained filtering with the set_ftrace_pid parameter writing a program that only does what you need, running a full trace on that program or filtering on the parent el0_svc_handler.
In case you don't actually know which parent functions are being called before the one you want, you can do a single targeted run with the func_stack_trace option enabled to get an idea about what the entire call chain is, and then use that output to set the appropriate filter for a "normal" run.
For example, let's say I want to trace do_dup2, but as you say I want to start from one of the parent functions. I'll first write a dummy test program like the following one:
int main(void) {
printf("My PID is %d, press ENTER to go...\n", getpid());
getchar();
dup2(0, 1);
return 0;
}
I'll compile and start the above program in one shell:
$ ./test
My PID is 1234, press ENTER to go...
Then in another root shell, configure tracing as follows:
cd /sys/kernel/tracing
echo function > current_tracer
echo 1 > options/func_stack_trace
echo do_dup2 > set_ftrace_filter
echo PID_OF_THE_PROGRAM_HERE > set_ftrace_pid
Note: echo do_dup2 > set_ftrace_filter is very important otherwise you will trace and dump the stack for every single kernel function, which would be a huge performance hit and can make the system unresponsive. For the same reason doing echo PID_OF_THE_PROGRAM_HERE > set_ftrace_pid is also important if you don't want to trace every single dup2 syscall done by the system.
Now I can do one trace:
echo 1 > tracing_on
# ... press ENTER in the other shell ...
echo 0 > tracing_on
cat trace
And the result will be something like this (my machine is x86 so the syscall entry functions have different names):
# tracer: function
#
# entries-in-buffer/entries-written: 2/2 #P:20
#
# _-----=> irqs-off
# / _----=> need-resched
# | / _---=> hardirq/softirq
# || / _--=> preempt-depth
# ||| / delay
# TASK-PID CPU# |||| TIMESTAMP FUNCTION
# | | | |||| | |
a.out-6396 [000] .... 1455.370160: do_dup2 <-__x64_sys_dup2
a.out-6396 [000] .... 1455.370174: <stack trace>
=> 0xffffffffc322006a
=> do_dup2
=> __x64_sys_dup2
=> do_syscall_64
=> entry_SYSCALL_64_after_hwframe
I can now see the entire call chain that led to do_dup2 (printed in reverse order above) and then do another normal trace from one of the parent functions (remember to disable options/func_stack_trace first).

Related

Function_graph cannot track a specific function

When I use Function_graph to trace the do_sys_open () function, I find it doesn't work.
Linux version 4.4.194
echo function_graph > current_tracer
echo do_sys_open > set_graph_function
echo 1 > tracing_on
cat trace
root#firefly:/sys/kernel/debug/tracing# cat set_ftrace_filter | grep do_sys_open
do_sys_open
root#firefly:/sys/kernel/debug/tracing# cat trace
# tracer: function_graph
#
# CPU DURATION FUNCTION CALLS
# | | | | | | |
1) 0.583 us | } /* cpu_needs_another_gp */
1) 0.583 us | rcu_all_qs();
1) + 29.750 us | } /* rcu_check_callbacks */
1) | scheduler_tick() {
1) | _raw_spin_lock() {
1) 0.583 us | do_raw_spin_lock();
1) 5.833 us | }
1) 0.875 us | update_rq_clock();
1) | task_tick_fair() {
1) | update_curr() {
1) 0.583 us | update_min_vruntime();
1) 0.875 us | cpuacct_charge();
1) + 11.375 us | }
1) 0.583 us | cpufreq_scale_freq_capacity();
1) | scale_cpu_capacity() {
1) 0.583 us | cpufreq_scale_max_freq_capacity();
1) 5.541 us | }
1) 0.583 us | __compute_runnable_contrib();
1) 0.583 us | cpufreq_scale_freq_capacity();
1) | scale_cpu_capacity() {
1) 0.291 us | cpufreq_scale_max_freq_capacity();
1) 5.542 us | }
1) 0.583 us | update_cfs_shares();
1) 0.583 us | hrtimer_active();
1) | sched_slice.isra.8() {
1) 0.584 us | __calc_delta();
1) 5.833 us | }
1) 0.583 us | __cpu_overutilized.constprop.22();
It seems that it outputs all the tracking functions.
Function_graph and function tracker are found to be ineffective on the ARM64 development board of Linux version 4.4.194.
After echo do_sys_open > set_graph_function, all functions will still be tracked.
But it is effective in Linux version 5.4.0-135 Ubuntu 18.04. I wonder if it's the kernel version.

Nodejs app not working with crontab #reboot

T'm trying to run a nodejs program after system reboot, I'm using crontab #reboot to do this but it did not work.
Here is my config steps, any idea what's wrong?
I'm using aws linux, and installed nodejs by nvm;
which node
/root/.nvm/versions/node/v8.9.3/bin/node
my test.js located
/home/ec2-user/spider/logger.js
this works fine
/root/.nvm/versions/node/v8.9.3/bin/node /home/ec2-user/spider/logger.js
this also works fine
#reboot echo "hi" > /home/reboot.txt 2>&1
crontab -e
#reboot /root/.nvm/versions/node/v7.1.0/bin/node /home/user/test.js
reboot, test.js never gets run
Also tried :
* * * * * /root/.nvm/versions/node/v8.9.3/bin/node /home/ec2-user/spider/logger.js >> /home/crontab.log 2>&1
* * * * * echo $(date '+%Y %b %d %H:%M') >> /home/reboot.txt 2>&1
* * * * * echo "hi" >> /home/hi.txt 2>&1
Only last one worked.
The crontab syntax composed of two parts, datetime to execute & command to be executed. In this case, you command is /root/.nvm/versions/node/v7.1.0/bin/node /home/user/test.js
* * * * * command to be executed
- - - - -
| | | | |
| | | | +----- day of week (0 - 6) (Sunday=0)
| | | +------- month (1 - 12)
| | +--------- day of month (1 - 31)
| +----------- hour (0 - 23)
+------------- min (0 - 59)

Strange bug in Julia or Screen

On Debian 8 Linux, I use vim together with screen to send lines from vim to a julia session. Today, I tried https://github.com/Keno/Cxx.jl. I followed the instructions there (i.e. I compiled the latest version 0.5.0-dev+3609 of Julia). The following bug appeared when I tried example 1, I could pinpoint it to the following simple steps:
Create the following files (don't overwrite your own files):
printf "using Cxx\ncxx\"\"\"#include<iostream> \"\"\"\ncxx\"\"\"void testfunction(){std::cout<<\"worked\"<< std::endl;}\"\"\"\njulia_function() = #cxx testfunction()\n" > start
and printf "julia_function()\n" > freeze
Open terminal 1 (I use gnome-terminal) and write screen -S session and then start Julia with julia. It should look like
_
_ _ _(_)_ | A fresh approach to technical computing
(_) | (_) (_) | Documentation: http://docs.julialang.org
_ _ _| |_ __ _ | Type "?help" for help.
| | | | | | |/ _` | |
| | |_| | | | (_| | | Version 0.5.0-dev+3609 (2016-04-18 07:07 UTC)
_/ |\__'_|_|_|\__'_| | Commit a136a6e (0 days old master)
|__/ | x86_64-linux-gnu
julia>
Open terminal 2 and do
screen -S session -p 0 -X eval "readreg p start" "paste p" Terminal 1 should now look like
_
_ _ _(_)_ | A fresh approach to technical computing
(_) | (_) (_) | Documentation: http://docs.julialang.org
_ _ _| |_ __ _ | Type "?help" for help.
| | | | | | |/ _` | |
| | |_| | | | (_| | | Version 0.5.0-dev+3609 (2016-04-18 07:07 UTC)
_/ |\__'_|_|_|\__'_| | Commit a136a6e (0 days old master)
|__/ | x86_64-linux-gnu
julia> using Cxx
julia> cxx"""#include&ltiostream&gt """
true
julia> cxx"""void testfunction(){std::cout<&lt"worked"&lt&lt std::endl;}"""
true
julia> julia_function() = #cxx testfunction()
julia_function (generic function with 1 method)
julia>
Now the strange bug appears: writing "ju", using TAB to complete to "julia_function" and adding "()" by hand in terminal 1 leads to
julia> julia_function()
worked
julia>
But if I do steps 1, 2, 3 and then screen -S session -p 0 -X eval "readreg p freeze" "paste p" in terminal 2 or write julia_function() in terminal 1 without using TAB to complete then I get a freeze in terminal 1:
julia> julia_function()
If I do steps 1, 2, 3, use TAB completion as described above, then (i.e. after the first call, which compiles the function) screen -S session -p 0 -X eval "readreg p freeze" "paste p" in terminal 2 and julia_function() without using TAB in terminal 1 work as expected (it prints "worked") and don't cause a freeze.
If I do not use screen at all, it works (with and without TAB). Can you please tell me what is going on here?

Why does sorting take so long?

I am currently trying to learn the syntax of Rust by solving little tasks. I compare the execution time as sanity-checks if I am using the language the right way.
One task is:
Create an array of 10000000 random integers in the range 0 - 1000000000
Sort it and measure the time
Print the time for sorting it
I got the following results:
| # | Language | Speed | LOCs |
| --- | -------------------- | ------ | ---- |
| 1 | C++ (with -O3) | 1.36s | 1 |
| 2 | Python (with PyPy) | 3.14s | 1 |
| 3 | Ruby | 5.04s | 1 |
| 4 | Go | 6.17s | 1 |
| 5 | C++ | 7.95s | 1 |
| 6 | Python (with Cython) | 11.51s | 1 |
| 7 | PHP | 36.28s | 1 |
Now I wrote the following Rust code:
rust.rs
extern crate rand;
extern crate time;
use rand::Rng;
use time::PreciseTime;
fn main() {
let n = 10000000;
let mut array = Vec::new();
let mut rng = rand::thread_rng();
for _ in 0..n {
//array[i] = rng.gen::<i32>();
array.push(rng.gen::<i32>());
}
// Sort
let start = PreciseTime::now();
array.sort();
let end = PreciseTime::now();
println!("{} seconds for sorting {} integers.", start.to(end), n);
}
with the following Cargo.toml:
[package]
name = "hello_world" # the name of the package
version = "0.0.1" # the current version, obeying semver
authors = [ "you#example.com" ]
[[bin]]
name = "rust"
path = "rust.rs"
[dependencies]
rand = "*" # Or a specific version
time = "*"
I compiled it with cargo run rust.rs and ran the binary. It outputs
PT18.207168155S seconds for sorting 10000000 integers.
Note that this is much slower than Python. I guess I am doing something wrong. (The complete code of rust and of the other languages is here if you are interested.)
Why does it take so long to sort with Rust? How can I make it faster?
I Tried your code on my computer, running it with cargo run gives:
PT11.634640178S seconds for sorting 10000000 integers.
And with cargo run --release (turning on optimizations) gives:
PT1.004434739S seconds for sorting 10000000 integers.

How to delete the data in Character device

I have written some data into my character device in /dev/my_char.
What should I do to delete the data without removing the device from the kernel ? .
The method which I follow to delete the contents is to
1) rm /dev/my_char and
2) rmmod My_Char.
But by using this method, I have to insert the module again into the kernel and create the device in dev folder which is a lengthy process.
Using only rm /dev/my_char doesn't delete its contents.
I would like to know if there is any other method other than this.
You could implement an ioctl to reset the input buffer.
Add an ioctl handler to the driver.
Add the entry point to the file_operations structure. .unlocked_ioctl =(your function name)
For the case of the correct ioctl command, reset the buffer pointer(s), clear the count, or whatever is needed to make the device look empty.
Or you could write a script to remove the driver and reload it. Here is what I use (I call it reload):
#!/bin/bash
if [ -d /device/my_device ]; then
sudo rmmod my_device.ko
fi
VERBOSE=0
MESSAGES=0
VENDOR=
DEVICEID=
while (( $# > 0 ))
do
arg="$1"
shift
case $arg in
v=* | ve=* | ver=* | verb=* | verbo=* | verbos=* | verbose=*)
VERBOSE=${arg#*=}
;;
v | ve | ver | verb | verbo | verbos | verbose)
VERBOSE=1
;;
t | tt | tty)
MESSAGES=1
;;
ven=* | vend=* | vendo=* | vendor=*)
VENDOR="opt_vendor_id=${arg#*=}"
;;
ven | vend | vendo | vendor)
VENDOR="opt_vendor_id=$1"
shift
;;
d=* | de=* | dev=* | devi=* | devic=* | device=*)
DEVICEID="opt_device_id=${arg#*=}"
;;
d | de | dev | devi | devic | device)
DEVICEID="opt_device_id=$1"
shift
;;
*)
echo "Invalid option '$arg':"
echo "Options are 'verbose', 'tty', 'vendor='<vendor number>, and 'deviceid='<device id>"
exit 1
;;
esac
done
echo "insmod my_device.ko opt_verbose=$VERBOSE opt_tty_msgs=$MESSAGES $VENDOR $DEVICEID"
sudo insmod my_device.ko opt_verbose=$VERBOSE opt_tty_msgs=$MESSAGES $VENDOR $DEVICEID
This has a lot of extra complexity to handle parameters which are passed to the module when it is loaded. If you don't have any module parameters, the above can be simplified to:
#!/bin/bash
if [ -d /device/my_device ]; then
sudo rmmod my_device.ko
fi
sudo insmod my_device.ko
You can work with your character device as if it is a generic file
cat /dev/null > /dev/my_char
Its possible to delete the data in the device by just removing the module from the kernel and then loading the module again to the kernel.ie "rmmod My_Char" and again "insmod My_Char".By this method we need not create the device again in the /dev/my_char as it will be automatically loaded with no data.

Resources