Skip to content

Commit 83a535e

Browse files
author
Philippe Waroquiers
committed
Enhance callgrind option --collect-system.
- The command option --collect-systime has been enhanced to specify the unit used to record the elapsed time spent during system calls. The command option now accepts the values no|yes|msec|usec|nsec, where yes is a synonym of msec. When giving the value nsec, the system cpu time of system calls is also recorded. Note that the nsec option is not supported on Darwin.
1 parent fe7ec1e commit 83a535e

File tree

9 files changed

+201
-46
lines changed

9 files changed

+201
-46
lines changed

NEWS

+5
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ support for X86/macOS 10.13 and AMD64/macOS 10.13.
3232
* Cachegrind:
3333

3434
* Callgrind:
35+
- The command option --collect-systime has been enhanced to specify
36+
the unit used to record the elapsed time spent during system calls.
37+
The command option now accepts the values no|yes|msec|usec|nsec,
38+
where yes is a synonym of msec. When giving the value nsec, the
39+
system cpu time of system calls is also recorded.
3540

3641
* Massif:
3742

callgrind/clo.c

+23-3
Original file line numberDiff line numberDiff line change
@@ -523,7 +523,23 @@ Bool CLG_(process_cmd_line_option)(const HChar* arg)
523523
else if VG_INT_CLO( arg, "--dump-every-bb", CLG_(clo).dump_every_bb) {}
524524

525525
else if VG_BOOL_CLO(arg, "--collect-alloc", CLG_(clo).collect_alloc) {}
526-
else if VG_BOOL_CLO(arg, "--collect-systime", CLG_(clo).collect_systime) {}
526+
else if VG_XACT_CLO(arg, "--collect-systime=no",
527+
CLG_(clo).collect_systime, systime_no) {}
528+
else if VG_XACT_CLO(arg, "--collect-systime=msec",
529+
CLG_(clo).collect_systime, systime_msec) {}
530+
else if VG_XACT_CLO(arg, "--collect-systime=yes", /* backward compatibility. */
531+
CLG_(clo).collect_systime, systime_msec) {}
532+
else if VG_XACT_CLO(arg, "--collect-systime=usec",
533+
CLG_(clo).collect_systime, systime_usec) {}
534+
else if VG_XACT_CLO(arg, "--collect-systime=nsec",
535+
CLG_(clo).collect_systime, systime_nsec) {
536+
# if defined(VGO_darwin)
537+
VG_(fmsg_bad_option)
538+
(arg,
539+
"--collect-systime=nsec not supported on darwin\n");
540+
# endif
541+
}
542+
527543
else if VG_BOOL_CLO(arg, "--collect-bus", CLG_(clo).collect_bus) {}
528544
/* for option compatibility with cachegrind */
529545
else if VG_BOOL_CLO(arg, "--cache-sim", CLG_(clo).simulate_cache) {}
@@ -580,7 +596,11 @@ void CLG_(print_usage)(void)
580596
#if CLG_EXPERIMENTAL
581597
" --collect-alloc=no|yes Collect memory allocation info? [no]\n"
582598
#endif
583-
" --collect-systime=no|yes Collect system call time info? [no]\n"
599+
" --collect-systime=no|yes|msec|usec|nsec Collect system call time info? [no]\n"
600+
" no Do not collect system call time info.\n"
601+
" msec|yes Collect syscount, syscall elapsed time (milli-seconds).\n"
602+
" usec Collect syscount, syscall elapsed time (micro-seconds).\n"
603+
" nsec Collect syscount, syscall elapsed and syscall cpu time (nano-seconds).\n"
584604

585605
"\n cost entity separation options:\n"
586606
" --separate-threads=no|yes Separate data per thread [no]\n"
@@ -646,7 +666,7 @@ void CLG_(set_clo_defaults)(void)
646666
CLG_(clo).collect_atstart = True;
647667
CLG_(clo).collect_jumps = False;
648668
CLG_(clo).collect_alloc = False;
649-
CLG_(clo).collect_systime = False;
669+
CLG_(clo).collect_systime = systime_no;
650670
CLG_(clo).collect_bus = False;
651671

