Project

General

Profile

Statistics
| Branch: | Revision:

root / src / envir / indexedfileoutvectormgr.cc @ e26d3d25

History | View | Annotate | Download (9.69 KB)

1 01873262 Georg Kunz
//==========================================================================
2
//  INDEXEDFILEOUTVECTORMGR.CC - part of
3
//                     OMNeT++/OMNEST
4
//            Discrete System Simulation in C++
5
//
6
//  Members of the following classes:
7
//     cIndexedFileOutputVectorManager
8
//
9
//  Author: Tamas Borbely
10
//
11
//==========================================================================
12
13
/*--------------------------------------------------------------*
14
  Copyright (C) 1992-2008 Andras Varga
15
  Copyright (C) 2006-2008 OpenSim Ltd.
16

17
  This file is distributed WITHOUT ANY WARRANTY. See the file
18
  `license' for details on this and other legal matters.
19
*--------------------------------------------------------------*/
20
21
#include "simkerneldefs.h"
22
23
#include <assert.h>
24
#include <string.h>
25
#include <fstream>
26
#include <errno.h> // SGI
27
#include <algorithm>
28
#include <sys/stat.h>
29
#include "cconfigoption.h"
30
#include "timeutil.h"
31
#include "platmisc.h"
32
#include "cenvir.h"
33
#include "envirbase.h"
34
#include "csimulation.h"
35
#include "regmacros.h"
36
#include "cmodule.h"
37
#include "cstatistic.h"
38
#include "stringutil.h"
39
#include "fileutil.h"
40
#include "unitconversion.h"
41
#include "indexedfileoutvectormgr.h"
42
43
USING_NAMESPACE
44
45
#define INDEX_FILE_VERSION 2
46
#define LL  INT64_PRINTF_FORMAT
47
48
using std::ostream;
49
using std::ofstream;
50
using std::ios;
51
52
Register_PerRunConfigOptionU(CFGID_OUTPUTVECTOR_MEMORY_LIMIT, "output-vectors-memory-limit", "B", DEFAULT_MEMORY_LIMIT, "Total memory that can be used for buffering output vectors. Larger values produce less fragmented vector files (i.e. cause vector data to be grouped into larger chunks), and therefore allow more efficient processing later.");
53
Register_PerObjectConfigOption(CFGID_VECTOR_MAX_BUFFERED_VALUES, "vector-max-buffered-values", CFG_INT, NULL, "For output vectors: the maximum number of values to buffer per vector, before writing out a block into the output vector file. The default is no per-vector limit (i.e. only the total memory limit is in effect)");
54
55
56
#ifdef CHECK
57
#undef CHECK
58
#endif
59
60
#define CHECK(fprintf, fname)    if (fprintf<0) throw cRuntimeError("Cannot write output file `%s'", fname.c_str())
61
#define WARN(msg)       fprintf(stderr,msg)
62
63
64
Register_Class(cIndexedFileOutputVectorManager);
65
66
67
cIndexedFileOutputVectorManager::cIndexedFileOutputVectorManager()
68
  : cFileOutputVectorManager()
