Statistics
| Branch: | Revision:

root / src / envir / eventlogfilemgr.cc @ fbe00e73

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

    
36
USING_NAMESPACE
37

    
38

    
39
Register_PerRunConfigOption(CFGID_EVENTLOG_FILE, "eventlog-file", CFG_FILENAME, "${resultdir}/${configname}-${runnumber}.elog", "Name of the event log file to generate.");
40
Register_PerRunConfigOption(CFGID_EVENTLOG_MESSAGE_DETAIL_PATTERN, "eventlog-message-detail-pattern", CFG_CUSTOM, NULL,
41
        "A list of patterns separated by '|' character which will be used to write "
42
        "message detail information into the event log for each message sent during "
43
        "the simulation. The message detail will be presented in the sequence chart "
44
        "tool. Each pattern starts with an object pattern optionally followed by ':' "
45
        "character and a comma separated list of field patterns. In both "
46
        "patterns and/or/not/* and various field match expressions can be used. "
47
        "The object pattern matches to class name, the field pattern matches to field name by default.\n"
48
        "  EVENTLOG-MESSAGE-DETAIL-PATTERN := ( DETAIL-PATTERN '|' )* DETAIL_PATTERN\n"
49
        "  DETAIL-PATTERN := OBJECT-PATTERN [ ':' FIELD-PATTERNS ]\n"
50
        "  OBJECT-PATTERN := MATCH-EXPRESSION\n"
51
        "  FIELD-PATTERNS := ( FIELD-PATTERN ',' )* FIELD_PATTERN\n"
52
        "  FIELD-PATTERN := MATCH-EXPRESSION\n"
53
        "Examples (enter them without quotes):\n"
54
        "  \"*\": captures all fields of all messages\n"
55
        "  \"*Frame:*Address,*Id\": captures all fields named somethingAddress and somethingId from messages of any class named somethingFrame\n"
56
        "  \"MyMessage:declaredOn(MyMessage)\": captures instances of MyMessage recording the fields declared on the MyMessage class\n"
57
        "  \"*:(not declaredOn(cMessage) and not declaredOn(cNamedObject) and not declaredOn(cObject))\": records user-defined fields from all messages");
58
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..");
59
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");
60

    
61
static va_list empty_va;
62

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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