652672
CLG_(clo).skip_plt = True;

callgrind/docs/cl-manual.xml

+16-2
Original file line numberDiff line numberDiff line change
@@ -800,11 +800,25 @@ Also see <xref linkend="cl-manual.limits"/>.</para>
800800

801801
<varlistentry id="opt.collect-systime" xreflabel="--collect-systime">
802802
<term>
803-
<option><![CDATA[--collect-systime=<no|yes> [default: no] ]]></option>
803+
<option><![CDATA[--collect-systime=<no|yes|msec|usec|nsec> [default: no] ]]></option>
804804
</term>
805805
<listitem>
806806
<para>This specifies whether information for system call times
807-
should be collected.</para>
807+
should be collected.</para>
808+
<para>The value <computeroutput>no</computeroutput> indicates to record
809+
no system call information.</para>
810+
<para>The other values indicate to record the number of system calls
811+
done (sysCount event) and the elapsed time (sysTime event) spent
812+
in system calls.
813+
The <computeroutput>--collect-systime</computeroutput> value gives
814+
the unit used for sysTime : milli seconds, micro seconds or nano
815+
seconds. With the value <computeroutput>nsec</computeroutput>,
816+
callgrind also records the cpu time spent during system calls
817+
(sysCpuTime).</para>
818+
<para>The value <computeroutput>yes</computeroutput> is a synonym
819+
of <computeroutput>msec</computeroutput>.
820+
The value <computeroutput>nsec</computeroutput> is not supported
821+
on Darwin.</para>
808822
</listitem>
809823
</varlistentry>
810824

callgrind/dump.c

+15
Original file line numberDiff line numberDiff line change
@@ -1305,6 +1305,21 @@ static VgFile *new_dumpfile(int tid, const HChar* trigger)
13051305
HChar *evmap = CLG_(eventmapping_as_string)(CLG_(dumpmap));
13061306
VG_(fprintf)(fp, "events: %s\n", evmap);
13071307
VG_(free)(evmap);
1308+
switch (CLG_(clo).collect_systime) {
1309+
case systime_no: break;
1310+
case systime_msec:
1311+
VG_(fprintf)(fp, "event: sysTime : sysTime (elapsed ms)\n");
1312+
break;
1313+
case systime_usec:
1314+
VG_(fprintf)(fp, "event: sysTime : sysTime (elapsed us)\n");
1315+
break;
1316+
case systime_nsec:
1317+
VG_(fprintf)(fp, "event: sysTime : sysTime (elapsed ns)\n");
1318+
VG_(fprintf)(fp, "event: sysCpuTime : sysCpuTime (system cpu ns)\n");
1319+
break;
1320+
default:
1321+
tl_assert(0);
1322+
}
13081323

13091324
/* summary lines */
13101325
sum = CLG_(get_eventset_cost)( CLG_(sets).full );

callgrind/global.h

+14-6
Original file line numberDiff line numberDiff line change
@@ -58,18 +58,26 @@
5858
/* Enable experimental features? */
5959
#define CLG_EXPERIMENTAL 0
6060

61-
/* Syscall Timing in microseconds?
62-
* (define to 0 if you get compile errors) */
63-
#define CLG_MICROSYSTIME 0
64-
65-
6661

6762
/*------------------------------------------------------------*/
6863
/*--- Command line options ---*/
6964
/*------------------------------------------------------------*/
7065

7166
#define DEFAULT_OUTFORMAT "callgrind.out.%p"
7267

