Statistics
| Branch: | Revision:

root / src / envir / eventlogfilemgr.cc @ 636cbdd5

History | View | Annotate | Download (19.2 KB)

1
//==========================================================================
2
//  EVENTLOGFILEMGR.CC - part of
3
//                     OMNeT++/OMNEST
4
//            Discrete System Simulation in C++
5
//
6
//  Author: Andras Varga
7
//
8
//==========================================================================
9

    
10
/*--------------------------------------------------------------*
11
  Copyright (C) 1992-2008 Andras Varga
12
  Copyright (C) 2006-2008 OpenSim Ltd.
13

14
  This file is distributed WITHOUT ANY WARRANTY. See the file
15
  `license' for details on this and other legal matters.
16
*--------------------------------------------------------------*/
17

    
18
#include <algorithm>
19
#include "opp_ctype.h"
20
#include "commonutil.h"  //vsnprintf
21
#include "eventlogfilemgr.h"
22
#include "eventlogwriter.h"
23
#include "cconfigoption.h"
24
#include "fileutil.h"
25
#include "cconfiguration.h"
26
#include "envirbase.h"
27
#include "cmodule.h"
28
#include "cmessage.h"
29
#include "cgate.h"
30
#include "cchannel.h"
31
#include "csimplemodule.h"
32
#include "ccompoundmodule.h"
33
#include "cdisplaystring.h"
34
#include "cclassdescriptor.h"
35
#include "casyncmodule.h"
36

    
37
USING_NAMESPACE
38

    
39

    
40
Register_PerRunConfigOption(CFGID_EVENTLOG_FILE, "eventlog-file", CFG_FILENAME, "${resultdir}/${configname}-${runnumber}.elog", "Name of the event log file to generate.");
41
Register_PerRunConfigOption(CFGID_EVENTLOG_MESSAGE_DETAIL_PATTERN, "eventlog-message-detail-pattern", CFG_CUSTOM, NULL,
42
        "A list of patterns separated by '|' character which will be used to write "
43
        "message detail information into the event log for each message sent during "
44
        "the simulation. The message detail will be presented in the sequence chart "
45
        "tool. Each pattern starts with an object pattern optionally followed by ':' "
46
        "character and a comma separated list of field patterns. In both "
47
        "patterns and/or/not/* and various field match expressions can be used. "
48
        "The object pattern matches to class name, the field pattern matches to field name by default.\n"
49
        "  EVENTLOG-MESSAGE-DETAIL-PATTERN := ( DETAIL-PATTERN '|' )* DETAIL_PATTERN\n"
50
        "  DETAIL-PATTERN := OBJECT-PATTERN [ ':' FIELD-PATTERNS ]\n"
51
        "  OBJECT-PATTERN := MATCH-EXPRESSION\n"
52
        "  FIELD-PATTERNS := ( FIELD-PATTERN ',' )* FIELD_PATTERN\n"
53
        "  FIELD-PATTERN := MATCH-EXPRESSION\n"
54
        "Examples (enter them without quotes):\n"
55
        "  \"*\": captures all fields of all messages\n"
56
        "  \"*Frame:*Address,*Id\": captures all fields named somethingAddress and somethingId from messages of any class named somethingFrame\n"
57
        "  \"MyMessage:declaredOn(MyMessage)\": captures instances of MyMessage recording the fields declared on the MyMessage class\n"
58
        "  \"*:(not declaredOn(cMessage) and not declaredOn(cNamedObject) and not declaredOn(cObject))\": records user-defined fields from all messages");
