1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
32
33
34 35 36
37 import xdc.runtime.ILogger;
38 import ti.uia.runtime.ILoggerSnapshot;
39 import xdc.rov.ViewInfo;
40 import xdc.runtime.Log;
41 import xdc.runtime.Diags;
42 import xdc.runtime.Types;
43 import xdc.runtime.Log;
44 import xdc.runtime.Error;
45
46 /*!
47 * ======== LoggerStreamer ========
48 * This general purpose logger is useful in situations where the application
49 * wants to manage the buffers used to store and transmit events. This
50 * includes managing the sending of the buffers to an instrumentation host
51 * (e.g. System Analyzer in CCS). The logger is named "LoggerStreamer"
52 * because it is designed to enable the application to send a stream of
53 * packets containing UIA event data to the instrumentation host.
54 *
55 * The application is responsible for providing the buffers that
56 * LoggerStreamer uses. There are two ways to accomplish this.
57 * @p(blist)
58 * - Provide a prime callback function via the `{@link #primeFxn}`
59 * configuration parameter.
60 * - Call the `{@link #prime}` API once.
61 * @p
62 *
63 * The logger stores the events in a UIAPacket event packet structure that
64 * allows them to be sent directly to System Analyzer (e.g. via UDP), enabling
65 * efficient streaming of the data from the target to the host. The first
66 * four 32-bit words contain a `{@link UIAPacket#Hdr}` structure. This struct
67 * is used by the host (e.g. System Analyzer in CCS) to help decode the
68 * data (e.g. endianess, length of data, etc.). The `{@link UIAPacket#Hdr}`
69 * structure is initialized via the `{@link #initBuffer}` API. All buffers
70 * given to LoggerStreamer (via priming or exchange) must be initialized via
71 * `{@link #initBuffer}`.
72 *
73 * The size of buffer -*- includes UIAPacket_Hdr?
74 * LoggerStreamer treats the buffer as a UInt32 array. So the application
75 * must guarantee the buffers are aligned on word addresses. Alignment on
76 * cache line boundaries is recommended for best performance.
77 *
78 * When the buffer is filled, LoggerStreamer will hand it off to the
79 * application using an application-provided exchange function (`{@link #exchangeFxn}`).
80 * The exchange function must be of type `{@link #ExchangeFxnType}`.
81 * The exchange function is called in the context of a log
82 * so generally the exchange function should be quick to execute.
83 *
84 * The exchange function is called within the context of a Log call, so the
85 * exchange function should be designed to be fast. Since the exchange
86 * function is called within the context of the Log call, LoggerStreamer
87 * guarantees no Log records are dropped (i.e. LoggerStreamer is lossless).
88 *
89 * LoggerStreamer was designed to have as minimal impact as possible on an
90 * application when calling a Log function. There are several configuration
91 * parameters that allow an application to get the optimal performance in
92 * exchange for certain restrictions.
93 *
94 * Interrupts are disabled during the duration of the log call including
95 * when the exchange function is called. LoggerStreamer will ignore any
96 * log events generated during the exchangeFxn (e.g. posting a semaphore).
97 *
98 * @a(Examples)
99 * The following XDC configuration statements
100 * create a logger module, and assign it as the default logger for all
101 * modules.
102 *
103 * @p(code)
104 * var Defaults = xdc.useModule('xdc.runtime.Defaults');
105 * var Diags = xdc.useModule('xdc.runtime.Diags');
106 * var LoggerStreamer = xdc.useModule('ti.uia.sysbios.LoggerStreamer');
107 *
108 * LoggerStreamer.bufSize = 1024;
109 * LoggerStreamer.isTimestampEnabled = true;
110 * LoggerStreamer.primeFxn = '&prime';
111 * LoggerStreamer.exchangeFxn = '&exchange';
112 * Defaults.common$.logger = LoggerStreamer.create();
113 * @p
114 *
115 * @a(Examples)
116 * The following C code demonstrates a basic prime and exchange example.
117 * A real implementation would send the buffer to an instrumentation
118 * host (e.g. System Analyzer in CCS) via a transport such as UDP.
119 *
120 * @p(code)
121 * UInt32 buffer[2][BUFSIZE];
122
123 * Ptr prime()
124 * {
125 * LoggerStreamer_initBuffer(buffer[0], 0);
126 * LoggerStreamer_initBuffer(buffer[1], 0);
127 * return ((Ptr)(buffer[0]));
128 * }
129 *
130 * Ptr exchange(Ptr *full)
131 * {
132 * count++;
133 * // Ping-pong between the two buffers
134 * return ((Ptr*)buffer[count & 1]);
135 * }
136 * @p
137 */
138
139 @ModuleStartup
140 @Template("./LoggerStreamer.xdt")
141 @CustomHeader
142 module LoggerStreamer inherits ILoggerSnapshot {
143
144 /*!
145 * ======== TransportType ========
146 * Used to specify the type of transport to use
147 *
148 * This enum is used by the instrumentation host to determine what
149 * the transport is. It is not used by the target code.
150 */
151 enum TransportType {
152 TransportType_UART = 0,
153 TransportType_USB = 1,
154 TransportType_ETHERNET = 2,
155 TransportType_CUSTOM = 3
156 };
157
158 /*!
159 * @_nodoc
160 * ======== ModuleView ========
161 */
162 metaonly struct ModuleView {
163 Bool isEnabled;
164 Bool isTimestampEnabled;
165 Int bufferSize;
166 String primeFunc;
167 String exchangeFunc;
168 String transportType;
169 String customTransport;
170 }
171
172 metaonly struct RecordView {
173 Int sequence;
174 Long timestampRaw;
175 String modName;
176 String text;
177 Int eventId;
178 String eventName;
179 IArg arg0;
180 IArg arg1;
181 IArg arg2;
182 IArg arg3;
183 IArg arg4;
184 IArg arg5;
185 IArg arg6;
186 IArg arg7;
187 }
188
189 /*!
190 * @_nodoc
191 * ======== rovViewInfo ========
192 */
193 @Facet
194 metaonly config ViewInfo.Instance rovViewInfo =
195 ViewInfo.create({
196 viewMap: [
197 ['Module',
198 {
199 type: ViewInfo.MODULE,
200 viewInitFxn: 'viewInitModule',
201 structName: 'ModuleView'
202 }
203 ],
204 ['Records',
205 {
206 type: xdc.rov.ViewInfo.MODULE_DATA,
207 viewInitFxn: 'viewInitRecords',
208 structName: 'RecordView'
209 }
210 ]
211 ]
212 });
213
214 /*!
215 * ======== initBuffer ========
216 * Initializes the UIA packet header.
217 *
218 * This API is used to initialize a buffer before it is given to
219 * LoggerStreamer (via priming or exchange). The function initializes
220 * the UIAPacket portion of the buffer.
221 *
222 * @param(buffer) Pointer to the buffer that LoggerStreamer will
223 * fill with Log events. The first four 32-bit words
224 * will contain the UIAPacket_Hdr structure.
225 *
226 * @param(src) Used to initialize the UIA source address. For
227 * a single core device, this will generally be 0.
228 * For multi-core devices, it generally corresponds
229 * to the DNUM (on C6xxxx deviecs) or the Ipc
230 * MultiProc id. It must be unique for all cores and
231 * match the configuration in the System Analyzer
232 * endpoint configuration.
233 */
234 @Macro Void initBuffer(Ptr buffer, UInt16 src);
235
236 /*!
237 * ======== flush ========
238 * Force LoggerStreamer to call the exchange function
239 *
240 * This API makes LoggerStreamer call the application provided
241 * `{@link #exchangeFxn}` function if there are Log events present
242 * in the buffer.
243 *
244 * The call to the `{@link #exchangeFxn}` function is called in the
245 * context of the flush call.
246 */
247 Void flush();
248
249 /*!
250 * ======== prime =========
251 * If PrimeFxn is not set the user must call prime with the first buffer.
252 */
253 Bool prime(Ptr buffer);
254
255 /*!
256 * ======== ExchangeFxnType ========
257 * Typedef for the exchange function pointer.
258 */
259 typedef Ptr (*ExchangeFxnType)(Ptr);
260
261 /*!
262 * ======== PrimeFxnType ========
263 * Typedef for the exchange function pointer.
264 */
265 typedef Ptr (*PrimeFxnType)(Void);
266
267 /*!
268 * ======== bufSize ========
269 * LoggerStreamer buffer size in MAUs (Minimum Addressable Units e.g.
270 * Bytes)
271 *
272 * NOTE: the buffer size must contain an integer number of 32b words
273 * (e.g. if a MAU = 1 byte, then the buffer size must be a multiple of 4).
274 * The buffer size must also be at least maxEventSize + 64.
275 */
276 config SizeT bufSize = 1400;
277
278 /*!
279 * ======== transportType ========
280 * Transport used to send the records to an instrumentation host
281 *
282 * This parameter is used to specify the transport that the
283 * `{@link #exchangeFxn}` function will use to send the buffer to
284 * an instrumentation host (e.g. System Analyzer in CCS).
285 *
286 * This parameter is placed into the generated UIA XML file. The
287 * instrumentation host can use the XML file to help it auto-detect as
288 * much as possible and act accordingly.
289 *
290 * If the desired transport is not in the `{@link #TransportType}` enum,
291 * select `{@link #TransportType_CUSTOM}` and set the
292 * `{@link #customTransportType}` string with the desired string.
293 */
294 metaonly config TransportType transportType = TransportType_ETHERNET;
295
296 /*!
297 * ======== customTransportType ========
298 * Custom transport used to send the records to an instrumentation host
299 *
300 * If the desired transport is not in the `{@link #TransportType}` enum,
301 * and `{@link #transportType}` is set to `{@link #TransportType_CUSTOM}`,
302 * this parameter must be filled in with the correct transport name.
303 *
304 * If `{@link #transportType}` is NOT set to
305 * `{@link #TransportType_CUSTOM}`, this parameter is ignored.
306 */
307 config String customTransportType = null;
308
309 /*!
310 * ======== isTimestampEnabled ========
311 * Enable or disable logging the 64b local CPU timestamp
312 * at the start of each event
313 *
314 * Having a timestamp allows an instrumentation host (e.g.
315 * System Analyzer) to display events with the correct system time.
316 */
317 config Bool isTimestampEnabled = false;
318
319 /*!
320 * @_nodoc
321 * ======== isBadPacketDetectionEnabled ========
322 * Enable or disable checking that the event contents in the packet are
323 * properly formatted with no data errors
324 *
325 * If enabled, a breakpoint can be placed in the code to detect when
326 * a bad packet is found.
327 */
328 config Bool isBadPacketDetectionEnabled = false;
329 /*!
330 * ======== supportLoggerDisable ========
331 * Allow LoggerStreamer to be enabled/disabled during runtime.
332 */
333 config Bool supportLoggerDisable = false;
334
335 /*!
336 * ======== testForNullWrPtr ========
337 * Protect against log calls during the exchange function.
338 */
339 config Bool testForNullWrPtr = true;
340
341 /*!
342 * ======== primeFxn ========
343 * Function pointer to the prime function.
344 */
345 config PrimeFxnType primeFxn = null;
346
347 /*!
348 * ======== exchangeFxn ========
349 * Function pointer to the exchange function.
350 *
351 * exchange function must return a pointer to a buffer that is word
352 * aligned, initialized with a UIA header and the correct size. This is
353 * called in the context of a log so generally the exchange function
354 * should be quick to execute.
355 */
356 config ExchangeFxnType exchangeFxn = null;
357
358
359 /*!
360 * ======== statusLogger ========
361 * This configuration option is not supported by this logger and should
362 * be left null.
363 */
364 config xdc.runtime.IFilterLogger.Handle statusLogger = null;
365
366 /*!
367 * ======== level1Mask ========
368 * Mask of diags categories whose initial filtering level is Diags.LEVEL1
369 *
370 * See '{@link #level4Mask}' for details.
371 */
372 config Diags.Mask level1Mask = 0;
373
374 /*!
375 * ======== level2Mask ========
376 * Mask of diags categories whose initial filtering level is Diags.LEVEL2
377 *
378 * See '{@link #level4Mask}' for details.
379 */
380 config Diags.Mask level2Mask = 0;
381
382 /*!
383 * ======== level3Mask ========
384 * Mask of diags categories whose initial filtering level is Diags.LEVEL3
385 *
386 * See '{@link #level4Mask}' for details.
387 */
388 config Diags.Mask level3Mask = 0;
389
390 /*!
391 * ======== level4Mask ========
392 * Mask of diags categories whose initial filtering level is Diags.LEVEL4
393 *
394 * If 'filterByLevel' is true, then all LoggerBuf instances will filter
395 * incoming events based on their event level.
396 *
397 * The LoggerCircBuf module allows for specifying a different filter level
398 * for every Diags bit. These filtering levels are module wide; LoggerBuf
399 * does not support specifying the levels on a per-instance basis.
400 *
401 * The setFilterLevel API can be used to change the filtering levels at
402 * runtime.
403 *
404 * The default filtering levels are assigned using the 'level1Mask' -
405 * 'level4Mask' config parameters. These are used to specify, for each of
406 * the four event levels, the set of bits which should filter at that
407 * level by default.
408 *
409 * The default filtering configuration sets the filter level to
410 * Diags.LEVEL4 for all logging-related diags bits so that all events are
411 * logged by default.
412 */
413 config Diags.Mask level4Mask = Diags.ALL_LOGGING;
414
415 /*!
416 * ======== moduleToRouteToStatusLogger ========
417 * This configuration option is not supported by this logger and should
418 * be left unconfigured.
419 */
420 metaonly config String moduleToRouteToStatusLogger;
421
422 /*!
423 * ======== setModuleIdToRouteToStatusLogger ========
424 * This function is provided for compatibility with the ILoggerSnapshot
425 * interface only and simply returns when called.
426 */
427 @DirectCall
428 Void setModuleIdToRouteToStatusLogger(Types.ModuleId mid);
429
430 /*!
431 * @_nodoc
432 * ======== L_test ========
433 * Event used to benchmark write0.
434 */
435 config xdc.runtime.Log.Event L_test = {
436 mask: xdc.runtime.Diags.USER1,
437 msg: "Test"
438 };
439
440 /*!
441 * @_nodoc
442 * ======== E_badLevel ========
443 * Error raised if get or setFilterLevel receive a bad level value
444 */
445 config Error.Id E_badLevel = {
446 msg: "E_badLevel: Bad filter level value: %d"
447 };
448
449 /*!
450 * ======== maxEventSize ========
451 * The maximum event size (in Maus) that can be written with a single
452 * event. Must be less than or equal to bufSize - 64.
453 *
454 * The writeMemoryRange API checks to see if the event size required to
455 * write the block of memory is larger than maxEventSize. If so, it will
456 * split the memory range up into a number of smaller blocks and log the
457 * blocks using separate events with a common snapshot ID in order to
458 * allow the events to be collated and the original memory block to be
459 * reconstructed on the host.
460 */
461 config SizeT maxEventSize = 512;
462
463 /*!
464 * @_nodoc
465 * ======== validatePacket ========
466 * if isBadPacketDetectionEnabled is configured as true, this function is
467 * called prior to the exchange function being called.
468 *
469 * Returns null if the packet is ok, else returns the address of a string
470 * that describes the error.
471 */
472 @DirectCall
473 Char* validatePacket(UInt32 *writePtr, UInt32 numBytesInPacket);
474
475 instance:
476
477 /*!
478 * ======== create ========
479 * Create a `LoggerStreamer` logger
480 */
481 create();
482
483 /*!
484 * ======== write0 ========
485 * Process a log event with 0 arguments and the calling address.
486 *
487 * Same as `write4` except with 0 arguments rather than 4.
488 * @see #write4()
489 */
490 @DirectCall
491 override Void write0(xdc.runtime.Log.Event evt,
492 xdc.runtime.Types.ModuleId mid);
493
494 /*!
495 * ======== write1 ========
496 * Process a log event with 1 arguments and the calling address.
497 *
498 * Same as `write4` except with 1 arguments rather than 4.
499 * @see #write4()
500 */
501 @DirectCall
502 override Void write1(xdc.runtime.Log.Event evt,
503 xdc.runtime.Types.ModuleId mid,
504 IArg a1);
505
506 /*!
507 * ======== write2 ========
508 * Process a log event with 2 arguments and the calling address.
509 *
510 * Same as `write4` except with 2 arguments rather than 4.
511 * @see #write4()
512 */
513 @DirectCall
514 override Void write2(xdc.runtime.Log.Event evt,
515 xdc.runtime.Types.ModuleId mid,
516 IArg a1, IArg a2);
517
518 /*!
519 * ======== write4 ========
520 * Process a log event with 4 arguments and the calling address.
521 *
522 * @see ILogger#write4()
523 */@DirectCall
524 override Void write4(xdc.runtime.Log.Event evt,
525 xdc.runtime.Types.ModuleId mid,
526 IArg a1, IArg a2, IArg a3, IArg a4);
527
528 /*!
529 * ======== write8 ========
530 * Process a log event with 8 arguments and the calling address.
531 *
532 * Same as `write4` except with 8 arguments rather than 4.
533 *
534 * @see #write4()
535 */
536 @DirectCall
537 override Void write8(xdc.runtime.Log.Event evt,
538 xdc.runtime.Types.ModuleId mid,
539 IArg a1, IArg a2, IArg a3, IArg a4,
540 IArg a5, IArg a6, IArg a7, IArg a8);
541
542 /*!
543 * ======== setFilterLevel ========
544 * Sets the level of detail that instances will log.
545 *
546 * Events with the specified level or higher will be logged, events
547 * below the specified level will be dropped.
548 *
549 * Events are filtered first by diags category, then by level. If an
550 * event's diags category is disabled in the module's diags mask, then it
551 * will be filtered out regardless of level. The event will not even be
552 * passed to the logger.
553 *
554 * This API allows for setting the filtering level for more than one
555 * diags category at a time. The mask parameter can be a single category
556 * or multiple categories combined, and the level will be set for all of
557 * those categories.
558 *
559 * @param(mask) The diags categories to set the level for
560 * @param(filterLevel) The new filtering level for the specified
561 * categories
562 */
563 @DirectCall
564 override Void setFilterLevel(Diags.Mask mask, Diags.EventLevel filterLevel);
565
566 /*!
567 * ======== getFilterLevel ========
568 * Returns the mask of diags categories currently set to the specified
569 * level.
570 *
571 * See '{@link #setFilterLevel}' for an explanation of level filtering.
572 */
573 @DirectCall
574 override Diags.Mask getFilterLevel(Diags.EventLevel level);
575
576
577
578 internal:
579
580
581 const Int WRITE0_SIZE_IN_BYTES = 8;
582 const Int WRITE1_SIZE_IN_BYTES = 12;
583 const Int WRITE2_SIZE_IN_BYTES = 16;
584 const Int WRITE4_SIZE_IN_BYTES = 24;
585 const Int WRITE8_SIZE_IN_BYTES = 40;
586
587 const Int TIMESTAMP = 8;
588 const Int NO_TIMESTAMP = 0;
589
590 /*!
591 * ======== filterOutEvent ========
592 */
593 @DirectCall
594 Bool filterOutEvent(Diags.Mask mask);
595
596 597 598 599
600 struct Module_State {
601 Bool enabled;
602 UInt32 *buffer;
603 UInt32 *write;
604 UInt32 *end;
605 Diags.Mask level1;
606 Diags.Mask level2;
607 Diags.Mask level3;
608 Types.ModuleId moduleIdToRouteToStatusLogger;
609 SizeT maxEventSizeInBits32;
610
611 612 613 614
615 Int droppedEvents;
616 };
617
618 struct Instance_State {
619 };
620 }