summaryrefslogtreecommitdiff
path: root/src/libpcp/src/fault.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libpcp/src/fault.c')
-rw-r--r--src/libpcp/src/fault.c314
1 files changed, 314 insertions, 0 deletions
diff --git a/src/libpcp/src/fault.c b/src/libpcp/src/fault.c
new file mode 100644
index 0000000..5ba8bf0
--- /dev/null
+++ b/src/libpcp/src/fault.c
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 2011 Ken McDonell. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public
+ * License for more details.
+ */
+
+#include "pmapi.h"
+#include "impl.h"
+#include "fault.h"
+/* need pmda.h and libpcp_pmda for the pmdaCache* routines */
+#include "pmda.h"
+
+#include <ctype.h>
+
+/*
+ * Fault Injection - run-time control structure
+ */
+typedef struct {
+ int ntrip;
+ int op;
+ int thres;
+ int nfault;
+} control_t;
+
+#define PM_FAULT_LT 0
+#define PM_FAULT_LE 1
+#define PM_FAULT_EQ 2
+#define PM_FAULT_GE 3
+#define PM_FAULT_GT 4
+#define PM_FAULT_NE 5
+#define PM_FAULT_MOD 6
+
+#ifdef PM_FAULT_INJECTION
+
+int __pmFault_arm;
+
+#define FAULT_INDOM pmInDom_build(DYNAMIC_PMID, 1024)
+
+static void
+__pmFaultAtExit(void)
+{
+ __pmFaultSummary(stderr);
+}
+
+void
+__pmFaultInject(const char *ident, int class)
+{
+ static int first = 1;
+ int sts;
+ control_t *cp;
+
+ if (first) {
+ char *fname = getenv("PM_FAULT_CONTROL");
+ if (fname != NULL) {
+ FILE *f;
+ if ((f = fopen(fname, "r")) == NULL) {
+ char msgbuf[PM_MAXERRMSGLEN];
+ fprintf(stderr, "__pmFaultInject: cannot open \"%s\": %s\n", fname, pmErrStr_r(-errno, msgbuf, sizeof(msgbuf)));
+ }
+ else {
+ char line[128];
+ int lineno = 0;
+ /*
+ * control line format
+ * ident - start of line to first white space
+ * guard - optional, consists of <op> and threshold
+ * <op> is one of <, <=, ==, >=, >=, != or %
+ * threshold is an integer value ...
+ * fault will be injected when
+ * tripcount <op> threshold == 1
+ * default guard is ">0", i.e. fault on every trip
+ * leading # => comment
+ */
+ pmdaCacheOp(FAULT_INDOM, PMDA_CACHE_CULL);
+ while (fgets(line, sizeof(line), f) != NULL) {
+ char *lp = line;
+ char *sp;
+ char *ep;
+ int op;
+ int thres;
+ lineno++;
+ while (*lp) {
+ if (*lp == '\n') {
+ *lp = '\0';
+ break;
+ }
+ lp++;
+ }
+ lp = line;
+ while (*lp && isspace((int)*lp)) lp++;
+ /* comment? */
+ if (*lp == '#')
+ continue;
+ sp = lp;
+ while (*lp && !isspace((int)*lp)) lp++;
+ /* empty line? */
+ if (lp == sp)
+ continue;
+ ep = lp;
+ while (*lp && isspace((int)*lp)) lp++;
+ if (*lp == '\0') {
+ op = PM_FAULT_GT;
+ thres = 0;
+ }
+ else {
+ if (strncmp(lp, "<=", 2) == 0) {
+ op = PM_FAULT_LE;
+ lp +=2;
+ }
+ else if (strncmp(lp, ">=", 2) == 0) {
+ op = PM_FAULT_GE;
+ lp +=2;
+ }
+ else if (strncmp(lp, "!=", 2) == 0) {
+ op = PM_FAULT_NE;
+ lp +=2;
+ }
+ else if (strncmp(lp, "==", 2) == 0) {
+ op = PM_FAULT_EQ;
+ lp +=2;
+ }
+ else if (*lp == '<') {
+ op = PM_FAULT_LT;
+ lp++;
+ }
+ else if (*lp == '>') {
+ op = PM_FAULT_GT;
+ lp++;
+ }
+ else if (*lp == '%') {
+ op = PM_FAULT_MOD;
+ lp++;
+ }
+ else {
+ fprintf(stderr, "Ignoring: %s[%d]: illegal operator: %s\n", fname, lineno, line);
+ continue;
+ }
+ }
+ while (*lp && isspace((int)*lp)) lp++;
+ thres = (int)strtol(lp, &lp, 10);
+ while (*lp && isspace((int)*lp)) lp++;
+ if (*lp != '\0') {
+ fprintf(stderr, "Ignoring: %s[%d]: non-numeric threshold: %s\n", fname, lineno, line);
+ continue;
+ }
+ cp = (control_t *)malloc(sizeof(control_t));
+ if (cp == NULL) {
+ char errmsg[PM_MAXERRMSGLEN];
+ fprintf(stderr, "__pmFaultInject: malloc failed: %s\n", pmErrStr_r(-errno, errmsg, sizeof(errmsg)));
+ break;
+ }
+ *ep = '\0';
+ cp->ntrip = cp->nfault = 0;
+ cp->op = op;
+ cp->thres = thres;
+ sts = pmdaCacheStore(FAULT_INDOM, PMDA_CACHE_ADD, sp, cp);
+ if (sts < 0) {
+ char errmsg[PM_MAXERRMSGLEN];
+ fprintf(stderr, "%s[%d]: %s\n", fname, lineno, pmErrStr_r(sts, errmsg, sizeof(errmsg)));
+ }
+ }
+ fclose(f);
+ }
+ }
+#ifdef HAVE_ATEXIT
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_FAULT)
+ atexit(__pmFaultAtExit);
+#endif
+#endif
+ first = 0;
+ }
+
+ sts = pmdaCacheLookupName(FAULT_INDOM, ident, NULL, (void **)&cp);
+ if (sts == PMDA_CACHE_ACTIVE) {
+ cp->ntrip++;
+ __pmFault_arm = 0;
+ switch (cp->op) {
+ case PM_FAULT_LT:
+ __pmFault_arm = (cp->ntrip < cp->thres) ? class : 0;
+ break;
+ case PM_FAULT_LE:
+ __pmFault_arm = (cp->ntrip <= cp->thres) ? class : 0;
+ break;
+ case PM_FAULT_EQ:
+ __pmFault_arm = (cp->ntrip == cp->thres) ? class : 0;
+ break;
+ case PM_FAULT_GE:
+ __pmFault_arm = (cp->ntrip >= cp->thres) ? class : 0;
+ break;
+ case PM_FAULT_GT:
+ __pmFault_arm = (cp->ntrip > cp->thres) ? class : 0;
+ break;
+ case PM_FAULT_NE:
+ __pmFault_arm = (cp->ntrip != cp->thres) ? class : 0;
+ break;
+ case PM_FAULT_MOD:
+ __pmFault_arm = ((cp->ntrip % cp->thres) == 1) ? class : 0;
+ break;
+ }
+ if (__pmFault_arm != 0)
+ cp->nfault++;
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_FAULT)
+ fprintf(stderr, "__pmFaultInject(%s) ntrip=%d %s\n", ident, cp->ntrip, __pmFault_arm == 0 ? "SKIP" : "INJECT");
+#endif
+ }
+ else if (sts == PM_ERR_INST) {
+ /*
+ * expected for injection points that are compiled in the code
+ * but not registered via the control file
+ */
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_FAULT)
+ fprintf(stderr, "__pmFaultInject(%s) not registered\n", ident);
+#endif
+ ;
+ }
+ else {
+ /* oops, this is serious */
+ char errmsg[PM_MAXERRMSGLEN];
+ fprintf(stderr, "__pmFaultInject(%s): %s\n", ident, pmErrStr_r(sts, errmsg, sizeof(errmsg)));
+ }
+
+}
+
+void
+__pmFaultSummary(FILE *f)
+{
+ int inst;
+ char *ident;
+ control_t *cp;
+ int sts;
+ static char *opstr[] = { "<", "<=", "==", ">=", ">", "!=", "%" };
+
+ pmdaCacheOp(FAULT_INDOM, PMDA_CACHE_WALK_REWIND);
+
+ fprintf(f, "=== Fault Injection Summary Report ===\n");
+ while ((inst = pmdaCacheOp(FAULT_INDOM, PMDA_CACHE_WALK_NEXT)) != -1) {
+ sts = pmdaCacheLookup(FAULT_INDOM, inst, &ident, (void **)&cp);
+ if (sts < 0) {
+ char strbuf[20];
+ char errmsg[PM_MAXERRMSGLEN];
+ fprintf(f, "pmdaCacheLookup(%s, %d, %s, ..): %s\n", pmInDomStr_r(FAULT_INDOM, strbuf, sizeof(strbuf)), inst, ident, pmErrStr_r(sts, errmsg, sizeof(errmsg)));
+ }
+ else
+ fprintf(f, "%s: guard trip%s%d, %d trips, %d faults\n", ident, opstr[cp->op], cp->thres, cp->ntrip, cp->nfault);
+
+ }
+}
+
+void
+*__pmFault_malloc(size_t size)
+{
+ if (__pmFault_arm == PM_FAULT_ALLOC) {
+ __pmFault_arm = 0;
+ errno = ENOMEM;
+ return NULL;
+ }
+ else
+#undef malloc
+ return malloc(size);
+}
+
+void
+*__pmFault_realloc(void *ptr, size_t size)
+{
+ if (__pmFault_arm == PM_FAULT_ALLOC) {
+ __pmFault_arm = 0;
+ errno = ENOMEM;
+ return NULL;
+ }
+ else
+#undef realloc
+ return realloc(ptr, size);
+}
+
+char *
+__pmFault_strdup(const char *s)
+{
+ if (__pmFault_arm == PM_FAULT_ALLOC) {
+ __pmFault_arm = 0;
+ errno = ENOMEM;
+ return NULL;
+ }
+ else
+#undef strdup
+ return strdup(s);
+}
+
+#else
+void
+__pmFaultInject(const char *ident, int class)
+{
+ fprintf(stderr, "__pmFaultInject() called but library not compiled with -DPM_FAULT_INJECTION\n");
+ exit(1);
+}
+
+void
+__pmFaultSummary(FILE *f)
+{
+ fprintf(f, "__pmFaultSummary() called but library not compiled with -DPM_FAULT_INJECTION\n");
+ exit(1);
+
+}
+#endif