/* evaluate Task */ static void eval(Task *task) { Symbol *s; pmValueSet *vset; int i; /* fetch metrics */ taskFetch(task); /* evaluate rule expressions */ s = task->rules; for (i = 0; i < task->nrules; i++) { curr = symValue(*s); if (curr->op < NOP) { (curr->eval)(curr); perf->eval_actual++; } s++; } if (verbose) { /* send binary values */ if (agent) { int sts; s = task->rules; for (i = 0; i < task->nrules; i++) { vset = task->rslt->vset[i]; fillVSet(symValue(*s), vset); s++; } __pmOverrideLastFd(PDU_OVERRIDE2); sts = __pmSendResult(STDOUT_FILENO, pmWhichContext(), task->rslt); if (sts < 0) { fprintf(stderr, "Error: __pmSendResult to summary agent failed: %s\n", pmErrStr(sts)); exit(0); } } /* send values to applet */ else if (applet) { s = task->rules; for (i = 0; i < task->nrules; i++) { showValue(stdout, symValue(*s)); putchar(' '); s++; } putchar('\n'); } /* print values in ASCII */ else { s = task->rules; for (i = 0; i < task->nrules; i++) { printf("%s", symName(*s)); if (archives || showTimeFlag) { printf(" ("); showTime(stdout, now); putchar(')'); } printf(": "); switch (verbose) { case 1: showValue(stdout, symValue(*s)); break; case 2: showAnnotatedValue(stdout, symValue(*s)); break; case 3: showSatisfyingValue(stdout, symValue(*s)); break; } putchar('\n'); s++; } putchar('\n'); } } }
int DoFetch(ClientInfo *cip, __pmPDU* pb) { int i, j; int sts; int ctxnum; __pmTimeval when; int nPmids; pmID *pmidList; static pmResult *endResult = NULL; static int maxnpmids = 0; /* sizes endResult */ DomPmidList *dList; /* NOTE: NOT indexed by agent index */ static int nDoms = 0; static pmResult **results = NULL; static int *resIndex = NULL; __pmFdSet waitFds; __pmFdSet readyFds; int nWait; int maxFd; struct timeval timeout; if (nAgents > nDoms) { if (results != NULL) free(results); if (resIndex != NULL) free(resIndex); results = (pmResult **)malloc((nAgents + 1) * sizeof (pmResult *)); resIndex = (int *)malloc((nAgents + 1) * sizeof(int)); if (results == NULL || resIndex == NULL) { __pmNoMem("DoFetch.results", (nAgents + 1) * sizeof (pmResult *) + (nAgents + 1) * sizeof(int), PM_FATAL_ERR); } nDoms = nAgents; } memset(results, 0, (nAgents + 1) * sizeof(results[0])); sts = __pmDecodeFetch(pb, &ctxnum, &when, &nPmids, &pmidList); if (sts < 0) return sts; /* Check that a profile has been received from the specified context */ if (ctxnum < 0 || ctxnum >= cip->szProfile || cip->profile[ctxnum] == NULL) { __pmUnpinPDUBuf(pb); if (ctxnum < 0 || ctxnum >= cip->szProfile) __pmNotifyErr(LOG_ERR, "DoFetch: bad ctxnum=%d\n", ctxnum); else __pmNotifyErr(LOG_ERR, "DoFetch: no profile for ctxnum=%d\n", ctxnum); return PM_ERR_NOPROFILE; } if (nPmids > maxnpmids) { int need; if (endResult != NULL) free(endResult); need = (int)sizeof(pmResult) + (nPmids - 1) * (int)sizeof(pmValueSet *); if ((endResult = (pmResult *)malloc(need)) == NULL) { __pmNoMem("DoFetch.endResult", need, PM_FATAL_ERR); } maxnpmids = nPmids; } dList = SplitPmidList(nPmids, pmidList); /* For each domain in the split pmidList, dispatch the per-domain subset * of pmIDs to the appropriate agent. For DSO agents, the pmResult will * come back immediately. If a request cannot be sent to an agent, a * suitable pmResult (containing metric not available values) will be * returned. */ __pmFD_ZERO(&waitFds); nWait = 0; maxFd = -1; for (i = 0; dList[i].domain != -1; i++) { j = mapdom[dList[i].domain]; results[j] = SendFetch(&dList[i], &agent[j], cip, ctxnum); if (results[j] == NULL) { /* Wait for agent's response */ int fd = agent[j].outFd; agent[j].status.busy = 1; __pmFD_SET(fd, &waitFds); if (fd > maxFd) maxFd = fd; nWait++; } } /* Construct pmResult for bad-pmID list */ if (dList[i].listSize != 0) results[nAgents] = MakeBadResult(dList[i].listSize, dList[i].list, PM_ERR_NOAGENT); /* Wait for results to roll in from agents */ while (nWait > 0) { __pmFD_COPY(&readyFds, &waitFds); if (nWait > 1) { timeout.tv_sec = _pmcd_timeout; timeout.tv_usec = 0; retry: setoserror(0); sts = __pmSelectRead(maxFd+1, &readyFds, &timeout); if (sts == 0) { __pmNotifyErr(LOG_INFO, "DoFetch: select timeout"); /* Timeout, terminate agents with undelivered results */ for (i = 0; i < nAgents; i++) { if (agent[i].status.busy) { /* Find entry in dList for this agent */ for (j = 0; dList[j].domain != -1; j++) if (dList[j].domain == agent[i].pmDomainId) break; results[i] = MakeBadResult(dList[j].listSize, dList[j].list, PM_ERR_NOAGENT); pmcd_trace(TR_RECV_TIMEOUT, agent[i].outFd, PDU_RESULT, 0); CleanupAgent(&agent[i], AT_COMM, agent[i].inFd); } } break; } else if (sts < 0) { if (neterror() == EINTR) goto retry; /* this is not expected to happen! */ __pmNotifyErr(LOG_ERR, "DoFetch: fatal select failure: %s\n", netstrerror()); Shutdown(); exit(1); } } /* Read results from agents that have them ready */ for (i = 0; i < nAgents; i++) { AgentInfo *ap = &agent[i]; int pinpdu; if (!ap->status.busy || !__pmFD_ISSET(ap->outFd, &readyFds)) continue; ap->status.busy = 0; __pmFD_CLR(ap->outFd, &waitFds); nWait--; pinpdu = sts = __pmGetPDU(ap->outFd, ANY_SIZE, _pmcd_timeout, &pb); if (sts > 0) pmcd_trace(TR_RECV_PDU, ap->outFd, sts, (int)((__psint_t)pb & 0xffffffff)); if (sts == PDU_RESULT) { if ((sts = __pmDecodeResult(pb, &results[i])) >= 0) if (results[i]->numpmid != aFreq[i]) { pmFreeResult(results[i]); sts = PM_ERR_IPC; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_ERR, "DoFetch: \"%s\" agent given %d pmIDs, returned %d\n", ap->pmDomainLabel, aFreq[i], results[i]->numpmid); #endif } } else { if (sts == PDU_ERROR) { int s; if ((s = __pmDecodeError(pb, &sts)) < 0) sts = s; else if (sts >= 0) sts = PM_ERR_GENERIC; pmcd_trace(TR_RECV_ERR, ap->outFd, PDU_RESULT, sts); } else if (sts >= 0) { pmcd_trace(TR_WRONG_PDU, ap->outFd, PDU_RESULT, sts); sts = PM_ERR_IPC; } } if (pinpdu > 0) __pmUnpinPDUBuf(pb); if (sts < 0) { /* Find entry in dList for this agent */ for (j = 0; dList[j].domain != -1; j++) if (dList[j].domain == agent[i].pmDomainId) break; results[i] = MakeBadResult(dList[j].listSize, dList[j].list, sts); if (sts == PM_ERR_PMDANOTREADY) { /* the agent is indicating it can't handle PDUs for now */ int k; extern int CheckError(AgentInfo *ap, int sts); for (k = 0; k < dList[j].listSize; k++) results[i]->vset[k]->numval = PM_ERR_AGAIN; sts = CheckError(&agent[i], sts); } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { fprintf(stderr, "RESULT error from \"%s\" agent : %s\n", ap->pmDomainLabel, pmErrStr(sts)); } #endif if (sts == PM_ERR_IPC || sts == PM_ERR_TIMEOUT) CleanupAgent(ap, AT_COMM, ap->outFd); } } } endResult->numpmid = nPmids; __pmtimevalNow(&endResult->timestamp); /* The order of the pmIDs in the per-domain results is the same as in the * original request, but on a per-domain basis. resIndex is an array of * indices (one per agent) of the next metric to be retrieved from each * per-domain result's vset. */ memset(resIndex, 0, (nAgents + 1) * sizeof(resIndex[0])); for (i = 0; i < nPmids; i++) { j = mapdom[((__pmID_int *)&pmidList[i])->domain]; endResult->vset[i] = results[j]->vset[resIndex[j]++]; } pmcd_trace(TR_XMIT_PDU, cip->fd, PDU_RESULT, endResult->numpmid); sts = 0; if (cip->status.changes) { /* notify client of PMCD state change */ sts = __pmSendError(cip->fd, FROM_ANON, (int)cip->status.changes); if (sts > 0) sts = 0; cip->status.changes = 0; } if (sts == 0) sts = __pmSendResult(cip->fd, FROM_ANON, endResult); if (sts < 0) { pmcd_trace(TR_XMIT_ERR, cip->fd, PDU_RESULT, sts); CleanupClient(cip, sts); } /* * pmFreeResult() all the accumulated results. */ for (i = 0; dList[i].domain != -1; i++) { j = mapdom[dList[i].domain]; if (agent[j].ipcType == AGENT_DSO && agent[j].status.connected && !agent[j].status.madeDsoResult) /* Living DSO's manage their own pmResult skeleton unless * MakeBadResult was called to create the result. The value sets * within the skeleton need to be freed though! */ __pmFreeResultValues(results[j]); else /* For others it is dynamically allocated in __pmDecodeResult or * MakeBadResult */ pmFreeResult(results[j]); } if (results[nAgents] != NULL) pmFreeResult(results[nAgents]); __pmUnpinPDUBuf(pmidList); return 0; }
static int do_control(__pmPDU *pb) { int sts; int control; int state; int delta; pmResult *request; pmResult *result; int siamised = 0; /* the verb from siamese (as in twins) */ int i; int j; int val; pmValueSet *vsp; optreq_t *rqp; task_t *tp; time_t now; int reqstate = 0; /* * TODO - encoding for logging interval in requests and results? */ if ((sts = __pmDecodeLogControl(pb, &request, &control, &state, &delta)) < 0) return sts; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) { fprintf(stderr, "do_control: control=%d state=%d delta=%d request ...\n", control, state, delta); dumpcontrol(stderr, request, 0); } #endif if (control == PM_LOG_MANDATORY || control == PM_LOG_ADVISORY) { time(&now); fprintf(stderr, "\n%s", ctime(&now)); fprintf(stderr, "pmlc request from %s: %s", pmlc_host, control == PM_LOG_MANDATORY ? "mandatory" : "advisory"); if (state == PM_LOG_ON) { if (delta == 0) fprintf(stderr, " on once\n"); else fprintf(stderr, " on %.1f sec\n", (float)delta/1000); } else if (state == PM_LOG_OFF) fprintf(stderr, " off\n"); else fprintf(stderr, " maybe\n"); } /* * access control checks */ sts = 0; switch (control) { case PM_LOG_MANDATORY: if (denyops & PM_OP_LOG_MAND) sts = PM_ERR_PERMISSION; break; case PM_LOG_ADVISORY: if (denyops & PM_OP_LOG_ADV) sts = PM_ERR_PERMISSION; break; case PM_LOG_ENQUIRE: /* * Don't need to check [access] as you have to have _some_ * permission (at least one of PM_OP_LOG_ADV or PM_OP_LOG_MAND * and PM_OP_LOG_ENQ) to make a connection ... and if you * have either PM_OP_LOG_ADV or PM_OP_LOG_MAND it makes no * sense to deny PM_OP_LOG_ENQ operations. */ break; default: fprintf(stderr, "Bad control PDU type %d\n", control); sts = PM_ERR_IPC; break; } if (sts < 0) { fprintf(stderr, "Error: %s\n", pmErrStr(sts)); if ((sts = __pmSendError(clientfd, FROM_ANON, sts)) < 0) __pmNotifyErr(LOG_ERR, "do_control: error sending Error PDU to client: %s\n", pmErrStr(sts)); pmFreeResult(request); return sts; } /* handle everything except PM_LOG_ENQUIRE */ if (control == PM_LOG_MANDATORY || control == PM_LOG_ADVISORY) { /* update the logging status of metrics */ task_t *newtp = NULL; /* task for metrics/insts in request */ struct timeval tdelta = { 0 }; int newtask; int mflags; /* convert state and control to the bitmask used in pmlogger and values * returned in results. Remember that reqstate starts with nothing on. */ if (state == PM_LOG_ON) PMLC_SET_ON(reqstate, 1); else PMLC_SET_ON(reqstate, 0); if (control == PM_LOG_MANDATORY) { if (state == PM_LOG_MAYBE) /* mandatory+maybe => maybe+advisory+off */ PMLC_SET_MAYBE(reqstate, 1); else PMLC_SET_MAND(reqstate, 1); } /* try to find an existing task for the request * Never return a "once only" task, it may have gone off already and just * be hanging around like a bad smell. */ if (delta != 0) { tdelta.tv_sec = delta / 1000; tdelta.tv_usec = (delta % 1000) * 1000; newtp = find_task(reqstate, &tdelta); } newtask = (newtp == NULL); for (i = 0; i < request->numpmid; i++) { vsp = request->vset[i]; if (vsp->numval < 0) /* * request is malformed, as we cannot control logging * for an undefined instance ... there is no way to * return an error from here, so simply ignore this * metric */ continue; mflags = find_metric(vsp->pmid); if (mflags < 0) { /* only add new metrics if they are ON or MANDATORY OFF * Careful: mandatory+maybe is mandatory+maybe+off */ if (PMLC_GET_ON(reqstate) || (PMLC_GET_MAND(reqstate) && !PMLC_GET_MAYBE(reqstate))) add_metric(vsp, &newtp); } else /* already a specification for this metric */ update_metric(vsp, reqstate, mflags, &newtp); } /* schedule new logging task if new metric(s) specified */ if (newtask && newtp != NULL) { if (newtp->t_fetch == NULL) { /* the new task ended up with no fetch groups, throw it away */ if (newtp->t_pmidlist != NULL) free(newtp->t_pmidlist); free(newtp); } else { /* link new task into tasklist */ newtp->t_next = tasklist; tasklist = newtp; /* use only the MAND/ADV and ON/OFF bits of reqstate */ newtp->t_state = PMLC_GET_STATE(reqstate); if (PMLC_GET_ON(reqstate)) { newtp->t_delta = tdelta; newtp->t_afid = __pmAFregister(&tdelta, (void *)newtp, log_callback); } else newtp->t_delta.tv_sec = newtp->t_delta.tv_usec = 0; linkback(newtp); } } } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) dumpit(); #endif /* just ignore advisory+maybe---the returned pmResult will have the metrics * in their original state indicating that the request could not be * satisfied. */ result = request; result->timestamp.tv_sec = result->timestamp.tv_usec = 0; /* for purify */ /* write the current state of affairs into the result _pmResult */ for (i = 0; i < request->numpmid; i++) { if (control == PM_LOG_MANDATORY || control == PM_LOG_ADVISORY) { char **names; sts = pmNameAll(request->vset[i]->pmid, &names); if (sts < 0) fprintf(stderr, " metric: %s", pmIDStr(request->vset[i]->pmid)); else { fprintf(stderr, " metric: "); __pmPrintMetricNames(stderr, sts, names, " or "); free(names); } } if (request->vset[i]->numval <= 0 && !siamised) { result = siamise_request(request); siamised = 1; } /* * pmids with numval <= 0 in the request have a null vset ptr in the * in the corresponding place in the siamised result. */ if (result->vset[i] != NULL) vsp = result->vset[i]; else { /* the result should also contain the history for an all instances * enquire request. Control requests just get the current indom * since the user of pmlc really wants to see what's being logged * now rather than in the past. */ vsp = build_vset(request->vset[i]->pmid, control == PM_LOG_ENQUIRE); result->vset[i] = vsp; } vsp->valfmt = PM_VAL_INSITU; for (j = 0; j < vsp->numval; j++) { rqp = findoptreq(vsp->pmid, vsp->vlist[j].inst); val = 0; if (rqp == NULL) { PMLC_SET_STATE(val, 0); PMLC_SET_DELTA(val, 0); } else { tp = rqp->r_fetch->f_aux; PMLC_SET_STATE(val, tp->t_state); PMLC_SET_DELTA(val, (tp->t_delta.tv_sec*1000 + tp->t_delta.tv_usec/1000)); } val |= gethistflags(vsp->pmid, vsp->vlist[j].inst); vsp->vlist[j].value.lval = val; if (control == PM_LOG_MANDATORY || control == PM_LOG_ADVISORY) { int expstate = 0; int statemask = 0; int expdelta; if (rqp != NULL && rqp->r_desc->indom != PM_INDOM_NULL) { char *p; if (j == 0) fputc('\n', stderr); if (pmNameInDom(rqp->r_desc->indom, vsp->vlist[j].inst, &p) >= 0) { fprintf(stderr, " instance: %s", p); free(p); } else fprintf(stderr, " instance: #%d", vsp->vlist[j].inst); } else { /* no pmDesc ... punt */ if (vsp->numval > 1 || vsp->vlist[j].inst != PM_IN_NULL) { if (j == 0) fputc('\n', stderr); fprintf(stderr, " instance: #%d", vsp->vlist[j].inst); } } if (state != PM_LOG_MAYBE) { if (control == PM_LOG_MANDATORY) PMLC_SET_MAND(expstate, 1); else PMLC_SET_MAND(expstate, 0); if (state == PM_LOG_ON) PMLC_SET_ON(expstate, 1); else PMLC_SET_ON(expstate, 0); PMLC_SET_MAND(statemask, 1); PMLC_SET_ON(statemask, 1); } else { PMLC_SET_MAND(expstate, 0); PMLC_SET_MAND(statemask, 1); } expdelta = PMLC_GET_ON(expstate) ? delta : 0; if ((PMLC_GET_STATE(val) & statemask) != expstate || PMLC_GET_DELTA(val) != expdelta) fprintf(stderr, " [request failed]"); fputc('\n', stderr); } } } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) { __pmDumpResult(stderr, result); } #endif if ((sts = __pmSendResult(clientfd, FROM_ANON, result)) < 0) __pmNotifyErr(LOG_ERR, "do_control: error sending Error PDU to client: %s\n", pmErrStr(sts)); if (siamised) { for (i = 0; i < request->numpmid; i++) if (request->vset[i]->numval <= 0) free(result->vset[i]); free(result); } pmFreeResult(request); return 0; }