68+
/* If and how to collect syscall time.
69+
systime_no : do not collect systime
70+
systime_msec : collect syscount, systime elapsed, milli second precision.
71+
systime_usec : collect syscount, systime elapsed, micro second precision.
72+
systime_nsec : collect syscount, systime elapsed, systime cpu, nano second
73+
precision. */
74+
typedef enum {
75+
systime_no,
76+
systime_msec,
77+
systime_usec,
78+
systime_nsec
79+
} Collect_Systime;
80+
7381
typedef struct _CommandLineOptions CommandLineOptions;
7482
struct _CommandLineOptions {
7583

@@ -100,7 +108,7 @@ struct _CommandLineOptions {
100108
Bool collect_jumps; /* Collect (cond.) jumps in functions ? */
101109

102110
Bool collect_alloc; /* Collect size of allocated memory */
103-
Bool collect_systime; /* Collect time for system calls */
111+
Collect_Systime collect_systime; /* Collect time for system calls */
104112

105113
Bool collect_bus; /* Collect global bus events */
106114

callgrind/main.c

+97-33
Original file line numberDiff line numberDiff line change
@@ -1697,60 +1697,115 @@ Bool CLG_(handle_client_request)(ThreadId tid, UWord *args, UWord *ret)
16971697
}
16981698

16991699

1700-
/* Syscall Timing */
1700+
/* Syscall Timing. syscalltime[tid] is the time at which thread tid last
1701+
started a syscall. */
1702+
1703+
/* struct vki_timespec syscalltime[VG_N_THREADS];
1704+
Whatever the syscall we use to measure the syscall time, we convert to
1705+
seconds and nanoseconds. */
1706+
struct vki_timespec *syscalltime;
1707+
struct vki_timespec *syscallcputime;
17011708

1702-
/* struct timeval syscalltime[VG_N_THREADS]; */
1703-
#if CLG_MICROSYSTIME
1704-
ULong *syscalltime;
1705-
#else
1706-
UInt *syscalltime;
1707-
#endif
1709+
1710+
static
1711+
void collect_time (struct vki_timespec *systime, struct vki_timespec *syscputime)
1712+
{
1713+
switch (CLG_(clo).collect_systime) {
1714+
case systime_no: tl_assert (0);
1715+
case systime_msec: {
1716+
UInt ms_timer = VG_(read_millisecond_timer)();
1717+
systime->tv_sec = ms_timer / 1000;
1718+
systime->tv_nsec = (ms_timer % 1000) * 1000000L;
1719+
break;
1720+
}
1721+
case systime_usec: {
1722+
struct vki_timeval tv_now;
1723+
VG_(gettimeofday)(&tv_now, NULL);
1724+
systime->tv_sec = tv_now.tv_sec;
1725+
systime->tv_nsec = tv_now.tv_usec * 1000;
1726+
break;
1727+
}
1728+
case systime_nsec:
1729+
# if defined(VGO_linux) || defined(VGO_solaris)
1730+
VG_(clock_gettime)(systime, VKI_CLOCK_MONOTONIC);
1731+
VG_(clock_gettime)(syscputime, VKI_CLOCK_THREAD_CPUTIME_ID);
1732+
1733+
# elif defined(VGO_darwin)
1734+
tl_assert(0);
1735+
# else
1736+
# error "Unknown OS"
1737+
# endif
1738+
break;
1739+
}
1740+
}
17081741

17091742
static
17101743
void CLG_(pre_syscalltime)(ThreadId tid, UInt syscallno,
17111744
UWord* args, UInt nArgs)
17121745
{
1713-
if (CLG_(clo).collect_systime) {
1714-
#if CLG_MICROSYSTIME
1715-
struct vki_timeval tv_now;
1716-
VG_(gettimeofday)(&tv_now, NULL);
1717-
syscalltime[tid] = tv_now.tv_sec * 1000000ULL + tv_now.tv_usec;
1718-
#else
1719-
syscalltime[tid] = VG_(read_millisecond_timer)();
1720-
#endif
1746+
collect_time(&syscalltime[tid],
1747+
CLG_(clo).collect_systime == systime_nsec ? &syscallcputime[tid] : NULL);
1748+
}
1749+
1750+
/* Returns "after - before" in the unit as specified by --collect-systime.
1751+
after is supposed to be >= before, and tv_nsec must be >= 0 and < One_Second_In_Nsec. */
1752+
static
1753+
ULong vki_timespec_diff (struct vki_timespec after, struct vki_timespec before)
1754+
{
1755+
vki_time_t diff_sec = after.tv_sec - before.tv_sec;
1756+
long diff_nsec = after.tv_nsec - before.tv_nsec;
1757+
ULong nsec_factor; // factor to convert the desired unit into nsec.
1758+
1759+
if (diff_nsec < 0) {
1760+
diff_sec--;
1761+
diff_nsec += 1000000000ULL;
1762+
}
1763+
switch (CLG_(clo).collect_systime) {
1764+
case systime_no: tl_assert (0);
1765+
case systime_msec: nsec_factor = 1000000ULL; break;
1766+
case systime_usec: nsec_factor = 1000ULL; break;
1767+
case systime_nsec: nsec_factor = 1ULL; break;
1768+
default: tl_assert(0);
17211769
}
1770+
return ((ULong) diff_sec * 1000000000ULL + diff_nsec) / nsec_factor;
17221771
}
17231772

17241773
static
17251774
void CLG_(post_syscalltime)(ThreadId tid, UInt syscallno,
17261775
UWord* args, UInt nArgs, SysRes res)
17271776
{
1728-
if (CLG_(clo).collect_systime &&
1729-
CLG_(current_state).bbcc) {
1730-
Int o;
1731-
#if CLG_MICROSYSTIME
1732-
struct vki_timeval tv_now;
1777+
if (CLG_(current_state).bbcc) {
1778+
Int o;
1779+
struct vki_timespec ts_now;
1780+
struct vki_timespec ts_cpunow;
17331781
ULong diff;
1734-
1735-
VG_(gettimeofday)(&tv_now, NULL);
1736-
diff = (tv_now.tv_sec * 1000000ULL + tv_now.tv_usec) - syscalltime[tid];
1737-
#else
1738-
UInt diff = VG_(read_millisecond_timer)() - syscalltime[tid];
1739-
#endif
17401782

1741-
/* offset o is for "SysCount", o+1 for "SysTime" */
1783+
collect_time(&ts_now,
1784+
CLG_(clo).collect_systime == systime_nsec ? &ts_cpunow : NULL);
1785+
1786+
diff = vki_timespec_diff (ts_now, syscalltime[tid]);
1787+
1788+
/* offset o is for "SysCount", o+1 for "SysTime",
1789+
o+2 is (optionally) "SysCpuTime". */
17421790
o = fullOffset(EG_SYS);
17431791
CLG_ASSERT(o>=0);
17441792
CLG_DEBUG(0," Time (Off %d) for Syscall %u: %llu\n", o, syscallno,
1745-
(ULong)diff);
1746-
1747-
CLG_(current_state).cost[o] ++;
1748-
CLG_(current_state).cost[o+1] += diff;
1793+
diff);
1794+
17491795
if (!CLG_(current_state).bbcc->skipped)
17501796
CLG_(init_cost_lz)(CLG_(sets).full,
17511797
&(CLG_(current_state).bbcc->skipped));
1798+
CLG_(current_state).cost[o] ++;
1799+
CLG_(current_state).cost[o+1] += diff;
17521800
CLG_(current_state).bbcc->skipped[o] ++;
17531801
CLG_(current_state).bbcc->skipped[o+1] += diff;
1802+
if (CLG_(clo).collect_systime == systime_nsec) {
1803+
diff = vki_timespec_diff (ts_cpunow, syscallcputime[tid]);
1804+
CLG_DEBUG(0," SysCpuTime (Off %d) for Syscall %u: %llu\n", o+2, syscallno,
1805+
diff);
1806+
CLG_(current_state).cost[o+2] += diff;
1807+
CLG_(current_state).bbcc->skipped[o+2] += diff;
1808+
}
17541809
}
17551810
}
17561811

@@ -1973,13 +2028,22 @@ void CLG_(post_clo_init)(void)
19732028
"sp-at-mem-access\n");
19742029
}
19752030

