Posted
almost 2 years
ago
by
Enrique Ocaña González
This is the last post on the instrumenting source code series. I hope you to find the tricks below as useful as the previous ones.
In this post I show some more useful debugging tricks. Don’t forget to have a look at the other posts of the
... [More]
series:
GStreamer WebKit debugging tricks using GDB (1/2)
GStreamer WebKit debugging tricks using GDB (2/2)
GStreamer WebKit debugging by instrumenting source code (1/3)
GStreamer WebKit debugging by instrumenting source code (2/3)
Finding memory leaks in a RefCounted subclass
The source code shown below must be placed in the .h where the class to be debugged is defined. It’s written in a way that doesn’t need to rebuild RefCounted.h, so it saves a lot of build time. It logs all refs, unrefs and adoptPtrs, so that any anomaly in the refcounting can be traced and investigated later. To use it, just make your class inherit from LoggedRefCounted instead of RefCounted.
Example output:
void WTF::adopted(WTF::LoggedRefCounted*) [with T = WebCore::MediaSourceClientGStreamerMSE]: this=0x673c07a4, refCount 1
void WTF::adopted(WTF::LoggedRefCounted*) [with T = WebCore::MediaSourceClientGStreamerMSE]: this=0x673c07a4, refCount 1
^^^ Two adopts, this is not good.
void WTF::LoggedRefCounted::ref() [with T = WebCore::MediaSourceClientGStreamerMSE]: this=0x673c07a4, refCount 1 --> ...
void WTF::LoggedRefCounted::ref() [with T = WebCore::MediaSourceClientGStreamerMSE]: this=0x673c07a4, refCount ... --> 2
void WTF::LoggedRefCounted::deref() [with T = WebCore::MediaSourceClientGStreamerMSE]: this=0x673c07a4, refCount 2 --> ...
void WTF::LoggedRefCounted::deref() [with T = WebCore::MediaSourceClientGStreamerMSE]: this=0x673c07a4, refCount ... --> 1
void WTF::adopted(WTF::LoggedRefCounted*) [with T = WebCore::MediaSourceClientGStreamerMSE]: this=0x673c07a4, refCount 1
void WTF::LoggedRefCounted::deref() [with T = WebCore::MediaSourceClientGStreamerMSE]: this=0x673c07a4, refCount 1 --> ...
void WTF::LoggedRefCounted::deref() [with T = WebCore::MediaSourceClientGStreamerMSE]: this=0x673c07a4, refCount 1 --> ...
^^^ Two recursive derefs, not good either.
#include "Logging.h"
namespace WTF {
template class LoggedRefCounted : public WTF::RefCounted {
WTF_MAKE_NONCOPYABLE(LoggedRefCounted); WTF_MAKE_FAST_ALLOCATED;
public:
void ref() {
printf("%s: this=%p, refCount %d --> ...\n", __PRETTY_FUNCTION__, this, WTF::RefCounted::refCount()); fflush(stdout);
WTF::RefCounted::ref();
printf("%s: this=%p, refCount ... --> %d\n", __PRETTY_FUNCTION__, this, WTF::RefCounted::refCount()); fflush(stdout);
}
void deref() {
printf("%s: this=%p, refCount %d --> ...\n", __PRETTY_FUNCTION__, this, WTF::RefCounted::refCount()); fflush(stdout);
WTF::RefCounted::deref();
printf("%s: this=%p, refCount ... --> %d\n", __PRETTY_FUNCTION__, this, WTF::RefCounted::refCount()); fflush(stdout);
}
protected:
LoggedRefCounted() { }
~LoggedRefCounted() { }
};
template inline void adopted(WTF::LoggedRefCounted* object)
{
printf("%s: this=%p, refCount %d\n", __PRETTY_FUNCTION__, object, (object)?object->refCount():0); fflush(stdout);
adopted(static_cast(object));
}
} // Namespace WTF
Pause WebProcess on launch
WebProcessMainGtk and WebProcessMainWPE will sleep for 30 seconds if a special environment variable is defined:
export WEBKIT2_PAUSE_WEB_PROCESS_ON_LAUNCH=1
It only works #if ENABLE(DEVELOPER_MODE), so you might want to remove those ifdefs if you’re building in Release mode.
Log tracers
In big pipelines (e.g. playbin) it can be very hard to find what element is replying to a query or handling an event. Even using gdb can be extremely tedious due to the very high level of recursion. My coworker Alicia commented that using log tracers is more helpful in this case.
GST_TRACERS=log enables additional GST_TRACE() calls all accross GStreamer. The following example logs entries and exits into the query function.
GST_TRACERS=log GST_DEBUG='query:TRACE'
The names of the logging categories are somewhat inconsistent:
log (the log tracer itself)
GST_BUFFER
GST_BUFFER_LIST
GST_EVENT
GST_MESSAGE
GST_STATES
GST_PADS
GST_ELEMENT_PADS
GST_ELEMENT_FACTORY
query
bin
The log tracer code is in subprojects/gstreamer/plugins/tracers/gstlog.c.
0 0 [Less]
|
Posted
almost 2 years
ago
by
Pavel Rojtberg
Lets say, you want to reduce the water carbonate hardness because you got a shiny coffee machine and descaling that is a time-consuming mess.
If you dont happen to run a coffee-shop, using a water-jug is totally sufficient for this.
... [More]
Unfortunately, while the jug itself is quite cheap, the filters you need will cost you an arm and a leg – similar to how the printer-ink business works.
The setup
Here, we want to look at the different filter options and compare their performance. The contenders are
Name
Pricing
Brita Classic
~15.19 €
PearlCo Classic
12.90 €
PearlCo Protect+
15.90 €
As said initially, the primary goal of using these filters is to reduce the water carbonate – any other changes, like pH mythology, will not be considered.
To measure the performance in this regard, I am using a digital total dissolved solid meter – just like the one used in the Wikipedia article. To make the measurement robust against environmental variations, I am not only measuring the PPM in the filtered water, but also in the tap water before filtering. The main indicator is then the reduction factor.
Also, you are not using the filter only once, so I repeat the measuring over the course of 37 days. Why 37? Well, most filters are specified for 30 days of usage – but I want to see how much cushion we got there.
So – without further ado – the results:
Results
Name
Ø PPM reduction
Ø absolute PPM
Brita Classic
31%
206
PearlCo Classic
24%
218
PearlCo Protect+
32%
191
As motivated above, the difference in absolute PPM can be explained by environmental variation – after all the measurements took place over the course of more than 3 months.
However, we see that the pricing difference is indeed reflected by filtering performance. By paying ~20% more, you get a ~30% higher PPM reduction.
The only thing missing, is the time-series to see beyond 30 days:
As you can see, the filtering performance is continuously declining after a peak at about 10-15 days of use.
And for completeness, the absolute PPM values:
0 0 [Less]
|
Posted
almost 2 years
ago
by
Pavel Rojtberg
Lets say, you want to reduce the water carbonate hardness because you got a shiny coffee machine and descaling that is a time-consuming mess.
If you dont happen to run a coffee-shop, using a water-jug is totally sufficient for this.
... [More]
Unfortunately, while the jug itself is quite cheap, the filters you need will cost you an arm and a leg – similar to how the printer-ink business works.
The setup
Here, we want to look at the different filter options and compare their performance. The contenders are
Name
Pricing
Brita Classic
~15.19 €
PearlCo Classic
12.90 €
PearlCo Protect+
15.90 €
As said initially, the primary goal of using these filters is to reduce the water carbonate – any other changes, like pH mythology, will not be considered.
To measure the performance in this regard, I am using a digital total dissolved solid meter – just like the one used in the Wikipedia article. To make the measurement robust against environmental variations, I am not only measuring the PPM in the filtered water, but also in the tap water before filtering. The main indicator is then the reduction factor.
Also, you are not using the filter only once, so I repeat the measuring over the course of 37 days. Why 37? Well, most filters are specified for 30 days of usage – but I want to see how much cushion we got there.
So – without further ado – the results:
Results
Name
Ø PPM reduction
Ø absolute PPM
Brite Classic
31%
206
PearlCo Classic
24%
218
PearlCo Protect+
32%
191
As motivated above, the difference in absolute PPM can be explained by environmental variation – after all the measurements took place over the course of more than 3 months.
However, we see that the pricing difference is indeed reflected by filtering performance. By paying ~20% more, you get a ~30% higher PPM reduction.
The only thing missing, is the time-series to see beyond 30 days:
As you can see, the filtering performance is continuously declining after a peak at about 10-15 days of use.
And for completeness, the absolute PPM values:
0 0 [Less]
|
Posted
almost 2 years
ago
by
Pavel Rojtberg
Lets say, you want to reduce the water carbonate hardness because you got a shiny coffee machine and descaling that is a time-consuming mess.
If you dont happen to run a coffee-shop, using a water-jug is totally sufficient for this.
... [More]
Unfortunately, while the jug itself is quite cheap, the filters you need will cost you an arm and a leg – similar to how the printer-ink business works.
The setup
Here, we want to look at the different filter options and compare their performance. The contenders are
Name
Pricing
Brita Classic
~15.19 €
PearlCo Classic
12.90 €
PearlCo Protect+
15.90 €
As said initially, the primary goal of using these filters is to reduce the water carbonate – any other changes, like pH mythology, will not be considered.
To measure the performance in this regard, I am using a digital total dissolved solid meter – just like the one used in the Wikipedia article. To make the measurement robust against environmental variations, I am not only measuring the PPM in the filtered water, but also in the tap water before filtering. The main indicator is then the reduction factor.
Also, you are not using the filter only once, so I repeat the measuring over the course of 37 days. Why 37? Well onlinemedikament.online , most filters are specified for 30 days of usage – but I want to see how much cushion we got there.
So – without further ado – the results:
Results
Name
Ø PPM reduction
Ø absolute PPM
Brita Classic
31%
206
PearlCo Classic
24%
218
PearlCo Protect+
32%
191
As motivated above, the difference in absolute PPM can be explained by environmental variation – after all the measurements took place over the course of more than 3 months.
However, we see that the pricing difference is indeed reflected by filtering performance. By paying ~20% more, you get a ~30% higher PPM reduction.
The only thing missing, is the time-series to see beyond 30 days:
As you can see, the filtering performance is continuously declining after a peak at about 10-15 days of use.
And for completeness, the absolute PPM values:
0 0 [Less]
|
Posted
almost 2 years
ago
by
Pavel Rojtberg
Lets say, you want to reduce the water carbonate hardness because you got a shiny coffee machine and descaling that is a time-consuming mess.
If you dont happen to run a coffee-shop, using a water-jug is totally sufficient for this.
... [More]
Unfortunately, while the jug itself is quite cheap, the filters you need will cost you an arm and a leg – similar to how the printer-ink business works.
The setup
Here, we want to look at the different filter options and compare their performance. The contenders are
Name
Pricing
Brita Classic
~15.19 €
PearlCo Classic
12.90 €
PearlCo Protect+
15.90 €
As said initially, the primary goal of using these filters is to reduce the water carbonate – any other changes, like pH mythology, will not be considered.
To measure the performance in this regard, I am using a digital total dissolved solid meter – just like the one used in the Wikipedia article. To make the measurement robust against environmental variations, I am not only measuring the PPM in the filtered water, but also in the tap water before filtering. The main indicator is then the reduction factor.
Also, you are not using the filter only once, so I repeat the measuring over the course of 37 days. Why 37? Well, most filters are specified for 30 days of usage – but I want to see how much cushion we got there.
So – without further ado – the results:
Results
Name
Ø PPM reduction
Ø absolute PPM
Brita Classic
31%
206
PearlCo Classic
24%
218
PearlCo Protect+
32%
191
As motivated above, the difference in absolute PPM can be explained by environmental variation – after all the measurements took place over the course of more than 3 months.
However, we see that the pricing difference is indeed reflected by filtering performance. By paying ~20% more, you get a ~30% higher PPM reduction.
The only thing missing, is the time-series to see beyond 30 days:
As you can see, the filtering performance is continuously declining after a peak at about 10-15 days of use.
And for completeness, the absolute PPM values:
0 0 [Less]
|
Posted
almost 2 years
ago
by
Enrique Ocaña González
In this post I show some more useful debugging tricks. Check also the other posts of the series:
GStreamer WebKit debugging tricks using GDB (1/2)
GStreamer WebKit debugging tricks using GDB (2/2)
GStreamer WebKit debugging by instrumenting
... [More]
source code (1/3)
Print current thread id
The thread id is generated by Linux and can take values higher than 1-9, just like PIDs. This thread number is useful to know which function calls are issued by the same thread, avoiding confusion between threads.
#include
#include
#include
printf("%s [%d]\n", __PRETTY_FUNCTION__, syscall(SYS_gettid));
fflush(stdout);
Debug GStreamer thread locks
We redefine the GST_OBJECT_LOCK/UNLOCK/TRYLOCK macros to print the calls, compare locks against unlocks, and see who’s not releasing its lock:
#include "wtf/Threading.h"
#define GST_OBJECT_LOCK(obj) do { \
printf("### [LOCK] %s [%p]\n", __PRETTY_FUNCTION__, &Thread::current()); fflush(stdout); \
g_mutex_lock(GST_OBJECT_GET_LOCK(obj)); \
} while (0)
#define GST_OBJECT_UNLOCK(obj) do { \
printf("### [UNLOCK] %s [%p]\n", __PRETTY_FUNCTION__, &Thread::current()); fflush(stdout); \
g_mutex_unlock(GST_OBJECT_GET_LOCK(obj)); \
} while (0)
#define GST_OBJECT_TRYLOCK(obj) ({ \
gboolean result = g_mutex_trylock(GST_OBJECT_GET_LOCK(obj)); \
if (result) { \
printf("### [LOCK] %s [%p]\n", __PRETTY_FUNCTION__, &Thread::current()); fflush(stdout); \
} \
result; \
})
Warning: The statement expression that allows the TRYLOCK macro to return a value will only work on GCC.
There’s a way to know which thread has taken a lock in glib/GStreamer using gdb. First locate the stalled thread:
(gdb) thread
(gdb) bt
#2 0x74f07416 in pthread_mutex_lock ()
#3 0x7488aec6 in gst_pad_query ()
#4 0x6debebf2 in autoplug_query_allocation ()
(gdb) frame 3
#3 0x7488aec6 in gst_pad_query (pad=pad@entry=0x54a9b8, ...)
4058 GST_PAD_STREAM_LOCK (pad);
Now get the process id (PID) and use the pthread_mutex_t structure to print the Linux thread id that has acquired the lock:
(gdb) call getpid()
$30 = 6321
(gdb) p ((pthread_mutex_t*)pad.stream_rec_lock.p)->__data.__owner
$31 = 6368
(gdb) thread find 6321.6368
Thread 21 has target id 'Thread 6321.6368'
Trace function calls (poor developer version)
If you’re using C++, you can define a tracer class. This is for webkit, but you get the idea:
#define MYTRACER() MyTracer(__PRETTY_FUNCTION__);
class MyTracer {
public:
MyTracer(const gchar* functionName)
: m_functionName(functionName) {
printf("### %s : begin %d\n", m_functionName.utf8().data(), currentThread()); fflush(stdout);
}
virtual ~MyTracer() {
printf("### %s : end %d\n", m_functionName.utf8().data(), currentThread()); fflush(stdout);
}
private:
String m_functionName;
};
And use it like this in all the functions you want to trace:
void somefunction() {
MYTRACER();
// Some other code...
}
The constructor will log when the execution flow enters into the function and the destructor will log when the flow exits.
Setting breakpoints from C
In the C code, just call raise(SIGINT) (simulate CTRL+C, normally the program would finish).
And then, in a previously attached gdb, after breaking and having debugging all you needed, just continue the execution by ignoring the signal or just plainly continuing:
(gdb) signal 0
(gdb) continue
There’s a way to do the same but attaching gdb after the raise. Use raise(SIGSTOP) instead (simulate CTRL+Z). Then attach gdb, locate the thread calling raise and switch to it:
(gdb) thread apply all bt
[now search for "raise" in the terminal log]
Thread 36 (Thread 1977.2033): #1 0x74f5b3f2 in raise () from /home/enrique/buildroot/output2/staging/lib/libpthread.so.0
(gdb) thread 36
Now, from a terminal, send a continuation signal: kill -SIGCONT 1977. Finally instruct gdb to single-step only the current thread (IMPORTANT!) and run some steps until all the raises have been processed:
(gdb) set scheduler-locking on
(gdb) next // Repeat several times...
Know the name of a GStreamer function stored in a pointer at runtime
Just use this macro:
GST_DEBUG_FUNCPTR_NAME(func)
Detecting memory leaks in WebKit
RefCountedLeakCounter is a tool class that can help to debug reference leaks by printing this kind of messages when WebKit exits:
LEAK: 2 XMLHttpRequest
LEAK: 25 CachedResource
LEAK: 3820 WebCoreNode
To use it you have to modify the particular class you want to debug:
Include wtf/RefCountedLeakCounter.h
DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, myClassCounter, ("MyClass"));
In the constructor: myClassCounter.increment()
In the destructor: myClassCounter.decrement()
0 0 [Less]
|
Posted
almost 2 years
ago
by
Enrique Ocaña González
In this post I show some more useful debugging tricks. Check also the other posts of the series:
GStreamer WebKit debugging tricks using GDB (1/2)
GStreamer WebKit debugging tricks using GDB (2/2)
GStreamer WebKit debugging by instrumenting
... [More]
source code (1/3)
Print current thread id
The thread id is generated by Linux and can take values higher than 1-9, just like PIDs. This thread number is useful to know which function calls are issued by the same thread, avoiding confusion between threads.
#include
#include
#include
printf("%s [%d]\n", __PRETTY_FUNCTION__, syscall(SYS_gettid));
fflush(stdout);
Debug GStreamer thread locks
We redefine the GST_OBJECT_LOCK/UNLOCK/TRYLOCK macros to print the calls, compare locks against unlocks, and see who’s not releasing its lock:
#include "wtf/Threading.h"
#define GST_OBJECT_LOCK(obj) do { \
printf("### [LOCK] %s [%p]\n", __PRETTY_FUNCTION__, &Thread::current()); fflush(stdout); \
g_mutex_lock(GST_OBJECT_GET_LOCK(obj)); \
} while (0)
#define GST_OBJECT_UNLOCK(obj) do { \
printf("### [UNLOCK] %s [%p]\n", __PRETTY_FUNCTION__, &Thread::current()); fflush(stdout); \
g_mutex_unlock(GST_OBJECT_GET_LOCK(obj)); \
} while (0)
#define GST_OBJECT_TRYLOCK(obj) ({ \
gboolean result = g_mutex_trylock(GST_OBJECT_GET_LOCK(obj)); \
if (result) { \
printf("### [LOCK] %s [%p]\n", __PRETTY_FUNCTION__, &Thread::current()); fflush(stdout); \
} \
result; \
})
Warning: The statement expression that allows the TRYLOCK macro to return a value will only work on GCC.
There’s a way to know which thread has taken a lock in glib/GStreamer using gdb. First locate the stalled thread:
(gdb) thread
(gdb) bt
#2 0x74f07416 in pthread_mutex_lock ()
#3 0x7488aec6 in gst_pad_query ()
#4 0x6debebf2 in autoplug_query_allocation ()
(gdb) frame 3
#3 0x7488aec6 in gst_pad_query (pad=pad@entry=0x54a9b8, ...)
4058 GST_PAD_STREAM_LOCK (pad);
Now get the process id (PID) and use the pthread_mutex_t structure to print the Linux thread id that has acquired the lock:
(gdb) call getpid()
$30 = 6321
(gdb) p ((pthread_mutex_t*)pad.stream_rec_lock.p)->__data.__owner
$31 = 6368
(gdb) thread find 6321.6368
Thread 21 has target id 'Thread 6321.6368'
Trace function calls (poor developer version)
If you’re using C++, you can define a tracer class. This is for webkit, but you get the idea:
#define MYTRACER() MyTracer(__PRETTY_FUNCTION__);
class MyTracer {
public:
MyTracer(const gchar* functionName)
: m_functionName(functionName) {
printf("### %s : begin %d\n", m_functionName.utf8().data(), currentThread()); fflush(stdout);
}
virtual ~MyTracer() {
printf("### %s : end %d\n", m_functionName.utf8().data(), currentThread()); fflush(stdout);
}
private:
String m_functionName;
};
And use it like this in all the functions you want to trace:
void somefunction() {
MYTRACER();
// Some other code...
}
The constructor will log when the execution flow enters into the function and the destructor will log when the flow exits.
Setting breakpoints from C
In the C code, just call raise(SIGINT) (simulate CTRL+C, normally the program would finish).
And then, in a previously attached gdb, after breaking and having debugging all you needed, just continue the execution by ignoring the signal or just plainly continuing:
(gdb) signal 0
(gdb) continue
There’s a way to do the same but attaching gdb after the raise. Use raise(SIGSTOP) instead (simulate CTRL+Z). Then attach gdb, locate the thread calling raise and switch to it:
(gdb) thread apply all bt
[now search for "raise" in the terminal log]
Thread 36 (Thread 1977.2033): #1 0x74f5b3f2 in raise () from /home/enrique/buildroot/output2/staging/lib/libpthread.so.0
(gdb) thread 36
Now, from a terminal, send a continuation signal: kill -SIGCONT 1977. Finally instruct gdb to single-step only the current thread (IMPORTANT!) and run some steps until all the raises have been processed:
(gdb) set scheduler-locking on
(gdb) next // Repeat several times...
Know the name of a GStreamer function stored in a pointer at runtime
Just use this macro:
GST_DEBUG_FUNCPTR_NAME(func)
Detecting memory leaks in WebKit
RefCountedLeakCounter is a tool class that can help to debug reference leaks by printing this kind of messages when WebKit exits:
LEAK: 2 XMLHttpRequest
LEAK: 25 CachedResource
LEAK: 3820 WebCoreNode
To use it you have to modify the particular class you want to debug:
Include wtf/RefCountedLeakCounter.h
DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, myClassCounter, ("MyClass"));
In the constructor: myClassCounter.increment()
In the destructor: myClassCounter.decrement()
0 0 [Less]
|
Posted
almost 2 years
ago
by
Enrique Ocaña González
In this post I show some more useful debugging tricks. Check also the other posts of the series:
GStreamer WebKit debugging tricks using GDB (1/2)
GStreamer WebKit debugging tricks using GDB (2/2)
GStreamer WebKit debugging by instrumenting
... [More]
source code (1/3)
Print current thread id
The thread id is generated by Linux and can take values higher than 1-9, just like PIDs. This thread number is useful to know which function calls are issued by the same thread, avoiding confusion between threads.
#include
#include
#include
printf("%s [%d]\n", __PRETTY_FUNCTION__, syscall(SYS_gettid));
fflush(stdout);
Debug GStreamer thread locks
We redefine the GST_OBJECT_LOCK/UNLOCK/TRYLOCK macros to print the calls, compare locks against unlocks, and see who’s not releasing its lock:
#include "wtf/Threading.h"
#define GST_OBJECT_LOCK(obj) do { \
printf("### [LOCK] %s [%p]\n", __PRETTY_FUNCTION__, &Thread::current()); fflush(stdout); \
g_mutex_lock(GST_OBJECT_GET_LOCK(obj)); \
} while (0)
#define GST_OBJECT_UNLOCK(obj) do { \
printf("### [UNLOCK] %s [%p]\n", __PRETTY_FUNCTION__, &Thread::current()); fflush(stdout); \
g_mutex_unlock(GST_OBJECT_GET_LOCK(obj)); \
} while (0)
#define GST_OBJECT_TRYLOCK(obj) ({ \
gboolean result = g_mutex_trylock(GST_OBJECT_GET_LOCK(obj)); \
if (result) { \
printf("### [LOCK] %s [%p]\n", __PRETTY_FUNCTION__, &Thread::current()); fflush(stdout); \
} \
result; \
})
Warning: The statement expression that allows the TRYLOCK macro to return a value will only work on GCC.
There’s a way to know which thread has taken a lock in glib/GStreamer using gdb. First locate the stalled thread:
(gdb) thread
(gdb) bt
#2 0x74f07416 in pthread_mutex_lock ()
#3 0x7488aec6 in gst_pad_query ()
#4 0x6debebf2 in autoplug_query_allocation ()
(gdb) frame 3
#3 0x7488aec6 in gst_pad_query (pad=pad@entry=0x54a9b8, ...)
4058 GST_PAD_STREAM_LOCK (pad);
Now get the process id (PID) and use the pthread_mutex_t structure to print the Linux thread id that has acquired the lock:
(gdb) call getpid()
$30 = 6321
(gdb) p ((pthread_mutex_t*)pad.stream_rec_lock.p)->__data.__owner
$31 = 6368
(gdb) thread find 6321.6368
Thread 21 has target id 'Thread 6321.6368'
Trace function calls (poor developer version)
If you’re using C++, you can define a tracer class. This is for webkit, but you get the idea:
#define MYTRACER() MyTracer(__PRETTY_FUNCTION__);
class MyTracer {
public:
MyTracer(const gchar* functionName)
: m_functionName(functionName) {
printf("### %s : begin %d\n", m_functionName.utf8().data(), currentThread()); fflush(stdout);
}
virtual ~MyTracer() {
printf("### %s : end %d\n", m_functionName.utf8().data(), currentThread()); fflush(stdout);
}
private:
String m_functionName;
};
And use it like this in all the functions you want to trace:
void somefunction() {
MYTRACER();
// Some other code...
}
The constructor will log when the execution flow enters into the function and the destructor will log when the flow exits.
Setting breakpoints from C
In the C code, just call raise(SIGINT) (simulate CTRL+C, normally the program would finish).
And then, in a previously attached gdb, after breaking and having debugging all you needed, just continue the execution by ignoring the signal or just plainly continuing:
(gdb) signal 0
(gdb) continue
There’s a way to do the same but attaching gdb after the raise. Use raise(SIGSTOP) instead (simulate CTRL+Z). Then attach gdb, locate the thread calling raise and switch to it:
(gdb) thread apply all bt
[now search for "raise" in the terminal log]
Thread 36 (Thread 1977.2033): #1 0x74f5b3f2 in raise () from /home/enrique/buildroot/output2/staging/lib/libpthread.so.0
(gdb) thread 36
Now, from a terminal, send a continuation signal: kill -SIGCONT 1977. Finally instruct gdb to single-step only the current thread (IMPORTANT!) and run some steps until all the raises have been processed:
(gdb) set scheduler-locking on
(gdb) next // Repeat several times...
Know the name of a GStreamer function stored in a pointer at runtime
Just use this macro:
GST_DEBUG_FUNCPTR_NAME(func)
Detecting memory leaks in WebKit
RefCountedLeakCounter is a tool class that can help to debug reference leaks by printing this kind of messages when WebKit exits:
LEAK: 2 XMLHttpRequest
LEAK: 25 CachedResource
LEAK: 3820 WebCoreNode
To use it you have to modify the particular class you want to debug:
Include wtf/RefCountedLeakCounter.h
DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, myClassCounter, ("MyClass"));
In the constructor: myClassCounter.increment()
In the destructor: myClassCounter.decrement()
0 0 [Less]
|
Posted
almost 2 years
ago
by
Enrique Ocaña González
This is the continuation of the GStreamer WebKit debugging tricks post series. In the next three posts, I’ll focus on what we can get by doing some little changes to the source code for debugging purposes (known as “instrumenting”), but before, you
... [More]
might want to check the previous posts of the series:
GStreamer WebKit debugging tricks using GDB (1/2)
GStreamer WebKit debugging tricks using GDB (2/2)
Know all the env vars read by a program by using LD_PRELOAD to intercept libc calls
// File getenv.c
// To compile: gcc -shared -Wall -fPIC -o getenv.so getenv.c -ldl
// To use: export LD_PRELOAD="./getenv.so", then run any program you want
// See http://www.catonmat.net/blog/simple-ld-preload-tutorial-part-2/
#define _GNU_SOURCE
#include
#include
// This function will take the place of the original getenv() in libc
char *getenv(const char *name) {
printf("Calling getenv(\"%s\")\n", name);
char *(*original_getenv)(const char*);
original_getenv = dlsym(RTLD_NEXT, "getenv");
return (*original_getenv)(name);
}
See the breakpoints with command example to know how to get the same using gdb. Check also Zan’s libpine for more features.
Track lifetime of GObjects by LD_PRELOADing gobject-list
The gobject-list project, written by Thibault Saunier, is a simple LD_PRELOAD library for tracking the lifetime of GObjects. When loaded into an application, it prints a list of living GObjects on exiting the application (unless the application crashes), and also prints reference count data when it changes. SIGUSR1 or SIGUSR2 can be sent to the application to trigger printing of more information.
Overriding the behaviour of a debugging macro
The usual debugging macros aren’t printing messages? Redefine them to make what you want:
#undef LOG_MEDIA_MESSAGE
#define LOG_MEDIA_MESSAGE(...) do { \
printf("LOG %s: ", __PRETTY_FUNCTION__); \
printf(__VA_ARGS__); \
printf("\n"); \
fflush(stdout); \
} while(0)
This can be done to enable asserts on demand in WebKit too:
#undef ASSERT
#define ASSERT(assertion) \
(!(assertion) ? \
(WTFReportAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, #assertion), \
CRASH()) : \
(void)0)
#undef ASSERT_NOT_REACHED
#define ASSERT_NOT_REACHED() do { \
WTFReportAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, 0); \
CRASH(); \
} while (0)
It may be interesting to enable WebKit LOG() and GStreamer GST_DEBUG() macros only on selected files:
#define LOG(channel, msg, ...) do { \
printf("%s: ", #channel); \
printf(msg, ## __VA_ARGS__); \
printf("\n"); \
fflush(stdout); \
} while (false)
#define _GST_DEBUG(msg, ...) do { \
printf("### %s: ", __PRETTY_FUNCTION__); \
printf(msg, ## __VA_ARGS__); \
printf("\n"); \
fflush(stdout); \
} while (false)
Note all the preprocessor trickery used here:
First arguments (channel, msg) are captured intependently
The remaining args are captured in __VA_ARGS__
do while(false) is a trick to avoid {braces} and make the code block work when used in if/then/else one-liners
#channel expands LOG(MyChannel,....) as printf("%s: ", "MyChannel"). It’s called “stringification”.
## __VA_ARGS__ expands the variable argument list as a comma-separated list of items, but if the list is empty, it eats the comma after “msg”, preventing syntax errors
Print the compile-time type of an expression
Use typeid().name(). Filter the ouput through c++filt -t:
std::vector v;
printf("Type: %s\n", typeid(v.begin()).name());
Abusing the compiler to know all the places where a function is called
If you want to know all the places from where the GstClockTime toGstClockTime(float time) function is called, you can convert it to a template function and use static_assert on a wrong datatype like this (in the .h):
template GstClockTime toGstClockTime(float time) {
static_assert(std::is_integral::value,
"Don't call toGstClockTime(float)!");
return 0;
}
Note that T=float is different to integer (is_integral). It has nothing to do with the float time parameter declaration.
You will get compile-time errors like this on every place the function is used:
WebKitMediaSourceGStreamer.cpp:474:87: required from here
GStreamerUtilities.h:84:43: error: static assertion failed: Don't call toGstClockTime(float)!
Use pragma message to print values at compile time
Sometimes is useful to know if a particular define is enabled:
#include
#define _STR(x) #x
#define STR(x) _STR(x)
#pragma message "Int max is " STR(INT_MAX)
#ifdef WHATEVER
#pragma message "Compilation goes by here"
#else
#pragma message "Compilation goes by there"
#endif
...
The code above would generate this output:
test.c:6:9: note: #pragma message: Int max is 0x7fffffff
#pragma message "Int max is " STR(INT_MAX)
^~~~~~~
test.c:11:9: note: #pragma message: Compilation goes by there
#pragma message "Compilation goes by there"
^~~~~~~
0 0 [Less]
|
Posted
almost 2 years
ago
by
Enrique Ocaña González
This is the continuation of the GStreamer WebKit debugging tricks post series. In the next three posts, I’ll focus on what we can get by doing some little changes to the source code for debugging purposes (known as “instrumenting”), but before, you
... [More]
might want to check the previous posts of the series:
GStreamer WebKit debugging tricks using GDB (1/2)
GStreamer WebKit debugging tricks using GDB (2/2)
Know all the env vars read by a program by using LD_PRELOAD to intercept libc calls
// File getenv.c
// To compile: gcc -shared -Wall -fPIC -o getenv.so getenv.c -ldl
// To use: export LD_PRELOAD="./getenv.so", then run any program you want
// See http://www.catonmat.net/blog/simple-ld-preload-tutorial-part-2/
#define _GNU_SOURCE
#include
#include
// This function will take the place of the original getenv() in libc
char *getenv(const char *name) {
printf("Calling getenv(\"%s\")\n", name);
char *(*original_getenv)(const char*);
original_getenv = dlsym(RTLD_NEXT, "getenv");
return (*original_getenv)(name);
}
See the breakpoints with command example to know how to get the same using gdb. Check also Zan’s libpine for more features.
Track lifetime of GObjects by LD_PRELOADing gobject-list
The gobject-list project, written by Thibault Saunier, is a simple LD_PRELOAD library for tracking the lifetime of GObjects. When loaded into an application, it prints a list of living GObjects on exiting the application (unless the application crashes), and also prints reference count data when it changes. SIGUSR1 or SIGUSR2 can be sent to the application to trigger printing of more information.
Overriding the behaviour of a debugging macro
The usual debugging macros aren’t printing messages? Redefine them to make what you want:
#undef LOG_MEDIA_MESSAGE
#define LOG_MEDIA_MESSAGE(...) do { \
printf("LOG %s: ", __PRETTY_FUNCTION__); \
printf(__VA_ARGS__); \
printf("\n"); \
fflush(stdout); \
} while(0)
This can be done to enable asserts on demand in WebKit too:
#undef ASSERT
#define ASSERT(assertion) \
(!(assertion) ? \
(WTFReportAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, #assertion), \
CRASH()) : \
(void)0)
#undef ASSERT_NOT_REACHED
#define ASSERT_NOT_REACHED() do { \
WTFReportAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, 0); \
CRASH(); \
} while (0)
It may be interesting to enable WebKit LOG() and GStreamer GST_DEBUG() macros only on selected files:
#define LOG(channel, msg, ...) do { \
printf("%s: ", #channel); \
printf(msg, ## __VA_ARGS__); \
printf("\n"); \
fflush(stdout); \
} while (false)
#define _GST_DEBUG(msg, ...) do { \
printf("### %s: ", __PRETTY_FUNCTION__); \
printf(msg, ## __VA_ARGS__); \
printf("\n"); \
fflush(stdout); \
} while (false)
Note all the preprocessor trickery used here:
First arguments (channel, msg) are captured intependently
The remaining args are captured in __VA_ARGS__
do while(false) is a trick to avoid {braces} and make the code block work when used in if/then/else one-liners
#channel expands LOG(MyChannel,....) as printf("%s: ", "MyChannel"). It’s called “stringification”.
## __VA_ARGS__ expands the variable argument list as a comma-separated list of items, but if the list is empty, it eats the comma after “msg”, preventing syntax errors
Print the compile-time type of an expression
Use typeid().name(). Filter the ouput through c++filt -t:
std::vector v;
printf("Type: %s\n", typeid(v.begin()).name());
Abusing the compiler to know all the places where a function is called
If you want to know all the places from where the GstClockTime toGstClockTime(float time) function is called, you can convert it to a template function and use static_assert on a wrong datatype like this (in the .h):
template GstClockTime toGstClockTime(float time) {
static_assert(std::is_integral::value,
"Don't call toGstClockTime(float)!");
return 0;
}
Note that T=float is different to integer (is_integral). It has nothing to do with the float time parameter declaration.
You will get compile-time errors like this on every place the function is used:
WebKitMediaSourceGStreamer.cpp:474:87: required from here
GStreamerUtilities.h:84:43: error: static assertion failed: Don't call toGstClockTime(float)!
Use pragma message to print values at compile time
Sometimes is useful to know if a particular define is enabled:
#include
#define _STR(x) #x
#define STR(x) _STR(x)
#pragma message "Int max is " STR(INT_MAX)
#ifdef WHATEVER
#pragma message "Compilation goes by here"
#else
#pragma message "Compilation goes by there"
#endif
...
The code above would generate this output:
test.c:6:9: note: #pragma message: Int max is 0x7fffffff
#pragma message "Int max is " STR(INT_MAX)
^~~~~~~
test.c:11:9: note: #pragma message: Compilation goes by there
#pragma message "Compilation goes by there"
^~~~~~~
0 0 [Less]
|