Sirikata
libcore/include/sirikata/core/trace/Trace.hpp
Go to the documentation of this file.
00001 /*  Sirikata
00002  *  Trace.hpp
00003  *
00004  *  Copyright (c) 2009, Ewen Cheslack-Postava
00005  *  All rights reserved.
00006  *
00007  *  Redistribution and use in source and binary forms, with or without
00008  *  modification, are permitted provided that the following conditions are
00009  *  met:
00010  *  * Redistributions of source code must retain the above copyright
00011  *    notice, this list of conditions and the following disclaimer.
00012  *  * Redistributions in binary form must reproduce the above copyright
00013  *    notice, this list of conditions and the following disclaimer in
00014  *    the documentation and/or other materials provided with the
00015  *    distribution.
00016  *  * Neither the name of Sirikata nor the names of its contributors may
00017  *    be used to endorse or promote products derived from this software
00018  *    without specific prior written permission.
00019  *
00020  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
00021  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
00022  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
00023  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
00024  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00025  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00026  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00027  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00028  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00029  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00030  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00031  */
00032 
00033 #ifndef _SIRIKATA_CORE_TRACE_HPP_
00034 #define _SIRIKATA_CORE_TRACE_HPP_
00035 
00036 #include <sirikata/core/util/Platform.hpp>
00037 #include <sirikata/core/util/Thread.hpp>
00038 #include <sirikata/core/util/AtomicTypes.hpp>
00039 #include <sirikata/core/network/ObjectMessage.hpp>
00040 #include <sirikata/core/trace/BatchedBuffer.hpp>
00041 
00042 namespace Sirikata {
00043 namespace Trace {
00044 
00045 #define TRACE_DROP(nam) ((mContext->trace()->drops.n[::Sirikata::Trace::Drops::nam]=#nam )&&++(mContext->trace()->drops.d[::Sirikata::Trace::Drops::nam])); SILOG(drop,insane,#nam)
00046 
00047 struct Drops {
00048     enum {
00049         OH_DROPPED_AT_SEND,
00050         OH_DROPPED_AT_RECEIVE_QUEUE,
00051         SPACE_DROPPED_AT_MAIN_STRAND_CROSSING,
00052         DROPPED_AT_FORWARDED_LOCALLY,
00053         DROPPED_DURING_FORWARDING,
00054         DROPPED_DURING_FORWARDING_ROUTING,
00055         DROPPED_AT_SPACE_ENQUEUED,
00056         DROPPED_CSFQ_OVERFLOW,
00057         DROPPED_CSFQ_PROBABILISTIC,
00058         NUM_DROPS
00059     };
00060     uint64 d[NUM_DROPS];
00061     const char*n[NUM_DROPS];
00062     Drops() {
00063         memset(d,0,NUM_DROPS*sizeof(uint64));
00064         memset(n,0,NUM_DROPS*sizeof(const char*));
00065     }
00066     void output();
00067 };
00068 
00069 #define ProximityTag 0
00070 #define ObjectLocationTag 1
00071 #define ServerDatagramQueuedTag 4
00072 #define ServerDatagramSentTag 5
00073 #define ServerDatagramReceivedTag 6
00074 #define SegmentationChangeTag 10
00075 
00076 #define MigrationBeginTag 11
00077 #define MigrationAckTag 12
00078 #define MigrationRoundTripTag 18
00079 
00080 #define ServerLocationTag 13
00081 #define ServerObjectEventTag 14
00082 #define ObjectSegmentationCraqLookupRequestAnalysisTag 15
00083 #define ObjectSegmentationProcessedRequestAnalysisTag 16
00084 #define ObjectPingTag 17
00085 #define ObjectPingCreatedTag 32
00086 #define ObjectHitPointTag 34
00087 
00088 #define OSegTrackedSetResultAnalysisTag   19
00089 #define OSegShutdownEventTag              20
00090 #define ObjectGeneratedLocationTag 22
00091 #define OSegCacheResponseTag 23
00092 #define OSegLookupNotOnServerAnalysisTag 24
00093 #define OSegCumulativeTraceAnalysisTag   25
00094 #define MessageTimestampTag 30
00095 #define MessageCreationTimestampTag 31
00096 
00097 #define ObjectConnectedTag 33
00098 
00099 enum MessagePath {
00100     NONE, // Used when tag is needed but we don't have a name for it
00101 
00102     // Object Host Checkpoints
00103     CREATED,
00104     DESTROYED,
00105     OH_HIT_NETWORK,
00106     OH_DROPPED_AT_SEND,
00107     OH_NET_RECEIVED,
00108     OH_DROPPED_AT_RECEIVE_QUEUE,
00109     OH_RECEIVED,
00110     SPACE_DROPPED_AT_MAIN_STRAND_CROSSING,
00111     // Space Checkpoints
00112     HANDLE_OBJECT_HOST_MESSAGE,
00113     HANDLE_SPACE_MESSAGE,
00114 
00115     FORWARDED_LOCALLY,
00116     DROPPED_AT_FORWARDED_LOCALLY,
00117 
00118     FORWARDING_STARTED,
00119 
00120     FORWARDED_LOCALLY_SLOW_PATH,
00121 
00122     // FIXME could follow FORWARDED_LOCALLY_SLOW_PATH or OSEG_LOOKUP_STARTED
00123     DROPPED_DURING_FORWARDING,
00124 
00125     OSEG_CACHE_CHECK_STARTED,
00126     OSEG_CACHE_CHECK_FINISHED,
00127 
00128     OSEG_LOOKUP_STARTED,
00129     OSEG_CACHE_LOOKUP_FINISHED,
00130     OSEG_SERVER_LOOKUP_FINISHED,
00131     OSEG_LOOKUP_FINISHED,
00132 
00133     SPACE_TO_SPACE_ENQUEUED,
00134     DROPPED_AT_SPACE_ENQUEUED,
00135 
00136     SPACE_TO_SPACE_HIT_NETWORK,
00137 
00138     SPACE_TO_SPACE_READ_FROM_NET,
00139     SPACE_TO_SPACE_SMR_DEQUEUED,
00140 
00141     SPACE_TO_OH_ENQUEUED,
00142 
00143     NUM_PATHS
00144 };
00145 
00146 class SIRIKATA_EXPORT Trace {
00147 public:
00148     Drops drops;
00149 
00150     ~Trace();
00151 
00152     // Initialize options which flip recording of trace data on and off
00153     static void InitOptions();
00154 
00155     Trace(const String& filename);
00156 
00157 
00158 #define CREATE_TRACE_CHECK_DECL(___name)           \
00159     bool check ## ___name () const;
00160 #define CREATE_TRACE_EVAL_DECL(___name, ...)    \
00161     void ___name( __VA_ARGS__ );
00162 
00163 #define CREATE_TRACE_DECL(___name, ...)         \
00164     CREATE_TRACE_CHECK_DECL(___name)            \
00165     CREATE_TRACE_EVAL_DECL(___name, __VA_ARGS__)
00166 
00167 
00168 
00169 // This macro simplifies creating the methods that check if we should actually
00170 // perform the trace.
00171 #define CREATE_TRACE_CHECK_DEF(__klass, ___name , ___log_var)    \
00172     bool __klass :: check ## ___name () const {          \
00173         return ___log_var->as<bool>();                \
00174     }
00175 
00176 #define CREATE_TRACE_EVAL_DEF(__klass, ___name , ... )   \
00177     void __klass :: ___name ( __VA_ARGS__ )
00178 
00179 // This macro takes care of everything -- just specify the name, the
00180 // OptionValue* to check, argument types, and then follow it with the body.
00181 #define CREATE_TRACE_DEF(__klass, ___name , ___log_var, ... )    \
00182     CREATE_TRACE_CHECK_DEF(__klass, ___name, ___log_var)          \
00183     CREATE_TRACE_EVAL_DEF(__klass, ___name, __VA_ARGS__)
00184 
00185 
00186     CREATE_TRACE_DECL(timestampMessageCreation, const Time&t, uint64 packetId, MessagePath path, ObjectMessagePort optionalMessageSourcePort=0, ObjectMessagePort optionalMessageDestPort=0);
00187     CREATE_TRACE_DECL(timestampMessage, const Time&t, uint64 packetId, MessagePath path);
00188 
00189 
00190     // Helper to prepend framing (size and payload type hint)
00191     void writeRecord(uint16 type_hint, BatchedBuffer::IOVec* data, uint32 iovcnt);
00192 
00193     // Helper to prepend framing (size and payload type hint)
00194     template<typename T>
00195     void writeRecord(uint16 type_hint, const T& pl) {
00196         if (mShuttingDown) return;
00197 
00198         std::string serialized_pl;
00199         bool serialized_success = pl.SerializeToString(&serialized_pl);
00200         assert(serialized_success);
00201 
00202         const uint32 num_data = 1;
00203         BatchedBuffer::IOVec data_vec[num_data] = {
00204             BatchedBuffer::IOVec(&(serialized_pl[0]), serialized_pl.size())
00205         };
00206         writeRecord(type_hint, data_vec, num_data);
00207     }
00208 
00209 
00210 public:
00211 
00212   void prepareShutdown();
00213   void shutdown();
00214 
00215 private:
00216     // Thread which flushes data to disk periodically
00217     void storageThread(const String& filename);
00218 
00219     BatchedBuffer data;
00220     bool mShuttingDown;
00221 
00222     Thread* mStorageThread;
00223     Sirikata::AtomicValue<bool> mFinishStorage;
00224 
00225     // OptionValues that turn tracing on/off
00226     static OptionValue* mLogMessage;
00227 }; // class Trace
00228 
00229 } // namespace Trace
00230 
00231 // This is how you should *actually*
00232 #define TRACE(___trace, ___name, ...)            \
00233     {                                            \
00234         if ( ___trace-> check ## ___name () )    \
00235             ___trace-> ___name ( __VA_ARGS__ );  \
00236     } while(0)
00237 // To check that you aren't using tracing via the incorrect interface (that is,
00238 // directly instead of via macros) uncomment the following and mark the DECL's
00239 // in Trace as private.
00240 //#undef TRACE
00241 //#define TRACE(___trace, ___name, ...)
00242 
00243 // This version of the TRACE macro automatically uses mContext->trace() and
00244 // passes mContext->simTime() as the first argument, which is the most common
00245 // form.
00246 #define CONTEXT_TRACE(___name, ...)                 \
00247     TRACE( mContext->trace(), ___name, mContext->simTime(), __VA_ARGS__)
00248 
00249 // This version is like the above, but you can specify the time yourself.  Use
00250 // this if you already called Context::simTime() recently. (It also works for
00251 // cases where the first parameter is not the current time.)
00252 #define CONTEXT_TRACE_NO_TIME(___name, ...)             \
00253     TRACE( mContext->trace(), ___name, __VA_ARGS__)
00254 
00255 } // namespace Sirikata
00256 
00257 
00258 
00259 
00260 #ifdef CBR_TIMESTAMP_PACKETS
00261 // The most complete macro, allows you to specify everything
00262 #define TIMESTAMP_FULL(trace, time, packetId, path) TRACE(trace, timestampMessage, time, packetId, path)
00263 
00264 // Slightly simplified version, works everywhere mContext->trace() and mContext->simTime() are valid
00265 #define TIMESTAMP_SIMPLE(packetId, path) TIMESTAMP_FULL(mContext->trace(), mContext->simTime(), packetId, path)
00266 
00267 // Further simplified version, works as long as packet is a valid pointer to a packet at the time this is called
00268 #define TIMESTAMP(packet, path) TIMESTAMP_SIMPLE(packet->unique(), path)
00269 
00270 // In cases where you need to split the time between recording the info for a timestamp and actually performing
00271 // the timestamp, use a _START _END combination. Generally this should only be needed if you are timestamping
00272 // after a message might be deleted or is out of your control (e.g. you pushed onto a queue or destroyed it).
00273 #define TIMESTAMP_START(prefix, packet)                                 \
00274     Sirikata::uint64 prefix ## _uniq = packet->unique();
00275 
00276 #define TIMESTAMP_END(prefix, path) TIMESTAMP_SIMPLE(prefix ## _uniq, path)
00277 
00278 // When the message has been wrapped in a space node -> space node message, we
00279 // need to use a special form, using the payload_id recorded in that message's
00280 // header
00281 #define TIMESTAMP_PAYLOAD(packet, path) TIMESTAMP_SIMPLE(packet->payload_id(), path)
00282 
00283 #define TIMESTAMP_PAYLOAD_START(prefix, packet)                                 \
00284     Sirikata::uint64 prefix ## _uniq = packet->payload_id();
00285 
00286 #define TIMESTAMP_PAYLOAD_END(prefix, path) TIMESTAMP_SIMPLE(prefix ## _uniq, path)
00287 
00288 
00289 #define TIMESTAMP_CREATED(packet, path) TRACE(mContext->trace(), timestampMessageCreation, mContext->simTime(), packet->unique(), path, packet->source_port(), packet->dest_port())
00290 
00291 #else //CBR_TIMESTAMP_PACKETS
00292 #define TIMESTAMP_FULL(trace, time, packetId, path)
00293 #define TIMESTAMP_SIMPLE(packetId, path)
00294 #define TIMESTAMP(packet, path)
00295 #define TIMESTAMP_START(prefix, packet)
00296 #define TIMESTAMP_END(prefix, path)
00297 #define TIMESTAMP_PAYLOAD(packet, path)
00298 #define TIMESTAMP_PAYLOAD_START(prefix, packet)
00299 #define TIMESTAMP_PAYLOAD_END(prefix, path)
00300 #define TIMESTAMP_CREATED(packet, path)
00301 #endif //CBR_TIMESTAMP_PACKETS
00302 
00303 #endif //_SIRIKATA_STATISTICS_HPP_