414d3ebbda8e34c9d02229f1dbe0b19b19503d54
[lttv.git] / lttv / lttv / sync / event_processing_lttng_standard.c
1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2009 Benjamin Poirier <benjamin.poirier@polymtl.ca>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License Version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
16 * MA 02111-1307, USA.
17 */
18
19 #define _ISOC99_SOURCE
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <linux/if_ether.h>
26 #include <math.h>
27 #include <netinet/in.h>
28 #include <stdint.h>
29 #include <stdlib.h>
30 #include <string.h>
31
32 #include "sync_chain.h"
33 #include "event_processing_lttng_common.h"
34
35 #include "event_processing_lttng_standard.h"
36
37
38 #ifndef g_info
39 #define g_info(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, format)
40 #endif
41
42
43 // Functions common to all processing modules
44 static void initProcessingLTTVStandard(SyncState* const syncState,
45 LttvTracesetContext* const traceSetContext);
46 static void destroyProcessingLTTVStandard(SyncState* const syncState);
47
48 static void finalizeProcessingLTTVStandard(SyncState* const syncState);
49 static void printProcessingStatsLTTVStandard(SyncState* const syncState);
50 static void writeProcessingGraphsOptionsLTTVStandard(SyncState* const
51 syncState, const unsigned int i, const unsigned int j);
52
53 // Functions specific to this module
54 static void registerProcessingLTTVStandard() __attribute__((constructor (102)));
55 static gboolean processEventLTTVStandard(void* hookData, void* callData);
56 static void partialDestroyProcessingLTTVStandard(SyncState* const syncState);
57
58
59 static ProcessingModule processingModuleLTTVStandard = {
60 .name= "LTTV-standard",
61 .initProcessing= &initProcessingLTTVStandard,
62 .destroyProcessing= &destroyProcessingLTTVStandard,
63 .finalizeProcessing= &finalizeProcessingLTTVStandard,
64 .printProcessingStats= &printProcessingStatsLTTVStandard,
65 .writeProcessingGraphsPlots= NULL,
66 .writeProcessingGraphsOptions= &writeProcessingGraphsOptionsLTTVStandard,
67 };
68
69
70
71 /*
72 * Processing Module registering function
73 */
74 static void registerProcessingLTTVStandard()
75 {
76 g_queue_push_tail(&processingModules, &processingModuleLTTVStandard);
77
78 createQuarks();
79 }
80
81
82 /*
83 * Allocate and initialize data structures for synchronizing a traceset.
84 * Register event hooks.
85 *
86 * Args:
87 * syncState: container for synchronization data.
88 * This function allocates these processingData members:
89 * traceNumTable
90 * pendingRecv
91 * hookListList
92 * stats
93 * traceSetContext: set of LTTV traces
94 */
95 static void initProcessingLTTVStandard(SyncState* const syncState, LttvTracesetContext*
96 const traceSetContext)
97 {
98 unsigned int i;
99 ProcessingDataLTTVStandard* processingData;
100
101 processingData= malloc(sizeof(ProcessingDataLTTVStandard));
102 syncState->processingData= processingData;
103 processingData->traceSetContext= traceSetContext;
104
105 if (syncState->stats)
106 {
107 processingData->stats= calloc(1, sizeof(ProcessingStatsLTTVStandard));
108 }
109 else
110 {
111 processingData->stats= NULL;
112 }
113
114 processingData->traceNumTable= g_hash_table_new(&g_direct_hash, NULL);
115 processingData->hookListList= g_array_sized_new(FALSE, FALSE,
116 sizeof(GArray*), syncState->traceNb);
117 processingData->pendingRecv= malloc(sizeof(GHashTable*) *
118 syncState->traceNb);
119
120 for(i= 0; i < syncState->traceNb; i++)
121 {
122 g_hash_table_insert(processingData->traceNumTable,
123 processingData->traceSetContext->traces[i]->t, (gpointer) i);
124 }
125
126 for(i= 0; i < syncState->traceNb; i++)
127 {
128 processingData->pendingRecv[i]= g_hash_table_new_full(&g_direct_hash,
129 NULL, NULL, &gdnDestroyEvent);
130 }
131
132 registerHooks(processingData->hookListList, traceSetContext,
133 &processEventLTTVStandard, syncState,
134 syncState->matchingModule->canMatch);
135 }
136
137
138 /*
139 * Call the partial processing destroyer, obtain and adjust the factors from
140 * downstream
141 *
142 * Args:
143 * syncState container for synchronization data.
144 */
145 static void finalizeProcessingLTTVStandard(SyncState* const syncState)
146 {
147 unsigned int i;
148 GArray* factors;
149 double minOffset, minDrift;
150 unsigned int refFreqTrace;
151 ProcessingDataLTTVStandard* processingData;
152
153 processingData= (ProcessingDataLTTVStandard*) syncState->processingData;
154
155 partialDestroyProcessingLTTVStandard(syncState);
156
157 factors= syncState->matchingModule->finalizeMatching(syncState);
158
159 /* The offsets are adjusted so the lowest one is 0. This is done because
160 * of a Lttv specific limitation: events cannot have negative times. By
161 * having non-negative offsets, events cannot be moved backwards to
162 * negative times.
163 */
164 minOffset= 0;
165 for (i= 0; i < syncState->traceNb; i++)
166 {
167 minOffset= MIN(g_array_index(factors, Factors, i).offset, minOffset);
168 }
169
170 for (i= 0; i < syncState->traceNb; i++)
171 {
172 g_array_index(factors, Factors, i).offset-= minOffset;
173 }
174
175 /* Because the timestamps are corrected at the TSC level (not at the
176 * LttTime level) all trace frequencies must be made equal. We choose to
177 * use the frequency of the system with the lowest drift
178 */
179 minDrift= INFINITY;
180 refFreqTrace= 0;
181 for (i= 0; i < syncState->traceNb; i++)
182 {
183 if (g_array_index(factors, Factors, i).drift < minDrift)
184 {
185 minDrift= g_array_index(factors, Factors, i).drift;
186 refFreqTrace= i;
187 }
188 }
189 g_assert(syncState->traceNb == 0 || minDrift != INFINITY);
190
191 // Write the factors to the LttTrace structures
192 for (i= 0; i < syncState->traceNb; i++)
193 {
194 LttTrace* t;
195 Factors* traceFactors;
196
197 t= processingData->traceSetContext->traces[i]->t;
198 traceFactors= &g_array_index(factors, Factors, i);
199
200 t->drift= traceFactors->drift;
201 t->offset= traceFactors->offset;
202 t->start_freq=
203 processingData->traceSetContext->traces[refFreqTrace]->t->start_freq;
204 t->freq_scale=
205 processingData->traceSetContext->traces[refFreqTrace]->t->freq_scale;
206 t->start_time_from_tsc =
207 ltt_time_from_uint64(tsc_to_uint64(t->freq_scale, t->start_freq,
208 t->drift * t->start_tsc + t->offset));
209 }
210
211 g_array_free(factors, TRUE);
212
213 lttv_traceset_context_compute_time_span(processingData->traceSetContext,
214 &processingData->traceSetContext->time_span);
215
216 g_debug("traceset start %ld.%09ld end %ld.%09ld\n",
217 processingData->traceSetContext->time_span.start_time.tv_sec,
218 processingData->traceSetContext->time_span.start_time.tv_nsec,
219 processingData->traceSetContext->time_span.end_time.tv_sec,
220 processingData->traceSetContext->time_span.end_time.tv_nsec);
221 }
222
223
224 /*
225 * Print statistics related to processing Must be called after
226 * finalizeProcessing.
227 *
228 * Args:
229 * syncState container for synchronization data.
230 */
231 static void printProcessingStatsLTTVStandard(SyncState* const syncState)
232 {
233 ProcessingDataLTTVStandard* processingData;
234
235 if (!syncState->stats)
236 {
237 return;
238 }
239
240 processingData= (ProcessingDataLTTVStandard*) syncState->processingData;
241
242 printf("LTTV processing stats:\n");
243 printf("\treceived frames: %d\n", processingData->stats->totRecv);
244 printf("\treceived frames that are IP: %d\n",
245 processingData->stats->totRecvIp);
246 if (syncState->matchingModule->canMatch[TCP])
247 {
248 printf("\treceived and processed packets that are TCP: %d\n",
249 processingData->stats->totRecvTCP);
250 }
251 if (syncState->matchingModule->canMatch[UDP])
252 {
253 printf("\treceived and processed packets that are UDP: %d\n",
254 processingData->stats->totRecvUDP);
255 }
256 if (syncState->matchingModule->canMatch[TCP])
257 {
258 printf("\tsent packets that are TCP: %d\n",
259 processingData->stats->totOutE);
260 }
261 }
262
263
264 /*
265 * Unregister event hooks. Deallocate processingData.
266 *
267 * Args:
268 * syncState: container for synchronization data.
269 * This function deallocates these processingData members:
270 * stats
271 */
272 static void destroyProcessingLTTVStandard(SyncState* const syncState)
273 {
274 ProcessingDataLTTVStandard* processingData;
275
276 processingData= (ProcessingDataLTTVStandard*) syncState->processingData;
277
278 if (processingData == NULL)
279 {
280 return;
281 }
282
283 partialDestroyProcessingLTTVStandard(syncState);
284
285 if (syncState->stats)
286 {
287 free(processingData->stats);
288 }
289
290 free(syncState->processingData);
291 syncState->processingData= NULL;
292 }
293
294
295 /*
296 * Unregister event hooks. Deallocate some of processingData.
297 *
298 * This function can be called right after the events have been processed to
299 * free some data structures that are not needed for finalization.
300 *
301 * Args:
302 * syncState: container for synchronization data.
303 * This function deallocates these members:
304 * traceNumTable
305 * hookListList
306 * pendingRecv
307 */
308 static void partialDestroyProcessingLTTVStandard(SyncState* const syncState)
309 {
310 unsigned int i;
311 ProcessingDataLTTVStandard* processingData;
312
313 processingData= (ProcessingDataLTTVStandard*) syncState->processingData;
314
315 if (processingData == NULL || processingData->traceNumTable == NULL)
316 {
317 return;
318 }
319
320 g_hash_table_destroy(processingData->traceNumTable);
321 processingData->traceNumTable= NULL;
322
323 for(i= 0; i < syncState->traceNb; i++)
324 {
325
326 g_debug("Cleaning up pendingRecv list\n");
327 g_hash_table_destroy(processingData->pendingRecv[i]);
328 }
329 free(processingData->pendingRecv);
330
331 unregisterHooks(processingData->hookListList,
332 processingData->traceSetContext);
333 }
334
335
336 /*
337 * Lttv hook function that will be called for network events
338 *
339 * Args:
340 * hookData: LttvTraceHook* for the type of event that generated the call
341 * callData: LttvTracefileContext* at the moment of the event
342 *
343 * Returns:
344 * FALSE Always returns FALSE, meaning to keep processing hooks for
345 * this event
346 */
347 static gboolean processEventLTTVStandard(void* hookData, void* callData)
348 {
349 LttvTraceHook* traceHook;
350 LttvTracefileContext* tfc;
351 LttEvent* event;
352 LttCycleCount tsc;
353 LttTime time;
354 WallTime wTime;
355 LttTrace* trace;
356 unsigned long traceNum;
357 struct marker_info* info;
358 SyncState* syncState;
359 ProcessingDataLTTVStandard* processingData;
360
361 traceHook= (LttvTraceHook*) hookData;
362 tfc= (LttvTracefileContext*) callData;
363 trace= tfc->t_context->t;
364 syncState= (SyncState*) traceHook->hook_data;
365 processingData= (ProcessingDataLTTVStandard*) syncState->processingData;
366 event= ltt_tracefile_get_event(tfc->tf);
367 info= marker_get_info_from_id(tfc->tf->mdata, event->event_id);
368 tsc= ltt_event_cycle_count(event);
369 time= ltt_event_time(event);
370 wTime.seconds= time.tv_sec;
371 wTime.nanosec= time.tv_nsec;
372
373 g_assert(g_hash_table_lookup_extended(processingData->traceNumTable,
374 trace, NULL, (gpointer*) &traceNum));
375
376 g_debug("XXXX process event: time: %ld.%09ld trace: %ld (%p) name: %s ",
377 time.tv_sec, time.tv_nsec, traceNum, trace,
378 g_quark_to_string(info->name));
379
380 if (info->name == LTT_EVENT_DEV_XMIT_EXTENDED)
381 {
382 Event* outE;
383
384 if (!ltt_event_get_unsigned(event,
385 lttv_trace_get_hook_field(traceHook, 1)) == ETH_P_IP ||
386 !ltt_event_get_unsigned(event,
387 lttv_trace_get_hook_field(traceHook, 2)) == IPPROTO_TCP)
388 {
389 return FALSE;
390 }
391
392 if (!syncState->matchingModule->canMatch[TCP])
393 {
394 return FALSE;
395 }
396
397 if (syncState->stats)
398 {
399 processingData->stats->totOutE++;
400 }
401
402 outE= malloc(sizeof(Event));
403 outE->traceNum= traceNum;
404 outE->cpuTime= tsc;
405 outE->wallTime= wTime;
406 outE->type= TCP;
407 outE->copy= &copyTCPEvent;
408 outE->destroy= &destroyTCPEvent;
409 outE->event.tcpEvent= malloc(sizeof(TCPEvent));
410 outE->event.tcpEvent->direction= OUT;
411 outE->event.tcpEvent->segmentKey= malloc(sizeof(SegmentKey));
412 outE->event.tcpEvent->segmentKey->connectionKey.saddr=
413 htonl(ltt_event_get_unsigned(event,
414 lttv_trace_get_hook_field(traceHook, 3)));
415 outE->event.tcpEvent->segmentKey->connectionKey.daddr=
416 htonl(ltt_event_get_unsigned(event,
417 lttv_trace_get_hook_field(traceHook, 4)));
418 outE->event.tcpEvent->segmentKey->tot_len=
419 ltt_event_get_unsigned(event, lttv_trace_get_hook_field(traceHook,
420 5));
421 outE->event.tcpEvent->segmentKey->ihl= ltt_event_get_unsigned(event,
422 lttv_trace_get_hook_field(traceHook, 6));
423 outE->event.tcpEvent->segmentKey->connectionKey.source=
424 ltt_event_get_unsigned(event, lttv_trace_get_hook_field(traceHook,
425 7));
426 outE->event.tcpEvent->segmentKey->connectionKey.dest=
427 ltt_event_get_unsigned(event, lttv_trace_get_hook_field(traceHook,
428 8));
429 outE->event.tcpEvent->segmentKey->seq= ltt_event_get_unsigned(event,
430 lttv_trace_get_hook_field(traceHook, 9));
431 outE->event.tcpEvent->segmentKey->ack_seq=
432 ltt_event_get_unsigned(event, lttv_trace_get_hook_field(traceHook,
433 10));
434 outE->event.tcpEvent->segmentKey->doff= ltt_event_get_unsigned(event,
435 lttv_trace_get_hook_field(traceHook, 11));
436 outE->event.tcpEvent->segmentKey->ack= ltt_event_get_unsigned(event,
437 lttv_trace_get_hook_field(traceHook, 12));
438 outE->event.tcpEvent->segmentKey->rst= ltt_event_get_unsigned(event,
439 lttv_trace_get_hook_field(traceHook, 13));
440 outE->event.tcpEvent->segmentKey->syn= ltt_event_get_unsigned(event,
441 lttv_trace_get_hook_field(traceHook, 14));
442 outE->event.tcpEvent->segmentKey->fin= ltt_event_get_unsigned(event,
443 lttv_trace_get_hook_field(traceHook, 15));
444
445 syncState->matchingModule->matchEvent(syncState, outE);
446
447 g_debug("Output event done\n");
448 }
449 else if (info->name == LTT_EVENT_DEV_RECEIVE)
450 {
451 guint32 protocol;
452
453 if (syncState->stats)
454 {
455 processingData->stats->totRecv++;
456 }
457
458 protocol= ltt_event_get_unsigned(event,
459 lttv_trace_get_hook_field(traceHook, 1));
460
461 if (protocol == ETH_P_IP)
462 {
463 Event* inE;
464 void* skb;
465
466 if (syncState->stats)
467 {
468 processingData->stats->totRecvIp++;
469 }
470
471 inE= malloc(sizeof(Event));
472 inE->traceNum= traceNum;
473 inE->cpuTime= tsc;
474 inE->wallTime= wTime;
475 inE->event.tcpEvent= NULL;
476 inE->copy= &copyEvent;
477 inE->destroy= &destroyEvent;
478
479 skb= (void*) (long) ltt_event_get_long_unsigned(event,
480 lttv_trace_get_hook_field(traceHook, 0));
481 g_hash_table_replace(processingData->pendingRecv[traceNum], skb,
482 inE);
483
484 g_debug("Adding inE %p for skb %p to pendingRecv\n", inE, skb);
485 }
486 else
487 {
488 g_debug("\n");
489 }
490 }
491 else if (info->name == LTT_EVENT_TCPV4_RCV_EXTENDED)
492 {
493 Event* inE;
494 void* skb;
495
496 // Search pendingRecv for an event with the same skb
497 skb= (void*) (long) ltt_event_get_long_unsigned(event,
498 lttv_trace_get_hook_field(traceHook, 0));
499
500 inE= (Event*)
501 g_hash_table_lookup(processingData->pendingRecv[traceNum], skb);
502 if (inE == NULL)
503 {
504 // This should only happen in case of lost events
505 g_warning("No matching pending receive event found");
506 }
507 else
508 {
509 if (syncState->stats)
510 {
511 processingData->stats->totRecvTCP++;
512 }
513
514 // If it's there, remove it and proceed with a receive event
515 g_hash_table_steal(processingData->pendingRecv[traceNum], skb);
516
517 inE->type= TCP;
518 inE->event.tcpEvent= malloc(sizeof(TCPEvent));
519 inE->copy= &copyTCPEvent;
520 inE->destroy= &destroyTCPEvent;
521 inE->event.tcpEvent->direction= IN;
522 inE->event.tcpEvent->segmentKey= malloc(sizeof(SegmentKey));
523 inE->event.tcpEvent->segmentKey->connectionKey.saddr=
524 htonl(ltt_event_get_unsigned(event,
525 lttv_trace_get_hook_field(traceHook, 1)));
526 inE->event.tcpEvent->segmentKey->connectionKey.daddr=
527 htonl(ltt_event_get_unsigned(event,
528 lttv_trace_get_hook_field(traceHook, 2)));
529 inE->event.tcpEvent->segmentKey->tot_len=
530 ltt_event_get_unsigned(event,
531 lttv_trace_get_hook_field(traceHook, 3));
532 inE->event.tcpEvent->segmentKey->ihl=
533 ltt_event_get_unsigned(event,
534 lttv_trace_get_hook_field(traceHook, 4));
535 inE->event.tcpEvent->segmentKey->connectionKey.source=
536 ltt_event_get_unsigned(event,
537 lttv_trace_get_hook_field(traceHook, 5));
538 inE->event.tcpEvent->segmentKey->connectionKey.dest=
539 ltt_event_get_unsigned(event,
540 lttv_trace_get_hook_field(traceHook, 6));
541 inE->event.tcpEvent->segmentKey->seq=
542 ltt_event_get_unsigned(event,
543 lttv_trace_get_hook_field(traceHook, 7));
544 inE->event.tcpEvent->segmentKey->ack_seq=
545 ltt_event_get_unsigned(event,
546 lttv_trace_get_hook_field(traceHook, 8));
547 inE->event.tcpEvent->segmentKey->doff=
548 ltt_event_get_unsigned(event,
549 lttv_trace_get_hook_field(traceHook, 9));
550 inE->event.tcpEvent->segmentKey->ack=
551 ltt_event_get_unsigned(event,
552 lttv_trace_get_hook_field(traceHook, 10));
553 inE->event.tcpEvent->segmentKey->rst=
554 ltt_event_get_unsigned(event,
555 lttv_trace_get_hook_field(traceHook, 11));
556 inE->event.tcpEvent->segmentKey->syn=
557 ltt_event_get_unsigned(event,
558 lttv_trace_get_hook_field(traceHook, 12));
559 inE->event.tcpEvent->segmentKey->fin=
560 ltt_event_get_unsigned(event,
561 lttv_trace_get_hook_field(traceHook, 13));
562
563 syncState->matchingModule->matchEvent(syncState, inE);
564
565 g_debug("TCP input event %p for skb %p done\n", inE, skb);
566 }
567 }
568 else if (info->name == LTT_EVENT_UDPV4_RCV_EXTENDED)
569 {
570 Event* inE;
571 void* skb;
572
573 // Search pendingRecv for an event with the same skb
574 skb= (void*) (long) ltt_event_get_long_unsigned(event,
575 lttv_trace_get_hook_field(traceHook, 0));
576
577 inE= (Event*)
578 g_hash_table_lookup(processingData->pendingRecv[traceNum], skb);
579 if (inE == NULL)
580 {
581 // This should only happen in case of lost events
582 g_warning("No matching pending receive event found");
583 }
584 else
585 {
586 guint64 dataStart;
587
588 if (syncState->stats)
589 {
590 processingData->stats->totRecvUDP++;
591 }
592
593 // If it's there, remove it and proceed with a receive event
594 g_hash_table_steal(processingData->pendingRecv[traceNum], skb);
595
596 inE->type= UDP;
597 inE->event.udpEvent= malloc(sizeof(UDPEvent));
598 inE->copy= &copyUDPEvent;
599 inE->destroy= &destroyUDPEvent;
600 inE->event.udpEvent->direction= IN;
601 inE->event.udpEvent->datagramKey= malloc(sizeof(DatagramKey));
602 inE->event.udpEvent->datagramKey->saddr=
603 htonl(ltt_event_get_unsigned(event,
604 lttv_trace_get_hook_field(traceHook, 1)));
605 inE->event.udpEvent->datagramKey->daddr=
606 htonl(ltt_event_get_unsigned(event,
607 lttv_trace_get_hook_field(traceHook, 2)));
608 inE->event.udpEvent->unicast= ltt_event_get_unsigned(event,
609 lttv_trace_get_hook_field(traceHook, 3)) == 0 ? false : true;
610 inE->event.udpEvent->datagramKey->ulen=
611 ltt_event_get_unsigned(event,
612 lttv_trace_get_hook_field(traceHook, 4));
613 inE->event.udpEvent->datagramKey->source=
614 ltt_event_get_unsigned(event,
615 lttv_trace_get_hook_field(traceHook, 5));
616 inE->event.udpEvent->datagramKey->dest=
617 ltt_event_get_unsigned(event,
618 lttv_trace_get_hook_field(traceHook, 6));
619 dataStart= ltt_event_get_long_unsigned(event,
620 lttv_trace_get_hook_field(traceHook, 7));
621 g_assert_cmpuint(sizeof(inE->event.udpEvent->datagramKey->dataKey),
622 ==, sizeof(guint64));
623 if (inE->event.udpEvent->datagramKey->ulen - 8 >=
624 sizeof(inE->event.udpEvent->datagramKey->dataKey))
625 {
626 memcpy(inE->event.udpEvent->datagramKey->dataKey, &dataStart,
627 sizeof(inE->event.udpEvent->datagramKey->dataKey));
628 }
629 else
630 {
631 memset(inE->event.udpEvent->datagramKey->dataKey, 0,
632 sizeof(inE->event.udpEvent->datagramKey->dataKey));
633 memcpy(inE->event.udpEvent->datagramKey->dataKey, &dataStart,
634 inE->event.udpEvent->datagramKey->ulen - 8);
635 }
636
637 syncState->matchingModule->matchEvent(syncState, inE);
638
639 g_debug("UDP input event %p for skb %p done\n", inE, skb);
640 }
641 }
642 else
643 {
644 g_assert_not_reached();
645 }
646
647 return FALSE;
648 }
649
650
651 /*
652 * Write the processing-specific options in the gnuplot script.
653 *
654 * Args:
655 * syncState: container for synchronization data
656 * i: first trace number
657 * j: second trace number, garanteed to be larger than i
658 */
659 static void writeProcessingGraphsOptionsLTTVStandard(SyncState* const
660 syncState, const unsigned int i, const unsigned int j)
661 {
662 ProcessingDataLTTVStandard* processingData;
663 LttTrace* traceI, * traceJ;
664
665 processingData= (ProcessingDataLTTVStandard*) syncState->processingData;
666
667 traceI= processingData->traceSetContext->traces[i]->t;
668 traceJ= processingData->traceSetContext->traces[j]->t;
669
670 fprintf(syncState->graphsStream,
671 "set key inside right bottom\n"
672 "set xlabel \"Clock %1$u\"\n"
673 "set xtics nomirror\n"
674 "set ylabel \"Clock %3$u\"\n"
675 "set ytics nomirror\n"
676 "set x2label \"Clock %1$d (s)\"\n"
677 "set x2range [GPVAL_X_MIN / %2$.1f : GPVAL_X_MAX / %2$.1f]\n"
678 "set x2tics\n"
679 "set y2label \"Clock %3$d (s)\"\n"
680 "set y2range [GPVAL_Y_MIN / %4$.1f : GPVAL_Y_MAX / %4$.1f]\n"
681 "set y2tics\n", i, (double) traceI->start_freq / traceI->freq_scale,
682 j, (double) traceJ->start_freq / traceJ->freq_scale);
683 }
This page took 0.042915 seconds and 3 git commands to generate.