![]() |
Home | Libraries | People | FAQ | More |
|
WARNING : PRE-RELEASE VERSION,
NOT OFFICIAL BOOST LIBRARY!!!! StackTrack is not an official Boost library. It has not been submitted for review as a potential Boost library, although the current intention is to seek review after a stable release with significant positive experience in the Boost community. |
The data which StackTrack captures is typically stored in a raw binary form, to be analyzed later using postprocessing utilities. While there are a variety of ways such utilities can be configured, and it is quite possible to create new utilities to fit particular tastes and local requirements, most will share some common attributes.
Stacktrack stores data as a sequence of fixed size binary buffers, instances of boost::stacktrack::raw_event. The format of these buffers is defined in boost/stacktrack/event.hpp. Each buffer contains
flags_t _entryFlags; ///< combination of FLAGS used to interpret payload
st_pid_t _pid; ///< process ID
sequence_t _sequence; ///< sequence number
payload_t payload; ///< here's the beef
where payload_t is a discriminated union, selected on buffer._entryFlags & boost::stacktrack::raw_event::TYPE_MASK.
Most buffers make reference to additional context defined by earlier buffer entries. Full processing requires collecting and maintaining this context in order to interpret later buffers. All such context is considered local to a specific process, identified by buffer._pid. It is also expected that for a given pid, buffers will be read and processed in the same order in which they were originally captured.
All buffers carry a sequence count in buffer._sequence. There are a few payload types (PROLOGUE, TIMETYPE, and TIMEINFO) which are not associated with a specific checkpoint, and should always have a sequence number of zero. All other buffers are created as StackTrack passes a specific checkpoint. They will be marked with the value of the sequence count at the time the checkpoint was entered. It is possible for one checkpoint entry to generate multiple buffers, in which case they will share the same sequence number. Comparing sequence counts is the most reliable way to correlate the timing of checkpoints on different threads within a process.
Time is stored in the type boost::stacktrack::detail::raw_hitime_t, which is an opaque, platform specific format. Stacktrack typically will store time values as directly as possible, with no conversions or adjustment. In order to make convenient use of time values, three things may need to happen in postprocessing:
| Conversion Step | Description |
|---|---|
| numeric | convert from "raw binary" value to numeric form (typically double) |
| normalize | apply scale factor to numeric value to common unit (typically seconds) |
| offset | apply offset to align normalized value with actual date/time |
The actual steps vary based on the specifics of the platform's boost::stacktrack::detail::raw_hitime_t implementation. However, there are two payload types which may be used to attempt dynamic interpretation of time values. TIMETYPE provides the divisor used to convert from the numeric form to seconds. TIMEINFO provides a relative raw time value and the corresponding ctime value (seconds since epoch as long), which can establish the necessary offset (+/- 1 second)
Some payloads contain a writeCount member. The write count is used to determine when the output for a given checkpoint needs to include additional context (such as the checkpoint's SOURCELOC). Typically this only occurs the first time a checkpoint is output, and further hits on that checkpoint expect the postprocessing to maintain the context. However, this does pose some difficulties for use cases in which the entire set of buffers since the process started may not be available. To address this issue, when a StackTrack monitored application calls boost::stacktrack::sink_control::next_cycle(), the internal write count is incremented, which will cause each checkpoint to repost the additional context the next time it is encountered. Complete interpretation of buffers is therefore possible as long as there is a full record of buffers since the last cycle increment.
Some payload types may need to record additional information whose size is not known until runtime. Stacktrack accomplishes this by converting such information to a series of INFO buffers following the original buffer (all with the same sequence count). If a buffer has INFO buffers following, buffer._entryFlags & boost::stacktrack::HAS_INFO will be true, and the buffer will be followed by a series of INFO buffers, with buffer._entryFlags & boost::stacktrack::INFO_END true for the last buffer. The INFO buffers should always be in order, but other buffers (with a different sequence count) may be interleaved with the series of INFO buffers.
The various payload formats are defined as follows:
/*BOOST_STACKTRACK_EVT_TYPE( TAG, name, description of type, */ \ /* BOOST_STACKTRACK_EVT_FLD( type, name, description of member */ \ /*) */ \ BOOST_STACKTRACK_EVT_TYPE( HIT, hit, ev_hit captures basic entry/exit/step data, \ BOOST_STACKTRACK_EVT_FLD( hitime_t, when, when the hit occured ) \ BOOST_STACKTRACK_EVT_FLD( scopex_t, scopeIndex, where the hit occured) \ BOOST_STACKTRACK_EVT_FLD( st_tid_t, tid, thread in which the hit occured ) \ ) \ BOOST_STACKTRACK_EVT_TYPEI( FLOC, fileloc, File Location data, filename, \ BOOST_STACKTRACK_EVT_FLD( int16, filenum, file index) \ BOOST_STACKTRACK_EVT_FLD( wcount_t, writeCount, write count) \ BOOST_STACKTRACK_EVT_FLD( int16, properties, number of properties) \ ) \ BOOST_STACKTRACK_EVT_TYPEI( FPROPERTY, fproperty, file properties, prop=value, \ BOOST_STACKTRACK_EVT_FLD( int16, filenum, file index ) \ BOOST_STACKTRACK_EVT_FLD( wcount_t, writeCount, write count ) \ BOOST_STACKTRACK_EVT_FLD( int16, propertynum, property index ) \ ) \ BOOST_STACKTRACK_EVT_TYPE( SLOC, sourceloc, source location, \ BOOST_STACKTRACK_EVT_FLD( scopex_t, scopeIndex, scope index ) \ BOOST_STACKTRACK_EVT_FLD( int16, style, scope style ) \ BOOST_STACKTRACK_EVT_FLD( int16, linenum, line number ) \ BOOST_STACKTRACK_EVT_FLD( wcount_t, writeCount, write count ) \ BOOST_STACKTRACK_EVT_FLD( int16, filenum, file number ) \ ) \ BOOST_STACKTRACK_EVT_TYPE( PROLOGUE, prologue, Prologue data, \ BOOST_STACKTRACK_EVT_FLD( uns32, _12345678, magic identifier ) \ BOOST_STACKTRACK_EVT_FLD( uns32, version, stacktrack format version ) \ BOOST_STACKTRACK_EVT_FLD( char, info_len, length of _info field ) \ BOOST_STACKTRACK_EVT_FLD( char, entry_size, size of entry ) \ BOOST_STACKTRACK_EVT_FLD( char, payload_offset, offset of payload in entry ) \ ) \ BOOST_STACKTRACK_EVT_TYPE( PROCINFO, procinfo, Process data, \ BOOST_STACKTRACK_EVT_FLD( st_pid_t, pid, proccess ID ) \ BOOST_STACKTRACK_EVT_FLD( wcount_t, writeCount, write count ) \ ) \ BOOST_STACKTRACK_EVT_TYPE( TIMEINFO, timeinfo, Time info (start time) data, \ BOOST_STACKTRACK_EVT_FLD( hitime_t, start_hires, start time in raw hi-res form ) \ BOOST_STACKTRACK_EVT_FLD( sctime_t, start, start time in CTIME form ) \ ) \ BOOST_STACKTRACK_EVT_TYPE( TIMETYPE, timetype, time conversion data, \ BOOST_STACKTRACK_EVT_FLD( hitime_t, tdiv, time divisor ) \ BOOST_STACKTRACK_EVT_FLD( uns16, timetype, time type ) \ ) \
In the StackTrack examples directory, there is a utility program called expand_events. expand_events can read raw StackTrack buffers from a file and expand their contents for output in XML format. By default, it will decode the binary data and convert all times to a double in seconds relative to the point at which StackTrack was initialized. For example,
T:\boost\boost_1_32_0\libs\stacktrack\example\test>expand_events.exe bar_20050325_082105_060C_1.tlg <PROLOGUE flags="0x4000" pid="0x60c0" seq="0" _12345678="305419896" version="256" info_len="16" entry_size="24" payload_offset="8"/> <PROCINFO flags="0x5000" pid="0x60c0" seq="0" pid="0x060c" writeCount="1"/> <TIMETYPE flags="0x7000" pid="0x60c0" seq="0" tdiv="1.000000" timetype="0x0020"/> <TIMEINFO flags="0x6000" pid="0x60c0" seq="0" start_hires="0.000000" start="1111756865"/> <FLOC flags="0x1010" pid="0x60c0" seq="1" filenum="2" writeCount="0" properties="0"/> <INFO flags="0x00ff" pid="0x060c" seq="1" text="..\..\..\libs\st"/> <INFO flags="0x00ff" pid="0x060c" seq="1" text="acktrack\src\fil"/> <INFO flags="0x02ff" pid="0x060c" seq="1" text="esink.cpp"/> <SLOC flags="0x1030" pid="0x60c0" seq="1" scopeIndex="1" style="3" linenum="98" writeCount="0" filenum="2"/> <INFO flags="0x00ff" pid="0x060c" seq="1" text="file_sink_impl::"/> <INFO flags="0x02ff" pid="0x060c" seq="1" text="open"/> <HIT flags="0x0000" pid="0x60c0" seq="1" when="0.000640" scopeIndex="1" tid="0x04c8"/> <SLOC flags="0x1030" pid="0x60c0" seq="2" scopeIndex="2" style="6" linenum="99" writeCount="0" filenum="2"/> <INFO flags="0x02ff" pid="0x060c" seq="2" text="name"/> <HIT flags="0x1000" pid="0x60c0" seq="2" when="0.000685" scopeIndex="2" tid="0x04c8"/> <INFO flags="0x02ff" pid="0x060c" seq="2" text="bar"/> ...
expand_events can also provide a report on the internal format of a raw_event using the --show_format option:
T:\boost\boost_1_32_0\libs\stacktrack\example\test>expand_events.exe --show_format <RAW_FORMAT version="100" size="24" payload_size="16" payload_offset="8" magic="0x12345678" magic_raw="0x78563412"> <TYPE uname="HIT" name="hit" typeindex="0" type="ev_hit" size="16" followedby="~" desc="ev_hit captures basic entry/exit/step data"> <MEMBER name="when" type="hitime_t" size="8" offset="0" desc="when the hit occured"/> <MEMBER name="scopeIndex" type="scopex_t" size="2" offset="8" desc="where the hit occured"/> <MEMBER name="tid" type="st_tid_t" size="2" offset="10" desc="thread in which the hit occured"/> </TYPE> <TYPE uname="FLOC" name="fileloc" typeindex="1" type="ev_fileloc" size="6" followedby="filename" desc="File Location data"> <MEMBER name="filenum" type="int16" size="2" offset="0" desc="file index"/> <MEMBER name="writeCount" type="wcount_t" size="2" offset="2" desc="write count"/> <MEMBER name="properties" type="int16" size="2" offset="4" desc="number of properties"/> </TYPE> ... <FLAG name="IS_HIT" value="0x0000"/> <FLAG name="IS_FLOC" value="0x0001"/> ... </RAW_FORMAT>
The RAW_FORMAT output should provide enough detail to create a utility which can process Stacktrack binary buffers from any platform when that platform's RAW_FORMAT information is available.
| Copyright © 2005 James Fowler |