summaryrefslogtreecommitdiffstats
path: root/examples/perfcounter
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 17:20:00 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 17:20:00 +0000
commit8daa83a594a2e98f39d764422bfbdbc62c9efd44 (patch)
tree4099e8021376c7d8c05bdf8503093d80e9c7bad0 /examples/perfcounter
parentInitial commit. (diff)
downloadsamba-8daa83a594a2e98f39d764422bfbdbc62c9efd44.tar.xz
samba-8daa83a594a2e98f39d764422bfbdbc62c9efd44.zip
Adding upstream version 2:4.20.0+dfsg.upstream/2%4.20.0+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'examples/perfcounter')
-rw-r--r--examples/perfcounter/Makefile38
-rw-r--r--examples/perfcounter/perf.h210
-rw-r--r--examples/perfcounter/perf_writer.c213
-rw-r--r--examples/perfcounter/perf_writer_cpu.c189
-rw-r--r--examples/perfcounter/perf_writer_disk.c224
-rw-r--r--examples/perfcounter/perf_writer_mem.c124
-rw-r--r--examples/perfcounter/perf_writer_process.c85
-rw-r--r--examples/perfcounter/perf_writer_util.c235
-rwxr-xr-xexamples/perfcounter/perfcountd.init65
9 files changed, 1383 insertions, 0 deletions
diff --git a/examples/perfcounter/Makefile b/examples/perfcounter/Makefile
new file mode 100644
index 0000000..86e2190
--- /dev/null
+++ b/examples/perfcounter/Makefile
@@ -0,0 +1,38 @@
+#
+# Copyright (C) Marcin Krzysztof Porwit 2005
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+
+SAMBA_SRC_DIR=../../source3
+TDB_SRC_DIR=$(SAMBA_SRC_DIR)/../lib/tdb
+
+CFLAGS = -g -I$(SAMBA_SRC_DIR) -I$(SAMBA_SRC_DIR)/include -I$(TDB_SRC_DIR)/include -I../../
+CC = gcc
+
+PROGS = perfcount
+TDB_OBJ = $(TDB_SRC_DIR)/common/tdb.o $(TDB_SRC_DIR)/common/dump.o \
+ $(TDB_SRC_DIR)/common/error.o $(TDB_SRC_DIR)/common/freelist.o \
+ $(TDB_SRC_DIR)/common/io.o $(TDB_SRC_DIR)/common/lock.o \
+ $(TDB_SRC_DIR)/common/open.o $(TDB_SRC_DIR)/common/transaction.o \
+ $(TDB_SRC_DIR)/common/traverse.o $(TDB_SRC_DIR)/common/hash.o
+PERF_WRITER_OBJ = perf_writer.o perf_writer_mem.o perf_writer_util.o perf_writer_cpu.o perf_writer_process.o perf_writer_disk.o
+
+default: $(PROGS)
+
+perfcount: $(PERF_WRITER_OBJ)
+ $(CC) $(CFLAGS) -o perfcount $(PERF_WRITER_OBJ) $(TDB_OBJ)
+
+clean:
+ rm -f $(PROGS) *.o *~ *% core
diff --git a/examples/perfcounter/perf.h b/examples/perfcounter/perf.h
new file mode 100644
index 0000000..03b5448
--- /dev/null
+++ b/examples/perfcounter/perf.h
@@ -0,0 +1,210 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Performance Counter Daemon
+ *
+ * Copyright (C) Marcin Krzysztof Porwit 2005
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __PERF_H__
+#define __PERF_H__
+
+#define _PUBLIC_
+
+#ifdef HAVE_STDBOOL_H
+#include <stdbool.h>
+#endif
+
+#if !defined(HAVE_BOOL)
+#ifdef HAVE__Bool
+#define bool _Bool
+#else
+#error Need a real boolean type
+#endif
+#endif
+
+
+#include <stdlib.h>
+#include <time.h>
+#include <math.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <limits.h>
+#include <tdb.h>
+#include "librpc/gen_ndr/perfcount.h"
+#include <sys/statfs.h>
+#include <sys/times.h>
+#include <sys/sysinfo.h>
+
+#define NUM_COUNTERS 10
+
+#define NAME_LEN 256
+#define HELP_LEN 1024
+
+#define PERF_OBJECT 0
+#define PERF_INSTANCE 1
+#define PERF_COUNTER 2
+
+#define FALSE 0
+#define TRUE !FALSE
+
+#define PROC_BUF 256
+#define LARGE_BUF 16384
+
+typedef struct perf_counter
+{
+ int index;
+ char name[NAME_LEN];
+ char help[HELP_LEN];
+ char relationships[NAME_LEN];
+ unsigned int counter_type;
+ int record_type;
+} PerfCounter;
+
+typedef struct mem_data
+{
+ unsigned int availPhysKb;
+ unsigned int availSwapKb;
+ unsigned int totalPhysKb;
+ unsigned int totalSwapKb;
+} MemData;
+
+typedef struct mem_info
+{
+ PerfCounter memObjDesc;
+ PerfCounter availPhysKb;
+ PerfCounter availSwapKb;
+ PerfCounter totalPhysKb;
+ PerfCounter totalSwapKb;
+ MemData *data;
+} MemInfo;
+
+typedef struct cpu_data
+{
+ unsigned long long user;
+ unsigned long long nice;
+ unsigned long long system;
+ unsigned long long idle;
+} CPUData;
+
+typedef struct cpu_info
+{
+ unsigned int numCPUs;
+ PerfCounter cpuObjDesc;
+ PerfCounter userCPU;
+ PerfCounter niceCPU;
+ PerfCounter systemCPU;
+ PerfCounter idleCPU;
+ CPUData *data;
+} CPUInfo;
+
+typedef struct disk_meta_data
+{
+ char name[NAME_LEN];
+ char mountpoint[NAME_LEN];
+} DiskMetaData;
+
+typedef struct disk_data
+{
+ unsigned long long freeMegs;
+ unsigned int writesPerSec;
+ unsigned int readsPerSec;
+} DiskData;
+
+typedef struct disk_info
+{
+ unsigned int numDisks;
+ DiskMetaData *mdata;
+ PerfCounter diskObjDesc;
+ PerfCounter freeMegs;
+ PerfCounter writesPerSec;
+ PerfCounter readsPerSec;
+ DiskData *data;
+} DiskInfo;
+
+typedef struct process_data
+{
+ unsigned int runningProcessCount;
+} ProcessData;
+
+typedef struct process_info
+{
+ PerfCounter processObjDesc;
+ PerfCounter runningProcessCount;
+ ProcessData *data;
+} ProcessInfo;
+
+typedef struct perf_data_block
+{
+ unsigned int counter_id;
+ unsigned int num_counters;
+ unsigned int NumObjectTypes;
+ unsigned long long PerfTime;
+ unsigned long long PerfFreq;
+ unsigned long long PerfTime100nSec;
+ MemInfo memInfo;
+ CPUInfo cpuInfo;
+ ProcessInfo processInfo;
+ DiskInfo diskInfo;
+} PERF_DATA_BLOCK;
+
+typedef struct runtime_settings
+{
+ /* Runtime flags */
+ int dflag;
+ /* DB path names */
+ char dbDir[PATH_MAX];
+ char nameFile[PATH_MAX];
+ char counterFile[PATH_MAX];
+ /* TDB context */
+ TDB_CONTEXT *cnames;
+ TDB_CONTEXT *cdata;
+} RuntimeSettings;
+
+/* perf_writer_ng_util.c function prototypes */
+void fatal(char *msg);
+void add_key(TDB_CONTEXT *db, char *keystring, char *datastring, int flags);
+void add_key_raw(TDB_CONTEXT *db, char *keystring, void *datastring, size_t datasize, int flags);
+void make_key(char *buf, int buflen, int key_part1, char *key_part2);
+void parse_flags(RuntimeSettings *rt, int argc, char **argv);
+void setup_file_paths(RuntimeSettings *rt);
+void daemonize(RuntimeSettings *rt);
+
+/* perf_writer_ng_mem.c function prototypes */
+void get_meminfo(PERF_DATA_BLOCK *data);
+void init_memdata_desc(PERF_DATA_BLOCK *data);
+void init_memdata(PERF_DATA_BLOCK *data);
+void output_mem_desc(PERF_DATA_BLOCK *data, RuntimeSettings rt);
+void output_meminfo(PERF_DATA_BLOCK *data, RuntimeSettings rt, int tdb_flags);
+void init_perf_counter(PerfCounter *counter, PerfCounter *parent, unsigned int index, char *name, char *help, int counter_type, int record_type);
+
+/* perf_writer_ng_cpu.c function prototypes */
+unsigned long long get_cpufreq();
+void init_cpudata_desc(PERF_DATA_BLOCK *data);
+void get_cpuinfo(PERF_DATA_BLOCK *data);
+void init_cpu_data(PERF_DATA_BLOCK *data);
+void output_cpu_desc(PERF_DATA_BLOCK *data, RuntimeSettings rt);
+void output_cpuinfo(PERF_DATA_BLOCK *data, RuntimeSettings rt, int tdb_flags);
+
+#endif /* __PERF_H__ */
diff --git a/examples/perfcounter/perf_writer.c b/examples/perfcounter/perf_writer.c
new file mode 100644
index 0000000..054d9e8
--- /dev/null
+++ b/examples/perfcounter/perf_writer.c
@@ -0,0 +1,213 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Performance Counter Daemon
+ *
+ * Copyright (C) Marcin Krzysztof Porwit 2005
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "perf.h"
+
+sig_atomic_t keep_running = TRUE;
+
+/* allocates memory and gets numCPUs, total memory, and PerfFreq, number of disks... */
+void get_constants(PERF_DATA_BLOCK *data)
+{
+ data->cpuInfo.numCPUs = sysconf(_SC_NPROCESSORS_ONLN) > 0 ? sysconf(_SC_NPROCESSORS_ONLN) : 1;
+ data->PerfFreq = sysconf(_SC_CLK_TCK);
+ init_mem_data(data);
+ init_cpu_data(data);
+ init_process_data(data);
+ init_disk_data(data);
+
+ return;
+}
+
+void output_num_instances(PerfCounter obj, int numInst, RuntimeSettings rt)
+{
+ char key[NAME_LEN];
+ char sdata[NAME_LEN];
+
+ make_key(key, NAME_LEN, obj.index, "inst");
+ memset(sdata, 0, NAME_LEN);
+ sprintf(sdata, "%d", numInst);
+ add_key(rt.cnames, key, sdata, TDB_INSERT);
+
+ return;
+}
+
+void output_perf_desc(PerfCounter counter, RuntimeSettings rt)
+{
+ char key[NAME_LEN];
+ char sdata[NAME_LEN];
+
+ /* First insert the counter name */
+ make_key(key, NAME_LEN, counter.index, NULL);
+ add_key(rt.cnames, key, counter.name, TDB_INSERT);
+ /* Add the help string */
+ make_key(key, NAME_LEN, counter.index + 1, NULL);
+ add_key(rt.cnames, key, counter.help, TDB_INSERT);
+ /* Add the relationships */
+ make_key(key, NAME_LEN, counter.index, "rel");
+ add_key(rt.cnames, key, counter.relationships, TDB_INSERT);
+ /* Add type data if not PERF_OBJECT or PERF_INSTANCE */
+ if(counter.record_type == PERF_COUNTER)
+ {
+ make_key(key, NAME_LEN, counter.index, "type");
+ memset(sdata, 0, NAME_LEN);
+ sprintf(sdata, "%d", counter.counter_type);
+ add_key(rt.cnames, key, sdata, TDB_INSERT);
+ }
+
+ return;
+}
+
+void initialize(PERF_DATA_BLOCK *data, RuntimeSettings *rt, int argc, char **argv)
+{
+ memset(data, 0, sizeof(*data));
+ memset(rt, 0, sizeof(*rt));
+
+ parse_flags(rt, argc, argv);
+ setup_file_paths(rt);
+
+ get_constants(data);
+
+ if(rt->dflag == TRUE)
+ daemonize(rt);
+
+ output_mem_desc(data, *rt);
+ output_cpu_desc(data, *rt);
+ output_process_desc(data, *rt);
+ output_disk_desc(data, *rt);
+
+ return;
+}
+
+void refresh_perf_data_block(PERF_DATA_BLOCK *data, RuntimeSettings rt)
+{
+ data->PerfTime100nSec = 0;
+ get_meminfo(data);
+ get_cpuinfo(data);
+ get_processinfo(data);
+ get_diskinfo(data);
+ return;
+}
+
+void output_perf_counter(PerfCounter counter, unsigned long long data,
+ RuntimeSettings rt, int tdb_flags)
+{
+ char key[NAME_LEN];
+ char sdata[NAME_LEN];
+ unsigned int size_mask;
+
+ make_key(key, NAME_LEN, counter.index, NULL);
+ memset(sdata, 0, NAME_LEN);
+
+ size_mask = counter.counter_type & PERF_SIZE_VARIABLE_LEN;
+
+ if(size_mask == PERF_SIZE_DWORD)
+ sprintf(sdata, "%d", (unsigned int)data);
+ else if(size_mask == PERF_SIZE_LARGE)
+ sprintf(sdata, "%Lu", data);
+
+ add_key(rt.cdata, key, sdata, tdb_flags);
+
+ return;
+}
+
+void output_perf_instance(int parentObjInd,
+ int instanceInd,
+ void *instData,
+ size_t dsize,
+ char *name,
+ RuntimeSettings rt,
+ int tdb_flags)
+{
+ char key[NAME_LEN];
+ char sdata[NAME_LEN];
+
+ memset(key, 0, NAME_LEN);
+ sprintf(key, "%di%d", parentObjInd, instanceInd);
+ add_key_raw(rt.cdata, key, instData, dsize, tdb_flags);
+
+ /* encode name */
+ memset(key, 0, NAME_LEN);
+ sprintf(key, "%di%dname", parentObjInd, instanceInd);
+ add_key(rt.cnames, key, name, tdb_flags);
+
+ return;
+}
+
+void output_global_data(PERF_DATA_BLOCK *data, RuntimeSettings rt, int tdb_flags)
+{
+ int i;
+ char key[NAME_LEN];
+ char sdata[NAME_LEN];
+
+ /* Initialize BaseIndex */
+ make_key(key, NAME_LEN, 1, NULL);
+ memset(sdata, 0, NAME_LEN);
+ sprintf(sdata, "%d", data->num_counters);
+ add_key(rt.cnames, key, sdata, tdb_flags);
+ /* Initialize PerfTime, PerfFreq and PerfTime100nSec */
+ memset(sdata, 0, NAME_LEN);
+ make_key(key, NAME_LEN, 0, "PerfTime");
+ sprintf(sdata, "%Lu", data->PerfTime);
+ add_key(rt.cdata, key, sdata, tdb_flags);
+ make_key(key, NAME_LEN, 0, "PerfTime100nSec");
+ memset(sdata, 0, NAME_LEN);
+ sprintf(sdata, "%Lu", data->PerfTime100nSec);
+ add_key(rt.cdata, key, sdata, tdb_flags);
+ memset(sdata, 0, NAME_LEN);
+ make_key(key, NAME_LEN, 0, "PerfFreq");
+ sprintf(sdata, "%Lu", data->PerfFreq);
+ add_key(rt.cnames, key, sdata, tdb_flags);
+
+ return;
+}
+
+void output_perf_data_block(PERF_DATA_BLOCK *data, RuntimeSettings rt, int tdb_flags)
+{
+ output_global_data(data, rt, tdb_flags);
+ output_meminfo(data, rt, tdb_flags);
+ output_cpuinfo(data, rt, tdb_flags);
+ output_processinfo(data, rt, tdb_flags);
+ output_diskinfo(data, rt, tdb_flags);
+ return;
+}
+
+void update_counters(PERF_DATA_BLOCK *data, RuntimeSettings rt)
+{
+ refresh_perf_data_block(data, rt);
+ output_perf_data_block(data, rt, TDB_REPLACE);
+
+ return;
+}
+
+int main(int argc, char **argv)
+{
+ PERF_DATA_BLOCK data;
+ RuntimeSettings rt;
+
+ initialize(&data, &rt, argc, argv);
+
+ while(keep_running)
+ {
+ update_counters(&data, rt);
+ sleep(1);
+ }
+
+ return 0;
+}
diff --git a/examples/perfcounter/perf_writer_cpu.c b/examples/perfcounter/perf_writer_cpu.c
new file mode 100644
index 0000000..215e073
--- /dev/null
+++ b/examples/perfcounter/perf_writer_cpu.c
@@ -0,0 +1,189 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Performance Counter Daemon
+ *
+ * Copyright (C) Marcin Krzysztof Porwit 2005
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "perf.h"
+
+void init_cpudata_desc(PERF_DATA_BLOCK *data)
+{
+ init_perf_counter(&(data->cpuInfo.cpuObjDesc),
+ &(data->cpuInfo.cpuObjDesc),
+ get_counter_id(data),
+ "Processor",
+ "The Processor object consists of counters that describe the behavior of the CPU.",
+ 0,
+ PERF_OBJECT);
+ init_perf_counter(&(data->cpuInfo.userCPU),
+ &(data->cpuInfo.cpuObjDesc),
+ get_counter_id(data),
+ "\% User CPU Utilization",
+ "\% User CPU Utilization is the percentage of the CPU used by processes executing user code.",
+ PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | PERF_TIMER_100NS | PERF_DELTA_COUNTER | PERF_DISPLAY_PERCENT,
+ PERF_COUNTER);
+ init_perf_counter(&(data->cpuInfo.systemCPU),
+ &(data->cpuInfo.cpuObjDesc),
+ get_counter_id(data),
+ "\% System CPU Utilization",
+ "\% System CPU Utilization is the percentage of the CPU used by processes doing system calls.",
+ PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | PERF_TIMER_100NS | PERF_DELTA_COUNTER | PERF_DISPLAY_PERCENT,
+ PERF_COUNTER);
+ init_perf_counter(&(data->cpuInfo.niceCPU),
+ &(data->cpuInfo.cpuObjDesc),
+ get_counter_id(data),
+ "\% Nice CPU Utilization",
+ "\% Nice CPU Utilization is the percentage of the CPU used by processes running in nice mode.",
+ PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | PERF_TIMER_100NS | PERF_DELTA_COUNTER | PERF_DISPLAY_NOSHOW,
+ PERF_COUNTER);
+ init_perf_counter(&(data->cpuInfo.idleCPU),
+ &(data->cpuInfo.cpuObjDesc),
+ get_counter_id(data),
+ "\% Idle CPU",
+ "\% Idle CPU is the percentage of the CPU not doing any work.",
+ PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | PERF_TIMER_100NS | PERF_DELTA_COUNTER | PERF_DISPLAY_NOSHOW,
+ PERF_COUNTER);
+
+ return;
+}
+
+void get_cpuinfo(PERF_DATA_BLOCK *data)
+{
+ int num, i;
+ unsigned int cpuid;
+ char buf[PROC_BUF];
+ static FILE *fp = NULL;
+
+ if(!fp)
+ {
+ if(!(fp = fopen("/proc/stat", "r")))
+ {
+ perror("get_cpuinfo: fopen");
+ exit(1);
+ }
+ }
+
+ rewind(fp);
+ fflush(fp);
+
+ /* Read in the first line and discard it -- that has the CPU summary */
+ if(!fgets(buf, sizeof(buf), fp))
+ {
+ perror("get_cpuinfo: fgets");
+ exit(1);
+ }
+ for(i = 0; i < data->cpuInfo.numCPUs; i++)
+ {
+ if(!fgets(buf, sizeof(buf), fp))
+ {
+ perror("get_cpuinfo: fgets");
+ exit(1);
+ }
+ num = sscanf(buf, "cpu%u %Lu %Lu %Lu %Lu",
+ &cpuid,
+ &data->cpuInfo.data[i].user,
+ &data->cpuInfo.data[i].nice,
+ &data->cpuInfo.data[i].system,
+ &data->cpuInfo.data[i].idle);
+ if(i != cpuid)
+ {
+ perror("get_cpuinfo: /proc/stat inconsistent?");
+ exit(1);
+ }
+ /*
+ Alternate way of doing things:
+ struct tms buffer;
+ data->PerfTime100nSec = times(&buffer);
+ */
+ data->PerfTime100nSec += data->cpuInfo.data[i].user +
+ data->cpuInfo.data[i].nice +
+ data->cpuInfo.data[i].system +
+ data->cpuInfo.data[i].idle;
+ }
+ data->PerfTime100nSec /= data->cpuInfo.numCPUs;
+ return;
+}
+
+void init_cpu_data(PERF_DATA_BLOCK *data)
+{
+ data->cpuInfo.data = calloc(data->cpuInfo.numCPUs, sizeof(*data->cpuInfo.data));
+ if(!data->cpuInfo.data)
+ {
+ perror("init_cpu_data: out of memory");
+ exit(1);
+ }
+
+ init_cpudata_desc(data);
+
+ get_cpuinfo(data);
+
+ return;
+}
+
+void output_cpu_desc(PERF_DATA_BLOCK *data, RuntimeSettings rt)
+{
+ output_perf_desc(data->cpuInfo.cpuObjDesc, rt);
+ output_perf_desc(data->cpuInfo.userCPU, rt);
+ output_perf_desc(data->cpuInfo.niceCPU, rt);
+ output_perf_desc(data->cpuInfo.systemCPU, rt);
+ output_perf_desc(data->cpuInfo.idleCPU, rt);
+ if(data->cpuInfo.numCPUs > 1)
+ output_num_instances(data->cpuInfo.cpuObjDesc, data->cpuInfo.numCPUs + 1, rt);
+
+ return;
+}
+
+void output_cpuinfo(PERF_DATA_BLOCK *data, RuntimeSettings rt, int tdb_flags)
+{
+ int i;
+ char buf[NAME_LEN];
+
+ output_perf_counter(data->cpuInfo.userCPU,
+ data->cpuInfo.data[0].user,
+ rt, tdb_flags);
+ output_perf_counter(data->cpuInfo.systemCPU,
+ data->cpuInfo.data[0].system,
+ rt, tdb_flags);
+ output_perf_counter(data->cpuInfo.niceCPU,
+ data->cpuInfo.data[0].nice,
+ rt, tdb_flags);
+ output_perf_counter(data->cpuInfo.idleCPU,
+ data->cpuInfo.data[0].idle,
+ rt, tdb_flags);
+ if(data->cpuInfo.numCPUs > 1)
+ {
+ for(i = 0; i < data->cpuInfo.numCPUs; i++)
+ {
+ memset(buf, 0, NAME_LEN);
+ sprintf(buf, "cpu%d", i);
+ output_perf_instance(data->cpuInfo.cpuObjDesc.index,
+ i,
+ (void *)&(data->cpuInfo.data[i]),
+ sizeof(data->cpuInfo.data[i]),
+ buf, rt, tdb_flags);
+ }
+
+ memset(buf, 0, NAME_LEN);
+ sprintf(buf, "_Total");
+ output_perf_instance(data->cpuInfo.cpuObjDesc.index,
+ i,
+ (void *)&(data->cpuInfo.data[i]),
+ sizeof(data->cpuInfo.data[i]),
+ buf, rt, tdb_flags);
+ }
+ return;
+}
diff --git a/examples/perfcounter/perf_writer_disk.c b/examples/perfcounter/perf_writer_disk.c
new file mode 100644
index 0000000..18a63a4
--- /dev/null
+++ b/examples/perfcounter/perf_writer_disk.c
@@ -0,0 +1,224 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Performance Counter Daemon
+ *
+ * Copyright (C) Marcin Krzysztof Porwit 2005
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "perf.h"
+
+void init_diskdata_desc(PERF_DATA_BLOCK *data)
+{
+ init_perf_counter(&(data->diskInfo.diskObjDesc),
+ &(data->diskInfo.diskObjDesc),
+ get_counter_id(data),
+ "Logical Disk",
+ "The Logical Disk object consists of counters that show information about disks.",
+ 0,
+ PERF_OBJECT);
+ init_perf_counter(&(data->diskInfo.freeMegs),
+ &(data->diskInfo.diskObjDesc),
+ get_counter_id(data),
+ "Megabytes Free",
+ "The amount of available disk space, in megabytes.",
+ PERF_SIZE_LARGE | PERF_TYPE_NUMBER | PERF_NUMBER_DECIMAL | PERF_DISPLAY_NO_SUFFIX,
+ PERF_COUNTER);
+ init_perf_counter(&(data->diskInfo.writesPerSec),
+ &(data->diskInfo.diskObjDesc),
+ get_counter_id(data),
+ "Writes/sec",
+ "The number of writes per second to that disk.",
+ PERF_SIZE_DWORD | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | PERF_DELTA_COUNTER | PERF_DISPLAY_PER_SEC,
+ PERF_COUNTER);
+ init_perf_counter(&(data->diskInfo.readsPerSec),
+ &(data->diskInfo.diskObjDesc),
+ get_counter_id(data),
+ "Reads/sec",
+ "The number of reads of that disk per second.",
+ PERF_SIZE_DWORD | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | PERF_DELTA_COUNTER | PERF_DISPLAY_PER_SEC,
+ PERF_COUNTER);
+
+ return;
+}
+void init_num_disks(PERF_DATA_BLOCK *data)
+{
+ FILE *mtab;
+ char buf[PROC_BUF];
+ char *start, *stop;
+ int i = 0, num;
+
+ if(!(mtab = fopen("/etc/mtab", "r")))
+ {
+ perror("init_disk_names: fopen");
+ exit(1);
+ }
+
+ rewind(mtab);
+ fflush(mtab);
+
+ while(fgets(buf, sizeof(buf), mtab))
+ {
+ if(start = strstr(buf, "/dev/"))
+ {
+ if(start = strstr(start, "da"))
+ {
+ i++;
+ }
+ }
+ }
+
+ data->diskInfo.numDisks = i;
+ fclose(mtab);
+
+ return;
+}
+
+void init_disk_names(PERF_DATA_BLOCK *data)
+{
+ FILE *mtab;
+ char buf[PROC_BUF];
+ char *start, *stop;
+ int i = 0, num;
+
+ if(!(mtab = fopen("/etc/mtab", "r")))
+ {
+ perror("init_disk_names: fopen");
+ exit(1);
+ }
+
+ rewind(mtab);
+ fflush(mtab);
+
+ while(fgets(buf, sizeof(buf), mtab))
+ {
+ if(start = strstr(buf, "/dev/"))
+ {
+ if(start = strstr(start, "da"))
+ {
+ start -=1;
+ stop = strstr(start, " ");
+ memcpy(data->diskInfo.mdata[i].name, start, stop - start);
+ start = stop +1;
+ stop = strstr(start, " ");
+ memcpy(data->diskInfo.mdata[i].mountpoint, start, stop - start);
+ i++;
+ }
+ }
+ }
+
+ fclose(mtab);
+
+ return;
+}
+
+void get_diskinfo(PERF_DATA_BLOCK *data)
+{
+ int i;
+ DiskData *p;
+ struct statfs statfsbuf;
+ int status, num;
+ char buf[LARGE_BUF], *start;
+ FILE *diskstats;
+ unsigned long reads, writes, discard;
+
+ diskstats = fopen("/proc/diskstats", "r");
+ rewind(diskstats);
+ fflush(diskstats);
+ status = fread(buf, sizeof(char), LARGE_BUF, diskstats);
+ fclose(diskstats);
+
+ for(i = 0; i < data->diskInfo.numDisks; i++)
+ {
+ p = &(data->diskInfo.data[i]);
+ status = statfs(data->diskInfo.mdata[i].mountpoint, &statfsbuf);
+ p->freeMegs = (statfsbuf.f_bfree*statfsbuf.f_bsize)/1048576;
+ start = strstr(buf, data->diskInfo.mdata[i].name);
+ start += strlen(data->diskInfo.mdata[i].name) + 1;
+ num = sscanf(start, "%lu %lu %lu %lu",
+ &reads,
+ &discard,
+ &writes,
+ &discard);
+ p->writesPerSec = writes;
+ p->readsPerSec = reads;
+ fprintf(stderr, "%s:\t%u\t%u\n",
+ data->diskInfo.mdata[i].mountpoint,
+ reads, writes);
+ }
+ return;
+}
+void init_disk_data(PERF_DATA_BLOCK *data)
+{
+ init_diskdata_desc(data);
+
+ init_num_disks(data);
+
+ data->diskInfo.mdata = calloc(data->diskInfo.numDisks, sizeof(DiskMetaData));
+ if(!data->diskInfo.mdata)
+ {
+ fatal("init_disk_data: out of memory");
+ }
+
+ init_disk_names(data);
+
+ data->diskInfo.data = calloc(data->diskInfo.numDisks, sizeof(DiskData));
+ if(!data->diskInfo.data)
+ {
+ fatal("init_disk_data: out of memory");
+ }
+
+ get_diskinfo(data);
+
+ return;
+}
+
+void output_disk_desc(PERF_DATA_BLOCK *data, RuntimeSettings rt)
+{
+ output_perf_desc(data->diskInfo.diskObjDesc, rt);
+ output_perf_desc(data->diskInfo.freeMegs, rt);
+ output_perf_desc(data->diskInfo.writesPerSec, rt);
+ output_perf_desc(data->diskInfo.readsPerSec, rt);
+ output_num_instances(data->diskInfo.diskObjDesc, data->diskInfo.numDisks, rt);
+
+ return;
+}
+
+void output_diskinfo(PERF_DATA_BLOCK *data, RuntimeSettings rt, int tdb_flags)
+{
+ int i;
+
+ output_perf_counter(data->diskInfo.freeMegs,
+ data->diskInfo.data[0].freeMegs,
+ rt, tdb_flags);
+ output_perf_counter(data->diskInfo.writesPerSec,
+ (unsigned long long)data->diskInfo.data[0].writesPerSec,
+ rt, tdb_flags);
+ output_perf_counter(data->diskInfo.readsPerSec,
+ (unsigned long long)data->diskInfo.data[0].readsPerSec,
+ rt, tdb_flags);
+
+ for(i = 0; i < data->diskInfo.numDisks; i++)
+ {
+ output_perf_instance(data->diskInfo.diskObjDesc.index,
+ i,
+ (void *)&(data->diskInfo.data[i]),
+ sizeof(DiskData),
+ data->diskInfo.mdata[i].mountpoint,
+ rt, tdb_flags);
+ }
+
+ return;
+}
diff --git a/examples/perfcounter/perf_writer_mem.c b/examples/perfcounter/perf_writer_mem.c
new file mode 100644
index 0000000..580207f
--- /dev/null
+++ b/examples/perfcounter/perf_writer_mem.c
@@ -0,0 +1,124 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Performance Counter Daemon
+ *
+ * Copyright (C) Marcin Krzysztof Porwit 2005
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "perf.h"
+
+void get_meminfo(PERF_DATA_BLOCK *data)
+{
+ int status;
+ struct sysinfo info;
+ status = sysinfo(&info);
+
+ data->memInfo.data->availPhysKb = (info.freeram * info.mem_unit)/1024;
+ data->memInfo.data->availSwapKb = (info.freeswap * info.mem_unit)/1024;
+ data->memInfo.data->totalPhysKb = (info.totalram * info.mem_unit)/1024;
+ data->memInfo.data->totalSwapKb = (info.totalswap * info.mem_unit)/1024;
+
+ /* Also get uptime since we have the structure */
+ data->PerfTime = (unsigned long)info.uptime;
+
+ return;
+}
+
+void init_memdata_desc(PERF_DATA_BLOCK *data)
+{
+ init_perf_counter(&(data->memInfo.memObjDesc),
+ &(data->memInfo.memObjDesc),
+ get_counter_id(data),
+ "Memory",
+ "The Memory performance object consists of counters that describe the behavior of physical and virtual memory on the computer.",
+ 0,
+ PERF_OBJECT);
+ init_perf_counter(&(data->memInfo.availPhysKb),
+ &(data->memInfo.memObjDesc),
+ get_counter_id(data),
+ "Available Physical Kilobytes",
+ "Available Physical Kilobytes is the number of free kilobytes in physical memory",
+ PERF_SIZE_DWORD | PERF_TYPE_NUMBER | PERF_NUMBER_DECIMAL | PERF_DISPLAY_NO_SUFFIX,
+ PERF_COUNTER);
+ init_perf_counter(&(data->memInfo.availSwapKb),
+ &(data->memInfo.memObjDesc),
+ get_counter_id(data),
+ "Available Swap Kilobytes",
+ "Available Swap Kilobytes is the number of free kilobytes in swap space",
+ PERF_SIZE_DWORD | PERF_TYPE_NUMBER | PERF_NUMBER_DECIMAL | PERF_DISPLAY_NO_SUFFIX,
+ PERF_COUNTER);
+ init_perf_counter(&(data->memInfo.totalPhysKb),
+ &(data->memInfo.memObjDesc),
+ get_counter_id(data),
+ "Total Physical Kilobytes",
+ "Total Physical Kilobytes is a base counter",
+ PERF_SIZE_DWORD | PERF_TYPE_NUMBER | PERF_NUMBER_DECIMAL | PERF_COUNTER_BASE | PERF_DISPLAY_NOSHOW,
+ PERF_COUNTER);
+ init_perf_counter(&(data->memInfo.totalSwapKb),
+ &(data->memInfo.memObjDesc),
+ get_counter_id(data),
+ "Total Swap Kilobytes",
+ "Total Swap Kilobytes is a base counter",
+ PERF_SIZE_DWORD | PERF_TYPE_NUMBER | PERF_NUMBER_DECIMAL | PERF_COUNTER_BASE | PERF_DISPLAY_NOSHOW,
+ PERF_COUNTER);
+
+ return;
+}
+
+void init_mem_data(PERF_DATA_BLOCK *data)
+{
+ data->memInfo.data = calloc(1, sizeof(*data->memInfo.data));
+ if(!data->memInfo.data)
+ {
+ perror("init_memdata: out of memory");
+ exit(1);
+ }
+
+ init_memdata_desc(data);
+
+ get_meminfo(data);
+
+ return;
+}
+
+void output_mem_desc(PERF_DATA_BLOCK *data, RuntimeSettings rt)
+{
+ output_perf_desc(data->memInfo.memObjDesc, rt);
+ output_perf_desc(data->memInfo.availPhysKb, rt);
+ output_perf_desc(data->memInfo.availSwapKb, rt);
+ output_perf_desc(data->memInfo.totalPhysKb, rt);
+ output_perf_desc(data->memInfo.totalSwapKb, rt);
+
+ return;
+}
+
+void output_meminfo(PERF_DATA_BLOCK *data, RuntimeSettings rt, int tdb_flags)
+{
+ output_perf_counter(data->memInfo.availPhysKb,
+ (unsigned long long)data->memInfo.data->availPhysKb,
+ rt, tdb_flags);
+ output_perf_counter(data->memInfo.availSwapKb,
+ (unsigned long long)data->memInfo.data->availSwapKb,
+ rt, tdb_flags);
+ output_perf_counter(data->memInfo.totalPhysKb,
+ (unsigned long long)data->memInfo.data->totalPhysKb,
+ rt, tdb_flags);
+ output_perf_counter(data->memInfo.totalSwapKb,
+ (unsigned long long)data->memInfo.data->totalSwapKb,
+ rt, tdb_flags);
+
+ return;
+}
diff --git a/examples/perfcounter/perf_writer_process.c b/examples/perfcounter/perf_writer_process.c
new file mode 100644
index 0000000..bddceea
--- /dev/null
+++ b/examples/perfcounter/perf_writer_process.c
@@ -0,0 +1,85 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Performance Counter Daemon
+ *
+ * Copyright (C) Marcin Krzysztof Porwit 2005
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "perf.h"
+
+void get_processinfo(PERF_DATA_BLOCK *data)
+{
+ int status;
+ struct sysinfo info;
+ status = sysinfo(&info);
+
+ data->processInfo.data->runningProcessCount = (unsigned int)info.procs;
+
+ return;
+}
+
+void init_processdata_desc(PERF_DATA_BLOCK *data)
+{
+ init_perf_counter(&(data->processInfo.processObjDesc),
+ &(data->processInfo.processObjDesc),
+ get_counter_id(data),
+ "Processes",
+ "%The Processes performance object displays aggregate information about processes on the machine.",
+ 0,
+ PERF_OBJECT);
+ init_perf_counter(&(data->processInfo.runningProcessCount),
+ &(data->processInfo.processObjDesc),
+ get_counter_id(data),
+ "Process Count",
+ "Process Count is the number of processes currently on the machine.",
+ PERF_SIZE_DWORD | PERF_TYPE_NUMBER | PERF_NUMBER_DECIMAL | PERF_DISPLAY_NO_SUFFIX,
+ PERF_COUNTER);
+
+ return;
+}
+
+void init_process_data(PERF_DATA_BLOCK *data)
+{
+ data->processInfo.data = calloc(1, sizeof(*data->processInfo.data));
+ if(!(data->processInfo.data))
+ {
+ perror("init_process_data: out of memory");
+ exit(1);
+ }
+
+ init_processdata_desc(data);
+
+ get_processinfo(data);
+
+ return;
+}
+
+void output_processinfo(PERF_DATA_BLOCK *data, RuntimeSettings rt, int tdb_flags)
+{
+ output_perf_counter(data->processInfo.runningProcessCount,
+ (unsigned long long)data->processInfo.data->runningProcessCount,
+ rt, tdb_flags);
+
+ return;
+}
+
+void output_process_desc(PERF_DATA_BLOCK *data, RuntimeSettings rt)
+{
+ output_perf_desc(data->processInfo.processObjDesc, rt);
+ output_perf_desc(data->processInfo.runningProcessCount, rt);
+
+ return;
+}
diff --git a/examples/perfcounter/perf_writer_util.c b/examples/perfcounter/perf_writer_util.c
new file mode 100644
index 0000000..6f1eb16
--- /dev/null
+++ b/examples/perfcounter/perf_writer_util.c
@@ -0,0 +1,235 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Performance Counter Daemon
+ *
+ * Copyright (C) Marcin Krzysztof Porwit 2005
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "perf.h"
+
+extern sig_atomic_t keep_running;
+
+void fatal(char *msg)
+{
+ perror(msg);
+ exit(1);
+}
+
+void add_key_raw(TDB_CONTEXT *db, char *keystring, void *databuf, size_t datasize, int flags)
+{
+ TDB_DATA key, data;
+
+ key.dptr = keystring;
+ key.dsize = strlen(keystring);
+ data.dptr = databuf;
+ data.dsize = datasize;
+
+ tdb_store(db, key, data, flags);
+}
+
+void add_key(TDB_CONTEXT *db, char *keystring, char *datastring, int flags)
+{
+ TDB_DATA key, data;
+
+ key.dptr = keystring;
+ key.dsize = strlen(keystring);
+ data.dptr = datastring;
+ data.dsize = strlen(datastring);
+
+ tdb_store(db, key, data, flags);
+}
+
+void make_key(char *buf, int buflen, int key_part1, char *key_part2)
+{
+ memset(buf, 0, buflen);
+ if(key_part2 != NULL)
+ sprintf(buf, "%d%s", key_part1, key_part2);
+ else
+ sprintf(buf, "%d", key_part1);
+
+ return;
+}
+
+void usage(char *progname)
+{
+ fprintf(stderr, "Usage: %s [-d] [-f <file_path>].\n", progname);
+ fprintf(stderr, "\t-d: run as a daemon.\n");
+ fprintf(stderr, "\t-f <file_path>: path where the TDB files reside.\n");
+ fprintf(stderr, "\t\tDEFAULT is /var/lib/samba/perfmon\n");
+ exit(1);
+}
+
+void parse_flags(RuntimeSettings *rt, int argc, char **argv)
+{
+ int flag;
+
+ while((flag = getopt(argc, argv, "df:")) != -1)
+ {
+ switch(flag)
+ {
+ case 'd':
+ {
+ rt->dflag = TRUE;
+ break;
+ }
+ case 'f':
+ {
+ memcpy(rt->dbDir, optarg, strlen(optarg));
+ break;
+ }
+ default:
+ {
+ usage(argv[0]);
+ }
+ }
+ }
+
+ return;
+}
+
+void setup_file_paths(RuntimeSettings *rt)
+{
+ int status;
+
+ if(strlen(rt->dbDir) == 0)
+ {
+ /* No file path was passed in, use default */
+ sprintf(rt->dbDir, "/var/lib/samba/perfmon");
+ }
+
+ sprintf(rt->nameFile, "%s/names.tdb", rt->dbDir);
+ sprintf(rt->counterFile, "%s/data.tdb", rt->dbDir);
+
+ mkdir(rt->dbDir, 0755);
+ rt->cnames = tdb_open(rt->nameFile, 0, TDB_CLEAR_IF_FIRST, O_RDWR | O_CREAT, 0644);
+ rt->cdata = tdb_open(rt->counterFile, 0, TDB_CLEAR_IF_FIRST, O_RDWR | O_CREAT, 0644);
+
+ if(rt->cnames == NULL || rt->cdata == NULL)
+ {
+ perror("setup_file_paths");
+ exit(1);
+ }
+
+ return;
+}
+
+void sigterm_handler()
+{
+ keep_running = FALSE;
+ return;
+}
+
+void daemonize(RuntimeSettings *rt)
+{
+ pid_t pid;
+ int i;
+ int fd;
+
+ /* Check if we're already a daemon */
+ if(getppid() == 1)
+ return;
+ pid = fork();
+ if(pid < 0)
+ /* can't fork */
+ exit(1);
+ else if(pid > 0)
+ {
+ /* we're the parent */
+ tdb_close(rt->cnames);
+ tdb_close(rt->cdata);
+ exit(0);
+ }
+
+ /* get a new session */
+ if(setsid() == -1)
+ exit(2);
+
+ /* Change CWD */
+ chdir("/");
+
+ /* close file descriptors */
+ close(STDIN_FILENO);
+ close(STDOUT_FILENO);
+ close(STDERR_FILENO);
+
+ /* And reopen them as safe defaults */
+ fd = open("/dev/null", O_RDONLY);
+ if(fd != 0)
+ {
+ dup2(fd, 0);
+ close(fd);
+ }
+ fd = open("/dev/null", O_WRONLY);
+ if(fd != 1)
+ {
+ dup2(fd, 1);
+ close(fd);
+ }
+ fd = open("/dev/null", O_WRONLY);
+ if(fd != 2)
+ {
+ dup2(fd, 2);
+ close(fd);
+ }
+
+ /* handle signals */
+ signal(SIGINT, SIG_IGN);
+ signal(SIGHUP, SIG_IGN);
+ signal(SIGTERM, sigterm_handler);
+
+ return;
+}
+
+int get_counter_id(PERF_DATA_BLOCK *data)
+{
+ data->counter_id += 2;
+ data->num_counters++;
+
+ return data->counter_id;
+}
+
+void init_perf_counter(PerfCounter *counter,
+ PerfCounter *parent,
+ unsigned int index,
+ char *name,
+ char *help,
+ int counter_type,
+ int record_type)
+{
+ counter->index = index;
+ memcpy(counter->name, name, strlen(name));
+ memcpy(counter->help, help, strlen(help));
+ counter->counter_type = counter_type;
+ counter->record_type = record_type;
+
+ switch(record_type)
+ {
+ case PERF_OBJECT:
+ sprintf(counter->relationships, "p");
+ break;
+ case PERF_COUNTER:
+ sprintf(counter->relationships, "c[%d]", parent->index);
+ break;
+ case PERF_INSTANCE:
+ sprintf(counter->relationships, "i[%d]", parent->index);
+ break;
+ default:
+ perror("init_perf_counter: unknown record type");
+ exit(1);
+ }
+
+ return;
+}
diff --git a/examples/perfcounter/perfcountd.init b/examples/perfcounter/perfcountd.init
new file mode 100755
index 0000000..0beff96
--- /dev/null
+++ b/examples/perfcounter/perfcountd.init
@@ -0,0 +1,65 @@
+#!/bin/sh
+#
+# Copyright (C) Gerald Carter 2005
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+####################################################################
+
+## This file should have uid root, gid sys and chmod 744
+
+PATH=/bin:/usr/bin:/sbin:/usr/sbin
+
+killproc()
+{
+ pid=`ps aux | grep $1 | egrep -v '(grep|perfcountd)' | awk '{print $2}'`
+ if [ x"$pid" != "x" ]; then
+ kill $pid
+ fi
+}
+
+# Start/stop processes
+
+case "$1"
+in
+start)
+ /opt/samba/bin/perfcount -d -f /var/lib/samba/perfmon 2> /dev/null
+ if [ $? -ne 0 ]; then
+ echo "Failed!"
+ exit 1
+ fi
+ echo "done!"
+ ;;
+stop)
+ killproc perfcount
+ ;;
+
+status)
+ pid=`ps aux | grep perfcount | egrep -v '(grep|perfcountd)' | awk '{print $2}'`
+ if [ x"$pid" = "x" ]; then
+ echo "Dead!"
+ exit 2;
+ fi
+ echo "OK!"
+ ;;
+restart)
+ $0 stop && $0 start
+ ;;
+
+*)
+ echo "Usage: $0 { start|stop|restart|status }"
+ ;;
+esac
+
+