59
Register_PerRunConfigOption(CFGID_EVENTLOG_RECORDING_INTERVALS, "eventlog-recording-intervals", CFG_CUSTOM, NULL, "Simulation time interval(s) when events should be recorded. Syntax: [<from>]..[<to>],... That is, both start and end of an interval are optional, and intervals are separated by comma. Example: ..10.2, 22.2..100, 233.3..");
60
Register_PerObjectConfigOption(CFGID_MODULE_EVENTLOG_RECORDING, "module-eventlog-recording", CFG_BOOL, "true", "Enables recording events on a per module basis. This is meaningful for simple modules only. \nExample:\n **.router[10..20].**.module-eventlog-recording = true\n **.module-eventlog-recording = false");
61

    
62
static va_list empty_va;
63

    
64
static bool compareMessageEventNumbers(cMessage *message1, cMessage *message2)
65
{
66
    return message1->getPreviousEventNumber() < message2->getPreviousEventNumber();
67
}
68

    
69
static ObjectPrinterRecursionControl recurseIntoMessageFields(void *object, cClassDescriptor *descriptor, int fieldIndex, void *fieldValue, void **parents, int level) {
70
    const char* propertyValue = descriptor->getFieldProperty(object, fieldIndex, "eventlog");
71

    
72
    if (propertyValue) {
73
        if (!strcmp(propertyValue, "skip"))
74
            return SKIP;
75
        else if (!strcmp(propertyValue, "fullName"))
76
            return FULL_NAME;
77
        else if (!strcmp(propertyValue, "fullPath"))
78
            return FULL_PATH;
79
    }
80

    
81
    bool isCObject = descriptor->getFieldIsCObject(object, fieldIndex);
82
    if (!isCObject)
83
        return RECURSE;
84
    else {
85
        if (!fieldValue)
86
            return RECURSE;
87
        else {
88
            cArray *array = dynamic_cast<cArray *>((cObject *)fieldValue);
89
            return !array || array->size() != 0 ? RECURSE : SKIP;
90
        }
91
    }
92
}
93

    
94
EventlogFileManager::EventlogFileManager()
95
{
96
    feventlog = NULL;
97
    objectPrinter = NULL;
98
    recordingIntervals = NULL;
99
    isEventLogRecordingEnabled = true;
100
    isIntervalEventLogRecordingEnabled = true;
101
    isModuleEventLogRecordingEnabled = true;
102
}
103

    
104
EventlogFileManager::~EventlogFileManager()
105
{
106
    delete objectPrinter;
107
    delete recordingIntervals;
108
}
109

    
110
void EventlogFileManager::configure()
111
{
112
    // setup event log object printer
113
    delete objectPrinter;
114
    objectPrinter = NULL;
115

    
116
    const char *eventLogMessageDetailPattern = ev.getConfig()->getAsCustom(CFGID_EVENTLOG_MESSAGE_DETAIL_PATTERN);
117

    
118
    if (eventLogMessageDetailPattern) {
119
        objectPrinter = new ObjectPrinter(recurseIntoMessageFields, eventLogMessageDetailPattern, 3);
120
    }
121

    
122
    // setup eventlog recording intervals
123
    const char *text = ev.getConfig()->getAsCustom(CFGID_EVENTLOG_RECORDING_INTERVALS);
124
    if (text) {
125
        recordingIntervals = new Intervals();
126
        recordingIntervals->parse(text);
127
    }
128

    
129
    // setup filename
130
    filename = ev.getConfig()->getAsFilename(CFGID_EVENTLOG_FILE).c_str();
131
    dynamic_cast<EnvirBase *>(&ev)->processFileName(filename);
132
    ::printf("Recording event log to file `%s'...\n", filename.c_str());
133
}
134

    
135
void EventlogFileManager::open()
136
{
137
    mkPath(directoryOf(filename.c_str()).c_str());
138
    FILE *out = fopen(filename.c_str(), "w");
139
    if (!out)
140
        throw cRuntimeError("Cannot open eventlog file `%s' for write", filename.c_str());
141
    feventlog = out;
142
}
143

    
144
void EventlogFileManager::recordSimulation()
145
{
146
    cModule *systemModule = simulation.getSystemModule();
147
    recordModules(systemModule);
148
    recordConnections(systemModule);
149
    recordMessages();
150
}
151

    
152
void EventlogFileManager::recordMessages()
153
{
154
    const char *runId = ev.getConfigEx()->getVariable(CFGVAR_RUNID);
155
    EventLogWriter::recordSimulationBeginEntry_v_rid(feventlog, OMNETPP_VERSION, runId);
156
    std::vector<cMessage *> messages;
157
    for (cMessageHeap::Iterator it = cMessageHeap::Iterator(simulation.getMessageQueue()); !it.end(); it++)
158
        messages.push_back(it());
159
    std::stable_sort(messages.begin(), messages.end(), compareMessageEventNumbers);
160
    eventnumber_t currentEvent = -1;
161
    for (std::vector<cMessage *>::iterator it = messages.begin(); it != messages.end(); it++) {
162
        cMessage *message = *it;
163
        if (currentEvent != message->getPreviousEventNumber()) {
164
            currentEvent = message->getPreviousEventNumber();
165
            EventLogWriter::recordEventEntry_e_t_m_ce_msg_d(feventlog, currentEvent, message->getSendingTime(), currentEvent == 0 ? simulation.getSystemModule()->getId() : message->getSenderModuleId(), 0, -1,0);
166
            EventLogWriter::recordEventEndEntry_e_c(feventlog, currentEvent,0);
167
        }
168
        if (currentEvent == 0)
169
            componentMethodBegin(simulation.getSystemModule(), message->getSenderModule(), "initialize", empty_va);
170
        if (message->isSelfMessage())
171
            messageScheduled(message);
172
        else if (!message->getSenderGate()) {
173
            beginSend(message);
174
            if (message->isPacket()) {
175
                cPacket *packet = (cPacket *)message;
176
                simtime_t propagationDelay = packet->getArrivalTime() - packet->getSendingTime() - (packet->isReceptionStart() ? 0 : packet->getDuration());
177
                messageSendDirect(message, message->getArrivalGate(), propagationDelay, packet->getDuration());
178
            }
179
            else
180
                messageSendDirect(message, message->getArrivalGate(), 0, 0);
181
            endSend(message);
182
        }
183
        else {
184
            beginSend(message);
185
            messageSendHop(message, message->getSenderGate());
186
            endSend(message);
187
        }
188
        if (currentEvent == 0)
189
            componentMethodEnd();
190
    }
191
}
192

    
193
void EventlogFileManager::recordModules(cModule *module)
194
{
195
    for (cModule::GateIterator it(module); !it.end(); it++) {
196
        cGate *gate = it();
197
        gateCreated(gate);
198
    }
199
    moduleCreated(module);
200
    // FIXME: records display string twice if it is lazily created right now
201
    if (strcmp(module->getDisplayString().str(), "")) {
202
        displayStringChanged(module);
203
    }
204
    for (cModule::SubmoduleIterator it(module); !it.end(); it++)
205
        recordModules(it());
206
}
207

    
208
void EventlogFileManager::recordConnections(cModule *module)
209
{
210
    for (cModule::GateIterator it(module); !it.end(); it++) {
211
        cGate *gate = it();
212
        if (gate->getNextGate())
213
            connectionCreated(gate);
214
        cChannel *channel = gate->getChannel();
215
        if (channel && strcmp(channel->getDisplayString(), "")) {
216
            displayStringChanged(channel);
217
        }
218
    }
219
    for (cModule::SubmoduleIterator it(module); !it.end(); it++)
220
        recordConnections(it());
221
}
222

    
223
void EventlogFileManager::startRun()
224
{
225
    if (isEventLogRecordingEnabled)
226
    {
227
        const char *runId = ev.getConfigEx()->getVariable(CFGVAR_RUNID);
228
        // TODO: we can't use simulation.getEventNumber() and simulation.getSimTime(), because when we start a new run
229
        // these numbers are still set from the previous run (i.e. not zero)
230
        EventLogWriter::recordEventEntry_e_t_m_ce_msg_d(feventlog, 0, 0, simulation.getSystemModule()->getId(), 0 ,  -1,0);
231
        EventLogWriter::recordSimulationBeginEntry_v_rid(feventlog, OMNETPP_VERSION, runId);
232
        fflush(feventlog);
233
    }
234
}
235

    
236
void EventlogFileManager::endRun()
237
{
238
    if (isEventLogRecordingEnabled)
239
    {
240
        EventLogWriter::recordSimulationEndEntry(feventlog);
241
        fclose(feventlog);
242
        feventlog = NULL;
243
    }
244
}
245

    
246
bool EventlogFileManager::hasRecordingIntervals() const
247
{
248
    return recordingIntervals && !recordingIntervals->empty();
249
}
250

    
251
void EventlogFileManager::clearRecordingIntervals()
252
{
253
    if (recordingIntervals)
254
    {
255
        delete recordingIntervals;
256
        recordingIntervals = NULL;
257
    }
258
}
259

    
260
void EventlogFileManager::flush()
261
{
262
    if (isEventLogRecordingEnabled)
263
    {
264
        fflush(feventlog);
265
    }
266
}
267

    
268
void EventlogFileManager::simulationEvent(cMessage *msg)
269
{
270
    cModule *mod = simulation.getContextModule();
271

    
272
    isModuleEventLogRecordingEnabled = simulation.getContextModule()->isRecordEvents();
273
    isIntervalEventLogRecordingEnabled = !recordingIntervals || recordingIntervals->contains(simulation.getSimTime());
274
    isEventLogRecordingEnabled = isModuleEventLogRecordingEnabled && isIntervalEventLogRecordingEnabled;
275

    
276
    if (isEventLogRecordingEnabled)
277
    {
278
        log_eventNumber = simulation.getEventNumber();
279
        log_simtime = simulation.getSimTime();
280
        log_modid = mod->getId();
281
        log_previd =msg->getPreviousEventNumber();
282
        log_msgid = msg->getId();
283
        log_duration = msg->getEventDuration();
284

    
285
        EventLogWriter::recordEventEntry_e_t_m_ce_msg_d(feventlog,
286
                log_eventNumber, log_simtime, log_modid,
287
                log_previd, log_msgid, log_duration);
288
    }
289
}
290

    
291
void EventlogFileManager::simulationEventEnd(double complexity) {
292
    if (isEventLogRecordingEnabled)
293
    {
294
        EventLogWriter::recordEventEndEntry_e_c(feventlog, log_eventNumber,
295
                        ((long)(1000*1000*complexity)));   //Store complexity in microseconds
296
    }
297
}
298

    
299
void EventlogFileManager::bubble(cComponent *component, const char *text)
300
{
301
    if (isEventLogRecordingEnabled)
302
    {
303
        if (dynamic_cast<cModule *>(component))
304
        {
305
            cModule *mod = (cModule *)component;
306
            EventLogWriter::recordBubbleEntry_id_txt(feventlog, mod->getId(), text);
307
        }
308
        else if (dynamic_cast<cChannel *>(component))
309
        {
310
            //TODO
311
        }
312
    }
313
}
314

    
315
void EventlogFileManager::beginSend(cMessage *msg)
316
{
317
    if (isEventLogRecordingEnabled)
318
    {
319
        //TODO record message display string as well?
320
        if (msg->isPacket()) {
321
            cPacket *pkt = (cPacket *)msg;
322
            EventLogWriter::recordBeginSendEntry_id_tid_eid_etid_c_n_pe_k_p_l_er_d(feventlog,
323
                pkt->getId(), pkt->getTreeId(), pkt->getEncapsulationId(), pkt->getEncapsulationTreeId(),
324
                pkt->getClassName(), pkt->getFullName(), pkt->getPreviousEventNumber(),
325
                pkt->getKind(), pkt->getSchedulingPriority(), pkt->getBitLength(), pkt->hasBitError(),
326
                objectPrinter ? objectPrinter->printObjectToString(pkt).c_str() : NULL);
327
        }
328
        else {
329
            EventLogWriter::recordBeginSendEntry_id_tid_eid_etid_c_n_pe_k_p_l_er_d(feventlog,
330
                msg->getId(), msg->getTreeId(), msg->getId(), msg->getTreeId(),
331
                msg->getClassName(), msg->getFullName(), msg->getPreviousEventNumber(),
332
                msg->getKind(), msg->getSchedulingPriority(), 0, false,
333
                objectPrinter ? objectPrinter->printObjectToString(msg).c_str() : NULL);
334
        }
335
    }
336
}
337

    
338
void EventlogFileManager::messageScheduled(cMessage *msg)
339
{
340
    if (isEventLogRecordingEnabled)
341
    {
342
        EventlogFileManager::beginSend(msg);
343
        EventlogFileManager::endSend(msg);
344
    }
345
}
346

    
347
void EventlogFileManager::messageCancelled(cMessage *msg)
348
{
349
    if (isEventLogRecordingEnabled)
350
    {
351
        EventLogWriter::recordCancelEventEntry_id_pe(feventlog, msg->getId(), msg->getPreviousEventNumber());
352
    }
353
}
354

    
355
void EventlogFileManager::messageSendDirect(cMessage *msg, cGate *toGate, simtime_t propagationDelay, simtime_t transmissionDelay)
356
{
357
    if (isEventLogRecordingEnabled)
358
    {
359
        EventLogWriter::recordSendDirectEntry_sm_dm_dg_pd_td(feventlog,
360
            msg->getSenderModuleId(), toGate->getOwnerModule()->getId(), toGate->getId(),
361
            propagationDelay, transmissionDelay);
362
    }
363
}
364

    
365
void EventlogFileManager::messageSendHop(cMessage *msg, cGate *srcGate)
366
{
367
    if (isEventLogRecordingEnabled)
368
    {
369
        EventLogWriter::recordSendHopEntry_sm_sg(feventlog,
370
            srcGate->getOwnerModule()->getId(), srcGate->getId());
371
    }
372
}
373

    
374
void EventlogFileManager::messageSendHop(cMessage *msg, cGate *srcGate, simtime_t propagationDelay, simtime_t transmissionDelay)
375
{
376
    if (isEventLogRecordingEnabled)
377
    {
378
        EventLogWriter::recordSendHopEntry_sm_sg_pd_td(feventlog,
379
            srcGate->getOwnerModule()->getId(), srcGate->getId(), propagationDelay, transmissionDelay);
380
    }
381
}
382

    
383
void EventlogFileManager::endSend(cMessage *msg)
384
{
385
    if (isEventLogRecordingEnabled)
386
    {
387
        bool isStart = msg->isPacket() ? ((cPacket *)msg)->isReceptionStart() : false;
388
        EventLogWriter::recordEndSendEntry_t_is(feventlog, msg->getArrivalTime(), isStart);
389
    }
390
}
391

    
392
void EventlogFileManager::messageDeleted(cMessage *msg)
393
{
394
    if (isEventLogRecordingEnabled)
395
    {
396
        EventLogWriter::recordDeleteMessageEntry_id_pe(feventlog, msg->getId(), msg->getPreviousEventNumber());
397
    }
398
}
399

    
400
void EventlogFileManager::componentMethodBegin(cComponent *from, cComponent *to, const char *methodFmt, va_list va)
401
{
402
    if (isEventLogRecordingEnabled)
403
    {
404
        if (from && from->isModule() && to->isModule())
405
        {
406
            const char *methodText = "";  // for the Enter_Method_Silent case
407
            if (methodFmt)
408
            {
409
                static char methodTextBuf[MAX_METHODCALL];
410
                vsnprintf(methodTextBuf, MAX_METHODCALL, methodFmt, va);
411
                methodTextBuf[MAX_METHODCALL-1] = '\0';
412
                methodText = methodTextBuf;
413
            }
414
            EventLogWriter::recordModuleMethodBeginEntry_sm_tm_m(feventlog,
415
                ((cModule *)from)->getId(), ((cModule *)to)->getId(), methodText);
416
        }
417
    }
418
}
419

    
420
void EventlogFileManager::componentMethodEnd()
421
{
422
    if (isEventLogRecordingEnabled)
423
    {
424
        //XXX problem when channel method is called: we'll emit an "End" entry but no "Begin"
425
        //XXX same problem when the caller is not a module or is NULL
426
        EventLogWriter::recordModuleMethodEndEntry(feventlog);
427
    }
428
}
429

    
430
void EventlogFileManager::moduleCreated(cModule *newmodule)
431
{
432
    if (isEventLogRecordingEnabled)
433
    {
434
        cModule *m = newmodule;
435

    
436
        bool recordModuleEvents = ev.getConfig()->getAsBool(m->getFullPath().c_str(), CFGID_MODULE_EVENTLOG_RECORDING);
437
        m->setRecordEvents(recordModuleEvents);
438

    
439
        bool isCompoundModule = dynamic_cast<cCompoundModule *>(m);
440

    
441
        EventLogWriter::recordModuleCreatedEntry_id_c_t_pid_n_cm(feventlog,
442
            m->getId(), m->getClassName(), m->getNedTypeName(), m->getParentModule() ? m->getParentModule()->getId() : -1, m->getFullName(), isCompoundModule); //FIXME size() is missing
443
    }
444
}
445

    
446
void EventlogFileManager::moduleDeleted(cModule *module)
447
{
448
    if (isEventLogRecordingEnabled)
449
    {
450
        EventLogWriter::recordModuleDeletedEntry_id(feventlog, module->getId());
451
    }
452
}
453

    
454
void EventlogFileManager::moduleReparented(cModule *module, cModule *oldparent)
455
{
456
    if (isEventLogRecordingEnabled)
457
    {
458
        EventLogWriter::recordModuleReparentedEntry_id_p(feventlog, module->getId(), module->getParentModule()->getId());
459
    }
460
}
461

    
462
void EventlogFileManager::gateCreated(cGate *newgate)
463
{
464
    if (isEventLogRecordingEnabled)
465
    {
466
        EventLogWriter::recordGateCreatedEntry_m_g_n_i_o(feventlog,
467
            newgate->getOwnerModule()->getId(), newgate->getId(), newgate->getName(),
468
            newgate->isVector() ? newgate->getIndex() : -1, newgate->getType() == cGate::OUTPUT);
469
    }
470
}
471

    
472
void EventlogFileManager::gateDeleted(cGate *gate)
473
{
474
    if (isEventLogRecordingEnabled)
475
    {
476
        EventLogWriter::recordGateDeletedEntry_m_g(feventlog, gate->getOwnerModule()->getId(), gate->getId());
477
    }
478
}
479

    
480
void EventlogFileManager::connectionCreated(cGate *srcgate)
481
{
482
    if (isEventLogRecordingEnabled)
483
    {
484
        cGate *destgate = srcgate->getNextGate();
485
        EventLogWriter::recordConnectionCreatedEntry_sm_sg_dm_dg(feventlog,
486
            srcgate->getOwnerModule()->getId(), srcgate->getId(), destgate->getOwnerModule()->getId(), destgate->getId());  //XXX channel, channel attributes, etc
487
    }
488
}
489

    
490
void EventlogFileManager::connectionDeleted(cGate *srcgate)
491
{
492
    if (isEventLogRecordingEnabled)
493
    {
494
        EventLogWriter::recordConnectionDeletedEntry_sm_sg(feventlog,
495
            srcgate->getOwnerModule()->getId(), srcgate->getId());
496
    }
497
}
498

    
499
void EventlogFileManager::displayStringChanged(cComponent *component)
500
{
501
    if (isEventLogRecordingEnabled)
502
    {
503
        if (dynamic_cast<cModule *>(component))
504
        {
505
            cModule *module = (cModule *)component;
506
            EventLogWriter::recordModuleDisplayStringChangedEntry_id_d(feventlog,
507
                module->getId(), module->getDisplayString().str());
508
        }
509
        else if (dynamic_cast<cChannel *>(component))
510
        {
511
            cChannel *channel = (cChannel *)component;
512
            cGate *gate = channel->getSourceGate();
513
            EventLogWriter::recordConnectionDisplayStringChangedEntry_sm_sg_d(feventlog,
514
                gate->getOwnerModule()->getId(), gate->getId(), channel->getDisplayString().str());
515
        }
516
    }
517
}
518

    
519
void EventlogFileManager::sputn(const char *s, int n)
520
{
521
    if (isEventLogRecordingEnabled)
522
    {
523
        EventLogWriter::recordLogLine(feventlog, s, n);
524
    }
525
}
526