/*
* dump-metrics.c --
*
* Operations to compute and dump some MIB metrics.
*
* Copyright (c) 2000 Frank Strauss, Technical University of Braunschweig.
* Copyright (c) 2000 J. Schoenwaelder, Technical University of Braunschweig.
* Copyright (c) 2002 J. Schoenwaelder, University of Osnabrueck.
* Copyright (c) 2004 J. Schoenwaelder, International University Bremen.
*
* See the file "COPYING" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
* @(#) $Id: dump-metrics.c 8090 2008-04-18 12:56:29Z strauss $
*/
/*
# revisions
# imports
# row creations:
# count node references in notification definitions
*/
#include <config.h>
#include <stdio.h>
#include <string.h>
#include "smi.h"
#include "smidump.h"
static int raw = 0;
static int silent = 0;
typedef struct BasetypeCounter {
unsigned long total;
unsigned long unknown;
unsigned long integer32;
unsigned long octetstring;
unsigned long objectidentifier;
unsigned long unsigned32;
unsigned long integer64;
unsigned long unsigned64;
unsigned long float32;
unsigned long float64;
unsigned long float128;
unsigned long enums;
unsigned long bits;
unsigned long pointer;
} BasetypeCounter;
typedef struct StatusCounter {
unsigned long total;
unsigned long current;
unsigned long deprecated;
unsigned long obsolete;
} StatusCounter;
typedef struct AccessCounter {
unsigned long total;
unsigned long noaccess;
unsigned long notify;
unsigned long readonly;
unsigned long readwrite;
} AccessCounter;
typedef struct IndexCounter {
unsigned long total;
unsigned long index;
unsigned long augment;
unsigned long reorder;
unsigned long sparse;
unsigned long expand;
} IndexCounter;
typedef struct IndexLenCounter {
unsigned long total;
unsigned long length[11];
} IndexLenCounter;
typedef struct TableLenCounter {
unsigned long total;
unsigned long length[81];
} TableLenCounter;
typedef struct ScalarLenCounter {
unsigned long total;
unsigned long length[81];
} ScalarLenCounter;
typedef struct IndexComplexityCounter {
unsigned long total;
unsigned long complexity[100];
} IndexComplexityCounter;
typedef struct LengthCounter {
unsigned long total;
unsigned long descr;
unsigned long descr_len;
unsigned long reference;
unsigned long reference_len;
unsigned long units;
unsigned long units_len;
unsigned long format;
unsigned long format_len;
} LengthCounter;
typedef struct RowStatusCounter {
unsigned long basetables;
unsigned long rowstatus;
unsigned long storagetype;
} RowStatusCounter;
typedef struct Metrics {
BasetypeCounter basetypesColumns;
BasetypeCounter basetypesScalars;
BasetypeCounter basetypesAll;
StatusCounter statusTypes;
StatusCounter statusTables;
StatusCounter statusColumns;
StatusCounter statusScalars;
StatusCounter statusNotifications;
StatusCounter statusGroups;
StatusCounter statusCompliances;
StatusCounter statusAll;
AccessCounter accessColumns;
AccessCounter accessScalars;
AccessCounter accessAll;
IndexCounter indexTables;
IndexLenCounter indexLenTables;
IndexComplexityCounter indexComplexity;
TableLenCounter tableLength;
ScalarLenCounter scalarLength;
LengthCounter lengthTypes;
LengthCounter lengthTables;
LengthCounter lengthRows;
LengthCounter lengthColumns;
LengthCounter lengthScalars;
LengthCounter lengthNotifications;
LengthCounter lengthAll;
} Metrics;
typedef struct UsageCounter {
char *module;
char *name;
unsigned count;
struct UsageCounter *nextPtr;
} UsageCounter;
static UsageCounter *typeList = NULL;
static UsageCounter *extTypeList = NULL;
static UsageCounter *extNodeList = NULL;
static UsageCounter *extModuleList = NULL;
static UsageCounter *indexComplexityList = NULL;
#define INCR_NODE 0x01
#define INCR_TYPE 0x02
static char*
getDateString(time_t t)
{
static char *s = NULL;
struct tm *tm;
if (s) xfree(s);
tm = gmtime(&t);
smiAsprintf(&s, "%04d-%02d-%02d",
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
return s;
}
static char*
language(SmiLanguage language)
{
return
(language == SMI_LANGUAGE_UNKNOWN) ? "-" :
(language == SMI_LANGUAGE_SMIV1) ? "SMIv1" :
(language == SMI_LANGUAGE_SMIV2) ? "SMIv2" :
(language == SMI_LANGUAGE_SMING) ? "SMIng" :
"-";
}
static int
calcSize(SmiModule *smiModule)
{
SmiNode *smiNode;
SmiType *smiType;
int size = 0;
for (smiType = smiGetFirstType(smiModule);
smiType;
smiType = smiGetNextType(smiType)) {
if (smiType->name) {
size++;
}
}
for (smiNode = smiGetFirstNode(smiModule, SMI_NODEKIND_ANY);
smiNode;
smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_ANY)) {
switch (smiNode->nodekind) {
case SMI_NODEKIND_SCALAR:
case SMI_NODEKIND_COLUMN:
case SMI_NODEKIND_NOTIFICATION:
size++;
break;
default:
break;
}
}
return size;
}
typedef void (*ForEachIndexFunc) (FILE *f, SmiNode *groupNode, SmiNode *smiNode, void *data);
static void
foreachIndexDo(FILE *f, SmiNode *smiNode, ForEachIndexFunc func, void *data)
{
SmiNode *indexNode = NULL, *iNode;
SmiElement *smiElement;
switch (smiNode->indexkind) {
case SMI_INDEX_INDEX:
case SMI_INDEX_REORDER:
indexNode = smiNode;
break;
case SMI_INDEX_EXPAND: /* TODO: we have to do more work here! */
break;
case SMI_INDEX_AUGMENT:
case SMI_INDEX_SPARSE:
indexNode = smiGetRelatedNode(smiNode);
break;
case SMI_INDEX_UNKNOWN:
break;
}
if (indexNode) {
for (smiElement = smiGetFirstElement(indexNode);
smiElement; smiElement = smiGetNextElement(smiElement)) {
iNode = smiGetElementNode(smiElement);
if (iNode) {
(func) (f, smiNode, iNode, data);
}
}
}
}
static UsageCounter*
incrUsageCounter(UsageCounter *uCntList, char *module, char *name, int incr)
{
UsageCounter *uCnt;
for (uCnt = uCntList; uCnt; uCnt = uCnt->nextPtr) {
if (strcmp(uCnt->module, module) == 0
&& (! name || strcmp(uCnt->name, name) == 0)) {
break;
}
}
if (! uCnt) {
uCnt = (UsageCounter *) xmalloc(sizeof(UsageCounter));
uCnt->module = xstrdup(module);
uCnt->name = name ? xstrdup(name) : NULL;
uCnt->count = 0;
uCnt->nextPtr = uCntList;
uCntList = uCnt;
}
uCnt->count += incr;
return uCntList;
}
static void
incrTypeAndNodeUsageCounter(SmiModule *smiModule, SmiNode *smiNode, int flags)
{
SmiType *smiType;
char *extModule;
/*
* First check whether the node is external. If yes, increment the
* external node counter and we are done.
*/
extModule = smiGetNodeModule(smiNode)->name;
if (extModule
&& strcmp(extModule, smiModule->name) != 0) {
if (flags & INCR_NODE) {
extNodeList = incrUsageCounter(extNodeList,
extModule, smiNode->name, 1);
extModuleList = incrUsageCounter(extModuleList, extModule, NULL, 1);
}
return;
}
/*
* Next, check whether the type of the node is external. If yes,
* increment the external type counter and we are done. Do not
* count base types (that is types that have no parent type).
*/
smiType = smiGetNodeType(smiNode);
if (! smiType) {
return;
}
if (smiType->name && smiGetParentType(smiType)) {
char *extModule = smiGetTypeModule(smiType)->name;
if (extModule /* && *extModule */
&& strcmp(extModule, smiModule->name) != 0) {
if (flags & INCR_TYPE) {
extTypeList = incrUsageCounter(extTypeList,
extModule, smiType->name, 1);
extModuleList = incrUsageCounter(extModuleList, extModule, NULL, 1);
}
}
}
/*
* Finally, count the type name (whether external or not does not
* matter here nor does it matter whether it is a base type or
* not).
*/
if (! smiType->name && smiGetParentType(smiType)) {
smiType = smiGetParentType(smiType);
}
typeList = incrUsageCounter(typeList, smiGetTypeModule(smiType)->name,
smiType->name, 1);
}
static void
incrIndexComplexityCounter(SmiModule *smiModule, SmiNode *smiNode, int complexity)
{
indexComplexityList = incrUsageCounter(indexComplexityList,
smiModule->name, smiNode->name, complexity);
}
static int
cmp(const void *va, const void *vb)
{
UsageCounter **a = (UsageCounter **) va;
UsageCounter **b = (UsageCounter **) vb;
if ((*a)->count > (*b)->count) return -1;
if ((*a)->count < (*b)->count) return 1;
if ((*a)->module && (*b)->module) {
int x = strcmp((*a)->module, (*b)->module);
if (x) return x;
}
if ((*a)->name && (*b)->name) {
int x = strcmp((*a)->name, (*b)->name);
if (x) return x;
}
return 0;
}
static int
fprintRevisions(FILE *f, int modLen, SmiRevision *smiRevision,
SmiModule *smiModule, int size)
{
int n = 0;
if (smiRevision) {
n = fprintRevisions(f, modLen,
smiGetNextRevision(smiRevision), smiModule, -1);
fprintf(f, "%-*s %7s ", modLen, smiModule->name,
(size >= 0) ? language(smiModule->language) : "-");
if (size >= 0) {
fprintf(f, "%4d", size);
} else {
fprintf(f, " -");
}
fprintf(f, " %3d %s\n", n, getDateString(smiRevision->date));
n++;
}
if (!smiRevision && size >= 0) {
fprintf(f, "%-*s %7s ", modLen, smiModule->name,
language(smiModule->language));
fprintf(f, "%4d", size);
fprintf(f, " - ----------\n");
}
return n;
}
static void
fprintRevision(FILE *f, int modc, SmiModule **modv)
{
int i;
int modLen = 8;
for (i = 0; i < modc; i++) {
if (modLen < strlen(modv[i]->name)) {
modLen = strlen(modv[i]->name);
}
}
fprintf(f, "%-*s LANGUAGE SIZE REVISION DATE\n", modLen, "MODULE");
for (i = 0; i < modc; i++) {
fprintRevisions(f, modLen, smiGetFirstRevision(modv[i]),
modv[i], calcSize(modv[i]));
}
fprintf(f, "\n");
}
static void
fprintTypeUsage(FILE *f, UsageCounter *typeUsageList)
{
UsageCounter *uCnt;
int modLen = 8, nameLen = 8;
unsigned total = 0;
int i, cnt = 0;
UsageCounter **sortCnt;
/* should be sorted */
for (uCnt = typeUsageList, cnt = 0; uCnt; uCnt = uCnt->nextPtr, cnt++) {
if (modLen < strlen(uCnt->module)) {
modLen = strlen(uCnt->module);
}
if (nameLen < strlen(uCnt->name)) {
nameLen = strlen(uCnt->name);
}
total += uCnt->count;
}
if (cnt == 0) {
return;
}
/* create an array for a quick qsort */
sortCnt = (UsageCounter **) xmalloc(cnt * sizeof(UsageCounter *));
memset(sortCnt, 0, cnt * sizeof(UsageCounter *));
for (uCnt = typeUsageList, i = 0; uCnt; uCnt = uCnt->nextPtr, i++) {
sortCnt[i] = uCnt;
}
qsort(sortCnt, cnt, sizeof(UsageCounter *), cmp);
if (! silent) {
fputs(
"# The following table shows the distribution of the number of references\n"
"# to defined types (including base types) in the set of loaded MIB\n"
"# modules.\n"
"\n", f);
}
fprintf(f, "%-*s %-*s USAGE\n", modLen, "MODULE", nameLen, "TYPE");
for (i = 0; i < cnt; i++) {
fprintf(f, "%-*s %-*s ",
modLen, sortCnt[i]->module, nameLen, sortCnt[i]->name);
if (raw) {
fprintf(f, "%8u\n", sortCnt[i]->count);
} else {
fprintf(f, "%6.1f%%\n", (double) sortCnt[i]->count * 100 / total);
}
}
xfree(sortCnt);
}
static void
fprintExtTypeUsage(FILE *f, UsageCounter *typeUsageList)
{
UsageCounter *uCnt;
int modLen = 8, nameLen = 8;
unsigned total = 0;
int i, cnt = 0;
UsageCounter **sortCnt;
/* should be sorted */
for (uCnt = typeUsageList, cnt = 0; uCnt; uCnt = uCnt->nextPtr, cnt++) {
if (modLen < strlen(uCnt->module)) {
modLen = strlen(uCnt->module);
}
if (nameLen < strlen(uCnt->name)) {
nameLen = strlen(uCnt->name);
}
total += uCnt->count;
}
if (cnt == 0) {
return;
}
/* create an array for a quick qsort */
sortCnt = (UsageCounter **) xmalloc(cnt * sizeof(UsageCounter *));
memset(sortCnt, 0, cnt * sizeof(UsageCounter *));
for (uCnt = typeUsageList, i = 0; uCnt; uCnt = uCnt->nextPtr, i++) {
sortCnt[i] = uCnt;
}
qsort(sortCnt, cnt, sizeof(UsageCounter *), cmp);
if (! silent) {
fputs(
"# The following table shows the distribution of the number of references\n"
"# to externally defined types (excluding base types) in the set of loaded\n"
"# MIB modules.\n"
"\n", f);
}
fprintf(f, "%-*s %-*s EXT-USAGE\n", modLen, "MODULE", nameLen, "TYPE");
for (i = 0; i < cnt; i++) {
fprintf(f, "%-*s %-*s ",
modLen, sortCnt[i]->module, nameLen, sortCnt[i]->name);
if (raw) {
fprintf(f, "%8u\n", sortCnt[i]->count);
} else {
fprintf(f, "%6.1f%%\n", (double) sortCnt[i]->count * 100 / total);
}
}
xfree(sortCnt);
}
static void
fprintExtNodeUsage(FILE *f, UsageCounter *typeUsageList)
{
UsageCounter *uCnt;
int modLen = 8, nameLen = 8;
unsigned total = 0;
int i, cnt = 0;
UsageCounter **sortCnt;
/* should be sorted */
for (uCnt = typeUsageList, cnt = 0; uCnt; uCnt = uCnt->nextPtr, cnt++) {
if (modLen < strlen(uCnt->module)) {
modLen = strlen(uCnt->module);
}
if (nameLen < strlen(uCnt->name)) {
nameLen = strlen(uCnt->name);
}
total += uCnt->count;
}
if (cnt == 0) {
return;
}
/* create an array for a quick qsort */
sortCnt = (UsageCounter **) xmalloc(cnt * sizeof(UsageCounter *));
memset(sortCnt, 0, cnt * sizeof(UsageCounter *));
for (uCnt = typeUsageList, i = 0; uCnt; uCnt = uCnt->nextPtr, i++) {
sortCnt[i] = uCnt;
}
qsort(sortCnt, cnt, sizeof(UsageCounter *), cmp);
if (! silent) {
fputs(
"# The following table shows the distribution of the number of references\n"
"# to externally defined nodes in the set of loaded MIB modules.\n"
"\n", f);
}
fprintf(f, "%-*s %-*s EXT-USAGE\n", modLen, "MODULE", nameLen, "NODE");
for (i = 0; i < cnt; i++) {
fprintf(f, "%-*s %-*s ",
modLen, sortCnt[i]->module, nameLen, sortCnt[i]->name);
if (raw) {
fprintf(f, "%8u\n", sortCnt[i]->count);
} else {
fprintf(f, "%6.1f%%\n", (double) sortCnt[i]->count * 100 / total);
}
}
xfree(sortCnt);
}
static void
fprintModuleUsage(FILE *f, UsageCounter *modUsageList)
{
UsageCounter *uCnt;
int modLen = 8;
unsigned total = 0;
int i, cnt = 0;
UsageCounter **sortCnt;
/* should be sorted */
for (uCnt = modUsageList, cnt = 0; uCnt; uCnt = uCnt->nextPtr, cnt++) {
if (modLen < strlen(uCnt->module)) {
modLen = strlen(uCnt->module);
}
total += uCnt->count;
}
if (cnt == 0) {
return;
}
/* create an array for a quick qsort */
sortCnt = (UsageCounter **) xmalloc(cnt * sizeof(UsageCounter *));
memset(sortCnt, 0, cnt * sizeof(UsageCounter *));
for (uCnt = modUsageList, i = 0; uCnt; uCnt = uCnt->nextPtr, i++) {
sortCnt[i] = uCnt;
}
qsort(sortCnt, cnt, sizeof(UsageCounter *), cmp);
if (! silent) {
fputs(
"# The following table shows the distribution of the number of references\n"
"# to externally defined items (such as types or objects) accumulated by\n"
"# the defining MIB module in the set of loaded MIB modules.\n"
"\n", f);
}
fprintf(f, "%-*s EXT-USAGE\n", modLen, "MODULE");
for (i = 0; i < cnt; i++) {
fprintf(f, "%-*s ", modLen, sortCnt[i]->module);
if (raw) {
fprintf(f, "%8u\n", sortCnt[i]->count);
} else {
fprintf(f, "%6.1f%%\n", (double) sortCnt[i]->count * 100 / total);
}
}
xfree(sortCnt);
}
static void
fprintIndexComplexity(FILE *f, UsageCounter *modUsageList)
{
UsageCounter *uCnt;
int modLen = 8;
int nameLen = 8;
unsigned total = 0;
int i, cnt = 0;
UsageCounter **sortCnt;
/* should be sorted */
for (uCnt = modUsageList, cnt = 0; uCnt; uCnt = uCnt->nextPtr, cnt++) {
if (modLen < strlen(uCnt->module)) {
modLen = strlen(uCnt->module);
}
if (nameLen < strlen(uCnt->name)) {
nameLen = strlen(uCnt->name);
}
total += uCnt->count;
}
if (cnt == 0) {
return;
}
/* create an array for a quick qsort */
sortCnt = (UsageCounter **) xmalloc(cnt * sizeof(UsageCounter *));
memset(sortCnt, 0, cnt * sizeof(UsageCounter *));
for (uCnt = modUsageList, i = 0; uCnt; uCnt = uCnt->nextPtr, i++) {
sortCnt[i] = uCnt;
}
qsort(sortCnt, cnt, sizeof(UsageCounter *), cmp);
if (! silent) {
fputs(
"# The following table shows the distribution of the index complexity\n"
"# in the set of loaded MIB modules.\n"
"\n", f);
}
fprintf(f, "%-*s %-*s COMPLEXITY\n", modLen, "MODULE", nameLen, "TABLE");
for (i = 0; i < cnt; i++) {
fprintf(f, "%-*s %-*s ", modLen, sortCnt[i]->module, nameLen, sortCnt[i]->name);
if (raw) {
fprintf(f, "%8u\n", sortCnt[i]->count);
} else {
fprintf(f, "%6.1f%%\n", (double) sortCnt[i]->count);
}
}
xfree(sortCnt);
}
static void
freeUsageCounter(UsageCounter *usageCounterList)
{
UsageCounter *uCnt, *p;
for (uCnt = usageCounterList; uCnt; ) {
p = uCnt, uCnt = uCnt->nextPtr;
xfree(p->module);
xfree(p->name);
xfree(p);
}
}
static void
incrBasetypeCounter(BasetypeCounter *basetypeCounter, SmiNode *smiNode)
{
SmiType *smiType;
smiType = smiGetNodeType(smiNode);
if (smiType) {
basetypeCounter->total++;
switch (smiType->basetype) {
case SMI_BASETYPE_UNKNOWN:
basetypeCounter->unknown++;
break;
case SMI_BASETYPE_INTEGER32:
basetypeCounter->integer32++;
break;
case SMI_BASETYPE_OCTETSTRING:
basetypeCounter->octetstring++;
break;
case SMI_BASETYPE_OBJECTIDENTIFIER:
basetypeCounter->objectidentifier++;
break;
case SMI_BASETYPE_UNSIGNED32:
basetypeCounter->unsigned32++;
break;
case SMI_BASETYPE_INTEGER64:
basetypeCounter->integer64++;
break;
case SMI_BASETYPE_UNSIGNED64:
basetypeCounter->unsigned64++;
break;
case SMI_BASETYPE_FLOAT32:
basetypeCounter->float32++;
break;
case SMI_BASETYPE_FLOAT64:
basetypeCounter->float64++;
break;
case SMI_BASETYPE_FLOAT128:
basetypeCounter->float128++;
break;
case SMI_BASETYPE_ENUM:
basetypeCounter->enums++;
break;
case SMI_BASETYPE_BITS:
basetypeCounter->bits++;
break;
case SMI_BASETYPE_POINTER:
basetypeCounter->pointer++;
break;
}
}
}
static void
incrStatusCounter(StatusCounter *cnt, SmiStatus smiStatus)
{
cnt->total++;
switch (smiStatus) {
case SMI_STATUS_CURRENT:
case SMI_STATUS_MANDATORY:
case SMI_STATUS_OPTIONAL:
cnt->current++;
break;
case SMI_STATUS_DEPRECATED:
cnt->deprecated++;
break;
case SMI_STATUS_OBSOLETE:
cnt->obsolete++;
break;
case SMI_STATUS_UNKNOWN:
break;
}
}
static void
incrAccessCounter(AccessCounter *cnt, SmiAccess smiAccess)
{
cnt->total++;
switch (smiAccess) {
case SMI_ACCESS_NOT_ACCESSIBLE:
cnt->noaccess++;
break;
case SMI_ACCESS_NOTIFY:
cnt->notify++;
break;
case SMI_ACCESS_READ_ONLY:
cnt->readonly++;
break;
case SMI_ACCESS_READ_WRITE:
cnt->readwrite++;
break;
case SMI_ACCESS_INSTALL:
case SMI_ACCESS_INSTALL_NOTIFY:
case SMI_ACCESS_REPORT_ONLY:
case SMI_ACCESS_UNKNOWN:
case SMI_ACCESS_NOT_IMPLEMENTED:
case SMI_ACCESS_EVENT_ONLY:
break;
}
}
static void
incrIndexCounter(IndexCounter *cnt, SmiIndexkind indexkind)
{
cnt->total++;
switch (indexkind) {
case SMI_INDEX_INDEX:
cnt->index++;
break;
case SMI_INDEX_AUGMENT:
cnt->augment++;
break;
case SMI_INDEX_REORDER:
cnt->reorder++;
break;
case SMI_INDEX_SPARSE:
cnt->sparse++;
break;
case SMI_INDEX_EXPAND:
cnt->expand++;
break;
case SMI_INDEX_UNKNOWN:
break;
}
}
static void
incrIndexLenCounter(IndexLenCounter *cnt, int len)
{
cnt->total++;
if (len < sizeof(cnt->length)/sizeof(cnt->length[0])) {
cnt->length[len]++;
} else {
fprintf(stderr, "smidump: index len overflow: %d\n", len);
}
}
static void
incrTableLenCounter(TableLenCounter *cnt, int len)
{
cnt->total++;
if (len < sizeof(cnt->length)/sizeof(cnt->length[0])) {
cnt->length[len]++;
} else {
fprintf(stderr, "smidump: table len overflow: %d\n", len);
}
}
static void
incrIndexComplexityMetric(IndexComplexityCounter *cnt, int cmplx)
{
cnt->total++;
if (cmplx < sizeof(cnt->complexity)/sizeof(cnt->complexity[0])) {
cnt->complexity[cmplx]++;
} else {
fprintf(stderr, "smidump: index complexity overflow: %d\n", cmplx);
}
}
static void
incrLengthCounter(LengthCounter *cnt, char *description, char *reference,
char *units, char *format)
{
cnt->total++;
if (description) {
cnt->descr++;
cnt->descr_len += strlen(description);
}
if (reference) {
cnt->reference++;
cnt->reference_len += strlen(reference);
}
if (units) {
cnt->units++;
cnt->units_len += strlen(units);
}
if (format) {
cnt->format++;
cnt->format_len += strlen(format);
}
}
static void
incrRowStatusCounter(SmiNode *rowNode)
{
SmiNode *smiNode;
SmiType *smiType;
SmiModule *smiModule;
for (smiNode = smiGetFirstChildNode(rowNode);
smiNode;
smiNode = smiGetNextChildNode(smiNode)) {
smiType = smiGetNodeType(smiNode);
if (smiType && smiType->name) {
smiModule = smiGetTypeModule(smiType);
if (smiModule && smiModule->name
&& strcmp(smiType->name, "RowStatus") == 0
&& strcmp(smiModule->name, "SNMPv2-TC") == 0) {
break;
}
}
}
if (smiNode) {
#if 0
fprintf(stderr, "** %s\t%s\t%s\n", rowNode->name,
smiNode->name, smiType->name);
/* xxx count rows indexed by ifIndex, InterfaceIndex, InterfaceIndexOrZero, ... */
#endif
}
}
static void
count(FILE *f, SmiNode *row, SmiNode *col, void *data)
{
int *cnt = (int *) data;
(*cnt)++;
}
static void
complexity(FILE *f, SmiNode *row, SmiNode *col, void *data)
{
int *cmplx = (int *) data;
SmiType *smiType;
unsigned long min, max;
smiType = smiGetNodeType(col);
if (! smiType) {
return;
}
switch (smiType->basetype) {
case SMI_BASETYPE_INTEGER32:
case SMI_BASETYPE_UNSIGNED32:
case SMI_BASETYPE_ENUM:
*cmplx += 1;
break;
case SMI_BASETYPE_OCTETSTRING:
case SMI_BASETYPE_OBJECTIDENTIFIER:
case SMI_BASETYPE_BITS:
*cmplx += 2;
min = smiGetMinSize(smiType);
max = smiGetMaxSize(smiType);
if (min != max) {
*cmplx += 1;
}
break;
default: /* ignore everything else */
break;
}
}
static void
yadayada(FILE *f, SmiNode *row, SmiNode *col, void *data)
{
SmiModule *smiModule = (SmiModule *) data;
int flags = 0;
if (col->access == SMI_ACCESS_NOT_ACCESSIBLE) {
flags |= INCR_TYPE;
}
flags |= INCR_NODE;
incrTypeAndNodeUsageCounter(smiModule, col, flags);
}
static void
addMetrics(Metrics *metrics, SmiModule *smiModule)
{
SmiNode *smiNode;
SmiType *smiType;
size_t len;
for (smiNode = smiGetFirstNode(smiModule, SMI_NODEKIND_ANY);
smiNode;
smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_ANY)) {
len = smiNode->description ? strlen(smiNode->description) : 0;
switch (smiNode->nodekind) {
case SMI_NODEKIND_TABLE:
incrStatusCounter(&metrics->statusTables, smiNode->status);
incrStatusCounter(&metrics->statusAll, smiNode->status);
incrLengthCounter(&metrics->lengthTables,
smiNode->description, smiNode->reference,
smiNode->units, smiNode->format);
incrLengthCounter(&metrics->lengthAll,
smiNode->description, smiNode->reference,
smiNode->units, smiNode->format);
break;
case SMI_NODEKIND_ROW:
incrIndexCounter(&metrics->indexTables, smiNode->indexkind);
incrLengthCounter(&metrics->lengthRows,
smiNode->description, smiNode->reference,
smiNode->units, smiNode->format);
incrLengthCounter(&metrics->lengthAll,
smiNode->description, smiNode->reference,
smiNode->units, smiNode->format);
incrRowStatusCounter(smiNode);
{
int cnt = 0;
foreachIndexDo(NULL, smiNode, count, &cnt);
incrIndexLenCounter(&metrics->indexLenTables, cnt);
foreachIndexDo(NULL, smiNode, yadayada, smiModule);
}
{
int cmplx = 0;
foreachIndexDo(NULL, smiNode, complexity, &cmplx);
incrIndexComplexityCounter(smiModule, smiNode, cmplx);
incrIndexComplexityMetric(&metrics->indexComplexity, cmplx);
}
/* count the childs ... */
{
SmiModule *smiModule = smiGetModule("SNMPv2-TC");
SmiNode *childNode;
SmiType *rowStatus = smiGetType(smiModule, "RowStatus");
SmiType *storageType = smiGetType(smiModule, "StorageType");
/* include index elements not in table */
int n = 0;
for (childNode = smiGetFirstChildNode(smiNode);
childNode;
childNode = smiGetNextChildNode(childNode)) {
n++;
if (rowStatus == smiGetNodeType(childNode)) {
fprintf(stderr, "**** GEEEEEE - ROWSTATUS\n");
}
if (storageType == smiGetNodeType(childNode)) {
fprintf(stderr, "**** GEEEEEE - STORAGETYPE\n");
}
}
incrTableLenCounter(&metrics->tableLength, n);
}
break;
case SMI_NODEKIND_COLUMN:
incrBasetypeCounter(&metrics->basetypesColumns, smiNode);
incrBasetypeCounter(&metrics->basetypesAll, smiNode);
incrStatusCounter(&metrics->statusColumns, smiNode->status);
incrStatusCounter(&metrics->statusAll, smiNode->status);
incrAccessCounter(&metrics->accessColumns, smiNode->access);
incrAccessCounter(&metrics->accessAll, smiNode->access);
incrLengthCounter(&metrics->lengthColumns,
smiNode->description, smiNode->reference,
smiNode->units, smiNode->format);
incrLengthCounter(&metrics->lengthAll,
smiNode->description, smiNode->reference,
smiNode->units, smiNode->format);
incrTypeAndNodeUsageCounter(smiModule, smiNode, INCR_TYPE);
break;
case SMI_NODEKIND_SCALAR:
incrBasetypeCounter(&metrics->basetypesScalars, smiNode);
incrBasetypeCounter(&metrics->basetypesAll, smiNode);
incrStatusCounter(&metrics->statusScalars, smiNode->status);
incrStatusCounter(&metrics->statusAll, smiNode->status);
incrAccessCounter(&metrics->accessScalars, smiNode->access);
incrAccessCounter(&metrics->accessAll, smiNode->access);
incrLengthCounter(&metrics->lengthScalars,
smiNode->description, smiNode->reference,
smiNode->units, smiNode->format);
incrLengthCounter(&metrics->lengthAll,
smiNode->description, smiNode->reference,
smiNode->units, smiNode->format);
incrTypeAndNodeUsageCounter(smiModule, smiNode, INCR_TYPE);
break;
case SMI_NODEKIND_NOTIFICATION:
incrStatusCounter(&metrics->statusNotifications, smiNode->status);
incrStatusCounter(&metrics->statusAll, smiNode->status);
incrLengthCounter(&metrics->lengthNotifications,
smiNode->description, smiNode->reference,
smiNode->units, smiNode->format);
incrLengthCounter(&metrics->lengthAll,
smiNode->description, smiNode->reference,
smiNode->units, smiNode->format);
break;
case SMI_NODEKIND_GROUP:
incrStatusCounter(&metrics->statusGroups, smiNode->status);
incrStatusCounter(&metrics->statusAll, smiNode->status);
break;
case SMI_NODEKIND_COMPLIANCE:
incrStatusCounter(&metrics->statusCompliances, smiNode->status);
incrStatusCounter(&metrics->statusAll, smiNode->status);
break;
}
}
for (smiType = smiGetFirstType(smiModule);
smiType;
smiType = smiGetNextType(smiType)) {
/*
* Ignore all types with empty descriptions coming from the
* "SNMPv2-SMI" module since they are not really defined
* types but part of the language itself.
*/
if (! smiType->description) {
SmiModule *m = smiGetTypeModule(smiType);
if (m && strcmp(m->name, "SNMPv2-SMI") == 0) {
continue;
}
}
incrStatusCounter(&metrics->statusTypes, smiType->status);
incrStatusCounter(&metrics->statusAll, smiType->status);
incrLengthCounter(&metrics->lengthTypes,
smiType->description, smiType->reference,
smiType->units, smiType->format);
incrLengthCounter(&metrics->lengthAll,
smiType->description, smiType->reference,
smiType->units, smiType->format);
}
}
static void
fprintBasetypeCounter(FILE *f, BasetypeCounter *cnt, const char *s)
{
if (!s && ! cnt) {
if (! silent) {
fputs(
"# The following table shows the basetype usage distribution in the\n"
"# set of loaded MIB modules.\n"
"\n", f);
}
fprintf(f, "%-10s Int32 Uns32 Int64 Uns64 OctSt ObjId Enums Bits Flo32 Flo64 Flo128\n",
"CATEGORY");
return;
}
if (raw) {
fprintf(f, "%-10s %5lu %5lu %5lu %5lu %5lu %5lu %5lu %5lu %5lu %5lu %5lu\n", s,
cnt->integer32, cnt->unsigned32,
cnt->integer64, cnt->unsigned64,
cnt->octetstring, cnt->objectidentifier,
cnt->enums, cnt->bits,
cnt->float32, cnt->float64, cnt->float128);
} else {
fprintf(f, "%-10s %4.1f%% %4.1f%% %4.1f%% %4.1f%% %4.1f%% %4.1f%% %4.1f%% %4.1f%% %4.1f%% %4.1f%% %4.1f%%\n", s,
cnt->total ? (double) cnt->integer32 * 100 / cnt->total : 0,
cnt->total ? (double) cnt->unsigned32 * 100 / cnt->total : 0,
cnt->total ? (double) cnt->integer64 * 100 / cnt->total : 0,
cnt->total ? (double) cnt->unsigned64 * 100 / cnt->total : 0,
cnt->total ? (double) cnt->octetstring * 100 / cnt->total : 0,
cnt->total ? (double) cnt->objectidentifier * 100 / cnt->total : 0,
cnt->total ? (double) cnt->enums * 100 / cnt->total : 0,
cnt->total ? (double) cnt->bits * 100 / cnt->total : 0,
cnt->total ? (double) cnt->float32 * 100 / cnt->total : 0,
cnt->total ? (double) cnt->float64 * 100 / cnt->total : 0,
cnt->total ? (double) cnt->float128 * 100 / cnt->total : 0);
}
}
static void
fprintStatusCounter(FILE *f, StatusCounter *cnt, char *s)
{
if (!s || !cnt) {
if (! silent) {
fputs(
"# The following table shows the status distribution of various\n"
"# definitions contained in the set of loaded MIB modules.\n"
"\n", f);
}
fprintf(f, "%-14s %8s %8s %11s %9s\n", "CATEGORY",
"TOTAL", "CURRENT", "DEPRECATED", "OBSOLETE");
return;
}
if (raw) {
fprintf(f, "%-14s %8lu %8lu %11lu %9lu\n", s,
cnt->total, cnt->current, cnt->deprecated, cnt->obsolete);
} else {
fprintf(f, "%-14s %8lu %7.1f%% %10.1f%% %8.1f%%\n", s,
cnt->total,
cnt->total ? (double) cnt->current * 100 / cnt->total : 0,
cnt->total ? (double) cnt->deprecated * 100 / cnt->total : 0,
cnt->total ? (double) cnt->obsolete * 100 / cnt->total : 0);
}
}
static void
fprintAccessCounter(FILE *f, AccessCounter *cnt, char *s)
{
if (!s || !cnt) {
if (! silent) {
fputs(
"# The following table shows the access mode distribution of all scalar\n"
"# or column definitions contained in the set of loaded MIB modules.\n"
"\n", f);
}
fprintf(f, "%-14s %8s %10s %9s %7s %8s\n", "CATEGORY",
"TOTAL", "READWRITE", "READONLY", "NOTIFY", "NOACCES");
return;
}
if (raw) {
fprintf(f, "%-14s %8lu %10lu %9lu %7lu %8lu\n", s,
cnt->total, cnt->readwrite, cnt->readonly,
cnt->notify, cnt->noaccess);
} else {
fprintf(f, "%-14s %8lu %9.1f%% %8.1f%% %6.1f%% %7.1f%%\n", s,
cnt->total,
cnt->total ? (double) cnt->readwrite * 100 / cnt->total : 0,
cnt->total ? (double) cnt->readonly * 100 / cnt->total : 0,
cnt->total ? (double) cnt->notify * 100 / cnt->total : 0,
cnt->total ? (double) cnt->noaccess * 100 / cnt->total : 0);
}
}
static void
fprintIndexCounter(FILE *f, IndexCounter *cnt, char *s)
{
if (! s || ! cnt) {
if (! silent) {
fputs(
"# The following table shows the table index kind distribution of\n"
"# table definitions contained in the set of loaded MIB modules.\n"
"\n", f);
fprintf(f, "%-14s %8s %8s %8s %8s %8s %8s\n", "CATEGORY",
"TOTAL", "INDEX", "AUGMENT", "REORDER", "SPARSE", "EXPAND");
}
return;
}
if (raw) {
fprintf(f, "%-14s %8lu %8lu %8lu %8lu %8lu %8lu\n", s,
cnt->total, cnt->index, cnt->augment,
cnt->reorder, cnt->sparse, cnt->expand);
} else {
fprintf(f, "%-14s %8lu %7.1f%% %7.1f%% %7.1f%% %7.1f%% %7.1f%%\n", s,
cnt->total,
cnt->total ? (double) cnt->index * 100 / cnt->total : 0,
cnt->total ? (double) cnt->augment * 100 / cnt->total : 0,
cnt->total ? (double) cnt->reorder * 100 / cnt->total : 0,
cnt->total ? (double) cnt->sparse * 100 / cnt->total : 0,
cnt->total ? (double) cnt->expand * 100 / cnt->total : 0);
}
}
static void
fprintIndexLenCounter(FILE *f, IndexLenCounter *cnt, char *s)
{
int i;
int n = sizeof(cnt->length)/sizeof(cnt->length[0]);
char buf[42];
if (! s || ! cnt) {
if (! silent) {
fputs(
"# The following table shows the table index length distribution of\n"
"# table definitions contained in the set of loaded MIB modules.\n"
"\n", f);
}
fprintf(f, "%-10s %6s ", "CATEGORY", "TOTAL");
for (i = 1; i < n; i++) {
sprintf(buf, "[%d]", i);
fprintf(f, " %5s", buf);
}
fprintf(f, "\n");
return;
}
fprintf(f, "%-10s %6lu ", s, cnt->total);
if (raw) {
for (i = 1; i < n; i++) {
fprintf(f, " %5lu", cnt->length[i]);
}
} else {
for (i = 1; i < n; i++) {
fprintf(f, " %4.1f%%", (double) cnt->length[i] * 100 / cnt->total);
}
}
fprintf(f, "\n");
}
static void
fprintTableLenCounter(FILE *f, TableLenCounter *cnt, char *s)
{
int i;
int n = sizeof(cnt->length)/sizeof(cnt->length[0]);
char buf[42];
if (! s || ! cnt) {
if (! silent) {
fputs(
"# The following table shows the table length distribution of\n"
"# table definitions contained in the set of loaded MIB modules.\n"
"\n", f);
}
fprintf(f, "%-10s %6s ", "CATEGORY", "TOTAL");
for (i = 1; i < n; i++) {
sprintf(buf, "[%d]", i);
fprintf(f, " %5s", buf);
}
fprintf(f, "\n");
return;
}
fprintf(f, "%-10s %6lu ", s, cnt->total);
if (raw) {
for (i = 1; i < n; i++) {
fprintf(f, " %5lu", cnt->length[i]);
}
} else {
for (i = 1; i < n; i++) {
fprintf(f, " %4.1f%%", (double) cnt->length[i] * 100 / cnt->total);
}
}
fprintf(f, "\n");
}
static void
fprintLengthCounter(FILE *f, LengthCounter *cnt, char *s)
{
if (! s) {
if (! silent) {
fputs(
"# The following table shows the text clause usage distribution of all\n"
"# definitions contained in the set of loaded MIB modules.\n"
"\n", f);
}
fprintf(f, "%-14s %8s %12s %10s %8s %8s\n", "CATEGORY",
"TOTAL", "DESCRIPTION", "REFERENCE", "UNIT", "FORMAT");
return;
}
if (raw) {
fprintf(f, "%-14s %8lu %12lu %10lu %8lu %8lu\n", s,
cnt->total, cnt->descr, cnt->reference,
cnt->units, cnt->format);
} else {
fprintf(f, "%-14s %8lu %11.1f%% %9.1f%% %7.1f%% %7.1f%%\n", s,
cnt->total,
cnt->total ? (double) cnt->descr * 100 / cnt->total : 0,
cnt->total ? (double) cnt->reference * 100 / cnt->total : 0,
cnt->total ? (double) cnt->units * 100 / cnt->total : 0,
cnt->total ? (double) cnt->format * 100 / cnt->total : 0);
}
}
static void
fprintLengthCounter2(FILE *f, LengthCounter *cnt, char *s)
{
if (! s) {
if (! silent) {
fprintf(f,
"# The following table shows the %s text length distribution (in\n"
"# bytes) of all definitions contained in the set of loaded MIB modules.\n"
"\n", raw ? "total" : "average");
}
fprintf(f, "%-14s %8s %12s %10s %8s %8s\n", "CATEGORY",
"TOTAL", "DESCRIPTION", "REFERENCE", "UNIT", "FORMAT");
return;
}
if (raw) {
fprintf(f, "%-14s %8lu %12lu %10lu %8lu %8lu\n", s,
cnt->total, cnt->descr_len, cnt->reference_len,
cnt->units_len, cnt->format_len);
} else {
fprintf(f, "%-14s %8lu %12.1f %10.1f %8.1f %8.1f\n", s,
cnt->total,
cnt->descr ? (double) cnt->descr_len / cnt->descr : 0,
cnt->reference ? (double) cnt->reference_len / cnt->reference : 0,
cnt->units ? (double) cnt->units_len / cnt->units : 0,
cnt->format ? (double) cnt->format_len / cnt->format : 0);
}
}
static void
fprintfComplexity(FILE *f, Metrics *metrics)
{
unsigned long cmplx = 0, fctrs = 0;
unsigned long total_cmplx = 0, total_fctrs = 0;
if (! silent) {
fputs(
"# The following table shows the complexity metrics of the set of loaded\n"
"# MIB modules.\n"
"\n", f);
}
fprintf(f, "%-14s %8s %8s %8s %8s\n", "CATEGORY", "TOTAL",
"RAW", "WEIGHT", "COMPLEXITY");
cmplx = metrics->accessScalars.readonly * 1;
fctrs = metrics->accessScalars.readonly;
fprintf(f, "%-14s %8lu %8lu\n", "Scalars (ro):", fctrs, cmplx);
total_cmplx += cmplx;
total_fctrs += fctrs;
cmplx = metrics->accessScalars.readwrite * 2;
fctrs = metrics->accessScalars.readwrite;
fprintf(f, "%-14s %8lu %8lu\n", "Scalars (rw):", fctrs, cmplx);
total_cmplx += cmplx;
total_fctrs += fctrs;
cmplx = metrics->accessColumns.readonly * 2;
fctrs = metrics->accessColumns.readonly;
fprintf(f, "%-14s %8lu %8lu\n", "Columns (ro):", fctrs, cmplx);
total_cmplx += cmplx;
total_fctrs += fctrs;
cmplx = metrics->accessColumns.readwrite * 3;
fctrs = metrics->accessColumns.readwrite;
fprintf(f, "%-14s %8lu %8lu\n", "Columns (rw):", fctrs, cmplx);
total_cmplx += cmplx;
total_fctrs += fctrs;
/* readcreate tables ? */
/* table index complexity ? */
{
int i;
cmplx = 0;
for (i = 0; i < 100; i++) {
cmplx += 3 * i * metrics->indexComplexity.complexity[i];
}
fprintf(f, "%-14s %8lu %8lu\n", "Indexes:", metrics->indexComplexity.total, cmplx);
}
fprintf(f, "%-14s %8lu %8lu\n", "Summary:", total_fctrs, total_cmplx);
}
static void
fprintMetrics(FILE *f, Metrics *metrics)
{
fprintStatusCounter(f, NULL, NULL);
fprintStatusCounter(f, &metrics->statusTypes, "Types:");
fprintStatusCounter(f, &metrics->statusTables, "Tables:");
fprintStatusCounter(f, &metrics->statusColumns, "Columns:");
fprintStatusCounter(f, &metrics->statusScalars, "Scalars:");
fprintStatusCounter(f, &metrics->statusNotifications, "Notifications:");
fprintStatusCounter(f, &metrics->statusGroups, "Groups:");
fprintStatusCounter(f, &metrics->statusCompliances, "Compliances:");
fprintStatusCounter(f, &metrics->statusAll, "Summary:");
fprintf(f, "\n");
fprintAccessCounter(f, NULL, NULL);
fprintAccessCounter(f, &metrics->accessColumns, "Columns:");
fprintAccessCounter(f, &metrics->accessScalars, "Scalars:");
fprintAccessCounter(f, &metrics->accessAll, "Summary:");
fprintf(f, "\n");
fprintIndexCounter(f, NULL, NULL);
fprintIndexCounter(f, &metrics->indexTables, "Tables:");
fprintf(f, "\n");
fprintIndexLenCounter(f, NULL, NULL);
fprintIndexLenCounter(f, &metrics->indexLenTables, "Tables:");
fprintf(f, "\n");
fprintTableLenCounter(f, NULL, NULL);
fprintTableLenCounter(f, &metrics->tableLength, "Tables:");
fprintf(f, "\n");
fprintLengthCounter(f, NULL, NULL);
fprintLengthCounter(f, &metrics->lengthTypes, "Types:");
fprintLengthCounter(f, &metrics->lengthTables, "Tables:");
fprintLengthCounter(f, &metrics->lengthColumns, "Columns:");
fprintLengthCounter(f, &metrics->lengthScalars, "Scalars:");
fprintLengthCounter(f, &metrics->lengthNotifications, "Notifications:");
fprintLengthCounter(f, &metrics->lengthAll, "Summary:");
fprintf(f, "\n");
fprintLengthCounter2(f, NULL, NULL);
fprintLengthCounter2(f, &metrics->lengthTypes, "Types:");
fprintLengthCounter2(f, &metrics->lengthTables, "Tables:");
fprintLengthCounter2(f, &metrics->lengthColumns, "Columns:");
fprintLengthCounter2(f, &metrics->lengthScalars, "Scalars:");
fprintLengthCounter2(f, &metrics->lengthNotifications, "Notifications:");
fprintLengthCounter2(f, &metrics->lengthAll, "Summary:");
fprintf(f, "\n");
fprintBasetypeCounter(f, NULL, NULL);
fprintBasetypeCounter(f, &metrics->basetypesColumns, "Columns:");
fprintBasetypeCounter(f, &metrics->basetypesScalars, "Scalars:");
fprintBasetypeCounter(f, &metrics->basetypesAll, "Summary:");
fprintf(f, "\n");
fprintfComplexity(f, metrics);
fprintf(f, "\n");
fprintTypeUsage(f, typeList);
freeUsageCounter(typeList), typeList = NULL;
fprintf(f, "\n");
fprintExtTypeUsage(f, extTypeList);
freeUsageCounter(extTypeList), extTypeList = NULL;
fprintf(f, "\n");
fprintExtNodeUsage(f, extNodeList);
freeUsageCounter(extNodeList), extNodeList = NULL;
fprintf(f, "\n");
fprintModuleUsage(f, extModuleList);
freeUsageCounter(extModuleList), extModuleList = NULL;
fprintf(f, "\n");
fprintIndexComplexity(f, indexComplexityList);
freeUsageCounter(indexComplexityList), indexComplexityList = NULL;
fprintf(f, "\n");
}
static void
dumpMetrics(int modc, SmiModule **modv, int flags, char *output)
{
Metrics metrics;
int i;
FILE *f = stdout;
silent = (flags & SMIDUMP_FLAG_SILENT);
if (output) {
f = fopen(output, "w");
if (!f) {
fprintf(stderr, "smidump: cannot open %s for writing: ", output);
perror(NULL);
exit(1);
}
}
if (flags & SMIDUMP_FLAG_UNITE) {
if (! silent) {
int pos = 8888;
fprintf(f, "# united module metrics [%d modules] "
"(generated by smidump " SMI_VERSION_STRING ")\n", modc);
fprintf(f, "#\n# smidump -u -f metrics");
if (raw) fprintf(f, " --metrics-raw");
for (i = 0; i < modc; i++) {
int len = strlen(modv[i]->name);
if (pos + len > 70) {
fprintf(f, " \\\n#\t"), pos = 8;
}
fprintf(f, "%s ", modv[i]->name);
pos += len + 1;
}
fprintf(f, "%s\n", (pos == 8) ? "" : "\n");
}
fprintRevision(f, modc, modv);
for (i = 0; i < modc; i++) {
memset(&metrics, 0, sizeof(Metrics));
}
for (i = 0; i < modc; i++) {
addMetrics(&metrics, modv[i]);
}
fprintMetrics(f, &metrics);
} else {
for (i = 0; i < modc; i++) {
if (! silent) {
fprintf(f, "# %s module metrics (generated by smidump "
SMI_VERSION_STRING ")\n\n", modv[i]->name);
}
fprintRevision(f, 1, modv+i);
memset(&metrics, 0, sizeof(Metrics));
addMetrics(&metrics, modv[i]);
fprintMetrics(f, &metrics);
}
}
if (fflush(f) || ferror(f)) {
perror("smidump: write error");
exit(1);
}
if (output) {
fclose(f);
}
}
void
initMetrics()
{
static SmidumpDriverOption opt[] = {
{ "raw", OPT_FLAG, &raw, 0,
"generate raw statistics (no percentages)"},
{ 0, OPT_END, 0, 0 }
};
static SmidumpDriver driver = {
"metrics",
dumpMetrics,
0,
0,
"metrics characterizing MIB modules",
opt,
NULL
};
smidumpRegisterDriver(&driver);
}