1976-
if (CLG_(clo).collect_systime) {
2031+
if (CLG_(clo).collect_systime != systime_no) {
19772032
VG_(needs_syscall_wrapper)(CLG_(pre_syscalltime),
19782033
CLG_(post_syscalltime));
19792034
syscalltime = CLG_MALLOC("cl.main.pci.1",
19802035
VG_N_THREADS * sizeof syscalltime[0]);
19812036
for (UInt i = 0; i < VG_N_THREADS; ++i) {
1982-
syscalltime[i] = 0;
2037+
syscalltime[i].tv_sec = 0;
2038+
syscalltime[i].tv_nsec = 0;
2039+
}
2040+
if (CLG_(clo).collect_systime == systime_nsec) {
2041+
syscallcputime = CLG_MALLOC("cl.main.pci.2",
2042+
VG_N_THREADS * sizeof syscallcputime[0]);
2043+
for (UInt i = 0; i < VG_N_THREADS; ++i) {
2044+
syscallcputime[i].tv_sec = 0;
2045+
syscallcputime[i].tv_nsec = 0;
2046+
}
19832047
}
19842048
}
19852049

callgrind/sim.c

+7-2
Original file line numberDiff line numberDiff line change
@@ -1625,8 +1625,12 @@ void CLG_(init_eventsets)()
16251625
if (CLG_(clo).collect_alloc)
16261626
CLG_(register_event_group2)(EG_ALLOC, "allocCount", "allocSize");
16271627

1628-
if (CLG_(clo).collect_systime)
1629-
CLG_(register_event_group2)(EG_SYS, "sysCount", "sysTime");
1628+
if (CLG_(clo).collect_systime != systime_no) {
1629+
if (CLG_(clo).collect_systime == systime_nsec)
1630+
CLG_(register_event_group3)(EG_SYS, "sysCount", "sysTime", "sysCpuTime");
1631+
else
1632+
CLG_(register_event_group2)(EG_SYS, "sysCount", "sysTime");
1633+
}
16301634

16311635
// event set used as base for instruction self cost
16321636
CLG_(sets).base = CLG_(get_event_set2)(EG_USE, EG_IR);
@@ -1670,6 +1674,7 @@ void CLG_(init_eventsets)()
16701674
CLG_(append_event)(CLG_(dumpmap), "allocSize");
16711675
CLG_(append_event)(CLG_(dumpmap), "sysCount");
16721676
CLG_(append_event)(CLG_(dumpmap), "sysTime");
1677+
CLG_(append_event)(CLG_(dumpmap), "sysCpuTime");
16731678
}
16741679

