I'm researching LTTNG with the purpose to gather kernel events from other processes (not by a specific pid, but any process).
I have managed to get kernel syscalls for read and write operations, however, the data retrieved there is not quite what i need.
I need to be able to see a live feed for when a process is created (i need the PID, process path and the parent PID), and most important, i need to see whenever a process is performing read/write operations on files (and exactly what those files are).
On Windows i can receive this using ETW tracing. I need the same thing on linux and LTTNG seems to be the closest thing to achieving that from what i've researched.
Did anybody tried to do this before?
Thank you in advance!
Getting the write and read syscall is a good first step!
The clone and execve syscalls will provide you information regarding the process creation.
... syscall_entry_clone: { cpu_id = 2 }, { clone_flags = 0x1200011, newsp = 0x0, parent_tid = 0x0, child_tid = 0x7F4440D7EA10 }
... syscall_exit_clone: { cpu_id = 2 }, { ret = 1606323 }
... syscall_exit_clone: { cpu_id = 1 }, { ret = 0 }
... syscall_entry_execve: { cpu_id = 1 }, { filename = "/bin/bash", argv = 0x55FA993F7EB0, envp = 0x55FA993BAF20 }
The execve syscall provides the process path.
Indeed, it would be nice to have the pid, ppid for each event to ease analysis. This can be done using the lttng add-context command. For this case:
lttng add-context -k -t vpid
lttng add-context -k -t vppid
We then get:
... syscall_entry_clone: { cpu_id = 0 }, { vpid = 1602589, vppid = 2996 }, { clone_flags = 0x1200011, newsp = 0x0, parent_tid = 0x0, child_tid = 0x7F4440D7EA10 }
... syscall_exit_clone: { cpu_id = 0 }, { vpid = 1602589, vppid = 2996 }, { ret = 1607998 }
... syscall_exit_clone: { cpu_id = 1 }, { vpid = 1607998, vppid = 1602589 }, { ret = 0 }
... syscall_entry_execve: { cpu_id = 1 }, { vpid = 1607998, vppid = 1602589 }, { filename = "/bin/bash", argv = 0x55FA993B8C00, envp = 0x55FA993BAF20 }
... syscall_exit_execve: { cpu_id = 1 }, { vpid = 1607998, vppid = 1602589 }, { ret = 0 }
I encourage you to take a look at the available context using the lttng add-context --list command.
Now onto the read/write/open/close for files, a base event setup would be:
lttng enable-event -k --syscall write,pwrite64,writev,pwritev
lttng enable-event -k --syscall read,pread64,readv,preadv
lttng enable-event -k --syscall open,openat,name_to_handle_at,open_by_handle_at
lttng enable-event -k --syscall close
The open family is important since it give the starting point of the relation between the fd number and the file path. The close syscall is important to give you the end of the relation.
As for the "live feed", the live mode would fit the bill. But if you can spare some delay, I would encourage you to look into the rotation feature.
From there you should have all the information required. Unfortunately, Trace Compass does not seem to offer a baked-in analysis for this. If you are up to the task, it should not be too hard to implement in a Babeltrace2 python plugin or simply using the python TraceCollection API.
In recap:
lttng create my_session
lttng enable-event -k --syscall clone,exec
lttng enable-event -k --syscall write,pwrite64,writev,pwritev
lttng enable-event -k --syscall read,pread64,readv,preadv
lttng enable-event -k --syscall open,openat,name_to_handle_at,open_by_handle_at
lttng enable-event -k --syscall close
lttng add-context -k -t vpid
lttng add-context -k -t vppid
Related
I would like to trace all function calls for a given library in a process, but the process is going to exit and re-open regularly, and I want to keep tracing.
I am doing this now:
oneshot$target:LIBRARY::entry
{
printf("%s\n", probefunc);
}
However, this only lets me provide one pid at a time. Can I keep this going?
I want something like:
*:LIBRARY::entry
/execname == "foo"/
but that * doesn't work there.
Thanks!
I don't think you can do this with just a single dtrace script. You'd need two (at least...). And you need to have the ability to run the destructive system() action, which most likely means root access.
Assume you want to run this script on any new ls process:
#!/usr/sbin/dtrace -s
pid$1:libc::entry
{
printf( "func: %s\n", probefunc );
}
Assuming the path to that script is /root/dtrace/tracelibc.d, the following script will start dtrace on any new ls process that gets started. Note that you need #pragma D option destructive to be able to start dtrace on the new process:
#!/usr/sbin/dtrace -s
#pragma D option destructive
#pragma D option quiet
proc:::exec-success
/ "ls" == basename( execname ) /
{
printf( "tracing process %d\n", pid );
system( "/root/dtrace/tracelibc.d %d", pid );
}
That should work, but in this case ls is such a short-lived process that something like this happens quite often:
dtrace: failed to compile script /root/dtrace/tracelibc.d: line 10:
failed to grab process 12289
The process is gone by the time dtrace gets going. If you're tracing long-lived processes and don't care that you might miss the first few probes because dtrace takes a while to attach, you're done.
But, if you want to trace short-lived processes, you need to stop the process right when it starts, then restart it after dtrace attaches:
#!/usr/sbin/dtrace -s
#pragma D option destructive
#pragma D option quiet
proc:::exec-success
/ "ls" == basename( execname ) /
{
printf( "stopping process %d\n", pid );
system( "/root/dtrace/tracelibc.d %d", pid );
stop();
}
and start it back up in tracelibc.d:
#!/usr/sbin/dtrace -s
#pragma D option destructive
BEGIN
{
system( "prun %d", $1 );
}
pid$1:libc::entry
{
printf( "func: %s\n", probefunc );
}
Note that I'm using Solaris prun to restart the stopped process. You'd have to look at the Mac dtrace documentation for the stop() call to get the Mac equivalent of Solaris prun.
But... ooops. The two scripts above combine to produce:
stopping process 12274
dtrace: failed to compile script /root/dtrace/tracelibc.d: line 10:
probe description pid12274:libc::entry does not match any probes
Why does this say pid12274:libc::entry doesn't match any probes? Oh, yeah - when exec returns, the libc.so shared object hasn't been loaded into memory yet. We need a probe that's guaranteed to exist in the target process, and that gets called after libc.so is loaded, but before any processing gets done. main should suffice. So the main script to start it all becomes:
#!/usr/sbin/dtrace -s
#pragma D option destructive
#pragma D option quiet
proc:::exec-success
/ "ls" == basename( execname ) /
{
printf( "stopping process %d\n", pid );
system( "/root/dtrace/tracemain.d %d", pid );
stop();
}
That starts the tracemain.d script, that restarts the process, loads the tracelibc.d script, and stops the process again:
#!/usr/sbin/dtrace -s
#pragma D option destructive
#pragma D option quiet
BEGIN
{
system( "prun %d", $1 );
}
pid$1::main:entry
{
system( "/root/dtrace/tracelibc.d %d", $1 );
stop();
/* this instance of dtrace is now done */
exit( 0 );
}
And tracelibc.d adds its own system( "prun %d", $1 ); in the BEGIN probe, and it looks like:
#!/usr/sbin/dtrace -s
#pragma D option destructive
BEGIN
{
system( "prun %d", $1 );
}
pid$1:libc::entry
{
printf( "func: %s\n", probefunc );
}
Those three really slow up the ls process, but they do produce the expected output - and there's a lot of it, as expected.
Linux Kernel : 4.13-rc7 x86_64
Configured Buildroot and Qemu for Linux Kernel Debugging.
Launch Qemu using following Command:
qemu-system-x86_64 -kernel linux-4.13-rc7/arch/x86/boot/bzImage -initrd buildroot-2017.02.5/output/images/rootfs.cpio -append "root=/dev/ram0 console=tty0 kgdboc=ttyS0,9600 kgdbwait" -chardev pty,id=pty -device isa-serial,chardev=pty
Now, In Next terminal window, launch gdb and proceed following gdb commands:
`
gdb-peda$ file vmlinux
Reading symbols from vmlinux...done.
warning: File "/root/drive/linux-4.13-rc7/scripts/gdb/vmlinux-gdb.py" auto-loading has been declined by your `auto-load safe-path' set to "$debugdir:$datadir/auto-load".
To enable execution of this file add
add-auto-load-safe-path /root/drive/linux-4.13-rc7/scripts/gdb/vmlinux-gdb.py
line to your configuration file "/root/.gdbinit".
To completely disable this security protection add
set auto-load safe-path /
line to your configuration file "/root/.gdbinit".
For more information about this security protection see the
"Auto-loading safe path" section in the GDB manual. E.g., run from the shell:
info "(gdb)Auto-loading safe path"
gdb-peda$ target remote /dev/pts/3
Remote debugging using /dev/pts/3
Warning: not running or target is remote
0xffffffffbd6f65af in ?? ()
gdb-peda$ b start_kernel
Breakpoint 1 at 0xffffffff81f79ad7: file init/main.c, line 510.
gdb-peda$ c
Continuing.
Warning:
Cannot insert breakpoint 1.
Cannot access memory at address 0xffffffff81f79ad7
Command aborted.
gdb-peda$ `
I also tried in Qemu machine:
echo "g" > /proc/sysrq-trigger. But, nothing happened .
Also, tried to set Hardware Breakpoints using hbreak on start_kernel, but nothing happened.
I figured out the solution by own , I did the following things to get working solution:
Apply patch to gdb then recompile it with patch in <$GDB_FOLDER>/gdb/remote.c file.
GDB Patch to resize its internal buffer :
`
root# diff -u gdb-8\ \(1\).0/gdb/remote.c gdb-8.0/gdb/remote.c
--- "gdb-8 (1).0/gdb/remote.c" 2017-06-04 21:24:54.000000000 +0530
+++ gdb-8.0/gdb/remote.c 2017-09-05 23:27:46.487820345 +0530
## -7583,7 +7583,27 ##
/* Further sanity checks, with knowledge of the architecture. */
if (buf_len > 2 * rsa->sizeof_g_packet)
- error (_("Remote 'g' packet reply is too long: %s"), rs->buf);
+ //error (_("Remote 'g' packet reply is too long: %s"), rs->buf); #patching
+ {
+ warning (_("Assuming long-mode change. [Remote 'g' packet reply is too long: %s]"), rs->buf);
+ rsa->sizeof_g_packet = buf_len ;
+
+ for (i = 0; i < gdbarch_num_regs (gdbarch); i++)
+ {
+ if (rsa->regs[i].pnum == -1)
+ continue;
+
+ if (rsa->regs[i].offset >= rsa->sizeof_g_packet)
+ rsa->regs[i].in_g_packet = 0;
+ else
+ rsa->regs[i].in_g_packet = 1;
+ }
+
+ // HACKFIX: Make sure at least the lower half of EIP is set correctly, so the proper
+ // breakpoint is recognized (and triggered).
+ rsa->regs[8].offset = 16*8;
+ }
+
/* Save the size of the packet sent to us by the target. It is used
as a heuristic when determining the max size of packets that the`
Build the minimal RootFS by Buildroot.
Launch Qemu by following command and launch new gdb then load vmlinux file .
In one terminal :
root# qemu-system-x86_64 -kernel /root/drive/linux-4.13-rc7/arch/x86/boot/bzImage -initrd /root/drive/buildroot-2017.02.5/output/images/rootfs.cpio -S -s
In another terminal :
gdb -q /root/drive/linux-4.13-rc7/vmlinux -ex "target remote localhost:1234"
Now set break point at start_kernel and continue, It will automatically hit the breakpoint.
I have an embedded Linux system running on an Atom, which is a new enough CPU to have an invariant TSC (time stamp counter), whose frequency the kernel measures on startup. I use the TSC in my own code to keep time (avoiding kernel calls), and my startup code measures the TSC rate, but I'd rather just use the kernel's measurement. Is there any way to retrieve this from the kernel? It's not in /proc/cpuinfo anywhere.
BPFtrace
As root, you can retrieve the kernel's TSC rate with bpftrace:
# bpftrace -e 'BEGIN { printf("%u\n", *kaddr("tsc_khz")); exit(); }' | tail -n
(tested it on CentOS 7 and Fedora 29)
That is the value that is defined, exported and maintained/calibrated in arch/x86/kernel/tsc.c.
GDB
Alternatively, also as root, you can also read it from /proc/kcore, e.g.:
# gdb /dev/null /proc/kcore -ex 'x/uw 0x'$(grep '\<tsc_khz\>' /proc/kallsyms \
| cut -d' ' -f1) -batch 2>/dev/null | tail -n 1 | cut -f2
(tested it on CentOS 7 and Fedora 29)
SystemTap
If the system doesn't have bpftrace nor gdb available but SystemTap you can get it like this (as root):
# cat tsc_khz.stp
#!/usr/bin/stap -g
function get_tsc_khz() %{ /* pure */
THIS->__retvalue = tsc_khz;
%}
probe oneshot {
printf("%u\n", get_tsc_khz());
}
# ./tsc_khz.stp
Of course, you can also write a small kernel module that provides access to tsc_khz via the /sys pseudo file system. Even better, somebody already did that and a tsc_freq_khz module is available on GitHub. With that the following should work:
# modprobe tsc_freq_khz
$ cat /sys/devices/system/cpu/cpu0/tsc_freq_khz
(tested on Fedora 29, reading the sysfs file doesn't require root)
Kernel Messages
In case nothing of the above is an option you can parse the TSC rate from the kernel logs. But this gets ugly fast because you see different kinds of messages on different hardware and kernels, e.g. on a Fedora 29 i7 system:
$ journalctl --boot | grep 'kernel: tsc:' -i | cut -d' ' -f5-
kernel: tsc: Detected 2800.000 MHz processor
kernel: tsc: Detected 2808.000 MHz TSC
But on a Fedora 29 Intel Atom just:
kernel: tsc: Detected 2200.000 MHz processor
While on a CentOS 7 i5 system:
kernel: tsc: Fast TSC calibration using PIT
kernel: tsc: Detected 1895.542 MHz processor
kernel: tsc: Refined TSC clocksource calibration: 1895.614 MHz
Perf Values
The Linux Kernel doesn't provide an API to read the TSC rate, yet. But it does provide one for getting the mult and shift values that can be used to convert TSC counts to nanoseconds. Those values are derived from tsc_khz - also in arch/x86/kernel/tsc.c - where tsc_khz is initialized and calibrated. And they are shared with userspace.
Example program that uses the perf API and accesses the shared page:
#include <asm/unistd.h>
#include <inttypes.h>
#include <linux/perf_event.h>
#include <stdio.h>
#include <sys/mman.h>
#include <unistd.h>
static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
int cpu, int group_fd, unsigned long flags)
{
return syscall(__NR_perf_event_open, hw_event, pid, cpu, group_fd, flags);
}
The actual code:
int main(int argc, char **argv)
{
struct perf_event_attr pe = {
.type = PERF_TYPE_HARDWARE,
.size = sizeof(struct perf_event_attr),
.config = PERF_COUNT_HW_INSTRUCTIONS,
.disabled = 1,
.exclude_kernel = 1,
.exclude_hv = 1
};
int fd = perf_event_open(&pe, 0, -1, -1, 0);
if (fd == -1) {
perror("perf_event_open failed");
return 1;
}
void *addr = mmap(NULL, 4*1024, PROT_READ, MAP_SHARED, fd, 0);
if (!addr) {
perror("mmap failed");
return 1;
}
struct perf_event_mmap_page *pc = addr;
if (pc->cap_user_time != 1) {
fprintf(stderr, "Perf system doesn't support user time\n");
return 1;
}
printf("%16s %5s\n", "mult", "shift");
printf("%16" PRIu32 " %5" PRIu16 "\n", pc->time_mult, pc->time_shift);
close(fd);
}
Tested in on Fedora 29 and it works also for non-root users.
Those values can be used to convert a TSC count to nanoseconds with a function like this one:
static uint64_t mul_u64_u32_shr(uint64_t cyc, uint32_t mult, uint32_t shift)
{
__uint128_t x = cyc;
x *= mult;
x >>= shift;
return x;
}
CPUID/MSR
Another way to obtain the TSC rate is to follow DPDK's lead.
DPDK on x86_64 basically uses the following strategy:
Read the 'Time Stamp Counter and Nominal Core Crystal Clock Information Leaf' via cpuid intrinsics (doesn't require special privileges), if available
Read it from the MSR (requires the rawio capability and read permissions on /dev/cpu/*/msr), if possible
Calibrate it in userspace by other means, otherwise
FWIW, a quick test shows that the cpuid leaf doesn't seem to be that widely available, e.g. an i7 Skylake and a goldmont atom don't have it. Otherwise, as can be seen from the DPDK code, using the MSR requires a bunch of intricate case distinctions.
However, in case the program already uses DPDK, getting the TSC rate, getting TSC values or converting TSC values is just a matter of using the right DPDK API.
I had a brief look and there doesn't seem to be a built-in way to directly get this information from the kernel.
However, the symbol tsc_khz (which I'm guessing is what you want) is exported by the kernel. You could write a small kernel module that exposes a sysfs interface and use that to read out the value of tsc_khz from userspace.
If writing a kernel module is not an option, it may be possible to use some Dark Magic™ to read out the value directly from the kernel memory space. Parse the kernel binary or System.map file to find the location of the tsc_khz symbol and read it from /dev/{k}mem. This is, of course, only possible provided that the kernel is configured with the appropriate options.
Lastly, from reading the kernel source comments, it looks like there's a possibility that the TSC may be unstable on some platforms. I don't know much about the inner workings of the x86 arch but this may be something you want to take into consideration.
The TSC rate is directly related to "cpu MHz" in /proc/cpuinfo. Actually, the better number to use is "bogomips". The reason is that while the freq for TSC is the max CPU freq, the current "cpu Mhz" can vary at time of your invocation.
The bogomips value is computed at boot. You'll need to adjust this value by number of cores and processor count (i.e. the number of hyperthreads) That gives you [fractional] MHz. That is what I use to do what you want to do.
To get the processor count, look for the last "processor: " line. The processor count is <value> + 1. Call it "cpu_count".
To get number of cores, any "cpu cores: " works. number of cores is <value>. Call it "core_count".
So, the formula is:
smt_count = cpu_count;
if (core_count)
smt_count /= core_count;
cpu_freq_in_khz = (bogomips * scale_factor) / smt_count;
That is extracted from my actual code, which is below.
Here's the actual code I use. You won't be able to use it directly because it relies on boilerplate I have, but it should give you some ideas, particularly with how to compute
// syslgx/tvtsc -- system time routines (RDTSC)
#include <tgb.h>
#include <zprt.h>
tgb_t systvinit_tgb[] = {
{ .tgb_val = 1, .tgb_tag = "cpu_mhz" },
{ .tgb_val = 2, .tgb_tag = "bogomips" },
{ .tgb_val = 3, .tgb_tag = "processor" },
{ .tgb_val = 4, .tgb_tag = "cpu_cores" },
{ .tgb_val = 5, .tgb_tag = "clflush_size" },
{ .tgb_val = 6, .tgb_tag = "cache_alignment" },
TGBEOT
};
// _systvinit -- get CPU speed
static void
_systvinit(void)
{
const char *file;
const char *dlm;
XFIL *xfsrc;
int matchflg;
char *cp;
char *cur;
char *rhs;
char lhs[1000];
tgb_pc tgb;
syskhz_t khzcpu;
syskhz_t khzbogo;
syskhz_t khzcur;
sysmpi_p mpi;
file = "/proc/cpuinfo";
xfsrc = fopen(file,"r");
if (xfsrc == NULL)
sysfault("systvinit: unable to open '%s' -- %s\n",file,xstrerror());
dlm = " \t";
khzcpu = 0;
khzbogo = 0;
mpi = &SYS->sys_cpucnt;
SYSZAPME(mpi);
// (1) look for "cpu MHz : 3192.515" (preferred)
// (2) look for "bogomips : 3192.51" (alternate)
// FIXME/CAE -- on machines with speed-step, bogomips may be preferred (or
// disable it)
while (1) {
cp = fgets(lhs,sizeof(lhs),xfsrc);
if (cp == NULL)
break;
// strip newline
cp = strchr(lhs,'\n');
if (cp != NULL)
*cp = 0;
// look for symbol value divider
cp = strchr(lhs,':');
if (cp == NULL)
continue;
// split symbol and value
*cp = 0;
rhs = cp + 1;
// strip trailing whitespace from symbol
for (cp -= 1; cp >= lhs; --cp) {
if (! XCTWHITE(*cp))
break;
*cp = 0;
}
// convert "foo bar" into "foo_bar"
for (cp = lhs; *cp != 0; ++cp) {
if (XCTWHITE(*cp))
*cp = '_';
}
// match on interesting data
matchflg = 0;
for (tgb = systvinit_tgb; TGBMORE(tgb); ++tgb) {
if (strcasecmp(lhs,tgb->tgb_tag) == 0) {
matchflg = tgb->tgb_val;
break;
}
}
if (! matchflg)
continue;
// look for the value
cp = strtok_r(rhs,dlm,&cur);
if (cp == NULL)
continue;
zprt(ZPXHOWSETUP,"_systvinit: GRAB/%d lhs='%s' cp='%s'\n",
matchflg,lhs,cp);
// process the value
// NOTE: because of Intel's speed step, take the highest cpu speed
switch (matchflg) {
case 1: // genuine CPU speed
khzcur = _systvinitkhz(cp);
if (khzcur > khzcpu)
khzcpu = khzcur;
break;
case 2: // the consolation prize
khzcur = _systvinitkhz(cp);
// we've seen some "wild" values
if (khzcur > 10000000)
break;
if (khzcur > khzbogo)
khzbogo = khzcur;
break;
case 3: // remember # of cpu's so we can adjust bogomips
mpi->mpi_cpucnt = atoi(cp);
mpi->mpi_cpucnt += 1;
break;
case 4: // remember # of cpu cores so we can adjust bogomips
mpi->mpi_corecnt = atoi(cp);
break;
case 5: // cache flush size
mpi->mpi_cshflush = atoi(cp);
break;
case 6: // cache alignment
mpi->mpi_cshalign = atoi(cp);
break;
}
}
fclose(xfsrc);
// we want to know the number of hyperthreads
mpi->mpi_smtcnt = mpi->mpi_cpucnt;
if (mpi->mpi_corecnt)
mpi->mpi_smtcnt /= mpi->mpi_corecnt;
zprt(ZPXHOWSETUP,"_systvinit: FINAL khzcpu=%d khzbogo=%d mpi_cpucnt=%d mpi_corecnt=%d mpi_smtcnt=%d mpi_cshalign=%d mpi_cshflush=%d\n",
khzcpu,khzbogo,mpi->mpi_cpucnt,mpi->mpi_corecnt,mpi->mpi_smtcnt,
mpi->mpi_cshalign,mpi->mpi_cshflush);
if ((mpi->mpi_cshalign == 0) || (mpi->mpi_cshflush == 0))
sysfault("_systvinit: cache parameter fault\n");
do {
// use the best reference
// FIXME/CAE -- with speed step, bogomips is better
#if 0
if (khzcpu != 0)
break;
#endif
khzcpu = khzbogo;
if (mpi->mpi_smtcnt)
khzcpu /= mpi->mpi_smtcnt;
if (khzcpu != 0)
break;
sysfault("_systvinit: unable to obtain cpu speed\n");
} while (0);
systvkhz(khzcpu);
zprt(ZPXHOWSETUP,"_systvinit: EXIT\n");
}
// _systvinitkhz -- decode value
// RETURNS: CPU freq in khz
static syskhz_t
_systvinitkhz(char *str)
{
char *src;
char *dst;
int rhscnt;
char bf[100];
syskhz_t khz;
zprt(ZPXHOWSETUP,"_systvinitkhz: ENTER str='%s'\n",str);
dst = bf;
src = str;
// get lhs of lhs.rhs
for (; *src != 0; ++src, ++dst) {
if (*src == '.')
break;
*dst = *src;
}
// skip over the dot
++src;
// get rhs of lhs.rhs and determine how many rhs digits we have
rhscnt = 0;
for (; *src != 0; ++src, ++dst, ++rhscnt)
*dst = *src;
*dst = 0;
khz = atol(bf);
zprt(ZPXHOWSETUP,"_systvinitkhz: PRESCALE bf='%s' khz=%d rhscnt=%d\n",
bf,khz,rhscnt);
// scale down (e.g. we got xxxx.yyyy)
for (; rhscnt > 3; --rhscnt)
khz /= 10;
// scale up (e.g. we got xxxx.yy--bogomips does this)
for (; rhscnt < 3; ++rhscnt)
khz *= 10;
zprt(ZPXHOWSETUP,"_systvinitkhz: EXIT khz=%d\n",khz);
return khz;
}
UPDATE:
Sigh. Yes.
I was using "cpu MHz" from /proc/cpuinfo prior to the introduction of processors with "speed step" technology, so I switched to "bogomips" and the algorithm was derived empirically based on that. When I derived it, I only had access to hyperthreaded machines. However, I've found an old one that is not and the SMT thing isn't valid.
However, it appears that bogomips is always 2x the [maximum] CPU speed. See http://www.clifton.nl/bogo-faq.html That hasn't always been my experience on all kernel versions over the years [IIRC, I started with 0.99.x], but it's probably a reliable assumption these days.
With "constant TSC" [which all newer processors have], denoted by constant_tsc in the flags: field in /proc/cpuinfo, the TSC rate is the maximum CPU frequency.
Originally, the only way to get the frequency information was from /proc/cpuinfo. Now, however, in more modern kernels, there is another way that may be easier and more definitive [I had code coverage for this in other software of mine, but had forgotten about it]:
/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq
The contents of this file is the maximum CPU frequency in kHz. There are analogous files for the other CPU cores. The files should be identical for most sane motherboards (e.g. ones that are composed of the same model chip and don't try to mix [say] i7s and atoms). Otherwise, you'd have to keep track of the info on a per-core basis and that would get messy fast.
The given directory also has other interesting files. For example, if your processor has "speed step" [and some of the other files can tell you that], you can force maximum performance by writing performance to the scaling_governor file. This will disable use of speed step.
If the processor did not have constant_tsc, you'd have to disable speed step [and run the cores at maximum rate] to get accurate measurements
I am trying to run the jmeter nongui command using java as follows:
Runtime rt = Runtime.getRuntime();
Process pr = rt.exec("C:\\apache-jmeter-2.13\\bin\\jmeter.bat -t \"C:\\jmeter scripts\\test.jmx\" -n -l \"C:\\jmeter scripts\\nonGUI.csv\"");
It runs perfectly fine, until I add the argument:
-Jusers=15 inside the command mentioned above in the next run.
The property set for the number of threads is: ${__P(users,10)}
The result file does not seem to fill up and the process seems to run forever under the CPU Resource monitor.
P.S.: Please do not suggest me to run the jmeter file using the steps given in the blazemeter website. It has used one of the deprecated method and there is no resolution given for the plausible runtime errors in that website.
I was not able to reproduce your error, but here is a complete example with JMX File. I removed the need for the "".
// OSX exmaple
public class r {
public static void main(String[] args) throws Exception {
Runtime rt = Runtime.getRuntime();
Process pr = rt.exec("/usr/local/bin/jmeter -t /Users/rfriedman/jmeter/SimpleUrl.jmx -Jusers=15 -n -l /Users/rfriedman/jmeter/nonGUI.csv");
}
}
Just to make sure I ran modified on Windows as well
// Windows Example
public class r {
public static void main(String[] args) throws Exception {
Runtime rt = Runtime.getRuntime();
Process pr = rt.exec("C:\\Users\\rfriedman\\Desktop\\apache-jmeter-2.13\\bin\\jmeter.bat -t C:\\Users\\rfriedman\\Desktop\\SimpleUrl.jmx -Jusers=20 -n -l C:\\Users\\rfriedman\\Desktop\\nonGUI.csv");
}
}
JMeter Test Plan
It works after I add the property value for Synchronization timer similar to Thread count.
Also, if I have to pass the value of -Jusers in the form of variable, how to do it? I am trying to do the following. But it's not getting executed.
eg:
int value=10;
Process pr = rt.exec("C:\Users\rfriedman\Desktop\apache-jmeter-2.13\bin\jmeter.bat -t C:\Users\rfriedman\Desktop\SimpleUrl.jmx -Jusers=value -n -l C:\Users\rfriedman\Desktop\nonGUI.csv");
Update:
I tried with String value="10"; as well. Still the jmeter logs says:
"jmeter.reporters.Summariser: summary = 0 in 0s = ******/s Avg: 0 Min: 9223372036854775807 Max: -9223372036854775808 Err: 0 (0.00%)"
Use this snippet.
int value = 10;
Runtime rt = Runtime.getRuntime();
Process pr = rt.exec("C:\\apache-jmeter-2.13\\bin\\jmeter.bat" +
" -t \"C:\\jmeter scripts\\test.jmx\" -Jusers=" + value + " -Jsync=" + value +
" -n -l \"C:\\jmeter scripts\\nonGUI.csv\" -j \"C:\\jmeter scripts\\jmeterLogs.log\"");
I'm writing a tool that calls through to DTrace to trace the program that the user specifies.
If my tool uses dtrace -c to run the program as a subprocess of DTrace, not only can I not pass any arguments to the program, but the program runs with all the privileges of DTrace—that is, as root (I'm on Mac OS X). This makes certain things that should work break, and obviously makes a great many things that shouldn't work possible.
The other solution I know of is to start the program myself, pause it by sending it SIGSTOP, pass its PID to dtrace -p, then continue it by sending it SIGCONT. The problem is that either the program runs for a few seconds without being traced while DTrace gathers the symbol information or, if I sleep for a few seconds before continuing the process, DTrace complains that objc<pid>:<class>:<method>:entry matches no probes.
Is there a way that I can run the program under the user's account, not as root, but still have DTrace able to trace it from the beginning?
Something like sudo dtruss -f sudo -u <original username> <command> has worked for me, but I felt bad about it afterwards.
I filed a Radar bug about it and had it closed as a duplicate of #5108629.
Well, this is a bit old, but why not :-)..
I don't think there is a way to do this simply from command line, but as suggested, a simple launcher application, such as the following, would do it. The manual attaching could of course also be replaced with a few calls to libdtrace.
int main(int argc, char *argv[]) {
pid_t pid = fork();
if(pid == 0) {
setuid(123);
seteuid(123);
ptrace(PT_TRACE_ME, 0, NULL, 0);
execl("/bin/ls", "/bin/ls", NULL);
} else if(pid > 0) {
int status;
wait(&status);
printf("Process %d started. Attach now, and click enter.\n", pid);
getchar();
ptrace(PT_CONTINUE, pid, (caddr_t) 1, 0);
}
return 0;
}
This script takes the name of the executable (for an app this is the info.plist's CFBundleExecutable) you want to monitor to DTrace as a parameter (you can then launch the target app after this script is running):
string gTarget; /* the name of the target executable */
dtrace:::BEGIN
{
gTarget = $$1; /* get the target execname from 1st DTrace parameter */
/*
* Note: DTrace's execname is limited to 15 characters so if $$1 has more
* than 15 characters the simple string comparison "($$1 == execname)"
* will fail. We work around this by copying the parameter passed in $$1
* to gTarget and truncating that to 15 characters.
*/
gTarget[15] = 0; /* truncate to 15 bytes */
gTargetPID = -1; /* invalidate target pid */
}
/*
* capture target launch (success)
*/
proc:::exec-success
/
gTarget == execname
/
{
gTargetPID = pid;
}
/*
* detect when our target exits
*/
syscall::*exit:entry
/
pid == gTargetPID
/
{
gTargetPID = -1; /* invalidate target pid */
}
/*
* capture open arguments
*/
syscall::open*:entry
/
((pid == gTargetPID) || progenyof(gTargetPID))
/
{
self->arg0 = arg0;
self->arg1 = arg1;
}
/*
* track opens
*/
syscall::open*:return
/
((pid == gTargetPID) || progenyof(gTargetPID))
/
{
this->op_kind = ((self->arg1 & O_ACCMODE) == O_RDONLY) ? "READ" : "WRITE";
this->path0 = self->arg0 ? copyinstr(self->arg0) : "<nil>";
printf("open for %s: <%s> #%d",
this->op_kind,
this->path0,
arg0);
}
If the other answer doesn't work for you, can you run the program in gdb, break in main (or even earlier), get the pid, and start the script? I've tried that in the past and it seemed to work.
Create a launcher program that will wait for a signal of some sort (not necessarily a literal signal, just an indication that it's ready), then exec() your target. Now dtrace -p the launcher program, and once dtrace is up, let the launcher go.
dtruss has the -n option where you can specify name of process you want to trace, without starting it (Credit to latter part of #kenorb's answer at https://stackoverflow.com/a/11706251/970301). So something like the following should do it:
sudo dtruss -n "$program"
$program
There exists a tool darwin-debug that ships in Apple's CLT LLDB.framework which will spawn your program and pause it before it does anything. You then read the pid out of the unix socket you pass as an argument, and after attaching the debugger/dtrace you continue the process.
darwin-debug will exec itself into a child process <PROGRAM> that is
halted for debugging. It does this by using posix_spawn() along with
darwin specific posix_spawn flags that allows exec only (no fork), and
stop at the program entry point. Any program arguments <PROGRAM-ARG> are
passed on to the exec as the arguments for the new process. The current
environment will be passed to the new process unless the "--no-env"
option is used. A unix socket must be supplied using the
--unix-socket=<SOCKET> option so the calling program can handshake with
this process and get its process id.
See my answer on related question "How can get dtrace to run the traced command with non-root priviledges?" [sic].
Essentially, you can start a (non-root) background process which waits 1sec for DTrace to start up (sorry for race condition), and snoops the PID of that process.
sudo true && \
(sleep 1; cat /etc/hosts) &; \
sudo dtrace -n 'syscall:::entry /pid == $1/ {#[probefunc] = count();}' $! \
&& kill $!
Full explanation in linked answer.