You can subscribe to this list here.
| 2002 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
(1) |
Oct
(122) |
Nov
(152) |
Dec
(69) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2003 |
Jan
(6) |
Feb
(25) |
Mar
(73) |
Apr
(82) |
May
(24) |
Jun
(25) |
Jul
(10) |
Aug
(11) |
Sep
(10) |
Oct
(54) |
Nov
(203) |
Dec
(182) |
| 2004 |
Jan
(307) |
Feb
(305) |
Mar
(430) |
Apr
(312) |
May
(187) |
Jun
(342) |
Jul
(487) |
Aug
(637) |
Sep
(336) |
Oct
(373) |
Nov
(441) |
Dec
(210) |
| 2005 |
Jan
(385) |
Feb
(480) |
Mar
(636) |
Apr
(544) |
May
(679) |
Jun
(625) |
Jul
(810) |
Aug
(838) |
Sep
(634) |
Oct
(521) |
Nov
(965) |
Dec
(543) |
| 2006 |
Jan
(494) |
Feb
(431) |
Mar
(546) |
Apr
(411) |
May
(406) |
Jun
(322) |
Jul
(256) |
Aug
(401) |
Sep
(345) |
Oct
(542) |
Nov
(308) |
Dec
(481) |
| 2007 |
Jan
(427) |
Feb
(326) |
Mar
(367) |
Apr
(255) |
May
(244) |
Jun
(204) |
Jul
(223) |
Aug
(231) |
Sep
(354) |
Oct
(374) |
Nov
(497) |
Dec
(362) |
| 2008 |
Jan
(322) |
Feb
(482) |
Mar
(658) |
Apr
(422) |
May
(476) |
Jun
(396) |
Jul
(455) |
Aug
(267) |
Sep
(280) |
Oct
(253) |
Nov
(232) |
Dec
(304) |
| 2009 |
Jan
(486) |
Feb
(470) |
Mar
(458) |
Apr
(423) |
May
(696) |
Jun
(461) |
Jul
(551) |
Aug
(575) |
Sep
(134) |
Oct
(110) |
Nov
(157) |
Dec
(102) |
| 2010 |
Jan
(226) |
Feb
(86) |
Mar
(147) |
Apr
(117) |
May
(107) |
Jun
(203) |
Jul
(193) |
Aug
(238) |
Sep
(300) |
Oct
(246) |
Nov
(23) |
Dec
(75) |
| 2011 |
Jan
(133) |
Feb
(195) |
Mar
(315) |
Apr
(200) |
May
(267) |
Jun
(293) |
Jul
(353) |
Aug
(237) |
Sep
(278) |
Oct
(611) |
Nov
(274) |
Dec
(260) |
| 2012 |
Jan
(303) |
Feb
(391) |
Mar
(417) |
Apr
(441) |
May
(488) |
Jun
(655) |
Jul
(590) |
Aug
(610) |
Sep
(526) |
Oct
(478) |
Nov
(359) |
Dec
(372) |
| 2013 |
Jan
(467) |
Feb
(226) |
Mar
(391) |
Apr
(281) |
May
(299) |
Jun
(252) |
Jul
(311) |
Aug
(352) |
Sep
(481) |
Oct
(571) |
Nov
(222) |
Dec
(231) |
| 2014 |
Jan
(185) |
Feb
(329) |
Mar
(245) |
Apr
(238) |
May
(281) |
Jun
(399) |
Jul
(382) |
Aug
(500) |
Sep
(579) |
Oct
(435) |
Nov
(487) |
Dec
(256) |
| 2015 |
Jan
(338) |
Feb
(357) |
Mar
(330) |
Apr
(294) |
May
(191) |
Jun
(108) |
Jul
(142) |
Aug
(261) |
Sep
(190) |
Oct
(54) |
Nov
(83) |
Dec
(22) |
| 2016 |
Jan
(49) |
Feb
(89) |
Mar
(33) |
Apr
(50) |
May
(27) |
Jun
(34) |
Jul
(53) |
Aug
(53) |
Sep
(98) |
Oct
(206) |
Nov
(93) |
Dec
(53) |
| 2017 |
Jan
(65) |
Feb
(82) |
Mar
(102) |
Apr
(86) |
May
(187) |
Jun
(67) |
Jul
(23) |
Aug
(93) |
Sep
(65) |
Oct
(45) |
Nov
(35) |
Dec
(17) |
| 2018 |
Jan
(26) |
Feb
(35) |
Mar
(38) |
Apr
(32) |
May
(8) |
Jun
(43) |
Jul
(27) |
Aug
(30) |
Sep
(43) |
Oct
(42) |
Nov
(38) |
Dec
(67) |
| 2019 |
Jan
(32) |
Feb
(37) |
Mar
(53) |
Apr
(64) |
May
(49) |
Jun
(18) |
Jul
(14) |
Aug
(53) |
Sep
(25) |
Oct
(30) |
Nov
(49) |
Dec
(31) |
| 2020 |
Jan
(87) |
Feb
(45) |
Mar
(37) |
Apr
(51) |
May
(99) |
Jun
(36) |
Jul
(11) |
Aug
(14) |
Sep
(20) |
Oct
(24) |
Nov
(40) |
Dec
(23) |
| 2021 |
Jan
(14) |
Feb
(53) |
Mar
(85) |
Apr
(15) |
May
(19) |
Jun
(3) |
Jul
(14) |
Aug
(1) |
Sep
(57) |
Oct
(73) |
Nov
(56) |
Dec
(22) |
| 2022 |
Jan
(3) |
Feb
(22) |
Mar
(6) |
Apr
(55) |
May
(46) |
Jun
(39) |
Jul
(15) |
Aug
(9) |
Sep
(11) |
Oct
(34) |
Nov
(20) |
Dec
(36) |
| 2023 |
Jan
(79) |
Feb
(41) |
Mar
(99) |
Apr
(169) |
May
(48) |
Jun
(16) |
Jul
(16) |
Aug
(57) |
Sep
(19) |
Oct
|
Nov
|
Dec
|
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
|
|
|
|
|
1
(20) |
2
(19) |
3
(7) |
|
4
(13) |
5
(24) |
6
(9) |
7
(12) |
8
(8) |
9
(34) |
10
(28) |
|
11
(20) |
12
(23) |
13
(12) |
14
(10) |
15
(15) |
16
(24) |
17
(26) |
|
18
(17) |
19
(14) |
20
(14) |
21
(8) |
22
(12) |
23
(22) |
24
(10) |
|
25
(21) |
26
(21) |
27
(18) |
28
(8) |
29
(13) |
30
(15) |
|
|
From: <sv...@va...> - 2007-11-03 23:27:01
|
Author: sewardj
Date: 2007-11-03 23:26:57 +0000 (Sat, 03 Nov 2007)
New Revision: 7086
Log:
Write loads more documentation. Is turning into a minor treatise ...
Modified:
branches/THRCHECK/thrcheck/docs/tc-manual.xml
Modified: branches/THRCHECK/thrcheck/docs/tc-manual.xml
===================================================================
--- branches/THRCHECK/thrcheck/docs/tc-manual.xml 2007-11-03 11:16:31 UTC (rev 7085)
+++ branches/THRCHECK/thrcheck/docs/tc-manual.xml 2007-11-03 23:26:57 UTC (rev 7086)
@@ -11,73 +11,547 @@
command line.</para>
+
+
<sect1 id="tc-manual.overview" xreflabel="Overview">
<title>Overview</title>
-<para>Thrcheck is a Valgrind tool for detecting threading errors in C,
-C++ and Fortran programs that use the POSIX Pthreads library.</para>
+<para>Thrcheck is a Valgrind tool for detecting synchronisation errors
+in C, C++ and Fortran programs that use the POSIX pthreads
+threading primitives.</para>
-<para>The main abstractions in POSIX Pthreads are: a set of threads
-sharing a common address space, mutexes (locks), condition variables
-(inter-thread event notifications), thread creation, thread joinage
-and thread exit.</para>
+<para>The main abstractions in POSIX pthreads are: a set of threads
+sharing a common address space, thread creation, thread joinage,
+thread exit, mutexes (locks), condition variables (inter-thread event
+notifications), reader-writer locks, and semaphores.</para>
-<para>Thrcheck can detect three the following three classes of
-errors:</para>
+<para>Thrcheck is aware of all these abstractions and tracks their
+effects as accurately as it can. Currently it does not correctly
+handle pthread barriers and pthread spinlocks, although it will not
+object if you use them. On x86 and amd64 platforms, it understands
+and partially handles implicit locking arising from the use of the
+LOCK instruction prefix.
+</para>
+<para>Thrcheck can detect three classes of errors, which are discussed
+in detail in the next three sections:</para>
+
<orderedlist>
<listitem>
- <para>Misuses of the POSIX Pthreads API. Because the tool observes all
- significant thread events (creation, joinage, exit, lock, unlock,
- wait, signal, broadcast), it can report various common problems:</para>
- <itemizedlist>
- <listitem><para>unlocking a not-locked mutex</para></listitem>
- <listitem><para>unlocking a mutex held by a different
- thread</para></listitem>
- <listitem><para>recursively locking a non-recursive mutex</para></listitem>
- <listitem><para>waiting for a condition variable without holding
- the associated mutex</para></listitem>
- <listitem><para>inconsistent association of mutex and condition
- variables in pthread_cond_wait</para></listitem>
- <listitem><para>threads which exit while holding locked
- mutexes</para></listitem>
- <listitem><para>deallocation of memory that contains a
- locked mutex</para></listitem>
- </itemizedlist>
+ <para>Section FIXME: Misuses of the POSIX pthreads API.</para>
</listitem>
-
<listitem>
- <para>Potential deadlocks arising from lock ordering problems. If
- threads must acquire more than one lock before accessing some shared
- resource, then all threads must acquire those locks in the same
- order. Not doing so risks deadlock. Detecting such inconsistencies
- is useful because, whilst actual deadlocks are fairly obvious,
- potential deadlocks may never be discovered during testing and could
- later lead to hard-to-diagnose in-service failures.
- </para>
- <para>
- Detecting such problems is a simple matter of keeping track of
- observed lock acquisition orderings and reporting when new
- acquisitions violate the existing ordering.</para>
+ <para>Section FIXME: Potential deadlocks arising from lock ordering
+ problems.</para>
</listitem>
-
<listitem>
- <para>Data races. A data race happens, or could happen, when two threads
- access a shared memory location without using suitable locks to
- ensure single-threaded access. Such missing locking can cause
- obscure timing dependent bugs. Ensuring programs are race-free is
- one of the central difficulties of threaded programming.</para>
+ <para>Section FIXME: Data races -- accessing memory without adequate
+ locking.</para>
</listitem>
</orderedlist>
+<para>Section FIXME contains guidance on how to get the best out of Thrcheck.
+This is really a discussion about debugging strategies and how to
+organise your program to enhance its verifiability.</para>
+
+<para>Section FIXME contains a summary of command-line options.</para>
+
+<para>Finally, Section FIXME contains a brief list of areas in which Thrcheck
+could be improved.</para>
+
</sect1>
+
+
+<sect1 id="tc-manual.api-checks" xreflabel="API Checks">
+<title>Detected errors: Misuses of the POSIX pthreads API</title>
+
+<para>Thrcheck intercepts calls to many POSIX pthreads functions, and
+is therefore able to report on various common problems. Although
+these are unglamourous errors, their presence can lead to undefined
+program behaviour and hard-to-find bugs later in execution. The
+detected errors include:</para>
+
+<itemizedlist>
+ <listitem><para>unlocking an invalid mutex</para></listitem>
+ <listitem><para>unlocking a not-locked mutex</para></listitem>
+ <listitem><para>unlocking a mutex held by a different
+ thread</para></listitem>
+ <listitem><para>destroying an invalid or a locked mutex</para></listitem>
+ <listitem><para>recursively locking a non-recursive mutex</para></listitem>
+ <listitem><para>deallocation of memory that contains a
+ locked mutex</para></listitem>
+ <listitem><para>passing mutex arguments to functions expecting
+ reader-writer lock arguments, and vice
+ versa</para></listitem>
+ <listitem><para>when a POSIX pthread function fails with an
+ error code that must be handled</para></listitem>
+</itemizedlist>
+
+<para>Checks pertaining to the validity of mutexes are generally also
+performed for reader-writer locks.</para>
+
+<para>Reported errors always contain a primary stack trace indicating
+where the error was detected. They may also contain auxiliary stack
+traces giving additional information. In particular, most errors
+relating to mutexes will also tell you where that mutex first came to
+Thrcheck's attention (the "<computeroutput>was first observed
+at</computeroutput>" part), so you have a chance of figuring out which
+mutex it is referring to. For example:</para>
+
+<programlisting><![CDATA[
+Thread #1 unlocked a not-locked lock at 0x7FEFFFA90
+ at 0x4C2408D: pthread_mutex_unlock (tc_intercepts.c:492)
+ by 0x40073A: nearly_main (tc09_bad_unlock.c:27)
+ by 0x40079B: main (tc09_bad_unlock.c:50)
+ Lock at 0x7FEFFFA90 was first observed
+ at 0x4C25D01: pthread_mutex_init (tc_intercepts.c:326)
+ by 0x40071F: nearly_main (tc09_bad_unlock.c:23)
+ by 0x40079B: main (tc09_bad_unlock.c:50)
+]]></programlisting>
+
+<para>Thrcheck has a way of summarising thread identities, as
+evidenced here by the text "<computeroutput>Thread
+#1</computeroutput>". This is so that it can speak about threads and
+sets of threads without overwhelming you with details. See FIXME
+below for details.</para>
+
+</sect1>
+
+
+
+
+<sect1 id="tc-manual.lock-orders" xreflabel="Lock Orders">
+<title>Detected errors: Inconsistent Lock Orderings</title>
+
+<para>In this section, and in general, to "acquire" a lock simply
+means to lock that lock, and to "release" a lock means to unlock
+it.</para>
+
+<para>Thrcheck monitors the order in which threads acquire locks.
+This allows it to detect potential deadlocks which could arise from
+the formation of cycles of locks. Detecting such inconsistencies is
+useful because, whilst actual deadlocks are fairly obvious, potential
+deadlocks may never be discovered during testing and could later lead
+to hard-to-diagnose in-service failures.</para>
+
+<para>The simplest example of such a problem is as
+follows.</para>
+
+<itemizedlist>
+ <listitem><para>Imagine some shared resource R, which, for whatever
+ reason, is guarded by two locks, L1 and L2, which must both be held
+ when R is accessed.</para>
+ </listitem>
+ <listitem><para>Suppose a thread acquires L1, then L2, and proceeds
+ to access R. The implication of this is that all threads in the
+ program must acquire the two locks in the order first L1 then L2.
+ Not doing so risks deadlock.</para>
+ </listitem>
+ <listitem><para>The deadlock could happen if two threads -- call them
+ T1 and T2 -- both want to access R. Suppose T1 acquires L1 first,
+ and T2 acquires L2 first. Then T1 tries to acquire L2, and T2 tries
+ to acquire L1, but those locks are both already held. So T1 and T2
+ become deadlocked.</para>
+ </listitem>
+</itemizedlist>
+
+<para>Thrcheck builds a directed graph indicating the order in which
+locks have been acquired in the past. When a thread acquires a new
+lock, the graph is updated, and then checked to see if it now contains
+a cycle. Presence of a cycle indicates a potential deadlock involving
+the locks in the cycle.</para>
+
+<para>In simple situations, where the cycle only contains two locks,
+Thrcheck will show where the required order was established:</para>
+
+<programlisting><![CDATA[
+Thread #1: lock order "0x7FEFFFAB0 before 0x7FEFFFA80" violated
+ at 0x4C23C91: pthread_mutex_lock (tc_intercepts.c:388)
+ by 0x40081F: main (tc13_laog1.c:24)
+ Required order was established by acquisition of lock at 0x7FEFFFAB0
+ at 0x4C23C91: pthread_mutex_lock (tc_intercepts.c:388)
+ by 0x400748: main (tc13_laog1.c:17)
+ followed by a later acquisition of lock at 0x7FEFFFA80
+ at 0x4C23C91: pthread_mutex_lock (tc_intercepts.c:388)
+ by 0x400773: main (tc13_laog1.c:18)
+]]></programlisting>
+
+<para>When there are more than two locks in the cycle, the error is
+equally serious. However, at present Thrcheck does not show the locks
+involved, so as to avoid flooding you with information. That could be
+fixed in future. For example, here is a an example involving a cycle
+of five locks from a naive implementation the famous Dining
+Philosophers problem
+(see <computeroutput>thrcheck/tests/tc14_laog_dinphils.c</computeroutput>).
+In this case Thrcheck has detected that all 5 philosophers could
+simultaneously pick up their left fork and then deadlock whilst
+waiting to pick up their right forks.</para>
+
+<programlisting><![CDATA[
+Thread #6: lock order "0x6010C0 before 0x601160" violated
+ at 0x4C23C91: pthread_mutex_lock (tc_intercepts.c:388)
+ by 0x4007C0: dine (tc14_laog_dinphils.c:19)
+ by 0x4C25DF7: mythread_wrapper (tc_intercepts.c:178)
+ by 0x4E2F09D: start_thread (in /lib64/libpthread-2.5.so)
+ by 0x51054CC: clone (in /lib64/libc-2.5.so)
+]]></programlisting>
+
+</sect1>
+
+
+
+
<sect1 id="tc-manual.data-races" xreflabel="Data Races">
-<title>Data Races</title>
+<title>Detected errors: Data Races</title>
-This section describes Thrcheck's data race detection in more detail.
+<para>A data race happens, or could happen, when two threads
+access a shared memory location without using suitable locks to
+ensure single-threaded access. Such missing locking can cause
+obscure timing dependent bugs. Ensuring programs are race-free is
+one of the central difficulties of threaded programming.</para>
+<para>Reliably detecting races is a difficult problem, and most
+of Thrcheck's internals are devoted to do dealing with it.
+As a consequence this section is somewhat long and involved.
+We begin with a simple example.</para>
+
+
+<sect2 id="tc-manual.data-races.example" xreflabel="Simple Race">
+<title>A simple data race</title>
+
+<para>About the simplest possible example of a race is as follows. In
+this program, it is impossible to know what the value
+of <computeroutput>var</computeroutput> is at the end of the program.
+Is it 2 ? Or 1 ?</para>
+
+<programlisting><![CDATA[
+#include <pthread.h>
+
+int var = 0;
+
+void* child_fn ( void* arg ) {
+ var++; /* Unprotected relative to parent */ /* this is line 6 */
+ return NULL;
+}
+
+int main ( void ) {
+ pthread_t child;
+ pthread_create(&child, NULL, child_fn, NULL);
+ var++; /* Unprotected relative to child */ /* this is line 13 */
+ pthread_join(child, NULL);
+ return 0;
+}
+]]></programlisting>
+
+<para>The problem is there is nothing to
+stop <computeroutput>var</computeroutput> being updated simultaneously
+by both threads. A correct program would
+protect <computeroutput>var</computeroutput> with a lock of type
+<computeroutput>pthread_mutex_t</computeroutput>, which is acquired
+before each access and released afterwards. Thrcheck's output for
+this program is:</para>
+
+<programlisting><![CDATA[
+Thread #1 is the program's root thread
+
+Thread #2 was created
+ at 0x510548E: clone (in /lib64/libc-2.5.so)
+ by 0x4E2F305: do_clone (in /lib64/libpthread-2.5.so)
+ by 0x4E2F7C5: pthread_create@@GLIBC_2.2.5 (in /lib64/libpthread-2.5.so)
+ by 0x4C23870: pthread_create@* (tc_intercepts.c:198)
+ by 0x4005F1: main (simple_race.c:12)
+
+Possible data race during write of size 4 at 0x601034
+ at 0x4005F2: main (simple_race.c:13)
+ Old state: shared-readonly by threads #1, #2
+ New state: shared-modified by threads #1, #2
+ Reason: this thread, #1, holds no consistent locks
+ Location 0x601034 has never been protected by any lock
+]]></programlisting>
+
+<para>This is quite a lot of detail for an apparently simple error.
+The last clause is the main error message. It says there is a race as
+a result of a write of size 4 (bytes), at 0x601034, which is
+presumably the address of <computeroutput>var</computeroutput>,
+happening in function <computeroutput>main</computeroutput> at line 13
+in the program.</para>
+
+<para>Note that it is purely by chance that the race is
+reported for the parent thread's access. It could equally have been
+reported instead for the child's access, at line 6. The error will
+only be reported for one of the locations, since neither the parent
+nor child is, by itself, incorrect. It is only when both access
+<computeroutput>var</computeroutput> without a lock that an error
+exists.</para>
+
+<para>The error message shows some other interesting details. The
+sections below explain them. Here we merely note their presence:</para>
+
+<itemizedlist>
+ <listitem><para>Thrcheck maintains some kind of state machine for the
+ memory location in question, hence the "<computeroutput>Old
+ state:</computeroutput>" and "<computeroutput>New
+ state:</computeroutput>" lines.</para>
+ </listitem>
+ <listitem><para>Thrcheck keeps track of which threads have accessed
+ the location: "<computeroutput>threads #1, #2</computeroutput>".
+ Before printing the main error message, it prints the creation
+ points of these two threads, so you can see which threads it is
+ referring to.</para>
+ </listitem>
+ <listitem><para>Thrcheck tries to provide an explaination of why the
+ race exists: "<computeroutput>Location 0x601034 has never been
+ protected by any lock</computeroutput>".</para>
+ </listitem>
+</itemizedlist>
+
+<para>Understanding the memory state machine is central to
+understanding Thrcheck's race-detection algorithm. The next two
+subsections explain this.</para>
+
+</sect2>
+
+
+<sect2 id="tc-manual.data-races.memstates" xreflabel="Memory States">
+<title>Thrcheck's Memory State Machine</title>
+
+<para>Thrcheck tracks the state of every byte of memory used by your
+program. There are a number of states, but only three are
+interesting:</para>
+
+<itemizedlist>
+ <listitem><para>Exclusive: memory in this state is regarded as owned
+ exclusively by one particular thread. That thread may read and
+ write it without a lock. Even in highly threaded programs, the
+ majority of locations never leave the Exclusive state, since most
+ data is thread-private.</para>
+ </listitem>
+ <listitem><para>Shared-Readonly: memory in this state is regarded as
+ shared by multiple threads. In this state, any thread may read the
+ memory without a lock, reflecting the fact that readonly data may
+ safely be shared between threads without locking.</para>
+ </listitem>
+ <listitem><para>Shared-Modified: memory in this state is regarded as
+ shared by multiple threads, at least one of which has written to it.
+ All participating threads must hold at least one lock in common when
+ accessing the memory. If no such lock exists, Thrcheck reports a
+ race error.</para>
+ </listitem>
+</itemizedlist>
+
+<para>Let's review the simple example above with this in mind. When
+the program starts, <computeroutput>var</computeroutput> is not in any
+of these states. Either the parent or child thread gets to its
+<computeroutput>var++</computeroutput> first, and thereby
+thereby gets Exclusive ownership of the location.</para>
+
+<para>The later-running thread now arrives at
+its <computeroutput>var++</computeroutput> statement. It first reads
+the existing value from memory.
+Because <computeroutput>var</computeroutput> is currently marked as
+owned exclusively by the other thread, its state is changed to
+shared-readonly by both threads.</para>
+
+<para>This same thread adds one to the value it has and stores it back
+in <computeroutput>var</computeroutput>. This causes another state
+change, this time to the shared-modified state. Because Thrcheck has
+also been tracking which threads hold which locks, it can see that
+<computeroutput>var</computeroutput> is in shared-modified state but
+no lock has been used to consistently protect it. Hence a race is
+reported exactly at the transition from shared-readonly to
+shared-modified.</para>
+
+<para>The essence of the algorithm is this. Thrcheck keeps track of
+each memory location that has been accessed by more than one thread.
+For each such location it incrementally infers the set of locks which
+have consistently been used to protect that location. If the
+location's lockset becomes empty, and at some point one of the threads
+attempts to write to it, a race is then reported.</para>
+
+<para>This technique is known as "lockset inference" and was
+introduced in FIXME. It has been widely implemented since then.
+Thrcheck incorporates several refinements aimed at reducing the false
+error rate generated by a naive version of the algorithm. In section
+FIXME a summary of the complete algorithm used by Thrcheck is
+presented. First, however, it is important to understand details of
+transitions pertaining to the Exclusive-ownership state.</para>
+
+</sect2>
+
+
+
+<sect2 id="tc-manual.data-races.exclusive" xreflabel="Excl Transfers">
+<title>Transfers of Exclusive Ownership Between Threads</title>
+
+<para>As presented, the algorithm is far too strict. It reports many
+errors in perfectly correct, widely used parallel programming
+constructions, for example, using child worker threads and worker
+thread pools.</para>
+
+<para>To avoid these false errors, we must refine the algorithm so
+that it keeps memory in an Exclusive ownership state in cases where it
+would otherwise decay into a shared-readonly or shared-modified state.
+Recall that Exclusive ownership is special in that it grants the
+owning thread the right to access memory without use of any locks. In
+order to support worker-thread and worker-thread-pool idioms, we will
+allow threads to steal exclusive ownership of memory from other
+threads under certain circumstances.</para>
+
+<para>Here's an example. Imagine a parent thread creates child
+threads to do units of work. For each unit of work, the parent
+allocates a work buffer, fills it in, and creates the child thread,
+handing it a pointer to the buffer. The child reads/writes the buffer
+and eventually exits, and the waiting parent then extracts the results
+from the buffer:</para>
+
+<programlisting><![CDATA[
+typedef ... Buffer;
+
+pthread_t child;
+Buffer buf;
+
+/* ---- Parent ---- */ /* ---- Child ---- */
+
+/* parent writes workload into buf */
+pthread_create( &child, child_fn, &buf );
+
+/* parent does not read */ void child_fn ( Buffer* buf ) {
+/* or write buf */ /* read/write buf */
+ }
+
+pthread_join ( child );
+/* parent reads results from buf */
+]]></programlisting>
+
+<para>Although <computeroutput>buf</computeroutput> is accessed by
+both threads, neither uses locks, yet the program is race-free. The
+essential observation is that the child's creation and exit create
+synchronisation events between it and the parent. These force the
+child's accesses to <computeroutput>buf</computeroutput> to happen
+after the parent initialises <computeroutput>buf</computeroutput>, and
+before the parent reads the results
+from <computeroutput>buf</computeroutput>.</para>
+
+<para>To model this, Thrcheck allows the child to steal, from the
+parent, exclusive ownership of any memory exclusively owned by the
+parent before the pthread_create call. Similarly, once the parent's
+pthread_join call returns, it can steal back ownership of memory
+exclusively owned by the child. In this way ownership
+of <computeroutput>buf</computeroutput> is transferred from parent to
+child and back, so the basic algorithm does not report any races
+despite the absence of any locking.</para>
+
+<para>Note that the child may only steal memory owned by the parent
+prior to the pthread_create call. If the child attempts to read or
+write memory which is also accessed by the parent in between the
+pthread_create and pthread_join calls, an error is still
+reported.</para>
+
+<para>This technique was introduced in FIXME with the name Thread
+Lifetime Segments. Thrcheck implements an extended version of it.
+Specifically, Thrcheck allows transfer of exclusive ownership in the
+following situations:</para>
+
+<itemizedlist>
+ <listitem><para>At thread creation: a child can acquire ownership of
+ memory held exclusively by the parent prior to the child's
+ creation.</para>
+ </listitem>
+ <listitem><para>At thread joining: the joiner (thread not exiting)
+ can acquire ownership of memory held exclusively by the joinee
+ (thread that is exiting) at the point it exited.</para>
+ </listitem>
+ <listitem><para>At condition variable signallings and broadcasts. A
+ thread Twait which completes a pthread_cond_wait call as a result of
+ a signal or broadcast on the same condition variable by some other
+ thread Tsig, may acquire ownership of memory held exclusively by
+ Tsig prior to the pthread_cond_signal/broadcast
+ call.</para>
+ </listitem>
+ <listitem><para>At semaphore posts (sem_post) calls. A thread Twait
+ which completes a sem_wait call call as a result of a sem_post call
+ on the same semaphore by some other thread Tpost, may acquire
+ ownership of memory held exclusively by Tpost prior to the sem_post
+ call.</para>
+ </listitem>
+</itemizedlist>
+
+
+
+</sect2>
+
+<sect2 id="tc-manual.data-races.re-excl" xreflabel="Re-Excl Transfers">
+<title>Reacquisition of Exclusive States</title>
+
+<para>Another common idiom is to partition the lifetime of the program
+as a whole into several distinct phases. In some of those phases, a
+memory location may be accessed by multiple threads and so require
+locking. In other phases only one thread exists and so can access the
+memory without locking. For example:</para>
+
+<programlisting><![CDATA[
+int var = 0; /* shared variable */
+pthread_mutex_t mx = PTHREAD_MUTEX_INITIALIZER; /* guard for var */
+pthread_t child;
+
+/* ---- Parent ---- */ /* ---- Child ---- */
+
+var += 1; /* no lock used */
+
+pthread_create( &child, child_fn, NULL );
+
+ void child_fn ( void* uu ) {
+pthread_mutex_lock(&mx); pthread_mutex_lock(&mx);
+var += 2; var += 3;
+pthread_mutex_unlock(&mx); pthread_mutex_unlock(&mx);
+ }
+
+pthread_join ( child );
+
+var += 4; /* no lock used */
+]]></programlisting>
+
+<para>This program is correct, but using only the mechanisms described
+so far, Thrcheck would report an error at
+<computeroutput>var += 4;</computeroutput>. This is because, by that
+point, <computeroutput>var</computeroutput> is marked as being in the
+state "shared-modified with a singleton
+lockset <computeroutput>{mx}</computeroutput>". Really, what we want
+is for <computeroutput>var</computeroutput> to return to the parent
+thread's exclusive ownership after the child thread has exited.</para>
+
+<para>To make this possible, for every memory location Thrcheck also keeps
+track of all the threads that have accessed that location
+-- its threadset. When a thread Tquitter joins back to Tstayer,
+Thrcheck examines the locksets of all memory in shared-modified or
+shared-readable state. In each such lockset, if Tquitter is
+mentioned, it is removed and replaced by Tstayer. If, as a result, a
+lockset becomes a singleton set containing Tstayer, then the
+location's state is changed to belongs-exclusively-to-Tstayer.</para>
+
+<para>In our example, the result is exactly as we desire:
+<computeroutput>var</computeroutput> is reacquired exclusively by the
+parent after the child exits.</para>
+
+<para>More generally, when a group of threads merges back to a single
+thread via a cascade of pthread_join calls, any memory shared by the
+group (or a subset of it) ends up being owned exclusively by the sole
+surviving thread. This significantly enhances Thrcheck's flexibility,
+since it means that memory can transition arbitrarily many times
+between exclusive and shared states over the lifetime of the program.
+Moreover, locations may be protected by different locks during
+different phases of shared ownership.</para>
+
+
+
+
+
+</sect2>
+
+<para>-------------------------------------------------</para>
+
<para>In short, what Thrcheck does is to look for memory locations
which are accessed by more than one thread. For each such location,
Thrcheck records which of the program's (pthread_mutex_)locks were
@@ -199,6 +673,26 @@
</sect1>
+
+<sect1 id="tc-manual.effective-use" xreflabel="Thrcheck Effective Use">
+<title>Hints and Tips for Effective Use of Thrcheck</title>
+
+
+<para>Thrcheck can be very helpful in finding and resolving
+threading-related problems. Like all sophisticated tools, it is most
+effective when you have some level of understanding of what the tool
+is doing. Thrcheck will be less effective when you merely throw an
+existing threaded program at it and try to make sense of any reported
+errors. It will be more effective if you design threaded programs
+from the start in a way that helps Thrcheck verify correctness. The
+same is true for finding memory errors with Memcheck, but applies more
+here, because thread checking is a harder problem.</para>
+
+</sect1>
+
+
+
+
<sect1 id="tc-manual.options" xreflabel="Thrcheck Options">
<title>Thrcheck Options</title>
@@ -276,6 +770,13 @@
</para></listitem>
</itemizedlist>
+Inconsistent cv/mx associations
+Thread exiting whilst holding locks
+
+waiting for a condition variable without holding
+ the associated mutex
+
+better printing of lock cycles
</sect1>
</chapter>
|
|
From: <sv...@va...> - 2007-11-03 11:16:32
|
Author: sewardj
Date: 2007-11-03 11:16:31 +0000 (Sat, 03 Nov 2007)
New Revision: 7085
Log:
Fix gcc-2.96 build failures.
Modified:
trunk/massif/tests/long-time.c
trunk/massif/tests/new-cpp.cpp
trunk/massif/tests/overloaded-new.cpp
Modified: trunk/massif/tests/long-time.c
===================================================================
--- trunk/massif/tests/long-time.c 2007-11-02 21:44:02 UTC (rev 7084)
+++ trunk/massif/tests/long-time.c 2007-11-03 11:16:31 UTC (rev 7085)
@@ -7,15 +7,15 @@
int main(void)
{
- int i;
+ int i, *x1, *x2, *x3, *x4;
for (i = 0; i < 1500; i++) {
- int* x1 = malloc( 800 * 1000);
- int* x2 = malloc(1100 * 1000);
+ x1 = malloc( 800 * 1000);
+ x2 = malloc(1100 * 1000);
free(x1);
- int* x3 = malloc(1200 * 1000);
+ x3 = malloc(1200 * 1000);
free(x2);
free(x3);
- int* x4 = malloc( 900 * 1000);
+ x4 = malloc( 900 * 1000);
free(x4);
}
return 0;
Modified: trunk/massif/tests/new-cpp.cpp
===================================================================
--- trunk/massif/tests/new-cpp.cpp 2007-11-02 21:44:02 UTC (rev 7084)
+++ trunk/massif/tests/new-cpp.cpp 2007-11-03 11:16:31 UTC (rev 7085)
@@ -10,14 +10,14 @@
using std::nothrow_t;
// A big structure. Its details don't matter.
-struct s {
- int array[1000];
-};
+typedef struct {
+ int array[1000];
+ } s;
int main(void)
{
- struct s* p1 = new struct s;
- struct s* p2 = new (std::nothrow) struct s;
+ s* p1 = new s;
+ s* p2 = new (std::nothrow) s;
char* c1 = new char[2000];
char* c2 = new (std::nothrow) char[2000];
delete p1;
Modified: trunk/massif/tests/overloaded-new.cpp
===================================================================
--- trunk/massif/tests/overloaded-new.cpp 2007-11-02 21:44:02 UTC (rev 7084)
+++ trunk/massif/tests/overloaded-new.cpp 2007-11-03 11:16:31 UTC (rev 7085)
@@ -10,9 +10,9 @@
using std::nothrow_t;
// A big structure. Its details don't matter.
-struct s {
- int array[1000];
-};
+typedef struct {
+ int array[1000];
+ } s;
void* operator new (std::size_t n) throw (std::bad_alloc)
{
@@ -46,8 +46,8 @@
int main(void)
{
- struct s* p1 = new struct s;
- struct s* p2 = new (std::nothrow) struct s;
+ s* p1 = new s;
+ s* p2 = new (std::nothrow) s;
char* c1 = new char[2000];
char* c2 = new (std::nothrow) char[2000];
delete p1;
|
|
From: Tom H. <th...@cy...> - 2007-11-03 03:23:38
|
Nightly build on dellow ( x86_64, Fedora 7 ) started at 2007-11-03 03:10:03 GMT Results differ from 24 hours ago Checking out valgrind source tree ... done Configuring valgrind ... done Building valgrind ... done Running regression tests ... failed Regression test results follow == 320 tests, 4 stderr failures, 2 stdout failures, 0 post failures == memcheck/tests/pointer-trace (stderr) memcheck/tests/vcpu_fnfns (stdout) memcheck/tests/x86/scalar (stderr) memcheck/tests/xml1 (stderr) none/tests/mremap (stderr) none/tests/mremap2 (stdout) ================================================= == Results from 24 hours ago == ================================================= Checking out valgrind source tree ... done Configuring valgrind ... done Building valgrind ... done Running regression tests ... failed Regression test results follow == 320 tests, 5 stderr failures, 4 stdout failures, 8 post failures == memcheck/tests/pointer-trace (stderr) memcheck/tests/vcpu_fnfns (stdout) memcheck/tests/x86/scalar (stderr) memcheck/tests/xml1 (stderr) massif/tests/basic (post) massif/tests/custom_alloc (post) massif/tests/deep-D (post) massif/tests/ignoring (post) massif/tests/new-cpp (post) massif/tests/overloaded-new (post) massif/tests/peak (post) massif/tests/peak2 (stderr) massif/tests/peak2 (post) none/tests/mremap (stderr) none/tests/mremap2 (stdout) none/tests/pth_cvsimple (stdout) none/tests/pth_detached (stdout) ================================================= == Difference between 24 hours ago and now == ================================================= *** old.short Sat Nov 3 03:16:55 2007 --- new.short Sat Nov 3 03:23:38 2007 *************** *** 8,10 **** ! == 320 tests, 5 stderr failures, 4 stdout failures, 8 post failures == memcheck/tests/pointer-trace (stderr) --- 8,10 ---- ! == 320 tests, 4 stderr failures, 2 stdout failures, 0 post failures == memcheck/tests/pointer-trace (stderr) *************** *** 13,27 **** memcheck/tests/xml1 (stderr) - massif/tests/basic (post) - massif/tests/custom_alloc (post) - massif/tests/deep-D (post) - massif/tests/ignoring (post) - massif/tests/new-cpp (post) - massif/tests/overloaded-new (post) - massif/tests/peak (post) - massif/tests/peak2 (stderr) - massif/tests/peak2 (post) none/tests/mremap (stderr) none/tests/mremap2 (stdout) - none/tests/pth_cvsimple (stdout) - none/tests/pth_detached (stdout) --- 13,16 ---- |
|
From: Tom H. <th...@cy...> - 2007-11-03 03:23:17
|
Nightly build on lloyd ( x86_64, Fedora 7 ) started at 2007-11-03 03:05:06 GMT Results differ from 24 hours ago Checking out valgrind source tree ... done Configuring valgrind ... done Building valgrind ... done Running regression tests ... failed Regression test results follow == 320 tests, 4 stderr failures, 2 stdout failures, 0 post failures == memcheck/tests/pointer-trace (stderr) memcheck/tests/vcpu_fnfns (stdout) memcheck/tests/x86/scalar (stderr) memcheck/tests/xml1 (stderr) none/tests/mremap (stderr) none/tests/mremap2 (stdout) ================================================= == Results from 24 hours ago == ================================================= Checking out valgrind source tree ... done Configuring valgrind ... done Building valgrind ... done Running regression tests ... failed Regression test results follow == 320 tests, 5 stderr failures, 2 stdout failures, 8 post failures == memcheck/tests/pointer-trace (stderr) memcheck/tests/vcpu_fnfns (stdout) memcheck/tests/x86/scalar (stderr) memcheck/tests/xml1 (stderr) massif/tests/basic (post) massif/tests/custom_alloc (post) massif/tests/deep-D (post) massif/tests/ignoring (post) massif/tests/new-cpp (post) massif/tests/overloaded-new (post) massif/tests/peak (post) massif/tests/peak2 (stderr) massif/tests/peak2 (post) none/tests/mremap (stderr) none/tests/mremap2 (stdout) ================================================= == Difference between 24 hours ago and now == ================================================= *** old.short Sat Nov 3 03:13:02 2007 --- new.short Sat Nov 3 03:23:16 2007 *************** *** 8,10 **** ! == 320 tests, 5 stderr failures, 2 stdout failures, 8 post failures == memcheck/tests/pointer-trace (stderr) --- 8,10 ---- ! == 320 tests, 4 stderr failures, 2 stdout failures, 0 post failures == memcheck/tests/pointer-trace (stderr) *************** *** 13,23 **** memcheck/tests/xml1 (stderr) - massif/tests/basic (post) - massif/tests/custom_alloc (post) - massif/tests/deep-D (post) - massif/tests/ignoring (post) - massif/tests/new-cpp (post) - massif/tests/overloaded-new (post) - massif/tests/peak (post) - massif/tests/peak2 (stderr) - massif/tests/peak2 (post) none/tests/mremap (stderr) --- 13,14 ---- |
|
From: Tom H. <th...@cy...> - 2007-11-03 03:21:22
|
Nightly build on alvis ( i686, Red Hat 7.3 ) started at 2007-11-03 03:15:02 GMT
Results differ from 24 hours ago
Checking out valgrind source tree ... done
Configuring valgrind ... done
Building valgrind ... done
Running regression tests ... failed
Last 20 lines of verbose log follow echo
fi
gcc -Winline -Wall -Wshadow -g -m32 -Wno-long-long -o long-time long-time.o
if g++ -DHAVE_CONFIG_H -I. -I. -I../.. -I../.. -I../../include -I../../coregrind -I../../include -I../../VEX/pub -g -O2 -MT new-cpp.o -MD -MP -MF ".deps/new-cpp.Tpo" \
-c -o new-cpp.o `test -f 'new-cpp.cpp' || echo './'`new-cpp.cpp; \
then mv -f ".deps/new-cpp.Tpo" ".deps/new-cpp.Po"; \
else rm -f ".deps/new-cpp.Tpo"; exit 1; \
fi
new-cpp.cpp: In function `int main()':
new-cpp.cpp:20: invalid use of undefined type `struct main()::s'
new-cpp.cpp:20: forward declaration of `struct main()::s'
new-cpp.cpp:20: ISO C++ forbids defining types within new
make[4]: *** [new-cpp.o] Error 1
make[4]: Leaving directory `/tmp/vgtest/2007-11-03/valgrind/massif/tests'
make[3]: *** [check-am] Error 2
make[3]: Leaving directory `/tmp/vgtest/2007-11-03/valgrind/massif/tests'
make[2]: *** [check-recursive] Error 1
make[2]: Leaving directory `/tmp/vgtest/2007-11-03/valgrind/massif'
make[1]: *** [check-recursive] Error 1
make[1]: Leaving directory `/tmp/vgtest/2007-11-03/valgrind'
make: *** [check] Error 2
=================================================
== Results from 24 hours ago ==
=================================================
Checking out valgrind source tree ... done
Configuring valgrind ... failed
Last 20 lines of verbose log follow echo
A valgrind/VEX/quote.txt
A valgrind/VEX/Makefile
A valgrind/VEX/LICENSE.README
U valgrind/VEX
Checked out external at revision 1791.
Checked out revision 7079.
Configuring valgrind ... cd valgrind && ./autogen.sh && ./configure --prefix=/tmp/vgtest/2007-11-03/Inst
running: aclocal
running: autoheader
running: automake -a
configure.in: installing `./install-sh'
configure.in: installing `./mkinstalldirs'
configure.in: installing `./missing'
configure.in:116: installing `./config.guess'
configure.in:116: installing `./config.sub'
auxprogs/Makefile.am: installing `./compile'
auxprogs/Makefile.am: installing `./depcomp'
EXTRA_DIST: variable `noinst_SCRIPTS' is used but `noinst_SCRIPTS' is undefined
error: while running 'automake -a'
=================================================
== Difference between 24 hours ago and now ==
=================================================
*** old.short Sat Nov 3 03:16:11 2007
--- new.short Sat Nov 3 03:21:22 2007
***************
*** 2,25 ****
Checking out valgrind source tree ... done
! Configuring valgrind ... failed
Last 20 lines of verbose log follow echo
! A valgrind/VEX/quote.txt
! A valgrind/VEX/Makefile
! A valgrind/VEX/LICENSE.README
! U valgrind/VEX
! Checked out external at revision 1791.
!
! Checked out revision 7079.
! Configuring valgrind ... cd valgrind && ./autogen.sh && ./configure --prefix=/tmp/vgtest/2007-11-03/Inst
! running: aclocal
! running: autoheader
! running: automake -a
! configure.in: installing `./install-sh'
! configure.in: installing `./mkinstalldirs'
! configure.in: installing `./missing'
! configure.in:116: installing `./config.guess'
! configure.in:116: installing `./config.sub'
! auxprogs/Makefile.am: installing `./compile'
! auxprogs/Makefile.am: installing `./depcomp'
! EXTRA_DIST: variable `noinst_SCRIPTS' is used but `noinst_SCRIPTS' is undefined
! error: while running 'automake -a'
--- 2,27 ----
Checking out valgrind source tree ... done
! Configuring valgrind ... done
! Building valgrind ... done
! Running regression tests ... failed
Last 20 lines of verbose log follow echo
! fi
! gcc -Winline -Wall -Wshadow -g -m32 -Wno-long-long -o long-time long-time.o
! if g++ -DHAVE_CONFIG_H -I. -I. -I../.. -I../.. -I../../include -I../../coregrind -I../../include -I../../VEX/pub -g -O2 -MT new-cpp.o -MD -MP -MF ".deps/new-cpp.Tpo" \
! -c -o new-cpp.o `test -f 'new-cpp.cpp' || echo './'`new-cpp.cpp; \
! then mv -f ".deps/new-cpp.Tpo" ".deps/new-cpp.Po"; \
! else rm -f ".deps/new-cpp.Tpo"; exit 1; \
! fi
! new-cpp.cpp: In function `int main()':
! new-cpp.cpp:20: invalid use of undefined type `struct main()::s'
! new-cpp.cpp:20: forward declaration of `struct main()::s'
! new-cpp.cpp:20: ISO C++ forbids defining types within new
! make[4]: *** [new-cpp.o] Error 1
! make[4]: Leaving directory `/tmp/vgtest/2007-11-03/valgrind/massif/tests'
! make[3]: *** [check-am] Error 2
! make[3]: Leaving directory `/tmp/vgtest/2007-11-03/valgrind/massif/tests'
! make[2]: *** [check-recursive] Error 1
! make[2]: Leaving directory `/tmp/vgtest/2007-11-03/valgrind/massif'
! make[1]: *** [check-recursive] Error 1
! make[1]: Leaving directory `/tmp/vgtest/2007-11-03/valgrind'
! make: *** [check] Error 2
|
|
From: Tom H. <th...@cy...> - 2007-11-03 03:05:04
|
Nightly build on gill ( x86_64, Fedora Core 2 ) started at 2007-11-03 03:00:03 GMT Results unchanged from 24 hours ago Checking out valgrind source tree ... done Configuring valgrind ... done Building valgrind ... done Running regression tests ... failed Last 20 lines of verbose log follow echo then mv -f ".deps/long-time.Tpo" ".deps/long-time.Po"; else rm -f ".deps/long-time.Tpo"; exit 1; fi long-time.c: In function `main': long-time.c:15: warning: ISO C90 forbids mixed declarations and code long-time.c:18: warning: ISO C90 forbids mixed declarations and code gcc -Winline -Wall -Wshadow -g -m64 -Wno-long-long -Wdeclaration-after-statement -o long-time long-time.o if g++ -DHAVE_CONFIG_H -I. -I. -I../.. -I../.. -I../../include -I../../coregrind -I../../include -I../../VEX/pub -g -O2 -MT new-cpp.o -MD -MP -MF ".deps/new-cpp.Tpo" -c -o new-cpp.o new-cpp.cpp; \ then mv -f ".deps/new-cpp.Tpo" ".deps/new-cpp.Po"; else rm -f ".deps/new-cpp.Tpo"; exit 1; fi new-cpp.cpp: In function `int main()': new-cpp.cpp:20: error: invalid use of undefined type `struct main()::s' new-cpp.cpp:20: error: forward declaration of `struct main()::s' new-cpp.cpp:20: error: ISO C++ forbids defining types within new make[4]: *** [new-cpp.o] Error 1 make[4]: Leaving directory `/tmp/vgtest/2007-11-03/valgrind/massif/tests' make[3]: *** [check-am] Error 2 make[3]: Leaving directory `/tmp/vgtest/2007-11-03/valgrind/massif/tests' make[2]: *** [check-recursive] Error 1 make[2]: Leaving directory `/tmp/vgtest/2007-11-03/valgrind/massif' make[1]: *** [check-recursive] Error 1 make[1]: Leaving directory `/tmp/vgtest/2007-11-03/valgrind' make: *** [check] Error 2 |
|
From: <js...@ac...> - 2007-11-03 01:17:50
|
Nightly build on g5 ( SuSE 10.1, ppc970 ) started at 2007-11-03 02:00:01 CET Results differ from 24 hours ago Checking out valgrind source tree ... done Configuring valgrind ... done Building valgrind ... done Running regression tests ... failed Regression test results follow == 255 tests, 11 stderr failures, 2 stdout failures, 0 post failures == memcheck/tests/deep_templates (stdout) memcheck/tests/leak-cycle (stderr) memcheck/tests/leak-tree (stderr) memcheck/tests/pointer-trace (stderr) massif/tests/culling1 (stderr) massif/tests/culling2 (stderr) massif/tests/deep-C (stderr) massif/tests/peak2 (stderr) massif/tests/realloc (stderr) none/tests/faultstatus (stderr) none/tests/fdleak_cmsg (stderr) none/tests/mremap (stderr) none/tests/mremap2 (stdout) ================================================= == Results from 24 hours ago == ================================================= Checking out valgrind source tree ... done Configuring valgrind ... done Building valgrind ... done Running regression tests ... failed Regression test results follow == 255 tests, 11 stderr failures, 2 stdout failures, 6 post failures == memcheck/tests/deep_templates (stdout) memcheck/tests/leak-cycle (stderr) memcheck/tests/leak-tree (stderr) memcheck/tests/pointer-trace (stderr) massif/tests/basic (post) massif/tests/culling1 (stderr) massif/tests/culling2 (stderr) massif/tests/custom_alloc (post) massif/tests/deep-C (stderr) massif/tests/deep-D (post) massif/tests/ignoring (post) massif/tests/peak (post) massif/tests/peak2 (stderr) massif/tests/peak2 (post) massif/tests/realloc (stderr) none/tests/faultstatus (stderr) none/tests/fdleak_cmsg (stderr) none/tests/mremap (stderr) none/tests/mremap2 (stdout) ================================================= == Difference between 24 hours ago and now == ================================================= *** old.short Sat Nov 3 02:08:30 2007 --- new.short Sat Nov 3 02:17:48 2007 *************** *** 8,10 **** ! == 255 tests, 11 stderr failures, 2 stdout failures, 6 post failures == memcheck/tests/deep_templates (stdout) --- 8,10 ---- ! == 255 tests, 11 stderr failures, 2 stdout failures, 0 post failures == memcheck/tests/deep_templates (stdout) *************** *** 13,24 **** memcheck/tests/pointer-trace (stderr) - massif/tests/basic (post) massif/tests/culling1 (stderr) massif/tests/culling2 (stderr) - massif/tests/custom_alloc (post) massif/tests/deep-C (stderr) - massif/tests/deep-D (post) - massif/tests/ignoring (post) - massif/tests/peak (post) massif/tests/peak2 (stderr) - massif/tests/peak2 (post) massif/tests/realloc (stderr) --- 13,18 ---- |
|
From: Josef W. <Jos...@gm...> - 2007-11-02 23:29:10
|
On Friday 02 November 2007, sv...@va... wrote: > Author: njn > +// - Massif out file: > +// default --> cachegrind.out.<pid> > +// --cg-out-file=X --> X.<pid> > +// --cg-out-file-exactly=X --> X > +// --cg-out-file-qualifier=QUAL --> [error] > +// --cg-out-file=X --cg-out-file-qualifier=QUAL --> X.$QUAL > +// - Likewise for Cachegrind, but with --cg-out/cg.out. > +// - And in cg_annotate, remove the --<pid> option. > +// - Likewise for Callgrind, but with --cl-out/cl.out (?) > +// - And don't create .1, .2 etc suffixed files. Hi Nick, cool, that you want to solve this mess in a consistent way. I am all for it. I am just not sure if the above is flexible enough. Eg. in callgrind, I can have output triggered from different threads, as well as multiple outputs. I think that allowing for a format pattern would be a good way. In this format pattern, we could allow for sequences to be substituted: %p <pid> of running process %t <thread> producing this output %T tool name %c counter to be incremented on each output I do not understand the benefit of QUAL above. Do I understand correctly, and you specify the name of an environment variable here that is substituted in the file name? Why can you not just say --cg-out-file=X.$QUAL (ie. the substitution is done by the shell at exec time)? With %T, we could generalize the options among the tools, e.g. by just using "--out-file=<pattern>". However. This does not really work for callgrind :-( To get the current behavior of callgrind, there is the need for four (!) such patterns for different contexts: 1) termination without separate counters per thread: %T.out.%p 2) termination with separate counters per thread: %T.out.%p-%t 3) dumping in the middle without seperate c.p.t. : %T.out.%p.%c 4) " with " : %T.out.%p.%c-%t I am open for any suggestions to unify this mess into just one pattern. The bad thing is that KCachegrind depends on this to some extend: When running KCachegrind on the generated output from termination, it searches for any further outputs with suffixes. However, I want to get rid of this because it is quite a confusing behavior. Josef |
|
From: <sv...@va...> - 2007-11-02 21:44:02
|
Author: njn Date: 2007-11-02 21:44:02 +0000 (Fri, 02 Nov 2007) New Revision: 7084 Log: Update todo notes Modified: trunk/massif/ms_main.c Modified: trunk/massif/ms_main.c =================================================================== --- trunk/massif/ms_main.c 2007-11-02 20:47:53 UTC (rev 7083) +++ trunk/massif/ms_main.c 2007-11-02 21:44:02 UTC (rev 7084) @@ -36,7 +36,25 @@ // documentation // - write documentation // - make --threshold and --peak-inaccuracy fractional -// - do filename properly, clean up Valgrind-wide log file naming mess +// - do filename properly, clean up Valgrind-wide log file naming mess. +// Expected behaviour: +// - Main log file: +// default --> stderr +// --log-file=X --> X.<pid> +// --log-file-exactly=X --> X +// --log-file-qualifier=QUAL --> [error] +// --log-file=X --log-file-qualifier=QUAL --> X.$QUAL +// - Massif out file: +// default --> cachegrind.out.<pid> +// --cg-out-file=X --> X.<pid> +// --cg-out-file-exactly=X --> X +// --cg-out-file-qualifier=QUAL --> [error] +// --cg-out-file=X --cg-out-file-qualifier=QUAL --> X.$QUAL +// - Likewise for Cachegrind, but with --cg-out/cg.out. +// - And in cg_annotate, remove the --<pid> option. +// - Likewise for Callgrind, but with --cl-out/cl.out (?) +// - And don't create .1, .2 etc suffixed files. +// // - currently recording asked-for sizes of heap blocks, not actual sizes. // Should add the difference to heap-admin, and change heap-admin name to // something else (heap-extra?). |
|
From: Julian S. <js...@ac...> - 2007-11-02 21:27:57
|
On Friday 02 November 2007 18:44, Oswald Buddenhagen wrote: > On Fri, Nov 02, 2007 at 08:56:08AM -0700, Dave Nomura wrote: > > Is it possible to run an x86 valgrind on a PPC program? If so, how > > would you do it? > > so you want a cross-executing valgrind ... > while i think vex would have no major problems with it (give or take > some minor adjustments), i'm pretty sure nobody has written a syscall > translation layer, That's true. One of the vex design goals was to support cross-translation although that's never been used so far. But anyway, why would you want to do such a bizarre thing? Why not just valgrindify your ppc app on a ppc box? J |
|
From: Oswald B. <os...@kd...> - 2007-11-02 21:07:28
|
On Sat, Nov 03, 2007 at 07:59:38AM +1100, Nicholas Nethercote wrote: > On Fri, 2 Nov 2007, Oswald Buddenhagen wrote: >> for *way* more clarity >> and less bloat i'd suggest writing the actual expression as >> update_alloc_stats(heap_szB_delta + (SizeT)clo_heap_admin*n_heap_blocks_delta); >> instead of making the variable bigger. > > I thought about following your suggestion, but your solution only > fixes that particular expression, whereas making it a SizeT avoids the > possibility of it happening elsewhere. > hmm, but by this logic you have to promote every single variable that is ever used in an offset or size calculation to [S]SizeT, no matter how oversized it seems ... i guess one simply has to keep such issues in mind when doing C. probably *the* reason why Java simply dropped unsigned types. -- Hi! I'm a .signature virus! Copy me into your ~/.signature, please! -- Chaos, panic, and disorder - my work here is done. |
|
From: Nicholas N. <nj...@cs...> - 2007-11-02 21:02:08
|
On Fri, 2 Nov 2007, Dave Nomura wrote: > Is it possible to run an x86 valgrind on a PPC program? If so, how > would you do it? Maybe if you run Valgrind on QEMU (or another dynamic binary translator) running the PPC program? Otherwise I can't see how it would work. Nick |
|
From: Nicholas N. <nj...@cs...> - 2007-11-02 21:00:32
|
On Fri, 2 Nov 2007, Oswald Buddenhagen wrote: > this is really odd ... That's what I thought :) > the code in update_heap_stats() did this: > (unsigned long) = (unsigned long) + (unsigned int) * (signed int); > while the actual multiplication is signed, the result is taken to be > unsigned and is accordingly zero-extended in the promotion. > you converted this to > (unsigned long) = (unsigned long) + (unsigned long) * (signed int); > which is about the right thing to do. however, for *way* more clarity > and less bloat i'd suggest writing the actual expression as > update_alloc_stats(heap_szB_delta + (SizeT)clo_heap_admin*n_heap_blocks_delta); > instead of making the variable bigger. I thought about following your suggestion, but your solution only fixes that particular expression, whereas making it a SizeT avoids the possibility of it happening elsewhere. Thanks for the explanation, that's basically what I thought was happening but you explained it more clearly than I had understood it in my head. Nick |
|
From: <sv...@va...> - 2007-11-02 20:47:52
|
Author: njn Date: 2007-11-02 20:47:53 +0000 (Fri, 02 Nov 2007) New Revision: 7083 Log: Fix a Makefile issue that I think caused automated testing to fail on 'alvis' last night. I don't no why it worked on the other machines, must be an automake version thing. Modified: trunk/massif/perf/Makefile.am Modified: trunk/massif/perf/Makefile.am =================================================================== --- trunk/massif/perf/Makefile.am 2007-11-02 20:44:57 UTC (rev 7082) +++ trunk/massif/perf/Makefile.am 2007-11-02 20:47:53 UTC (rev 7083) @@ -2,7 +2,7 @@ # For AM_FLAG_M3264_PRI include $(top_srcdir)/Makefile.flags.am -EXTRA_DIST = $(noinst_SCRIPTS) \ +EXTRA_DIST = \ many-xpts.vgperf check_PROGRAMS = \ |
|
From: <sv...@va...> - 2007-11-02 20:44:57
|
Author: njn
Date: 2007-11-02 20:44:57 +0000 (Fri, 02 Nov 2007)
New Revision: 7082
Log:
Change ms_print to ms_print.in, link it into the build/install system.
Added:
trunk/massif/ms_print.in
Removed:
trunk/massif/ms_print
Modified:
trunk/configure.in
trunk/massif/Makefile.am
Modified: trunk/configure.in
===================================================================
--- trunk/configure.in 2007-11-02 04:17:28 UTC (rev 7081)
+++ trunk/configure.in 2007-11-02 20:44:57 UTC (rev 7082)
@@ -983,6 +983,7 @@
massif/tests/Makefile
massif/perf/Makefile
massif/docs/Makefile
+ massif/ms_print
lackey/Makefile
lackey/tests/Makefile
lackey/docs/Makefile
Modified: trunk/massif/Makefile.am
===================================================================
--- trunk/massif/Makefile.am 2007-11-02 04:17:28 UTC (rev 7081)
+++ trunk/massif/Makefile.am 2007-11-02 20:44:57 UTC (rev 7082)
@@ -2,6 +2,8 @@
SUBDIRS += perf
+bin_SCRIPTS = ms_print
+
noinst_PROGRAMS =
if VGP_X86_LINUX
noinst_PROGRAMS += massif-x86-linux vgpreload_massif-x86-linux.so
Deleted: trunk/massif/ms_print
===================================================================
--- trunk/massif/ms_print 2007-11-02 04:17:28 UTC (rev 7081)
+++ trunk/massif/ms_print 2007-11-02 20:44:57 UTC (rev 7082)
@@ -1,649 +0,0 @@
-#! /usr/bin/perl
-
-##--------------------------------------------------------------------##
-##--- Massif's results printer ms_print.in ---##
-##--------------------------------------------------------------------##
-
-# This file is part of Massif, a Valgrind tool for profiling memory
-# usage of programs.
-#
-# Copyright (C) 2007-2007 Nicholas Nethercote
-# nj...@va...
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License as
-# published by the Free Software Foundation; either version 2 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-# 02111-1307, USA.
-#
-# The GNU General Public License is contained in the file COPYING.
-
-use warnings;
-use strict;
-
-#----------------------------------------------------------------------------
-# Global variables, main data structures
-#----------------------------------------------------------------------------
-
-# Command line of profiled program.
-my $cmd;
-
-# Time unit used in profile.
-my $time_unit;
-
-# Threshold dictating what percentage an entry must represent for us to
-# bother showing it.
-my $threshold = 1.0;
-
-# Graph x and y dimensions.
-my $graph_x = 72;
-my $graph_y = 20;
-
-# Input file name
-my $input_file = undef;
-
-# Tmp file name.
-my $tmp_file = "ms_print.tmp.$$";
-
-# Version number (XXX: change it when I convert this file to ms_print.in)
-my $version = "XXX"; # "@VERSION@";
-
-# Args passed, for printing.
-my $ms_print_args;
-
-# Usage message.
-my $usage = <<END
-usage: ms_print [options] <file>
-
- options for the user, with defaults in [ ], are:
- -h --help show this message
- -v --version show version
- --threshold=<n.n> significance threshold, in percent [$threshold]
- --x=<n> graph width, in columns; min=4, max=1000 [72]
- --y=<n> graph height, in rows; min=4, max=1000 [20]
-
- ms_print is Copyright (C) 2007-2007 Nicholas Nethercote.
- and licensed under the GNU General Public License, version 2.
- Bug reports, feedback, admiration, abuse, etc, to: njn\@valgrind.org.
-
-END
-;
-
-# Used in various places of output.
-my $fancy = '-' x 80;
-my $fancy_nl = $fancy . "\n";
-
-# Returns 0 if the denominator is 0.
-sub safe_div_0($$)
-{
- my ($x, $y) = @_;
- return ($y ? $x / $y : 0);
-}
-
-#-----------------------------------------------------------------------------
-# Argument and option handling
-#-----------------------------------------------------------------------------
-sub process_cmd_line()
-{
- my @files;
-
- # Grab a copy of the arguments, for printing later.
- for my $arg (@ARGV) {
- $ms_print_args .= " $arg"; # The arguments.
- }
-
- for my $arg (@ARGV) {
-
- # Option handling
- if ($arg =~ /^-/) {
-
- # --version
- if ($arg =~ /^-v$|^--version$/) {
- die("ms_print-$version\n");
-
- # --threshold=X (tolerates a trailing '%')
- } elsif ($arg =~ /^--threshold=([\d\.]+)%?$/) {
- $threshold = $1;
- ($1 >= 0 && $1 <= 100) or die($usage);
-
- } elsif ($arg =~ /^--x=(\d+)$/) {
- $graph_x = $1;
- (4 <= $graph_x && $graph_x <= 1000) or die($usage);
-
- } elsif ($arg =~ /^--y=(\d+)$/) {
- $graph_y = $1;
- (4 <= $graph_y && $graph_y <= 1000) or die($usage);
-
- } else { # -h and --help fall under this case
- die($usage);
- }
- } else {
- # Not an option. Remember it as a filename.
- push(@files, $arg);
- }
- }
-
- # Must have chosen exactly one input file.
- if (scalar @files) {
- $input_file = $files[0];
- } else {
- die($usage);
- }
-}
-
-#-----------------------------------------------------------------------------
-# Reading the input file: auxiliary functions
-#-----------------------------------------------------------------------------
-
-# Gets the next line, stripping comments and skipping blanks.
-# Returns undef at EOF.
-sub get_line()
-{
- while (my $line = <INPUTFILE>) {
- $line =~ s/#.*$//; # remove comments
- if ($line !~ /^\s*$/) {
- return $line; # return $line if non-empty
- }
- }
- return undef; # EOF: return undef
-}
-
-sub equals_num_line($$)
-{
- my ($line, $fieldname) = @_;
- defined($line)
- or die("Line $.: expected \"$fieldname\" line, got end of file\n");
- $line =~ s/^$fieldname=(.*)\s*$//
- or die("Line $.: expected \"$fieldname\" line, got:\n$line");
- return $1;
-}
-
-sub is_significant_XPt($$$)
-{
- my ($is_top_node, $xpt_szB, $total_szB) = @_;
- ($xpt_szB <= $total_szB) or die;
- # Nb: we always consider the alloc-XPt significant, even if the size is
- # zero.
- return $is_top_node || 0 == $threshold ||
- ( $total_szB != 0 && $xpt_szB * 100 / $total_szB >= $threshold );
-}
-
-#-----------------------------------------------------------------------------
-# Reading the input file: reading heap trees
-#-----------------------------------------------------------------------------
-
-# Forward declaration, because it's recursive.
-sub read_heap_tree($$$$$);
-
-# Return pair: if the tree was significant, both are zero. If it was
-# insignificant, the first element is 1 and the second is the number of
-# bytes.
-sub read_heap_tree($$$$$)
-{
- # Read the line and determine if it is significant.
- my ($is_top_node, $this_prefix, $child_midfix, $arrow, $mem_total_B) = @_;
- my $line = get_line();
- (defined $line and $line =~ /^\s*n(\d+):\s*(\d+)(.*)$/)
- or die("Line $.: expected a tree node line, got:\n$line\n");
- my $n_children = $1;
- my $bytes = $2;
- my $details = $3;
- my $perc = safe_div_0(100 * $bytes, $mem_total_B);
- # Nb: we always print the alloc-XPt, even if its size is zero.
- my $is_significant = is_significant_XPt($is_top_node, $bytes, $mem_total_B);
-
- # We precede this node's line with "$this_prefix.$arrow". We precede
- # any children of this node with "$this_prefix$child_midfix$arrow".
- if ($is_significant) {
- # Nb: $details might have '%' in it, so don't embed directly in the
- # format string.
- printf(TMPFILE
- "$this_prefix$arrow%05.2f%% (%sB)%s\n", $perc, commify($bytes),
- $details);
- }
-
- # Now read all the children.
- my $n_insig_children = 0;
- my $total_insig_children_szB = 0;
- my $this_prefix2 = $this_prefix . $child_midfix;
- for (my $i = 0; $i < $n_children; $i++) {
- # If child is the last sibling, the midfix is empty.
- my $child_midfix2 = ( $i+1 == $n_children ? " " : "| " );
- my ($is_child_insignificant, $child_insig_bytes) =
- # '0' means it's not the top node of the tree.
- read_heap_tree(0, $this_prefix2, $child_midfix2, "->",
- $mem_total_B);
- $n_insig_children += $is_child_insignificant;
- $total_insig_children_szB += $child_insig_bytes;
- }
-
- if ($is_significant) {
- # If this was significant but any children were insignificant, print
- # the "in N places" line for them.
- if ($n_insig_children > 0) {
- $perc = safe_div_0(100 * $total_insig_children_szB, $mem_total_B);
- printf(TMPFILE "%s->%05.2f%% (%sB) in %d+ places, all below "
- . "ms_print's threshold (%05.2f%%)\n",
- $this_prefix2, $perc, commify($total_insig_children_szB),
- $n_insig_children, $threshold);
- print(TMPFILE "$this_prefix2\n");
- }
-
- # If this node has no children, print an extra (mostly) empty line.
- if (0 == $n_children) {
- print(TMPFILE "$this_prefix2\n");
- }
- return (0, 0);
-
- } else {
- return (1, $bytes);
- }
-}
-
-#-----------------------------------------------------------------------------
-# Reading the input file: main
-#-----------------------------------------------------------------------------
-
-sub max_label_2($$)
-{
- my ($szB, $szB_scaled) = @_;
-
- # For the label, if $szB is 999B or below, we print it as an integer.
- # Otherwise, we print it as a float with 5 characters (including the '.').
- # Examples (for bytes):
- # 1 --> 1 B
- # 999 --> 999 B
- # 1000 --> 0.977 KB
- # 1024 --> 1.000 KB
- # 10240 --> 10.00 KB
- # 102400 --> 100.0 KB
- # 1024000 --> 0.977 MB
- # 1048576 --> 1.000 MB
- #
- if ($szB < 1000) { return sprintf("%5d", $szB); }
- elsif ($szB_scaled < 10) { return sprintf("%5.3f", $szB_scaled); }
- elsif ($szB_scaled < 100) { return sprintf("%5.2f", $szB_scaled); }
- else { return sprintf("%5.1f", $szB_scaled); }
-}
-
-# Work out the units for the max value, measured in bytes.
-sub B_max_label($)
-{
- my ($szB) = @_;
-
- # We repeat until the number is less than 1000, but we divide by 1024 on
- # each scaling.
- my $szB_scaled = $szB;
- my $unit = "B";
- if ($szB_scaled >= 1000) { $unit = "KB"; $szB_scaled /= 1024; }
- if ($szB_scaled >= 1000) { $unit = "MB"; $szB_scaled /= 1024; }
- if ($szB_scaled >= 1000) { $unit = "GB"; $szB_scaled /= 1024; }
- if ($szB_scaled >= 1000) { $unit = "TB"; $szB_scaled /= 1024; }
- if ($szB_scaled >= 1000) { $unit = "PB"; $szB_scaled /= 1024; }
- if ($szB_scaled >= 1000) { $unit = "EB"; $szB_scaled /= 1024; }
- if ($szB_scaled >= 1000) { $unit = "ZB"; $szB_scaled /= 1024; }
- if ($szB_scaled >= 1000) { $unit = "YB"; $szB_scaled /= 1024; }
-
- return (max_label_2($szB, $szB_scaled), $unit);
-}
-
-# Work out the units for the max value, measured in ms/s/h.
-sub t_max_label($)
-{
- my ($szB) = @_;
-
- # We scale from millisecond to seconds to hours.
- #
- # XXX: this allows a number with 6 chars, eg. "3599.0 s"
- my $szB_scaled = $szB;
- my $unit = "ms";
- if ($szB_scaled >= 1000) { $unit = "s"; $szB_scaled /= 1000; }
- if ($szB_scaled >= 3600) { $unit = "h"; $szB_scaled /= 3600; }
-
- return (max_label_2($szB, $szB_scaled), $unit);
-}
-
-# This prints four things:
-# - the output header
-# - the graph
-# - the snapshot summaries (number, list of detailed ones)
-# - the snapshots
-#
-# The first three parts can't be printed until we've read the whole input file;
-# but the fourth part is much easier to print while we're reading the file. So
-# we print the fourth part to a tmp file, and then dump the tmp file at the
-# end.
-#
-sub read_input_file()
-{
- my $desc = ""; # Concatenated description lines.
- my $peak_mem_total_szB = 0;
-
- # Info about each snapshot.
- my @snapshot_nums = ();
- my @times = ();
- my @mem_total_Bs = ();
- my @is_detaileds = ();
- my $peak_num = -1; # An initial value that will be ok if no peak
- # entry is in the file.
-
- #-------------------------------------------------------------------------
- # Read start of input file.
- #-------------------------------------------------------------------------
- open(INPUTFILE, "< $input_file")
- || die "Cannot open $input_file for reading\n";
-
- # Read "desc:" lines.
- my $line;
- while ($line = get_line()) {
- if ($line =~ s/^desc://) {
- $desc .= $line;
- } else {
- last;
- }
- }
-
- # Read "cmd:" line (Nb: will already be in $line from "desc:" loop above).
- ($line =~ /^cmd:\s*(.*)$/) or die("Line $.: missing 'cmd' line\n");
- $cmd = $1;
-
- # Read "time_unit:" line.
- $line = get_line();
- ($line =~ /^time_unit:\s*(.*)$/) or
- die("Line $.: missing 'time_unit' line\n");
- $time_unit = $1;
-
- #-------------------------------------------------------------------------
- # Print snapshot list header to $tmp_file.
- #-------------------------------------------------------------------------
- open(TMPFILE, "> $tmp_file")
- || die "Cannot open $tmp_file for reading\n";
-
- my $time_column = sprintf("%14s", "time($time_unit)");
- my $column_format = "%3s %14s %16s %16s %13s %12s\n";
- my $header =
- $fancy_nl .
- sprintf($column_format
- , "n"
- , $time_column
- , "total(B)"
- , "useful-heap(B)"
- , "admin-heap(B)"
- , "stacks(B)"
- ) .
- $fancy_nl;
- print(TMPFILE $header);
-
- #-------------------------------------------------------------------------
- # Read body of input file.
- #-------------------------------------------------------------------------
- $line = get_line();
- while (defined $line) {
- my $snapshot_num = equals_num_line($line, "snapshot");
- my $time = equals_num_line(get_line(), "time");
- my $mem_heap_B = equals_num_line(get_line(), "mem_heap_B");
- my $mem_heap_admin_B = equals_num_line(get_line(), "mem_heap_admin_B");
- my $mem_stacks_B = equals_num_line(get_line(), "mem_stacks_B");
- my $mem_total_B = $mem_heap_B + $mem_heap_admin_B + $mem_stacks_B;
- my $heap_tree = equals_num_line(get_line(), "heap_tree");
-
- # Print the snapshot data to $tmp_file.
- printf(TMPFILE $column_format,
- , $snapshot_num
- , commify($time)
- , commify($mem_total_B)
- , commify($mem_heap_B)
- , commify($mem_heap_admin_B)
- , commify($mem_stacks_B)
- );
-
- # Remember the snapshot data.
- push(@snapshot_nums, $snapshot_num);
- push(@times, $time);
- push(@mem_total_Bs, $mem_total_B);
- push(@is_detaileds, ( $heap_tree eq "empty" ? 0 : 1 ));
- $peak_mem_total_szB = $mem_total_B
- if $mem_total_B > $peak_mem_total_szB;
-
- # Read the heap tree, and if it's detailed, print it and a subsequent
- # snapshot list header to $tmp_file.
- if ($heap_tree eq "empty") {
- $line = get_line();
- } elsif ($heap_tree =~ "(detailed|peak)") {
- # If "peak", remember the number.
- if ($heap_tree eq "peak") {
- $peak_num = $snapshot_num;
- }
- # '1' means it's the top node of the tree.
- read_heap_tree(1, "", "", "", $mem_total_B);
-
- # Print the header, unless there are no more snapshots.
- $line = get_line();
- if (defined $line) {
- print(TMPFILE $header);
- }
- } else {
- die("Line $.: expected 'empty' or '...' after 'heap_tree='\n");
- }
- }
-
- close(INPUTFILE);
- close(TMPFILE);
-
- #-------------------------------------------------------------------------
- # Print header.
- #-------------------------------------------------------------------------
- print($fancy_nl);
- print("Command: $cmd\n");
- print("Massif arguments: $desc");
- print("ms_print arguments:$ms_print_args\n");
- print($fancy_nl);
- print("\n\n");
-
- #-------------------------------------------------------------------------
- # Setup for graph.
- #-------------------------------------------------------------------------
- # The ASCII graph.
- # Row 0 ([0..graph_x][0]) is the X-axis.
- # Column 0 ([0][0..graph_y]) is the Y-axis.
- # The rest ([1][1]..[graph_x][graph_y]) is the usable graph area.
- my @graph;
- my $x;
- my $y;
-
- my $n_snapshots = scalar(@snapshot_nums);
- ($n_snapshots > 0) or die;
- my $end_time = $times[$n_snapshots-1];
- ($end_time >= 0) or die;
-
- # Setup graph[][].
- $graph[0][0] = '+'; # axes join point
- for ($x = 1; $x <= $graph_x; $x++) { $graph[$x][0] = '-'; } # X-axis
- for ($y = 1; $y <= $graph_y; $y++) { $graph[0][$y] = '|'; } # Y-axis
- $graph[$graph_x][0] = '>'; # X-axis arrow
- $graph[0][$graph_y] = '^'; # Y-axis arrow
- for ($x = 1; $x <= $graph_x; $x++) { # usable area
- for ($y = 1; $y <= $graph_y; $y++) {
- $graph[$x][$y] = ' ';
- }
- }
-
- #-------------------------------------------------------------------------
- # Write snapshot bars into graph[][].
- #-------------------------------------------------------------------------
- # Each row represents K bytes, which is 1/graph_y of the peak size
- # (and K can be non-integral). When drawing the column for a snapshot,
- # in order to fill the slot in row y (where the first row drawn on is
- # row 1) with a half-char (eg. '.'), it must be >= (y - 1/2)*K. In
- # order to fill a row/column spot with a full-char (eg. ':'), it must be
- # >= y*K. For example, if K = 10 bytes, then the values 0, 4, 5, 9, 10,
- # 14, 15, 19, 20, 24, 25, 29, 30 would be drawn like this (showing one
- # per column):
- #
- # y (y - 1/2) * K y * K
- # - ------------- -----------
- # 30 | ..: 3 (3 - 1/2) * 10 = 25 3 * 10 = 30
- # 20 | ..::::: 2 (2 - 1/2) * 10 = 15 2 * 10 = 20
- # 10 | ..::::::::: 1 (1 - 1/2) * 10 = 5 1 * 10 = 10
- # 0 +-------------
-
- my $peak_full_char = '#';
- my $detailed_full_char = '@';
- my $normal_full_char = ':';
- my $half_char = '.';
-
- # Work out how many bytes each row represents. If the peak size was 0,
- # make it 1 so that the Y-axis covers a non-zero range of values.
- # Likewise for end_time.
- if (0 == $peak_mem_total_szB) { $peak_mem_total_szB = 1; }
- if (0 == $end_time ) { $end_time = 1; }
- my $K = $peak_mem_total_szB / $graph_y;
-
- # If we leave end_time as is, the final snapshot will spill over past
- # the last column. So we add a small epsilon to it to prevent this from
- # happening.
- $end_time += 0.001;
-
- for (my $i = 0; $i < $n_snapshots; $i++) {
-
- # Work out which column this snapshot belongs to.
- my $x_pos_frac = ($times[$i] / ($end_time)) * $graph_x;
- $x = int($x_pos_frac) + 1; # +1 due to Y-axis
- # The final snapshot will spill over into the n+1th column, which
- # doesn't get shown. So we fudge that one and pull it back a
- # column, as if the end_time was actually end_time+epsilon.
- if ($times[$i] == $end_time) {
- ($x == $graph_x+1) or die;
- $x = $graph_x;
- }
-
- # Draw the column if:
- # - it's the peak column, or
- # - it's a detailed column, and we won't overwrite the peak column, or
- # - it's a normal column, and we won't overwrite the peak column or a
- # detailed column.
- my $should_draw_column =
- (($i == $peak_num) or
- ($is_detaileds[$i] and $graph[$x][0] ne $peak_full_char) or
- ($graph[$x][0] ne $peak_full_char and
- $graph[$x][0] ne $detailed_full_char));
-
- if ($should_draw_column) {
- # If it's detailed, mark the X-axis. Also choose the full-slot
- # char.
- my $full_char;
- if ($i == $peak_num) {
- $full_char = $peak_full_char;
- $graph[$x][0] = $full_char;
- } elsif ($is_detaileds[$i]) {
- $full_char = $detailed_full_char;
- $graph[$x][0] = $full_char;
- } else {
- $full_char = $normal_full_char;
- }
- # Grow this snapshot bar from bottom to top.
- for ($y = 1; $y <= $graph_y; $y++) {
- if ($mem_total_Bs[$i] >= ($y - 1/2) * $K) {
- $graph[$x][$y] = $half_char;
- }
- if ($mem_total_Bs[$i] >= $y * $K) {
- $graph[$x][$y] = $full_char;
- }
- }
- }
- }
-
- #-------------------------------------------------------------------------
- # Print graph[][].
- #-------------------------------------------------------------------------
- my ($y_label, $y_unit) = B_max_label($peak_mem_total_szB);
- my ($x_label, $x_unit) = ( $time_unit eq "ms"
- ? t_max_label($end_time)
- : B_max_label($end_time) );
-
- printf(" %2s\n", $y_unit);
- for ($y = $graph_y; $y >= 0; $y--) {
- if ($graph_y == $y) { # top row
- print($y_label);
- } elsif (0 == $y) { # bottom row
- print(" 0 ");
- } else { # anywhere else
- print(" ");
- }
-
- # Axis and data for the row.
- for ($x = 0; $x <= $graph_x; $x++) {
- printf("%s", $graph[$x][$y]);
- }
- if (0 == $y) {
- print("$x_unit\n");
- } else {
- print("\n");
- }
- }
- printf(" 0%s%5s\n", ' ' x ($graph_x-5), $x_label);
-
- #-------------------------------------------------------------------------
- # Print snapshot numbers.
- #-------------------------------------------------------------------------
- print("\n");
- print("Number of snapshots: $n_snapshots\n");
- print(" Detailed snapshots: [");
- my $first_detailed = 1;
- for (my $i = 0; $i < $n_snapshots; $i++) {
- if ($is_detaileds[$i]) {
- if ($first_detailed) {
- printf("$i");
- $first_detailed = 0;
- } else {
- printf(", $i");
- }
- if ($i == $peak_num) {
- print(" (peak)");
- }
- }
- }
- print("]\n");
-
- #-------------------------------------------------------------------------
- # Print snapshots, from $tmp_file.
- #-------------------------------------------------------------------------
- open(TMPFILE, "< $tmp_file")
- || die "Cannot open $tmp_file for reading\n";
-
- while (my $line = <TMPFILE>) {
- print($line);
- }
- unlink($tmp_file);
-}
-
-#-----------------------------------------------------------------------------
-# Misc functions
-#-----------------------------------------------------------------------------
-sub commify ($) {
- my ($val) = @_;
- 1 while ($val =~ s/^(\d+)(\d{3})/$1,$2/);
- return $val;
-}
-
-
-#----------------------------------------------------------------------------
-# "main()"
-#----------------------------------------------------------------------------
-process_cmd_line();
-read_input_file();
-
-##--------------------------------------------------------------------##
-##--- end ms_print.in ---##
-##--------------------------------------------------------------------##
-
-
Copied: trunk/massif/ms_print.in (from rev 7080, trunk/massif/ms_print)
===================================================================
--- trunk/massif/ms_print.in (rev 0)
+++ trunk/massif/ms_print.in 2007-11-02 20:44:57 UTC (rev 7082)
@@ -0,0 +1,649 @@
+#! @PERL@
+
+##--------------------------------------------------------------------##
+##--- Massif's results printer ms_print.in ---##
+##--------------------------------------------------------------------##
+
+# This file is part of Massif, a Valgrind tool for profiling memory
+# usage of programs.
+#
+# Copyright (C) 2007-2007 Nicholas Nethercote
+# nj...@va...
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+# 02111-1307, USA.
+#
+# The GNU General Public License is contained in the file COPYING.
+
+use warnings;
+use strict;
+
+#----------------------------------------------------------------------------
+# Global variables, main data structures
+#----------------------------------------------------------------------------
+
+# Command line of profiled program.
+my $cmd;
+
+# Time unit used in profile.
+my $time_unit;
+
+# Threshold dictating what percentage an entry must represent for us to
+# bother showing it.
+my $threshold = 1.0;
+
+# Graph x and y dimensions.
+my $graph_x = 72;
+my $graph_y = 20;
+
+# Input file name
+my $input_file = undef;
+
+# Tmp file name.
+my $tmp_file = "ms_print.tmp.$$";
+
+# Version number.
+my $version = "@VERSION@";
+
+# Args passed, for printing.
+my $ms_print_args;
+
+# Usage message.
+my $usage = <<END
+usage: ms_print [options] <file>
+
+ options for the user, with defaults in [ ], are:
+ -h --help show this message
+ -v --version show version
+ --threshold=<n.n> significance threshold, in percent [$threshold]
+ --x=<n> graph width, in columns; min=4, max=1000 [72]
+ --y=<n> graph height, in rows; min=4, max=1000 [20]
+
+ ms_print is Copyright (C) 2007-2007 Nicholas Nethercote.
+ and licensed under the GNU General Public License, version 2.
+ Bug reports, feedback, admiration, abuse, etc, to: njn\@valgrind.org.
+
+END
+;
+
+# Used in various places of output.
+my $fancy = '-' x 80;
+my $fancy_nl = $fancy . "\n";
+
+# Returns 0 if the denominator is 0.
+sub safe_div_0($$)
+{
+ my ($x, $y) = @_;
+ return ($y ? $x / $y : 0);
+}
+
+#-----------------------------------------------------------------------------
+# Argument and option handling
+#-----------------------------------------------------------------------------
+sub process_cmd_line()
+{
+ my @files;
+
+ # Grab a copy of the arguments, for printing later.
+ for my $arg (@ARGV) {
+ $ms_print_args .= " $arg"; # The arguments.
+ }
+
+ for my $arg (@ARGV) {
+
+ # Option handling
+ if ($arg =~ /^-/) {
+
+ # --version
+ if ($arg =~ /^-v$|^--version$/) {
+ die("ms_print-$version\n");
+
+ # --threshold=X (tolerates a trailing '%')
+ } elsif ($arg =~ /^--threshold=([\d\.]+)%?$/) {
+ $threshold = $1;
+ ($1 >= 0 && $1 <= 100) or die($usage);
+
+ } elsif ($arg =~ /^--x=(\d+)$/) {
+ $graph_x = $1;
+ (4 <= $graph_x && $graph_x <= 1000) or die($usage);
+
+ } elsif ($arg =~ /^--y=(\d+)$/) {
+ $graph_y = $1;
+ (4 <= $graph_y && $graph_y <= 1000) or die($usage);
+
+ } else { # -h and --help fall under this case
+ die($usage);
+ }
+ } else {
+ # Not an option. Remember it as a filename.
+ push(@files, $arg);
+ }
+ }
+
+ # Must have chosen exactly one input file.
+ if (scalar @files) {
+ $input_file = $files[0];
+ } else {
+ die($usage);
+ }
+}
+
+#-----------------------------------------------------------------------------
+# Reading the input file: auxiliary functions
+#-----------------------------------------------------------------------------
+
+# Gets the next line, stripping comments and skipping blanks.
+# Returns undef at EOF.
+sub get_line()
+{
+ while (my $line = <INPUTFILE>) {
+ $line =~ s/#.*$//; # remove comments
+ if ($line !~ /^\s*$/) {
+ return $line; # return $line if non-empty
+ }
+ }
+ return undef; # EOF: return undef
+}
+
+sub equals_num_line($$)
+{
+ my ($line, $fieldname) = @_;
+ defined($line)
+ or die("Line $.: expected \"$fieldname\" line, got end of file\n");
+ $line =~ s/^$fieldname=(.*)\s*$//
+ or die("Line $.: expected \"$fieldname\" line, got:\n$line");
+ return $1;
+}
+
+sub is_significant_XPt($$$)
+{
+ my ($is_top_node, $xpt_szB, $total_szB) = @_;
+ ($xpt_szB <= $total_szB) or die;
+ # Nb: we always consider the alloc-XPt significant, even if the size is
+ # zero.
+ return $is_top_node || 0 == $threshold ||
+ ( $total_szB != 0 && $xpt_szB * 100 / $total_szB >= $threshold );
+}
+
+#-----------------------------------------------------------------------------
+# Reading the input file: reading heap trees
+#-----------------------------------------------------------------------------
+
+# Forward declaration, because it's recursive.
+sub read_heap_tree($$$$$);
+
+# Return pair: if the tree was significant, both are zero. If it was
+# insignificant, the first element is 1 and the second is the number of
+# bytes.
+sub read_heap_tree($$$$$)
+{
+ # Read the line and determine if it is significant.
+ my ($is_top_node, $this_prefix, $child_midfix, $arrow, $mem_total_B) = @_;
+ my $line = get_line();
+ (defined $line and $line =~ /^\s*n(\d+):\s*(\d+)(.*)$/)
+ or die("Line $.: expected a tree node line, got:\n$line\n");
+ my $n_children = $1;
+ my $bytes = $2;
+ my $details = $3;
+ my $perc = safe_div_0(100 * $bytes, $mem_total_B);
+ # Nb: we always print the alloc-XPt, even if its size is zero.
+ my $is_significant = is_significant_XPt($is_top_node, $bytes, $mem_total_B);
+
+ # We precede this node's line with "$this_prefix.$arrow". We precede
+ # any children of this node with "$this_prefix$child_midfix$arrow".
+ if ($is_significant) {
+ # Nb: $details might have '%' in it, so don't embed directly in the
+ # format string.
+ printf(TMPFILE
+ "$this_prefix$arrow%05.2f%% (%sB)%s\n", $perc, commify($bytes),
+ $details);
+ }
+
+ # Now read all the children.
+ my $n_insig_children = 0;
+ my $total_insig_children_szB = 0;
+ my $this_prefix2 = $this_prefix . $child_midfix;
+ for (my $i = 0; $i < $n_children; $i++) {
+ # If child is the last sibling, the midfix is empty.
+ my $child_midfix2 = ( $i+1 == $n_children ? " " : "| " );
+ my ($is_child_insignificant, $child_insig_bytes) =
+ # '0' means it's not the top node of the tree.
+ read_heap_tree(0, $this_prefix2, $child_midfix2, "->",
+ $mem_total_B);
+ $n_insig_children += $is_child_insignificant;
+ $total_insig_children_szB += $child_insig_bytes;
+ }
+
+ if ($is_significant) {
+ # If this was significant but any children were insignificant, print
+ # the "in N places" line for them.
+ if ($n_insig_children > 0) {
+ $perc = safe_div_0(100 * $total_insig_children_szB, $mem_total_B);
+ printf(TMPFILE "%s->%05.2f%% (%sB) in %d+ places, all below "
+ . "ms_print's threshold (%05.2f%%)\n",
+ $this_prefix2, $perc, commify($total_insig_children_szB),
+ $n_insig_children, $threshold);
+ print(TMPFILE "$this_prefix2\n");
+ }
+
+ # If this node has no children, print an extra (mostly) empty line.
+ if (0 == $n_children) {
+ print(TMPFILE "$this_prefix2\n");
+ }
+ return (0, 0);
+
+ } else {
+ return (1, $bytes);
+ }
+}
+
+#-----------------------------------------------------------------------------
+# Reading the input file: main
+#-----------------------------------------------------------------------------
+
+sub max_label_2($$)
+{
+ my ($szB, $szB_scaled) = @_;
+
+ # For the label, if $szB is 999B or below, we print it as an integer.
+ # Otherwise, we print it as a float with 5 characters (including the '.').
+ # Examples (for bytes):
+ # 1 --> 1 B
+ # 999 --> 999 B
+ # 1000 --> 0.977 KB
+ # 1024 --> 1.000 KB
+ # 10240 --> 10.00 KB
+ # 102400 --> 100.0 KB
+ # 1024000 --> 0.977 MB
+ # 1048576 --> 1.000 MB
+ #
+ if ($szB < 1000) { return sprintf("%5d", $szB); }
+ elsif ($szB_scaled < 10) { return sprintf("%5.3f", $szB_scaled); }
+ elsif ($szB_scaled < 100) { return sprintf("%5.2f", $szB_scaled); }
+ else { return sprintf("%5.1f", $szB_scaled); }
+}
+
+# Work out the units for the max value, measured in bytes.
+sub B_max_label($)
+{
+ my ($szB) = @_;
+
+ # We repeat until the number is less than 1000, but we divide by 1024 on
+ # each scaling.
+ my $szB_scaled = $szB;
+ my $unit = "B";
+ if ($szB_scaled >= 1000) { $unit = "KB"; $szB_scaled /= 1024; }
+ if ($szB_scaled >= 1000) { $unit = "MB"; $szB_scaled /= 1024; }
+ if ($szB_scaled >= 1000) { $unit = "GB"; $szB_scaled /= 1024; }
+ if ($szB_scaled >= 1000) { $unit = "TB"; $szB_scaled /= 1024; }
+ if ($szB_scaled >= 1000) { $unit = "PB"; $szB_scaled /= 1024; }
+ if ($szB_scaled >= 1000) { $unit = "EB"; $szB_scaled /= 1024; }
+ if ($szB_scaled >= 1000) { $unit = "ZB"; $szB_scaled /= 1024; }
+ if ($szB_scaled >= 1000) { $unit = "YB"; $szB_scaled /= 1024; }
+
+ return (max_label_2($szB, $szB_scaled), $unit);
+}
+
+# Work out the units for the max value, measured in ms/s/h.
+sub t_max_label($)
+{
+ my ($szB) = @_;
+
+ # We scale from millisecond to seconds to hours.
+ #
+ # XXX: this allows a number with 6 chars, eg. "3599.0 s"
+ my $szB_scaled = $szB;
+ my $unit = "ms";
+ if ($szB_scaled >= 1000) { $unit = "s"; $szB_scaled /= 1000; }
+ if ($szB_scaled >= 3600) { $unit = "h"; $szB_scaled /= 3600; }
+
+ return (max_label_2($szB, $szB_scaled), $unit);
+}
+
+# This prints four things:
+# - the output header
+# - the graph
+# - the snapshot summaries (number, list of detailed ones)
+# - the snapshots
+#
+# The first three parts can't be printed until we've read the whole input file;
+# but the fourth part is much easier to print while we're reading the file. So
+# we print the fourth part to a tmp file, and then dump the tmp file at the
+# end.
+#
+sub read_input_file()
+{
+ my $desc = ""; # Concatenated description lines.
+ my $peak_mem_total_szB = 0;
+
+ # Info about each snapshot.
+ my @snapshot_nums = ();
+ my @times = ();
+ my @mem_total_Bs = ();
+ my @is_detaileds = ();
+ my $peak_num = -1; # An initial value that will be ok if no peak
+ # entry is in the file.
+
+ #-------------------------------------------------------------------------
+ # Read start of input file.
+ #-------------------------------------------------------------------------
+ open(INPUTFILE, "< $input_file")
+ || die "Cannot open $input_file for reading\n";
+
+ # Read "desc:" lines.
+ my $line;
+ while ($line = get_line()) {
+ if ($line =~ s/^desc://) {
+ $desc .= $line;
+ } else {
+ last;
+ }
+ }
+
+ # Read "cmd:" line (Nb: will already be in $line from "desc:" loop above).
+ ($line =~ /^cmd:\s*(.*)$/) or die("Line $.: missing 'cmd' line\n");
+ $cmd = $1;
+
+ # Read "time_unit:" line.
+ $line = get_line();
+ ($line =~ /^time_unit:\s*(.*)$/) or
+ die("Line $.: missing 'time_unit' line\n");
+ $time_unit = $1;
+
+ #-------------------------------------------------------------------------
+ # Print snapshot list header to $tmp_file.
+ #-------------------------------------------------------------------------
+ open(TMPFILE, "> $tmp_file")
+ || die "Cannot open $tmp_file for reading\n";
+
+ my $time_column = sprintf("%14s", "time($time_unit)");
+ my $column_format = "%3s %14s %16s %16s %13s %12s\n";
+ my $header =
+ $fancy_nl .
+ sprintf($column_format
+ , "n"
+ , $time_column
+ , "total(B)"
+ , "useful-heap(B)"
+ , "admin-heap(B)"
+ , "stacks(B)"
+ ) .
+ $fancy_nl;
+ print(TMPFILE $header);
+
+ #-------------------------------------------------------------------------
+ # Read body of input file.
+ #-------------------------------------------------------------------------
+ $line = get_line();
+ while (defined $line) {
+ my $snapshot_num = equals_num_line($line, "snapshot");
+ my $time = equals_num_line(get_line(), "time");
+ my $mem_heap_B = equals_num_line(get_line(), "mem_heap_B");
+ my $mem_heap_admin_B = equals_num_line(get_line(), "mem_heap_admin_B");
+ my $mem_stacks_B = equals_num_line(get_line(), "mem_stacks_B");
+ my $mem_total_B = $mem_heap_B + $mem_heap_admin_B + $mem_stacks_B;
+ my $heap_tree = equals_num_line(get_line(), "heap_tree");
+
+ # Print the snapshot data to $tmp_file.
+ printf(TMPFILE $column_format,
+ , $snapshot_num
+ , commify($time)
+ , commify($mem_total_B)
+ , commify($mem_heap_B)
+ , commify($mem_heap_admin_B)
+ , commify($mem_stacks_B)
+ );
+
+ # Remember the snapshot data.
+ push(@snapshot_nums, $snapshot_num);
+ push(@times, $time);
+ push(@mem_total_Bs, $mem_total_B);
+ push(@is_detaileds, ( $heap_tree eq "empty" ? 0 : 1 ));
+ $peak_mem_total_szB = $mem_total_B
+ if $mem_total_B > $peak_mem_total_szB;
+
+ # Read the heap tree, and if it's detailed, print it and a subsequent
+ # snapshot list header to $tmp_file.
+ if ($heap_tree eq "empty") {
+ $line = get_line();
+ } elsif ($heap_tree =~ "(detailed|peak)") {
+ # If "peak", remember the number.
+ if ($heap_tree eq "peak") {
+ $peak_num = $snapshot_num;
+ }
+ # '1' means it's the top node of the tree.
+ read_heap_tree(1, "", "", "", $mem_total_B);
+
+ # Print the header, unless there are no more snapshots.
+ $line = get_line();
+ if (defined $line) {
+ print(TMPFILE $header);
+ }
+ } else {
+ die("Line $.: expected 'empty' or '...' after 'heap_tree='\n");
+ }
+ }
+
+ close(INPUTFILE);
+ close(TMPFILE);
+
+ #-------------------------------------------------------------------------
+ # Print header.
+ #-------------------------------------------------------------------------
+ print($fancy_nl);
+ print("Command: $cmd\n");
+ print("Massif arguments: $desc");
+ print("ms_print arguments:$ms_print_args\n");
+ print($fancy_nl);
+ print("\n\n");
+
+ #-------------------------------------------------------------------------
+ # Setup for graph.
+ #-------------------------------------------------------------------------
+ # The ASCII graph.
+ # Row 0 ([0..graph_x][0]) is the X-axis.
+ # Column 0 ([0][0..graph_y]) is the Y-axis.
+ # The rest ([1][1]..[graph_x][graph_y]) is the usable graph area.
+ my @graph;
+ my $x;
+ my $y;
+
+ my $n_snapshots = scalar(@snapshot_nums);
+ ($n_snapshots > 0) or die;
+ my $end_time = $times[$n_snapshots-1];
+ ($end_time >= 0) or die;
+
+ # Setup graph[][].
+ $graph[0][0] = '+'; # axes join point
+ for ($x = 1; $x <= $graph_x; $x++) { $graph[$x][0] = '-'; } # X-axis
+ for ($y = 1; $y <= $graph_y; $y++) { $graph[0][$y] = '|'; } # Y-axis
+ $graph[$graph_x][0] = '>'; # X-axis arrow
+ $graph[0][$graph_y] = '^'; # Y-axis arrow
+ for ($x = 1; $x <= $graph_x; $x++) { # usable area
+ for ($y = 1; $y <= $graph_y; $y++) {
+ $graph[$x][$y] = ' ';
+ }
+ }
+
+ #-------------------------------------------------------------------------
+ # Write snapshot bars into graph[][].
+ #-------------------------------------------------------------------------
+ # Each row represents K bytes, which is 1/graph_y of the peak size
+ # (and K can be non-integral). When drawing the column for a snapshot,
+ # in order to fill the slot in row y (where the first row drawn on is
+ # row 1) with a half-char (eg. '.'), it must be >= (y - 1/2)*K. In
+ # order to fill a row/column spot with a full-char (eg. ':'), it must be
+ # >= y*K. For example, if K = 10 bytes, then the values 0, 4, 5, 9, 10,
+ # 14, 15, 19, 20, 24, 25, 29, 30 would be drawn like this (showing one
+ # per column):
+ #
+ # y (y - 1/2) * K y * K
+ # - ------------- -----------
+ # 30 | ..: 3 (3 - 1/2) * 10 = 25 3 * 10 = 30
+ # 20 | ..::::: 2 (2 - 1/2) * 10 = 15 2 * 10 = 20
+ # 10 | ..::::::::: 1 (1 - 1/2) * 10 = 5 1 * 10 = 10
+ # 0 +-------------
+
+ my $peak_full_char = '#';
+ my $detailed_full_char = '@';
+ my $normal_full_char = ':';
+ my $half_char = '.';
+
+ # Work out how many bytes each row represents. If the peak size was 0,
+ # make it 1 so that the Y-axis covers a non-zero range of values.
+ # Likewise for end_time.
+ if (0 == $peak_mem_total_szB) { $peak_mem_total_szB = 1; }
+ if (0 == $end_time ) { $end_time = 1; }
+ my $K = $peak_mem_total_szB / $graph_y;
+
+ # If we leave end_time as is, the final snapshot will spill over past
+ # the last column. So we add a small epsilon to it to prevent this from
+ # happening.
+ $end_time += 0.001;
+
+ for (my $i = 0; $i < $n_snapshots; $i++) {
+
+ # Work out which column this snapshot belongs to.
+ my $x_pos_frac = ($times[$i] / ($end_time)) * $graph_x;
+ $x = int($x_pos_frac) + 1; # +1 due to Y-axis
+ # The final snapshot will spill over into the n+1th column, which
+ # doesn't get shown. So we fudge that one and pull it back a
+ # column, as if the end_time was actually end_time+epsilon.
+ if ($times[$i] == $end_time) {
+ ($x == $graph_x+1) or die;
+ $x = $graph_x;
+ }
+
+ # Draw the column if:
+ # - it's the peak column, or
+ # - it's a detailed column, and we won't overwrite the peak column, or
+ # - it's a normal column, and we won't overwrite the peak column or a
+ # detailed column.
+ my $should_draw_column =
+ (($i == $peak_num) or
+ ($is_detaileds[$i] and $graph[$x][0] ne $peak_full_char) or
+ ($graph[$x][0] ne $peak_full_char and
+ $graph[$x][0] ne $detailed_full_char));
+
+ if ($should_draw_column) {
+ # If it's detailed, mark the X-axis. Also choose the full-slot
+ # char.
+ my $full_char;
+ if ($i == $peak_num) {
+ $full_char = $peak_full_char;
+ $graph[$x][0] = $full_char;
+ } elsif ($is_detaileds[$i]) {
+ $full_char = $detailed_full_char;
+ $graph[$x][0] = $full_char;
+ } else {
+ $full_char = $normal_full_char;
+ }
+ # Grow this snapshot bar from bottom to top.
+ for ($y = 1; $y <= $graph_y; $y++) {
+ if ($mem_total_Bs[$i] >= ($y - 1/2) * $K) {
+ $graph[$x][$y] = $half_char;
+ }
+ if ($mem_total_Bs[$i] >= $y * $K) {
+ $graph[$x][$y] = $full_char;
+ }
+ }
+ }
+ }
+
+ #-------------------------------------------------------------------------
+ # Print graph[][].
+ #-------------------------------------------------------------------------
+ my ($y_label, $y_unit) = B_max_label($peak_mem_total_szB);
+ my ($x_label, $x_unit) = ( $time_unit eq "ms"
+ ? t_max_label($end_time)
+ : B_max_label($end_time) );
+
+ printf(" %2s\n", $y_unit);
+ for ($y = $graph_y; $y >= 0; $y--) {
+ if ($graph_y == $y) { # top row
+ print($y_label);
+ } elsif (0 == $y) { # bottom row
+ print(" 0 ");
+ } else { # anywhere else
+ print(" ");
+ }
+
+ # Axis and data for the row.
+ for ($x = 0; $x <= $graph_x; $x++) {
+ printf("%s", $graph[$x][$y]);
+ }
+ if (0 == $y) {
+ print("$x_unit\n");
+ } else {
+ print("\n");
+ }
+ }
+ printf(" 0%s%5s\n", ' ' x ($graph_x-5), $x_label);
+
+ #-------------------------------------------------------------------------
+ # Print snapshot numbers.
+ #-------------------------------------------------------------------------
+ print("\n");
+ print("Number of snapshots: $n_snapshots\n");
+ print(" Detailed snapshots: [");
+ my $first_detailed = 1;
+ for (my $i = 0; $i < $n_snapshots; $i++) {
+ if ($is_detaileds[$i]) {
+ if ($first_detailed) {
+ printf("$i");
+ $first_detailed = 0;
+ } else {
+ printf(", $i");
+ }
+ if ($i == $peak_num) {
+ print(" (peak)");
+ }
+ }
+ }
+ print("]\n");
+
+ #-------------------------------------------------------------------------
+ # Print snapshots, from $tmp_file.
+ #-------------------------------------------------------------------------
+ open(TMPFILE, "< $tmp_file")
+ || die "Cannot open $tmp_file for reading\n";
+
+ while (my $line = <TMPFILE>) {
+ print($line);
+ }
+ unlink($tmp_file);
+}
+
+#-----------------------------------------------------------------------------
+# Misc functions
+#-----------------------------------------------------------------------------
+sub commify ($) {
+ my ($val) = @_;
+ 1 while ($val =~ s/^(\d+)(\d{3})/$1,$2/);
+ return $val;
+}
+
+
+#----------------------------------------------------------------------------
+# "main()"
+#----------------------------------------------------------------------------
+process_cmd_line();
+read_input_file();
+
+##--------------------------------------------------------------------##
+##--- end ms_print.in ---##
+##--------------------------------------------------------------------##
+
+
|
|
From: Oswald B. <os...@kd...> - 2007-11-02 17:44:23
|
On Fri, Nov 02, 2007 at 08:56:08AM -0700, Dave Nomura wrote: > Is it possible to run an x86 valgrind on a PPC program? If so, how > would you do it? > so you want a cross-executing valgrind ... while i think vex would have no major problems with it (give or take some minor adjustments), i'm pretty sure nobody has written a syscall translation layer, and i guess it's unlikely that anybody will. -- Hi! I'm a .signature virus! Copy me into your ~/.signature, please! -- Chaos, panic, and disorder - my work here is done. |
|
From: Dave N. <dc...@us...> - 2007-11-02 15:56:08
|
Is it possible to run an x86 valgrind on a PPC program? If so, how would you do it? -- Dave Nomura LTC Linux Power Toolchain |
|
From: Oswald B. <os...@kd...> - 2007-11-02 08:51:39
|
On Fri, Nov 02, 2007 at 04:12:50AM +0000, sv...@va... wrote: > Author: njn > -static UInt clo_heap_admin = 8; > + // clo_heap_admin is deliberately a word-sized type. At one point it was > + // a UInt, but this caused problems on 64-bit machines when it was > + // multiplied by a small negative number and then promoted to a > + // word-sized type -- it ended up with a value of 4.2 billion. Sigh. > +static SizeT clo_heap_admin = 8; > this is really odd ... the code in update_heap_stats() did this: (unsigned long) = (unsigned long) + (unsigned int) * (signed int); while the actual multiplication is signed, the result is taken to be unsigned and is accordingly zero-extended in the promotion. you converted this to (unsigned long) = (unsigned long) + (unsigned long) * (signed int); which is about the right thing to do. however, for *way* more clarity and less bloat i'd suggest writing the actual expression as update_alloc_stats(heap_szB_delta + (SizeT)clo_heap_admin*n_heap_blocks_delta); instead of making the variable bigger. btw, in ms_post_clo_init() you'll get a warning, because, duh, an unsigned value cannot be smaller than zero. -- Hi! I'm a .signature virus! Copy me into your ~/.signature, please! -- Chaos, panic, and disorder - my work here is done. |
|
From: Konstantin S. <kon...@gm...> - 2007-11-02 08:39:20
|
It works, many thanks!
--kcc
On 11/1/07, Julian Seward <js...@ac...> wrote:
>
> On Thursday 01 November 2007 14:26, Konstantin Serebryany wrote:
> > Hi Julian,
> >
> > What shall I do if my .so has no soname?
> > What if my locking primitives reside in the main binary?
>
> That's ok. Use "NONE". See readelf.c:904.
>
> J
>
> >
> > Thanks,
> >
> > --kcc
> >
> > On 10/31/07, Julian Seward <js...@ac...> wrote:
> > > On Wednesday 31 October 2007 16:01, Konstantin Serebryany wrote:
> > > > Hi,
> > > >
> > > > I am trying to use thrcheck from THRCHECK branch.
> > > >
> > > > My program uses pthread_create to create threads, however it does
> not
> > >
> > > use
> > >
> > > > pthread_mutex_lock/unclock for locking -- it has its own set of
> locking
> > > > primitives.
> > > >
> > > > Is it possible to enhance thrcheck to handle user-settable
> lock/unlock
> > > > primitives?
> > >
> > > Yes, it is already possible. Look in tc_intercepts.c
> > > and look at the functions pthreadZumutexZulock and
> > > pthreadZumutexZuunlock. You need to make something like these
> > > (add them to tc_intercepts.c to keep your life simple).
> > >
> > > In the lock wrapper, the important components are
> > >
> > > VALGRIND_GET_ORIG_FN(fn);
> > >
> > > CALL_FN_W_W(ret, fn, mutex);
> > >
> > > if (ret == 0 /*success*/) {
> > > DO_CREQ_v_W(_VG_USERREQ__TC_PTHREAD_MUTEX_LOCK_POST,
> > > pthread_mutex_t*,mutex);
> > >
> > > It is this last part that notifies the tool that you acquired
> > > the lock.
> > >
> > > In the unlock wrapper, the important components are
> > >
> > > VALGRIND_GET_ORIG_FN(fn);
> > >
> > > DO_CREQ_v_W(_VG_USERREQ__TC_PTHREAD_MUTEX_UNLOCK_PRE,
> > > pthread_mutex_t*,mutex);
> > >
> > > CALL_FN_W_W(ret, fn, mutex);
> > >
> > > So in the lock wrapper you don't notify Thrcheck you have the lock
> > > until after the CALL_FN_W_W (the real lock call) succeeds.
> > > Conversely in the unlock wrapper you tell thrcheck you have
> > > released the lock before you really have released it.
> > >
> > > You will need to know the soname of the object containing your
> > > lock/unlock functions in order that you can write the magic PTH_FUNC
> > > wrapper. Study PTH_FUNC and QT4_FUNC. You can find the soname of
> > > xyz.so by doing "readelf -a xyz.so | grep soname".
> > >
> > > Use --trace-redir=yes and/or -v to find out whether your wrappers
> > > are actually getting called or not.
> > >
> > > J
>
|
|
From: <sv...@va...> - 2007-11-02 04:17:26
|
Author: njn Date: 2007-11-02 04:17:28 +0000 (Fri, 02 Nov 2007) New Revision: 7081 Log: Filter out libc differences. All Massif tests now pass on the AMD64 machine I just tested. Modified: trunk/massif/tests/deep-D.post.exp trunk/massif/tests/deep-D.vgtest Modified: trunk/massif/tests/deep-D.post.exp =================================================================== --- trunk/massif/tests/deep-D.post.exp 2007-11-02 04:12:48 UTC (rev 7080) +++ trunk/massif/tests/deep-D.post.exp 2007-11-02 04:17:28 UTC (rev 7081) @@ -45,7 +45,7 @@ 8 864 864 800 64 0 9 972 972 900 72 0 92.59% (900B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc. -->92.59% (900B) 0x........: (below main) (in /lib/libc-2.3.5.so) +->92.59% (900B) 0x........: (below main) (in /...libc...) -------------------------------------------------------------------------------- n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B) Modified: trunk/massif/tests/deep-D.vgtest =================================================================== --- trunk/massif/tests/deep-D.vgtest 2007-11-02 04:12:48 UTC (rev 7080) +++ trunk/massif/tests/deep-D.vgtest 2007-11-02 04:17:28 UTC (rev 7081) @@ -1,4 +1,4 @@ prog: deep vgopts: --stacks=no --time-unit=B --alloc-fn=a1 --alloc-fn=a2 --alloc-fn=a3 --alloc-fn=a4 --alloc-fn=a5 --alloc-fn=a6 --alloc-fn=a7 --alloc-fn=a8 --alloc-fn=a9 --alloc-fn=a10 --alloc-fn=a11 --alloc-fn=a12 --alloc-fn=main --depth=20 -post: perl ../../massif/ms_print massif.out | ../../tests/filter_addresses +post: perl ../../massif/ms_print massif.out | ../../tests/filter_addresses | ../../tests/filter_libc cleanup: rm massif.out |
|
From: <sv...@va...> - 2007-11-02 04:12:49
|
Author: njn Date: 2007-11-02 04:12:48 +0000 (Fri, 02 Nov 2007) New Revision: 7080 Log: Fix 64-bit Massif breakage, caused by problems with integer arithmetic on values of different signs and sizes that only a C language lawyer would spot. Modified: trunk/massif/ms_main.c Modified: trunk/massif/ms_main.c =================================================================== --- trunk/massif/ms_main.c 2007-11-01 18:58:46 UTC (rev 7079) +++ trunk/massif/ms_main.c 2007-11-02 04:12:48 UTC (rev 7080) @@ -395,7 +395,11 @@ } static Bool clo_heap = True; -static UInt clo_heap_admin = 8; + // clo_heap_admin is deliberately a word-sized type. At one point it was + // a UInt, but this caused problems on 64-bit machines when it was + // multiplied by a small negative number and then promoted to a + // word-sized type -- it ended up with a value of 4.2 billion. Sigh. +static SizeT clo_heap_admin = 8; static Bool clo_stacks = False; static UInt clo_depth = 30; static UInt clo_threshold = 100; // 100 == 1% |
|
From: Tom H. <th...@cy...> - 2007-11-02 03:26:45
|
Nightly build on alvis ( i686, Red Hat 7.3 ) started at 2007-11-02 03:15:01 GMT
Results differ from 24 hours ago
Checking out valgrind source tree ... done
Configuring valgrind ... failed
Last 20 lines of verbose log follow echo
A valgrind/VEX/quote.txt
A valgrind/VEX/Makefile
A valgrind/VEX/LICENSE.README
U valgrind/VEX
Checked out external at revision 1791.
Checked out revision 7079.
Configuring valgrind ... cd valgrind && ./autogen.sh && ./configure --prefix=/tmp/vgtest/2007-11-02/Inst
running: aclocal
running: autoheader
running: automake -a
configure.in: installing `./install-sh'
configure.in: installing `./mkinstalldirs'
configure.in: installing `./missing'
configure.in:116: installing `./config.guess'
configure.in:116: installing `./config.sub'
auxprogs/Makefile.am: installing `./compile'
auxprogs/Makefile.am: installing `./depcomp'
EXTRA_DIST: variable `noinst_SCRIPTS' is used but `noinst_SCRIPTS' is undefined
error: while running 'automake -a'
=================================================
== Results from 24 hours ago ==
=================================================
Checking out valgrind source tree ... done
Configuring valgrind ... done
Building valgrind ... done
Running regression tests ... failed
Regression test results follow
== 260 tests, 27 stderr failures, 1 stdout failure, 0 posttest failures ==
memcheck/tests/addressable (stderr)
memcheck/tests/badjump (stderr)
memcheck/tests/describe-block (stderr)
memcheck/tests/erringfds (stderr)
memcheck/tests/leak-0 (stderr)
memcheck/tests/leak-cycle (stderr)
memcheck/tests/leak-pool-0 (stderr)
memcheck/tests/leak-pool-1 (stderr)
memcheck/tests/leak-pool-2 (stderr)
memcheck/tests/leak-pool-3 (stderr)
memcheck/tests/leak-pool-4 (stderr)
memcheck/tests/leak-pool-5 (stderr)
memcheck/tests/leak-regroot (stderr)
memcheck/tests/leak-tree (stderr)
memcheck/tests/long_namespace_xml (stderr)
memcheck/tests/match-overrun (stderr)
memcheck/tests/partial_load_dflt (stderr)
memcheck/tests/partial_load_ok (stderr)
memcheck/tests/partiallydefinedeq (stderr)
memcheck/tests/pointer-trace (stderr)
memcheck/tests/sigkill (stderr)
memcheck/tests/stack_changes (stderr)
memcheck/tests/x86/scalar (stderr)
memcheck/tests/x86/scalar_supp (stderr)
memcheck/tests/x86/xor-undef-x86 (stderr)
memcheck/tests/xml1 (stderr)
none/tests/mremap (stderr)
none/tests/mremap2 (stdout)
=================================================
== Difference between 24 hours ago and now ==
=================================================
*** old.short Fri Nov 2 03:25:26 2007
--- new.short Fri Nov 2 03:26:44 2007
***************
*** 2,38 ****
Checking out valgrind source tree ... done
! Configuring valgrind ... done
! Building valgrind ... done
! Running regression tests ... failed
! Regression test results follow
!
! == 260 tests, 27 stderr failures, 1 stdout failure, 0 posttest failures ==
! memcheck/tests/addressable (stderr)
! memcheck/tests/badjump (stderr)
! memcheck/tests/describe-block (stderr)
! memcheck/tests/erringfds (stderr)
! memcheck/tests/leak-0 (stderr)
! memcheck/tests/leak-cycle (stderr)
! memcheck/tests/leak-pool-0 (stderr)
! memcheck/tests/leak-pool-1 (stderr)
! memcheck/tests/leak-pool-2 (stderr)
! memcheck/tests/leak-pool-3 (stderr)
! memcheck/tests/leak-pool-4 (stderr)
! memcheck/tests/leak-pool-5 (stderr)
! memcheck/tests/leak-regroot (stderr)
! memcheck/tests/leak-tree (stderr)
! memcheck/tests/long_namespace_xml (stderr)
! memcheck/tests/match-overrun (stderr)
! memcheck/tests/partial_load_dflt (stderr)
! memcheck/tests/partial_load_ok (stderr)
! memcheck/tests/partiallydefinedeq (stderr)
! memcheck/tests/pointer-trace (stderr)
! memcheck/tests/sigkill (stderr)
! memcheck/tests/stack_changes (stderr)
! memcheck/tests/x86/scalar (stderr)
! memcheck/tests/x86/scalar_supp (stderr)
! memcheck/tests/x86/xor-undef-x86 (stderr)
! memcheck/tests/xml1 (stderr)
! none/tests/mremap (stderr)
! none/tests/mremap2 (stdout)
--- 2,25 ----
Checking out valgrind source tree ... done
! Configuring valgrind ... failed
! Last 20 lines of verbose log follow echo
! A valgrind/VEX/quote.txt
! A valgrind/VEX/Makefile
! A valgrind/VEX/LICENSE.README
! U valgrind/VEX
! Checked out external at revision 1791.
+ Checked out revision 7079.
+ Configuring valgrind ... cd valgrind && ./autogen.sh && ./configure --prefix=/tmp/vgtest/2007-11-02/Inst
+ running: aclocal
+ running: autoheader
+ running: automake -a
+ configure.in: installing `./install-sh'
+ configure.in: installing `./mkinstalldirs'
+ configure.in: installing `./missing'
+ configure.in:116: installing `./config.guess'
+ configure.in:116: installing `./config.sub'
+ auxprogs/Makefile.am: installing `./compile'
+ auxprogs/Makefile.am: installing `./depcomp'
+ EXTRA_DIST: variable `noinst_SCRIPTS' is used but `noinst_SCRIPTS' is undefined
+ error: while running 'automake -a'
|
|
From: Tom H. <th...@cy...> - 2007-11-02 03:24:30
|
Nightly build on lloyd ( x86_64, Fedora 7 ) started at 2007-11-02 03:05:06 GMT Results differ from 24 hours ago Checking out valgrind source tree ... done Configuring valgrind ... done Building valgrind ... done Running regression tests ... failed Regression test results follow == 320 tests, 5 stderr failures, 2 stdout failures, 8 post failures == memcheck/tests/pointer-trace (stderr) memcheck/tests/vcpu_fnfns (stdout) memcheck/tests/x86/scalar (stderr) memcheck/tests/xml1 (stderr) massif/tests/basic (post) massif/tests/custom_alloc (post) massif/tests/deep-D (post) massif/tests/ignoring (post) massif/tests/new-cpp (post) massif/tests/overloaded-new (post) massif/tests/peak (post) massif/tests/peak2 (stderr) massif/tests/peak2 (post) none/tests/mremap (stderr) none/tests/mremap2 (stdout) ================================================= == Results from 24 hours ago == ================================================= Checking out valgrind source tree ... done Configuring valgrind ... done Building valgrind ... done Running regression tests ... failed Regression test results follow == 293 tests, 4 stderr failures, 2 stdout failures, 0 posttest failures == memcheck/tests/pointer-trace (stderr) memcheck/tests/vcpu_fnfns (stdout) memcheck/tests/x86/scalar (stderr) memcheck/tests/xml1 (stderr) none/tests/mremap (stderr) none/tests/mremap2 (stdout) ================================================= == Difference between 24 hours ago and now == ================================================= *** old.short Fri Nov 2 03:12:55 2007 --- new.short Fri Nov 2 03:24:29 2007 *************** *** 8,10 **** ! == 293 tests, 4 stderr failures, 2 stdout failures, 0 posttest failures == memcheck/tests/pointer-trace (stderr) --- 8,10 ---- ! == 320 tests, 5 stderr failures, 2 stdout failures, 8 post failures == memcheck/tests/pointer-trace (stderr) *************** *** 13,14 **** --- 13,23 ---- memcheck/tests/xml1 (stderr) + massif/tests/basic (post) + massif/tests/custom_alloc (post) + massif/tests/deep-D (post) + massif/tests/ignoring (post) + massif/tests/new-cpp (post) + massif/tests/overloaded-new (post) + massif/tests/peak (post) + massif/tests/peak2 (stderr) + massif/tests/peak2 (post) none/tests/mremap (stderr) |
|
From: Tom H. <th...@cy...> - 2007-11-02 03:23:33
|
Nightly build on dellow ( x86_64, Fedora 7 ) started at 2007-11-02 03:10:04 GMT Results differ from 24 hours ago Checking out valgrind source tree ... done Configuring valgrind ... done Building valgrind ... done Running regression tests ... failed Regression test results follow == 320 tests, 5 stderr failures, 3 stdout failures, 8 post failures == memcheck/tests/pointer-trace (stderr) memcheck/tests/vcpu_fnfns (stdout) memcheck/tests/x86/scalar (stderr) memcheck/tests/xml1 (stderr) massif/tests/basic (post) massif/tests/custom_alloc (post) massif/tests/deep-D (post) massif/tests/ignoring (post) massif/tests/new-cpp (post) massif/tests/overloaded-new (post) massif/tests/peak (post) massif/tests/peak2 (stderr) massif/tests/peak2 (post) none/tests/mremap (stderr) none/tests/mremap2 (stdout) none/tests/pth_detached (stdout) ================================================= == Results from 24 hours ago == ================================================= Checking out valgrind source tree ... done Configuring valgrind ... done Building valgrind ... done Running regression tests ... failed Regression test results follow == 293 tests, 4 stderr failures, 2 stdout failures, 0 posttest failures == memcheck/tests/pointer-trace (stderr) memcheck/tests/vcpu_fnfns (stdout) memcheck/tests/x86/scalar (stderr) memcheck/tests/xml1 (stderr) none/tests/mremap (stderr) none/tests/mremap2 (stdout) ================================================= == Difference between 24 hours ago and now == ================================================= *** old.short Fri Nov 2 03:16:48 2007 --- new.short Fri Nov 2 03:23:34 2007 *************** *** 8,10 **** ! == 293 tests, 4 stderr failures, 2 stdout failures, 0 posttest failures == memcheck/tests/pointer-trace (stderr) --- 8,10 ---- ! == 320 tests, 5 stderr failures, 3 stdout failures, 8 post failures == memcheck/tests/pointer-trace (stderr) *************** *** 13,16 **** --- 13,26 ---- memcheck/tests/xml1 (stderr) + massif/tests/basic (post) + massif/tests/custom_alloc (post) + massif/tests/deep-D (post) + massif/tests/ignoring (post) + massif/tests/new-cpp (post) + massif/tests/overloaded-new (post) + massif/tests/peak (post) + massif/tests/peak2 (stderr) + massif/tests/peak2 (post) none/tests/mremap (stderr) none/tests/mremap2 (stdout) + none/tests/pth_detached (stdout) |
|
From: Tom H. <th...@cy...> - 2007-11-02 03:08:27
|
Nightly build on gill ( x86_64, Fedora Core 2 ) started at 2007-11-02 03:00:02 GMT Results differ from 24 hours ago Checking out valgrind source tree ... done Configuring valgrind ... done Building valgrind ... done Running regression tests ... failed Last 20 lines of verbose log follow echo then mv -f ".deps/long-time.Tpo" ".deps/long-time.Po"; else rm -f ".deps/long-time.Tpo"; exit 1; fi long-time.c: In function `main': long-time.c:15: warning: ISO C90 forbids mixed declarations and code long-time.c:18: warning: ISO C90 forbids mixed declarations and code gcc -Winline -Wall -Wshadow -g -m64 -Wno-long-long -Wdeclaration-after-statement -o long-time long-time.o if g++ -DHAVE_CONFIG_H -I. -I. -I../.. -I../.. -I../../include -I../../coregrind -I../../include -I../../VEX/pub -g -O2 -MT new-cpp.o -MD -MP -MF ".deps/new-cpp.Tpo" -c -o new-cpp.o new-cpp.cpp; \ then mv -f ".deps/new-cpp.Tpo" ".deps/new-cpp.Po"; else rm -f ".deps/new-cpp.Tpo"; exit 1; fi new-cpp.cpp: In function `int main()': new-cpp.cpp:20: error: invalid use of undefined type `struct main()::s' new-cpp.cpp:20: error: forward declaration of `struct main()::s' new-cpp.cpp:20: error: ISO C++ forbids defining types within new make[4]: *** [new-cpp.o] Error 1 make[4]: Leaving directory `/tmp/vgtest/2007-11-02/valgrind/massif/tests' make[3]: *** [check-am] Error 2 make[3]: Leaving directory `/tmp/vgtest/2007-11-02/valgrind/massif/tests' make[2]: *** [check-recursive] Error 1 make[2]: Leaving directory `/tmp/vgtest/2007-11-02/valgrind/massif' make[1]: *** [check-recursive] Error 1 make[1]: Leaving directory `/tmp/vgtest/2007-11-02/valgrind' make: *** [check] Error 2 ================================================= == Results from 24 hours ago == ================================================= Checking out valgrind source tree ... done Configuring valgrind ... done Building valgrind ... done Running regression tests ... failed Regression test results follow == 295 tests, 6 stderr failures, 1 stdout failure, 0 posttest failures == memcheck/tests/pointer-trace (stderr) memcheck/tests/stack_switch (stderr) memcheck/tests/x86/scalar (stderr) memcheck/tests/x86/scalar_supp (stderr) none/tests/fdleak_fcntl (stderr) none/tests/mremap (stderr) none/tests/mremap2 (stdout) ================================================= == Difference between 24 hours ago and now == ================================================= *** old.short Fri Nov 2 03:05:45 2007 --- new.short Fri Nov 2 03:08:28 2007 *************** *** 6,17 **** ! Regression test results follow ! ! == 295 tests, 6 stderr failures, 1 stdout failure, 0 posttest failures == ! memcheck/tests/pointer-trace (stderr) ! memcheck/tests/stack_switch (stderr) ! memcheck/tests/x86/scalar (stderr) ! memcheck/tests/x86/scalar_supp (stderr) ! none/tests/fdleak_fcntl (stderr) ! none/tests/mremap (stderr) ! none/tests/mremap2 (stdout) ! --- 6,27 ---- ! Last 20 lines of verbose log follow echo ! then mv -f ".deps/long-time.Tpo" ".deps/long-time.Po"; else rm -f ".deps/long-time.Tpo"; exit 1; fi ! long-time.c: In function `main': ! long-time.c:15: warning: ISO C90 forbids mixed declarations and code ! long-time.c:18: warning: ISO C90 forbids mixed declarations and code ! gcc -Winline -Wall -Wshadow -g -m64 -Wno-long-long -Wdeclaration-after-statement -o long-time long-time.o ! if g++ -DHAVE_CONFIG_H -I. -I. -I../.. -I../.. -I../../include -I../../coregrind -I../../include -I../../VEX/pub -g -O2 -MT new-cpp.o -MD -MP -MF ".deps/new-cpp.Tpo" -c -o new-cpp.o new-cpp.cpp; \ ! then mv -f ".deps/new-cpp.Tpo" ".deps/new-cpp.Po"; else rm -f ".deps/new-cpp.Tpo"; exit 1; fi ! new-cpp.cpp: In function `int main()': ! new-cpp.cpp:20: error: invalid use of undefined type `struct main()::s' ! new-cpp.cpp:20: error: forward declaration of `struct main()::s' ! new-cpp.cpp:20: error: ISO C++ forbids defining types within new ! make[4]: *** [new-cpp.o] Error 1 ! make[4]: Leaving directory `/tmp/vgtest/2007-11-02/valgrind/massif/tests' ! make[3]: *** [check-am] Error 2 ! make[3]: Leaving directory `/tmp/vgtest/2007-11-02/valgrind/massif/tests' ! make[2]: *** [check-recursive] Error 1 ! make[2]: Leaving directory `/tmp/vgtest/2007-11-02/valgrind/massif' ! make[1]: *** [check-recursive] Error 1 ! make[1]: Leaving directory `/tmp/vgtest/2007-11-02/valgrind' ! make: *** [check] Error 2 |