69
{
70
    fi = NULL;
71
    memoryUsed = 0;
72
73
    long d = (long) ev.getConfig()->getAsDouble(CFGID_OUTPUTVECTOR_MEMORY_LIMIT);
74
    maxMemoryUsed = (size_t) std::max(d, (long)MIN_BUFFER_MEMORY);
75
}
76
77
void cIndexedFileOutputVectorManager::openIndexFile()
78
{
79
    mkPath(directoryOf(ifname.c_str()).c_str());
80
    fi = fopen(ifname.c_str(),"w");
81
    if (fi==NULL)
82
        throw cRuntimeError("Cannot open index file `%s'",ifname.c_str());
83
84
    // leave blank space for fingerprint
85
    fprintf(fi, "%64s\n", "");
86
}
87
88
void cIndexedFileOutputVectorManager::closeIndexFile()
89
{
90
    if (fi)
91
    {
92
        // write out fingerprint (size and modification date of the vector file)
93
        struct opp_stat_t s;
94
        if (opp_stat(fname.c_str(), &s) == 0)
95
        {
96
            opp_fseek(fi, 0, SEEK_SET);
97
            fprintf(fi, "file %"LL"d %"LL"d", (int64)s.st_size, (int64)s.st_mtime);
98
        }
99
100
        fclose(fi);
101
        fi = NULL;
102
    }
103
}
104
105
static opp_string createIndexFileName(const opp_string fname)
106
{
107
    int len = strlen(fname.c_str());
108
    opp_string ifname;
109
    ifname.reserve(len + 4);
110
    strcpy(ifname.buffer(), fname.c_str());
111
    char *extension = strrchr(ifname.buffer(), '.');
112
    if (!extension)
113
        extension = ifname.buffer()+len;
114
115
    strcpy(extension, ".vci");
116
    return ifname;
117
}
118
119
void cIndexedFileOutputVectorManager::startRun()
120
{
121
    cFileOutputVectorManager::startRun();
122
123
    closeIndexFile();
124
    ifname = createIndexFileName(fname);
125
    removeFile(ifname.c_str(), "old index file");
126
}
127
128
void cIndexedFileOutputVectorManager::endRun()
129
{
130
    if (f!=NULL) {
131
        for (std::vector<sVector*>::iterator it=vectors.begin(); it!=vectors.end(); ++it)
132
            finalizeVector(*it);
133
    }
134
135
    vectors.clear();
136
    cFileOutputVectorManager::endRun();
137
    closeIndexFile();
138
}
139
140
void *cIndexedFileOutputVectorManager::registerVector(const char *modulename, const char *vectorname)
141
{
142
    sVector *vp = (sVector *)cFileOutputVectorManager::registerVector(modulename, vectorname);
143
    vp->maxBufferedSamples = ev.getConfig()->getAsInt(modulename, CFGID_VECTOR_MAX_BUFFERED_VALUES);
144
    if (vp->maxBufferedSamples > 0)
145
        vp->allocateBuffer(vp->maxBufferedSamples);
146
147
    vectors.push_back(vp);
148
    return vp;
149
}
150
151
cFileOutputVectorManager::sVectorData *cIndexedFileOutputVectorManager::createVectorData()
152
{
153
    return new sVector();
154
}
155
156
void cIndexedFileOutputVectorManager::deregisterVector(void *vectorhandle)
157
{
158
    sVector *vp = (sVector *)vectorhandle;
159
    Vectors::iterator newEnd = std::remove(vectors.begin(), vectors.end(), vp);
160
    vectors.erase(newEnd, vectors.end());
161
    finalizeVector(vp);
162
    cFileOutputVectorManager::deregisterVector(vectorhandle);
163
}
164
165
void cIndexedFileOutputVectorManager::initVector(sVectorData *vp)
166
{
167
    cFileOutputVectorManager::initVector(vp);
168
169
    // write vector declaration and vector attributes to the index file too
170
    CHECK(fprintf(fi,"vector %d  %s  %s  %s\n",
171
                  vp->id, QUOTE(vp->modulename.c_str()), QUOTE(vp->vectorname.c_str()), vp->getColumns()),
172
          ifname);
173
    for (opp_string_map::iterator it=vp->attributes.begin(); it!=vp->attributes.end(); it++)
174
        CHECK(fprintf(fi,"attr %s  %s\n", QUOTE(it->first.c_str()), QUOTE(it->second.c_str())),
175
              ifname);
176
}
177
178
179
void cIndexedFileOutputVectorManager::finalizeVector(sVector *vp)
180
{
181
    if (f)
182
    {
183
        if (!vp->buffer.empty())
184
            writeBlock(vp);
185
    }
186
}
187
188
bool cIndexedFileOutputVectorManager::record(void *vectorhandle, simtime_t t, double value)
189
{
190
    sVector *vp = (sVector *)vectorhandle;
191
192
    if (!vp->enabled)
193
        return false;
194
195
    if (vp->intervals.contains(t))
196
    {
197
        if (!vp->initialized)
198
            initVector(vp);
199
200
        sBlock &currentBlock = vp->currentBlock;
201
        eventnumber_t eventNumber = simulation.getEventNumber();
202
        if (currentBlock.count == 0)
203
        {
204
            currentBlock.startTime = t;
205
            currentBlock.startEventNum = eventNumber;
206
        }
207
        currentBlock.endTime = t;
208
        currentBlock.endEventNum = eventNumber;
209
        currentBlock.count++;
210
        currentBlock.min = std::min(currentBlock.min, value);
211
        currentBlock.max = std::max(currentBlock.max, value);
212
        currentBlock.sum += value;
213
        currentBlock.sumSqr += value*value;
214
215
        vp->buffer.push_back(sSample(t, eventNumber, value));
216
        memoryUsed += sizeof(sSample);
217
218
        if (vp->maxBufferedSamples > 0 && (int)vp->buffer.size() >= vp->maxBufferedSamples)
219
            writeBlock(vp);
220
        else if (memoryUsed >= maxMemoryUsed)
221
            writeRecords();
222
223
        return true;
224
    }
225
    return false;
226
}
227
228
void cIndexedFileOutputVectorManager::writeRunData()
229
{
230
    // write run attributes to the vector file
231
    cFileOutputVectorManager::writeRunData();
232
233
    // and to the index file
234
    if (!fi)
235
    {
236
        openIndexFile();
237
        CHECK(fprintf(fi, "version %d\n", INDEX_FILE_VERSION), ifname);
238
    }
239
240
    run.writeRunData(fi, ifname);
241
}
242
243
// empties all buffer
244
void cIndexedFileOutputVectorManager::writeRecords()
245
{
246
    for (Vectors::iterator it = vectors.begin(); it != vectors.end(); ++it)
247
    {
248
        if (!(*it)->buffer.empty()) // TODO: size() > configured limit
249
            writeBlock(*it);
250
    }
251
}
252
253
void cIndexedFileOutputVectorManager::writeBlock(sVector *vp)
254
{
255
    assert(f!=NULL);
256
    assert(vp!=NULL);
257
    assert(!vp->buffer.empty());
258
259
    static char buff[64];
260
261
    sBlock &currentBlock = vp->currentBlock;
262
    currentBlock.offset = opp_ftell(f);
263
264
    if (vp->recordEventNumbers)
265
    {
266
        for (std::vector<sSample>::iterator it = vp->buffer.begin(); it != vp->buffer.end(); ++it)
267
            CHECK(fprintf(f,"%d\t%"LL"d\t%s\t%.*g\n", vp->id, it->eventNumber, SIMTIME_TTOA(buff, it->simtime), prec, it->value), fname);
268
    }
269
    else
270
    {
271
        for (std::vector<sSample>::iterator it = vp->buffer.begin(); it != vp->buffer.end(); ++it)
272
            CHECK(fprintf(f,"%d\t%s\t%.*g\n", vp->id, SIMTIME_TTOA(buff, it->simtime), prec, it->value), fname);
273
    }
274
275
    currentBlock.size = opp_ftell(f) - currentBlock.offset;
276
    writeBlockToIndexFile(vp);
277
278
    memoryUsed -= vp->buffer.size()*sizeof(sSample);
279
    vp->buffer.clear();
280
}
281
282
void cIndexedFileOutputVectorManager::writeBlockToIndexFile(sVector *vp)
283
{
284
    assert(f!=NULL);
285
    assert(fi!=NULL);
286
287
    static char buff1[64], buff2[64];
288
    sBlock &block = vp->currentBlock;
289
290
    if (block.count > 0)
291
    {
292
        // make sure that the offsets refered by the index file are exists in the vector file
293
        // so the index can be used to access the vector file while it is being written
294
        fflush(f);
295
296
        if (vp->recordEventNumbers)
297
        {
298
            CHECK(fprintf(fi, "%d\t%"LL"d %"LL"d %"LL"d %"LL"d %s %s %ld %.*g %.*g %.*g %.*g\n",
299
                        vp->id, block.offset, block.size,
300
                        block.startEventNum, block.endEventNum,
301
                        SIMTIME_TTOA(buff1, block.startTime), SIMTIME_TTOA(buff2, block.endTime),
302
                        block.count, prec, block.min, prec, block.max, prec, block.sum, prec, block.sumSqr)
303
                  , ifname);
304
        }
305
        else
306
        {
307
            CHECK(fprintf(fi, "%d\t%"LL"d %"LL"d %s %s %ld %.*g %.*g %.*g %.*g\n",
308
                        vp->id, block.offset, block.size,
309
                        SIMTIME_TTOA(buff1, block.startTime), SIMTIME_TTOA(buff2, block.endTime),
310
                        block.count, prec, block.min, prec, block.max, prec, block.sum, prec, block.sumSqr)
311
                  , ifname);
312
        }
313
314
        fflush(fi);
315
        block.reset();
316
    }
317
}
318