Project

General

Profile

Statistics
| Branch: | Revision:

root / src / envir / indexedfileoutvectormgr.cc @ e26d3d25

History | View | Annotate | Download (9.69 KB)

1
//==========================================================================
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

    
319