16751680

coregrind/m_libcproc.c

+14
Original file line numberDiff line numberDiff line change
@@ -962,6 +962,20 @@ UInt VG_(read_millisecond_timer) ( void )
962962
return (now - base) / 1000;
963963
}
964964

965+
# if defined(VGO_linux) || defined(VGO_solaris)
966+
void VG_(clock_gettime) ( struct vki_timespec *ts, vki_clockid_t clk_id )
967+
{
968+
SysRes res;
969+
res = VG_(do_syscall2)(__NR_clock_gettime, clk_id,
970+
(UWord)ts);
971+
vg_assert (sr_isError(res) == 0);
972+
}
973+
# elif defined(VGO_darwin)
974+
/* See pub_tool_libcproc.h */
975+
# else
976+
# error "Unknown OS"
977+
# endif
978+
965979
Int VG_(gettimeofday)(struct vki_timeval *tv, struct vki_timezone *tz)
966980
{
967981
SysRes res;

include/pub_tool_libcproc.h

+10
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,16 @@ extern UInt VG_(read_millisecond_timer) ( void );
103103

104104
extern Int VG_(gettimeofday)(struct vki_timeval *tv, struct vki_timezone *tz);
105105

106+
# if defined(VGO_linux) || defined(VGO_solaris)
107+
/* Get the clock value as specified by clk_id. Asserts if unsuccesful. */
108+
extern void VG_(clock_gettime)(struct vki_timespec *ts, vki_clockid_t clk_id);
109+
# elif defined(VGO_darwin)
110+
/* It seems clock_gettime is only available on recent Darwin versions.
111+
For the moment, let's assume it is not available. */
112+
# else
113+
# error "Unknown OS"
114+
# endif
115+
106116
// Returns the number of milliseconds of user cpu time we have used,
107117
// as reported by 'getrusage'.
108118
extern UInt VG_(get_user_milliseconds)(void);

0 commit comments

Comments
 (0)